mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-04 11:25:44 +08:00
Added memory free management; decoupled mesh result from ctypes; added tests
This commit is contained in:
parent
48a662f733
commit
7a68d823f9
Binary file not shown.
@ -1,27 +1,13 @@
|
||||
'''
|
||||
Usage Example:
|
||||
|
||||
from draco import Draco
|
||||
|
||||
drc = Draco()
|
||||
mesh = drc.decode('path-to-file.drc')
|
||||
|
||||
print("")
|
||||
print("==== FACES ====")
|
||||
print(mesh.faces_num)
|
||||
print(mesh.faces[0:10])
|
||||
print("")
|
||||
print("==== VERTICES ====")
|
||||
print(mesh.vertices_num)
|
||||
print(mesh.vertices[0:10])
|
||||
print("==== NORMALS ====")
|
||||
print(mesh.normals_num)
|
||||
print(mesh.normals[0:10])
|
||||
'''
|
||||
"""
|
||||
Draco wrapper for Maya extensions
|
||||
"""
|
||||
|
||||
import os
|
||||
import ctypes
|
||||
|
||||
__author__ = "Mattia Pezzano, Federico de Felici, Duccio Lenkowicz"
|
||||
__version__ = "0.1"
|
||||
|
||||
class Drc2PyMesh(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("faces_num", ctypes.c_uint),
|
||||
@ -35,26 +21,53 @@ class Drc2PyMesh(ctypes.Structure):
|
||||
# TODO: Add integration for UNIX
|
||||
class Draco:
|
||||
def __init__(self):
|
||||
# Lib loading
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
lib_path = os.path.join(dir_path, 'dracodec_maya')
|
||||
self.drc_lib = ctypes.CDLL(lib_path)
|
||||
# Mapping free funct
|
||||
self.drc_decode = self.drc_lib.drc2py_decode
|
||||
self.drc_decode.argtype = [ ctypes.POINTER(ctypes.c_char), ctypes.c_uint, ctypes.POINTER(ctypes.POINTER(Drc2PyMesh)) ]
|
||||
|
||||
self.drc_decode.restype = ctypes.c_uint
|
||||
# Mapping free funct
|
||||
self.drc_free = self.drc_lib.drc2py_free
|
||||
self.drc_free.argtype = ctypes.POINTER(ctypes.POINTER(Drc2PyMesh))
|
||||
self.drc_free.restype = None
|
||||
|
||||
def decode(self, file_path):
|
||||
# Open drc file
|
||||
file = None
|
||||
bytes = None
|
||||
try:
|
||||
file = open(file_path, 'rb')
|
||||
bytes = file.read()
|
||||
except IOError as err:
|
||||
print('[ERROR] Failure opening file: ' + repr(err))
|
||||
raise Exception('[ERROR] Failure opening file: ['+ os.path.realpath(file_path) + '] => ' + repr(err))
|
||||
return None
|
||||
finally:
|
||||
if file: file.close()
|
||||
|
||||
# Decode drc file
|
||||
size = len(bytes)
|
||||
mesh_ptr = ctypes.POINTER(Drc2PyMesh)()
|
||||
self.drc_decode(bytes, size, ctypes.byref(mesh_ptr))
|
||||
mesh = mesh_ptr.contents
|
||||
return mesh;
|
||||
|
||||
# Preparing result to decouple from ctypes types
|
||||
result = type('', (), {})()
|
||||
result.faces = mesh.faces[0:mesh.faces_num * 3]
|
||||
result.faces_len = mesh.faces_num * 3
|
||||
result.faces_num = mesh.faces_num
|
||||
|
||||
result.vertices = mesh.vertices[0:mesh.vertices_num * 3]
|
||||
result.vertices_len = mesh.vertices_num * 3
|
||||
result.vertices_num = mesh.vertices_num
|
||||
|
||||
result.normals = mesh.normals[0:mesh.normals_num * 3]
|
||||
result.normals_len = mesh.normals_num * 3
|
||||
result.normals_num = mesh.normals_num
|
||||
|
||||
# Free memory allocated by the lib
|
||||
self.drc_free(ctypes.byref(mesh_ptr))
|
||||
mesh_ptr = None
|
||||
return result;
|
||||
|
BIN
maya/test/bunny.drc
Normal file
BIN
maya/test/bunny.drc
Normal file
Binary file not shown.
35
maya/test/dracodec_maya_test.py
Normal file
35
maya/test/dracodec_maya_test.py
Normal file
@ -0,0 +1,35 @@
|
||||
import unittest
|
||||
import os
|
||||
import sys
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
root_path = os.path.join(dir_path, '..')
|
||||
sys.path.insert(0, root_path)
|
||||
|
||||
|
||||
from dracodec_maya import Draco
|
||||
|
||||
class DracoTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.drc = Draco()
|
||||
|
||||
def test_valid_bunny_drc(self):
|
||||
mesh = self.drc.decode(os.path.join(dir_path, 'bunny.drc'))
|
||||
# Faces check
|
||||
self.assertEqual(69451, mesh.faces_num, 'Number of faces')
|
||||
self.assertEqual(208353, mesh.faces_len,'Length of faces array precalculated')
|
||||
self.assertEqual(208353, len(mesh.faces),'Length of faces array by len')
|
||||
# Vertices check
|
||||
self.assertEqual(34834, mesh.vertices_num, 'Number of vertices')
|
||||
self.assertEqual(104502, mesh.vertices_len,'Length of vertices array precalculated')
|
||||
self.assertEqual(104502, len(mesh.vertices),'Length of vertices array by len')
|
||||
# Normals check
|
||||
self.assertEqual(0, mesh.normals_num, 'Number of normals')
|
||||
self.assertEqual(0, mesh.normals_len,'Length of normals array precalculated')
|
||||
self.assertEqual(0, len(mesh.normals),'Length of normals array by len')
|
||||
|
||||
def test_unexistent_drc(self):
|
||||
self.assertRaises(Exception, self.drc.decode, 'unexistent.drc')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -76,44 +76,34 @@ namespace draco {
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
void ReleaseMayaMesh(DracoToMayaMesh **mesh_ptr) {
|
||||
DracoToMayaMesh *mesh = *mesh_ptr;
|
||||
if (!mesh)
|
||||
return;
|
||||
if (mesh->indices) {
|
||||
delete[] mesh->indices;
|
||||
mesh->indices = nullptr;
|
||||
}
|
||||
if (mesh->position) {
|
||||
delete[] mesh->position;
|
||||
mesh->position = nullptr;
|
||||
}
|
||||
if (mesh->has_normal && mesh->normal) {
|
||||
delete[] mesh->normal;
|
||||
mesh->has_normal = false;
|
||||
mesh->normal = nullptr;
|
||||
}
|
||||
if (mesh->has_texcoord && mesh->texcoord) {
|
||||
delete[] mesh->texcoord;
|
||||
mesh->has_texcoord = false;
|
||||
mesh->texcoord = nullptr;
|
||||
}
|
||||
if (mesh->has_color && mesh->color) {
|
||||
delete[] mesh->color;
|
||||
mesh->has_color = false;
|
||||
mesh->color = nullptr;
|
||||
}
|
||||
delete mesh;
|
||||
*mesh_ptr = nullptr;
|
||||
|
||||
void drc2py_free(Drc2PyMesh **mesh_ptr) {
|
||||
Drc2PyMesh *mesh = *mesh_ptr;
|
||||
if (!mesh) return;
|
||||
if (mesh->faces) {
|
||||
delete[] mesh->faces;
|
||||
mesh->faces = nullptr;
|
||||
mesh->faces_num = 0;
|
||||
}
|
||||
if (mesh->vertices) {
|
||||
delete[] mesh->vertices;
|
||||
mesh->vertices = nullptr;
|
||||
mesh->vertices_num = 0;
|
||||
}
|
||||
if (mesh->normals) {
|
||||
delete[] mesh->normals;
|
||||
mesh->normals = nullptr;
|
||||
mesh->normals_num = 0;
|
||||
}
|
||||
delete mesh;
|
||||
*mesh_ptr = nullptr;
|
||||
}
|
||||
*/
|
||||
|
||||
int drc2py_decode(char *data, unsigned int length, Drc2PyMesh **res_mesh) {
|
||||
draco::DecoderBuffer buffer;
|
||||
buffer.Init(data, length);
|
||||
auto type_statusor = draco::Decoder::GetEncodedGeometryType(&buffer);
|
||||
if (!type_statusor.ok()) {
|
||||
// TODO(zhafang): Use enum instead.
|
||||
return -1;
|
||||
}
|
||||
const draco::EncodedGeometryType geom_type = type_statusor.value();
|
||||
@ -135,65 +125,6 @@ namespace draco {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
int DecodeMeshForMaya(char *data, unsigned int length, DracoToMayaMesh **tmp_mesh) {
|
||||
draco::DecoderBuffer buffer;
|
||||
buffer.Init(data, length);
|
||||
auto type_statusor = draco::Decoder::GetEncodedGeometryType(&buffer);
|
||||
if (!type_statusor.ok()) {
|
||||
// TODO(zhafang): Use enum instead.
|
||||
return -1;
|
||||
}
|
||||
const draco::EncodedGeometryType geom_type = type_statusor.value();
|
||||
if (geom_type != draco::TRIANGULAR_MESH) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
draco::Decoder decoder;
|
||||
auto statusor = decoder.DecodeMeshFromBuffer(&buffer);
|
||||
if (!statusor.ok()) {
|
||||
return -3;
|
||||
}
|
||||
std::unique_ptr<draco::Mesh> in_mesh = std::move(statusor).value();
|
||||
|
||||
*tmp_mesh = new DracoToMayaMesh();
|
||||
DracoToMayaMesh *unity_mesh = *tmp_mesh;
|
||||
unity_mesh->num_faces = in_mesh->num_faces();
|
||||
unity_mesh->num_vertices = in_mesh->num_points();
|
||||
|
||||
unity_mesh->indices = new int[in_mesh->num_faces() * 3];
|
||||
for (draco::FaceIndex face_id(0); face_id < in_mesh->num_faces(); ++face_id) {
|
||||
const Mesh::Face &face = in_mesh->face(draco::FaceIndex(face_id));
|
||||
memcpy(unity_mesh->indices + face_id.value() * 3,
|
||||
reinterpret_cast<const int *>(face.data()), sizeof(int) * 3);
|
||||
}
|
||||
|
||||
// TODO(zhafang): Add other attributes.
|
||||
unity_mesh->position = new float[in_mesh->num_points() * 3];
|
||||
const auto pos_att =
|
||||
in_mesh->GetNamedAttribute(draco::GeometryAttribute::POSITION);
|
||||
for (draco::PointIndex i(0); i < in_mesh->num_points(); ++i) {
|
||||
const draco::AttributeValueIndex val_index = pos_att->mapped_index(i);
|
||||
if (!pos_att->ConvertValue<float, 3>(
|
||||
val_index, unity_mesh->position + i.value() * 3)) {
|
||||
ReleaseMayaMesh(&unity_mesh);
|
||||
return -8;
|
||||
}
|
||||
}
|
||||
// Get normal attributes.
|
||||
const auto normal_att =
|
||||
in_mesh->GetNamedAttribute(draco::GeometryAttribute::NORMAL);
|
||||
if (normal_att != nullptr) {
|
||||
unity_mesh->normal = new float[in_mesh->num_points() * 3];
|
||||
unity_mesh->has_normal = true;
|
||||
for (draco::PointIndex i(0); i < in_mesh->num_points(); ++i) {
|
||||
const draco::AttributeValueIndex val_index = normal_att->mapped_index(i);
|
||||
if (!normal_att->ConvertValue<float, 3>(
|
||||
val_index, unity_mesh->normal + i.value() * 3)) {
|
||||
ReleaseMayaMesh(&unity_mesh);
|
||||
return -8;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get color attributes.
|
||||
const auto color_att =
|
||||
in_mesh->GetNamedAttribute(draco::GeometryAttribute::COLOR);
|
||||
@ -225,9 +156,6 @@ namespace draco {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return in_mesh->num_faces();
|
||||
}
|
||||
*/
|
||||
} // namespace maya
|
||||
|
||||
|
@ -28,9 +28,7 @@
|
||||
|
||||
namespace draco {
|
||||
namespace maya {
|
||||
extern "C" {
|
||||
//void ReleaseMayaMesh(DracoToMayaMesh **mesh_ptr);
|
||||
|
||||
extern "C" {
|
||||
struct EXPORT_API Drc2PyMesh {
|
||||
Drc2PyMesh()
|
||||
: faces_num(0),
|
||||
@ -48,6 +46,7 @@ namespace draco {
|
||||
};
|
||||
|
||||
EXPORT_API int drc2py_decode(char *data, unsigned int length, Drc2PyMesh **res_mesh);
|
||||
EXPORT_API void drc2py_free(Drc2PyMesh **res_mesh);
|
||||
} // extern "C"
|
||||
|
||||
} // namespace maya
|
||||
|
Loading…
x
Reference in New Issue
Block a user