فهرست منبع

Merge branch 'master' into warning-level-max

Kim Kulling 5 سال پیش
والد
کامیت
b10b8b2f1e

+ 1 - 1
CMakeLists.txt

@@ -257,7 +257,7 @@ ELSEIF(MSVC)
   IF(MSVC12)
     ADD_COMPILE_OPTIONS(/wd4351)
   ENDIF()
-  SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi")
+  SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi /O0")
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
   IF(NOT HUNTER_ENABLED)
     SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")

+ 7 - 2
Readme.md

@@ -60,14 +60,19 @@ __Importers__:
 - ENFF
 - [FBX](https://en.wikipedia.org/wiki/FBX)
 - [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
-- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0)
+- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0):
+  At the moment for glTF2.0 the following extensions are supported:
+  + KHR_lights_punctual ( 5.0 )
+  + KHR_materials_pbrSpecularGlossiness ( 5.0 )
+  + KHR_materials_unlit ( 5.0 )
+  + KHR_texture_transform ( 5.1 under test )
 - HMB
 - IFC-STEP
 - IRR / IRRMESH
 - [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
 - LWS
 - LXO
-- [M3D](https://gitlab.com/bztsrc/model3d)
+- [M3D](https://bztsrc.gitlab.io/model3d)
 - MD2
 - MD3
 - MD5

+ 41 - 30
code/Collada/ColladaParser.cpp

@@ -3234,13 +3234,12 @@ void ColladaParser::ReadScene()
 
 // ------------------------------------------------------------------------------------------------
 // Aborts the file reading with an exception
-AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const
-{
+AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const {
     throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError);
 }
-void ColladaParser::ReportWarning(const char* msg, ...)
-{
-    ai_assert(NULL != msg);
+
+void ColladaParser::ReportWarning(const char* msg, ...) {
+    ai_assert(nullptr != msg);
 
     va_list args;
     va_start(args, msg);
@@ -3255,11 +3254,11 @@ void ColladaParser::ReportWarning(const char* msg, ...)
 
 // ------------------------------------------------------------------------------------------------
 // Skips all data until the end node of the current element
-void ColladaParser::SkipElement()
-{
+void ColladaParser::SkipElement() {
     // nothing to skip if it's an <element />
-    if (mReader->isEmptyElement())
+    if (mReader->isEmptyElement()) {
         return;
+    }
 
     // reroute
     SkipElement(mReader->getNodeName());
@@ -3267,63 +3266,75 @@ void ColladaParser::SkipElement()
 
 // ------------------------------------------------------------------------------------------------
 // Skips all data until the end node of the given element
-void ColladaParser::SkipElement(const char* pElement)
-{
+void ColladaParser::SkipElement(const char* pElement) {
     // copy the current node's name because it'a pointer to the reader's internal buffer,
     // which is going to change with the upcoming parsing
     std::string element = pElement;
-    while (mReader->read())
-    {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
-            if (mReader->getNodeName() == element)
+    while (mReader->read()) {
+        if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
+            if (mReader->getNodeName() == element) {
                 break;
+            }
+        }
     }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Tests for an opening element of the given name, throws an exception if not found
-void ColladaParser::TestOpening(const char* pName)
-{
+void ColladaParser::TestOpening(const char* pName) {
     // read element start
-    if (!mReader->read())
+    if (!mReader->read()) {
         ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element.");
+    }
     // whitespace in front is ok, just read again if found
-    if (mReader->getNodeType() == irr::io::EXN_TEXT)
-        if (!mReader->read())
+    if (mReader->getNodeType() == irr::io::EXN_TEXT) {
+        if (!mReader->read()) {
             ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element.");
+        }
+    }
 
-    if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0)
+    if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) {
         ThrowException(format() << "Expected start of <" << pName << "> element.");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Tests for the closing tag of the given element, throws an exception if not found
-void ColladaParser::TestClosing(const char* pName)
-{
+void ColladaParser::TestClosing(const char* pName) {
+    // check if we have an empty (self-closing) element
+    if (mReader->isEmptyElement()) {
+        return;
+    }
+
     // check if we're already on the closing tag and return right away
-    if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0)
+    if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) {
         return;
+    }
 
     // if not, read some more
-    if (!mReader->read())
+    if (!mReader->read()) {
         ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element.");
+    }
     // whitespace in front is ok, just read again if found
-    if (mReader->getNodeType() == irr::io::EXN_TEXT)
-        if (!mReader->read())
+    if (mReader->getNodeType() == irr::io::EXN_TEXT) {
+        if (!mReader->read()) {
             ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element.");
+        }
+    }
 
     // but this has the be the closing tag, or we're lost
-    if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0)
+    if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) {
         ThrowException(format() << "Expected end of <" << pName << "> element.");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
-int ColladaParser::GetAttribute(const char* pAttr) const
-{
+int ColladaParser::GetAttribute(const char* pAttr) const {
     int index = TestAttribute(pAttr);
-    if (index != -1)
+    if (index != -1) {
         return index;
+    }
 
     // attribute not found -> throw an exception
     ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");

+ 1 - 2
code/Common/Exporter.cpp

@@ -445,8 +445,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
 
                 ExportProperties emptyProperties;  // Never pass NULL ExportProperties so Exporters don't have to worry.
                 ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
-                                pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again);
-                                exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
+        		pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
                 exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
 
                 pimpl->mProgressHandler->UpdateFileWrite(4, 4);

+ 2 - 2
code/Common/Importer.cpp

@@ -493,7 +493,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
     ReadFile(fbuff,pFlags);
     SetIOHandler(io);
 
-    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
     return pimpl->mScene;
 }
 
@@ -710,7 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 
     // either successful or failure - the pointer expresses it anyways
-    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
     return pimpl->mScene;
 }
 

+ 6 - 0
code/Common/Version.cpp

@@ -66,6 +66,12 @@ ASSIMP_API const char*  aiGetLegalString  ()    {
     return LEGAL_INFORMATION;
 }
 
+// ------------------------------------------------------------------------------------------------
+// Get Assimp patch version
+ASSIMP_API unsigned int aiGetVersionPatch() {
+	return VER_PATCH;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Get Assimp minor version
 ASSIMP_API unsigned int aiGetVersionMinor ()    {

+ 4 - 1
code/FBX/FBXExporter.cpp

@@ -1860,6 +1860,7 @@ void FBXExporter::WriteObjects ()
             sdnode.AddChild("Version", int32_t(100));
             sdnode.AddChild("UserData", "", "");
 
+            std::set<int32_t> setWeightedVertex;
             // add indices and weights, if any
             if (b) {
                 std::vector<int32_t> subdef_indices;
@@ -1867,7 +1868,8 @@ void FBXExporter::WriteObjects ()
                 int32_t last_index = -1;
                 for (size_t wi = 0; wi < b->mNumWeights; ++wi) {
                     int32_t vi = vertex_indices[b->mWeights[wi].mVertexId];
-                    if (vi == last_index) {
+                    bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end());
+                    if (vi == last_index || bIsWeightedAlready) {
                         // only for vertices we exported to fbx
                         // TODO, FIXME: this assumes identically-located vertices
                         // will always deform in the same way.
@@ -1877,6 +1879,7 @@ void FBXExporter::WriteObjects ()
                         // identical vertex.
                         continue;
                     }
+                    setWeightedVertex.insert(vi);
                     subdef_indices.push_back(vi);
                     subdef_weights.push_back(b->mWeights[wi].mWeight);
                     last_index = vi;

+ 31 - 6
code/M3D/M3DExporter.cpp

@@ -169,6 +169,33 @@ void M3DExporter::doExport (
     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
 void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
@@ -221,25 +248,23 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
                 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,
+                m3d->vertex = 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->tmap = 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);
+                    vertex.color = 0;
+                    m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
                     m3d->face[n].normal[k] = (M3D_INDEX)idx;
                 }
             }

+ 2 - 0
code/M3D/M3DExporter.h

@@ -87,6 +87,8 @@ namespace Assimp
 
         // helper to do the recursive walking
         void NodeWalk(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);

+ 50 - 21
code/M3D/M3DImporter.cpp

@@ -44,6 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #define M3D_IMPLEMENTATION
 #define M3D_ASCII
+#define M3D_NONORMALS       /* leave the post-processing to Assimp */
+#define M3D_NOWEIGHTS
+#define M3D_NOANIMATION
 
 #include <assimp/IOStreamBuffer.h>
 #include <memory>
@@ -104,16 +107,21 @@ extern "C" {
         std::string file(fn);
         std::unique_ptr<Assimp::IOStream> pStream(
             (reinterpret_cast<Assimp::IOSystem*>(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)) {
+        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 = 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;
     }
@@ -307,7 +315,7 @@ void M3DImporter::importMaterials()
                 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);
+                    mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
                     n = 0;
                     mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
             }
@@ -321,6 +329,7 @@ void M3DImporter::importMaterials()
 void M3DImporter::importTextures()
 {
     unsigned int i;
+    const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
     m3dtx_t *t;
 
     ai_assert(mScene != nullptr);
@@ -334,14 +343,29 @@ void M3DImporter::importTextures()
 
     mScene->mTextures = new aiTexture*[m3d->numtexture];
     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, "rgba8888");
+        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 ];
-        memcpy(tx->pcData, t->d, tx->mWidth*tx->mHeight*4);
+        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;
     }
 }
@@ -372,9 +396,14 @@ void M3DImporter::importMeshes()
         // we must switch mesh if material changes
         if(lastMat != m3d->face[i].materialid) {
             lastMat = m3d->face[i].materialid;
-            if(pMesh && vertices->size() && faces->size()) {
+            if(pMesh && vertices && vertices->size() && faces && faces->size()) {
                 populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
                 meshes->push_back(pMesh);
+                delete faces;
+                delete vertices;
+                delete normals;
+                delete texcoords;
+                delete colors;
                 delete vertexids;   // this is not stored in pMesh, just to collect bone vertices
             }
             pMesh = new aiMesh;
@@ -574,15 +603,15 @@ 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->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;
+        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->a2 = 2 * (q->x * q->y - q->z * q->w);     if(m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 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->b1 = 2 * (q->x * q->y + q->z * q->w);     if(m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 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 */

+ 2 - 2
code/M3D/M3DMaterials.h

@@ -75,7 +75,7 @@ static const aiMatProp aiProps[] = {
     { AI_MATKEY_REFLECTIVITY },                                 /* m3dp_Pm */
     { NULL, 0, 0 },                                             /* m3dp_Ps */
     { AI_MATKEY_REFRACTI },                                     /* m3dp_Ni */
-    { NULL, 0, 0 },
+    { NULL, 0, 0 },                                             /* m3dp_Nt */
     { NULL, 0, 0 },
     { NULL, 0, 0 },
     { NULL, 0, 0 }
@@ -97,7 +97,7 @@ static const aiMatProp aiTxProps[] = {
     { 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 },                                          /* m3dp_map_Nt */
     { NULL, 0, 0 },
     { NULL, 0, 0 },
     { NULL, 0, 0 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 391 - 196
code/M3D/m3d.h


+ 2 - 2
code/Material/MaterialSystem.cpp

@@ -273,14 +273,14 @@ aiReturn aiGetMaterialColor(const aiMaterial* pMat,
 }
 
 // ------------------------------------------------------------------------------------------------
-// Get a aiUVTransform (4 floats) from the material
+// Get a aiUVTransform (5 floats) from the material
 aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat,
     const char* pKey,
     unsigned int type,
     unsigned int index,
     aiUVTransform* pOut)
 {
-    unsigned int iMax = 4;
+    unsigned int iMax = 5;
     return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
 }
 

+ 8 - 0
code/glTF2/glTF2Asset.h

@@ -1034,6 +1034,12 @@ namespace glTF2
 			bool KHR_texture_transform;
         } extensionsUsed;
 
+        //! Keeps info about the required extensions
+        struct RequiredExtensions
+        {
+            bool KHR_draco_mesh_compression;
+        } extensionsRequired;
+
         AssetMetadata asset;
 
 
@@ -1076,6 +1082,7 @@ namespace glTF2
             , textures      (*this, "textures")
         {
             memset(&extensionsUsed, 0, sizeof(extensionsUsed));
+            memset(&extensionsRequired, 0, sizeof(extensionsRequired));
         }
 
         //! Main function
@@ -1094,6 +1101,7 @@ namespace glTF2
         void ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData);
 
         void ReadExtensionsUsed(Document& doc);
+        void ReadExtensionsRequired(Document& doc);
 
         IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
     };

+ 32 - 2
code/glTF2/glTF2Asset.inl

@@ -270,13 +270,14 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i)
         throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object");
     }
 
-    T* inst = new T();
+    // Unique ptr prevents memory leak in case of Read throws an exception
+    auto inst = std::unique_ptr<T>(new T());
     inst->id = std::string(mDictId) + "_" + to_string(i);
     inst->oIndex = i;
     ReadMember(obj, "name", inst->name);
     inst->Read(obj, mAsset);
 
-    return Add(inst);
+    return Add(inst.release());
 }
 
 template<class T>
@@ -1432,6 +1433,12 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
     // Load the metadata
     asset.Read(doc);
     ReadExtensionsUsed(doc);
+    ReadExtensionsRequired(doc);
+
+    // Currently Draco is not supported
+    if (extensionsRequired.KHR_draco_mesh_compression) {
+        throw DeadlyImportError("GLTF: Draco mesh compression not currently supported.");
+    }
 
     // Prepare the dictionaries
     for (size_t i = 0; i < mDicts.size(); ++i) {
@@ -1478,6 +1485,29 @@ inline void Asset::SetAsBinary()
     }
 }
 
+// As required extensions are only a concept in glTF 2.0, this is here
+// instead of glTFCommon.h
+#define CHECK_REQUIRED_EXT(EXT) \
+	if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
+
+inline void Asset::ReadExtensionsRequired(Document& doc)
+{
+    Value* extsRequired = FindArray(doc, "extensionsRequired");
+    if (nullptr == extsRequired) {
+	return;
+    }
+
+    std::gltf_unordered_map<std::string, bool> exts;
+    for (unsigned int i = 0; i < extsRequired->Size(); ++i) {
+        if ((*extsRequired)[i].IsString()) {
+            exts[(*extsRequired)[i].GetString()] = true;
+        }
+    }
+
+    CHECK_REQUIRED_EXT(KHR_draco_mesh_compression);
+
+    #undef CHECK_REQUIRED_EXT
+}
 
 inline void Asset::ReadExtensionsUsed(Document& doc)
 {

+ 13 - 3
code/glTF2/glTF2Importer.cpp

@@ -204,11 +204,21 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
 
 		if (prop.textureTransformSupported) {
 			aiUVTransform transform;
-			transform.mTranslation.x = prop.TextureTransformExt_t.offset[0];
-			transform.mTranslation.y = prop.TextureTransformExt_t.offset[0];
-			transform.mRotation = prop.TextureTransformExt_t.rotation;
 			transform.mScaling.x = prop.TextureTransformExt_t.scale[0];
 			transform.mScaling.y = prop.TextureTransformExt_t.scale[1];
+			transform.mRotation = -prop.TextureTransformExt_t.rotation; // must be negated
+
+			// A change of coordinates is required to map glTF UV transformations into the space used by
+			// Assimp. In glTF all UV origins are at 0,1 (top left of texture) in Assimp space. In Assimp
+			// rotation occurs around the image center (0.5,0.5) where as in glTF rotation is around the
+			// texture origin. All three can be corrected for solely by a change of the translation since
+			// the transformations available are shape preserving. Note the importer already flips the V
+			// coordinate of the actual meshes during import.
+			const ai_real rcos(cos(-transform.mRotation));
+			const ai_real rsin(sin(-transform.mRotation));
+			transform.mTranslation.x = (0.5 * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0];
+			transform.mTranslation.y = ((0.5 * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];;
+
 			mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot);
 		}
 

+ 10 - 0
include/assimp/Exceptional.h

@@ -119,6 +119,16 @@ struct ExceptionSwallower<void> {
 {\
     try {
 
+#define ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(type, ASSIMP_END_EXCEPTION_REGION_errorString)\
+    } catch(const DeadlyImportError& e) {\
+        ASSIMP_END_EXCEPTION_REGION_errorString = e.what();\
+        return ExceptionSwallower<type>()();\
+    } catch(...) {\
+        ASSIMP_END_EXCEPTION_REGION_errorString = "Unknown exception";\
+        return ExceptionSwallower<type>()();\
+    }\
+}
+
 #define ASSIMP_END_EXCEPTION_REGION(type)\
     } catch(...) {\
         return ExceptionSwallower<type>()();\

+ 7 - 0
include/assimp/version.h

@@ -62,6 +62,13 @@ extern "C" {
  */
 ASSIMP_API const char*  aiGetLegalString  (void);
 
+// ---------------------------------------------------------------------------
+/** @brief Returns the current patch version number of Assimp.
+ *  @return Patch version of the Assimp runtime the application was
+ *    linked/built against
+ */
+ASSIMP_API unsigned int aiGetVersionPatch(void);
+
 // ---------------------------------------------------------------------------
 /** @brief Returns the current minor version number of Assimp.
  *  @return Minor version of the Assimp runtime the application was

+ 181 - 0
test/models/glTF2/MissingBin/BoxTextured.gltf

@@ -0,0 +1,181 @@
+{
+    "asset": {
+        "generator": "COLLADA2GLTF",
+        "version": "2.0"
+    },
+    "scene": 0,
+    "scenes": [
+        {
+            "nodes": [
+                0
+            ]
+        }
+    ],
+    "nodes": [
+        {
+            "children": [
+                1
+            ],
+            "matrix": [
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                -1.0,
+                0.0,
+                0.0,
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ]
+        },
+        {
+            "mesh": 0
+        }
+    ],
+    "meshes": [
+        {
+            "primitives": [
+                {
+                    "attributes": {
+                        "NORMAL": 1,
+                        "POSITION": 2,
+                        "TEXCOORD_0": 3
+                    },
+                    "indices": 0,
+                    "mode": 4,
+                    "material": 0
+                }
+            ],
+            "name": "Mesh"
+        }
+    ],
+    "accessors": [
+        {
+            "bufferView": 0,
+            "byteOffset": 0,
+            "componentType": 5123,
+            "count": 36,
+            "max": [
+                23
+            ],
+            "min": [
+                0
+            ],
+            "type": "SCALAR"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "min": [
+                -1.0,
+                -1.0,
+                -1.0
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 288,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                0.5,
+                0.5,
+                0.5
+            ],
+            "min": [
+                -0.5,
+                -0.5,
+                -0.5
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 2,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                6.0,
+                1.0
+            ],
+            "min": [
+                0.0,
+                0.0
+            ],
+            "type": "VEC2"
+        }
+    ],
+    "materials": [
+        {
+            "pbrMetallicRoughness": {
+                "baseColorTexture": {
+                    "index": 0
+                },
+                "metallicFactor": 0.0
+            },
+            "name": "Texture"
+        }
+    ],
+    "textures": [
+        {
+            "sampler": 0,
+            "source": 0
+        }
+    ],
+    "images": [
+        {
+            "uri": "CesiumLogoFlat.png"
+        }
+    ],
+    "samplers": [
+        {
+            "magFilter": 9729,
+            "minFilter": 9986,
+            "wrapS": 33648,
+            "wrapT": 33071
+        }
+    ],
+    "bufferViews": [
+        {
+            "buffer": 0,
+            "byteOffset": 768,
+            "byteLength": 72,
+            "target": 34963
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 0,
+            "byteLength": 576,
+            "byteStride": 12,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 576,
+            "byteLength": 192,
+            "byteStride": 8,
+            "target": 34962
+        }
+    ],
+    "buffers": [
+        {
+            "byteLength": 840,
+            "uri": "BoxTextured0.bin"
+        }
+    ]
+}

+ 1 - 1
test/unit/utM3DImportExport.cpp

@@ -54,7 +54,7 @@ class utM3DImportExport : public AbstractImportExportBase {
 public:
     virtual bool importerTest() {
         Assimp::Importer importer;
-        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/M3D/WusonBlitz0.m3d", aiProcess_ValidateDataStructure );
+        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/M3D/cube_normals.m3d", aiProcess_ValidateDataStructure );
 #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
         return nullptr != scene;
 #else

+ 9 - 0
test/unit/utglTF2ImportExport.cpp

@@ -426,4 +426,13 @@ TEST_F( utglTF2ImportExport, crash_in_anim_mesh_destructor ) {
     ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF"));
 }
 
+TEST_F(utglTF2ImportExport, error_string_preserved) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/MissingBin/BoxTextured.gltf",
+        aiProcess_ValidateDataStructure);
+    ASSERT_EQ(nullptr, scene);
+    std::string error = importer.GetErrorString();
+    ASSERT_NE(error.find("BoxTextured0.bin"), std::string::npos) << "Error string should contain an error about missing .bin file";
+}
+
 #endif // ASSIMP_BUILD_NO_EXPORT

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است