|
|
@@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
|
|
|
|
|
#define M3D_IMPLEMENTATION
|
|
|
-#define M3D_ASCII
|
|
|
#define M3D_NONORMALS /* leave the post-processing to Assimp */
|
|
|
#define M3D_NOWEIGHTS
|
|
|
#define M3D_NOANIMATION
|
|
|
@@ -57,9 +56,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
#include <assimp/Importer.hpp>
|
|
|
#include <memory>
|
|
|
|
|
|
+#include "M3DWrapper.h"
|
|
|
#include "M3DImporter.h"
|
|
|
#include "M3DMaterials.h"
|
|
|
-#include "M3DWrapper.h"
|
|
|
|
|
|
// RESOURCES:
|
|
|
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
|
|
@@ -96,7 +95,11 @@ static const aiImporterDesc desc = {
|
|
|
0,
|
|
|
0,
|
|
|
0,
|
|
|
+#ifdef M3D_ASCII
|
|
|
"m3d a3d"
|
|
|
+#else
|
|
|
+ "m3d"
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
namespace Assimp {
|
|
|
@@ -113,7 +116,11 @@ M3DImporter::M3DImporter() :
|
|
|
bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
|
|
const std::string extension = GetExtension(pFile);
|
|
|
|
|
|
- if (extension == "m3d" || extension == "a3d")
|
|
|
+ if (extension == "m3d"
|
|
|
+#ifdef M3D_ASCII
|
|
|
+ || extension == "a3d"
|
|
|
+#endif
|
|
|
+ )
|
|
|
return true;
|
|
|
else if (!extension.length() || checkSig) {
|
|
|
if (!pIOHandler) {
|
|
|
@@ -131,7 +138,11 @@ bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c
|
|
|
if (4 != pStream->Read(data, 1, 4)) {
|
|
|
return false;
|
|
|
}
|
|
|
- return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */;
|
|
|
+ return !memcmp(data, "3DMO", 4) /* bin */
|
|
|
+#ifdef M3D_ASCII
|
|
|
+ || !memcmp(data, "3dmo", 4) /* ASCII */
|
|
|
+#endif
|
|
|
+ ;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
@@ -159,6 +170,16 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
|
|
|
if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
|
|
|
throw DeadlyImportError("Failed to read the file " + file + ".");
|
|
|
}
|
|
|
+ // extra check for binary format's first 8 bytes. Not done for the ASCII variant
|
|
|
+ if(!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
|
|
|
+ throw DeadlyImportError("Bad binary header in file " + file + ".");
|
|
|
+ }
|
|
|
+#ifdef M3D_ASCII
|
|
|
+ // make sure there's a terminator zero character, as input must be ASCIIZ
|
|
|
+ if(!memcmp(buffer.data(), "3dmo", 4)) {
|
|
|
+ buffer.push_back(0);
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
// Get the path for external assets
|
|
|
std::string folderName("./");
|
|
|
@@ -176,7 +197,6 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
|
|
|
// let the C SDK do the hard work for us
|
|
|
M3DWrapper m3d(pIOHandler, buffer);
|
|
|
|
|
|
-
|
|
|
if (!m3d) {
|
|
|
throw DeadlyImportError("Unable to parse " + file + " as M3D.");
|
|
|
}
|
|
|
@@ -193,7 +213,7 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
|
|
|
// now we just have to fill up the Assimp structures in pScene
|
|
|
importMaterials(m3d);
|
|
|
importTextures(m3d);
|
|
|
- importBones(m3d, -1U, pScene->mRootNode);
|
|
|
+ importBones(m3d, M3D_NOTDEFINED, pScene->mRootNode);
|
|
|
importMeshes(m3d);
|
|
|
importAnimations(m3d);
|
|
|
|
|
|
@@ -306,32 +326,40 @@ void M3DImporter::importTextures(const M3DWrapper &m3d) {
|
|
|
for (i = 0; i < m3d->numtexture; i++) {
|
|
|
unsigned int j, k;
|
|
|
t = &m3d->texture[i];
|
|
|
- if (!t->w || !t->h || !t->f || !t->d) continue;
|
|
|
aiTexture *tx = new aiTexture;
|
|
|
- strcpy(tx->achFormatHint, formatHint[t->f - 1]);
|
|
|
tx->mFilename = aiString(std::string(t->name) + ".png");
|
|
|
- tx->mWidth = t->w;
|
|
|
- tx->mHeight = t->h;
|
|
|
- tx->pcData = new aiTexel[tx->mWidth * tx->mHeight];
|
|
|
- for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) {
|
|
|
- switch (t->f) {
|
|
|
- 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 3:
|
|
|
- tx->pcData[j].r = t->d[k++];
|
|
|
- tx->pcData[j].g = t->d[k++];
|
|
|
- tx->pcData[j].b = t->d[k++];
|
|
|
- tx->pcData[j].a = 255;
|
|
|
- break;
|
|
|
- case 4:
|
|
|
- tx->pcData[j].r = 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;
|
|
|
+ if (!t->w || !t->h || !t->f || !t->d) {
|
|
|
+ /* without ASSIMP_USE_M3D_READFILECB, we only have the filename, but no texture data ever */
|
|
|
+ tx->mWidth = 0;
|
|
|
+ tx->mHeight = 0;
|
|
|
+ memcpy(tx->achFormatHint, "png\000", 4);
|
|
|
+ tx->pcData = nullptr;
|
|
|
+ } else {
|
|
|
+ /* if we have the texture loaded, set format hint and pcData too */
|
|
|
+ tx->mWidth = t->w;
|
|
|
+ tx->mHeight = t->h;
|
|
|
+ strcpy(tx->achFormatHint, formatHint[t->f - 1]);
|
|
|
+ tx->pcData = new aiTexel[tx->mWidth * tx->mHeight];
|
|
|
+ for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) {
|
|
|
+ switch (t->f) {
|
|
|
+ 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 3:
|
|
|
+ tx->pcData[j].r = t->d[k++];
|
|
|
+ tx->pcData[j].g = t->d[k++];
|
|
|
+ tx->pcData[j].b = t->d[k++];
|
|
|
+ tx->pcData[j].a = 255;
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ tx->pcData[j].r = 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;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
mScene->mTextures[i] = tx;
|
|
|
@@ -343,7 +371,7 @@ void M3DImporter::importTextures(const M3DWrapper &m3d) {
|
|
|
// individually. In assimp there're per mesh vertex and UV lists, and they must be
|
|
|
// indexed simultaneously.
|
|
|
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 = M3D_INDEXMAX;
|
|
|
std::vector<aiMesh *> *meshes = new std::vector<aiMesh *>();
|
|
|
std::vector<aiFace> *faces = nullptr;
|
|
|
std::vector<aiVector3D> *vertices = nullptr;
|
|
|
@@ -398,20 +426,20 @@ void M3DImporter::importMeshes(const M3DWrapper &m3d) {
|
|
|
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) {
|
|
|
+ if (m3d->vertex[l].skinid != M3D_UNDEF && m3d->vertex[l].skinid != M3D_INDEXMAX && 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) {
|
|
|
+ if (l != M3D_UNDEF) {
|
|
|
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) {
|
|
|
+ if (l != M3D_UNDEF) {
|
|
|
norm.x = m3d->vertex[l].x;
|
|
|
norm.y = m3d->vertex[l].y;
|
|
|
norm.z = m3d->vertex[l].z;
|
|
|
@@ -557,8 +585,8 @@ aiColor4D M3DImporter::mkColor(uint32_t c) {
|
|
|
void M3DImporter::convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) {
|
|
|
ai_assert(m != nullptr);
|
|
|
ai_assert(m3d);
|
|
|
- ai_assert(posid != -1U && posid < m3d->numvertex);
|
|
|
- ai_assert(orientid != -1U && orientid < m3d->numvertex);
|
|
|
+ ai_assert(posid != M3D_UNDEF && posid < m3d->numvertex);
|
|
|
+ ai_assert(orientid != M3D_UNDEF && orientid < m3d->numvertex);
|
|
|
m3dv_t *p = &m3d->vertex[posid];
|
|
|
m3dv_t *q = &m3d->vertex[orientid];
|
|
|
|
|
|
@@ -692,7 +720,7 @@ void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector
|
|
|
// first count how many vertices we have per bone
|
|
|
for (i = 0; i < vertexids->size(); i++) {
|
|
|
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
|
|
- if (s != -1U && s != -2U) {
|
|
|
+ if (s != M3D_UNDEF && s != M3D_INDEXMAX) {
|
|
|
for (unsigned int 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++) {
|
|
|
@@ -715,7 +743,7 @@ void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector
|
|
|
// fill up with data
|
|
|
for (i = 0; i < vertexids->size(); i++) {
|
|
|
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
|
|
- if (s != -1U && s != -2U) {
|
|
|
+ if (s != M3D_UNDEF && s != M3D_INDEXMAX) {
|
|
|
for (unsigned int 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++) {
|