Some cleanup of M3D support
Wrap the m3d.h header Note: C++11 support required to use in a threaded environment Fix export memory leak (although exporter apopears to be unused) Apply clangformat.pull/2805/head
parent
6117c3f589
commit
e668eead19
|
@ -411,6 +411,8 @@ ADD_ASSIMP_IMPORTER( M3D
|
||||||
M3D/M3DMaterials.h
|
M3D/M3DMaterials.h
|
||||||
M3D/M3DImporter.h
|
M3D/M3DImporter.h
|
||||||
M3D/M3DImporter.cpp
|
M3D/M3DImporter.cpp
|
||||||
|
M3D/M3DWrapper.h
|
||||||
|
M3D/M3DWrapper.cpp
|
||||||
M3D/m3d.h
|
M3D/m3d.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -55,17 +55,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <assimp/version.h> // aiGetVersion
|
|
||||||
#include <assimp/IOSystem.hpp>
|
|
||||||
#include <assimp/Exporter.hpp>
|
|
||||||
#include <assimp/DefaultLogger.hpp>
|
|
||||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
|
||||||
#include <assimp/Exceptional.h> // DeadlyExportError
|
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||||
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
#include <assimp/material.h> // aiTextureType
|
#include <assimp/material.h> // aiTextureType
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/version.h> // aiGetVersion
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
#include "M3DExporter.h"
|
#include "M3DExporter.h"
|
||||||
#include "M3DMaterials.h"
|
#include "M3DMaterials.h"
|
||||||
|
#include "M3DWrapper.h"
|
||||||
|
|
||||||
// RESOURCES:
|
// RESOURCES:
|
||||||
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
||||||
|
@ -80,7 +82,171 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation
|
* - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation
|
||||||
* triplets, instead of per bone timestamp + lists)
|
* triplets, instead of per bone timestamp + lists)
|
||||||
*/
|
*/
|
||||||
using namespace Assimp;
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Conversion functions
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// helper to add a vertex (private to NodeWalk)
|
||||||
|
m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) {
|
||||||
|
if (v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
|
||||||
|
if (v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
|
||||||
|
if (v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
|
||||||
|
if (v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
|
||||||
|
vrtx = (m3dv_t *)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
|
||||||
|
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
|
||||||
|
*idx = *numvrtx;
|
||||||
|
(*numvrtx)++;
|
||||||
|
return vrtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// helper to add a tmap (private to NodeWalk)
|
||||||
|
m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx) {
|
||||||
|
tmap = (m3dti_t *)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
|
||||||
|
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
|
||||||
|
*idx = *numtmap;
|
||||||
|
(*numtmap)++;
|
||||||
|
return tmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// convert aiColor4D into uint32_t
|
||||||
|
uint32_t 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 property to the output
|
||||||
|
void 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// add a material to the output
|
||||||
|
M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) {
|
||||||
|
unsigned int 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 (unsigned int 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) {
|
||||||
|
unsigned int k;
|
||||||
|
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 < 15; k++) {
|
||||||
|
unsigned int j;
|
||||||
|
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) {
|
||||||
|
unsigned int i;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -91,8 +257,7 @@ namespace Assimp {
|
||||||
const char *pFile,
|
const char *pFile,
|
||||||
IOSystem *pIOSystem,
|
IOSystem *pIOSystem,
|
||||||
const aiScene *pScene,
|
const aiScene *pScene,
|
||||||
const ExportProperties* pProperties
|
const ExportProperties *pProperties) {
|
||||||
){
|
|
||||||
// initialize the exporter
|
// initialize the exporter
|
||||||
M3DExporter exporter(pScene, pProperties);
|
M3DExporter exporter(pScene, pProperties);
|
||||||
|
|
||||||
|
@ -117,21 +282,17 @@ namespace Assimp {
|
||||||
exporter.doExport(pFile, pIOSystem, true);
|
exporter.doExport(pFile, pIOSystem, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace Assimp
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties )
|
M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) :
|
||||||
: mScene(pScene)
|
mScene(pScene),
|
||||||
, mProperties(pProperties)
|
mProperties(pProperties),
|
||||||
, outfile()
|
outfile() {}
|
||||||
, m3d(nullptr) { }
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void M3DExporter::doExport(
|
void M3DExporter::doExport(
|
||||||
const char *pFile,
|
const char *pFile,
|
||||||
IOSystem *pIOSystem,
|
IOSystem *pIOSystem,
|
||||||
bool toAscii
|
bool toAscii) {
|
||||||
){
|
|
||||||
// TODO: convert mProperties into M3D_EXP_* flags
|
// TODO: convert mProperties into M3D_EXP_* flags
|
||||||
(void)mProperties;
|
(void)mProperties;
|
||||||
|
|
||||||
|
@ -141,8 +302,7 @@ void M3DExporter::doExport (
|
||||||
throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile));
|
throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
// use malloc() here because m3d_free() will call free()
|
M3DWrapper m3d;
|
||||||
m3d = (m3d_t*)calloc(1, sizeof(m3d_t));
|
|
||||||
if (!m3d) {
|
if (!m3d) {
|
||||||
throw DeadlyExportError("memory allocation error");
|
throw DeadlyExportError("memory allocation error");
|
||||||
}
|
}
|
||||||
|
@ -150,13 +310,12 @@ void M3DExporter::doExport (
|
||||||
|
|
||||||
// Create a model from assimp structures
|
// Create a model from assimp structures
|
||||||
aiMatrix4x4 m;
|
aiMatrix4x4 m;
|
||||||
NodeWalk(mScene->mRootNode, m);
|
NodeWalk(m3d, mScene->mRootNode, m);
|
||||||
|
|
||||||
// serialize the structures
|
// serialize the structures
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT,
|
unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size);
|
||||||
M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size);
|
|
||||||
m3d_free(m3d);
|
|
||||||
if (!output || size < 8) {
|
if (!output || size < 8) {
|
||||||
throw DeadlyExportError("unable to serialize into Model 3D");
|
throw DeadlyExportError("unable to serialize into Model 3D");
|
||||||
}
|
}
|
||||||
|
@ -169,37 +328,9 @@ void M3DExporter::doExport (
|
||||||
outfile.reset();
|
outfile.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// helper to add a vertex (private to NodeWalk)
|
|
||||||
m3dv_t *M3DExporter::AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx)
|
|
||||||
{
|
|
||||||
if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
|
|
||||||
if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
|
|
||||||
if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
|
|
||||||
if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
|
|
||||||
vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
|
|
||||||
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
|
|
||||||
*idx = *numvrtx;
|
|
||||||
(*numvrtx)++;
|
|
||||||
return vrtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// helper to add a tmap (private to NodeWalk)
|
|
||||||
m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx)
|
|
||||||
{
|
|
||||||
tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
|
|
||||||
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
|
|
||||||
*idx = *numtmap;
|
|
||||||
(*numtmap)++;
|
|
||||||
return tmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// recursive node walker
|
// recursive node walker
|
||||||
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
|
void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4x4 m) {
|
||||||
{
|
|
||||||
aiMatrix4x4 nm = m * pNode->mTransformation;
|
aiMatrix4x4 nm = m * pNode->mTransformation;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pNode->mNumMeshes; i++) {
|
for (unsigned int i = 0; i < pNode->mNumMeshes; i++) {
|
||||||
|
@ -207,7 +338,7 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
|
||||||
unsigned int mi = (M3D_INDEX)-1U;
|
unsigned int mi = (M3D_INDEX)-1U;
|
||||||
if (mScene->mMaterials) {
|
if (mScene->mMaterials) {
|
||||||
// get the material for this mesh
|
// get the material for this mesh
|
||||||
mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]);
|
mi = addMaterial(m3d, mScene->mMaterials[mesh->mMaterialIndex]);
|
||||||
}
|
}
|
||||||
// iterate through the mesh faces
|
// iterate through the mesh faces
|
||||||
for (unsigned int j = 0; j < mesh->mNumFaces; j++) {
|
for (unsigned int j = 0; j < mesh->mNumFaces; j++) {
|
||||||
|
@ -272,149 +403,10 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
|
||||||
}
|
}
|
||||||
// repeat for the children nodes
|
// repeat for the children nodes
|
||||||
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
|
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
|
||||||
NodeWalk(pNode->mChildren[i], nm);
|
NodeWalk(m3d, pNode->mChildren[i], nm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Assimp
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// 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 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(unsigned int 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) {
|
|
||||||
unsigned int k;
|
|
||||||
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 < 15; k++) {
|
|
||||||
unsigned int j;
|
|
||||||
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) {
|
|
||||||
unsigned int i;
|
|
||||||
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_M3D_EXPORTER
|
||||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
||||||
|
|
|
@ -48,8 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
|
||||||
|
|
||||||
#include "m3d.h"
|
|
||||||
|
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
//#include <assimp/material.h>
|
//#include <assimp/material.h>
|
||||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
|
@ -68,6 +66,8 @@ namespace Assimp
|
||||||
class IOStream;
|
class IOStream;
|
||||||
class ExportProperties;
|
class ExportProperties;
|
||||||
|
|
||||||
|
class M3DWrapper;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
/** Helper class to export a given scene to an M3D file. */
|
/** Helper class to export a given scene to an M3D file. */
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
@ -83,15 +83,9 @@ namespace Assimp
|
||||||
const aiScene* mScene; // the scene to export
|
const aiScene* mScene; // the scene to export
|
||||||
const ExportProperties* mProperties; // currently unused
|
const ExportProperties* mProperties; // currently unused
|
||||||
std::shared_ptr<IOStream> outfile; // file to write to
|
std::shared_ptr<IOStream> outfile; // file to write to
|
||||||
m3d_t *m3d; // model for the C library to convert to
|
|
||||||
|
|
||||||
// helper to do the recursive walking
|
// helper to do the recursive walking
|
||||||
void NodeWalk(const aiNode* pNode, aiMatrix4x4 m);
|
void NodeWalk(const M3DWrapper &m3d, const aiNode* pNode, aiMatrix4x4 m);
|
||||||
m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx);
|
|
||||||
m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx);
|
|
||||||
uint32_t mkColor(aiColor4D* c);
|
|
||||||
M3D_INDEX addMaterial(const aiMaterial *mat);
|
|
||||||
void addProp(m3dm_t *m, uint8_t type, uint32_t value);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,16 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define M3D_NOWEIGHTS
|
#define M3D_NOWEIGHTS
|
||||||
#define M3D_NOANIMATION
|
#define M3D_NOANIMATION
|
||||||
|
|
||||||
#include <assimp/IOStreamBuffer.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <assimp/DefaultIOSystem.h>
|
#include <assimp/DefaultIOSystem.h>
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/IOStreamBuffer.h>
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/ai_assert.h>
|
#include <assimp/ai_assert.h>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "M3DImporter.h"
|
#include "M3DImporter.h"
|
||||||
#include "M3DMaterials.h"
|
#include "M3DMaterials.h"
|
||||||
|
#include "M3DWrapper.h"
|
||||||
|
|
||||||
// RESOURCES:
|
// RESOURCES:
|
||||||
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
||||||
|
@ -89,7 +91,7 @@ static const aiImporterDesc desc = {
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
aiImporterFlags_SupportBinaryFlavour,
|
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -97,49 +99,14 @@ static const aiImporterDesc desc = {
|
||||||
"m3d a3d"
|
"m3d a3d"
|
||||||
};
|
};
|
||||||
|
|
||||||
// workaround: the SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
|
|
||||||
extern "C" {
|
|
||||||
void* 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<Assimp::IOStream> pStream(
|
|
||||||
(reinterpret_cast<Assimp::IOSystem*>(m3dimporter_pIOHandler))->Open( file, "rb"));
|
|
||||||
size_t fileSize = 0;
|
|
||||||
unsigned char *data = NULL;
|
|
||||||
// sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
|
|
||||||
if(pStream) {
|
|
||||||
fileSize = pStream->FileSize();
|
|
||||||
// should be allocated with malloc(), because the library will call free() to deallocate
|
|
||||||
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 {
|
namespace Assimp {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Default constructor
|
// Default constructor
|
||||||
M3DImporter::M3DImporter()
|
M3DImporter::M3DImporter() :
|
||||||
: mScene(nullptr)
|
mScene(nullptr) {}
|
||||||
, m3d(nullptr) { }
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Destructor.
|
|
||||||
M3DImporter::~M3DImporter() {}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns true, if file is a binary or ASCII Model 3D file.
|
// Returns true, if file is a binary or ASCII Model 3D file.
|
||||||
|
@ -188,9 +155,8 @@ void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSy
|
||||||
if (fileSize < 8) {
|
if (fileSize < 8) {
|
||||||
throw DeadlyImportError("M3D-file " + file + " is too small.");
|
throw DeadlyImportError("M3D-file " + file + " is too small.");
|
||||||
}
|
}
|
||||||
std::unique_ptr<unsigned char[]> _buffer (new unsigned char[fileSize]);
|
std::vector<unsigned char> buffer(fileSize);
|
||||||
unsigned char *data( _buffer.get() );
|
if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
|
||||||
if(fileSize != pStream->Read(data,1,fileSize)) {
|
|
||||||
throw DeadlyImportError("Failed to read the file " + file + ".");
|
throw DeadlyImportError("Failed to read the file " + file + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,37 +169,33 @@ void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSy
|
||||||
pIOHandler->PushDirectory(folderName);
|
pIOHandler->PushDirectory(folderName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// pass this IOHandler to the C callback
|
|
||||||
m3dimporter_pIOHandler = pIOHandler;
|
|
||||||
|
|
||||||
//DefaultLogger::create("/dev/stderr", Logger::VERBOSE);
|
//DefaultLogger::create("/dev/stderr", Logger::VERBOSE);
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: loading ", file);
|
ASSIMP_LOG_DEBUG_F("M3D: loading ", file);
|
||||||
|
|
||||||
// let the C SDK do the hard work for us
|
// let the C SDK do the hard work for us
|
||||||
m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr);
|
M3DWrapper m3d(pIOHandler, buffer);
|
||||||
m3dimporter_pIOHandler = nullptr;
|
|
||||||
|
|
||||||
if (!m3d) {
|
if (!m3d) {
|
||||||
throw DeadlyImportError("Unable to parse " + file + " as M3D.");
|
throw DeadlyImportError("Unable to parse " + file + " as M3D.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the root node
|
// create the root node
|
||||||
pScene->mRootNode = new aiNode;
|
pScene->mRootNode = new aiNode;
|
||||||
pScene->mRootNode->mName = aiString(std::string(std::string(m3d->name)));
|
pScene->mRootNode->mName = aiString(m3d.Name());
|
||||||
pScene->mRootNode->mTransformation = aiMatrix4x4();
|
pScene->mRootNode->mTransformation = aiMatrix4x4();
|
||||||
pScene->mRootNode->mNumChildren = 0;
|
pScene->mRootNode->mNumChildren = 0;
|
||||||
mScene = pScene;
|
mScene = pScene;
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG("M3D: root node " + std::string(m3d->name));
|
ASSIMP_LOG_DEBUG("M3D: root node " + m3d.Name());
|
||||||
|
|
||||||
// now we just have to fill up the Assimp structures in pScene
|
// now we just have to fill up the Assimp structures in pScene
|
||||||
importMaterials();
|
importMaterials(m3d);
|
||||||
importTextures();
|
importTextures(m3d);
|
||||||
importBones(-1U, pScene->mRootNode);
|
importBones(m3d, -1U, pScene->mRootNode);
|
||||||
importMeshes();
|
importMeshes(m3d);
|
||||||
importAnimations();
|
importAnimations(m3d);
|
||||||
|
|
||||||
// we don't need the SDK's version any more
|
|
||||||
m3d_free(m3d);
|
|
||||||
|
|
||||||
// Pop directory stack
|
// Pop directory stack
|
||||||
if (pIOHandler->StackSize() > 0) {
|
if (pIOHandler->StackSize() > 0) {
|
||||||
|
@ -243,8 +205,7 @@ void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSy
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// convert materials. properties are converted using a static table in M3DMaterials.h
|
// convert materials. properties are converted using a static table in M3DMaterials.h
|
||||||
void M3DImporter::importMaterials()
|
void M3DImporter::importMaterials(const M3DWrapper &m3d_wrap) {
|
||||||
{
|
|
||||||
unsigned int i, j, k, l, n;
|
unsigned int i, j, k, l, n;
|
||||||
m3dm_t *m;
|
m3dm_t *m;
|
||||||
aiString name = aiString(AI_DEFAULT_MATERIAL_NAME);
|
aiString name = aiString(AI_DEFAULT_MATERIAL_NAME);
|
||||||
|
@ -252,22 +213,23 @@ void M3DImporter::importMaterials()
|
||||||
ai_real f;
|
ai_real f;
|
||||||
|
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d_wrap);
|
||||||
|
|
||||||
mScene->mNumMaterials = m3d->nummaterial + 1;
|
mScene->mNumMaterials = m3d_wrap->nummaterial + 1;
|
||||||
mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ];
|
mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials);
|
ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials);
|
||||||
|
|
||||||
// add a default material as first
|
// add a default material as first
|
||||||
aiMaterial *mat = new aiMaterial;
|
aiMaterial *mat = new aiMaterial;
|
||||||
mat->AddProperty(&name, AI_MATKEY_NAME);
|
mat->AddProperty(&name, AI_MATKEY_NAME);
|
||||||
c.a = 1.0; c.b = c.g = c.r = 0.6;
|
c.a = 1.0f;
|
||||||
|
c.b = c.g = c.r = 0.6f;
|
||||||
mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
|
mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
mScene->mMaterials[0] = mat;
|
mScene->mMaterials[0] = mat;
|
||||||
|
|
||||||
for(i = 0; i < m3d->nummaterial; i++) {
|
for (i = 0; i < m3d_wrap->nummaterial; i++) {
|
||||||
m = &m3d->material[i];
|
m = &m3d_wrap->material[i];
|
||||||
aiMaterial *mat = new aiMaterial;
|
aiMaterial *mat = new aiMaterial;
|
||||||
name.Set(std::string(m->name));
|
name.Set(std::string(m->name));
|
||||||
mat->AddProperty(&name, AI_MATKEY_NAME);
|
mat->AddProperty(&name, AI_MATKEY_NAME);
|
||||||
|
@ -312,9 +274,9 @@ void M3DImporter::importMaterials()
|
||||||
// texture map properties
|
// texture map properties
|
||||||
if (m->prop[j].type >= 128 && aiTxProps[k].pKey &&
|
if (m->prop[j].type >= 128 && aiTxProps[k].pKey &&
|
||||||
// extra check, should never happen, do we have the refered texture?
|
// extra check, should never happen, do we have the refered texture?
|
||||||
m->prop[j].value.textureid < m3d->numtexture &&
|
m->prop[j].value.textureid < m3d_wrap->numtexture &&
|
||||||
m3d->texture[m->prop[j].value.textureid].name) {
|
m3d_wrap->texture[m->prop[j].value.textureid].name) {
|
||||||
name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png"));
|
name.Set(std::string(std::string(m3d_wrap->texture[m->prop[j].value.textureid].name) + ".png"));
|
||||||
mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
|
mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
|
||||||
n = 0;
|
n = 0;
|
||||||
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
|
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
|
||||||
|
@ -326,14 +288,13 @@ void M3DImporter::importMaterials()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// import textures, this is the simplest of all
|
// import textures, this is the simplest of all
|
||||||
void M3DImporter::importTextures()
|
void M3DImporter::importTextures(const M3DWrapper &m3d) {
|
||||||
{
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
|
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
|
||||||
m3dtx_t *t;
|
m3dtx_t *t;
|
||||||
|
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d);
|
||||||
|
|
||||||
mScene->mNumTextures = m3d->numtexture;
|
mScene->mNumTextures = m3d->numtexture;
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures);
|
ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures);
|
||||||
|
@ -355,14 +316,21 @@ void M3DImporter::importTextures()
|
||||||
for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) {
|
for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) {
|
||||||
switch (t->f) {
|
switch (t->f) {
|
||||||
case 1: tx->pcData[j].g = t->d[k++]; break;
|
case 1: tx->pcData[j].g = t->d[k++]; break;
|
||||||
case 2: tx->pcData[j].g = t->d[k++]; tx->pcData[j].a = t->d[k++]; break;
|
case 2:
|
||||||
|
tx->pcData[j].g = t->d[k++];
|
||||||
|
tx->pcData[j].a = t->d[k++];
|
||||||
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
|
tx->pcData[j].r = t->d[k++];
|
||||||
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = 255;
|
tx->pcData[j].g = t->d[k++];
|
||||||
|
tx->pcData[j].b = t->d[k++];
|
||||||
|
tx->pcData[j].a = 255;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
|
tx->pcData[j].r = t->d[k++];
|
||||||
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = t->d[k++];
|
tx->pcData[j].g = t->d[k++];
|
||||||
|
tx->pcData[j].b = t->d[k++];
|
||||||
|
tx->pcData[j].a = t->d[k++];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,8 +342,7 @@ void M3DImporter::importTextures()
|
||||||
// this is tricky. M3D has a global vertex and UV list, and faces are indexing them
|
// 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
|
// individually. In assimp there're per mesh vertex and UV lists, and they must be
|
||||||
// indexed simultaneously.
|
// indexed simultaneously.
|
||||||
void M3DImporter::importMeshes()
|
void M3DImporter::importMeshes(const M3DWrapper &m3d) {
|
||||||
{
|
|
||||||
unsigned int i, j, k, l, numpoly = 3, lastMat = -2U;
|
unsigned int i, j, k, l, numpoly = 3, lastMat = -2U;
|
||||||
std::vector<aiMesh *> *meshes = new std::vector<aiMesh *>();
|
std::vector<aiMesh *> *meshes = new std::vector<aiMesh *>();
|
||||||
std::vector<aiFace> *faces = nullptr;
|
std::vector<aiFace> *faces = nullptr;
|
||||||
|
@ -387,7 +354,7 @@ void M3DImporter::importMeshes()
|
||||||
aiMesh *pMesh = nullptr;
|
aiMesh *pMesh = nullptr;
|
||||||
|
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d);
|
||||||
ai_assert(mScene->mRootNode != nullptr);
|
ai_assert(mScene->mRootNode != nullptr);
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface);
|
ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface);
|
||||||
|
@ -397,7 +364,7 @@ void M3DImporter::importMeshes()
|
||||||
if (lastMat != m3d->face[i].materialid) {
|
if (lastMat != m3d->face[i].materialid) {
|
||||||
lastMat = m3d->face[i].materialid;
|
lastMat = m3d->face[i].materialid;
|
||||||
if (pMesh && vertices && vertices->size() && faces && faces->size()) {
|
if (pMesh && vertices && vertices->size() && faces && faces->size()) {
|
||||||
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
|
populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
|
||||||
meshes->push_back(pMesh);
|
meshes->push_back(pMesh);
|
||||||
delete faces;
|
delete faces;
|
||||||
delete vertices;
|
delete vertices;
|
||||||
|
@ -422,7 +389,7 @@ void M3DImporter::importMeshes()
|
||||||
pFace->mIndices = new unsigned int[numpoly];
|
pFace->mIndices = new unsigned int[numpoly];
|
||||||
for (j = 0; j < numpoly; j++) {
|
for (j = 0; j < numpoly; j++) {
|
||||||
aiVector3D pos, uv, norm;
|
aiVector3D pos, uv, norm;
|
||||||
k = vertices->size();
|
k = static_cast<unsigned int>(vertices->size());
|
||||||
pFace->mIndices[j] = k;
|
pFace->mIndices[j] = k;
|
||||||
l = m3d->face[i].vertex[j];
|
l = m3d->face[i].vertex[j];
|
||||||
pos.x = m3d->vertex[l].x;
|
pos.x = m3d->vertex[l].x;
|
||||||
|
@ -456,17 +423,17 @@ void M3DImporter::importMeshes()
|
||||||
}
|
}
|
||||||
// if there's data left in the temporary vectors, flush them
|
// if there's data left in the temporary vectors, flush them
|
||||||
if (pMesh && vertices->size() && faces->size()) {
|
if (pMesh && vertices->size() && faces->size()) {
|
||||||
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
|
populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
|
||||||
meshes->push_back(pMesh);
|
meshes->push_back(pMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create global mesh list in scene
|
// create global mesh list in scene
|
||||||
mScene->mNumMeshes = meshes->size();
|
mScene->mNumMeshes = static_cast<unsigned int>(meshes->size());
|
||||||
mScene->mMeshes = new aiMesh *[mScene->mNumMeshes];
|
mScene->mMeshes = new aiMesh *[mScene->mNumMeshes];
|
||||||
std::copy(meshes->begin(), meshes->end(), mScene->mMeshes);
|
std::copy(meshes->begin(), meshes->end(), mScene->mMeshes);
|
||||||
|
|
||||||
// create mesh indeces in root node
|
// create mesh indeces in root node
|
||||||
mScene->mRootNode->mNumMeshes = meshes->size();
|
mScene->mRootNode->mNumMeshes = static_cast<unsigned int>(meshes->size());
|
||||||
mScene->mRootNode->mMeshes = new unsigned int[meshes->size()];
|
mScene->mRootNode->mMeshes = new unsigned int[meshes->size()];
|
||||||
for (i = 0; i < meshes->size(); i++) {
|
for (i = 0; i < meshes->size(); i++) {
|
||||||
mScene->mRootNode->mMeshes[i] = i;
|
mScene->mRootNode->mMeshes[i] = i;
|
||||||
|
@ -483,13 +450,12 @@ void M3DImporter::importMeshes()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// a reentrant node parser. Otherwise this is simple
|
// a reentrant node parser. Otherwise this is simple
|
||||||
void M3DImporter::importBones(unsigned int parentid, aiNode *pParent)
|
void M3DImporter::importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent) {
|
||||||
{
|
|
||||||
unsigned int i, n;
|
unsigned int i, n;
|
||||||
|
|
||||||
ai_assert(pParent != nullptr);
|
ai_assert(pParent != nullptr);
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d);
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid);
|
ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid);
|
||||||
|
|
||||||
|
@ -502,11 +468,11 @@ void M3DImporter::importBones(unsigned int parentid, aiNode *pParent)
|
||||||
aiNode *pChild = new aiNode;
|
aiNode *pChild = new aiNode;
|
||||||
pChild->mParent = pParent;
|
pChild->mParent = pParent;
|
||||||
pChild->mName = aiString(std::string(m3d->bone[i].name));
|
pChild->mName = aiString(std::string(m3d->bone[i].name));
|
||||||
convertPose(&pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori);
|
convertPose(m3d, &pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori);
|
||||||
pChild->mNumChildren = 0;
|
pChild->mNumChildren = 0;
|
||||||
pParent->mChildren[pParent->mNumChildren] = pChild;
|
pParent->mChildren[pParent->mNumChildren] = pChild;
|
||||||
pParent->mNumChildren++;
|
pParent->mNumChildren++;
|
||||||
importBones(i, pChild);
|
importBones(m3d, i, pChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,14 +481,13 @@ void M3DImporter::importBones(unsigned int parentid, aiNode *pParent)
|
||||||
// this is another headache. M3D stores list of changed bone id/position/orientation triplets and
|
// 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
|
// 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
|
// bone, so we have to convert between the two conceptually different representation forms
|
||||||
void M3DImporter::importAnimations()
|
void M3DImporter::importAnimations(const M3DWrapper &m3d) {
|
||||||
{
|
|
||||||
unsigned int i, j, k, l, pos, ori;
|
unsigned int i, j, k, l, pos, ori;
|
||||||
double t;
|
double t;
|
||||||
m3da_t *a;
|
m3da_t *a;
|
||||||
|
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d);
|
||||||
|
|
||||||
mScene->mNumAnimations = m3d->numaction;
|
mScene->mNumAnimations = m3d->numaction;
|
||||||
|
|
||||||
|
@ -589,10 +554,9 @@ aiColor4D M3DImporter::mkColor(uint32_t c) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// convert a position id and orientation id into a 4 x 4 transformation matrix
|
// 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)
|
void M3DImporter::convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) {
|
||||||
{
|
|
||||||
ai_assert(m != nullptr);
|
ai_assert(m != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d);
|
||||||
ai_assert(posid != -1U && posid < m3d->numvertex);
|
ai_assert(posid != -1U && posid < m3d->numvertex);
|
||||||
ai_assert(orientid != -1U && orientid < m3d->numvertex);
|
ai_assert(orientid != -1U && orientid < m3d->numvertex);
|
||||||
m3dv_t *p = &m3d->vertex[posid];
|
m3dv_t *p = &m3d->vertex[posid];
|
||||||
|
@ -603,27 +567,40 @@ void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int o
|
||||||
m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0;
|
m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0;
|
||||||
m->a1 = m->b2 = m->c3 = -1.0;
|
m->a1 = m->b2 = m->c3 = -1.0;
|
||||||
} else {
|
} else {
|
||||||
m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0;
|
m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z);
|
||||||
m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0;
|
if (m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0;
|
||||||
m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0;
|
m->a2 = 2 * (q->x * q->y - q->z * q->w);
|
||||||
m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0;
|
if (m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0;
|
||||||
m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0;
|
m->a3 = 2 * (q->x * q->z + q->y * q->w);
|
||||||
m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0;
|
if (m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0;
|
||||||
m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0;
|
m->b1 = 2 * (q->x * q->y + q->z * q->w);
|
||||||
m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0;
|
if (m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0;
|
||||||
m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0;
|
m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z);
|
||||||
|
if (m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0;
|
||||||
|
m->b3 = 2 * (q->y * q->z - q->x * q->w);
|
||||||
|
if (m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0;
|
||||||
|
m->c1 = 2 * (q->x * q->z - q->y * q->w);
|
||||||
|
if (m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0;
|
||||||
|
m->c2 = 2 * (q->y * q->z + q->x * q->w);
|
||||||
|
if (m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0;
|
||||||
|
m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y);
|
||||||
|
if (m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set translation */
|
/* set translation */
|
||||||
m->a4 = p->x; m->b4 = p->y; m->c4 = p->z;
|
m->a4 = p->x;
|
||||||
|
m->b4 = p->y;
|
||||||
|
m->c4 = p->z;
|
||||||
|
|
||||||
m->d1 = 0; m->d2 = 0; m->d3 = 0; m->d4 = 1;
|
m->d1 = 0;
|
||||||
|
m->d2 = 0;
|
||||||
|
m->d3 = 0;
|
||||||
|
m->d4 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// find a node by name
|
// find a node by name
|
||||||
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name)
|
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) {
|
||||||
{
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
ai_assert(pNode != nullptr);
|
ai_assert(pNode != nullptr);
|
||||||
|
@ -640,8 +617,7 @@ aiNode *M3DImporter::findNode(aiNode *pNode, aiString name)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// fills up offsetmatrix in mBones
|
// fills up offsetmatrix in mBones
|
||||||
void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m)
|
void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) {
|
||||||
{
|
|
||||||
ai_assert(pNode != nullptr);
|
ai_assert(pNode != nullptr);
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
|
|
||||||
|
@ -657,7 +633,7 @@ void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m)
|
||||||
// because M3D has a global mesh, global vertex ids and stores materialid on the face, we need
|
// 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
|
// 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
|
// this function fills up an aiMesh with those temporary lists
|
||||||
void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *vertices,
|
void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *vertices,
|
||||||
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
|
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
|
||||||
std::vector<unsigned int> *vertexids) {
|
std::vector<unsigned int> *vertexids) {
|
||||||
|
|
||||||
|
@ -668,16 +644,16 @@ void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::v
|
||||||
ai_assert(texcoords != nullptr);
|
ai_assert(texcoords != nullptr);
|
||||||
ai_assert(colors != nullptr);
|
ai_assert(colors != nullptr);
|
||||||
ai_assert(vertexids != nullptr);
|
ai_assert(vertexids != nullptr);
|
||||||
ai_assert(m3d != nullptr);
|
ai_assert(m3d);
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(),
|
ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(),
|
||||||
" numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone);
|
" numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone);
|
||||||
|
|
||||||
if (vertices->size() && faces->size()) {
|
if (vertices->size() && faces->size()) {
|
||||||
pMesh->mNumFaces = faces->size();
|
pMesh->mNumFaces = static_cast<unsigned int>(faces->size());
|
||||||
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
|
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
|
||||||
std::copy(faces->begin(), faces->end(), pMesh->mFaces);
|
std::copy(faces->begin(), faces->end(), pMesh->mFaces);
|
||||||
pMesh->mNumVertices = vertices->size();
|
pMesh->mNumVertices = static_cast<unsigned int>(vertices->size());
|
||||||
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||||
std::copy(vertices->begin(), vertices->end(), pMesh->mVertices);
|
std::copy(vertices->begin(), vertices->end(), pMesh->mVertices);
|
||||||
if (normals->size() == vertices->size()) {
|
if (normals->size() == vertices->size()) {
|
||||||
|
|
|
@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||||
|
|
||||||
#include "m3d.h"
|
|
||||||
#include <assimp/BaseImporter.h>
|
#include <assimp/BaseImporter.h>
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -60,22 +59,20 @@ struct aiFace;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
class M3DWrapper;
|
||||||
|
|
||||||
class M3DImporter : public BaseImporter {
|
class M3DImporter : public BaseImporter {
|
||||||
public:
|
public:
|
||||||
/// \brief Default constructor
|
/// \brief Default constructor
|
||||||
M3DImporter();
|
M3DImporter();
|
||||||
|
|
||||||
/// \brief Destructor
|
|
||||||
~M3DImporter();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief Returns whether the class can handle the format of the given file.
|
/// \brief Returns whether the class can handle the format of the given file.
|
||||||
/// \remark See BaseImporter::CanRead() for details.
|
/// \remark See BaseImporter::CanRead() for details.
|
||||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
aiScene* mScene; // the scene to import to
|
aiScene *mScene = nullptr; // the scene to import to
|
||||||
m3d_t *m3d; // model for the C library to convert from
|
|
||||||
|
|
||||||
//! \brief Appends the supported extension.
|
//! \brief Appends the supported extension.
|
||||||
const aiImporterDesc *GetInfo() const;
|
const aiImporterDesc *GetInfo() const;
|
||||||
|
@ -83,18 +80,18 @@ private:
|
||||||
//! \brief File import implementation.
|
//! \brief File import implementation.
|
||||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
|
||||||
|
|
||||||
void importMaterials();
|
void importMaterials(const M3DWrapper &m3d);
|
||||||
void importTextures();
|
void importTextures(const M3DWrapper &m3d);
|
||||||
void importMeshes();
|
void importMeshes(const M3DWrapper &m3d);
|
||||||
void importBones(unsigned int parentid, aiNode *pParent);
|
void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent);
|
||||||
void importAnimations();
|
void importAnimations(const M3DWrapper &m3d);
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
aiColor4D mkColor(uint32_t c);
|
aiColor4D mkColor(uint32_t c);
|
||||||
void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
|
void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
|
||||||
aiNode *findNode(aiNode *pNode, aiString name);
|
aiNode *findNode(aiNode *pNode, aiString name);
|
||||||
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
|
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
|
||||||
void populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
|
void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
|
||||||
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
|
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
|
||||||
std::vector<unsigned int> *vertexids);
|
std::vector<unsigned int> *vertexids);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) && !ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||||
|
|
||||||
|
#include "M3DWrapper.h"
|
||||||
|
|
||||||
|
#include <assimp/DefaultIOSystem.h>
|
||||||
|
#include <assimp/IOStreamBuffer.h>
|
||||||
|
#include <assimp/ai_assert.h>
|
||||||
|
|
||||||
|
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1915) || defined(AI_M3D_USE_STDMUTEX) // C++11 and MSVC that mostly supports it
|
||||||
|
#define AI_M3D_USE_STDMUTEX
|
||||||
|
#include <mutex>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// workaround: the M3D SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
|
||||||
|
// This makes it non-rentrant so lock a mutex (requires C++11)
|
||||||
|
|
||||||
|
std::mutex file_mutex;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void *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<Assimp::IOStream> pStream(
|
||||||
|
(reinterpret_cast<Assimp::IOSystem *>(m3dimporter_pIOHandler))->Open(file, "rb"));
|
||||||
|
size_t fileSize = 0;
|
||||||
|
unsigned char *data = NULL;
|
||||||
|
// sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
|
||||||
|
if (pStream) {
|
||||||
|
fileSize = pStream->FileSize();
|
||||||
|
// should be allocated with malloc(), because the library will call free() to deallocate
|
||||||
|
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 {
|
||||||
|
M3DWrapper::M3DWrapper() {
|
||||||
|
// use malloc() here because m3d_free() will call free()
|
||||||
|
m3d_ = (m3d_t *)calloc(1, sizeof(m3d_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
|
||||||
|
#ifdef AI_M3D_USE_STDMUTEX
|
||||||
|
// M3D is NOT thread-safe, so lock the global mutex
|
||||||
|
const std::lock_guard<std::mutex> lock(file_mutex);
|
||||||
|
#endif
|
||||||
|
// pass this IOHandler to the C callback
|
||||||
|
m3dimporter_pIOHandler = pIOHandler;
|
||||||
|
m3d_ = m3d_load(const_cast<unsigned char *>(buffer.data()), m3dimporter_readfile, free, nullptr);
|
||||||
|
// Clear the C callback
|
||||||
|
m3dimporter_pIOHandler = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
M3DWrapper::~M3DWrapper() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void M3DWrapper::reset() {
|
||||||
|
ClearSave();
|
||||||
|
if (m3d_)
|
||||||
|
m3d_free(m3d_);
|
||||||
|
m3d_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
|
||||||
|
#if (!(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER))
|
||||||
|
ClearSave();
|
||||||
|
saved_output_ = m3d_save(m3d_, quality, flags, &size);
|
||||||
|
return saved_output_;
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void M3DWrapper::ClearSave() {
|
||||||
|
if (saved_output_)
|
||||||
|
M3D_FREE(saved_output_);
|
||||||
|
saved_output_ = nullptr;
|
||||||
|
}
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,96 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
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 M3DWrapper.h
|
||||||
|
* @brief Declares a class to wrap the C m3d SDK
|
||||||
|
*/
|
||||||
|
#ifndef AI_M3DWRAPPER_H_INC
|
||||||
|
#define AI_M3DWRAPPER_H_INC
|
||||||
|
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) && !ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "m3d.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
class IOSystem;
|
||||||
|
|
||||||
|
class M3DWrapper {
|
||||||
|
m3d_t *m3d_ = nullptr;
|
||||||
|
unsigned char *saved_output_ = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Construct an empty M3D model
|
||||||
|
explicit M3DWrapper();
|
||||||
|
|
||||||
|
// Construct an M3D model from provided buffer
|
||||||
|
// NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write.
|
||||||
|
// BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN
|
||||||
|
explicit M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer);
|
||||||
|
|
||||||
|
~M3DWrapper();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Name
|
||||||
|
inline std::string Name() const {
|
||||||
|
if (m3d_) return std::string(m3d_->name);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute a save
|
||||||
|
unsigned char *Save(int quality, int flags, unsigned int &size);
|
||||||
|
void ClearSave();
|
||||||
|
|
||||||
|
inline explicit operator bool() const { return m3d_ != nullptr; }
|
||||||
|
|
||||||
|
// Allow direct access to M3D API
|
||||||
|
inline m3d_t *operator->() const { return m3d_; }
|
||||||
|
inline m3d_t *M3D() const { return m3d_; }
|
||||||
|
};
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // AI_M3DWRAPPER_H_INC
|
Loading…
Reference in New Issue