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:
|
Draco wrapper for Maya extensions
|
||||||
|
"""
|
||||||
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])
|
|
||||||
'''
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
|
__author__ = "Mattia Pezzano, Federico de Felici, Duccio Lenkowicz"
|
||||||
|
__version__ = "0.1"
|
||||||
|
|
||||||
class Drc2PyMesh(ctypes.Structure):
|
class Drc2PyMesh(ctypes.Structure):
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("faces_num", ctypes.c_uint),
|
("faces_num", ctypes.c_uint),
|
||||||
@ -35,26 +21,53 @@ class Drc2PyMesh(ctypes.Structure):
|
|||||||
# TODO: Add integration for UNIX
|
# TODO: Add integration for UNIX
|
||||||
class Draco:
|
class Draco:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
# Lib loading
|
||||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
lib_path = os.path.join(dir_path, 'dracodec_maya')
|
lib_path = os.path.join(dir_path, 'dracodec_maya')
|
||||||
self.drc_lib = ctypes.CDLL(lib_path)
|
self.drc_lib = ctypes.CDLL(lib_path)
|
||||||
|
# Mapping free funct
|
||||||
self.drc_decode = self.drc_lib.drc2py_decode
|
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.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):
|
def decode(self, file_path):
|
||||||
|
# Open drc file
|
||||||
file = None
|
file = None
|
||||||
bytes = None
|
bytes = None
|
||||||
try:
|
try:
|
||||||
file = open(file_path, 'rb')
|
file = open(file_path, 'rb')
|
||||||
bytes = file.read()
|
bytes = file.read()
|
||||||
except IOError as err:
|
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
|
return None
|
||||||
finally:
|
finally:
|
||||||
if file: file.close()
|
if file: file.close()
|
||||||
|
|
||||||
|
# Decode drc file
|
||||||
size = len(bytes)
|
size = len(bytes)
|
||||||
mesh_ptr = ctypes.POINTER(Drc2PyMesh)()
|
mesh_ptr = ctypes.POINTER(Drc2PyMesh)()
|
||||||
self.drc_decode(bytes, size, ctypes.byref(mesh_ptr))
|
self.drc_decode(bytes, size, ctypes.byref(mesh_ptr))
|
||||||
mesh = mesh_ptr.contents
|
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) {
|
void drc2py_free(Drc2PyMesh **mesh_ptr) {
|
||||||
DracoToMayaMesh *mesh = *mesh_ptr;
|
Drc2PyMesh *mesh = *mesh_ptr;
|
||||||
if (!mesh)
|
if (!mesh) return;
|
||||||
return;
|
if (mesh->faces) {
|
||||||
if (mesh->indices) {
|
delete[] mesh->faces;
|
||||||
delete[] mesh->indices;
|
mesh->faces = nullptr;
|
||||||
mesh->indices = nullptr;
|
mesh->faces_num = 0;
|
||||||
}
|
}
|
||||||
if (mesh->position) {
|
if (mesh->vertices) {
|
||||||
delete[] mesh->position;
|
delete[] mesh->vertices;
|
||||||
mesh->position = nullptr;
|
mesh->vertices = nullptr;
|
||||||
}
|
mesh->vertices_num = 0;
|
||||||
if (mesh->has_normal && mesh->normal) {
|
}
|
||||||
delete[] mesh->normal;
|
if (mesh->normals) {
|
||||||
mesh->has_normal = false;
|
delete[] mesh->normals;
|
||||||
mesh->normal = nullptr;
|
mesh->normals = nullptr;
|
||||||
}
|
mesh->normals_num = 0;
|
||||||
if (mesh->has_texcoord && mesh->texcoord) {
|
}
|
||||||
delete[] mesh->texcoord;
|
delete mesh;
|
||||||
mesh->has_texcoord = false;
|
*mesh_ptr = nullptr;
|
||||||
mesh->texcoord = nullptr;
|
|
||||||
}
|
|
||||||
if (mesh->has_color && mesh->color) {
|
|
||||||
delete[] mesh->color;
|
|
||||||
mesh->has_color = false;
|
|
||||||
mesh->color = nullptr;
|
|
||||||
}
|
|
||||||
delete mesh;
|
|
||||||
*mesh_ptr = nullptr;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
int drc2py_decode(char *data, unsigned int length, Drc2PyMesh **res_mesh) {
|
int drc2py_decode(char *data, unsigned int length, Drc2PyMesh **res_mesh) {
|
||||||
draco::DecoderBuffer buffer;
|
draco::DecoderBuffer buffer;
|
||||||
buffer.Init(data, length);
|
buffer.Init(data, length);
|
||||||
auto type_statusor = draco::Decoder::GetEncodedGeometryType(&buffer);
|
auto type_statusor = draco::Decoder::GetEncodedGeometryType(&buffer);
|
||||||
if (!type_statusor.ok()) {
|
if (!type_statusor.ok()) {
|
||||||
// TODO(zhafang): Use enum instead.
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
const draco::EncodedGeometryType geom_type = type_statusor.value();
|
const draco::EncodedGeometryType geom_type = type_statusor.value();
|
||||||
@ -135,65 +125,6 @@ namespace draco {
|
|||||||
return 0;
|
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.
|
// Get color attributes.
|
||||||
const auto color_att =
|
const auto color_att =
|
||||||
in_mesh->GetNamedAttribute(draco::GeometryAttribute::COLOR);
|
in_mesh->GetNamedAttribute(draco::GeometryAttribute::COLOR);
|
||||||
@ -225,9 +156,6 @@ namespace draco {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return in_mesh->num_faces();
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
} // namespace maya
|
} // namespace maya
|
||||||
|
|
||||||
|
@ -29,8 +29,6 @@
|
|||||||
namespace draco {
|
namespace draco {
|
||||||
namespace maya {
|
namespace maya {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
//void ReleaseMayaMesh(DracoToMayaMesh **mesh_ptr);
|
|
||||||
|
|
||||||
struct EXPORT_API Drc2PyMesh {
|
struct EXPORT_API Drc2PyMesh {
|
||||||
Drc2PyMesh()
|
Drc2PyMesh()
|
||||||
: faces_num(0),
|
: faces_num(0),
|
||||||
@ -48,6 +46,7 @@ namespace draco {
|
|||||||
};
|
};
|
||||||
|
|
||||||
EXPORT_API int drc2py_decode(char *data, unsigned int length, Drc2PyMesh **res_mesh);
|
EXPORT_API int drc2py_decode(char *data, unsigned int length, Drc2PyMesh **res_mesh);
|
||||||
|
EXPORT_API void drc2py_free(Drc2PyMesh **res_mesh);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
} // namespace maya
|
} // namespace maya
|
||||||
|
Loading…
x
Reference in New Issue
Block a user