Added memory free management; decoupled mesh result from ctypes; added tests

This commit is contained in:
Federico De Felici 2018-05-11 15:37:39 +02:00
parent 48a662f733
commit 7a68d823f9
6 changed files with 95 additions and 120 deletions

Binary file not shown.

View File

@ -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

Binary file not shown.

View 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()

View File

@ -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

View File

@ -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