From 2d086fd23627289fc5fecf87ffd0ecb22640be86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raphael=20D=C3=BCmig?= Date: Fri, 25 Oct 2019 15:10:54 +0200 Subject: [PATCH 01/12] ColladaParser: fix handling of empty XML-elements --- code/Collada/ColladaParser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/Collada/ColladaParser.cpp b/code/Collada/ColladaParser.cpp index 646ec473d..fc7ab8c2f 100644 --- a/code/Collada/ColladaParser.cpp +++ b/code/Collada/ColladaParser.cpp @@ -3236,6 +3236,10 @@ void ColladaParser::TestOpening(const char* pName) // Tests for the closing tag of the given element, throws an exception if not found 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) return; From 805bc2e766fa215f858af1ac787b2766e65f6e4c Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Oct 2019 20:18:39 +0100 Subject: [PATCH 02/12] Update ColladaParser.cpp Add missing brackets. --- code/Collada/ColladaParser.cpp | 69 +++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/code/Collada/ColladaParser.cpp b/code/Collada/ColladaParser.cpp index fc7ab8c2f..d5e4382a5 100644 --- a/code/Collada/ColladaParser.cpp +++ b/code/Collada/ColladaParser.cpp @@ -3170,13 +3170,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); @@ -3191,11 +3190,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 - if (mReader->isEmptyElement()) + if (mReader->isEmptyElement()) { return; + } // reroute SkipElement(mReader->getNodeName()); @@ -3203,67 +3202,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()) + 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() << ">."); From 5cfb0fd633372bbbec87f08015139d71d330d4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc?= Date: Fri, 22 Nov 2019 18:27:34 +0100 Subject: [PATCH 03/12] Add function aiGetVersionPatch() to be able to display Assimp version as in Git tags --- code/Common/Version.cpp | 6 ++++++ include/assimp/version.h | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index cf1da7d5b..ea4c996f0 100644 --- a/code/Common/Version.cpp +++ b/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 () { diff --git a/include/assimp/version.h b/include/assimp/version.h index 2fdd37a43..90645a38f 100644 --- a/include/assimp/version.h +++ b/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 From 929d83398d686d7a7fbe8698413cf57f3e90223f Mon Sep 17 00:00:00 2001 From: Paul Arden Date: Mon, 25 Nov 2019 13:51:33 +1100 Subject: [PATCH 04/12] Remove duplicate call to exporter. Fixes issue #2718. --- code/Common/Exporter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 8a95ceae5..b9bd0409b 100644 --- a/code/Common/Exporter.cpp +++ b/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", must_join_again); exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); pimpl->mProgressHandler->UpdateFileWrite(4, 4); From 9ddeb4edadbd8fa52565f462b8f4d58bd1058ae6 Mon Sep 17 00:00:00 2001 From: bzt Date: Mon, 25 Nov 2019 05:03:10 +0100 Subject: [PATCH 05/12] MinGW support, profiling and signed error code --- code/M3D/m3d.h | 169 +++++++++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 69 deletions(-) diff --git a/code/M3D/m3d.h b/code/M3D/m3d.h index a73e7a02c..c1d690bcc 100644 --- a/code/M3D/m3d.h +++ b/code/M3D/m3d.h @@ -388,7 +388,7 @@ typedef struct { /* label entry */ typedef struct { - char *name; /* name of the annotation group or NULL */ + char *name; /* name of the annotation layer or NULL */ char *lang; /* language code or NULL */ char *text; /* the label text */ uint32_t color; /* color */ @@ -438,7 +438,7 @@ typedef struct { typedef struct { m3dhdr_t *raw; /* pointer to raw data */ char flags; /* internal flags */ - char errcode; /* returned error code */ + signed char errcode; /* returned error code */ char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s,fi_s; /* decoded sizes for types */ char *name; /* name of the model, like "Utah teapot" */ char *license; /* usage condition or license, like "MIT", "LGPL" or "BSD-3clause" */ @@ -1192,7 +1192,6 @@ static int _m3dstbi__parse_zlib(_m3dstbi__zbuf *a, int parse_header) return 0; } else { if (type == 1) { - _m3dstbi__init_zdefaults(); if (!_m3dstbi__zbuild_huffman(&a->z_length , _m3dstbi__zdefault_length , 288)) return 0; if (!_m3dstbi__zbuild_huffman(&a->z_distance, _m3dstbi__zdefault_distance, 32)) return 0; } else { @@ -1210,7 +1209,7 @@ static int _m3dstbi__do_zlib(_m3dstbi__zbuf *a, char *obuf, int olen, int exp, i a->zout = obuf; a->zout_end = obuf + olen; a->z_expandable = exp; - + _m3dstbi__init_zdefaults(); return _m3dstbi__parse_zlib(a, parse_header); } @@ -2012,6 +2011,9 @@ unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *o #include /* get sprintf */ #include /* sprintf and strtod cares about number locale */ #endif +#ifdef M3D_PROFILING +#include +#endif #if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII) /* helper functions for the ASCII parser */ @@ -2088,7 +2090,7 @@ char *_m3d_safestr(char *in, int morelines) } for(; o > out && (*(o-1) == ' ' || *(o-1) == '\t' || *(o-1) == '\r' || *(o-1) == '\n'); o--); *o = 0; - out = (char*)M3D_REALLOC(out, (uint64_t)o - (uint64_t)out + 1); + out = (char*)M3D_REALLOC(out, (uintptr_t)o - (uintptr_t)out + 1); } return out; } @@ -2322,6 +2324,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d m3da_t *a; m3di_t *t; #ifndef M3D_NONORMALS + char neednorm = 0; m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb; #endif #ifndef M3D_NOANIMATION @@ -2339,6 +2342,10 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d const char *ol; char *ptr, *pe, *fn; #endif +#ifdef M3D_PROFILING + struct timeval tv0, tv1, tvd; + gettimeofday(&tv0, NULL); +#endif if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O') #ifdef M3D_ASCII @@ -2647,6 +2654,9 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!*ptr) goto asciiend; } } +#ifndef M3D_NONORMALS + if(model->face[i].normal[j] == (M3D_INDEX)-1U) neednorm = 1; +#endif ptr = _m3d_findarg(ptr); } } @@ -2870,7 +2880,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d pe = _m3d_findarg(pe); if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; buff = (unsigned char*)_m3d_findnl(ptr); - k = ((uint32_t)((uint64_t)buff - (uint64_t)ptr) / 3) + 1; + k = ((uint32_t)((uintptr_t)buff - (uintptr_t)ptr) / 3) + 1; i = model->numextra++; model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); if(!model->extra) goto memerr; @@ -2892,8 +2902,8 @@ asciiend: setlocale(LC_NUMERIC, ol); goto postprocess; } - /* Binary variant */ #endif + /* Binary variant */ if(!M3D_CHUNKMAGIC(data + 8, 'H','E','A','D')) { buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data+8, ((m3dchunk_t*)data)->length-8, 4096, (int*)&len, 1); @@ -2905,6 +2915,14 @@ asciiend: buff = (unsigned char*)M3D_REALLOC(buff, len); model->flags |= M3D_FLG_FREERAW; /* mark that we have to free the raw buffer */ data = buff; +#ifdef M3D_PROFILING + gettimeofday(&tv1, NULL); + tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; + tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Deflate model %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); + memcpy(&tv0, &tv1, sizeof(struct timeval)); +#endif } else { len = ((m3dhdr_t*)data)->length; data += 8; @@ -2961,7 +2979,7 @@ asciiend: return NULL; } if(model->nb_s > M3D_NUMBONE) { - M3D_LOG("Model has more bones per vertex than what importer configured to support"); + M3D_LOG("Model has more bones per vertex than what importer was configured to support"); model->errcode = M3D_ERR_TRUNC; } @@ -3295,6 +3313,9 @@ memerr: M3D_LOG("Out of memory"); /* normal */ if(k & 2) data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]); +#ifndef M3D_NONORMALS + if(model->face[i].normal[j] == (M3D_INDEX)-1U) neednorm = 1; +#endif } } model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); @@ -3454,9 +3475,18 @@ postprocess: #endif if(model) { M3D_LOG("Post-process"); +#ifdef M3D_PROFILING + gettimeofday(&tv1, NULL); + tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; + tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Parsing chunks %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); +#endif #ifndef M3D_NONORMALS - if(model->numface && model->face) { + if(model->numface && model->face && neednorm) { /* if they are missing, calculate triangle normals into a temporary buffer */ + norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t)); + if(!norm) goto memerr; for(i = 0, n = model->numvertex; i < model->numface; i++) if(model->face[i].normal[0] == -1U) { v0 = &model->vertex[model->face[i].vertex[0]]; @@ -3464,10 +3494,6 @@ postprocess: v2 = &model->vertex[model->face[i].vertex[2]]; va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z; vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z; - if(!norm) { - norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t)); - if(!norm) goto memerr; - } v0 = &norm[i]; v0->x = (va.y * vb.z) - (va.z * vb.y); v0->y = (va.z * vb.x) - (va.x * vb.z); @@ -3479,28 +3505,26 @@ postprocess: model->face[i].normal[2] = model->face[i].vertex[2] + n; } /* this is the fast way, we don't care if a normal is repeated in model->vertex */ - if(norm) { - M3D_LOG("Generating normals"); - model->flags |= M3D_FLG_GENNORM; - model->numvertex <<= 1; - model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); - if(!model->vertex) goto memerr; - memset(&model->vertex[n], 0, n * sizeof(m3dv_t)); - for(i = 0; i < model->numface; i++) - for(j = 0; j < 3; j++) { - v0 = &model->vertex[model->face[i].vertex[j] + n]; - v0->x += norm[i].x; - v0->y += norm[i].y; - v0->z += norm[i].z; - } - /* for each vertex, take the average of the temporary normals and use that */ - for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) { - w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); - v0->x *= w; v0->y *= w; v0->z *= w; - v0->skinid = -1U; + M3D_LOG("Generating normals"); + model->flags |= M3D_FLG_GENNORM; + model->numvertex <<= 1; + model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); + if(!model->vertex) goto memerr; + memset(&model->vertex[n], 0, n * sizeof(m3dv_t)); + for(i = 0; i < model->numface; i++) + for(j = 0; j < 3; j++) { + v0 = &model->vertex[model->face[i].vertex[j] + n]; + v0->x += norm[i].x; + v0->y += norm[i].y; + v0->z += norm[i].z; } - M3D_FREE(norm); + /* for each vertex, take the average of the temporary normals and use that */ + for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) { + w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); + v0->x *= w; v0->y *= w; v0->z *= w; + v0->skinid = -1U; } + M3D_FREE(norm); } #endif if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) { @@ -3539,6 +3563,13 @@ postprocess: _m3d_inv((M3D_FLOAT*)&model->bone[i].mat4); #endif } +#ifdef M3D_PROFILING + gettimeofday(&tv0, NULL); + tvd.tv_sec = tv0.tv_sec - tv1.tv_sec; + tvd.tv_usec = tv0.tv_usec - tv1.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Post-process %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); +#endif } return model; } @@ -4509,8 +4540,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); if(model->preview.data && model->preview.length) { sl = _m3d_safestr(sn, 0); if(sl) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + 20; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + 20; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl); M3D_FREE(sl); sl = NULL; @@ -4519,8 +4550,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); M3D_FREE(sn); sn = NULL; /* texture map */ if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + maxtmap * 32 + 12; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + maxtmap * 32 + 12; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Textmap\r\n"); last = (M3D_INDEX)-1U; @@ -4533,8 +4564,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } /* vertex chunk */ if(numvrtx && vrtx && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + maxvrtx * 128 + 10; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + maxvrtx * 128 + 10; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Vertex\r\n"); last = (M3D_INDEX)-1U; @@ -4559,11 +4590,11 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } /* bones chunk */ if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + 9; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + 9; for(i = 0; i < model->numbone; i++) { len += strlen(model->bone[i].name) + 128; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Bones\r\n"); ptr = _m3d_prtbone(ptr, model->bone, model->numbone, (M3D_INDEX)-1U, 0, vrtxidx); @@ -4576,14 +4607,14 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); m = &model->material[j]; sn = _m3d_safestr(m->name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 12; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 12; for(i = 0; i < m->numprop; i++) { if(m->prop[i].type < 128) len += 32; else if(m->prop[i].value.textureid < model->numtexture && model->texture[m->prop[i].value.textureid].name) len += strlen(model->texture[m->prop[i].value.textureid].name) + 16; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Material %s\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -4645,8 +4676,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); if(k) continue; sn = _m3d_safestr(model->inlined[j].name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 18; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 18; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Procedural\r\n%s\r\n\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -4654,7 +4685,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } /* mesh face */ if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + model->numface * 128 + 6; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + model->numface * 128 + 6; last = (M3D_INDEX)-1U; if(!(flags & M3D_EXP_NOMATERIAL)) for(i = 0; i < model->numface; i++) { @@ -4666,7 +4697,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); len += 6; } } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Mesh\r\n"); last = (M3D_INDEX)-1U; @@ -4703,8 +4734,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); for(j = 0; j < model->numshape; j++) { sn = _m3d_safestr(model->shape[j].name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 33; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 33; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Shape %s\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -4715,14 +4746,14 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) continue; cd = &m3d_commandtypes[cmd->type]; - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(cd->key) + 3; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(cd->key) + 3; for(k = 0; k < cd->p; k++) switch(cd->a[k]) { case m3dcp_mi_t: if(cmd->arg[k] != -1U) { len += strlen(model->material[cmd->arg[k]].name) + 1; } break; case m3dcp_va_t: len += cmd->arg[k] * (cd->p - k - 1) * 16; k = cd->p; break; default: len += 16; break; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "%s", cd->key); for(k = n = 0, l = cd->p; k < l; k++) { @@ -4755,8 +4786,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); if(model->label[i].text) j += strlen(model->label[i].text); j += 40; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + j; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + j; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } for(i = 0; i < model->numlabel; i++) { if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { @@ -4790,10 +4821,10 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); a = &model->action[j]; sn = _m3d_safestr(a->name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 48; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 48; for(i = 0; i < a->numframe; i++) len += a->frame[i].numtransform * 128 + 8; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Action %d %s\r\n", a->durationmsec, sn); M3D_FREE(sn); sn = NULL; @@ -4813,8 +4844,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); if(model->inlined[i].name) j += strlen(model->inlined[i].name) + 6; if(j > 0) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + j + 16; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + j + 16; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Assets\r\n"); for(i = 0; i < model->numinlined; i++) @@ -4827,8 +4858,8 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); if(model->numextra && (flags & M3D_EXP_EXTRA)) { for(i = 0; i < model->numextra; i++) { if(model->extra[i]->length < 9) continue; - ptr -= (uint64_t)out; len = (uint64_t)ptr + 17 + model->extra[i]->length * 3; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (uintptr_t)ptr + 17 + model->extra[i]->length * 3; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Extra %c%c%c%c\r\n", model->extra[i]->magic[0] > ' ' ? model->extra[i]->magic[0] : '_', @@ -4842,7 +4873,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } } setlocale(LC_NUMERIC, ol); - len = (uint64_t)ptr - (uint64_t)out; + len = (uintptr_t)ptr - (uintptr_t)out; out = (unsigned char*)M3D_REALLOC(out, len + 1); if(!out) goto memerr; out[len] = 0; @@ -4943,7 +4974,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); case 8: *((double*)out) = tmap[i].data.u; out += 8; *((double*)out) = tmap[i].data.v; out += 8; break; } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); out = NULL; len += *length; } @@ -4993,7 +5024,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } out = _m3d_addidx(out, sk_s, vrtx[i].data.skinid); } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); out = NULL; len += *length; } @@ -5035,7 +5066,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); out = NULL; len += *length; } @@ -5084,7 +5115,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); break; } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); len += *length; out = NULL; } @@ -5144,7 +5175,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.normal[j]]); } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); len += *length; out = NULL; } @@ -5195,7 +5226,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); } } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); len += *length; out = NULL; } @@ -5207,7 +5238,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); sl = model->label[i].lang; sn = model->label[i].name; if(length) { - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); len += *length; } chunklen = 8 + 2 * si_s + ci_s + model->numlabel * (vi_s + si_s); @@ -5229,7 +5260,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].text)); } if(length) { - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); len += *length; } out = NULL; @@ -5257,7 +5288,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx); out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].ori]); } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len); len += *length; out = NULL; } From 7230f32c143d656f365d628de1d7ad1f14dced61 Mon Sep 17 00:00:00 2001 From: Paul Arden Date: Mon, 25 Nov 2019 20:58:21 +1100 Subject: [PATCH 06/12] Fix issue with y UV translation. Fixes #2119. --- code/glTF2/glTF2Importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 43eabdab7..88345f98a 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -205,7 +205,7 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset if (prop.textureTransformSupported) { aiUVTransform transform; transform.mTranslation.x = prop.TextureTransformExt_t.offset[0]; - transform.mTranslation.y = prop.TextureTransformExt_t.offset[0]; + transform.mTranslation.y = prop.TextureTransformExt_t.offset[1]; transform.mRotation = prop.TextureTransformExt_t.rotation; transform.mScaling.x = prop.TextureTransformExt_t.scale[0]; transform.mScaling.y = prop.TextureTransformExt_t.scale[1]; From b4f778f53b11340facb26371d2e0ae3e6c12dda2 Mon Sep 17 00:00:00 2001 From: Paul Arden Date: Tue, 26 Nov 2019 18:17:35 +1100 Subject: [PATCH 07/12] Fix aiGetMaterialUVTransform which assumed the data was 4 floats when in fact it is 5 floats. Fixes and issue seen in #2119. --- code/Material/MaterialSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/Material/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp index fabd9415a..aa3df9ac2 100644 --- a/code/Material/MaterialSystem.cpp +++ b/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); } From e4f1b8e609d6957ea664e1759600a8b6600d1189 Mon Sep 17 00:00:00 2001 From: Paul Arden Date: Wed, 27 Nov 2019 11:05:31 +1100 Subject: [PATCH 08/12] Correctly change the coordinate system of the glTF UV transforms to match those used internally inside Assimp. This should now hopefully result in a complete implementation for issue #2119 --- code/glTF2/glTF2Importer.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 88345f98a..1868ec119 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -204,11 +204,21 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset if (prop.textureTransformSupported) { aiUVTransform transform; - transform.mTranslation.x = prop.TextureTransformExt_t.offset[0]; - transform.mTranslation.y = prop.TextureTransformExt_t.offset[1]; - 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. + ai_real rcos(cos(-transform.mRotation)); + 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); } From 30851b796faaac0bd7fcb74974a06dd411784a3a Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 27 Nov 2019 17:18:12 +0100 Subject: [PATCH 09/12] Update glTF2Importer.cpp Make them const --- code/glTF2/glTF2Importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 1868ec119..dd80aeba9 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -214,8 +214,8 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset // 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. - ai_real rcos(cos(-transform.mRotation)); - ai_real rsin(sin(-transform.mRotation)); + 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];; From 4754d2dc6d13276a9e8b0586a83afd53840916c4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 27 Nov 2019 17:32:55 +0100 Subject: [PATCH 10/12] Update CMakeLists.txt - closes https://github.com/assimp/assimp/issues/2785 - Disable optimization in debug mode. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 693d6f16a..4caaaf4a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,7 +253,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}") From 97b71dd03b6a4caafa1be137fa036d142846d1ce Mon Sep 17 00:00:00 2001 From: Paul Arden Date: Thu, 28 Nov 2019 09:01:01 +1000 Subject: [PATCH 11/12] Add reading of extensionsRequired and explicit check to throw an error if Draco compression is required. Fixes issue #2791. --- code/glTF2/glTF2Asset.h | 8 ++++++++ code/glTF2/glTF2Asset.inl | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index 831a763cd..d13ebfd66 100644 --- a/code/glTF2/glTF2Asset.h +++ b/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& sceneData); void ReadExtensionsUsed(Document& doc); + void ReadExtensionsRequired(Document& doc); IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); }; diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 4259022e9..32bca88ce 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -1432,6 +1432,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 +1484,28 @@ 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 (!extsRequired) return; + + std::gltf_unordered_map 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) { From 7967deb06a7c549d16133330e3d383faa84f425f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 1 Dec 2019 12:34:45 +0100 Subject: [PATCH 12/12] Update glTF2Asset.inl some minor review finding: use brackets and add a newline. --- code/glTF2/glTF2Asset.inl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 32bca88ce..99f8c876f 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -1492,10 +1492,11 @@ inline void Asset::SetAsBinary() inline void Asset::ReadExtensionsRequired(Document& doc) { Value* extsRequired = FindArray(doc, "extensionsRequired"); - if (!extsRequired) return; + if (nullptr == extsRequired) { + return; + } std::gltf_unordered_map exts; - for (unsigned int i = 0; i < extsRequired->Size(); ++i) { if ((*extsRequired)[i].IsString()) { exts[(*extsRequired)[i].GetString()] = true;