From dd1474e2801c6e0261e8a2d88fbe189789f76d14 Mon Sep 17 00:00:00 2001 From: ThatOSDev <100424906+ThatOSDev@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:12:58 -0600 Subject: [PATCH 01/10] Update zip.c (#5639) Now works with GCC without failing the compilation. Co-authored-by: Kim Kulling --- contrib/zip/src/zip.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c index ac520a265..deef56178 100644 --- a/contrib/zip/src/zip.c +++ b/contrib/zip/src/zip.c @@ -13,10 +13,14 @@ #include #include +#if defined(_MSC_VER) +/* For Visual Studio only, NOT MinGW (GCC) -- ThatOSDev */ +#pragma warning( disable : 4706 ) +#endif + #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) -/* Win32, DOS, MSVC, MSVS */ -#pragma warning( disable : 4706 ) +/* Win32, DOS, MSVC, MSVS, MinGW(GCC for windows) */ #include #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) From 35976a4eb460632c4565234ee5d7105fc1ee2086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20M=C3=B6ller?= Date: Tue, 2 Jul 2024 21:54:18 +0200 Subject: [PATCH 02/10] fixes some uninit bool loads (#5644) This commit fixes some bool loads which are not initialized. With ubsan and the "option -fsanitize=bool", this results in a runtime error during test execution. Co-authored-by: Kim Kulling --- .../LimitBoneWeightsProcess.cpp | 3 ++- include/assimp/metadata.h | 12 +++++------ test/unit/utMetadata.cpp | 20 +++++++++++++++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/code/PostProcessing/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp index 816914ada..71b6f9ec6 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -53,7 +53,8 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) { +LimitBoneWeightsProcess::LimitBoneWeightsProcess() : + mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) { // empty } diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index 8d387ca00..4fd4adf7e 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -113,19 +113,19 @@ struct aiMetadata; */ // ------------------------------------------------------------------------------- -inline aiMetadataType GetAiType(bool) { +inline aiMetadataType GetAiType(const bool &) { return AI_BOOL; } inline aiMetadataType GetAiType(int32_t) { return AI_INT32; } -inline aiMetadataType GetAiType(uint64_t) { +inline aiMetadataType GetAiType(const uint64_t &) { return AI_UINT64; } -inline aiMetadataType GetAiType(float) { +inline aiMetadataType GetAiType(const float &) { return AI_FLOAT; } -inline aiMetadataType GetAiType(double) { +inline aiMetadataType GetAiType(const double &) { return AI_DOUBLE; } inline aiMetadataType GetAiType(const aiString &) { @@ -137,10 +137,10 @@ inline aiMetadataType GetAiType(const aiVector3D &) { inline aiMetadataType GetAiType(const aiMetadata &) { return AI_AIMETADATA; } -inline aiMetadataType GetAiType(int64_t) { +inline aiMetadataType GetAiType(const int64_t &) { return AI_INT64; } -inline aiMetadataType GetAiType(uint32_t) { +inline aiMetadataType GetAiType(const uint32_t &) { return AI_UINT32; } diff --git a/test/unit/utMetadata.cpp b/test/unit/utMetadata.cpp index e7cd239aa..76afd52ef 100644 --- a/test/unit/utMetadata.cpp +++ b/test/unit/utMetadata.cpp @@ -242,6 +242,22 @@ TEST_F( utMetadata, copy_test ) { EXPECT_EQ( i32v, v ); } + // uint32_t test + { + uint32_t v = 0; + bool ok = copy.Get("uint32_t", v); + EXPECT_TRUE(ok); + EXPECT_EQ( ui32, v ); + } + + // int64_t test + { + int64_t v = -1; + bool ok = copy.Get("int64_t", v); + EXPECT_TRUE(ok); + EXPECT_EQ( i64, v ); + } + // uint64_t test { uint64_t v = 255; @@ -264,14 +280,14 @@ TEST_F( utMetadata, copy_test ) { EXPECT_EQ( dv, v ); } - // bool test + // string test { aiString v; EXPECT_TRUE( copy.Get( "aiString", v ) ); EXPECT_EQ( strVal, v ); } - // bool test + // vector test { aiVector3D v; EXPECT_TRUE( copy.Get( "aiVector3D", v ) ); From 7e053cc64104605898bb5c48f6b245ca3e1edab3 Mon Sep 17 00:00:00 2001 From: Markus Prettner Date: Tue, 2 Jul 2024 22:11:52 +0200 Subject: [PATCH 03/10] Fix names of enum values in docstring of aiProcess_FindDegenerates (#5640) Co-authored-by: Kim Kulling --- include/assimp/postprocess.h | 2 +- port/PyAssimp/pyassimp/postprocess.py | 2 +- port/dAssimp/assimp/postprocess.d | 2 +- port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index 962d500f8..4fcbbea37 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -379,7 +379,7 @@ enum aiPostProcessSteps * point primitives to separate meshes. * *
  • Set the #AI_CONFIG_PP_SBP_REMOVE importer property to - * @code aiPrimitiveType_POINTS | aiPrimitiveType_LINES + * @code aiPrimitiveType_POINT | aiPrimitiveType_LINE * @endcode to cause SortByPType to reject point * and line meshes from the scene. *
  • diff --git a/port/PyAssimp/pyassimp/postprocess.py b/port/PyAssimp/pyassimp/postprocess.py index 0c55d6798..f5a4ac414 100644 --- a/port/PyAssimp/pyassimp/postprocess.py +++ b/port/PyAssimp/pyassimp/postprocess.py @@ -270,7 +270,7 @@ aiProcess_SortByPType = 0x8000 # point primitives to separate meshes. #
  • #
  • Set the AI_CONFIG_PP_SBP_REMOVE option to -# @code aiPrimitiveType_POINTS | aiPrimitiveType_LINES +# @code aiPrimitiveType_POINT | aiPrimitiveType_LINE # @endcode to cause SortByPType to reject point # and line meshes from the scene. #
  • diff --git a/port/dAssimp/assimp/postprocess.d b/port/dAssimp/assimp/postprocess.d index 343bb36dd..ec0d82dbd 100644 --- a/port/dAssimp/assimp/postprocess.d +++ b/port/dAssimp/assimp/postprocess.d @@ -348,7 +348,7 @@ extern ( C ) { *
  • Specify the SortByPType flag. This moves line and * point primitives to separate meshes.
  • *
  • Set the AI_CONFIG_PP_SBP_REMOVE option to - * aiPrimitiveType_POINTS | aiPrimitiveType_LINES + * aiPrimitiveType_POINT | aiPrimitiveType_LINE * to cause SortByPType to reject point and line meshes from the * scene.
  • * diff --git a/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java b/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java index 7bb617b2c..44d400f58 100644 --- a/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java +++ b/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java @@ -349,7 +349,7 @@ public enum AiPostProcessSteps { *
  • Specify the #SortByPType flag. This moves line and point * primitives to separate meshes. *
  • Set the AI_CONFIG_PP_SBP_REMOVE option to - * aiPrimitiveType_POINTS | aiPrimitiveType_LINES + * aiPrimitiveType_POINT | aiPrimitiveType_LINE * to cause SortByPType to reject point and line meshes from the * scene. * From 625528d02c17505e752ae63d8d23132782046807 Mon Sep 17 00:00:00 2001 From: Brad D <59133880+bedwardly-down@users.noreply.github.com> Date: Wed, 3 Jul 2024 03:05:58 -0500 Subject: [PATCH 04/10] Fix: StackAllocator Undefined Reference fix (#5650) Co-authored-by: Kim Kulling --- code/Common/StackAllocator.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h index a5d97c22d..fcb72a09e 100644 --- a/code/Common/StackAllocator.h +++ b/code/Common/StackAllocator.h @@ -88,6 +88,11 @@ private: } // namespace Assimp +/// @brief Fixes an undefined reference error when linking in certain build environments. +// May throw warnings about needing stdc++17, but should compile without issues on modern compilers. +inline const size_t Assimp::StackAllocator::g_maxBytesPerBlock; +inline const size_t Assimp::StackAllocator::g_startBytesPerBlock; + #include "StackAllocator.inl" #endif // include guard From ddb74c2bbdee1565dda667e85f0c82a0588c8053 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 3 Jul 2024 21:37:24 +0200 Subject: [PATCH 05/10] Fix out of bound access (#5651) --- code/AssetLib/Ply/PlyLoader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/AssetLib/Ply/PlyLoader.cpp b/code/AssetLib/Ply/PlyLoader.cpp index 3e92339fb..0c2463f24 100644 --- a/code/AssetLib/Ply/PlyLoader.cpp +++ b/code/AssetLib/Ply/PlyLoader.cpp @@ -564,6 +564,10 @@ void PLYImporter::LoadFace(const PLY::Element *pcElement, const PLY::ElementInst if (mGeneratedMesh->mFaces == nullptr) { mGeneratedMesh->mNumFaces = pcElement->NumOccur; mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; + } else { + if (mGeneratedMesh->mNumFaces < pcElement->NumOccur) { + throw DeadlyImportError("Invalid .ply file: Too many faces"); + } } if (!bIsTriStrip) { From fe6e25080be4efc44a4a4df833b99019e963305a Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 5 Jul 2024 13:43:50 +0200 Subject: [PATCH 06/10] Docker: Fix security finding (#5655) - Use --no-install-recommends to avoid getting more deps than needed --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index eb5715d0f..716e8b5d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:22.04 -RUN apt-get update && apt-get install -y ninja-build \ +RUN apt-get update && apt-get install --no-install-recommends -y ninja-build \ git cmake build-essential software-properties-common RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update From d5cb1fe01f3e38d611ba30348ab3f2851fdb3402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20M=C3=B6ller?= Date: Sat, 6 Jul 2024 08:27:05 +0200 Subject: [PATCH 07/10] Fix potential heapbuffer overflow in md5 parsing (#5652) --- code/AssetLib/MD5/MD5Parser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/AssetLib/MD5/MD5Parser.cpp b/code/AssetLib/MD5/MD5Parser.cpp index 24882af7e..2de8d5033 100644 --- a/code/AssetLib/MD5/MD5Parser.cpp +++ b/code/AssetLib/MD5/MD5Parser.cpp @@ -234,8 +234,12 @@ inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *buf AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber); if ('(' != **sz) { MD5Parser::ReportWarning("Unexpected token: ( was expected", linenumber); + if (*sz == bufferEnd) + return; ++*sz; } + if (*sz == bufferEnd) + return; ++*sz; AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber); *sz = fast_atoreal_move(*sz, (float &)vec.x); @@ -247,6 +251,8 @@ inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *buf if (')' != **sz) { MD5Parser::ReportWarning("Unexpected token: ) was expected", linenumber); } + if (*sz == bufferEnd) + return; ++*sz; } From bff00b15f13df3f0afa77ef23b60685dadfbfd55 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 6 Jul 2024 13:59:02 +0200 Subject: [PATCH 08/10] Replace raw pointers by std::string (#5656) * Replace raw pointers by std::string --- code/AssetLib/3MF/XmlSerializer.cpp | 10 +- code/AssetLib/AMF/AMFImporter.cpp | 27 +- code/AssetLib/AMF/AMFImporter.hpp | 1 - code/AssetLib/AMF/AMFImporter_Node.hpp | 15 - code/AssetLib/AMF/AMFImporter_Postprocess.cpp | 5 +- code/AssetLib/ASE/ASELoader.cpp | 29 +- code/AssetLib/ASE/ASELoader.h | 7 +- code/AssetLib/ASE/ASEParser.cpp | 553 +++++++++--------- code/AssetLib/ASE/ASEParser.h | 11 +- test/unit/utB3DImportExport.cpp | 2 +- 10 files changed, 312 insertions(+), 348 deletions(-) diff --git a/code/AssetLib/3MF/XmlSerializer.cpp b/code/AssetLib/3MF/XmlSerializer.cpp index 354ed19bb..fdc9f5a3d 100644 --- a/code/AssetLib/3MF/XmlSerializer.cpp +++ b/code/AssetLib/3MF/XmlSerializer.cpp @@ -57,8 +57,8 @@ static constexpr size_t ColRGBA_Len = 9; static constexpr size_t ColRGB_Len = 7; // format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1) -bool validateColorString(const char *color) { - const size_t len = strlen(color); +bool validateColorString(const std::string color) { + const size_t len = color.size(); if (ColRGBA_Len != len && ColRGB_Len != len) { return false; } @@ -157,8 +157,8 @@ aiMatrix4x4 parseTransformMatrix(const std::string& matrixStr) { return transformMatrix; } -bool parseColor(const char *color, aiColor4D &diffuse) { - if (nullptr == color) { +bool parseColor(const std::string &color, aiColor4D &diffuse) { + if (color.empty()) { return false; } @@ -178,7 +178,7 @@ bool parseColor(const char *color, aiColor4D &diffuse) { char b[3] = { color[5], color[6], '\0' }; diffuse.b = static_cast(strtol(b, nullptr, 16)) / ai_real(255.0); - const size_t len = strlen(color); + const size_t len = color.size(); if (ColRGB_Len == len) { return true; } diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index 7c0d3b4e9..42f9664be 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -178,28 +178,6 @@ bool AMFImporter::XML_SearchNode(const std::string &nodeName) { return nullptr != mXmlParser->findNode(nodeName); } -void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) { - size_t instr_len; - - pOutString.clear(); - instr_len = strlen(pInStr); - if (!instr_len) return; - - pOutString.reserve(instr_len * 3 / 2); - // check and correct floats in format ".x". Must be "x.y". - if (pInStr[0] == '.') pOutString.push_back('0'); - - pOutString.push_back(pInStr[0]); - for (size_t ci = 1; ci < instr_len; ci++) { - if ((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) { - pOutString.push_back('0'); - pOutString.push_back('.'); - } else { - pOutString.push_back(pInStr[ci]); - } - } -} - static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) { return (isalnum((unsigned char)pChar) || (pChar == '+') || (pChar == '/')); } @@ -213,7 +191,10 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std uint8_t arr4[4], arr3[3]; // check input data - if (pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four."); + if (pInputBase64.size() % 4) { + throw DeadlyImportError("Base64-encoded data must have size multiply of four."); + } + // prepare output place pOutputData.clear(); pOutputData.reserve(pInputBase64.size() / 4 * 3); diff --git a/code/AssetLib/AMF/AMFImporter.hpp b/code/AssetLib/AMF/AMFImporter.hpp index 50be465ce..97e0a7118 100644 --- a/code/AssetLib/AMF/AMFImporter.hpp +++ b/code/AssetLib/AMF/AMFImporter.hpp @@ -168,7 +168,6 @@ public: AI_WONT_RETURN void Throw_ID_NotFound(const std::string &pID) const AI_WONT_RETURN_SUFFIX; void XML_CheckNode_MustHaveChildren(pugi::xml_node &node); bool XML_SearchNode(const std::string &nodeName); - void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString); AMFImporter(const AMFImporter &pScene) = delete; AMFImporter &operator=(const AMFImporter &pScene) = delete; diff --git a/code/AssetLib/AMF/AMFImporter_Node.hpp b/code/AssetLib/AMF/AMFImporter_Node.hpp index 21068a9ba..2b4f6717d 100644 --- a/code/AssetLib/AMF/AMFImporter_Node.hpp +++ b/code/AssetLib/AMF/AMFImporter_Node.hpp @@ -56,7 +56,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -/// \class CAMFImporter_NodeElement /// Base class for elements of nodes. class AMFNodeElementBase { public: @@ -106,7 +105,6 @@ protected: } }; // class IAMFImporter_NodeElement -/// \struct CAMFImporter_NodeElement_Constellation /// A collection of objects or constellations with specific relative locations. struct AMFConstellation : public AMFNodeElementBase { /// Constructor. @@ -116,7 +114,6 @@ struct AMFConstellation : public AMFNodeElementBase { }; // struct CAMFImporter_NodeElement_Constellation -/// \struct CAMFImporter_NodeElement_Instance /// Part of constellation. struct AMFInstance : public AMFNodeElementBase { @@ -135,7 +132,6 @@ struct AMFInstance : public AMFNodeElementBase { AMFNodeElementBase(ENET_Instance, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Metadata /// Structure that define metadata node. struct AMFMetadata : public AMFNodeElementBase { @@ -148,7 +144,6 @@ struct AMFMetadata : public AMFNodeElementBase { AMFNodeElementBase(ENET_Metadata, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Root /// Structure that define root node. struct AMFRoot : public AMFNodeElementBase { @@ -161,7 +156,6 @@ struct AMFRoot : public AMFNodeElementBase { AMFNodeElementBase(ENET_Root, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Color /// Structure that define object node. struct AMFColor : public AMFNodeElementBase { bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. @@ -177,7 +171,6 @@ struct AMFColor : public AMFNodeElementBase { } }; -/// \struct CAMFImporter_NodeElement_Material /// Structure that define material node. struct AMFMaterial : public AMFNodeElementBase { @@ -187,7 +180,6 @@ struct AMFMaterial : public AMFNodeElementBase { AMFNodeElementBase(ENET_Material, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Object /// Structure that define object node. struct AMFObject : public AMFNodeElementBase { @@ -206,7 +198,6 @@ struct AMFMesh : public AMFNodeElementBase { AMFNodeElementBase(ENET_Mesh, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Vertex /// Structure that define vertex node. struct AMFVertex : public AMFNodeElementBase { /// Constructor. @@ -215,7 +206,6 @@ struct AMFVertex : public AMFNodeElementBase { AMFNodeElementBase(ENET_Vertex, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Edge /// Structure that define edge node. struct AMFEdge : public AMFNodeElementBase { /// Constructor. @@ -224,7 +214,6 @@ struct AMFEdge : public AMFNodeElementBase { AMFNodeElementBase(ENET_Edge, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Vertices /// Structure that define vertices node. struct AMFVertices : public AMFNodeElementBase { /// Constructor. @@ -233,7 +222,6 @@ struct AMFVertices : public AMFNodeElementBase { AMFNodeElementBase(ENET_Vertices, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Volume /// Structure that define volume node. struct AMFVolume : public AMFNodeElementBase { std::string MaterialID; ///< Which material to use. @@ -245,7 +233,6 @@ struct AMFVolume : public AMFNodeElementBase { AMFNodeElementBase(ENET_Volume, pParent) {} }; -/// \struct CAMFImporter_NodeElement_Coordinates /// Structure that define coordinates node. struct AMFCoordinates : public AMFNodeElementBase { aiVector3D Coordinate; ///< Coordinate. @@ -256,7 +243,6 @@ struct AMFCoordinates : public AMFNodeElementBase { AMFNodeElementBase(ENET_Coordinates, pParent) {} }; -/// \struct CAMFImporter_NodeElement_TexMap /// Structure that define texture coordinates node. struct AMFTexMap : public AMFNodeElementBase { aiVector3D TextureCoordinate[3]; ///< Texture coordinates. @@ -273,7 +259,6 @@ struct AMFTexMap : public AMFNodeElementBase { } }; -/// \struct CAMFImporter_NodeElement_Triangle /// Structure that define triangle node. struct AMFTriangle : public AMFNodeElementBase { size_t V[3]; ///< Triangle vertices. diff --git a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp index 969c64bd2..bc6fb42a8 100644 --- a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp +++ b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp @@ -224,7 +224,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string & } // Create format hint. - strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string. + constexpr char templateColor[] = "rgba0000"; + memcpy(converted_texture.FormatHint, templateColor, 8); if (!r.empty()) converted_texture.FormatHint[4] = '8'; if (!g.empty()) converted_texture.FormatHint[5] = '8'; if (!b.empty()) converted_texture.FormatHint[6] = '8'; @@ -867,7 +868,7 @@ nl_clean_loop: pScene->mTextures[idx]->mHeight = static_cast(tex_convd.Height); pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data; // texture format description. - strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint); + strncpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint, HINTMAXTEXTURELEN); idx++; } // for(const SPP_Texture& tex_convd: mTexture_Converted) diff --git a/code/AssetLib/ASE/ASELoader.cpp b/code/AssetLib/ASE/ASELoader.cpp index 7e411fc03..c5f2eba32 100644 --- a/code/AssetLib/ASE/ASELoader.cpp +++ b/code/AssetLib/ASE/ASELoader.cpp @@ -124,7 +124,7 @@ void ASEImporter::InternReadFile(const std::string &pFile, // Allocate storage and copy the contents of the file to a memory buffer std::vector mBuffer2; TextFileToBuffer(file.get(), mBuffer2); - + const size_t fileSize = mBuffer2.size(); this->mBuffer = &mBuffer2[0]; this->pcScene = pScene; @@ -146,7 +146,7 @@ void ASEImporter::InternReadFile(const std::string &pFile, }; // Construct an ASE parser and parse the file - ASE::Parser parser(mBuffer, defaultFormat); + ASE::Parser parser(mBuffer, fileSize, defaultFormat); mParser = &parser; mParser->Parse(); @@ -446,10 +446,9 @@ void ASEImporter::BuildLights() { } // ------------------------------------------------------------------------------------------------ -void ASEImporter::AddNodes(const std::vector &nodes, - aiNode *pcParent, const char *szName) { +void ASEImporter::AddNodes(const std::vector &nodes, aiNode *pcParent, const std::string &name) { aiMatrix4x4 m; - AddNodes(nodes, pcParent, szName, m); + AddNodes(nodes, pcParent, name, m); } // ------------------------------------------------------------------------------------------------ @@ -506,10 +505,9 @@ void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) { // ------------------------------------------------------------------------------------------------ // Add child nodes to a given parent node -void ASEImporter::AddNodes(const std::vector &nodes, - aiNode *pcParent, const char *szName, +void ASEImporter::AddNodes(const std::vector &nodes, aiNode *pcParent, const std::string &name, const aiMatrix4x4 &mat) { - const size_t len = szName ? ::strlen(szName) : 0; + const size_t len = name.size(); ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); // Receives child nodes for the pcParent node @@ -519,16 +517,18 @@ void ASEImporter::AddNodes(const std::vector &nodes, // which has *us* as parent. for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { const BaseNode *snode = *it; - if (szName) { - if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str())) + if (!name.empty()) { + if (len != snode->mParent.length() || name != snode->mParent.c_str()) { continue; - } else if (snode->mParent.length()) + } + } else if (snode->mParent.length()) { continue; + } (*it)->mProcessed = true; // Allocate a new node and add it to the output data structure - apcNodes.push_back(new aiNode()); + apcNodes.push_back(new aiNode); aiNode *node = apcNodes.back(); node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node")); @@ -541,7 +541,7 @@ void ASEImporter::AddNodes(const std::vector &nodes, // Add sub nodes - prevent stack overflow due to recursive parenting if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName) { - AddNodes(nodes, node, node->mName.data, snode->mTransform); + AddNodes(nodes, node, node->mName.C_Str(), snode->mTransform); } // Further processing depends on the type of the node @@ -619,7 +619,8 @@ void ASEImporter::BuildNodes(std::vector &nodes) { } // add all nodes - AddNodes(nodes, ch, nullptr); + static const std::string none = ""; + AddNodes(nodes, ch, none); // now iterate through al nodes and find those that have not yet // been added to the nodegraph (= their parent could not be recognized) diff --git a/code/AssetLib/ASE/ASELoader.h b/code/AssetLib/ASE/ASELoader.h index 5654fa630..99d5119ed 100644 --- a/code/AssetLib/ASE/ASELoader.h +++ b/code/AssetLib/ASE/ASELoader.h @@ -153,13 +153,13 @@ private: * \param matrix Current transform */ void AddNodes(const std::vector& nodes, - aiNode* pcParent,const char* szName); + aiNode* pcParent, const std::string &name); void AddNodes(const std::vector& nodes, - aiNode* pcParent,const char* szName, + aiNode* pcParent, const std::string &name, const aiMatrix4x4& matrix); - void AddMeshes(const ASE::BaseNode* snode,aiNode* node); + void AddMeshes(const ASE::BaseNode* snode, aiNode* node); // ------------------------------------------------------------------- /** Generate a default material and add it to the parser's list @@ -188,5 +188,4 @@ protected: } // end of namespace Assimp - #endif // AI_3DSIMPORTER_H_INC diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index c071ae900..02d21f41b 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -66,23 +66,24 @@ using namespace Assimp::ASE; // Handle a "top-level" section in the file. EOF is no error in this case. #define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \ - else if ('{' == *filePtr) iDepth++; \ - else if ('}' == *filePtr) { \ + else if ('{' == *mFilePtr) \ + ++iDepth; \ + else if ('}' == *mFilePtr) { \ if (0 == --iDepth) { \ - ++filePtr; \ + ++mFilePtr; \ SkipToNextToken(); \ return; \ } \ } \ - if ('\0' == *filePtr) { \ + if ('\0' == *mFilePtr) { \ return; \ } \ - if (IsLineEnd(*filePtr) && !bLastWasEndLine) { \ + if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {\ ++iLineNumber; \ bLastWasEndLine = true; \ } else \ bLastWasEndLine = false; \ - ++filePtr; + ++mFilePtr; // ------------------------------------------------------------------------------------------------ // Handle a nested section in the file. EOF is an error in this case @@ -90,32 +91,32 @@ using namespace Assimp::ASE; // @param msg Full name of the section (including the asterisk) #define AI_ASE_HANDLE_SECTION(level, msg) \ - if ('{' == *filePtr) \ + if ('{' == *mFilePtr) \ iDepth++; \ - else if ('}' == *filePtr) { \ + else if ('}' == *mFilePtr) { \ if (0 == --iDepth) { \ - ++filePtr; \ + ++mFilePtr; \ SkipToNextToken(); \ return; \ } \ - } else if ('\0' == *filePtr) { \ + } else if ('\0' == *mFilePtr) { \ LogError("Encountered unexpected EOL while parsing a " msg \ " chunk (Level " level ")"); \ } \ - if (IsLineEnd(*filePtr) && !bLastWasEndLine) { \ + if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) { \ ++iLineNumber; \ bLastWasEndLine = true; \ } else \ bLastWasEndLine = false; \ - ++filePtr; + ++mFilePtr; // ------------------------------------------------------------------------------------------------ -Parser::Parser(const char *szFile, unsigned int fileFormatDefault) : - filePtr(nullptr), mEnd (nullptr) { - ai_assert(nullptr != szFile); +Parser::Parser(const char *file, size_t fileLen, unsigned int fileFormatDefault) : + mFilePtr(nullptr), mEnd (nullptr) { + ai_assert(file != nullptr); - filePtr = szFile; - mEnd = filePtr + std::strlen(filePtr); + mFilePtr = file; + mEnd = mFilePtr + fileLen; iFileFormat = fileFormatDefault; // make sure that the color values are invalid @@ -179,9 +180,9 @@ AI_WONT_RETURN void Parser::LogError(const char *szWarn) { // ------------------------------------------------------------------------------------------------ bool Parser::SkipToNextToken() { while (true) { - char me = *filePtr; + char me = *mFilePtr; - if (filePtr == mEnd) { + if (mFilePtr == mEnd) { return false; } @@ -198,7 +199,7 @@ bool Parser::SkipToNextToken() { return false; } - ++filePtr; + ++mFilePtr; } } @@ -207,22 +208,22 @@ bool Parser::SkipSection() { // must handle subsections ... int iCnt = 0; while (true) { - if ('}' == *filePtr) { + if ('}' == *mFilePtr) { --iCnt; if (0 == iCnt) { // go to the next valid token ... - ++filePtr; + ++mFilePtr; SkipToNextToken(); return true; } - } else if ('{' == *filePtr) { + } else if ('{' == *mFilePtr) { ++iCnt; - } else if ('\0' == *filePtr) { + } else if ('\0' == *mFilePtr) { LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]"); return false; - } else if (IsLineEnd(*filePtr)) + } else if (IsLineEnd(*mFilePtr)) ++iLineNumber; - ++filePtr; + ++mFilePtr; } } @@ -230,11 +231,11 @@ bool Parser::SkipSection() { void Parser::Parse() { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Version should be 200. Validate this ... - if (TokenMatch(filePtr, "3DSMAX_ASCIIEXPORT", 18)) { + if (TokenMatch(mFilePtr, "3DSMAX_ASCIIEXPORT", 18)) { unsigned int fmt; ParseLV4MeshLong(fmt); @@ -255,23 +256,23 @@ void Parser::Parse() { continue; } // main scene information - if (TokenMatch(filePtr, "SCENE", 5)) { + if (TokenMatch(mFilePtr, "SCENE", 5)) { ParseLV1SceneBlock(); continue; } // "group" - no implementation yet, in facte // we're just ignoring them for the moment - if (TokenMatch(filePtr, "GROUP", 5)) { + if (TokenMatch(mFilePtr, "GROUP", 5)) { Parse(); continue; } // material list - if (TokenMatch(filePtr, "MATERIAL_LIST", 13)) { + if (TokenMatch(mFilePtr, "MATERIAL_LIST", 13)) { ParseLV1MaterialListBlock(); continue; } // geometric object (mesh) - if (TokenMatch(filePtr, "GEOMOBJECT", 10)) + if (TokenMatch(mFilePtr, "GEOMOBJECT", 10)) { m_vMeshes.emplace_back("UNNAMED"); @@ -279,7 +280,7 @@ void Parser::Parse() { continue; } // helper object = dummy in the hierarchy - if (TokenMatch(filePtr, "HELPEROBJECT", 12)) + if (TokenMatch(mFilePtr, "HELPEROBJECT", 12)) { m_vDummies.emplace_back(); @@ -287,7 +288,7 @@ void Parser::Parse() { continue; } // light object - if (TokenMatch(filePtr, "LIGHTOBJECT", 11)) + if (TokenMatch(mFilePtr, "LIGHTOBJECT", 11)) { m_vLights.emplace_back("UNNAMED"); @@ -295,20 +296,20 @@ void Parser::Parse() { continue; } // camera object - if (TokenMatch(filePtr, "CAMERAOBJECT", 12)) { + if (TokenMatch(mFilePtr, "CAMERAOBJECT", 12)) { m_vCameras.emplace_back("UNNAMED"); ParseLV1ObjectBlock(m_vCameras.back()); continue; } // comment - print it on the console - if (TokenMatch(filePtr, "COMMENT", 7)) { + if (TokenMatch(mFilePtr, "COMMENT", 7)) { std::string out = ""; ParseString(out, "*COMMENT"); LogInfo(("Comment: " + out).c_str()); continue; } // ASC bone weights - if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr, "MESH_SOFTSKINVERTS", 18)) { + if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(mFilePtr, "MESH_SOFTSKINVERTS", 18)) { ParseLV1SoftSkinBlock(); } } @@ -340,25 +341,25 @@ void Parser::ParseLV1SoftSkinBlock() { */ // ************************************************************** while (true) { - if (*filePtr == '}') { - ++filePtr; + if (*mFilePtr == '}') { + ++mFilePtr; return; - } else if (*filePtr == '\0') + } else if (*mFilePtr == '\0') return; - else if (*filePtr == '{') - ++filePtr; + else if (*mFilePtr == '{') + ++mFilePtr; else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr)) { ASE::Mesh *curMesh = nullptr; unsigned int numVerts = 0; - const char *sz = filePtr; - while (!IsSpaceOrNewLine(*filePtr)) { - ++filePtr; + const char *sz = mFilePtr; + while (!IsSpaceOrNewLine(*mFilePtr)) { + ++mFilePtr; } - const unsigned int diff = (unsigned int)(filePtr - sz); + const unsigned int diff = (unsigned int)(mFilePtr - sz); if (diff) { std::string name = std::string(sz, diff); for (std::vector::iterator it = m_vMeshes.begin(); @@ -374,24 +375,24 @@ void Parser::ParseLV1SoftSkinBlock() { // Skip the mesh data - until we find a new mesh // or the end of the *MESH_SOFTSKINVERTS section while (true) { - SkipSpacesAndLineEnd(&filePtr, mEnd); - if (*filePtr == '}') { - ++filePtr; + SkipSpacesAndLineEnd(&mFilePtr, mEnd); + if (*mFilePtr == '}') { + ++mFilePtr; return; - } else if (!IsNumeric(*filePtr)) + } else if (!IsNumeric(*mFilePtr)) break; - SkipLine(&filePtr, mEnd); + SkipLine(&mFilePtr, mEnd); } } else { - SkipSpacesAndLineEnd(&filePtr, mEnd); + SkipSpacesAndLineEnd(&mFilePtr, mEnd); ParseLV4MeshLong(numVerts); // Reserve enough storage curMesh->mBoneVertices.reserve(numVerts); for (unsigned int i = 0; i < numVerts; ++i) { - SkipSpacesAndLineEnd(&filePtr, mEnd); + SkipSpacesAndLineEnd(&mFilePtr, mEnd); unsigned int numWeights; ParseLV4MeshLong(numWeights); @@ -430,10 +431,10 @@ void Parser::ParseLV1SoftSkinBlock() { } } } - if (*filePtr == '\0') + if (*mFilePtr == '\0') return; - ++filePtr; - SkipSpacesAndLineEnd(&filePtr, mEnd); + ++mFilePtr; + SkipSpacesAndLineEnd(&mFilePtr, mEnd); } } @@ -441,35 +442,35 @@ void Parser::ParseLV1SoftSkinBlock() { void Parser::ParseLV1SceneBlock() { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (TokenMatch(filePtr, "SCENE_BACKGROUND_STATIC", 23)) + if ('*' == *mFilePtr) { + ++mFilePtr; + if (TokenMatch(mFilePtr, "SCENE_BACKGROUND_STATIC", 23)) { // parse a color triple and assume it is really the bg color ParseLV4MeshFloatTriple(&m_clrBackground.r); continue; } - if (TokenMatch(filePtr, "SCENE_AMBIENT_STATIC", 20)) + if (TokenMatch(mFilePtr, "SCENE_AMBIENT_STATIC", 20)) { // parse a color triple and assume it is really the bg color ParseLV4MeshFloatTriple(&m_clrAmbient.r); continue; } - if (TokenMatch(filePtr, "SCENE_FIRSTFRAME", 16)) { + if (TokenMatch(mFilePtr, "SCENE_FIRSTFRAME", 16)) { ParseLV4MeshLong(iFirstFrame); continue; } - if (TokenMatch(filePtr, "SCENE_LASTFRAME", 15)) { + if (TokenMatch(mFilePtr, "SCENE_LASTFRAME", 15)) { ParseLV4MeshLong(iLastFrame); continue; } - if (TokenMatch(filePtr, "SCENE_FRAMESPEED", 16)) { + if (TokenMatch(mFilePtr, "SCENE_FRAMESPEED", 16)) { ParseLV4MeshLong(iFrameSpeed); continue; } - if (TokenMatch(filePtr, "SCENE_TICKSPERFRAME", 19)) { + if (TokenMatch(mFilePtr, "SCENE_TICKSPERFRAME", 19)) { ParseLV4MeshLong(iTicksPerFrame); continue; } @@ -485,9 +486,9 @@ void Parser::ParseLV1MaterialListBlock() { unsigned int iMaterialCount = 0; unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size(); while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (TokenMatch(filePtr, "MATERIAL_COUNT", 14)) { + if ('*' == *mFilePtr) { + ++mFilePtr; + if (TokenMatch(mFilePtr, "MATERIAL_COUNT", 14)) { ParseLV4MeshLong(iMaterialCount); if (UINT_MAX - iOldMaterialCount < iMaterialCount) { @@ -499,7 +500,7 @@ void Parser::ParseLV1MaterialListBlock() { m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID")); continue; } - if (TokenMatch(filePtr, "MATERIAL", 8)) { + if (TokenMatch(mFilePtr, "MATERIAL", 8)) { // ensure we have at least one material allocated if (iMaterialCount == 0) { LogWarning("*MATERIAL_COUNT unspecified or 0"); @@ -524,7 +525,7 @@ void Parser::ParseLV1MaterialListBlock() { if( iDepth == 1 ){ // CRUDE HACK: support missing brace after "Ascii Scene Exporter v2.51" LogWarning("Missing closing brace in material list"); - --filePtr; + --mFilePtr; return; } } @@ -538,37 +539,37 @@ void Parser::ParseLV2MaterialBlock(ASE::Material &mat) { unsigned int iNumSubMaterials = 0; while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (TokenMatch(filePtr, "MATERIAL_NAME", 13)) { + if ('*' == *mFilePtr) { + ++mFilePtr; + if (TokenMatch(mFilePtr, "MATERIAL_NAME", 13)) { if (!ParseString(mat.mName, "*MATERIAL_NAME")) SkipToNextToken(); continue; } // ambient material color - if (TokenMatch(filePtr, "MATERIAL_AMBIENT", 16)) { + if (TokenMatch(mFilePtr, "MATERIAL_AMBIENT", 16)) { ParseLV4MeshFloatTriple(&mat.mAmbient.r); continue; } // diffuse material color - if (TokenMatch(filePtr, "MATERIAL_DIFFUSE", 16)) { + if (TokenMatch(mFilePtr, "MATERIAL_DIFFUSE", 16)) { ParseLV4MeshFloatTriple(&mat.mDiffuse.r); continue; } // specular material color - if (TokenMatch(filePtr, "MATERIAL_SPECULAR", 17)) { + if (TokenMatch(mFilePtr, "MATERIAL_SPECULAR", 17)) { ParseLV4MeshFloatTriple(&mat.mSpecular.r); continue; } // material shading type - if (TokenMatch(filePtr, "MATERIAL_SHADING", 16)) { - if (TokenMatch(filePtr, "Blinn", 5)) { + if (TokenMatch(mFilePtr, "MATERIAL_SHADING", 16)) { + if (TokenMatch(mFilePtr, "Blinn", 5)) { mat.mShading = Discreet3DS::Blinn; - } else if (TokenMatch(filePtr, "Phong", 5)) { + } else if (TokenMatch(mFilePtr, "Phong", 5)) { mat.mShading = Discreet3DS::Phong; - } else if (TokenMatch(filePtr, "Flat", 4)) { + } else if (TokenMatch(mFilePtr, "Flat", 4)) { mat.mShading = Discreet3DS::Flat; - } else if (TokenMatch(filePtr, "Wire", 4)) { + } else if (TokenMatch(mFilePtr, "Wire", 4)) { mat.mShading = Discreet3DS::Wire; } else { // assume gouraud shading @@ -578,13 +579,13 @@ void Parser::ParseLV2MaterialBlock(ASE::Material &mat) { continue; } // material transparency - if (TokenMatch(filePtr, "MATERIAL_TRANSPARENCY", 21)) { + if (TokenMatch(mFilePtr, "MATERIAL_TRANSPARENCY", 21)) { ParseLV4MeshFloat(mat.mTransparency); mat.mTransparency = ai_real(1.0) - mat.mTransparency; continue; } // material self illumination - if (TokenMatch(filePtr, "MATERIAL_SELFILLUM", 18)) { + if (TokenMatch(mFilePtr, "MATERIAL_SELFILLUM", 18)) { ai_real f = 0.0; ParseLV4MeshFloat(f); @@ -594,71 +595,71 @@ void Parser::ParseLV2MaterialBlock(ASE::Material &mat) { continue; } // material shininess - if (TokenMatch(filePtr, "MATERIAL_SHINE", 14)) { + if (TokenMatch(mFilePtr, "MATERIAL_SHINE", 14)) { ParseLV4MeshFloat(mat.mSpecularExponent); mat.mSpecularExponent *= 15; continue; } // two-sided material - if (TokenMatch(filePtr, "MATERIAL_TWOSIDED", 17)) { + if (TokenMatch(mFilePtr, "MATERIAL_TWOSIDED", 17)) { mat.mTwoSided = true; continue; } // material shininess strength - if (TokenMatch(filePtr, "MATERIAL_SHINESTRENGTH", 22)) { + if (TokenMatch(mFilePtr, "MATERIAL_SHINESTRENGTH", 22)) { ParseLV4MeshFloat(mat.mShininessStrength); continue; } // diffuse color map - if (TokenMatch(filePtr, "MAP_DIFFUSE", 11)) { + if (TokenMatch(mFilePtr, "MAP_DIFFUSE", 11)) { // parse the texture block ParseLV3MapBlock(mat.sTexDiffuse); continue; } // ambient color map - if (TokenMatch(filePtr, "MAP_AMBIENT", 11)) { + if (TokenMatch(mFilePtr, "MAP_AMBIENT", 11)) { // parse the texture block ParseLV3MapBlock(mat.sTexAmbient); continue; } // specular color map - if (TokenMatch(filePtr, "MAP_SPECULAR", 12)) { + if (TokenMatch(mFilePtr, "MAP_SPECULAR", 12)) { // parse the texture block ParseLV3MapBlock(mat.sTexSpecular); continue; } // opacity map - if (TokenMatch(filePtr, "MAP_OPACITY", 11)) { + if (TokenMatch(mFilePtr, "MAP_OPACITY", 11)) { // parse the texture block ParseLV3MapBlock(mat.sTexOpacity); continue; } // emissive map - if (TokenMatch(filePtr, "MAP_SELFILLUM", 13)) { + if (TokenMatch(mFilePtr, "MAP_SELFILLUM", 13)) { // parse the texture block ParseLV3MapBlock(mat.sTexEmissive); continue; } // bump map - if (TokenMatch(filePtr, "MAP_BUMP", 8)) { + if (TokenMatch(mFilePtr, "MAP_BUMP", 8)) { // parse the texture block ParseLV3MapBlock(mat.sTexBump); } // specular/shininess map - if (TokenMatch(filePtr, "MAP_SHINESTRENGTH", 17)) { + if (TokenMatch(mFilePtr, "MAP_SHINESTRENGTH", 17)) { // parse the texture block ParseLV3MapBlock(mat.sTexShininess); continue; } // number of submaterials - if (TokenMatch(filePtr, "NUMSUBMTLS", 10)) { + if (TokenMatch(mFilePtr, "NUMSUBMTLS", 10)) { ParseLV4MeshLong(iNumSubMaterials); // allocate enough storage mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL")); } // submaterial chunks - if (TokenMatch(filePtr, "SUBMATERIAL", 11)) { + if (TokenMatch(mFilePtr, "SUBMATERIAL", 11)) { // ensure we have at least one material allocated if (iNumSubMaterials == 0) { LogWarning("*NUMSUBMTLS unspecified or 0"); @@ -701,10 +702,10 @@ void Parser::ParseLV3MapBlock(Texture &map) { bool parsePath = true; std::string temp; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // type of map - if (TokenMatch(filePtr, "MAP_CLASS", 9)) { + if (TokenMatch(mFilePtr, "MAP_CLASS", 9)) { temp.clear(); if (!ParseString(temp, "*MAP_CLASS")) SkipToNextToken(); @@ -715,7 +716,7 @@ void Parser::ParseLV3MapBlock(Texture &map) { continue; } // path to the texture - if (parsePath && TokenMatch(filePtr, "BITMAP", 6)) { + if (parsePath && TokenMatch(mFilePtr, "BITMAP", 6)) { if (!ParseString(map.mMapName, "*BITMAP")) SkipToNextToken(); @@ -729,32 +730,32 @@ void Parser::ParseLV3MapBlock(Texture &map) { continue; } // offset on the u axis - if (TokenMatch(filePtr, "UVW_U_OFFSET", 12)) { + if (TokenMatch(mFilePtr, "UVW_U_OFFSET", 12)) { ParseLV4MeshFloat(map.mOffsetU); continue; } // offset on the v axis - if (TokenMatch(filePtr, "UVW_V_OFFSET", 12)) { + if (TokenMatch(mFilePtr, "UVW_V_OFFSET", 12)) { ParseLV4MeshFloat(map.mOffsetV); continue; } // tiling on the u axis - if (TokenMatch(filePtr, "UVW_U_TILING", 12)) { + if (TokenMatch(mFilePtr, "UVW_U_TILING", 12)) { ParseLV4MeshFloat(map.mScaleU); continue; } // tiling on the v axis - if (TokenMatch(filePtr, "UVW_V_TILING", 12)) { + if (TokenMatch(mFilePtr, "UVW_V_TILING", 12)) { ParseLV4MeshFloat(map.mScaleV); continue; } // rotation around the z-axis - if (TokenMatch(filePtr, "UVW_ANGLE", 9)) { + if (TokenMatch(mFilePtr, "UVW_ANGLE", 9)) { ParseLV4MeshFloat(map.mRotation); continue; } // map blending factor - if (TokenMatch(filePtr, "MAP_AMOUNT", 10)) { + if (TokenMatch(mFilePtr, "MAP_AMOUNT", 10)) { ParseLV4MeshFloat(map.mTextureBlend); continue; } @@ -766,14 +767,14 @@ void Parser::ParseLV3MapBlock(Texture &map) { // ------------------------------------------------------------------------------------------------ bool Parser::ParseString(std::string &out, const char *szName) { char szBuffer[1024]; - if (!SkipSpaces(&filePtr, mEnd)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName); LogWarning(szBuffer); return false; } // there must be '"' - if ('\"' != *filePtr) { + if ('\"' != *mFilePtr) { ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected " "to be enclosed in double quotation marks", @@ -781,8 +782,8 @@ bool Parser::ParseString(std::string &out, const char *szName) { LogWarning(szBuffer); return false; } - ++filePtr; - const char *sz = filePtr; + ++mFilePtr; + const char *sz = mFilePtr; while (true) { if ('\"' == *sz) break; @@ -796,8 +797,8 @@ bool Parser::ParseString(std::string &out, const char *szName) { } sz++; } - out = std::string(filePtr, (uintptr_t)sz - (uintptr_t)filePtr); - filePtr = sz + 1; + out = std::string(mFilePtr, (uintptr_t)sz - (uintptr_t)mFilePtr); + mFilePtr = sz + 1; return true; } @@ -805,48 +806,48 @@ bool Parser::ParseString(std::string &out, const char *szName) { void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // first process common tokens such as node name and transform // name of the mesh/node - if (TokenMatch(filePtr, "NODE_NAME", 9)) { + if (TokenMatch(mFilePtr, "NODE_NAME", 9)) { if (!ParseString(node.mName, "*NODE_NAME")) SkipToNextToken(); continue; } // name of the parent of the node - if (TokenMatch(filePtr, "NODE_PARENT", 11)) { + if (TokenMatch(mFilePtr, "NODE_PARENT", 11)) { if (!ParseString(node.mParent, "*NODE_PARENT")) SkipToNextToken(); continue; } // transformation matrix of the node - if (TokenMatch(filePtr, "NODE_TM", 7)) { + if (TokenMatch(mFilePtr, "NODE_TM", 7)) { ParseLV2NodeTransformBlock(node); continue; } // animation data of the node - if (TokenMatch(filePtr, "TM_ANIMATION", 12)) { + if (TokenMatch(mFilePtr, "TM_ANIMATION", 12)) { ParseLV2AnimationBlock(node); continue; } if (node.mType == BaseNode::Light) { // light settings - if (TokenMatch(filePtr, "LIGHT_SETTINGS", 14)) { + if (TokenMatch(mFilePtr, "LIGHT_SETTINGS", 14)) { ParseLV2LightSettingsBlock((ASE::Light &)node); continue; } // type of the light source - if (TokenMatch(filePtr, "LIGHT_TYPE", 10)) { - if (!ASSIMP_strincmp("omni", filePtr, 4)) { + if (TokenMatch(mFilePtr, "LIGHT_TYPE", 10)) { + if (!ASSIMP_strincmp("omni", mFilePtr, 4)) { ((ASE::Light &)node).mLightType = ASE::Light::OMNI; - } else if (!ASSIMP_strincmp("target", filePtr, 6)) { + } else if (!ASSIMP_strincmp("target", mFilePtr, 6)) { ((ASE::Light &)node).mLightType = ASE::Light::TARGET; - } else if (!ASSIMP_strincmp("free", filePtr, 4)) { + } else if (!ASSIMP_strincmp("free", mFilePtr, 4)) { ((ASE::Light &)node).mLightType = ASE::Light::FREE; - } else if (!ASSIMP_strincmp("directional", filePtr, 11)) { + } else if (!ASSIMP_strincmp("directional", mFilePtr, 11)) { ((ASE::Light &)node).mLightType = ASE::Light::DIRECTIONAL; } else { LogWarning("Unknown kind of light source"); @@ -855,13 +856,13 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) { } } else if (node.mType == BaseNode::Camera) { // Camera settings - if (TokenMatch(filePtr, "CAMERA_SETTINGS", 15)) { + if (TokenMatch(mFilePtr, "CAMERA_SETTINGS", 15)) { ParseLV2CameraSettingsBlock((ASE::Camera &)node); continue; - } else if (TokenMatch(filePtr, "CAMERA_TYPE", 11)) { - if (!ASSIMP_strincmp("target", filePtr, 6)) { + } else if (TokenMatch(mFilePtr, "CAMERA_TYPE", 11)) { + if (!ASSIMP_strincmp("target", mFilePtr, 6)) { ((ASE::Camera &)node).mCameraType = ASE::Camera::TARGET; - } else if (!ASSIMP_strincmp("free", filePtr, 4)) { + } else if (!ASSIMP_strincmp("free", mFilePtr, 4)) { ((ASE::Camera &)node).mCameraType = ASE::Camera::FREE; } else { LogWarning("Unknown kind of camera"); @@ -871,13 +872,13 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) { } else if (node.mType == BaseNode::Mesh) { // mesh data // FIX: Older files use MESH_SOFTSKIN - if (TokenMatch(filePtr, "MESH", 4) || - TokenMatch(filePtr, "MESH_SOFTSKIN", 13)) { + if (TokenMatch(mFilePtr, "MESH", 4) || + TokenMatch(mFilePtr, "MESH_SOFTSKIN", 13)) { ParseLV2MeshBlock((ASE::Mesh &)node); continue; } // mesh material index - if (TokenMatch(filePtr, "MATERIAL_REF", 12)) { + if (TokenMatch(mFilePtr, "MATERIAL_REF", 12)) { ParseLV4MeshLong(((ASE::Mesh &)node).iMaterialIndex); continue; } @@ -891,17 +892,17 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) { void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (TokenMatch(filePtr, "CAMERA_NEAR", 11)) { + if ('*' == *mFilePtr) { + ++mFilePtr; + if (TokenMatch(mFilePtr, "CAMERA_NEAR", 11)) { ParseLV4MeshFloat(camera.mNear); continue; } - if (TokenMatch(filePtr, "CAMERA_FAR", 10)) { + if (TokenMatch(mFilePtr, "CAMERA_FAR", 10)) { ParseLV4MeshFloat(camera.mFar); continue; } - if (TokenMatch(filePtr, "CAMERA_FOV", 10)) { + if (TokenMatch(mFilePtr, "CAMERA_FOV", 10)) { ParseLV4MeshFloat(camera.mFOV); continue; } @@ -914,21 +915,21 @@ void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) { void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (TokenMatch(filePtr, "LIGHT_COLOR", 11)) { + if ('*' == *mFilePtr) { + ++mFilePtr; + if (TokenMatch(mFilePtr, "LIGHT_COLOR", 11)) { ParseLV4MeshFloatTriple(&light.mColor.r); continue; } - if (TokenMatch(filePtr, "LIGHT_INTENS", 12)) { + if (TokenMatch(mFilePtr, "LIGHT_INTENS", 12)) { ParseLV4MeshFloat(light.mIntensity); continue; } - if (TokenMatch(filePtr, "LIGHT_HOTSPOT", 13)) { + if (TokenMatch(mFilePtr, "LIGHT_HOTSPOT", 13)) { ParseLV4MeshFloat(light.mAngle); continue; } - if (TokenMatch(filePtr, "LIGHT_FALLOFF", 13)) { + if (TokenMatch(mFilePtr, "LIGHT_FALLOFF", 13)) { ParseLV4MeshFloat(light.mFalloff); continue; } @@ -943,9 +944,9 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) { ASE::Animation *anim = &mesh.mAnim; while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (TokenMatch(filePtr, "NODE_NAME", 9)) { + if ('*' == *mFilePtr) { + ++mFilePtr; + if (TokenMatch(mFilePtr, "NODE_NAME", 9)) { std::string temp; if (!ParseString(temp, "*NODE_NAME")) SkipToNextToken(); @@ -967,9 +968,9 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) { } // position keyframes - if (TokenMatch(filePtr, "CONTROL_POS_TRACK", 17) || - TokenMatch(filePtr, "CONTROL_POS_BEZIER", 18) || - TokenMatch(filePtr, "CONTROL_POS_TCB", 15)) { + if (TokenMatch(mFilePtr, "CONTROL_POS_TRACK", 17) || + TokenMatch(mFilePtr, "CONTROL_POS_BEZIER", 18) || + TokenMatch(mFilePtr, "CONTROL_POS_TCB", 15)) { if (!anim) SkipSection(); else @@ -977,9 +978,9 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) { continue; } // scaling keyframes - if (TokenMatch(filePtr, "CONTROL_SCALE_TRACK", 19) || - TokenMatch(filePtr, "CONTROL_SCALE_BEZIER", 20) || - TokenMatch(filePtr, "CONTROL_SCALE_TCB", 17)) { + if (TokenMatch(mFilePtr, "CONTROL_SCALE_TRACK", 19) || + TokenMatch(mFilePtr, "CONTROL_SCALE_BEZIER", 20) || + TokenMatch(mFilePtr, "CONTROL_SCALE_TCB", 17)) { if (!anim || anim == &mesh.mTargetAnim) { // Target animation channels may have no rotation channels ASSIMP_LOG_ERROR("ASE: Ignoring scaling channel in target animation"); @@ -989,9 +990,9 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) { continue; } // rotation keyframes - if (TokenMatch(filePtr, "CONTROL_ROT_TRACK", 17) || - TokenMatch(filePtr, "CONTROL_ROT_BEZIER", 18) || - TokenMatch(filePtr, "CONTROL_ROT_TCB", 15)) { + if (TokenMatch(mFilePtr, "CONTROL_ROT_TRACK", 17) || + TokenMatch(mFilePtr, "CONTROL_ROT_BEZIER", 18) || + TokenMatch(mFilePtr, "CONTROL_ROT_TCB", 15)) { if (!anim || anim == &mesh.mTargetAnim) { // Target animation channels may have no rotation channels ASSIMP_LOG_ERROR("ASE: Ignoring rotation channel in target animation"); @@ -1010,8 +1011,8 @@ void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation &anim) { unsigned int iIndex; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; bool b = false; @@ -1019,18 +1020,18 @@ void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation &anim) { // we ignore the additional information for bezier's and TCBs // simple scaling keyframe - if (TokenMatch(filePtr, "CONTROL_SCALE_SAMPLE", 20)) { + if (TokenMatch(mFilePtr, "CONTROL_SCALE_SAMPLE", 20)) { b = true; anim.mScalingType = ASE::Animation::TRACK; } // Bezier scaling keyframe - if (TokenMatch(filePtr, "CONTROL_BEZIER_SCALE_KEY", 24)) { + if (TokenMatch(mFilePtr, "CONTROL_BEZIER_SCALE_KEY", 24)) { b = true; anim.mScalingType = ASE::Animation::BEZIER; } // TCB scaling keyframe - if (TokenMatch(filePtr, "CONTROL_TCB_SCALE_KEY", 21)) { + if (TokenMatch(mFilePtr, "CONTROL_TCB_SCALE_KEY", 21)) { b = true; anim.mScalingType = ASE::Animation::TCB; } @@ -1049,8 +1050,8 @@ void Parser::ParseLV3PosAnimationBlock(ASE::Animation &anim) { AI_ASE_PARSER_INIT(); unsigned int iIndex; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; bool b = false; @@ -1058,18 +1059,18 @@ void Parser::ParseLV3PosAnimationBlock(ASE::Animation &anim) { // we ignore the additional information for bezier's and TCBs // simple scaling keyframe - if (TokenMatch(filePtr, "CONTROL_POS_SAMPLE", 18)) { + if (TokenMatch(mFilePtr, "CONTROL_POS_SAMPLE", 18)) { b = true; anim.mPositionType = ASE::Animation::TRACK; } // Bezier scaling keyframe - if (TokenMatch(filePtr, "CONTROL_BEZIER_POS_KEY", 22)) { + if (TokenMatch(mFilePtr, "CONTROL_BEZIER_POS_KEY", 22)) { b = true; anim.mPositionType = ASE::Animation::BEZIER; } // TCB scaling keyframe - if (TokenMatch(filePtr, "CONTROL_TCB_POS_KEY", 19)) { + if (TokenMatch(mFilePtr, "CONTROL_TCB_POS_KEY", 19)) { b = true; anim.mPositionType = ASE::Animation::TCB; } @@ -1088,8 +1089,8 @@ void Parser::ParseLV3RotAnimationBlock(ASE::Animation &anim) { AI_ASE_PARSER_INIT(); unsigned int iIndex; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; bool b = false; @@ -1097,18 +1098,18 @@ void Parser::ParseLV3RotAnimationBlock(ASE::Animation &anim) { // we ignore the additional information for bezier's and TCBs // simple scaling keyframe - if (TokenMatch(filePtr, "CONTROL_ROT_SAMPLE", 18)) { + if (TokenMatch(mFilePtr, "CONTROL_ROT_SAMPLE", 18)) { b = true; anim.mRotationType = ASE::Animation::TRACK; } // Bezier scaling keyframe - if (TokenMatch(filePtr, "CONTROL_BEZIER_ROT_KEY", 22)) { + if (TokenMatch(mFilePtr, "CONTROL_BEZIER_ROT_KEY", 22)) { b = true; anim.mRotationType = ASE::Animation::BEZIER; } // TCB scaling keyframe - if (TokenMatch(filePtr, "CONTROL_TCB_ROT_KEY", 19)) { + if (TokenMatch(mFilePtr, "CONTROL_TCB_ROT_KEY", 19)) { b = true; anim.mRotationType = ASE::Animation::TCB; } @@ -1131,10 +1132,10 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) { AI_ASE_PARSER_INIT(); int mode = 0; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // name of the node - if (TokenMatch(filePtr, "NODE_NAME", 9)) { + if (TokenMatch(mFilePtr, "NODE_NAME", 9)) { std::string temp; if (!ParseString(temp, "*NODE_NAME")) SkipToNextToken(); @@ -1161,28 +1162,28 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) { if (mode) { // fourth row of the transformation matrix - and also the // only information here that is interesting for targets - if (TokenMatch(filePtr, "TM_ROW3", 7)) { + if (TokenMatch(mFilePtr, "TM_ROW3", 7)) { ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x)); continue; } if (mode == 1) { // first row of the transformation matrix - if (TokenMatch(filePtr, "TM_ROW0", 7)) { + if (TokenMatch(mFilePtr, "TM_ROW0", 7)) { ParseLV4MeshFloatTriple(mesh.mTransform[0]); continue; } // second row of the transformation matrix - if (TokenMatch(filePtr, "TM_ROW1", 7)) { + if (TokenMatch(mFilePtr, "TM_ROW1", 7)) { ParseLV4MeshFloatTriple(mesh.mTransform[1]); continue; } // third row of the transformation matrix - if (TokenMatch(filePtr, "TM_ROW2", 7)) { + if (TokenMatch(mFilePtr, "TM_ROW2", 7)) { ParseLV4MeshFloatTriple(mesh.mTransform[2]); continue; } // inherited position axes - if (TokenMatch(filePtr, "INHERIT_POS", 11)) { + if (TokenMatch(mFilePtr, "INHERIT_POS", 11)) { unsigned int aiVal[3]; ParseLV4MeshLongTriple(aiVal); @@ -1191,7 +1192,7 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) { continue; } // inherited rotation axes - if (TokenMatch(filePtr, "INHERIT_ROT", 11)) { + if (TokenMatch(mFilePtr, "INHERIT_ROT", 11)) { unsigned int aiVal[3]; ParseLV4MeshLongTriple(aiVal); @@ -1200,7 +1201,7 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) { continue; } // inherited scaling axes - if (TokenMatch(filePtr, "INHERIT_SCL", 11)) { + if (TokenMatch(mFilePtr, "INHERIT_SCL", 11)) { unsigned int aiVal[3]; ParseLV4MeshLongTriple(aiVal); @@ -1225,75 +1226,75 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) { unsigned int iNumCVertices = 0; unsigned int iNumCFaces = 0; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Number of vertices in the mesh - if (TokenMatch(filePtr, "MESH_NUMVERTEX", 14)) { + if (TokenMatch(mFilePtr, "MESH_NUMVERTEX", 14)) { ParseLV4MeshLong(iNumVertices); continue; } // Number of texture coordinates in the mesh - if (TokenMatch(filePtr, "MESH_NUMTVERTEX", 15)) { + if (TokenMatch(mFilePtr, "MESH_NUMTVERTEX", 15)) { ParseLV4MeshLong(iNumTVertices); continue; } // Number of vertex colors in the mesh - if (TokenMatch(filePtr, "MESH_NUMCVERTEX", 15)) { + if (TokenMatch(mFilePtr, "MESH_NUMCVERTEX", 15)) { ParseLV4MeshLong(iNumCVertices); continue; } // Number of regular faces in the mesh - if (TokenMatch(filePtr, "MESH_NUMFACES", 13)) { + if (TokenMatch(mFilePtr, "MESH_NUMFACES", 13)) { ParseLV4MeshLong(iNumFaces); continue; } // Number of UVWed faces in the mesh - if (TokenMatch(filePtr, "MESH_NUMTVFACES", 15)) { + if (TokenMatch(mFilePtr, "MESH_NUMTVFACES", 15)) { ParseLV4MeshLong(iNumTFaces); continue; } // Number of colored faces in the mesh - if (TokenMatch(filePtr, "MESH_NUMCVFACES", 15)) { + if (TokenMatch(mFilePtr, "MESH_NUMCVFACES", 15)) { ParseLV4MeshLong(iNumCFaces); continue; } // mesh vertex list block - if (TokenMatch(filePtr, "MESH_VERTEX_LIST", 16)) { + if (TokenMatch(mFilePtr, "MESH_VERTEX_LIST", 16)) { ParseLV3MeshVertexListBlock(iNumVertices, mesh); continue; } // mesh face list block - if (TokenMatch(filePtr, "MESH_FACE_LIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_FACE_LIST", 14)) { ParseLV3MeshFaceListBlock(iNumFaces, mesh); continue; } // mesh texture vertex list block - if (TokenMatch(filePtr, "MESH_TVERTLIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_TVERTLIST", 14)) { ParseLV3MeshTListBlock(iNumTVertices, mesh); continue; } // mesh texture face block - if (TokenMatch(filePtr, "MESH_TFACELIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_TFACELIST", 14)) { ParseLV3MeshTFaceListBlock(iNumTFaces, mesh); continue; } // mesh color vertex list block - if (TokenMatch(filePtr, "MESH_CVERTLIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_CVERTLIST", 14)) { ParseLV3MeshCListBlock(iNumCVertices, mesh); continue; } // mesh color face block - if (TokenMatch(filePtr, "MESH_CFACELIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_CFACELIST", 14)) { ParseLV3MeshCFaceListBlock(iNumCFaces, mesh); continue; } // mesh normals - if (TokenMatch(filePtr, "MESH_NORMALS", 12)) { + if (TokenMatch(mFilePtr, "MESH_NORMALS", 12)) { ParseLV3MeshNormalListBlock(mesh); continue; } // another mesh UV channel ... - if (TokenMatch(filePtr, "MESH_MAPPINGCHANNEL", 19)) { + if (TokenMatch(mFilePtr, "MESH_MAPPINGCHANNEL", 19)) { unsigned int iIndex(0); ParseLV4MeshLong(iIndex); if (0 == iIndex) { @@ -1318,7 +1319,7 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) { } } // mesh animation keyframe. Not supported - if (TokenMatch(filePtr, "MESH_ANIMATION", 14)) { + if (TokenMatch(mFilePtr, "MESH_ANIMATION", 14)) { LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. " "Keyframe animation is not supported by Assimp, this element " @@ -1326,7 +1327,7 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) { //SkipSection(); continue; } - if (TokenMatch(filePtr, "MESH_WEIGHTS", 12)) { + if (TokenMatch(mFilePtr, "MESH_WEIGHTS", 12)) { ParseLV3MeshWeightsBlock(mesh); continue; } @@ -1340,26 +1341,26 @@ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) { unsigned int iNumVertices = 0, iNumBones = 0; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Number of bone vertices ... - if (TokenMatch(filePtr, "MESH_NUMVERTEX", 14)) { + if (TokenMatch(mFilePtr, "MESH_NUMVERTEX", 14)) { ParseLV4MeshLong(iNumVertices); continue; } // Number of bones - if (TokenMatch(filePtr, "MESH_NUMBONE", 12)) { + if (TokenMatch(mFilePtr, "MESH_NUMBONE", 12)) { ParseLV4MeshLong(iNumBones); continue; } // parse the list of bones - if (TokenMatch(filePtr, "MESH_BONE_LIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_BONE_LIST", 14)) { ParseLV4MeshBones(iNumBones, mesh); continue; } // parse the list of bones vertices - if (TokenMatch(filePtr, "MESH_BONE_VERTEX_LIST", 21)) { + if (TokenMatch(mFilePtr, "MESH_BONE_VERTEX_LIST", 21)) { ParseLV4MeshBonesVertices(iNumVertices, mesh); continue; } @@ -1372,14 +1373,14 @@ void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); mesh.mBones.resize(iNumBones, Bone("UNNAMED")); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Mesh bone with name ... - if (TokenMatch(filePtr, "MESH_BONE_NAME", 14)) { + if (TokenMatch(mFilePtr, "MESH_BONE_NAME", 14)) { // parse an index ... - if (SkipSpaces(&filePtr, mEnd)) { - unsigned int iIndex = strtoul10(filePtr, &filePtr); + if (SkipSpaces(&mFilePtr, mEnd)) { + unsigned int iIndex = strtoul10(mFilePtr, &mFilePtr); if (iIndex >= iNumBones) { LogWarning("Bone index is out of bounds"); continue; @@ -1398,13 +1399,13 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes AI_ASE_PARSER_INIT(); mesh.mBoneVertices.resize(iNumVertices); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Mesh bone vertex - if (TokenMatch(filePtr, "MESH_BONE_VERTEX", 16)) { + if (TokenMatch(mFilePtr, "MESH_BONE_VERTEX", 16)) { // read the vertex index - unsigned int iIndex = strtoul10(filePtr, &filePtr); + unsigned int iIndex = strtoul10(mFilePtr, &mFilePtr); if (iIndex >= mesh.mPositions.size()) { iIndex = (unsigned int)mesh.mPositions.size() - 1; LogWarning("Bone vertex index is out of bounds. Using the largest valid " @@ -1418,12 +1419,12 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes std::pair pairOut; while (true) { // first parse the bone index ... - if (!SkipSpaces(&filePtr, mEnd)) break; - pairOut.first = strtoul10(filePtr, &filePtr); + if (!SkipSpaces(&mFilePtr, mEnd)) break; + pairOut.first = strtoul10(mFilePtr, &mFilePtr); // then parse the vertex weight - if (!SkipSpaces(&filePtr, mEnd)) break; - filePtr = fast_atoreal_move(filePtr, pairOut.second); + if (!SkipSpaces(&mFilePtr, mEnd)) break; + mFilePtr = fast_atoreal_move(mFilePtr, pairOut.second); // -1 marks unused entries if (-1 != pairOut.first) { @@ -1444,11 +1445,11 @@ void Parser::ParseLV3MeshVertexListBlock( // allocate enough storage in the array mesh.mPositions.resize(iNumVertices); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Vertex entry - if (TokenMatch(filePtr, "MESH_VERTEX", 11)) { + if (TokenMatch(mFilePtr, "MESH_VERTEX", 11)) { aiVector3D vTemp; unsigned int iIndex; @@ -1471,11 +1472,11 @@ void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) // allocate enough storage in the face array mesh.mFaces.resize(iNumFaces); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Face entry - if (TokenMatch(filePtr, "MESH_FACE", 9)) { + if (TokenMatch(mFilePtr, "MESH_FACE", 9)) { ASE::Face mFace; ParseLV4MeshFace(mFace); @@ -1498,11 +1499,11 @@ void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices, // allocate enough storage in the array mesh.amTexCoords[iChannel].resize(iNumVertices); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Vertex entry - if (TokenMatch(filePtr, "MESH_TVERT", 10)) { + if (TokenMatch(mFilePtr, "MESH_TVERT", 10)) { aiVector3D vTemp; unsigned int iIndex; ParseLV4MeshFloatTriple(&vTemp.x, iIndex); @@ -1527,11 +1528,11 @@ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh, unsigned int iChannel) { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Face entry - if (TokenMatch(filePtr, "MESH_TFACE", 10)) { + if (TokenMatch(mFilePtr, "MESH_TFACE", 10)) { unsigned int aiValues[3]; unsigned int iIndex = 0; @@ -1557,26 +1558,26 @@ void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) { unsigned int iNumTVertices = 0; unsigned int iNumTFaces = 0; while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Number of texture coordinates in the mesh - if (TokenMatch(filePtr, "MESH_NUMTVERTEX", 15)) { + if (TokenMatch(mFilePtr, "MESH_NUMTVERTEX", 15)) { ParseLV4MeshLong(iNumTVertices); continue; } // Number of UVWed faces in the mesh - if (TokenMatch(filePtr, "MESH_NUMTVFACES", 15)) { + if (TokenMatch(mFilePtr, "MESH_NUMTVFACES", 15)) { ParseLV4MeshLong(iNumTFaces); continue; } // mesh texture vertex list block - if (TokenMatch(filePtr, "MESH_TVERTLIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_TVERTLIST", 14)) { ParseLV3MeshTListBlock(iNumTVertices, mesh, iChannel); continue; } // mesh texture face block - if (TokenMatch(filePtr, "MESH_TFACELIST", 14)) { + if (TokenMatch(mFilePtr, "MESH_TFACELIST", 14)) { ParseLV3MeshTFaceListBlock(iNumTFaces, mesh, iChannel); continue; } @@ -1591,11 +1592,11 @@ void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) // allocate enough storage in the array mesh.mVertexColors.resize(iNumVertices); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Vertex entry - if (TokenMatch(filePtr, "MESH_VERTCOL", 12)) { + if (TokenMatch(mFilePtr, "MESH_VERTCOL", 12)) { aiColor4D vTemp; vTemp.a = 1.0f; unsigned int iIndex; @@ -1615,11 +1616,11 @@ void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); while (true) { - if ('*' == *filePtr) { - ++filePtr; + if ('*' == *mFilePtr) { + ++mFilePtr; // Face entry - if (TokenMatch(filePtr, "MESH_CFACE", 10)) { + if (TokenMatch(mFilePtr, "MESH_CFACE", 10)) { unsigned int aiValues[3]; unsigned int iIndex = 0; @@ -1652,9 +1653,9 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) { // Smooth the vertex and face normals together. The result // will be edgy then, but otherwise everything would be soft ... while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (faceIdx != UINT_MAX && TokenMatch(filePtr, "MESH_VERTEXNORMAL", 17)) { + if ('*' == *mFilePtr) { + ++mFilePtr; + if (faceIdx != UINT_MAX && TokenMatch(mFilePtr, "MESH_VERTEXNORMAL", 17)) { aiVector3D vNormal; ParseLV4MeshFloatTriple(&vNormal.x, index); if (faceIdx >= sMesh.mFaces.size()) @@ -1676,7 +1677,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) { sMesh.mNormals[faceIdx * 3 + index] += vNormal; continue; } - if (TokenMatch(filePtr, "MESH_FACENORMAL", 15)) { + if (TokenMatch(mFilePtr, "MESH_FACENORMAL", 15)) { aiVector3D vNormal; ParseLV4MeshFloatTriple(&vNormal.x, faceIdx); @@ -1698,34 +1699,34 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) { // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFace(ASE::Face &out) { // skip spaces and tabs - if (!SkipSpaces(&filePtr, mEnd)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]"); SkipToNextToken(); return; } // parse the face index - out.iFace = strtoul10(filePtr, &filePtr); + out.iFace = strtoul10(mFilePtr, &mFilePtr); // next character should be ':' - if (!SkipSpaces(&filePtr, mEnd)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { // FIX: there are some ASE files which haven't got : here .... LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]"); SkipToNextToken(); return; } // FIX: There are some ASE files which haven't got ':' here - if (':' == *filePtr) ++filePtr; + if (':' == *mFilePtr) ++mFilePtr; // Parse all mesh indices for (unsigned int i = 0; i < 3; ++i) { unsigned int iIndex = 0; - if (!SkipSpaces(&filePtr, mEnd)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL"); SkipToNextToken(); return; } - switch (*filePtr) { + switch (*mFilePtr) { case 'A': case 'a': break; @@ -1743,39 +1744,39 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) { SkipToNextToken(); return; }; - ++filePtr; + ++mFilePtr; // next character should be ':' - if (!SkipSpaces(&filePtr, mEnd) || ':' != *filePtr) { + if (!SkipSpaces(&mFilePtr, mEnd) || ':' != *mFilePtr) { LogWarning("Unable to parse *MESH_FACE Element: " "Unexpected EOL. \':\' expected [#2]"); SkipToNextToken(); return; } - ++filePtr; - if (!SkipSpaces(&filePtr, mEnd)) { + ++mFilePtr; + if (!SkipSpaces(&mFilePtr, mEnd)) { LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " "Vertex index expected [#4]"); SkipToNextToken(); return; } - out.mIndices[iIndex] = strtoul10(filePtr, &filePtr); + out.mIndices[iIndex] = strtoul10(mFilePtr, &mFilePtr); } // now we need to skip the AB, BC, CA blocks. while (true) { - if ('*' == *filePtr) break; - if (IsLineEnd(*filePtr)) { + if ('*' == *mFilePtr) break; + if (IsLineEnd(*mFilePtr)) { //iLineNumber++; return; } - filePtr++; + mFilePtr++; } // parse the smoothing group of the face - if (TokenMatch(filePtr, "*MESH_SMOOTHING", 15)) { - if (!SkipSpaces(&filePtr, mEnd)) { + if (TokenMatch(mFilePtr, "*MESH_SMOOTHING", 15)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { LogWarning("Unable to parse *MESH_SMOOTHING Element: " "Unexpected EOL. Smoothing group(s) expected [#5]"); SkipToNextToken(); @@ -1785,43 +1786,43 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) { // Parse smoothing groups until we don't anymore see commas // FIX: There needn't always be a value, sad but true while (true) { - if (*filePtr < '9' && *filePtr >= '0') { - uint32_t value = strtoul10(filePtr, &filePtr); + if (*mFilePtr < '9' && *mFilePtr >= '0') { + uint32_t value = strtoul10(mFilePtr, &mFilePtr); if (value < 32) { - out.iSmoothGroup |= (1 << strtoul10(filePtr, &filePtr)); + out.iSmoothGroup |= (1 << strtoul10(mFilePtr, &mFilePtr)); } else { const std::string message = std::string("Unable to set smooth group, value with ") + ai_to_string(value) + std::string(" out of range"); LogWarning(message.c_str()); } } - SkipSpaces(&filePtr, mEnd); - if (',' != *filePtr) { + SkipSpaces(&mFilePtr, mEnd); + if (',' != *mFilePtr) { break; } - ++filePtr; - SkipSpaces(&filePtr, mEnd); + ++mFilePtr; + SkipSpaces(&mFilePtr, mEnd); } } // *MESH_MTLID is optional, too while (true) { - if ('*' == *filePtr) { + if ('*' == *mFilePtr) { break; } - if (IsLineEnd(*filePtr)) { + if (IsLineEnd(*mFilePtr)) { return; } - filePtr++; + mFilePtr++; } - if (TokenMatch(filePtr, "*MESH_MTLID", 11)) { - if (!SkipSpaces(&filePtr, mEnd)) { + if (TokenMatch(mFilePtr, "*MESH_MTLID", 11)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. " "Material index expected [#6]"); SkipToNextToken(); return; } - out.iMaterial = strtoul10(filePtr, &filePtr); + out.iMaterial = strtoul10(mFilePtr, &mFilePtr); } return; } @@ -1863,7 +1864,7 @@ void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) { // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFloat(ai_real &fOut) { // skip spaces and tabs - if (!SkipSpaces(&filePtr, mEnd)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { // LOG LogWarning("Unable to parse float: unexpected EOL [#1]"); fOut = 0.0; @@ -1871,12 +1872,12 @@ void Parser::ParseLV4MeshFloat(ai_real &fOut) { return; } // parse the first float - filePtr = fast_atoreal_move(filePtr, fOut); + mFilePtr = fast_atoreal_move(mFilePtr, fOut); } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshLong(unsigned int &iOut) { // Skip spaces and tabs - if (!SkipSpaces(&filePtr, mEnd)) { + if (!SkipSpaces(&mFilePtr, mEnd)) { // LOG LogWarning("Unable to parse long: unexpected EOL [#1]"); iOut = 0; @@ -1884,7 +1885,7 @@ void Parser::ParseLV4MeshLong(unsigned int &iOut) { return; } // parse the value - iOut = strtoul10(filePtr, &filePtr); + iOut = strtoul10(mFilePtr, &mFilePtr); } } diff --git a/code/AssetLib/ASE/ASEParser.h b/code/AssetLib/ASE/ASEParser.h index 263b5ca73..9c5cd39b1 100644 --- a/code/AssetLib/ASE/ASEParser.h +++ b/code/AssetLib/ASE/ASEParser.h @@ -391,11 +391,11 @@ public: // ------------------------------------------------------------------- //! Construct a parser from a given input file which is //! guaranteed to be terminated with zero. - //! @param szFile Input file + //! @param file The name of the input file. //! @param fileFormatDefault Assumed file format version. If the //! file format is specified in the file the new value replaces //! the default value. - Parser(const char *szFile, unsigned int fileFormatDefault); + Parser(const char *file, size_t fileLen, unsigned int fileFormatDefault); // ------------------------------------------------------------------- //! Parses the file into the parsers internal representation @@ -617,11 +617,8 @@ private: bool ParseString(std::string &out, const char *szName); public: - //! Pointer to current data - const char *filePtr; - - /// The end pointer of the file data - const char *mEnd; + const char *mFilePtr; ////< Pointer to current data + const char *mEnd; ///< The end pointer of the file data //! background color to be passed to the viewer //! QNAN if none was found diff --git a/test/unit/utB3DImportExport.cpp b/test/unit/utB3DImportExport.cpp index 76017f66c..e84313ad8 100644 --- a/test/unit/utB3DImportExport.cpp +++ b/test/unit/utB3DImportExport.cpp @@ -56,6 +56,6 @@ public: } }; -TEST_F(utB3DImportExport, importACFromFileTest) { +TEST_F(utB3DImportExport, importB3DFromFileTest) { EXPECT_TRUE(importerTest()); } From 193f2c5d87ee4e62f64942be33e72ccd59168632 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 8 Jul 2024 17:09:17 +0200 Subject: [PATCH 09/10] Fix compile warning (#5657) --- code/AssetLib/glTF2/glTF2Asset.inl | 2 +- code/AssetLib/glTF2/glTF2AssetWriter.inl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 457fee8fa..3d309049e 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1440,7 +1440,7 @@ inline void MaterialSheen::SetDefaults() { inline void MaterialVolume::SetDefaults() { //KHR_materials_volume properties thicknessFactor = 0.f; - attenuationDistance = INFINITY; + attenuationDistance = std::numeric_limits::infinity(); SetVector(attenuationColor, defaultAttenuationColor); } diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 17e29d8e7..3e42ffe57 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -507,7 +507,7 @@ namespace glTF2 { WriteTex(materialVolume, volume.thicknessTexture, "thicknessTexture", w.mAl); - if (volume.attenuationDistance != INFINITY) { + if (volume.attenuationDistance != std::numeric_limits::infinity()) { WriteFloat(materialVolume, volume.attenuationDistance, "attenuationDistance", w.mAl); } From 206839d4f23162fb515010d5d93a21e1bbde5c50 Mon Sep 17 00:00:00 2001 From: Stepan Hrbek Date: Wed, 10 Jul 2024 09:01:53 +0200 Subject: [PATCH 10/10] Allow empty slots in mTextureCoords (#5636) * Allow empty slots in aiMesh::mTextureCoords. 1.Explicitly say in documentation that empty slots are allowed (it was unclear). 2.Change GetNumUVChannels() implementation to allow empty slots. 3.Revert fraction of 2da2835b29355a0b8f077fee466aba7a4148c1e1 where empty slots are detected and error logged. * Fix #5632 by reverting fraction of d6aacefa1ef1219b85028b4038ef7e861c2e9462 where Collada texcoords are renumbered to avoid empty slots. --------- Co-authored-by: Kim Kulling --- code/AssetLib/Collada/ColladaLoader.cpp | 10 ++++------ code/PostProcessing/ValidateDataStructure.cpp | 15 +-------------- include/assimp/mesh.h | 11 +++++++---- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 2574fd2ea..6d7085b35 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -625,16 +625,14 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc } // same for texture coords, as many as we have - // empty slots are not allowed, need to pack and adjust UV indexes accordingly - for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { if (pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) { - dstMesh->mTextureCoords[real] = new aiVector3D[numVertices]; + dstMesh->mTextureCoords[a] = new aiVector3D[numVertices]; for (size_t b = 0; b < numVertices; ++b) { - dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex + b]; + dstMesh->mTextureCoords[a][b] = pSrcMesh->mTexCoords[a][pStartVertex + b]; } - dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a]; - ++real; + dstMesh->mNumUVComponents[a] = pSrcMesh->mNumUVComponents[a]; } } diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index 1dd5d436a..8441b48be 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -371,20 +371,7 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh) { ReportWarning("There are unreferenced vertices"); } - // texture channel 2 may not be set if channel 1 is zero ... - { - unsigned int i = 0; - for (; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (!pMesh->HasTextureCoords(i)) break; - } - for (; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) - if (pMesh->HasTextureCoords(i)) { - ReportError("Texture coordinate channel %i exists " - "although the previous channel was nullptr.", - i); - } - } - // the same for the vertex colors + // vertex color channel 2 may not be set if channel 1 is zero ... { unsigned int i = 0; for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index ed9a8faf9..da81cc24c 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -729,8 +729,9 @@ struct aiMesh { /** * @brief Vertex texture coordinates, also known as UV channels. * - * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per - * vertex. nullptr if not present. The array is mNumVertices in size. + * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS channels per + * vertex. Used and unused (nullptr) channels may go in any order. + * The array is mNumVertices in size. */ C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; @@ -950,8 +951,10 @@ struct aiMesh { //! @return the number of stored uv-channels. unsigned int GetNumUVChannels() const { unsigned int n(0); - while (n < AI_MAX_NUMBER_OF_TEXTURECOORDS && mTextureCoords[n]) { - ++n; + for (unsigned i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) { + if (mTextureCoords[i]) { + ++n; + } } return n;