From 0baec5f0bd726dc2cd40317abc1015bd6add6c93 Mon Sep 17 00:00:00 2001 From: bzt Date: Tue, 29 Oct 2019 14:14:00 +0100 Subject: [PATCH] Added M3D format support --- Readme.md | 1 + code/CMakeLists.txt | 12 + code/Common/Exporter.cpp | 7 + code/Common/ImporterRegistry.cpp | 6 + code/M3D/M3DExporter.cpp | 392 +++++++++++ code/M3D/M3DExporter.h | 98 +++ code/M3D/M3DImporter.cpp | 734 +++++++++++++++++++++ code/M3D/M3DImporter.h | 106 +++ code/M3D/M3DMaterials.h | 106 +++ code/M3D/m3d.h | 1 + test/models/M3D/README.md | 14 + test/models/M3D/WusonBlitz0.m3d | Bin 0 -> 29223 bytes test/models/M3D/WusonBlitz1.m3d | Bin 0 -> 35058 bytes test/models/M3D/WusonBlitz2.m3d | Bin 0 -> 42228 bytes test/models/M3D/aliveai_character.m3d | Bin 0 -> 2532 bytes test/models/M3D/cube_normals.m3d | Bin 0 -> 156 bytes test/models/M3D/cube_usemtl.m3d | Bin 0 -> 249 bytes test/models/M3D/cube_with_vertexcolors.a3d | 33 + test/models/M3D/cube_with_vertexcolors.m3d | Bin 0 -> 228 bytes test/models/M3D/mobs_dwarves_character.m3d | Bin 0 -> 11255 bytes test/models/M3D/suzanne.m3d | Bin 0 -> 11645 bytes 21 files changed, 1510 insertions(+) create mode 100644 code/M3D/M3DExporter.cpp create mode 100644 code/M3D/M3DExporter.h create mode 100644 code/M3D/M3DImporter.cpp create mode 100644 code/M3D/M3DImporter.h create mode 100644 code/M3D/M3DMaterials.h create mode 120000 code/M3D/m3d.h create mode 100644 test/models/M3D/README.md create mode 100644 test/models/M3D/WusonBlitz0.m3d create mode 100644 test/models/M3D/WusonBlitz1.m3d create mode 100644 test/models/M3D/WusonBlitz2.m3d create mode 100644 test/models/M3D/aliveai_character.m3d create mode 100644 test/models/M3D/cube_normals.m3d create mode 100644 test/models/M3D/cube_usemtl.m3d create mode 100644 test/models/M3D/cube_with_vertexcolors.a3d create mode 100644 test/models/M3D/cube_with_vertexcolors.m3d create mode 100644 test/models/M3D/mobs_dwarves_character.m3d create mode 100644 test/models/M3D/suzanne.m3d diff --git a/Readme.md b/Readme.md index f749993fd..f02a3b617 100644 --- a/Readme.md +++ b/Readme.md @@ -67,6 +67,7 @@ __Importers__: - [LWO](https://en.wikipedia.org/wiki/LightWave_3D) - LWS - LXO +- [M3D](https://gitlab.com/bztsrc/model3d) - MD2 - MD3 - MD5 diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index eec805b54..910a43562 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -407,6 +407,18 @@ ADD_ASSIMP_IMPORTER( LWS LWS/LWSLoader.h ) +ADD_ASSIMP_IMPORTER( M3D + M3D/M3DMaterials.h + M3D/M3DImporter.h + M3D/M3DImporter.cpp + M3D/m3d.h +) + +ADD_ASSIMP_EXPORTER( M3D + M3D/M3DExporter.h + M3D/M3DExporter.cpp +) + ADD_ASSIMP_IMPORTER( MD2 MD2/MD2FileData.h MD2/MD2Loader.cpp diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 34d49c472..4ce1a2bd8 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -102,6 +102,8 @@ void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperti void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); +void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); // ------------------------------------------------------------------------------------------------ @@ -179,6 +181,11 @@ Exporter::ExportFormatEntry gExporters[] = Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), #endif +#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER + Exporter::ExportFormatEntry( "m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0 ), + Exporter::ExportFormatEntry( "a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0 ), +#endif + #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), #endif diff --git a/code/Common/ImporterRegistry.cpp b/code/Common/ImporterRegistry.cpp index 32ac3b416..b9f28f035 100644 --- a/code/Common/ImporterRegistry.cpp +++ b/code/Common/ImporterRegistry.cpp @@ -197,6 +197,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER # include "MMD/MMDImporter.h" #endif +#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER +# include "M3D/M3DImporter.h" +#endif #ifndef ASSIMP_BUILD_NO_STEP_IMPORTER # include "Importer/StepFile/StepFileImporter.h" #endif @@ -223,6 +226,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) out.push_back( new Discreet3DSImporter()); #endif +#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER) + out.push_back( new M3DImporter()); +#endif #if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER) out.push_back( new MD3Importer()); #endif diff --git a/code/M3D/M3DExporter.cpp b/code/M3D/M3DExporter.cpp new file mode 100644 index 000000000..35cae078a --- /dev/null +++ b/code/M3D/M3DExporter.cpp @@ -0,0 +1,392 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team +Copyright (c) 2019 bzt + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER + +#define M3D_IMPLEMENTATION +#define M3D_NOIMPORTER +#define M3D_EXPORTER +#define M3D_ASCII +#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER +#define M3D_NODUP +#endif + +// Header files, standard library. +#include // shared_ptr +#include +#include + +#include // aiGetVersion +#include +#include +#include +#include // StreamWriterLE +#include // DeadlyExportError +#include // aiTextureType +#include +#include +#include "M3DExporter.h" +#include "M3DMaterials.h" + +// RESOURCES: +// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md +// https://gitlab.com/bztsrc/model3d/blob/master/docs/a3d_format.md + +/* + * Currently supports static meshes, vertex colors, materials, textures + * + * For animation, it would require the following conversions: + * - aiNode (bones) -> m3d_t.bone (with parent id, position vector and oriantation quaternion) + * - aiMesh.aiBone -> m3d_t.skin (per vertex, with bone id, weight pairs) + * - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation + * triplets, instead of per bone timestamp + lists) + */ +using namespace Assimp; + +namespace Assimp { + + // --------------------------------------------------------------------- + // Worker function for exporting a scene to binary M3D. + // Prototyped and registered in Exporter.cpp + void ExportSceneM3D ( + const char* pFile, + IOSystem* pIOSystem, + const aiScene* pScene, + const ExportProperties* pProperties + ){ + // initialize the exporter + M3DExporter exporter(pScene, pProperties); + + // perform binary export + exporter.doExport(pFile, pIOSystem, false); + } + + // --------------------------------------------------------------------- + // Worker function for exporting a scene to ASCII A3D. + // Prototyped and registered in Exporter.cpp + void ExportSceneA3D ( + const char* pFile, + IOSystem* pIOSystem, + const aiScene* pScene, + const ExportProperties* pProperties + + ){ + // initialize the exporter + M3DExporter exporter(pScene, pProperties); + + // perform ascii export + exporter.doExport(pFile, pIOSystem, true); + } + +} // end of namespace Assimp + +// ------------------------------------------------------------------------------------------------ +M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties ) +: mScene(pScene) +, mProperties(pProperties) +, outfile() +, m3d(nullptr) { } + +// ------------------------------------------------------------------------------------------------ +void M3DExporter::doExport ( + const char* pFile, + IOSystem* pIOSystem, + bool toAscii +){ + // TODO: convert mProperties into M3D_EXP_* flags + (void)mProperties; + + // open the indicated file for writing (in binary / ASCII mode) + outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb")); + if (!outfile) { + throw DeadlyExportError( "could not open output .m3d file: " + std::string(pFile) ); + } + + // use malloc() here because m3d_free() will call free() + m3d = (m3d_t*)malloc(sizeof(m3d_t)); + if(!m3d) { + throw DeadlyExportError( "memory allocation error" ); + } + memset(m3d, 0, sizeof(m3d_t)); + m3d->name = _m3d_safestr((char*)&mScene->mRootNode->mName.data, 2); + + // Create a model from assimp structures + aiMatrix4x4 m; + NodeWalk(mScene->mRootNode, m); + + // serialize the structures + unsigned int size; + unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT, + M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size); + m3d_free(m3d); + if(!output || size < 8) { + throw DeadlyExportError( "unable to serialize into Model 3D" ); + } + + // Write out serialized model + outfile->Write(output, size, 1); + + // explicitly release file pointer, + // so we don't have to rely on class destruction. + outfile.reset(); +} + +// ------------------------------------------------------------------------------------------------ +// recursive node walker +void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m) +{ + unsigned int i, j, k, l, n, mi, idx; + aiMatrix4x4 nm = m * pNode->mTransformation; + m3dv_t vertex; + m3dti_t ti; + + for(i = 0; i < pNode->mNumMeshes; i++) { + const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]]; + + mi = (M3D_INDEX)-1U; + if(mScene->mMaterials) { + // get the material for this mesh + mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]); + } + // iterate through the mesh faces + for(j = 0; j < mesh->mNumFaces; j++) { + const aiFace* face = &(mesh->mFaces[j]); + // only triangle meshes supported for now + if(face->mNumIndices != 3) { + throw DeadlyExportError( "use aiProcess_Triangulate before export" ); + } + // add triangle to the output + n = m3d->numface++; + m3d->face = (m3df_t*)M3D_REALLOC(m3d->face, + m3d->numface * sizeof(m3df_t)); + if(!m3d->face) { + throw DeadlyExportError( "memory allocation error" ); + } + /* set all index to -1 by default */ + memset(&m3d->face[n], 255, sizeof(m3df_t)); + m3d->face[n].materialid = mi; + for(k = 0; k < face->mNumIndices; k++) { + // get the vertex's index + l = face->mIndices[k]; + // multiply the position vector by the transformation matrix + aiVector3D v = mesh->mVertices[l]; + v *= nm; + memset(&vertex, 0, sizeof(m3dv_t)); + vertex.x = v.x; + vertex.y = v.y; + vertex.z = v.z; + vertex.w = 1.0; + // add color if defined + if(mesh->HasVertexColors(0)) + vertex.color = mkColor(&mesh->mColors[0][l]); + // save the vertex to the output + m3d->vertex = _m3d_addvrtx(m3d->vertex, &m3d->numvertex, + &vertex, &idx); + m3d->face[n].vertex[k] = (M3D_INDEX)idx; + // do we have texture coordinates? + if(mesh->HasTextureCoords(0)) { + ti.u = mesh->mTextureCoords[0][l].x; + ti.v = mesh->mTextureCoords[0][l].y; + m3d->tmap = _m3d_addtmap(m3d->tmap, &m3d->numtmap, &ti, + &idx); + m3d->face[n].texcoord[k] = (M3D_INDEX)idx; + } + // do we have normal vectors? + if(mesh->HasNormals()) { + vertex.color = 0; + vertex.x = mesh->mNormals[l].x; + vertex.y = mesh->mNormals[l].y; + vertex.z = mesh->mNormals[l].z; + m3d->vertex = _m3d_addnorm(m3d->vertex, &m3d->numvertex, + &vertex, &idx); + m3d->face[n].normal[k] = (M3D_INDEX)idx; + } + } + } + } + // repeat for the children nodes + for (i = 0; i < pNode->mNumChildren; i++) { + NodeWalk(pNode->mChildren[i], nm); + } +} + +// ------------------------------------------------------------------------------------------------ +// convert aiColor4D into uint32_t +uint32_t M3DExporter::mkColor(aiColor4D* c) +{ + return ((uint8_t)(c->a*255) << 24L) | + ((uint8_t)(c->b*255) << 16L) | + ((uint8_t)(c->g*255) << 8L) | + ((uint8_t)(c->r*255) << 0L); +} + +// ------------------------------------------------------------------------------------------------ +// add a material to the output +M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat) +{ + unsigned int i, j, k, mi = -1U; + aiColor4D c; + aiString name; + ai_real f; + char *fn; + + if(mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length && + strcmp((char*)&name.data, AI_DEFAULT_MATERIAL_NAME)) { + // check if we have saved a material by this name. This has to be done + // because only the referenced materials should be added to the output + for(i = 0; i < m3d->nummaterial; i++) + if(!strcmp((char*)&name.data, m3d->material[i].name)) { + mi = i; + break; + } + // if not found, add the material to the output + if(mi == -1U) { + mi = m3d->nummaterial++; + m3d->material = (m3dm_t*)M3D_REALLOC(m3d->material, m3d->nummaterial + * sizeof(m3dm_t)); + if(!m3d->material) { + throw DeadlyExportError( "memory allocation error" ); + } + m3d->material[mi].name = _m3d_safestr((char*)&name.data, 0); + m3d->material[mi].numprop = 0; + m3d->material[mi].prop = NULL; + // iterate through the material property table and see what we got + for(k = 0; + k < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); + k++) { + if(m3d_propertytypes[k].format == m3dpf_map) + continue; + if(aiProps[k].pKey) { + switch(m3d_propertytypes[k].format) { + case m3dpf_color: + if(mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, c) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, mkColor(&c)); + break; + case m3dpf_float: + if(mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, f) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, + /* not (uint32_t)f, because we don't want to convert + * it, we want to see it as 32 bits of memory */ + *((uint32_t*)&f)); + break; + case m3dpf_uint8: + if(mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, j) == AI_SUCCESS) { + // special conversion for illumination model property + if(m3d_propertytypes[k].id == m3dp_il) { + switch(j) { + case aiShadingMode_NoShading: j = 0; break; + case aiShadingMode_Phong: j = 2; break; + default: j = 1; break; + } + } + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, j); + } + break; + default: + if(mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, j) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, j); + break; + } + } + if(aiTxProps[k].pKey && + mat->GetTexture((aiTextureType)aiTxProps[k].type, + aiTxProps[k].index, &name, NULL, NULL, NULL, + NULL, NULL) == AI_SUCCESS) { + for(j = name.length-1; j > 0 && name.data[j]!='.'; j++); + if(j && name.data[j]=='.' && + (name.data[j+1]=='p' || name.data[j+1]=='P') && + (name.data[j+1]=='n' || name.data[j+1]=='N') && + (name.data[j+1]=='g' || name.data[j+1]=='G')) + name.data[j]=0; + // do we have this texture saved already? + fn = _m3d_safestr((char*)&name.data, 0); + for(j = 0, i = -1U; j < m3d->numtexture; j++) + if(!strcmp(fn, m3d->texture[j].name)) { + i = j; + free(fn); + break; + } + if(i == -1U) { + i = m3d->numtexture++; + m3d->texture = (m3dtx_t*)M3D_REALLOC( + m3d->texture, + m3d->numtexture * sizeof(m3dtx_t)); + if(!m3d->texture) { + throw DeadlyExportError( "memory allocation error" ); + } + // we don't need the texture itself, only its name + m3d->texture[i].name = fn; + m3d->texture[i].w = 0; + m3d->texture[i].h = 0; + m3d->texture[i].d = NULL; + } + addProp(&m3d->material[mi], + m3d_propertytypes[k].id + 128, i); + } + } + } + } + return mi; +} + +// ------------------------------------------------------------------------------------------------ +// add a material property to the output +void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value) +{ + unsigned int i; + i = m->numprop++; + m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); + if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); } + m->prop[i].type = type; + m->prop[i].value.num = value; +} + +#endif // ASSIMP_BUILD_NO_M3D_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/M3D/M3DExporter.h b/code/M3D/M3DExporter.h new file mode 100644 index 000000000..dfcff8bc9 --- /dev/null +++ b/code/M3D/M3DExporter.h @@ -0,0 +1,98 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team +Copyright (c) 2019 bzt + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file M3DExporter.h +* @brief Declares the exporter class to write a scene to a Model 3D file +*/ +#ifndef AI_M3DEXPORTER_H_INC +#define AI_M3DEXPORTER_H_INC + +#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER + +#include "m3d.h" + +#include +//#include +#include // StreamWriterLE +#include // DeadlyExportError + +#include // shared_ptr + +struct aiScene; +struct aiNode; +struct aiMaterial; +struct aiFace; + +namespace Assimp +{ + class IOSystem; + class IOStream; + class ExportProperties; + + // --------------------------------------------------------------------- + /** Helper class to export a given scene to an M3D file. */ + // --------------------------------------------------------------------- + class M3DExporter + { + public: + /// Constructor for a specific scene to export + M3DExporter(const aiScene* pScene, const ExportProperties* pProperties); + // call this to do the actual export + void doExport(const char* pFile, IOSystem* pIOSystem, bool toAscii); + + private: + const aiScene* mScene; // the scene to export + const ExportProperties* mProperties; // currently unused + std::shared_ptr outfile; // file to write to + m3d_t *m3d; // model for the C library to convert to + + // helper to do the recursive walking + void NodeWalk(const aiNode* pNode, aiMatrix4x4 m); + uint32_t mkColor(aiColor4D* c); + M3D_INDEX addMaterial(const aiMaterial *mat); + void addProp(m3dm_t *m, uint8_t type, uint32_t value); + }; +} + +#endif // ASSIMP_BUILD_NO_M3D_EXPORTER + +#endif // AI_M3DEXPORTER_H_INC diff --git a/code/M3D/M3DImporter.cpp b/code/M3D/M3DImporter.cpp new file mode 100644 index 000000000..76ba51364 --- /dev/null +++ b/code/M3D/M3DImporter.cpp @@ -0,0 +1,734 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team +Copyright (c) 2019 bzt + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER + +#define M3D_IMPLEMENTATION +#define M3D_ASCII + +#include +#include +#include +#include +#include +#include +#include +#include +#include "M3DImporter.h" +#include "M3DMaterials.h" + +// RESOURCES: +// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md +// https://gitlab.com/bztsrc/model3d/blob/master/docs/a3d_format.md + +/* + Unfortunately aiNode has bone structures and meshes too, yet we can't assign + the mesh to a bone aiNode as a skin may refer to several aiNodes. Therefore + I've decided to import into this structure: + + aiScene->mRootNode + | |->mMeshes (all the meshes) + | \->children (empty if there's no skeleton imported, no meshes) + | \->skeleton root aiNode* + | |->bone aiNode + | | \->subbone aiNode + | |->bone aiNode + | | ... + | \->bone aiNode + \->mMeshes[] + \->aiBone, referencing mesh-less aiNodes from above + + * - normally one, but if a model has several skeleton roots, then all of them + are listed in aiScene->mRootNode->children, but all without meshes +*/ + +static const aiImporterDesc desc = { + "Model 3D Importer", + "", + "", + "", + aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, + "m3d a3d" +}; + +// workaround: the SDK expects a C callback, but we want to use Assimp::IOSystem to implement that +extern "C" { + struct Assimp::IOSystem* m3dimporter_pIOHandler; + + unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) { + ai_assert( nullptr != fn ); + ai_assert( nullptr != size ); + std::string file(fn); + std::unique_ptr pStream( m3dimporter_pIOHandler->Open( file, "rb")); + size_t fileSize = pStream->FileSize(); + // should be allocated with malloc(), because the library will call free() to deallocate + unsigned char *data = (unsigned char*)malloc(fileSize); + if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) { + pStream.reset(); + *size = 0; + // don't throw a deadly exception, it's not fatal if we can't read an external asset + return nullptr; + } + pStream.reset(); + *size = (int)fileSize; + return data; + } +} + +namespace Assimp { + +using namespace std; + +// ------------------------------------------------------------------------------------------------ +// Default constructor +M3DImporter::M3DImporter() +: mScene(nullptr) +, m3d(nullptr) { } + +// ------------------------------------------------------------------------------------------------ +// Destructor. +M3DImporter::~M3DImporter() {} + +// ------------------------------------------------------------------------------------------------ +// Returns true, if file is a binary or ASCII Model 3D file. +bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool checkSig) const { + const std::string extension = GetExtension(pFile); + + if (extension == "m3d" || extension == "a3d") + return true; + else if (!extension.length() || checkSig) { + if (!pIOHandler) { + return true; + } + /* + * don't use CheckMagicToken because that checks with swapped bytes too, leading to false + * positives. This magic is not uint32_t, but char[4], so memcmp is the best way + + const char* tokens[] = {"3DMO", "3dmo"}; + return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4); + */ + std::unique_ptr pStream (pIOHandler->Open(pFile, "rb")); + unsigned char data[4]; + if(4 != pStream->Read(data,1,4)) { + return false; + } + return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */; + } + return false; +} + +// ------------------------------------------------------------------------------------------------ +const aiImporterDesc* M3DImporter::GetInfo() const { + return &desc; +} + +// ------------------------------------------------------------------------------------------------ +// Model 3D import implementation +void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) { + // Read file into memory + std::unique_ptr pStream( pIOHandler->Open( file, "rb")); + if( !pStream.get() ) { + throw DeadlyImportError( "Failed to open file " + file + "." ); + } + + // Get the file-size and validate it, throwing an exception when fails + size_t fileSize = pStream->FileSize(); + if( fileSize < 8 ) { + throw DeadlyImportError( "M3D-file " + file + " is too small." ); + } + unsigned char data[fileSize]; + if(fileSize != pStream->Read(data,1,fileSize)) { + throw DeadlyImportError( "Failed to read the file " + file + "." ); + } + + // Get the path for external assets + std::string folderName( "./" ); + std::string::size_type pos = file.find_last_of( "\\/" ); + if ( pos != std::string::npos ) { + folderName = file.substr( 0, pos ); + if ( !folderName.empty() ) { + pIOHandler->PushDirectory( folderName ); + } + } + // pass this IOHandler to the C callback + m3dimporter_pIOHandler = pIOHandler; + + //DefaultLogger::create("/dev/stderr", Logger::VERBOSE); + ASSIMP_LOG_DEBUG_F("M3D: loading ", file); + + // let the C SDK do the hard work for us + m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr); + m3dimporter_pIOHandler = nullptr; + if( !m3d ) { + throw DeadlyImportError( "Unable to parse " + file + " as M3D." ); + } + + // create the root node + pScene->mRootNode = new aiNode; + pScene->mRootNode->mName = aiString(std::string(std::string(m3d->name))); + pScene->mRootNode->mTransformation = aiMatrix4x4(); + pScene->mRootNode->mNumChildren = 0; + mScene = pScene; + + ASSIMP_LOG_DEBUG("M3D: root node " + std::string(m3d->name)); + + // now we just have to fill up the Assimp structures in pScene + importMaterials(); + importTextures(); + importBones(-1U, pScene->mRootNode); + importMeshes(); + importAnimations(); + + // we don't need the SDK's version any more + m3d_free(m3d); + + // Pop directory stack + if ( pIOHandler->StackSize() > 0 ) { + pIOHandler->PopDirectory(); + } +} + +// ------------------------------------------------------------------------------------------------ +// convert materials. properties are converted using a static table in M3DMaterials.h +void M3DImporter::importMaterials() +{ + unsigned int i, j, k, l, n; + m3dm_t *m; + aiString name = aiString(AI_DEFAULT_MATERIAL_NAME); + aiColor4D c; + ai_real f; + + ai_assert(mScene != nullptr); + ai_assert(m3d != nullptr); + + mScene->mNumMaterials = m3d->nummaterial + 1; + mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ]; + + ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials); + + // add a default material as first + aiMaterial* mat = new aiMaterial; + mat->AddProperty( &name, AI_MATKEY_NAME ); + c.a = 1.0; c.b = c.g = c.r = 0.6; + mat->AddProperty( &c, 1, AI_MATKEY_COLOR_DIFFUSE); + mScene->mMaterials[0] = mat; + + for(i = 0; i < m3d->nummaterial; i++) { + m = &m3d->material[i]; + aiMaterial* mat = new aiMaterial; + name.Set(std::string(m->name)); + mat->AddProperty( &name, AI_MATKEY_NAME ); + for(j = 0; j < m->numprop; j++) { + // look up property type + // 0 - 127 scalar values, + // 128 - 255 the same properties but for texture maps + k = 256; + for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) + if(m->prop[j].type == m3d_propertytypes[l].id || + m->prop[j].type == m3d_propertytypes[l].id + 128) { + k = l; + break; + } + // should never happen, but be safe than sorry + if(k == 256) continue; + + // scalar properties + if(m->prop[j].type < 128 && aiProps[k].pKey) { + switch(m3d_propertytypes[k].format) { + case m3dpf_color: + c = mkColor(m->prop[j].value.color); + mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + case m3dpf_float: + f = m->prop[j].value.fnum; + mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + default: + n = m->prop[j].value.num; + if(m->prop[j].type == m3dp_il) { + switch(n) { + case 0: n = aiShadingMode_NoShading; break; + case 2: n = aiShadingMode_Phong; break; + default: n = aiShadingMode_Gouraud; break; + } + } + mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + } + } + // texture map properties + if(m->prop[j].type >= 128 && aiTxProps[k].pKey && + // extra check, should never happen, do we have the refered texture? + m->prop[j].value.textureid < m3d->numtexture && + m3d->texture[m->prop[j].value.textureid].name) { + name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); + mat->AddProperty(&name, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + n = 0; + mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); + } + } + mScene->mMaterials[i + 1] = mat; + } +} + +// ------------------------------------------------------------------------------------------------ +// import textures, this is the simplest of all +void M3DImporter::importTextures() +{ + unsigned int i; + m3dtx_t *t; + + ai_assert(mScene != nullptr); + ai_assert(m3d != nullptr); + + mScene->mNumTextures = m3d->numtexture; + ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures); + + if(!m3d->numtexture) + return; + + mScene->mTextures = new aiTexture*[m3d->numtexture]; + for(i = 0; i < m3d->numtexture; i++) { + t = &m3d->texture[i]; + aiTexture *tx = new aiTexture; + strcpy(tx->achFormatHint, "rgba8888"); + tx->mFilename = aiString(std::string(t->name) + ".png"); + tx->mWidth = t->w; + tx->mHeight = t->h; + tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ]; + memcpy(tx->pcData, t->d, tx->mWidth*tx->mHeight*4); + mScene->mTextures[i] = tx; + } +} + +// ------------------------------------------------------------------------------------------------ +// this is tricky. M3D has a global vertex and UV list, and faces are indexing them +// individually. In assimp there're per mesh vertex and UV lists, and they must be +// indexed simultaneously. +void M3DImporter::importMeshes() +{ + unsigned int i, j, k, l, numpoly = 3, lastMat = -2U; + std::vector *meshes = new std::vector(); + std::vector *faces = nullptr; + std::vector *vertices = nullptr; + std::vector *normals = nullptr; + std::vector *texcoords = nullptr; + std::vector *colors = nullptr; + std::vector *vertexids = nullptr; + aiMesh *pMesh = nullptr; + + ai_assert(mScene != nullptr); + ai_assert(m3d != nullptr); + ai_assert(mScene->mRootNode != nullptr); + + ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface); + + for(i = 0; i < m3d->numface; i++) { + // we must switch mesh if material changes + if(lastMat != m3d->face[i].materialid) { + lastMat = m3d->face[i].materialid; + if(pMesh && vertices->size() && faces->size()) { + populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); + meshes->push_back(pMesh); + delete vertexids; // this is not stored in pMesh, just to collect bone vertices + } + pMesh = new aiMesh; + pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + pMesh->mMaterialIndex = lastMat + 1; + faces = new std::vector(); + vertices = new std::vector(); + normals = new std::vector(); + texcoords = new std::vector(); + colors = new std::vector(); + vertexids = new std::vector(); + } + // add a face to temporary vector + aiFace *pFace = new aiFace; + pFace->mNumIndices = numpoly; + pFace->mIndices = new unsigned int[numpoly]; + for(j = 0; j < numpoly; j++) { + aiVector3D pos, uv, norm; + k = vertices->size(); + pFace->mIndices[j] = k; + l = m3d->face[i].vertex[j]; + pos.x = m3d->vertex[l].x; + pos.y = m3d->vertex[l].y; + pos.z = m3d->vertex[l].z; + vertices->push_back(pos); + colors->push_back(mkColor(m3d->vertex[l].color)); + // add a bone to temporary vector + if(m3d->vertex[l].skinid != -1U &&m3d->vertex[l].skinid != -2U && m3d->skin && m3d->bone) { + // this is complicated, because M3D stores a list of bone id / weight pairs per + // vertex but assimp uses lists of local vertex id/weight pairs per local bone list + vertexids->push_back(l); + } + l = m3d->face[i].texcoord[j]; + if(l != -1U) { + uv.x = m3d->tmap[l].u; + uv.y = m3d->tmap[l].v; + uv.z = 0.0; + texcoords->push_back(uv); + } + l = m3d->face[i].normal[j]; + if(l != -1U) { + norm.x = m3d->vertex[l].x; + norm.y = m3d->vertex[l].y; + norm.z = m3d->vertex[l].z; + normals->push_back(norm); + } + } + faces->push_back(*pFace); + delete pFace; + } + // if there's data left in the temporary vectors, flush them + if(pMesh && vertices->size() && faces->size()) { + populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); + meshes->push_back(pMesh); + } + + // create global mesh list in scene + mScene->mNumMeshes = meshes->size(); + mScene->mMeshes = new aiMesh*[mScene->mNumMeshes]; + std::copy(meshes->begin(), meshes->end(), mScene->mMeshes); + + // create mesh indeces in root node + mScene->mRootNode->mNumMeshes = meshes->size(); + mScene->mRootNode->mMeshes = new unsigned int[meshes->size()]; + for(i = 0; i < meshes->size(); i++) { + mScene->mRootNode->mMeshes[i] = i; + } + + delete meshes; + if(faces) delete faces; + if(vertices) delete vertices; + if(normals) delete normals; + if(texcoords) delete texcoords; + if(colors) delete colors; + if(vertexids) delete vertexids; +} + +// ------------------------------------------------------------------------------------------------ +// a reentrant node parser. Otherwise this is simple +void M3DImporter::importBones(unsigned int parentid, aiNode *pParent) +{ + unsigned int i, n; + + ai_assert(pParent != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d != nullptr); + + ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid); + + for(n = 0, i = parentid + 1; i < m3d->numbone; i++) + if(m3d->bone[i].parent == parentid) n++; + pParent->mChildren = new aiNode*[n]; + + for(i = parentid + 1; i < m3d->numbone; i++) { + if(m3d->bone[i].parent == parentid) { + aiNode *pChild = new aiNode; + pChild->mParent = pParent; + pChild->mName = aiString(std::string(m3d->bone[i].name)); + convertPose(&pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori); + pChild->mNumChildren = 0; + pParent->mChildren[pParent->mNumChildren] = pChild; + pParent->mNumChildren++; + importBones(i, pChild); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// this is another headache. M3D stores list of changed bone id/position/orientation triplets and +// a timestamp per frame, but assimp needs timestamp and lists of position, orientation lists per +// bone, so we have to convert between the two conceptually different representation forms +void M3DImporter::importAnimations() +{ + unsigned int i, j, k, l, n, pos, ori; + double t; + m3da_t *a; + + ai_assert(mScene != nullptr); + ai_assert(m3d != nullptr); + + mScene->mNumAnimations = m3d->numaction; + + ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations); + + if(!m3d->numaction || !m3d->numbone) + return; + + mScene->mAnimations = new aiAnimation*[m3d->numaction]; + for(i = 0; i < m3d->numaction; i++) { + a = &m3d->action[i]; + aiAnimation *pAnim = new aiAnimation; + pAnim->mName = aiString(std::string(a->name)); + pAnim->mDuration = ((double)a->durationmsec) / 10; + pAnim->mTicksPerSecond = 100; + // now we know how many bones are referenced in this animation + pAnim->mNumChannels = m3d->numbone; + pAnim->mChannels = new aiNodeAnim*[pAnim->mNumChannels]; + for(l = 0; l < m3d->numbone; l++) { + pAnim->mChannels[l] = new aiNodeAnim; + pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name)); + // now n is the size of positions / orientations arrays + pAnim->mChannels[l]->mNumPositionKeys = pAnim->mChannels[l]->mNumRotationKeys = a->numframe; + pAnim->mChannels[l]->mPositionKeys = new aiVectorKey[a->numframe]; + pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe]; + pos = m3d->bone[l].pos; + ori = m3d->bone[l].ori; + for(j = n = 0; j < a->numframe; j++) { + t = ((double)a->frame[j].msec) / 10; + for(k = 0; k < a->frame[j].numtransform; k++) { + if(a->frame[j].transform[k].boneid == l) { + pos = a->frame[j].transform[k].pos; + ori = a->frame[j].transform[k].ori; + } + } + m3dv_t *v = &m3d->vertex[pos]; + m3dv_t *q = &m3d->vertex[ori]; + pAnim->mChannels[l]->mPositionKeys[j].mTime = t; + pAnim->mChannels[l]->mPositionKeys[j].mValue.x = v->x; + pAnim->mChannels[l]->mPositionKeys[j].mValue.y = v->y; + pAnim->mChannels[l]->mPositionKeys[j].mValue.z = v->z; + pAnim->mChannels[l]->mRotationKeys[j].mTime = t; + pAnim->mChannels[l]->mRotationKeys[j].mValue.w = q->w; + pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x; + pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y; + pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z; + }// foreach frame + }// foreach bones + mScene->mAnimations[i] = pAnim; + } +} + +// ------------------------------------------------------------------------------------------------ +// convert uint32_t into aiColor4D +aiColor4D M3DImporter::mkColor(uint32_t c) { + aiColor4D color; + color.a = ((float)((c >> 24)&0xff)) / 255; + color.b = ((float)((c >> 16)&0xff)) / 255; + color.g = ((float)((c >> 8)&0xff)) / 255; + color.r = ((float)((c >> 0)&0xff)) / 255; + return color; +} + +// ------------------------------------------------------------------------------------------------ +// convert a position id and orientation id into a 4 x 4 transformation matrix +void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) +{ + ai_assert(m != nullptr); + ai_assert(m3d != nullptr); + ai_assert(posid != -1U && posid < m3d->numvertex); + ai_assert(orientid != -1U && orientid < m3d->numvertex); + m3dv_t *p = &m3d->vertex[posid]; + m3dv_t *q = &m3d->vertex[orientid]; + + /* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */ + if(q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) { + m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; + m->a1 = m->b2 = m->c3 = -1.0; + } else { + m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -1e-7 && m->a1 < 1e-7) m->a1 = 0.0; + m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -1e-7 && m->a2 < 1e-7) m->a2 = 0.0; + m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -1e-7 && m->a3 < 1e-7) m->a3 = 0.0; + m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -1e-7 && m->b1 < 1e-7) m->b1 = 0.0; + m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -1e-7 && m->b2 < 1e-7) m->b2 = 0.0; + m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -1e-7 && m->b3 < 1e-7) m->b3 = 0.0; + m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -1e-7 && m->c1 < 1e-7) m->c1 = 0.0; + m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -1e-7 && m->c2 < 1e-7) m->c2 = 0.0; + m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -1e-7 && m->c3 < 1e-7) m->c3 = 0.0; + } + + /* set translation */ + m->a4 = p->x; m->b4 = p->y; m->c4 = p->z; + + m->d1 = 0; m->d2 = 0; m->d3 = 0; m->d4 = 1; +} + +// ------------------------------------------------------------------------------------------------ +// find a node by name +aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) +{ + unsigned int i; + + ai_assert(pNode != nullptr); + ai_assert(mScene != nullptr); + + if(pNode->mName == name) + return pNode; + for(i = 0; i < pNode->mNumChildren; i++) { + aiNode *pChild = findNode(pNode->mChildren[i], name); + if(pChild) return pChild; + } + return nullptr; +} + +// ------------------------------------------------------------------------------------------------ +// fills up offsetmatrix in mBones +void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) +{ + ai_assert(pNode != nullptr); + ai_assert(mScene != nullptr); + + if(pNode->mParent) { + calculateOffsetMatrix(pNode->mParent, m); + *m *= pNode->mTransformation; + } else { + *m = pNode->mTransformation; + } +} + +// ------------------------------------------------------------------------------------------------ +// because M3D has a global mesh, global vertex ids and stores materialid on the face, we need +// temporary lists to collect data for an aiMesh, which requires local arrays and local indeces +// this function fills up an aiMesh with those temporary lists +void M3DImporter::populateMesh(aiMesh *pMesh, std::vector *faces, std::vector *vertices, + std::vector *normals, std::vector *texcoords, std::vector *colors, + std::vector *vertexids) { + unsigned int i, j, k, s; + aiNode *pNode; + + ai_assert(pMesh != nullptr); + ai_assert(faces != nullptr); + ai_assert(vertices != nullptr); + ai_assert(normals != nullptr); + ai_assert(texcoords != nullptr); + ai_assert(colors != nullptr); + ai_assert(vertexids != nullptr); + ai_assert(m3d != nullptr); + + ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(), + " numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone); + + if(vertices->size() && faces->size()) { + pMesh->mNumFaces = faces->size(); + pMesh->mFaces = new aiFace[pMesh->mNumFaces]; + std::copy(faces->begin(), faces->end(), pMesh->mFaces); + pMesh->mNumVertices = vertices->size(); + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + std::copy(vertices->begin(), vertices->end(), pMesh->mVertices); + if(normals->size() == vertices->size()) { + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + std::copy(normals->begin(), normals->end(), pMesh->mNormals); + } + if(texcoords->size() == vertices->size()) { + pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices]; + std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]); + pMesh->mNumUVComponents[0] = 2; + } + if(colors->size() == vertices->size()) { + pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; + std::copy(colors->begin(), colors->end(), pMesh->mColors[0]); + } + // this is complicated, because M3D stores a list of bone id / weight pairs per + // vertex but assimp uses lists of local vertex id/weight pairs per local bone list + pMesh->mNumBones = m3d->numbone; + /* we need aiBone with mOffsetMatrix for bones without weights as well */ + if(pMesh->mNumBones) { + pMesh->mBones = new aiBone*[pMesh->mNumBones]; + for(i = 0; i < m3d->numbone; i++) { + pMesh->mBones[i] = new aiBone; + pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name)); + pMesh->mBones[i]->mNumWeights = 0; + pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName); + if(pNode) { + calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix); + pMesh->mBones[i]->mOffsetMatrix.Inverse(); + } else + pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4(); + } + if(vertexids->size()) { + // first count how many vertices we have per bone + for(i = 0; i < vertexids->size(); i++) { + s = m3d->vertex[vertexids->at(i)].skinid; + if(s != -1U && s!= -2U) { + for(k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { + aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); + for(j = 0; j < pMesh->mNumBones; j++) { + if(pMesh->mBones[j]->mName == name) { + pMesh->mBones[j]->mNumWeights++; + break; + } + } + } + } + } + // allocate mWeights + for(j = 0; j < pMesh->mNumBones; j++) { + aiBone *pBone = pMesh->mBones[j]; + if(pBone->mNumWeights) { + pBone->mWeights = new aiVertexWeight[pBone->mNumWeights]; + pBone->mNumWeights = 0; + } + } + // fill up with data + for(i = 0; i < vertexids->size(); i++) { + s = m3d->vertex[vertexids->at(i)].skinid; + if(s != -1U && s!= -2U) { + for(k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { + aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); + for(j = 0; j < pMesh->mNumBones; j++) { + if(pMesh->mBones[j]->mName == name) { + aiBone *pBone = pMesh->mBones[j]; + pBone->mWeights[pBone->mNumWeights].mVertexId = i; + pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k]; + pBone->mNumWeights++; + break; + } + } + } // foreach skin + } + } // foreach vertexids + } + } + } +} + +// ------------------------------------------------------------------------------------------------ + +} // Namespace Assimp + +#endif // !! ASSIMP_BUILD_NO_M3D_IMPORTER diff --git a/code/M3D/M3DImporter.h b/code/M3D/M3DImporter.h new file mode 100644 index 000000000..06cc757b6 --- /dev/null +++ b/code/M3D/M3DImporter.h @@ -0,0 +1,106 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team +Copyright (c) 2019 bzt + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file M3DImporter.h +* @brief Declares the importer class to read a scene from a Model 3D file +*/ +#ifndef AI_M3DIMPORTER_H_INC +#define AI_M3DIMPORTER_H_INC + +#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER + +#include "m3d.h" +#include +#include +#include + +struct aiMesh; +struct aiNode; +struct aiMaterial; +struct aiFace; + +namespace Assimp { + +class M3DImporter : public BaseImporter { +public: + /// \brief Default constructor + M3DImporter(); + + /// \brief Destructor + ~M3DImporter(); + +public: + /// \brief Returns whether the class can handle the format of the given file. + /// \remark See BaseImporter::CanRead() for details. + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + +private: + aiScene* mScene; // the scene to import to + m3d_t *m3d; // model for the C library to convert from + + //! \brief Appends the supported extension. + const aiImporterDesc* GetInfo () const; + + //! \brief File import implementation. + void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + + void importMaterials(); + void importTextures(); + void importMeshes(); + void importBones(unsigned int parentid, aiNode *pParent); + void importAnimations(); + + // helper functions + aiColor4D mkColor(uint32_t c); + void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); + aiNode *findNode(aiNode *pNode, aiString name); + void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); + void populateMesh(aiMesh *pMesh, std::vector *faces, std::vector *verteces, + std::vector *normals, std::vector *texcoords, std::vector *colors, + std::vector *vertexids); +}; + +} // Namespace Assimp + +#endif // ASSIMP_BUILD_NO_M3D_IMPORTER + +#endif // AI_M3DIMPORTER_H_INC diff --git a/code/M3D/M3DMaterials.h b/code/M3D/M3DMaterials.h new file mode 100644 index 000000000..86a802021 --- /dev/null +++ b/code/M3D/M3DMaterials.h @@ -0,0 +1,106 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team +Copyright (c) 2019 bzt + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file M3DMaterials.h +* @brief Declares the Assimp and Model 3D file material type relations +*/ +#ifndef AI_M3DMATERIALS_H_INC +#define AI_M3DMATERIALS_H_INC + +/* + * In the m3d.h header, there's a static array which defines the material + * properties, called m3d_propertytypes. These must have the same size, and + * list the matching Assimp materials for those properties. Used by both the + * M3DImporter and the M3DExporter, so you have to define these relations + * only once. D.R.Y. and K.I.S.S. + */ +typedef struct { + char *pKey; + unsigned int type; + unsigned int index; +} aiMatProp; + +/* --- Scalar Properties --- !!!!! must match m3d_propertytypes !!!!! */ +static aiMatProp aiProps[] = { + { AI_MATKEY_COLOR_DIFFUSE }, /* m3dp_Kd */ + { AI_MATKEY_COLOR_AMBIENT }, /* m3dp_Ka */ + { AI_MATKEY_COLOR_SPECULAR }, /* m3dp_Ks */ + { AI_MATKEY_SHININESS }, /* m3dp_Ns */ + { AI_MATKEY_COLOR_EMISSIVE }, /* m3dp_Ke */ + { AI_MATKEY_COLOR_REFLECTIVE }, /* m3dp_Tf */ + { AI_MATKEY_BUMPSCALING }, /* m3dp_Km */ + { AI_MATKEY_OPACITY }, /* m3dp_d */ + { AI_MATKEY_SHADING_MODEL }, /* m3dp_il */ + + { NULL, 0, 0 }, /* m3dp_Pr */ + { AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */ + { NULL, 0, 0 }, /* m3dp_Ps */ + { AI_MATKEY_REFRACTI }, /* m3dp_Ni */ + { NULL, 0, 0 }, + { NULL, 0, 0 }, + { NULL, 0, 0 }, + { NULL, 0, 0 } +}; + +/* --- Texture Map Properties --- !!!!! must match m3d_propertytypes !!!!! */ +static aiMatProp aiTxProps[] = { + { AI_MATKEY_TEXTURE_DIFFUSE(0) }, /* m3dp_map_Kd */ + { AI_MATKEY_TEXTURE_AMBIENT(0) }, /* m3dp_map_Ka */ + { AI_MATKEY_TEXTURE_SPECULAR(0) }, /* m3dp_map_Ks */ + { AI_MATKEY_TEXTURE_SHININESS(0) }, /* m3dp_map_Ns */ + { AI_MATKEY_TEXTURE_EMISSIVE(0) }, /* m3dp_map_Ke */ + { NULL, 0, 0 }, /* m3dp_map_Tf */ + { AI_MATKEY_TEXTURE_HEIGHT(0) }, /* m3dp_bump */ + { AI_MATKEY_TEXTURE_OPACITY(0) }, /* m3dp_map_d */ + { AI_MATKEY_TEXTURE_REFLECTION(0) }, /* m3dp_refl */ + + { AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS,0) },/* m3dp_map_Pr */ + { AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */ + { NULL, 0, 0 }, /* m3dp_map_Ps */ + { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */ + { NULL, 0, 0 }, + { NULL, 0, 0 }, + { NULL, 0, 0 }, + { NULL, 0, 0 } +}; + +#endif // AI_M3DMATERIALS_H_INC diff --git a/code/M3D/m3d.h b/code/M3D/m3d.h new file mode 120000 index 000000000..bb58a6d64 --- /dev/null +++ b/code/M3D/m3d.h @@ -0,0 +1 @@ +../../../m3d.h \ No newline at end of file diff --git a/test/models/M3D/README.md b/test/models/M3D/README.md new file mode 100644 index 000000000..144d1ec64 --- /dev/null +++ b/test/models/M3D/README.md @@ -0,0 +1,14 @@ +Model 3D Samples +================ + + aliveai_character.m3d - from Minetest aliveai mod (textures, animations, original 47k, m3d 2.5k) + cube.m3d - smallest possible example, 119 bytes only + cube_normals.m3d - cube with normal vectors, 159 bytes + cube_usemtl.m3d - converted from Assimp sample OBJ by the same name, cube with materials + cube_with_vertexcolors.m3d - converted from Assimp sample OBJ by the same name, cube with vertex colors + cube_with_vertexcolors.a3d - same, but saved in ASCII variant with Windows line endings (\r\n) + mobs_dwarves_character.m3d - from Minetest mobs_dwarves mod (with Assimp artifacts converted perfectly too...) + suzanne.m3d - exported from Blender (monkey face, with normals and texture UVs and materials) + WusonBlitz0.m3d - from Assimp sample by the same name (was 87k, triangle mesh) with int8 coordinates, minor quality degradation + WusonBlitz1.m3d - same, but uses int16 coordinates (no noticable difference to the original, but just 35k) + WusonBlitz2.m3d - same, but with 32 bit floating point numbers (same precision as the original, half the file size, 42k) diff --git a/test/models/M3D/WusonBlitz0.m3d b/test/models/M3D/WusonBlitz0.m3d new file mode 100644 index 0000000000000000000000000000000000000000..29a397b7915ba06070c728840890f2099b3d001e GIT binary patch literal 29223 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 literal 0 HcmV?d00001 diff --git a/test/models/M3D/WusonBlitz1.m3d b/test/models/M3D/WusonBlitz1.m3d new file mode 100644 index 0000000000000000000000000000000000000000..3661252576ba84b860410277330b71d6fb4fbf08 GIT binary patch literal 35058 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 literal 0 HcmV?d00001 diff --git a/test/models/M3D/WusonBlitz2.m3d b/test/models/M3D/WusonBlitz2.m3d new file mode 100644 index 0000000000000000000000000000000000000000..682876816c37b3d05a5aba27d5267661759bf692 GIT binary patch literal 42228 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 literal 0 HcmV?d00001 diff --git a/test/models/M3D/suzanne.m3d b/test/models/M3D/suzanne.m3d new file mode 100644 index 0000000000000000000000000000000000000000..9bc64d7d787a4cd7c135af96c71cc0c6d8c463f5 GIT binary patch literal 11645 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 W?QqGf)qqRRMyLE2$&$JCoc{se_CU4( literal 0 HcmV?d00001