From 031d3b648ea98bdc6b61b4925bdc1137ff5fcb95 Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Sun, 10 Nov 2019 08:23:17 +0100 Subject: [PATCH 01/12] defs: use noexcept only for C++11 and more --- include/assimp/defs.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/assimp/defs.h b/include/assimp/defs.h index 6f2f8ae88..d8fc98179 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -306,7 +306,11 @@ static const ai_real ai_epsilon = (ai_real) 0.00001; #define AI_MAX_ALLOC(type) ((256U * 1024 * 1024) / sizeof(type)) #ifndef _MSC_VER -# define AI_NO_EXCEPT noexcept +# if __cplusplus >= 201103L // C++11 +# define AI_NO_EXCEPT noexcept +# else +# define AI_NO_EXCEPT +# endif #else # if (_MSC_VER >= 1915 ) # define AI_NO_EXCEPT noexcept From aa25c815bddd168ec6d1ac0d353c061428d28e27 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 10 Nov 2019 09:47:50 +0100 Subject: [PATCH 02/12] closes https://github.com/assimp/assimp/issues/1320: make sure build works with all exporter disabled. --- code/Common/Exporter.cpp | 127 ++++++++++++++++++------------------ include/assimp/Exporter.hpp | 2 - 2 files changed, 64 insertions(+), 65 deletions(-) diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 4ce1a2bd8..8a95ceae5 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -106,97 +106,88 @@ void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperti void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); -// ------------------------------------------------------------------------------------------------ -// global array of all export formats which Assimp supports in its current build -Exporter::ExportFormatEntry gExporters[] = -{ + +static void setupExporterArray(std::vector &exporters) { #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER - Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada ), + exporters.push_back(Exporter::ExportFormatEntry("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada)); #endif #ifndef ASSIMP_BUILD_NO_X_EXPORTER - Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile, - aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ), + exporters.push_back(Exporter::ExportFormatEntry("x", "X Files", "x", &ExportSceneXFile, + aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs)); #endif #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER - Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("stp", "Step Files", "stp", &ExportSceneStep, 0)); #endif #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER - Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), - Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), + exporters.push_back(Exporter::ExportFormatEntry("obj", "Wavefront OBJ format", "obj", &ExportSceneObj, + aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */)); + exporters.push_back(Exporter::ExportFormatEntry("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl, + aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */)); #endif #ifndef ASSIMP_BUILD_NO_STL_EXPORTER - Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, - aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices - ), - Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary, - aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices - ), + exporters.push_back(Exporter::ExportFormatEntry("stl", "Stereolithography", "stl", &ExportSceneSTL, + aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices)); + exporters.push_back(Exporter::ExportFormatEntry("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary, + aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices)); #endif #ifndef ASSIMP_BUILD_NO_PLY_EXPORTER - Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, - aiProcess_PreTransformVertices - ), - Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary, - aiProcess_PreTransformVertices - ), + exporters.push_back(Exporter::ExportFormatEntry("ply", "Stanford Polygon Library", "ply", &ExportScenePly, + aiProcess_PreTransformVertices)); + exporters.push_back(Exporter::ExportFormatEntry("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary, + aiProcess_PreTransformVertices)); #endif #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER - Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS, - aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ), + exporters.push_back(Exporter::ExportFormatEntry("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS, + aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices)); #endif #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER - Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), + exporters.push_back(Exporter::ExportFormatEntry("gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2, + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType)); + exporters.push_back(Exporter::ExportFormatEntry("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2, + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType)); + exporters.push_back(Exporter::ExportFormatEntry("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType)); + exporters.push_back(Exporter::ExportFormatEntry("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType)); #endif #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER - Exporter::ExportFormatEntry( "assbin", "Assimp Binary File", "assbin" , &ExportSceneAssbin, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0)); #endif #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER - Exporter::ExportFormatEntry( "assxml", "Assimp XML Document", "assxml" , &ExportSceneAssxml, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0)); #endif #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER - Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("x3d", "Extensible 3D", "x3d", &ExportSceneX3D, 0)); #endif #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ), - Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0)); + exporters.push_back(Exporter::ExportFormatEntry("fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0)); #endif #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER - Exporter::ExportFormatEntry( "m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0 ), - Exporter::ExportFormatEntry( "a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0)); + exporters.push_back(Exporter::ExportFormatEntry("a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0)); #endif #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER - Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), + exporters.push_back(Exporter::ExportFormatEntry("3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0)); #endif #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER - Exporter::ExportFormatEntry( "assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0) + exporters.push_back(Exporter::ExportFormatEntry("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0)); #endif -}; - -#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0])) - +} class ExporterPimpl { public: @@ -212,10 +203,7 @@ public: GetPostProcessingStepInstanceList(mPostProcessingSteps); // grab all built-in exporters - if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) { - mExporters.resize( ASSIMP_NUM_EXPORTERS ); - std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() ); - } + setupExporterArray(mExporters); } ~ExporterPimpl() { @@ -259,24 +247,28 @@ Exporter :: Exporter() // ------------------------------------------------------------------------------------------------ Exporter::~Exporter() { - FreeBlob(); + ai_assert(nullptr != pimpl); + FreeBlob(); delete pimpl; } // ------------------------------------------------------------------------------------------------ void Exporter::SetIOHandler( IOSystem* pIOHandler) { - pimpl->mIsDefaultIOHandler = !pIOHandler; + ai_assert(nullptr != pimpl); + pimpl->mIsDefaultIOHandler = !pIOHandler; pimpl->mIOSystem.reset(pIOHandler); } // ------------------------------------------------------------------------------------------------ IOSystem* Exporter::GetIOHandler() const { - return pimpl->mIOSystem.get(); + ai_assert(nullptr != pimpl); + return pimpl->mIOSystem.get(); } // ------------------------------------------------------------------------------------------------ bool Exporter::IsDefaultIOHandler() const { - return pimpl->mIsDefaultIOHandler; + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultIOHandler; } // ------------------------------------------------------------------------------------------------ @@ -302,6 +294,7 @@ void Exporter::SetProgressHandler(ProgressHandler* pHandler) { // ------------------------------------------------------------------------------------------------ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing, const ExportProperties* pProperties) { + ai_assert(nullptr != pimpl); if (pimpl->blob) { delete pimpl->blob; pimpl->blob = nullptr; @@ -326,7 +319,7 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) { ASSIMP_BEGIN_EXCEPTION_REGION(); - + ai_assert(nullptr != pimpl); // when they create scenes from scratch, users will likely create them not in verbose // format. They will likely not be aware that there is a flag in the scene to indicate // this, however. To avoid surprises and bug reports, we check for duplicates in @@ -473,11 +466,13 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c // ------------------------------------------------------------------------------------------------ const char* Exporter::GetErrorString() const { + ai_assert(nullptr != pimpl); return pimpl->mError.c_str(); } // ------------------------------------------------------------------------------------------------ void Exporter::FreeBlob() { + ai_assert(nullptr != pimpl); delete pimpl->blob; pimpl->blob = nullptr; @@ -486,30 +481,34 @@ void Exporter::FreeBlob() { // ------------------------------------------------------------------------------------------------ const aiExportDataBlob* Exporter::GetBlob() const { - return pimpl->blob; + ai_assert(nullptr != pimpl); + return pimpl->blob; } // ------------------------------------------------------------------------------------------------ const aiExportDataBlob* Exporter::GetOrphanedBlob() const { - const aiExportDataBlob* tmp = pimpl->blob; + ai_assert(nullptr != pimpl); + const aiExportDataBlob *tmp = pimpl->blob; pimpl->blob = nullptr; return tmp; } // ------------------------------------------------------------------------------------------------ size_t Exporter::GetExportFormatCount() const { + ai_assert(nullptr != pimpl); return pimpl->mExporters.size(); } // ------------------------------------------------------------------------------------------------ const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const { - if (index >= GetExportFormatCount()) { + ai_assert(nullptr != pimpl); + if (index >= GetExportFormatCount()) { return nullptr; } // Return from static storage if the requested index is built-in. - if (index < sizeof(gExporters) / sizeof(gExporters[0])) { - return &gExporters[index].mDescription; + if (index < pimpl->mExporters.size()) { + return &pimpl->mExporters[index].mDescription; } return &pimpl->mExporters[index].mDescription; @@ -517,7 +516,8 @@ const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) c // ------------------------------------------------------------------------------------------------ aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) { - for(const ExportFormatEntry& e : pimpl->mExporters) { + ai_assert(nullptr != pimpl); + for (const ExportFormatEntry &e : pimpl->mExporters) { if (!strcmp(e.mDescription.id,desc.mDescription.id)) { return aiReturn_FAILURE; } @@ -529,7 +529,8 @@ aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) { // ------------------------------------------------------------------------------------------------ void Exporter::UnregisterExporter(const char* id) { - for(std::vector::iterator it = pimpl->mExporters.begin(); + ai_assert(nullptr != pimpl); + for (std::vector::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) { if (!strcmp((*it).mDescription.id,id)) { pimpl->mExporters.erase(it); diff --git a/include/assimp/Exporter.hpp b/include/assimp/Exporter.hpp index 2612e1f9d..20e7c6c6f 100644 --- a/include/assimp/Exporter.hpp +++ b/include/assimp/Exporter.hpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, From 04db5cd5ea8f2c2095df06e11b5899796f225da6 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 14 Nov 2019 21:11:53 +0100 Subject: [PATCH 03/12] closes https://github.com/assimp/assimp/issues/2119: initial version. --- code/glTF/glTFAsset.inl | 3 --- code/glTF/glTFCommon.h | 17 +++++++---------- code/glTF2/glTF2Asset.h | 6 +++++- code/glTF2/glTF2Asset.inl | 23 ++++++++++++++++++----- code/glTF2/glTF2Exporter.h | 1 + 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/code/glTF/glTFAsset.inl b/code/glTF/glTFAsset.inl index f31781a3f..25cf1873c 100644 --- a/code/glTF/glTFAsset.inl +++ b/code/glTF/glTFAsset.inl @@ -1427,9 +1427,6 @@ inline void Asset::ReadExtensionsUsed(Document& doc) } } - #define CHECK_EXT(EXT) \ - if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; - CHECK_EXT(KHR_binary_glTF); CHECK_EXT(KHR_materials_common); diff --git a/code/glTF/glTFCommon.h b/code/glTF/glTFCommon.h index d9edee75e..b2e28d580 100644 --- a/code/glTF/glTFCommon.h +++ b/code/glTF/glTFCommon.h @@ -188,7 +188,7 @@ namespace glTFCommon { size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); inline - size_t DecodeBase64(const char* in, uint8_t*& out) { + size_t DecodeBase64(const char* in, uint8_t*& out) { return DecodeBase64(in, strlen(in), out); } @@ -221,25 +221,22 @@ namespace glTFCommon { }; inline - char EncodeCharBase64(uint8_t b) { + char EncodeCharBase64(uint8_t b) { return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; } inline - uint8_t DecodeCharBase64(char c) { + uint8_t DecodeCharBase64(char c) { return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? - /*if (c >= 'A' && c <= 'Z') return c - 'A'; - if (c >= 'a' && c <= 'z') return c - 'a' + 26; - if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') return 62; - if (c == '/') return 63; - return 64; // '-' */ } size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); - } + } // namespace Util + +#define CHECK_EXT(EXT) \ + if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; } diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index 15c4c44fa..60a393170 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -685,6 +685,10 @@ namespace glTF2 Ref texture; unsigned int index; unsigned int texCoord = 0; + + float offset[2]; + float rotation; + float scale[2]; }; struct NormalTextureInfo : TextureInfo @@ -1024,7 +1028,7 @@ namespace glTF2 bool KHR_materials_pbrSpecularGlossiness; bool KHR_materials_unlit; bool KHR_lights_punctual; - + bool KHR_texture_transform; } extensionsUsed; AssetMetadata asset; diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 6b47b1607..310fcde06 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -800,8 +800,20 @@ inline void Texture::Read(Value& obj, Asset& r) } namespace { - inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) - { + inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) { + if (r.extensionsUsed.KHR_texture_transform) { + if (Value *extensions = FindObject(*prop, "extensions")) { + if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) { + if (Value *array = FindArray(*pKHR_texture_transform, "offset")) { + out.offset[0] = (*array)[0].GetFloat(); + out.offset[1] = (*array)[1].GetFloat(); + } + ReadMember(*pKHR_texture_transform, "rotation", out.rotation); + ReadMember(*pKHR_texture_transform, "scale", *out.scale); + } + } + } + if (Value* index = FindUInt(*prop, "index")) { out.texture = r.textures.Retrieve(index->GetUint()); } @@ -877,6 +889,9 @@ inline void Material::Read(Value& material, Asset& r) } } + if (r.extensionsUsed.KHR_texture_transform) { + } + unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit"); } } @@ -1463,12 +1478,10 @@ inline void Asset::ReadExtensionsUsed(Document& doc) } } - #define CHECK_EXT(EXT) \ - if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; - CHECK_EXT(KHR_materials_pbrSpecularGlossiness); CHECK_EXT(KHR_materials_unlit); CHECK_EXT(KHR_lights_punctual); + CHECK_EXT(KHR_texture_transform); #undef CHECK_EXT } diff --git a/code/glTF2/glTF2Exporter.h b/code/glTF2/glTF2Exporter.h index 2dc083709..b527c4bc9 100644 --- a/code/glTF2/glTF2Exporter.h +++ b/code/glTF2/glTF2Exporter.h @@ -74,6 +74,7 @@ namespace glTF2 struct Texture; // Vec/matrix types, as raw float arrays + typedef float (vec2)[2]; typedef float (vec3)[3]; typedef float (vec4)[4]; } From 74080a083ad4764485bc633156dd37d0416281a0 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 14 Nov 2019 21:15:30 +0100 Subject: [PATCH 04/12] add texture-transfrm unittest. --- test/models/glTF2/textureTransform/Arrow.png | Bin 0 -> 867 bytes .../models/glTF2/textureTransform/Correct.png | Bin 0 -> 2457 bytes test/models/glTF2/textureTransform/Error.png | Bin 0 -> 2273 bytes .../models/glTF2/textureTransform/License.txt | 0 .../glTF2/textureTransform/NotSupported.png | Bin 0 -> 3291 bytes .../textureTransform/TextureTransformTest.bin | Bin 0 -> 136 bytes .../TextureTransformTest.gltf | 540 ++++++++++++++++++ test/models/glTF2/textureTransform/UV.png | Bin 0 -> 12345 bytes test/unit/utglTF2ImportExport.cpp | 7 + 9 files changed, 547 insertions(+) create mode 100644 test/models/glTF2/textureTransform/Arrow.png create mode 100644 test/models/glTF2/textureTransform/Correct.png create mode 100644 test/models/glTF2/textureTransform/Error.png create mode 100644 test/models/glTF2/textureTransform/License.txt create mode 100644 test/models/glTF2/textureTransform/NotSupported.png create mode 100644 test/models/glTF2/textureTransform/TextureTransformTest.bin create mode 100644 test/models/glTF2/textureTransform/TextureTransformTest.gltf create mode 100644 test/models/glTF2/textureTransform/UV.png diff --git a/test/models/glTF2/textureTransform/Arrow.png b/test/models/glTF2/textureTransform/Arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..fe3405b3f6b14ffdc920bc0f4f30560cabcbab39 GIT binary patch literal 867 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrVAk?aJ56J?j$lS^=gjZ_g@TqW zaQReo#@OwU{5ebgCEMCMJT~8a;-RrdgX`zf#0#yxL)Q;a@-sk40k#~WxL&^iVd z1_nkNG8?wL7TC>aTp-zK$i^^BP{s4n_S?B442yQ9`bRI_!+Sh;ipY*&d}^#?Whhux|hU{RJu8Z@=7~*iy!F?biAEizS#1`x>l{J5ExW zf1b0J$K|`;f;^Vvk3ZfncB(TMcx&kp`}o1@Z}Mj)E^J^9*(%J_emH+WcO{R-^BU*N zXAL*$2n$ZUne*+F--itL9s8wUl2_L` zFCVYk6mXw+1zP}+KHgBp5UR*g%EPe0iAAxG@hiirO;c>ntNI3Oo({Szk&zLdlfCv$ znf1;0-;>thB?JXa{Z~BZ-(r;Vc*+0fuRQIl+8DL{$1T4wKipM-07^X zlU{#~y8SmdKI;Vst03QEK`~Uy| literal 0 HcmV?d00001 diff --git a/test/models/glTF2/textureTransform/Correct.png b/test/models/glTF2/textureTransform/Correct.png new file mode 100644 index 0000000000000000000000000000000000000000..e332824fbc00f15ed290ac891bf18dedf74415e5 GIT binary patch literal 2457 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 L1NF*>w&DK)(UL^| literal 0 HcmV?d00001 diff --git a/test/models/glTF2/textureTransform/License.txt b/test/models/glTF2/textureTransform/License.txt new file mode 100644 index 000000000..e69de29bb diff --git a/test/models/glTF2/textureTransform/NotSupported.png b/test/models/glTF2/textureTransform/NotSupported.png new file mode 100644 index 0000000000000000000000000000000000000000..721e7fd765079c7f2111254145c49e1dbec124d3 GIT binary patch literal 3291 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 literal 0 HcmV?d00001 diff --git a/test/models/glTF2/textureTransform/TextureTransformTest.bin b/test/models/glTF2/textureTransform/TextureTransformTest.bin new file mode 100644 index 0000000000000000000000000000000000000000..6765a13008a0b763d65a217da7fd651a66c2f056 GIT binary patch literal 136 zcmY+6fe8R048x)x=4*cDYc4uL3ngVM1t!qLO1{~jk~i-IjO@ub=lkEu?%A$UDPgHv Fcmbi}2l)U1 literal 0 HcmV?d00001 diff --git a/test/models/glTF2/textureTransform/TextureTransformTest.gltf b/test/models/glTF2/textureTransform/TextureTransformTest.gltf new file mode 100644 index 000000000..6dde51d9a --- /dev/null +++ b/test/models/glTF2/textureTransform/TextureTransformTest.gltf @@ -0,0 +1,540 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 4, + "type": "VEC3", + "max": [ + 0.5, + 0.5, + 0.0 + ], + "min": [ + -0.5, + -0.5, + 0.0 + ], + "name": "Positions" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 4, + "type": "VEC2", + "name": "UV0" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 4, + "type": "VEC2", + "name": "UV1" + }, + { + "bufferView": 3, + "componentType": 5125, + "count": 6, + "type": "SCALAR", + "name": "Indices" + } + ], + "asset": { + "version": "2.0" + }, + "buffers": [ + { + "uri": "TextureTransformTest.bin", + "byteLength": 136 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteLength": 48, + "name": "Positions" + }, + { + "buffer": 0, + "byteOffset": 48, + "byteLength": 32, + "name": "UV0" + }, + { + "buffer": 0, + "byteOffset": 80, + "byteLength": 32, + "name": "UV1" + }, + { + "buffer": 0, + "byteOffset": 112, + "byteLength": 24, + "name": "Indices" + } + ], + "extensionsUsed": [ + "KHR_texture_transform" + ], + "images": [ + { + "uri": "UV.png" + }, + { + "uri": "Arrow.png" + }, + { + "uri": "Correct.png" + }, + { + "uri": "NotSupported.png" + }, + { + "uri": "Error.png" + } + ], + "materials": [ + { + "name": "Offset U", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0, + "extensions": { + "KHR_texture_transform": { + "offset": [ + 0.5, + 0.0 + ] + } + } + }, + "metallicFactor": 0 + } + }, + { + "name": "Offset V", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0, + "extensions": { + "KHR_texture_transform": { + "offset": [ + 0.0, + 0.5 + ] + } + } + }, + "metallicFactor": 0 + } + }, + { + "name": "Offset UV", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0, + "extensions": { + "KHR_texture_transform": { + "offset": [ + 0.5, + 0.5 + ] + } + } + }, + "metallicFactor": 0 + } + }, + { + "name": "Rotation", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 1, + "extensions": { + "KHR_texture_transform": { + "rotation": 0.39269908169872415480783042290994 + } + } + }, + "metallicFactor": 0 + } + }, + { + "name": "Scale", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 1, + "extensions": { + "KHR_texture_transform": { + "scale": [ + 1.5, + 1.5 + ] + } + } + }, + "metallicFactor": 0 + } + }, + { + "name": "All", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 1, + "extensions": { + "KHR_texture_transform": { + "offset": [ + -0.2, + -0.1 + ], + "rotation": 0.3, + "scale": [ + 1.5, + 1.5 + ] + } + } + }, + "metallicFactor": 0 + } + }, + { + "name": "Correct", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 2 + }, + "metallicFactor": 0 + } + }, + { + "name": "NotSupported", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 3 + }, + "metallicFactor": 0 + } + }, + { + "name": "Error", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 4 + }, + "metallicFactor": 0 + } + } + ], + "meshes": [ + { + "name": "Offset U", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 2 + }, + "indices": 3, + "material": 0 + } + ] + }, + { + "name": "Offset V", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 2 + }, + "indices": 3, + "material": 1 + } + ] + }, + { + "name": "Offset UV", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 2 + }, + "indices": 3, + "material": 2 + } + ] + }, + { + "name": "Rotation", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 1 + }, + "indices": 3, + "material": 3 + } + ] + }, + { + "name": "Scale", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 1 + }, + "indices": 3, + "material": 4 + } + ] + }, + { + "name": "All", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 1 + }, + "indices": 3, + "material": 5 + } + ] + }, + { + "name": "Correct Marker", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 1 + }, + "indices": 3, + "material": 6 + } + ] + }, + { + "name": "Not Supported Marker", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 1 + }, + "indices": 3, + "material": 7 + } + ] + }, + { + "name": "Error Marker", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "TEXCOORD_0": 1 + }, + "indices": 3, + "material": 8 + } + ] + } + ], + "nodes": [ + { + "name": "Offset U", + "mesh": 0, + "translation": [ + -1.1, + 0.55, + 0 + ] + }, + { + "name": "Offset V", + "mesh": 1, + "translation": [ + 0, + 0.55, + 0 + ] + }, + { + "name": "Offset UV", + "mesh": 2, + "translation": [ + 1.1, + 0.55, + 0 + ] + }, + { + "name": "Rotation", + "mesh": 3, + "translation": [ + -1.1, + -0.55, + 0 + ], + "children": [ + 4, + 5, + 6 + ] + }, + { + "name": "Rotation - Correct", + "mesh": 6, + "translation": [ + -0.07904822439840125109869401756656, + -0.51626748576241543174100150833647, + 0.01 + ], + "scale": [ + 0.15, + 0.15, + 0.15 + ] + }, + { + "name": "Rotation - Not Supported", + "mesh": 7, + "translation": [ + 0.27781745930520227684092879831533, + -0.27781745930520227684092879831533, + 0.01 + ], + "scale": [ + 0.15, + 0.15, + 0.15 + ] + }, + { + "name": "Rotation - Error", + "mesh": 8, + "translation": [ + 0.51626748576241543174100150833647, + 0.07904822439840125109869401756656, + 0.01 + ], + "scale": [ + 0.15, + 0.15, + 0.15 + ] + }, + { + "name": "Scale", + "mesh": 4, + "translation": [ + 0, + -0.55, + 0 + ], + "children": [ + 8, + 9 + ] + }, + { + "name": "Scale - Correct", + "mesh": 6, + "translation": [ + 0.01854497287013485122728586554355, + -0.01854497287013485122728586554355, + 0.01 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + { + "name": "Scale - Not Supported", + "mesh": 7, + "translation": [ + 0.27781745930520227684092879831533, + -0.27781745930520227684092879831533, + 0.01 + ], + "scale": [ + 0.15, + 0.15, + 0.15 + ] + }, + { + "name": "All", + "mesh": 5, + "translation": [ + 1.1, + -0.55, + 0 + ], + "children": [ + 11 + ] + }, + { + "name": "All - Correct", + "mesh": 6, + "translation": [ + -0.07, + -0.25, + 0.01 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0, + 1, + 2, + 3, + 7, + 10 + ] + } + ], + "textures": [ + { + "source": 0, + "sampler": 0 + }, + { + "source": 1, + "sampler": 0 + }, + { + "source": 2 + }, + { + "source": 3 + }, + { + "source": 4 + } + ], + "samplers": [ + { + "wrapS": 33071, + "wrapT": 33071, + "magFilter": 9729, + "minFilter": 9729 + } + ] +} \ No newline at end of file diff --git a/test/models/glTF2/textureTransform/UV.png b/test/models/glTF2/textureTransform/UV.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a6d4d370c48c7e42ea7337dc5acb4376e5c92f GIT binary patch literal 12345 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[7]->mNumFaces, 17u); } +TEST_F( utglTF2ImportExport, texture_transform_test ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/textureTransform/TextureTransformTest.gltf", + aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); +} + #ifndef ASSIMP_BUILD_NO_EXPORT TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) { EXPECT_TRUE( exporterTest() ); From 17946e26efd2b408f0b5e9bd08615a3a992611ca Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 15 Nov 2019 18:35:33 +0100 Subject: [PATCH 05/12] add missing setup of texture transform in aiMaterial. --- code/glTF2/glTF2Asset.inl | 12 ++++++++++-- code/glTF2/glTF2Importer.cpp | 8 ++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 310fcde06..35f285d85 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -802,14 +802,22 @@ inline void Texture::Read(Value& obj, Asset& r) namespace { inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) { if (r.extensionsUsed.KHR_texture_transform) { - if (Value *extensions = FindObject(*prop, "extensions")) { + out.scale[0] = 1; + out.scale[1] = 1; + out.offset[0] = 0; + out.offset[1] = 0; + out.rotation = 0; + if (Value *extensions = FindObject(*prop, "extensions")) { if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) { if (Value *array = FindArray(*pKHR_texture_transform, "offset")) { out.offset[0] = (*array)[0].GetFloat(); out.offset[1] = (*array)[1].GetFloat(); } ReadMember(*pKHR_texture_transform, "rotation", out.rotation); - ReadMember(*pKHR_texture_transform, "scale", *out.scale); + if (Value *array = FindArray(*pKHR_texture_transform, "scale")) { + out.scale[0] = (*array)[0].GetFloat(); + out.scale[1] = (*array)[1].GetFloat(); + } } } } diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index b3141fd96..8d88260db 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -206,6 +206,14 @@ inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); } + aiUVTransform transform; + transform.mTranslation.x = prop.offset[0]; + transform.mTranslation.y = prop.offset[0]; + transform.mRotation = prop.rotation; + transform.mScaling.x = prop.scale[0]; + transform.mScaling.y = prop.scale[1]; + mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); + mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); From a8182d86cb4c6af514d3d286bf96907a349c3e60 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 15 Nov 2019 19:38:37 +0100 Subject: [PATCH 06/12] fix initialization + some vs2019 compiler warnings. --- code/glTF2/glTF2Asset.inl | 23 ++++++++++++++--------- code/glTF2/glTF2Importer.cpp | 6 +++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 35f285d85..5bc241342 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -802,22 +802,27 @@ inline void Texture::Read(Value& obj, Asset& r) namespace { inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) { if (r.extensionsUsed.KHR_texture_transform) { - out.scale[0] = 1; - out.scale[1] = 1; - out.offset[0] = 0; - out.offset[1] = 0; - out.rotation = 0; if (Value *extensions = FindObject(*prop, "extensions")) { if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) { if (Value *array = FindArray(*pKHR_texture_transform, "offset")) { out.offset[0] = (*array)[0].GetFloat(); out.offset[1] = (*array)[1].GetFloat(); - } - ReadMember(*pKHR_texture_transform, "rotation", out.rotation); - if (Value *array = FindArray(*pKHR_texture_transform, "scale")) { + } else { + out.offset[0] = 0; + out.offset[1] = 0; + } + + if (!ReadMember(*pKHR_texture_transform, "rotation", out.rotation)) { + out.rotation = 0; + } + + if (Value *array = FindArray(*pKHR_texture_transform, "scale")) { out.scale[0] = (*array)[0].GetFloat(); out.scale[1] = (*array)[1].GetFloat(); - } + } else { + out.scale[0] = 1; + out.scale[1] = 1; + } } } } diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 8d88260db..91b758c48 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -622,7 +622,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) nFaces = count / 2; if (nFaces * 2 != count) { ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); - count = nFaces * 2; + count = (unsigned int) nFaces * 2; } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 2) { @@ -649,7 +649,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) nFaces = count / 3; if (nFaces * 3 != count) { ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); - count = nFaces * 3; + count = (unsigned int) nFaces * 3; } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 3) { @@ -1134,7 +1134,7 @@ aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSampl samplers.weight->output->ExtractData(values); anim->mNumKeys = static_cast(samplers.weight->input->count); - const unsigned int numMorphs = samplers.weight->output->count / anim->mNumKeys; + const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys; anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; unsigned int k = 0u; From 3a8cb442f39efee20425dfe6d5ae65bfc5ba6e48 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 15 Nov 2019 20:52:13 +0100 Subject: [PATCH 07/12] closes https://github.com/assimp/assimp/issues/2681: add dx11-sample to cmake. --- CMakeLists.txt | 2 +- .../SimpleTexturedDirectx11/CMakeLists.txt | 48 ++++++ .../SimpleTexturedDirectx11.sln | 28 ---- .../SimpleTexturedDirectx11/ModelLoader.cpp | 2 + .../SimpleTexturedDirectx11.vcxproj | 146 ------------------ .../SimpleTexturedDirectx11.vcxproj.filters | 50 ------ 6 files changed, 51 insertions(+), 225 deletions(-) create mode 100644 samples/SimpleTexturedDirectx11/CMakeLists.txt delete mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln delete mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj delete mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters diff --git a/CMakeLists.txt b/CMakeLists.txt index 693d6f16a..7a94ddf68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ OPTION( ASSIMP_BUILD_ASSIMP_TOOLS ) OPTION ( ASSIMP_BUILD_SAMPLES "If the official samples are built as well (needs Glut)." - OFF + ON ) OPTION ( ASSIMP_BUILD_TESTS "If the test suite for Assimp is built in addition to the library." diff --git a/samples/SimpleTexturedDirectx11/CMakeLists.txt b/samples/SimpleTexturedDirectx11/CMakeLists.txt new file mode 100644 index 000000000..a463ee282 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/CMakeLists.txt @@ -0,0 +1,48 @@ +FIND_PACKAGE(DirectX) + +IF ( MSVC ) + SET(M_LIB) +ELSE ( MSVC ) + find_library(M_LIB m) +ENDIF ( MSVC ) + +if ( MSVC ) + ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) + ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) + REMOVE_DEFINITIONS( -DUNICODE -D_UNICODE ) +endif ( MSVC ) + +INCLUDE_DIRECTORIES( + ${Assimp_SOURCE_DIR}/include + ${Assimp_SOURCE_DIR}/code + ${OPENGL_INCLUDE_DIR} + ${GLUT_INCLUDE_DIR} + ${Assimp_SOURCE_DIR}/samples/freeglut/include +) + +LINK_DIRECTORIES( + ${Assimp_BINARY_DIR} + ${Assimp_BINARY_DIR}/lib +) + +ADD_EXECUTABLE( assimp_simpletextureddirectx11 WIN32 + SimpleTexturedDirectx11/Mesh.h + SimpleTexturedDirectx11/ModelLoader.cpp + SimpleTexturedDirectx11/ModelLoader.h + #SimpleTexturedDirectx11/PixelShader.hlsl + SimpleTexturedDirectx11/TextureLoader.cpp + SimpleTexturedDirectx11/TextureLoader.h + #SimpleTexturedDirectx11/VertexShader.hlsl + SimpleTexturedDirectx11/main.cpp +) + +SET_PROPERTY(TARGET assimp_simpletextureddirectx11 PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +TARGET_LINK_LIBRARIES( assimp_simpletextureddirectx11 assimp ${DirectX_LIBRARY} comctl32.lib winmm.lib ) +SET_TARGET_PROPERTIES( assimp_simpletextureddirectx11 PROPERTIES + OUTPUT_NAME assimp_simpletextureddirectx11 +) + +INSTALL( TARGETS assimp_simpletextureddirectx11 + DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-dev +) diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln deleted file mode 100644 index 381ac8f94..000000000 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.9 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp index a2d3faeb3..10ba07a98 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -180,6 +180,8 @@ string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat { return "textures are on disk"; } + + return "."; } int ModelLoader::getTextureIndex(aiString * str) diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj deleted file mode 100644 index 6584b7d7c..000000000 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj +++ /dev/null @@ -1,146 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {E3B160B5-E71F-4F3F-9310-B8F156F736D8} - SimpleTexturedDirectx11 - 10.0.14393.0 - - - - Application - true - v141 - MultiByte - - - Application - false - v141 - true - MultiByte - - - Application - true - v141 - MultiByte - - - Application - false - v141 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - $(IncludePath);E:\OpenGL VS Files\include - $(LibraryPath);E:\OpenGL VS Files\lib - - - - Level3 - Disabled - true - - - assimp-vc140-mt.lib;%(AdditionalDependencies) - - - - - Level3 - Disabled - true - - - - - Level3 - MaxSpeed - true - true - true - - - true - true - - - - - Level3 - MaxSpeed - true - true - true - - - true - true - - - - - - - - - - Pixel - Pixel - Pixel - Pixel - - - Vertex - Vertex - Vertex - Vertex - - - - - - - - - - - \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters deleted file mode 100644 index 3568b73c5..000000000 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters +++ /dev/null @@ -1,50 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {b6a86d3e-70a5-4d1e-ba05-c20902300206} - - - - - Source Files - - - Source Files - - - Source Files - - - - - Shaders - - - Shaders - - - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file From 4ad2368116f984e2ba36f32083f649dbba175fcc Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 15 Nov 2019 21:46:09 +0100 Subject: [PATCH 08/12] disable samples per default. --- CMakeLists.txt | 2 +- samples/SimpleTexturedDirectx11/CMakeLists.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a94ddf68..693d6f16a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ OPTION( ASSIMP_BUILD_ASSIMP_TOOLS ) OPTION ( ASSIMP_BUILD_SAMPLES "If the official samples are built as well (needs Glut)." - ON + OFF ) OPTION ( ASSIMP_BUILD_TESTS "If the test suite for Assimp is built in addition to the library." diff --git a/samples/SimpleTexturedDirectx11/CMakeLists.txt b/samples/SimpleTexturedDirectx11/CMakeLists.txt index a463ee282..373b5a9db 100644 --- a/samples/SimpleTexturedDirectx11/CMakeLists.txt +++ b/samples/SimpleTexturedDirectx11/CMakeLists.txt @@ -2,8 +2,6 @@ FIND_PACKAGE(DirectX) IF ( MSVC ) SET(M_LIB) -ELSE ( MSVC ) - find_library(M_LIB m) ENDIF ( MSVC ) if ( MSVC ) From 2eed8b18208d93000ae5b23339f7ecb4672fda8e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 16 Nov 2019 08:08:57 +0100 Subject: [PATCH 09/12] TextureTransform: set material transform only when the extension is provided. --- code/glTF2/glTF2Asset.h | 11 +- code/glTF2/glTF2Asset.inl | 23 +- code/glTF2/glTF2Importer.cpp | 2006 +++++++++++++++++----------------- 3 files changed, 1001 insertions(+), 1039 deletions(-) diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index 60a393170..831a763cd 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -685,10 +685,13 @@ namespace glTF2 Ref texture; unsigned int index; unsigned int texCoord = 0; - - float offset[2]; - float rotation; - float scale[2]; + + bool textureTransformSupported = false; + struct TextureTransformExt { + float offset[2]; + float rotation; + float scale[2]; + } TextureTransformExt_t; }; struct NormalTextureInfo : TextureInfo diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 5bc241342..4259022e9 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -803,25 +803,26 @@ namespace { inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) { if (r.extensionsUsed.KHR_texture_transform) { if (Value *extensions = FindObject(*prop, "extensions")) { - if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) { + out.textureTransformSupported = true; + if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) { if (Value *array = FindArray(*pKHR_texture_transform, "offset")) { - out.offset[0] = (*array)[0].GetFloat(); - out.offset[1] = (*array)[1].GetFloat(); + out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat(); + out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat(); } else { - out.offset[0] = 0; - out.offset[1] = 0; + out.TextureTransformExt_t.offset[0] = 0; + out.TextureTransformExt_t.offset[1] = 0; } - if (!ReadMember(*pKHR_texture_transform, "rotation", out.rotation)) { - out.rotation = 0; + if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) { + out.TextureTransformExt_t.rotation = 0; } if (Value *array = FindArray(*pKHR_texture_transform, "scale")) { - out.scale[0] = (*array)[0].GetFloat(); - out.scale[1] = (*array)[1].GetFloat(); + out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat(); + out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat(); } else { - out.scale[0] = 1; - out.scale[1] = 1; + out.TextureTransformExt_t.scale[0] = 1; + out.TextureTransformExt_t.scale[1] = 1; } } } diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 91b758c48..3dffa4b27 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -43,18 +43,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #include "glTF2/glTF2Importer.h" +#include "PostProcessing/MakeVerboseFormat.h" #include "glTF2/glTF2Asset.h" #include "glTF2/glTF2AssetWriter.h" -#include "PostProcessing/MakeVerboseFormat.h" +#include #include #include -#include -#include #include -#include #include -#include +#include +#include +#include #include #include @@ -67,11 +67,11 @@ using namespace glTF2; using namespace glTFCommon; namespace { - // generate bi-tangents from normals and tangents according to spec - struct Tangent { - aiVector3D xyz; - ai_real w; - }; +// generate bi-tangents from normals and tangents according to spec +struct Tangent { + aiVector3D xyz; + ai_real w; +}; } // namespace // @@ -79,66 +79,63 @@ namespace { // static const aiImporterDesc desc = { - "glTF2 Importer", - "", - "", - "", - aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, - 0, - 0, - 0, - 0, - "gltf glb" + "glTF2 Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + 0, + 0, + 0, + 0, + "gltf glb" }; -glTF2Importer::glTF2Importer() -: BaseImporter() -, meshOffsets() -, embeddedTexIdxs() -, mScene( NULL ) { - // empty +glTF2Importer::glTF2Importer() : + BaseImporter(), + meshOffsets(), + embeddedTexIdxs(), + mScene(NULL) { + // empty } glTF2Importer::~glTF2Importer() { - // empty + // empty } -const aiImporterDesc* glTF2Importer::GetInfo() const -{ - return &desc; +const aiImporterDesc *glTF2Importer::GetInfo() const { + return &desc; } -bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool /* checkSig */) const -{ - const std::string &extension = GetExtension(pFile); +bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const { + const std::string &extension = GetExtension(pFile); - if (extension != "gltf" && extension != "glb") - return false; + if (extension != "gltf" && extension != "glb") + return false; - if (pIOHandler) { - glTF2::Asset asset(pIOHandler); - asset.Load(pFile, extension == "glb"); - std::string version = asset.asset.version; - return !version.empty() && version[0] == '2'; - } + if (pIOHandler) { + glTF2::Asset asset(pIOHandler); + asset.Load(pFile, extension == "glb"); + std::string version = asset.asset.version; + return !version.empty() && version[0] == '2'; + } - return false; + return false; } -static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) -{ - switch (gltfWrapMode) { - case SamplerWrap::Mirrored_Repeat: - return aiTextureMapMode_Mirror; +static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) { + switch (gltfWrapMode) { + case SamplerWrap::Mirrored_Repeat: + return aiTextureMapMode_Mirror; - case SamplerWrap::Clamp_To_Edge: - return aiTextureMapMode_Clamp; + case SamplerWrap::Clamp_To_Edge: + return aiTextureMapMode_Clamp; - case SamplerWrap::UNSET: - case SamplerWrap::Repeat: - default: - return aiTextureMapMode_Wrap; - } + case SamplerWrap::UNSET: + case SamplerWrap::Repeat: + default: + return aiTextureMapMode_Wrap; + } } /*static void CopyValue(const glTF2::vec3& v, aiColor3D& out) @@ -180,1190 +177,1151 @@ static void CopyValue(const glTF2::vec4& v, aiQuaternion& out) o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; }*/ -inline void SetMaterialColorProperty(Asset& /*r*/, vec4& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) -{ - aiColor4D col; - CopyValue(prop, col); - mat->AddProperty(&col, 1, pKey, type, idx); +inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat, const char *pKey, unsigned int type, unsigned int idx) { + aiColor4D col; + CopyValue(prop, col); + mat->AddProperty(&col, 1, pKey, type, idx); } -inline void SetMaterialColorProperty(Asset& /*r*/, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) -{ - aiColor4D col; - glTFCommon::CopyValue(prop, col); - mat->AddProperty(&col, 1, pKey, type, idx); +inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat, const char *pKey, unsigned int type, unsigned int idx) { + aiColor4D col; + glTFCommon::CopyValue(prop, col); + mat->AddProperty(&col, 1, pKey, type, idx); } -inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& /*r*/, glTF2::TextureInfo prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0) -{ - if (prop.texture && prop.texture->source) { - aiString uri(prop.texture->source->uri); +inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset & /*r*/, glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) { + if (prop.texture && prop.texture->source) { + aiString uri(prop.texture->source->uri); - int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; - if (texIdx != -1) { // embedded - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) - uri.data[0] = '*'; - uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); - } + int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; + if (texIdx != -1) { // embedded + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) + uri.data[0] = '*'; + uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); + } - aiUVTransform transform; - transform.mTranslation.x = prop.offset[0]; - transform.mTranslation.y = prop.offset[0]; - transform.mRotation = prop.rotation; - transform.mScaling.x = prop.scale[0]; - transform.mScaling.y = prop.scale[1]; - mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); + if (prop.textureTransformSupported) { + aiUVTransform transform; + transform.mTranslation.x = prop.TextureTransformExt_t.offset[0]; + transform.mTranslation.y = prop.TextureTransformExt_t.offset[0]; + transform.mRotation = prop.TextureTransformExt_t.rotation; + transform.mScaling.x = prop.TextureTransformExt_t.scale[0]; + transform.mScaling.y = prop.TextureTransformExt_t.scale[1]; + mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); + } - mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); - mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); + mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); + mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); - if (prop.texture->sampler) { - Ref sampler = prop.texture->sampler; + if (prop.texture->sampler) { + Ref sampler = prop.texture->sampler; - aiString name(sampler->name); - aiString id(sampler->id); + aiString name(sampler->name); + aiString id(sampler->id); - mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot)); - mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot)); + mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot)); + mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot)); - aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS); - aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT); - mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot)); - mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot)); + aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS); + aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT); + mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot)); + mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot)); - if (sampler->magFilter != SamplerMagFilter::UNSET) { - mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot)); - } + if (sampler->magFilter != SamplerMagFilter::UNSET) { + mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot)); + } - if (sampler->minFilter != SamplerMinFilter::UNSET) { - mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot)); - } - } - } + if (sampler->minFilter != SamplerMinFilter::UNSET) { + mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot)); + } + } + } } -inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& r, glTF2::NormalTextureInfo& prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0) -{ - SetMaterialTextureProperty( embeddedTexIdxs, r, (glTF2::TextureInfo) prop, mat, texType, texSlot ); +inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset &r, glTF2::NormalTextureInfo &prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) { + SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot); - if (prop.texture && prop.texture->source) { - mat->AddProperty(&prop.scale, 1, AI_MATKEY_GLTF_TEXTURE_SCALE(texType, texSlot)); - } + if (prop.texture && prop.texture->source) { + mat->AddProperty(&prop.scale, 1, AI_MATKEY_GLTF_TEXTURE_SCALE(texType, texSlot)); + } } -inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& r, glTF2::OcclusionTextureInfo& prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0) -{ - SetMaterialTextureProperty( embeddedTexIdxs, r, (glTF2::TextureInfo) prop, mat, texType, texSlot ); +inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset &r, glTF2::OcclusionTextureInfo &prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) { + SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot); - if (prop.texture && prop.texture->source) { - mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot)); - } + if (prop.texture && prop.texture->source) { + mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot)); + } } -static aiMaterial* ImportMaterial(std::vector& embeddedTexIdxs, Asset& r, Material& mat) -{ - aiMaterial* aimat = new aiMaterial(); +static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, Material &mat) { + aiMaterial *aimat = new aiMaterial(); - if (!mat.name.empty()) { - aiString str(mat.name); + if (!mat.name.empty()) { + aiString str(mat.name); - aimat->AddProperty(&str, AI_MATKEY_NAME); - } + aimat->AddProperty(&str, AI_MATKEY_NAME); + } - SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); - SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); - aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); - aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); + aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); + aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); - float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; - roughnessAsShininess *= roughnessAsShininess * 1000; - aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS); + float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; + roughnessAsShininess *= roughnessAsShininess * 1000; + aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); - SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); + SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); - aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); + aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); - aiString alphaMode(mat.alphaMode); - aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); - aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); + aiString alphaMode(mat.alphaMode); + aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); + aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); - //pbrSpecularGlossiness - if (mat.pbrSpecularGlossiness.isPresent) { - PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; + //pbrSpecularGlossiness + if (mat.pbrSpecularGlossiness.isPresent) { + PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; - aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); - SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); - SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); + aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); + SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); - float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; - aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); - aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); + float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; + aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); + aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); - SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); - } - if (mat.unlit) { - aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); - } + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); + } + if (mat.unlit) { + aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); + } - return aimat; + return aimat; } -void glTF2Importer::ImportMaterials(glTF2::Asset& r) -{ - const unsigned int numImportedMaterials = unsigned(r.materials.Size()); - Material defaultMaterial; +void glTF2Importer::ImportMaterials(glTF2::Asset &r) { + const unsigned int numImportedMaterials = unsigned(r.materials.Size()); + Material defaultMaterial; - mScene->mNumMaterials = numImportedMaterials + 1; - mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials]; - mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial); + mScene->mNumMaterials = numImportedMaterials + 1; + mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; + mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial); - for (unsigned int i = 0; i < numImportedMaterials; ++i) { - mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]); - } + for (unsigned int i = 0; i < numImportedMaterials; ++i) { + mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]); + } } - -static inline void SetFace(aiFace& face, int a) -{ - face.mNumIndices = 1; - face.mIndices = new unsigned int[1]; - face.mIndices[0] = a; +static inline void SetFace(aiFace &face, int a) { + face.mNumIndices = 1; + face.mIndices = new unsigned int[1]; + face.mIndices[0] = a; } -static inline void SetFace(aiFace& face, int a, int b) -{ - face.mNumIndices = 2; - face.mIndices = new unsigned int[2]; - face.mIndices[0] = a; - face.mIndices[1] = b; +static inline void SetFace(aiFace &face, int a, int b) { + face.mNumIndices = 2; + face.mIndices = new unsigned int[2]; + face.mIndices[0] = a; + face.mIndices[1] = b; } -static inline void SetFace(aiFace& face, int a, int b, int c) -{ - face.mNumIndices = 3; - face.mIndices = new unsigned int[3]; - face.mIndices[0] = a; - face.mIndices[1] = b; - face.mIndices[2] = c; +static inline void SetFace(aiFace &face, int a, int b, int c) { + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = a; + face.mIndices[1] = b; + face.mIndices[2] = c; } #ifdef ASSIMP_BUILD_DEBUG -static inline bool CheckValidFacesIndices(aiFace* faces, unsigned nFaces, unsigned nVerts) -{ - for (unsigned i = 0; i < nFaces; ++i) { - for (unsigned j = 0; j < faces[i].mNumIndices; ++j) { - unsigned idx = faces[i].mIndices[j]; - if (idx >= nVerts) - return false; - } - } - return true; +static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsigned nVerts) { + for (unsigned i = 0; i < nFaces; ++i) { + for (unsigned j = 0; j < faces[i].mNumIndices; ++j) { + unsigned idx = faces[i].mIndices[j]; + if (idx >= nVerts) + return false; + } + } + return true; } #endif // ASSIMP_BUILD_DEBUG -void glTF2Importer::ImportMeshes(glTF2::Asset& r) -{ - std::vector meshes; +void glTF2Importer::ImportMeshes(glTF2::Asset &r) { + std::vector meshes; - unsigned int k = 0; + unsigned int k = 0; - for (unsigned int m = 0; m < r.meshes.Size(); ++m) { - Mesh& mesh = r.meshes[m]; + for (unsigned int m = 0; m < r.meshes.Size(); ++m) { + Mesh &mesh = r.meshes[m]; - meshOffsets.push_back(k); - k += unsigned(mesh.primitives.size()); + meshOffsets.push_back(k); + k += unsigned(mesh.primitives.size()); - for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { - Mesh::Primitive& prim = mesh.primitives[p]; + for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { + Mesh::Primitive &prim = mesh.primitives[p]; - aiMesh* aim = new aiMesh(); - meshes.push_back(aim); + aiMesh *aim = new aiMesh(); + meshes.push_back(aim); - aim->mName = mesh.name.empty() ? mesh.id : mesh.name; + aim->mName = mesh.name.empty() ? mesh.id : mesh.name; - if (mesh.primitives.size() > 1) { - ai_uint32& len = aim->mName.length; - aim->mName.data[len] = '-'; - len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); - } + if (mesh.primitives.size() > 1) { + ai_uint32 &len = aim->mName.length; + aim->mName.data[len] = '-'; + len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); + } - switch (prim.mode) { - case PrimitiveMode_POINTS: - aim->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; + switch (prim.mode) { + case PrimitiveMode_POINTS: + aim->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; - case PrimitiveMode_LINES: - case PrimitiveMode_LINE_LOOP: - case PrimitiveMode_LINE_STRIP: - aim->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; + case PrimitiveMode_LINES: + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: + aim->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; - case PrimitiveMode_TRIANGLES: - case PrimitiveMode_TRIANGLE_STRIP: - case PrimitiveMode_TRIANGLE_FAN: - aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; + case PrimitiveMode_TRIANGLES: + case PrimitiveMode_TRIANGLE_STRIP: + case PrimitiveMode_TRIANGLE_FAN: + aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + } - } + Mesh::Primitive::Attributes &attr = prim.attributes; - Mesh::Primitive::Attributes& attr = prim.attributes; + if (attr.position.size() > 0 && attr.position[0]) { + aim->mNumVertices = static_cast(attr.position[0]->count); + attr.position[0]->ExtractData(aim->mVertices); + } - if (attr.position.size() > 0 && attr.position[0]) { - aim->mNumVertices = static_cast(attr.position[0]->count); - attr.position[0]->ExtractData(aim->mVertices); - } + if (attr.normal.size() > 0 && attr.normal[0]) { + attr.normal[0]->ExtractData(aim->mNormals); - if (attr.normal.size() > 0 && attr.normal[0]) { - attr.normal[0]->ExtractData(aim->mNormals); + // only extract tangents if normals are present + if (attr.tangent.size() > 0 && attr.tangent[0]) { + // generate bitangents from normals and tangents according to spec + Tangent *tangents = nullptr; - // only extract tangents if normals are present - if (attr.tangent.size() > 0 && attr.tangent[0]) { - // generate bitangents from normals and tangents according to spec - Tangent *tangents = nullptr; + attr.tangent[0]->ExtractData(tangents); - attr.tangent[0]->ExtractData(tangents); + aim->mTangents = new aiVector3D[aim->mNumVertices]; + aim->mBitangents = new aiVector3D[aim->mNumVertices]; - aim->mTangents = new aiVector3D[aim->mNumVertices]; - aim->mBitangents = new aiVector3D[aim->mNumVertices]; + for (unsigned int i = 0; i < aim->mNumVertices; ++i) { + aim->mTangents[i] = tangents[i].xyz; + aim->mBitangents[i] = (aim->mNormals[i] ^ tangents[i].xyz) * tangents[i].w; + } - for (unsigned int i = 0; i < aim->mNumVertices; ++i) { - aim->mTangents[i] = tangents[i].xyz; - aim->mBitangents[i] = (aim->mNormals[i] ^ tangents[i].xyz) * tangents[i].w; - } + delete[] tangents; + } + } - delete [] tangents; - } - } + for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) { + if (attr.color[c]->count != aim->mNumVertices) { + DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name + + "\" does not match the vertex count"); + continue; + } + attr.color[c]->ExtractData(aim->mColors[c]); + } + for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { + if (attr.texcoord[tc]->count != aim->mNumVertices) { + DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name + + "\" does not match the vertex count"); + continue; + } - for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) { - if (attr.color[c]->count != aim->mNumVertices) { - DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name + - "\" does not match the vertex count"); - continue; - } - attr.color[c]->ExtractData(aim->mColors[c]); - } - for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { - if (attr.texcoord[tc]->count != aim->mNumVertices) { - DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name + - "\" does not match the vertex count"); - continue; - } + attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); + aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); - attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); - aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); + aiVector3D *values = aim->mTextureCoords[tc]; + for (unsigned int i = 0; i < aim->mNumVertices; ++i) { + values[i].y = 1 - values[i].y; // Flip Y coords + } + } - aiVector3D* values = aim->mTextureCoords[tc]; - for (unsigned int i = 0; i < aim->mNumVertices; ++i) { - values[i].y = 1 - values[i].y; // Flip Y coords - } - } + std::vector &targets = prim.targets; + if (targets.size() > 0) { + aim->mNumAnimMeshes = (unsigned int)targets.size(); + aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes]; + for (size_t i = 0; i < targets.size(); i++) { + aim->mAnimMeshes[i] = aiCreateAnimMesh(aim); + aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]); + Mesh::Primitive::Target &target = targets[i]; - std::vector& targets = prim.targets; - if (targets.size() > 0) { - aim->mNumAnimMeshes = (unsigned int)targets.size(); - aim->mAnimMeshes = new aiAnimMesh*[aim->mNumAnimMeshes]; - for (size_t i = 0; i < targets.size(); i++) { - aim->mAnimMeshes[i] = aiCreateAnimMesh(aim); - aiAnimMesh& aiAnimMesh = *(aim->mAnimMeshes[i]); - Mesh::Primitive::Target& target = targets[i]; + if (target.position.size() > 0) { + aiVector3D *positionDiff = nullptr; + target.position[0]->ExtractData(positionDiff); + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; + } + delete[] positionDiff; + } + if (target.normal.size() > 0) { + aiVector3D *normalDiff = nullptr; + target.normal[0]->ExtractData(normalDiff); + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; + } + delete[] normalDiff; + } + if (target.tangent.size() > 0) { + Tangent *tangent = nullptr; + attr.tangent[0]->ExtractData(tangent); - if (target.position.size() > 0) { - aiVector3D *positionDiff = nullptr; - target.position[0]->ExtractData(positionDiff); - for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { - aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; - } - delete [] positionDiff; - } - if (target.normal.size() > 0) { - aiVector3D *normalDiff = nullptr; - target.normal[0]->ExtractData(normalDiff); - for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { - aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; - } - delete [] normalDiff; - } - if (target.tangent.size() > 0) { - Tangent *tangent = nullptr; - attr.tangent[0]->ExtractData(tangent); + aiVector3D *tangentDiff = nullptr; + target.tangent[0]->ExtractData(tangentDiff); - aiVector3D *tangentDiff = nullptr; - target.tangent[0]->ExtractData(tangentDiff); + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { + tangent[vertexId].xyz += tangentDiff[vertexId]; + aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz; + aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; + } + delete[] tangent; + delete[] tangentDiff; + } + if (mesh.weights.size() > i) { + aiAnimMesh.mWeight = mesh.weights[i]; + } + } + } - for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { - tangent[vertexId].xyz += tangentDiff[vertexId]; - aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz; - aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; - } - delete [] tangent; - delete [] tangentDiff; - } - if (mesh.weights.size() > i) { - aiAnimMesh.mWeight = mesh.weights[i]; - } - } - } + aiFace *faces = 0; + size_t nFaces = 0; + if (prim.indices) { + size_t count = prim.indices->count; - aiFace* faces = 0; - size_t nFaces = 0; + Accessor::Indexer data = prim.indices->GetIndexer(); + ai_assert(data.IsValid()); - if (prim.indices) { - size_t count = prim.indices->count; + switch (prim.mode) { + case PrimitiveMode_POINTS: { + nFaces = count; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; ++i) { + SetFace(faces[i], data.GetUInt(i)); + } + break; + } - Accessor::Indexer data = prim.indices->GetIndexer(); - ai_assert(data.IsValid()); + case PrimitiveMode_LINES: { + nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = nFaces * 2; + } + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 2) { + SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); + } + break; + } - switch (prim.mode) { - case PrimitiveMode_POINTS: { - nFaces = count; - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; ++i) { - SetFace(faces[i], data.GetUInt(i)); - } - break; - } + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: { + nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1)); + for (unsigned int i = 2; i < count; ++i) { + SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i)); + } + if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop + SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); + } + break; + } - case PrimitiveMode_LINES: { - nFaces = count / 2; - if (nFaces * 2 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); - count = nFaces * 2; - } - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 2) { - SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); - } - break; - } + case PrimitiveMode_TRIANGLES: { + nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = nFaces * 3; + } + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 3) { + SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + break; + } + case PrimitiveMode_TRIANGLE_STRIP: { + nFaces = count - 2; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < nFaces; ++i) { + //The ordering is to ensure that the triangles are all drawn with the same orientation + if ((i + 1) % 2 == 0) { + //For even n, vertices n + 1, n, and n + 2 define triangle n + SetFace(faces[i], data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2)); + } else { + //For odd n, vertices n, n+1, and n+2 define triangle n + SetFace(faces[i], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + } + break; + } + case PrimitiveMode_TRIANGLE_FAN: + nFaces = count - 2; + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); + for (unsigned int i = 1; i < nFaces; ++i) { + SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i + 2)); + } + break; + } + } else { // no indices provided so directly generate from counts - case PrimitiveMode_LINE_LOOP: - case PrimitiveMode_LINE_STRIP: { - nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); - faces = new aiFace[nFaces]; - SetFace(faces[0], data.GetUInt(0), data.GetUInt(1)); - for (unsigned int i = 2; i < count; ++i) { - SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i)); - } - if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop - SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); - } - break; - } + // use the already determined count as it includes checks + unsigned int count = aim->mNumVertices; - case PrimitiveMode_TRIANGLES: { - nFaces = count / 3; - if (nFaces * 3 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); - count = nFaces * 3; - } - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 3) { - SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); - } - break; - } - case PrimitiveMode_TRIANGLE_STRIP: { - nFaces = count - 2; - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < nFaces; ++i) { - //The ordering is to ensure that the triangles are all drawn with the same orientation - if ((i + 1) % 2 == 0) - { - //For even n, vertices n + 1, n, and n + 2 define triangle n - SetFace(faces[i], data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2)); - } - else - { - //For odd n, vertices n, n+1, and n+2 define triangle n - SetFace(faces[i], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); - } - } - break; - } - case PrimitiveMode_TRIANGLE_FAN: - nFaces = count - 2; - faces = new aiFace[nFaces]; - SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); - for (unsigned int i = 1; i < nFaces; ++i) { - SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i + 2)); - } - break; - } - } - else { // no indices provided so directly generate from counts + switch (prim.mode) { + case PrimitiveMode_POINTS: { + nFaces = count; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; ++i) { + SetFace(faces[i], i); + } + break; + } - // use the already determined count as it includes checks - unsigned int count = aim->mNumVertices; + case PrimitiveMode_LINES: { + nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = (unsigned int)nFaces * 2; + } + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 2) { + SetFace(faces[i / 2], i, i + 1); + } + break; + } - switch (prim.mode) { - case PrimitiveMode_POINTS: { - nFaces = count; - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; ++i) { - SetFace(faces[i], i); - } - break; - } + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: { + nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); + faces = new aiFace[nFaces]; + SetFace(faces[0], 0, 1); + for (unsigned int i = 2; i < count; ++i) { + SetFace(faces[i - 1], faces[i - 2].mIndices[1], i); + } + if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop + SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); + } + break; + } - case PrimitiveMode_LINES: { - nFaces = count / 2; - if (nFaces * 2 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); - count = (unsigned int) nFaces * 2; - } - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 2) { - SetFace(faces[i / 2], i, i + 1); - } - break; - } + case PrimitiveMode_TRIANGLES: { + nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = (unsigned int)nFaces * 3; + } + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 3) { + SetFace(faces[i / 3], i, i + 1, i + 2); + } + break; + } + case PrimitiveMode_TRIANGLE_STRIP: { + nFaces = count - 2; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < nFaces; ++i) { + //The ordering is to ensure that the triangles are all drawn with the same orientation + if ((i + 1) % 2 == 0) { + //For even n, vertices n + 1, n, and n + 2 define triangle n + SetFace(faces[i], i + 1, i, i + 2); + } else { + //For odd n, vertices n, n+1, and n+2 define triangle n + SetFace(faces[i], i, i + 1, i + 2); + } + } + break; + } + case PrimitiveMode_TRIANGLE_FAN: + nFaces = count - 2; + faces = new aiFace[nFaces]; + SetFace(faces[0], 0, 1, 2); + for (unsigned int i = 1; i < nFaces; ++i) { + SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], i + 2); + } + break; + } + } - case PrimitiveMode_LINE_LOOP: - case PrimitiveMode_LINE_STRIP: { - nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); - faces = new aiFace[nFaces]; - SetFace(faces[0], 0, 1); - for (unsigned int i = 2; i < count; ++i) { - SetFace(faces[i - 1], faces[i - 2].mIndices[1], i); - } - if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop - SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); - } - break; - } + if (faces) { + aim->mFaces = faces; + aim->mNumFaces = static_cast(nFaces); + ai_assert(CheckValidFacesIndices(faces, static_cast(nFaces), aim->mNumVertices)); + } - case PrimitiveMode_TRIANGLES: { - nFaces = count / 3; - if (nFaces * 3 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); - count = (unsigned int) nFaces * 3; - } - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 3) { - SetFace(faces[i / 3], i, i + 1, i + 2); - } - break; - } - case PrimitiveMode_TRIANGLE_STRIP: { - nFaces = count - 2; - faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < nFaces; ++i) { - //The ordering is to ensure that the triangles are all drawn with the same orientation - if ((i+1) % 2 == 0) - { - //For even n, vertices n + 1, n, and n + 2 define triangle n - SetFace(faces[i], i+1, i, i+2); - } - else - { - //For odd n, vertices n, n+1, and n+2 define triangle n - SetFace(faces[i], i, i+1, i+2); - } - } - break; - } - case PrimitiveMode_TRIANGLE_FAN: - nFaces = count - 2; - faces = new aiFace[nFaces]; - SetFace(faces[0], 0, 1, 2); - for (unsigned int i = 1; i < nFaces; ++i) { - SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], i + 2); - } - break; - } - } + if (prim.material) { + aim->mMaterialIndex = prim.material.GetIndex(); + } else { + aim->mMaterialIndex = mScene->mNumMaterials - 1; + } + } + } - if (faces) { - aim->mFaces = faces; - aim->mNumFaces = static_cast(nFaces); - ai_assert(CheckValidFacesIndices(faces, static_cast(nFaces), aim->mNumVertices)); - } + meshOffsets.push_back(k); - if (prim.material) { - aim->mMaterialIndex = prim.material.GetIndex(); - } - else { - aim->mMaterialIndex = mScene->mNumMaterials - 1; - } - - } - } - - meshOffsets.push_back(k); - - CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); + CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); } -void glTF2Importer::ImportCameras(glTF2::Asset& r) -{ - if (!r.cameras.Size()) return; +void glTF2Importer::ImportCameras(glTF2::Asset &r) { + if (!r.cameras.Size()) return; - mScene->mNumCameras = r.cameras.Size(); - mScene->mCameras = new aiCamera*[r.cameras.Size()]; + mScene->mNumCameras = r.cameras.Size(); + mScene->mCameras = new aiCamera *[r.cameras.Size()]; - for (size_t i = 0; i < r.cameras.Size(); ++i) { - Camera& cam = r.cameras[i]; + for (size_t i = 0; i < r.cameras.Size(); ++i) { + Camera &cam = r.cameras[i]; - aiCamera* aicam = mScene->mCameras[i] = new aiCamera(); + aiCamera *aicam = mScene->mCameras[i] = new aiCamera(); - // cameras point in -Z by default, rest is specified in node transform - aicam->mLookAt = aiVector3D(0.f,0.f,-1.f); + // cameras point in -Z by default, rest is specified in node transform + aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f); - if (cam.type == Camera::Perspective) { + if (cam.type == Camera::Perspective) { - aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; - aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); - aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; - aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; - } else { - aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar; - aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear; - aicam->mHorizontalFOV = 0.0; - aicam->mAspect = 1.0f; - if (0.f != cam.cameraProperties.ortographic.ymag ) { - aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag; - } - } - } + aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; + aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); + aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; + } else { + aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear; + aicam->mHorizontalFOV = 0.0; + aicam->mAspect = 1.0f; + if (0.f != cam.cameraProperties.ortographic.ymag) { + aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag; + } + } + } } -void glTF2Importer::ImportLights(glTF2::Asset& r) -{ - if (!r.lights.Size()) - return; +void glTF2Importer::ImportLights(glTF2::Asset &r) { + if (!r.lights.Size()) + return; - mScene->mNumLights = r.lights.Size(); - mScene->mLights = new aiLight*[r.lights.Size()]; + mScene->mNumLights = r.lights.Size(); + mScene->mLights = new aiLight *[r.lights.Size()]; - for (size_t i = 0; i < r.lights.Size(); ++i) { - Light& light = r.lights[i]; + for (size_t i = 0; i < r.lights.Size(); ++i) { + Light &light = r.lights[i]; - aiLight* ail = mScene->mLights[i] = new aiLight(); + aiLight *ail = mScene->mLights[i] = new aiLight(); - switch (light.type) - { - case Light::Directional: - ail->mType = aiLightSource_DIRECTIONAL; break; - case Light::Point: - ail->mType = aiLightSource_POINT; break; - case Light::Spot: - ail->mType = aiLightSource_SPOT; break; - } + switch (light.type) { + case Light::Directional: + ail->mType = aiLightSource_DIRECTIONAL; + break; + case Light::Point: + ail->mType = aiLightSource_POINT; + break; + case Light::Spot: + ail->mType = aiLightSource_SPOT; + break; + } - if (ail->mType != aiLightSource_POINT) - { - ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f); - ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f); - } + if (ail->mType != aiLightSource_POINT) { + ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f); + ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f); + } - vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity }; - CopyValue(colorWithIntensity, ail->mColorAmbient); - CopyValue(colorWithIntensity, ail->mColorDiffuse); - CopyValue(colorWithIntensity, ail->mColorSpecular); + vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity }; + CopyValue(colorWithIntensity, ail->mColorAmbient); + CopyValue(colorWithIntensity, ail->mColorDiffuse); + CopyValue(colorWithIntensity, ail->mColorSpecular); - if (ail->mType == aiLightSource_DIRECTIONAL) - { - ail->mAttenuationConstant = 1.0; - ail->mAttenuationLinear = 0.0; - ail->mAttenuationQuadratic = 0.0; - } - else - { - //in PBR attenuation is calculated using inverse square law which can be expressed - //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters - //this is correct equation for the case when range (see - //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual) - //is not present. When range is not present it is assumed that it is infinite and so numerator is 1. - //When range is present then numerator might be any value in range [0,1] and then assimps equation - //will not suffice. In this case range is added into metadata in ImportNode function - //and its up to implementation to read it when it wants to - ail->mAttenuationConstant = 0.0; - ail->mAttenuationLinear = 0.0; - ail->mAttenuationQuadratic = 1.0; - } + if (ail->mType == aiLightSource_DIRECTIONAL) { + ail->mAttenuationConstant = 1.0; + ail->mAttenuationLinear = 0.0; + ail->mAttenuationQuadratic = 0.0; + } else { + //in PBR attenuation is calculated using inverse square law which can be expressed + //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters + //this is correct equation for the case when range (see + //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual) + //is not present. When range is not present it is assumed that it is infinite and so numerator is 1. + //When range is present then numerator might be any value in range [0,1] and then assimps equation + //will not suffice. In this case range is added into metadata in ImportNode function + //and its up to implementation to read it when it wants to + ail->mAttenuationConstant = 0.0; + ail->mAttenuationLinear = 0.0; + ail->mAttenuationQuadratic = 1.0; + } - if (ail->mType == aiLightSource_SPOT) - { - ail->mAngleInnerCone = light.innerConeAngle; - ail->mAngleOuterCone = light.outerConeAngle; - } - } + if (ail->mType == aiLightSource_SPOT) { + ail->mAngleInnerCone = light.innerConeAngle; + ail->mAngleOuterCone = light.outerConeAngle; + } + } } -static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) { - if (node.matrix.isPresent) { - CopyValue(node.matrix.value, matrix); - } - else { - if (node.translation.isPresent) { - aiVector3D trans; - CopyValue(node.translation.value, trans); - aiMatrix4x4 t; - aiMatrix4x4::Translation(trans, t); - matrix = matrix * t; - } +static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) { + if (node.matrix.isPresent) { + CopyValue(node.matrix.value, matrix); + } else { + if (node.translation.isPresent) { + aiVector3D trans; + CopyValue(node.translation.value, trans); + aiMatrix4x4 t; + aiMatrix4x4::Translation(trans, t); + matrix = matrix * t; + } - if (node.rotation.isPresent) { - aiQuaternion rot; - CopyValue(node.rotation.value, rot); - matrix = matrix * aiMatrix4x4(rot.GetMatrix()); - } + if (node.rotation.isPresent) { + aiQuaternion rot; + CopyValue(node.rotation.value, rot); + matrix = matrix * aiMatrix4x4(rot.GetMatrix()); + } - if (node.scale.isPresent) { - aiVector3D scal(1.f); - CopyValue(node.scale.value, scal); - aiMatrix4x4 s; - aiMatrix4x4::Scaling(scal, s); - matrix = matrix * s; - } - } + if (node.scale.isPresent) { + aiVector3D scal(1.f); + CopyValue(node.scale.value, scal); + aiMatrix4x4 s; + aiMatrix4x4::Scaling(scal, s); + matrix = matrix * s; + } + } } -static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vector>& map) -{ - Mesh::Primitive::Attributes& attr = primitive.attributes; - if (attr.weight.empty() || attr.joint.empty()) { - return; - } - if (attr.weight[0]->count != attr.joint[0]->count) { - return; - } +static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector> &map) { + Mesh::Primitive::Attributes &attr = primitive.attributes; + if (attr.weight.empty() || attr.joint.empty()) { + return; + } + if (attr.weight[0]->count != attr.joint[0]->count) { + return; + } - size_t num_vertices = attr.weight[0]->count; + size_t num_vertices = attr.weight[0]->count; - struct Weights { float values[4]; }; - Weights* weights = nullptr; - attr.weight[0]->ExtractData(weights); + struct Weights { + float values[4]; + }; + Weights *weights = nullptr; + attr.weight[0]->ExtractData(weights); - struct Indices8 { uint8_t values[4]; }; - struct Indices16 { uint16_t values[4]; }; - Indices8* indices8 = nullptr; - Indices16* indices16 = nullptr; - if (attr.joint[0]->GetElementSize() == 4) { - attr.joint[0]->ExtractData(indices8); - }else { - attr.joint[0]->ExtractData(indices16); - } - // - if (nullptr == indices8 && nullptr == indices16) { - // Something went completely wrong! - ai_assert(false); - return; - } + struct Indices8 { + uint8_t values[4]; + }; + struct Indices16 { + uint16_t values[4]; + }; + Indices8 *indices8 = nullptr; + Indices16 *indices16 = nullptr; + if (attr.joint[0]->GetElementSize() == 4) { + attr.joint[0]->ExtractData(indices8); + } else { + attr.joint[0]->ExtractData(indices16); + } + // + if (nullptr == indices8 && nullptr == indices16) { + // Something went completely wrong! + ai_assert(false); + return; + } - for (size_t i = 0; i < num_vertices; ++i) { - for (int j = 0; j < 4; ++j) { - const unsigned int bone = (indices8!=nullptr) ? indices8[i].values[j] : indices16[i].values[j]; - const float weight = weights[i].values[j]; - if (weight > 0 && bone < map.size()) { - map[bone].reserve(8); - map[bone].emplace_back(static_cast(i), weight); - } - } - } + for (size_t i = 0; i < num_vertices; ++i) { + for (int j = 0; j < 4; ++j) { + const unsigned int bone = (indices8 != nullptr) ? indices8[i].values[j] : indices16[i].values[j]; + const float weight = weights[i].values[j]; + if (weight > 0 && bone < map.size()) { + map[bone].reserve(8); + map[bone].emplace_back(static_cast(i), weight); + } + } + } - delete[] weights; - delete[] indices8; - delete[] indices16; + delete[] weights; + delete[] indices8; + delete[] indices16; } -static std::string GetNodeName(const Node& node) -{ - return node.name.empty() ? node.id : node.name; +static std::string GetNodeName(const Node &node) { + return node.name.empty() ? node.id : node.name; } -aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& meshOffsets, glTF2::Ref& ptr) -{ - Node& node = *ptr; +aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector &meshOffsets, glTF2::Ref &ptr) { + Node &node = *ptr; - aiNode* ainode = new aiNode(GetNodeName(node)); + aiNode *ainode = new aiNode(GetNodeName(node)); - if (!node.children.empty()) { - ainode->mNumChildren = unsigned(node.children.size()); - ainode->mChildren = new aiNode*[ainode->mNumChildren]; + if (!node.children.empty()) { + ainode->mNumChildren = unsigned(node.children.size()); + ainode->mChildren = new aiNode *[ainode->mNumChildren]; - for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { - aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]); - child->mParent = ainode; - ainode->mChildren[i] = child; - } - } + for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { + aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); + child->mParent = ainode; + ainode->mChildren[i] = child; + } + } - GetNodeTransform(ainode->mTransformation, node); + GetNodeTransform(ainode->mTransformation, node); - if (!node.meshes.empty()) { - // GLTF files contain at most 1 mesh per node. - assert(node.meshes.size() == 1); - int mesh_idx = node.meshes[0].GetIndex(); - int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; + if (!node.meshes.empty()) { + // GLTF files contain at most 1 mesh per node. + assert(node.meshes.size() == 1); + int mesh_idx = node.meshes[0].GetIndex(); + int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; - ainode->mNumMeshes = count; - ainode->mMeshes = new unsigned int[count]; + ainode->mNumMeshes = count; + ainode->mMeshes = new unsigned int[count]; - if (node.skin) { - for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { - aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]+primitiveNo]; - mesh->mNumBones = static_cast(node.skin->jointNames.size()); - mesh->mBones = new aiBone*[mesh->mNumBones]; + if (node.skin) { + for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { + aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; + mesh->mNumBones = static_cast(node.skin->jointNames.size()); + mesh->mBones = new aiBone *[mesh->mNumBones]; - // GLTF and Assimp choose to store bone weights differently. - // GLTF has each vertex specify which bones influence the vertex. - // Assimp has each bone specify which vertices it has influence over. - // To convert this data, we first read over the vertex data and pull - // out the bone-to-vertex mapping. Then, when creating the aiBones, - // we copy the bone-to-vertex mapping into the bone. This is unfortunate - // both because it's somewhat slow and because, for many applications, - // we then need to reconvert the data back into the vertex-to-bone - // mapping which makes things doubly-slow. - std::vector> weighting(mesh->mNumBones); - BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); + // GLTF and Assimp choose to store bone weights differently. + // GLTF has each vertex specify which bones influence the vertex. + // Assimp has each bone specify which vertices it has influence over. + // To convert this data, we first read over the vertex data and pull + // out the bone-to-vertex mapping. Then, when creating the aiBones, + // we copy the bone-to-vertex mapping into the bone. This is unfortunate + // both because it's somewhat slow and because, for many applications, + // we then need to reconvert the data back into the vertex-to-bone + // mapping which makes things doubly-slow. + std::vector> weighting(mesh->mNumBones); + BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); - mat4* pbindMatrices = nullptr; - node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + mat4 *pbindMatrices = nullptr; + node.skin->inverseBindMatrices->ExtractData(pbindMatrices); - for (uint32_t i = 0; i < mesh->mNumBones; ++i) { - aiBone* bone = new aiBone(); + for (uint32_t i = 0; i < mesh->mNumBones; ++i) { + aiBone *bone = new aiBone(); - Ref joint = node.skin->jointNames[i]; - if (!joint->name.empty()) { - bone->mName = joint->name; - } else { - // Assimp expects each bone to have a unique name. - static const std::string kDefaultName = "bone_"; - char postfix[10] = {0}; - ASSIMP_itoa10(postfix, i); - bone->mName = (kDefaultName + postfix); - } - GetNodeTransform(bone->mOffsetMatrix, *joint); + Ref joint = node.skin->jointNames[i]; + if (!joint->name.empty()) { + bone->mName = joint->name; + } else { + // Assimp expects each bone to have a unique name. + static const std::string kDefaultName = "bone_"; + char postfix[10] = { 0 }; + ASSIMP_itoa10(postfix, i); + bone->mName = (kDefaultName + postfix); + } + GetNodeTransform(bone->mOffsetMatrix, *joint); - CopyValue(pbindMatrices[i], bone->mOffsetMatrix); + CopyValue(pbindMatrices[i], bone->mOffsetMatrix); - std::vector& weights = weighting[i]; + std::vector &weights = weighting[i]; - bone->mNumWeights = static_cast(weights.size()); - if (bone->mNumWeights > 0) { - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); - } else { - // Assimp expects all bones to have at least 1 weight. - bone->mWeights = new aiVertexWeight[1]; - bone->mNumWeights = 1; - bone->mWeights->mVertexId = 0; - bone->mWeights->mWeight = 0.f; - } - mesh->mBones[i] = bone; - } + bone->mNumWeights = static_cast(weights.size()); + if (bone->mNumWeights > 0) { + bone->mWeights = new aiVertexWeight[bone->mNumWeights]; + memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + } else { + // Assimp expects all bones to have at least 1 weight. + bone->mWeights = new aiVertexWeight[1]; + bone->mNumWeights = 1; + bone->mWeights->mVertexId = 0; + bone->mWeights->mWeight = 0.f; + } + mesh->mBones[i] = bone; + } - if (pbindMatrices) { - delete[] pbindMatrices; - } - } - } + if (pbindMatrices) { + delete[] pbindMatrices; + } + } + } - int k = 0; - for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) { - ainode->mMeshes[k] = j; - } - } + int k = 0; + for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) { + ainode->mMeshes[k] = j; + } + } - if (node.camera) { - pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; - } + if (node.camera) { + pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; + } - if (node.light) { - pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; + if (node.light) { + pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; - //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual - //it is added to meta data of parent node, because there is no other place to put it - if (node.light->range.isPresent) - { - ainode->mMetaData = aiMetadata::Alloc(1); - ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); - } - } + //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual + //it is added to meta data of parent node, because there is no other place to put it + if (node.light->range.isPresent) { + ainode->mMetaData = aiMetadata::Alloc(1); + ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); + } + } - return ainode; + return ainode; } -void glTF2Importer::ImportNodes(glTF2::Asset& r) -{ - if (!r.scene) return; +void glTF2Importer::ImportNodes(glTF2::Asset &r) { + if (!r.scene) return; - std::vector< Ref > rootNodes = r.scene->nodes; + std::vector> rootNodes = r.scene->nodes; - // The root nodes - unsigned int numRootNodes = unsigned(rootNodes.size()); - if (numRootNodes == 1) { // a single root node: use it - mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); - } - else if (numRootNodes > 1) { // more than one root node: create a fake root - aiNode* root = new aiNode("ROOT"); - root->mChildren = new aiNode*[numRootNodes]; - for (unsigned int i = 0; i < numRootNodes; ++i) { - aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); - node->mParent = root; - root->mChildren[root->mNumChildren++] = node; - } - mScene->mRootNode = root; - } - - //if (!mScene->mRootNode) { - // mScene->mRootNode = new aiNode("EMPTY"); - //} + // The root nodes + unsigned int numRootNodes = unsigned(rootNodes.size()); + if (numRootNodes == 1) { // a single root node: use it + mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); + } else if (numRootNodes > 1) { // more than one root node: create a fake root + aiNode *root = new aiNode("ROOT"); + root->mChildren = new aiNode *[numRootNodes]; + for (unsigned int i = 0; i < numRootNodes; ++i) { + aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); + node->mParent = root; + root->mChildren[root->mNumChildren++] = node; + } + mScene->mRootNode = root; + } } struct AnimationSamplers { - AnimationSamplers() - : translation(nullptr) - , rotation(nullptr) - , scale(nullptr) - , weight(nullptr) { - // empty - } + AnimationSamplers() : + translation(nullptr), + rotation(nullptr), + scale(nullptr), + weight(nullptr) { + // empty + } - Animation::Sampler* translation; - Animation::Sampler* rotation; - Animation::Sampler* scale; - Animation::Sampler* weight; + Animation::Sampler *translation; + Animation::Sampler *rotation; + Animation::Sampler *scale; + Animation::Sampler *weight; }; -aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) -{ - aiNodeAnim* anim = new aiNodeAnim(); - anim->mNodeName = GetNodeName(node); +aiNodeAnim *CreateNodeAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) { + aiNodeAnim *anim = new aiNodeAnim(); + anim->mNodeName = GetNodeName(node); - static const float kMillisecondsFromSeconds = 1000.f; + static const float kMillisecondsFromSeconds = 1000.f; - if (samplers.translation) { - float* times = nullptr; - samplers.translation->input->ExtractData(times); - aiVector3D* values = nullptr; - samplers.translation->output->ExtractData(values); - anim->mNumPositionKeys = static_cast(samplers.translation->input->count); - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; - for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { - anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mPositionKeys[i].mValue = values[i]; - } - delete[] times; - delete[] values; - } else if (node.translation.isPresent) { - anim->mNumPositionKeys = 1; - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; - anim->mPositionKeys->mTime = 0.f; - anim->mPositionKeys->mValue.x = node.translation.value[0]; - anim->mPositionKeys->mValue.y = node.translation.value[1]; - anim->mPositionKeys->mValue.z = node.translation.value[2]; - } + if (samplers.translation) { + float *times = nullptr; + samplers.translation->input->ExtractData(times); + aiVector3D *values = nullptr; + samplers.translation->output->ExtractData(values); + anim->mNumPositionKeys = static_cast(samplers.translation->input->count); + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; + for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { + anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mPositionKeys[i].mValue = values[i]; + } + delete[] times; + delete[] values; + } else if (node.translation.isPresent) { + anim->mNumPositionKeys = 1; + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; + anim->mPositionKeys->mTime = 0.f; + anim->mPositionKeys->mValue.x = node.translation.value[0]; + anim->mPositionKeys->mValue.y = node.translation.value[1]; + anim->mPositionKeys->mValue.z = node.translation.value[2]; + } - if (samplers.rotation) { - float* times = nullptr; - samplers.rotation->input->ExtractData(times); - aiQuaternion* values = nullptr; - samplers.rotation->output->ExtractData(values); - anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; - for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { - anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mRotationKeys[i].mValue.x = values[i].w; - anim->mRotationKeys[i].mValue.y = values[i].x; - anim->mRotationKeys[i].mValue.z = values[i].y; - anim->mRotationKeys[i].mValue.w = values[i].z; - } - delete[] times; - delete[] values; - } else if (node.rotation.isPresent) { - anim->mNumRotationKeys = 1; - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; - anim->mRotationKeys->mTime = 0.f; - anim->mRotationKeys->mValue.x = node.rotation.value[0]; - anim->mRotationKeys->mValue.y = node.rotation.value[1]; - anim->mRotationKeys->mValue.z = node.rotation.value[2]; - anim->mRotationKeys->mValue.w = node.rotation.value[3]; - } + if (samplers.rotation) { + float *times = nullptr; + samplers.rotation->input->ExtractData(times); + aiQuaternion *values = nullptr; + samplers.rotation->output->ExtractData(values); + anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; + for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { + anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mRotationKeys[i].mValue.x = values[i].w; + anim->mRotationKeys[i].mValue.y = values[i].x; + anim->mRotationKeys[i].mValue.z = values[i].y; + anim->mRotationKeys[i].mValue.w = values[i].z; + } + delete[] times; + delete[] values; + } else if (node.rotation.isPresent) { + anim->mNumRotationKeys = 1; + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; + anim->mRotationKeys->mTime = 0.f; + anim->mRotationKeys->mValue.x = node.rotation.value[0]; + anim->mRotationKeys->mValue.y = node.rotation.value[1]; + anim->mRotationKeys->mValue.z = node.rotation.value[2]; + anim->mRotationKeys->mValue.w = node.rotation.value[3]; + } - if (samplers.scale) { - float* times = nullptr; - samplers.scale->input->ExtractData(times); - aiVector3D* values = nullptr; - samplers.scale->output->ExtractData(values); - anim->mNumScalingKeys = static_cast(samplers.scale->input->count); - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; - for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { - anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mScalingKeys[i].mValue = values[i]; - } - delete[] times; - delete[] values; - } else if (node.scale.isPresent) { - anim->mNumScalingKeys = 1; - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; - anim->mScalingKeys->mTime = 0.f; - anim->mScalingKeys->mValue.x = node.scale.value[0]; - anim->mScalingKeys->mValue.y = node.scale.value[1]; - anim->mScalingKeys->mValue.z = node.scale.value[2]; - } + if (samplers.scale) { + float *times = nullptr; + samplers.scale->input->ExtractData(times); + aiVector3D *values = nullptr; + samplers.scale->output->ExtractData(values); + anim->mNumScalingKeys = static_cast(samplers.scale->input->count); + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; + for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { + anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mScalingKeys[i].mValue = values[i]; + } + delete[] times; + delete[] values; + } else if (node.scale.isPresent) { + anim->mNumScalingKeys = 1; + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; + anim->mScalingKeys->mTime = 0.f; + anim->mScalingKeys->mValue.x = node.scale.value[0]; + anim->mScalingKeys->mValue.y = node.scale.value[1]; + anim->mScalingKeys->mValue.z = node.scale.value[2]; + } - return anim; + return anim; } -aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) -{ - aiMeshMorphAnim* anim = new aiMeshMorphAnim(); - anim->mName = GetNodeName(node); +aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) { + aiMeshMorphAnim *anim = new aiMeshMorphAnim(); + anim->mName = GetNodeName(node); - static const float kMillisecondsFromSeconds = 1000.f; + static const float kMillisecondsFromSeconds = 1000.f; - if (nullptr != samplers.weight) { - float* times = nullptr; - samplers.weight->input->ExtractData(times); - float* values = nullptr; - samplers.weight->output->ExtractData(values); - anim->mNumKeys = static_cast(samplers.weight->input->count); + if (nullptr != samplers.weight) { + float *times = nullptr; + samplers.weight->input->ExtractData(times); + float *values = nullptr; + samplers.weight->output->ExtractData(values); + anim->mNumKeys = static_cast(samplers.weight->input->count); - const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys; + const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys; - anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; - unsigned int k = 0u; - for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { - anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mKeys[i].mNumValuesAndWeights = numMorphs; - anim->mKeys[i].mValues = new unsigned int[numMorphs]; - anim->mKeys[i].mWeights = new double[numMorphs]; + anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; + unsigned int k = 0u; + for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { + anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mKeys[i].mNumValuesAndWeights = numMorphs; + anim->mKeys[i].mValues = new unsigned int[numMorphs]; + anim->mKeys[i].mWeights = new double[numMorphs]; - for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { - anim->mKeys[i].mValues[j] = j; - anim->mKeys[i].mWeights[j] = ( 0.f > values[k] ) ? 0.f : values[k]; - } - } + for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { + anim->mKeys[i].mValues[j] = j; + anim->mKeys[i].mWeights[j] = (0.f > values[k]) ? 0.f : values[k]; + } + } - delete[] times; - delete[] values; - } + delete[] times; + delete[] values; + } - return anim; + return anim; } -std::unordered_map GatherSamplers(Animation& anim) -{ - std::unordered_map samplers; - for (unsigned int c = 0; c < anim.channels.size(); ++c) { - Animation::Channel& channel = anim.channels[c]; - if (channel.sampler >= static_cast(anim.samplers.size())) { - continue; - } +std::unordered_map GatherSamplers(Animation &anim) { + std::unordered_map samplers; + for (unsigned int c = 0; c < anim.channels.size(); ++c) { + Animation::Channel &channel = anim.channels[c]; + if (channel.sampler >= static_cast(anim.samplers.size())) { + continue; + } - const unsigned int node_index = channel.target.node.GetIndex(); + const unsigned int node_index = channel.target.node.GetIndex(); - AnimationSamplers& sampler = samplers[node_index]; - if (channel.target.path == AnimationPath_TRANSLATION) { - sampler.translation = &anim.samplers[channel.sampler]; - } else if (channel.target.path == AnimationPath_ROTATION) { - sampler.rotation = &anim.samplers[channel.sampler]; - } else if (channel.target.path == AnimationPath_SCALE) { - sampler.scale = &anim.samplers[channel.sampler]; - } else if (channel.target.path == AnimationPath_WEIGHTS) { - sampler.weight = &anim.samplers[channel.sampler]; - } - } + AnimationSamplers &sampler = samplers[node_index]; + if (channel.target.path == AnimationPath_TRANSLATION) { + sampler.translation = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_ROTATION) { + sampler.rotation = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_SCALE) { + sampler.scale = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_WEIGHTS) { + sampler.weight = &anim.samplers[channel.sampler]; + } + } - return samplers; + return samplers; } -void glTF2Importer::ImportAnimations(glTF2::Asset& r) -{ - if (!r.scene) return; +void glTF2Importer::ImportAnimations(glTF2::Asset &r) { + if (!r.scene) return; - mScene->mNumAnimations = r.animations.Size(); - if (mScene->mNumAnimations == 0) { - return; - } + mScene->mNumAnimations = r.animations.Size(); + if (mScene->mNumAnimations == 0) { + return; + } - mScene->mAnimations = new aiAnimation*[mScene->mNumAnimations]; - for (unsigned int i = 0; i < r.animations.Size(); ++i) { - Animation& anim = r.animations[i]; + mScene->mAnimations = new aiAnimation *[mScene->mNumAnimations]; + for (unsigned int i = 0; i < r.animations.Size(); ++i) { + Animation &anim = r.animations[i]; - aiAnimation* ai_anim = new aiAnimation(); - ai_anim->mName = anim.name; - ai_anim->mDuration = 0; - ai_anim->mTicksPerSecond = 0; + aiAnimation *ai_anim = new aiAnimation(); + ai_anim->mName = anim.name; + ai_anim->mDuration = 0; + ai_anim->mTicksPerSecond = 0; - std::unordered_map samplers = GatherSamplers(anim); + std::unordered_map samplers = GatherSamplers(anim); - uint32_t numChannels = 0u; - uint32_t numMorphMeshChannels = 0u; + uint32_t numChannels = 0u; + uint32_t numMorphMeshChannels = 0u; - for (auto& iter : samplers) { - if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { - ++numChannels; - } - if (nullptr != iter.second.weight) { - ++numMorphMeshChannels; - } - } + for (auto &iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ++numChannels; + } + if (nullptr != iter.second.weight) { + ++numMorphMeshChannels; + } + } - ai_anim->mNumChannels = numChannels; - if (ai_anim->mNumChannels > 0) { - ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels]; - int j = 0; - for (auto& iter : samplers) { - if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { - ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); - ++j; - } - } - } + ai_anim->mNumChannels = numChannels; + if (ai_anim->mNumChannels > 0) { + ai_anim->mChannels = new aiNodeAnim *[ai_anim->mNumChannels]; + int j = 0; + for (auto &iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); + ++j; + } + } + } - ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; - if (ai_anim->mNumMorphMeshChannels > 0) { - ai_anim->mMorphMeshChannels = new aiMeshMorphAnim*[ai_anim->mNumMorphMeshChannels]; - int j = 0; - for (auto& iter : samplers) { - if (nullptr != iter.second.weight) { - ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second); - ++j; - } - } - } + ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; + if (ai_anim->mNumMorphMeshChannels > 0) { + ai_anim->mMorphMeshChannels = new aiMeshMorphAnim *[ai_anim->mNumMorphMeshChannels]; + int j = 0; + for (auto &iter : samplers) { + if (nullptr != iter.second.weight) { + ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second); + ++j; + } + } + } - // Use the latest keyframe for the duration of the animation - double maxDuration = 0; - unsigned int maxNumberOfKeys = 0; - for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) { - auto chan = ai_anim->mChannels[j]; - if (chan->mNumPositionKeys) { - auto lastPosKey = chan->mPositionKeys[chan->mNumPositionKeys - 1]; - if (lastPosKey.mTime > maxDuration) { - maxDuration = lastPosKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys); - } - if (chan->mNumRotationKeys) { - auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1]; - if (lastRotKey.mTime > maxDuration) { - maxDuration = lastRotKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys); - } - if (chan->mNumScalingKeys) { - auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1]; - if (lastScaleKey.mTime > maxDuration) { - maxDuration = lastScaleKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys); - } - } + // Use the latest keyframe for the duration of the animation + double maxDuration = 0; + unsigned int maxNumberOfKeys = 0; + for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) { + auto chan = ai_anim->mChannels[j]; + if (chan->mNumPositionKeys) { + auto lastPosKey = chan->mPositionKeys[chan->mNumPositionKeys - 1]; + if (lastPosKey.mTime > maxDuration) { + maxDuration = lastPosKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys); + } + if (chan->mNumRotationKeys) { + auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1]; + if (lastRotKey.mTime > maxDuration) { + maxDuration = lastRotKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys); + } + if (chan->mNumScalingKeys) { + auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1]; + if (lastScaleKey.mTime > maxDuration) { + maxDuration = lastScaleKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys); + } + } - for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) { - const auto* const chan = ai_anim->mMorphMeshChannels[j]; + for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) { + const auto *const chan = ai_anim->mMorphMeshChannels[j]; - if (0u != chan->mNumKeys) { - const auto& lastKey = chan->mKeys[chan->mNumKeys - 1u]; - if (lastKey.mTime > maxDuration) { - maxDuration = lastKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys); - } - } + if (0u != chan->mNumKeys) { + const auto &lastKey = chan->mKeys[chan->mNumKeys - 1u]; + if (lastKey.mTime > maxDuration) { + maxDuration = lastKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys); + } + } - ai_anim->mDuration = maxDuration; - ai_anim->mTicksPerSecond = 1000.0; + ai_anim->mDuration = maxDuration; + ai_anim->mTicksPerSecond = 1000.0; - mScene->mAnimations[i] = ai_anim; - } + mScene->mAnimations[i] = ai_anim; + } } -void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset& r) -{ - embeddedTexIdxs.resize(r.images.Size(), -1); +void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { + embeddedTexIdxs.resize(r.images.Size(), -1); - int numEmbeddedTexs = 0; - for (size_t i = 0; i < r.images.Size(); ++i) { - if (r.images[i].HasData()) - numEmbeddedTexs += 1; - } + int numEmbeddedTexs = 0; + for (size_t i = 0; i < r.images.Size(); ++i) { + if (r.images[i].HasData()) + numEmbeddedTexs += 1; + } - if (numEmbeddedTexs == 0) - return; + if (numEmbeddedTexs == 0) + return; - mScene->mTextures = new aiTexture*[numEmbeddedTexs]; + mScene->mTextures = new aiTexture *[numEmbeddedTexs]; - // Add the embedded textures - for (size_t i = 0; i < r.images.Size(); ++i) { - Image &img = r.images[i]; - if (!img.HasData()) continue; + // Add the embedded textures + for (size_t i = 0; i < r.images.Size(); ++i) { + Image &img = r.images[i]; + if (!img.HasData()) continue; - int idx = mScene->mNumTextures++; - embeddedTexIdxs[i] = idx; + int idx = mScene->mNumTextures++; + embeddedTexIdxs[i] = idx; - aiTexture* tex = mScene->mTextures[idx] = new aiTexture(); + aiTexture *tex = mScene->mTextures[idx] = new aiTexture(); - size_t length = img.GetDataLength(); - void* data = img.StealData(); + size_t length = img.GetDataLength(); + void *data = img.StealData(); - tex->mWidth = static_cast(length); - tex->mHeight = 0; - tex->pcData = reinterpret_cast(data); + tex->mWidth = static_cast(length); + tex->mHeight = 0; + tex->pcData = reinterpret_cast(data); - if (!img.mimeType.empty()) { - const char* ext = strchr(img.mimeType.c_str(), '/') + 1; - if (ext) { - if (strcmp(ext, "jpeg") == 0) ext = "jpg"; + if (!img.mimeType.empty()) { + const char *ext = strchr(img.mimeType.c_str(), '/') + 1; + if (ext) { + if (strcmp(ext, "jpeg") == 0) ext = "jpg"; - size_t len = strlen(ext); - if (len <= 3) { - strcpy(tex->achFormatHint, ext); - } - } - } - } + size_t len = strlen(ext); + if (len <= 3) { + strcpy(tex->achFormatHint, ext); + } + } + } + } } -void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) -{ - // clean all member arrays - meshOffsets.clear(); - embeddedTexIdxs.clear(); +void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + // clean all member arrays + meshOffsets.clear(); + embeddedTexIdxs.clear(); - this->mScene = pScene; + this->mScene = pScene; - // read the asset file - glTF2::Asset asset(pIOHandler); - asset.Load(pFile, GetExtension(pFile) == "glb"); + // read the asset file + glTF2::Asset asset(pIOHandler); + asset.Load(pFile, GetExtension(pFile) == "glb"); - // - // Copy the data out - // + // + // Copy the data out + // - ImportEmbeddedTextures(asset); - ImportMaterials(asset); + ImportEmbeddedTextures(asset); + ImportMaterials(asset); - ImportMeshes(asset); + ImportMeshes(asset); - ImportCameras(asset); - ImportLights(asset); + ImportCameras(asset); + ImportLights(asset); - ImportNodes(asset); + ImportNodes(asset); - ImportAnimations(asset); + ImportAnimations(asset); - if (pScene->mNumMeshes == 0) { - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } + if (pScene->mNumMeshes == 0) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } } #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER - From 17257cd2aeed5de4b86b95fc258f79436a860ff2 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 16 Nov 2019 15:51:26 +0100 Subject: [PATCH 10/12] just a try, i dunno have a clue ... --- code/Common/DefaultLogger.cpp | 4 ++-- code/Material/MaterialSystem.cpp | 6 +++--- code/PostProcessing/ValidateDataStructure.cpp | 11 +++++++---- code/glTF2/glTF2Importer.cpp | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/code/Common/DefaultLogger.cpp b/code/Common/DefaultLogger.cpp index de3528d2b..eee53bd7c 100644 --- a/code/Common/DefaultLogger.cpp +++ b/code/Common/DefaultLogger.cpp @@ -107,7 +107,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, return nullptr; #endif - // Platform-independent default streams + // Platform-independent default streams case aiDefaultLogStream_STDERR: return new StdOStreamLogStream(std::cerr); case aiDefaultLogStream_STDOUT: @@ -121,7 +121,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, }; // For compilers without dead code path detection - return NULL; + return nullptr; } // ---------------------------------------------------------------------------------- diff --git a/code/Material/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp index 0be6e9f7b..fabd9415a 100644 --- a/code/Material/MaterialSystem.cpp +++ b/code/Material/MaterialSystem.cpp @@ -471,12 +471,12 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput, aiPropertyTypeInfo pType ) { - ai_assert( pInput != NULL ); - ai_assert( pKey != NULL ); + ai_assert( pInput != nullptr ); + ai_assert(pKey != nullptr ); ai_assert( 0 != pSizeInBytes ); if ( 0 == pSizeInBytes ) { - + return AI_FAILURE; } // first search the list whether there is already an entry with this key diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index 75d1b6ef7..b7f56a582 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -603,15 +603,18 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, ReportError("%s #%i is set, but there are only %i %s textures", szType,iIndex,iNumIndices,szType); } - if (!iNumIndices)return; + if (!iNumIndices) { + return; + } std::vector mappings(iNumIndices); // Now check whether all UV indices are valid ... bool bNoSpecified = true; - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) - { + for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) { aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (prop->mSemantic != type)continue; + if (prop->mSemantic != type) { + continue; + } if ((int)prop->mIndex >= iNumIndices) { diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 3dffa4b27..584a2717f 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -200,6 +200,9 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); } + mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); + mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); + if (prop.textureTransformSupported) { aiUVTransform transform; transform.mTranslation.x = prop.TextureTransformExt_t.offset[0]; @@ -210,9 +213,6 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); } - mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); - mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); - if (prop.texture->sampler) { Ref sampler = prop.texture->sampler; From 75204e20bdc9a2a71cc1c183d14c549576e3d1f4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 16 Nov 2019 19:22:37 +0100 Subject: [PATCH 11/12] fix invalid setup for texture enum. --- code/glTF2/glTF2Importer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 584a2717f..43eabdab7 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -201,7 +201,6 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset } mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); - mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); if (prop.textureTransformSupported) { aiUVTransform transform; From 7e222f0730253b93f2348cd6874d62478668f54f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 18 Nov 2019 18:43:28 +0100 Subject: [PATCH 12/12] fix invalid cast. --- code/PostProcessing/ValidateDataStructure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index b7f56a582..1dc217663 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -637,7 +637,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, ReportError("Material property %s%i is expected to be 5 floats large (size is %i)", prop->mKey.data,prop->mIndex, prop->mDataLength); } - mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); + //mappings[prop->mIndex] = ((aiUVTransform*)prop->mData); } else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) { if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)