// python2/3 module for tinyobjloader // // usage: // import tinyobjloader as tol // model = tol.LoadObj(name) // print(model["shapes"]) // print(model["materials"] // note: // `shape.mesh.index_t` is represented as flattened array: (vertex_index, normal_index, texcoord_index) * num_faces #include #include #include "../tiny_obj_loader.h" typedef std::vector vectd; typedef std::vector vecti; PyObject* pyTupleFromfloat3(float array[3]) { int i; PyObject* tuple = PyTuple_New(3); for (i = 0; i <= 2; i++) { PyTuple_SetItem(tuple, i, PyFloat_FromDouble(array[i])); } return tuple; } extern "C" { static PyObject* pyLoadObj(PyObject* self, PyObject* args) { PyObject *rtndict, *pyshapes, *pymaterials, *attribobj, *current, *meshobj; char const* current_name; char const* filename; vectd vect; std::vector indices; std::vector face_verts; tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; if (!PyArg_ParseTuple(args, "s", &filename)) return NULL; std::string err; tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename); pyshapes = PyDict_New(); pymaterials = PyDict_New(); rtndict = PyDict_New(); attribobj = PyDict_New(); for (int i = 0; i <= 2; i++) { current = PyList_New(0); switch (i) { case 0: current_name = "vertices"; vect = vectd(attrib.vertices.begin(), attrib.vertices.end()); break; case 1: current_name = "normals"; vect = vectd(attrib.normals.begin(), attrib.normals.end()); break; case 2: current_name = "texcoords"; vect = vectd(attrib.texcoords.begin(), attrib.texcoords.end()); break; } for (vectd::iterator it = vect.begin(); it != vect.end(); it++) { PyList_Insert(current, it - vect.begin(), PyFloat_FromDouble(*it)); } PyDict_SetItemString(attribobj, current_name, current); } for (std::vector::iterator shape = shapes.begin(); shape != shapes.end(); shape++) { meshobj = PyDict_New(); tinyobj::mesh_t cm = (*shape).mesh; { current = PyList_New(0); for (size_t i = 0; i < cm.indices.size(); i++) { // Flatten index array: v_idx, vn_idx, vt_idx, v_idx, vn_idx, vt_idx, // ... PyList_Insert(current, 3 * i + 0, PyLong_FromLong(cm.indices[i].vertex_index)); PyList_Insert(current, 3 * i + 1, PyLong_FromLong(cm.indices[i].normal_index)); PyList_Insert(current, 3 * i + 2, PyLong_FromLong(cm.indices[i].texcoord_index)); } PyDict_SetItemString(meshobj, "indices", current); } { current = PyList_New(0); for (size_t i = 0; i < cm.num_face_vertices.size(); i++) { // Widen data type to long. PyList_Insert(current, i, PyLong_FromLong(cm.num_face_vertices[i])); } PyDict_SetItemString(meshobj, "num_face_vertices", current); } { current = PyList_New(0); for (size_t i = 0; i < cm.material_ids.size(); i++) { PyList_Insert(current, i, PyLong_FromLong(cm.material_ids[i])); } PyDict_SetItemString(meshobj, "material_ids", current); } PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj); } for (std::vector::iterator mat = materials.begin(); mat != materials.end(); mat++) { PyObject* matobj = PyDict_New(); PyObject* unknown_parameter = PyDict_New(); for (std::map::iterator p = (*mat).unknown_parameter.begin(); p != (*mat).unknown_parameter.end(); ++p) { PyDict_SetItemString(unknown_parameter, p->first.c_str(), PyUnicode_FromString(p->second.c_str())); } PyDict_SetItemString(matobj, "shininess", PyFloat_FromDouble((*mat).shininess)); PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble((*mat).ior)); PyDict_SetItemString(matobj, "dissolve", PyFloat_FromDouble((*mat).dissolve)); PyDict_SetItemString(matobj, "illum", PyLong_FromLong((*mat).illum)); PyDict_SetItemString(matobj, "ambient_texname", PyUnicode_FromString((*mat).ambient_texname.c_str())); PyDict_SetItemString(matobj, "diffuse_texname", PyUnicode_FromString((*mat).diffuse_texname.c_str())); PyDict_SetItemString(matobj, "specular_texname", PyUnicode_FromString((*mat).specular_texname.c_str())); PyDict_SetItemString( matobj, "specular_highlight_texname", PyUnicode_FromString((*mat).specular_highlight_texname.c_str())); PyDict_SetItemString(matobj, "bump_texname", PyUnicode_FromString((*mat).bump_texname.c_str())); PyDict_SetItemString( matobj, "displacement_texname", PyUnicode_FromString((*mat).displacement_texname.c_str())); PyDict_SetItemString(matobj, "alpha_texname", PyUnicode_FromString((*mat).alpha_texname.c_str())); PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3((*mat).ambient)); PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3((*mat).diffuse)); PyDict_SetItemString(matobj, "specular", pyTupleFromfloat3((*mat).specular)); PyDict_SetItemString(matobj, "transmittance", pyTupleFromfloat3((*mat).transmittance)); PyDict_SetItemString(matobj, "emission", pyTupleFromfloat3((*mat).emission)); PyDict_SetItemString(matobj, "unknown_parameter", unknown_parameter); PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj); } PyDict_SetItemString(rtndict, "shapes", pyshapes); PyDict_SetItemString(rtndict, "materials", pymaterials); PyDict_SetItemString(rtndict, "attribs", attribobj); return rtndict; } static PyMethodDef mMethods[] = { {"LoadObj", pyLoadObj, METH_VARARGS}, {NULL, NULL, 0, NULL} }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "tinyobjloader", NULL, -1, mMethods}; PyMODINIT_FUNC PyInit_tinyobjloader(void) { return PyModule_Create(&moduledef); } #else PyMODINIT_FUNC inittinyobjloader(void) { Py_InitModule3("tinyobjloader", mMethods, NULL); } #endif // PY_MAJOR_VERSION >= 3 }