소스 검색

Merge branch 'fix_memory_leak_in_gltf2_on_exception' of https://github.com/muxanickms/assimp into fix_memory_leak_in_gltf2_on_exception

Mike Samsonov 5 년 전
부모
커밋
375ee17339

+ 2 - 2
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;
 }
 
 // ----------------------------------------------------------------------------------

+ 3 - 3
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

+ 8 - 5
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<aiTextureMapping> 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)
         {
@@ -634,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)

+ 0 - 3
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);
 

+ 7 - 10
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<true>::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;
 
 }
 

+ 8 - 1
code/glTF2/glTF2Asset.h

@@ -685,6 +685,13 @@ namespace glTF2
         Ref<Texture> texture;
         unsigned int index;
         unsigned int texCoord = 0;
+
+        bool textureTransformSupported = false;
+        struct TextureTransformExt {
+			float offset[2];
+			float rotation;
+			float scale[2];
+		} TextureTransformExt_t;
     };
 
     struct NormalTextureInfo : TextureInfo
@@ -1024,7 +1031,7 @@ namespace glTF2
             bool KHR_materials_pbrSpecularGlossiness;
             bool KHR_materials_unlit;
             bool KHR_lights_punctual;
-
+			bool KHR_texture_transform;
         } extensionsUsed;
 
         AssetMetadata asset;

+ 32 - 5
code/glTF2/glTF2Asset.inl

@@ -801,8 +801,34 @@ 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")) {
+				out.textureTransformSupported = true;
+                if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) {
+					if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
+						out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
+						out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
+					} else {
+						out.TextureTransformExt_t.offset[0] = 0;
+						out.TextureTransformExt_t.offset[1] = 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.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
+						out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
+					} else {
+						out.TextureTransformExt_t.scale[0] = 1;
+						out.TextureTransformExt_t.scale[1] = 1;
+                    }
+				}
+			}
+        }
+
         if (Value* index = FindUInt(*prop, "index")) {
             out.texture = r.textures.Retrieve(index->GetUint());
         }
@@ -878,6 +904,9 @@ inline void Material::Read(Value& material, Asset& r)
             }
         }
 
+        if (r.extensionsUsed.KHR_texture_transform) {
+		}
+
         unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
     }
 }
@@ -1464,12 +1493,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
 }

+ 1 - 0
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];
 }

+ 1101 - 1136
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 <assimp/CreateAnimMesh.h>
 #include <assimp/StringComparison.h>
 #include <assimp/StringUtils.h>
-#include <assimp/Importer.hpp>
-#include <assimp/scene.h>
 #include <assimp/ai_assert.h>
-#include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
-#include <assimp/CreateAnimMesh.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/Importer.hpp>
 
 #include <memory>
 #include <unordered_map>
@@ -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;
-
-        case SamplerWrap::Clamp_To_Edge:
-            return aiTextureMapMode_Clamp;
-
-        case SamplerWrap::UNSET:
-        case SamplerWrap::Repeat:
-        default:
-            return aiTextureMapMode_Wrap;
-    }
+static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
+	switch (gltfWrapMode) {
+		case SamplerWrap::Mirrored_Repeat:
+			return aiTextureMapMode_Mirror;
+
+		case SamplerWrap::Clamp_To_Edge:
+			return aiTextureMapMode_Clamp;
+
+		case SamplerWrap::UNSET:
+		case SamplerWrap::Repeat:
+		default:
+			return aiTextureMapMode_Wrap;
+	}
 }
 
 /*static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
@@ -180,1182 +177,1150 @@ 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<int>& 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<int> &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);
+		}
 
         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> sampler = prop.texture->sampler;
-
-            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));
-
-            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->minFilter != SamplerMinFilter::UNSET) {
-                mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(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);
+		}
+
+		if (prop.texture->sampler) {
+			Ref<Sampler> sampler = prop.texture->sampler;
+
+			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));
+
+			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->minFilter != SamplerMinFilter::UNSET) {
+				mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot));
+			}
+		}
+	}
 }
 
-inline void SetMaterialTextureProperty(std::vector<int>& 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<int> &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<int>& 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<int> &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<int>& embeddedTexIdxs, Asset& r, Material& mat)
-{
-    aiMaterial* aimat = new aiMaterial();
+static aiMaterial *ImportMaterial(std::vector<int> &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<aiMesh*> meshes;
-
-    unsigned int k = 0;
-
-    for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
-        Mesh& mesh = r.meshes[m];
-
-        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];
-
-            aiMesh* aim = new aiMesh();
-            meshes.push_back(aim);
-
-            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);
-            }
-
-            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_TRIANGLES:
-                case PrimitiveMode_TRIANGLE_STRIP:
-                case PrimitiveMode_TRIANGLE_FAN:
-                    aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
-                    break;
-
-            }
-
-            Mesh::Primitive::Attributes& attr = prim.attributes;
-
-            if (attr.position.size() > 0 && attr.position[0]) {
-                aim->mNumVertices = static_cast<unsigned int>(attr.position[0]->count);
-                attr.position[0]->ExtractData(aim->mVertices);
-            }
-
-            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;
-
-                    attr.tangent[0]->ExtractData(tangents);
-
-                    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;
-                    }
-
-                    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;
-                }
-
-                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
-                }
-            }
-
-            std::vector<Mesh::Primitive::Target>& 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);
-
-                        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];
-                    }
-                }
-            }
-
-
-            aiFace* faces = 0;
-            size_t nFaces = 0;
-
-            if (prim.indices) {
-                size_t count = prim.indices->count;
-
-                Accessor::Indexer data = prim.indices->GetIndexer();
-                ai_assert(data.IsValid());
-
-                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_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_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_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
-
-                // use the already determined count as it includes checks
-                unsigned int count = aim->mNumVertices;
-
-                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_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], i, i + 1);
-                    }
-                    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_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], 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 (faces) {
-                aim->mFaces = faces;
-                aim->mNumFaces = static_cast<unsigned int>(nFaces);
-                ai_assert(CheckValidFacesIndices(faces, static_cast<unsigned>(nFaces), aim->mNumVertices));
-            }
-
-            if (prim.material) {
-                aim->mMaterialIndex = prim.material.GetIndex();
-            }
-            else {
-                aim->mMaterialIndex = mScene->mNumMaterials - 1;
-            }
-
-        }
-    }
-
-    meshOffsets.push_back(k);
-
-    CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
+void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
+	std::vector<aiMesh *> meshes;
+
+	unsigned int k = 0;
+
+	for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
+		Mesh &mesh = r.meshes[m];
+
+		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];
+
+			aiMesh *aim = new aiMesh();
+			meshes.push_back(aim);
+
+			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);
+			}
+
+			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_TRIANGLES:
+				case PrimitiveMode_TRIANGLE_STRIP:
+				case PrimitiveMode_TRIANGLE_FAN:
+					aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+					break;
+			}
+
+			Mesh::Primitive::Attributes &attr = prim.attributes;
+
+			if (attr.position.size() > 0 && attr.position[0]) {
+				aim->mNumVertices = static_cast<unsigned int>(attr.position[0]->count);
+				attr.position[0]->ExtractData(aim->mVertices);
+			}
+
+			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;
+
+					attr.tangent[0]->ExtractData(tangents);
+
+					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;
+					}
+
+					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;
+				}
+
+				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
+				}
+			}
+
+			std::vector<Mesh::Primitive::Target> &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);
+
+						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];
+					}
+				}
+			}
+
+			aiFace *faces = 0;
+			size_t nFaces = 0;
+
+			if (prim.indices) {
+				size_t count = prim.indices->count;
+
+				Accessor::Indexer data = prim.indices->GetIndexer();
+				ai_assert(data.IsValid());
+
+				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_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_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_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
+
+				// use the already determined count as it includes checks
+				unsigned int count = aim->mNumVertices;
+
+				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_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_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_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 (faces) {
+				aim->mFaces = faces;
+				aim->mNumFaces = static_cast<unsigned int>(nFaces);
+				ai_assert(CheckValidFacesIndices(faces, static_cast<unsigned>(nFaces), aim->mNumVertices));
+			}
+
+			if (prim.material) {
+				aim->mMaterialIndex = prim.material.GetIndex();
+			} else {
+				aim->mMaterialIndex = mScene->mNumMaterials - 1;
+			}
+		}
+	}
+
+	meshOffsets.push_back(k);
+
+	CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
 }
 
-void glTF2Importer::ImportCameras(glTF2::Asset& r)
-{
-    if (!r.cameras.Size()) return;
-
-    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];
-
-        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);
-
-        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;
-            }
-        }
-    }
+void glTF2Importer::ImportCameras(glTF2::Asset &r) {
+	if (!r.cameras.Size()) return;
+
+	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];
+
+		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);
+
+		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;
+			}
+		}
+	}
 }
 
-void glTF2Importer::ImportLights(glTF2::Asset& r)
-{
-    if (!r.lights.Size())
-        return;
-
-    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];
-
-        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;
-        }
-
-        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);
-
-        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;
-        }
-    }
+void glTF2Importer::ImportLights(glTF2::Asset &r) {
+	if (!r.lights.Size())
+		return;
+
+	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];
+
+		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;
+		}
+
+		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);
+
+		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;
+		}
+	}
 }
 
-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.scale.isPresent) {
-            aiVector3D scal(1.f);
-            CopyValue(node.scale.value, scal);
-            aiMatrix4x4 s;
-            aiMatrix4x4::Scaling(scal, s);
-            matrix = matrix * s;
-        }
-    }
+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.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<std::vector<aiVertexWeight>>& 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;
-
-    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;
-    }
-
-    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<unsigned int>(i), weight);
-            }
-        }
-    }
-
-    delete[] weights;
-    delete[] indices8;
-    delete[] indices16;
+static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &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;
+
+	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;
+	}
+
+	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<unsigned int>(i), weight);
+			}
+		}
+	}
+
+	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<unsigned int>& meshOffsets, glTF2::Ref<glTF2::Node>& ptr)
-{
-    Node& node = *ptr;
-
-    aiNode* ainode = new aiNode(GetNodeName(node));
-
-    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;
-        }
-    }
-
-    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];
-
-        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<unsigned int>(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<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
-                BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
-
-                mat4* pbindMatrices = nullptr;
-                node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
-
-                for (uint32_t i = 0; i < mesh->mNumBones; ++i) {
-                    aiBone* bone = new aiBone();
-
-                    Ref<Node> 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);
-
-                    std::vector<aiVertexWeight>& weights = weighting[i];
-
-                    bone->mNumWeights = static_cast<uint32_t>(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;
-                }
-            }
-        }
-
-        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.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);
-        }
-    }
-
-    return ainode;
+aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
+	Node &node = *ptr;
+
+	aiNode *ainode = new aiNode(GetNodeName(node));
+
+	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;
+		}
+	}
+
+	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];
+
+		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<unsigned int>(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<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
+				BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
+
+				mat4 *pbindMatrices = nullptr;
+				node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
+
+				for (uint32_t i = 0; i < mesh->mNumBones; ++i) {
+					aiBone *bone = new aiBone();
+
+					Ref<Node> 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);
+
+					std::vector<aiVertexWeight> &weights = weighting[i];
+
+					bone->mNumWeights = static_cast<uint32_t>(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;
+				}
+			}
+		}
+
+		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.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);
+		}
+	}
+
+	return ainode;
 }
 
-void glTF2Importer::ImportNodes(glTF2::Asset& r)
-{
-    if (!r.scene) return;
-
-    std::vector< Ref<Node> > 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");
-    //}
+void glTF2Importer::ImportNodes(glTF2::Asset &r) {
+	if (!r.scene) return;
+
+	std::vector<Ref<Node>> 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;
+	}
 }
 
 struct AnimationSamplers {
-    AnimationSamplers()
-    : translation(nullptr)
-    , rotation(nullptr)
-    , scale(nullptr)
-    , weight(nullptr) {
-        // empty
-    }
-
-    Animation::Sampler* translation;
-    Animation::Sampler* rotation;
-    Animation::Sampler* scale;
-    Animation::Sampler* weight;
+	AnimationSamplers() :
+			translation(nullptr),
+			rotation(nullptr),
+			scale(nullptr),
+			weight(nullptr) {
+		// empty
+	}
+
+	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);
-
-    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<uint32_t>(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<uint32_t>(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<uint32_t>(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;
+aiNodeAnim *CreateNodeAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) {
+	aiNodeAnim *anim = new aiNodeAnim();
+	anim->mNodeName = GetNodeName(node);
+
+	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<uint32_t>(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<uint32_t>(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<uint32_t>(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;
 }
 
-aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers)
-{
-    aiMeshMorphAnim* anim = new aiMeshMorphAnim();
-    anim->mName = GetNodeName(node);
-
-    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<uint32_t>(samplers.weight->input->count);
-
-        const unsigned int numMorphs = 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];
-
-            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;
-    }
-
-    return anim;
+aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) {
+	aiMeshMorphAnim *anim = new aiMeshMorphAnim();
+	anim->mName = GetNodeName(node);
+
+	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<uint32_t>(samplers.weight->input->count);
+
+		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];
+
+			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;
+	}
+
+	return anim;
 }
 
-std::unordered_map<unsigned int, AnimationSamplers> GatherSamplers(Animation& anim)
-{
-    std::unordered_map<unsigned int, AnimationSamplers> samplers;
-    for (unsigned int c = 0; c < anim.channels.size(); ++c) {
-        Animation::Channel& channel = anim.channels[c];
-        if (channel.sampler >= static_cast<int>(anim.samplers.size())) {
-            continue;
-        }
-
-        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];
-        }
-    }
-
-    return samplers;
+std::unordered_map<unsigned int, AnimationSamplers> GatherSamplers(Animation &anim) {
+	std::unordered_map<unsigned int, AnimationSamplers> samplers;
+	for (unsigned int c = 0; c < anim.channels.size(); ++c) {
+		Animation::Channel &channel = anim.channels[c];
+		if (channel.sampler >= static_cast<int>(anim.samplers.size())) {
+			continue;
+		}
+
+		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];
+		}
+	}
+
+	return samplers;
 }
 
-void glTF2Importer::ImportAnimations(glTF2::Asset& r)
-{
-    if (!r.scene) 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];
-
-        aiAnimation* ai_anim = new aiAnimation();
-        ai_anim->mName = anim.name;
-        ai_anim->mDuration = 0;
-        ai_anim->mTicksPerSecond = 0;
-
-        std::unordered_map<unsigned int, AnimationSamplers> samplers = GatherSamplers(anim);
-
-        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;
-            }
-        }
-
-        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;
-                }
-            }
-        }
-
-        // 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];
-
-            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;
-
-        mScene->mAnimations[i] = ai_anim;
-    }
+void glTF2Importer::ImportAnimations(glTF2::Asset &r) {
+	if (!r.scene) 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];
+
+		aiAnimation *ai_anim = new aiAnimation();
+		ai_anim->mName = anim.name;
+		ai_anim->mDuration = 0;
+		ai_anim->mTicksPerSecond = 0;
+
+		std::unordered_map<unsigned int, AnimationSamplers> samplers = GatherSamplers(anim);
+
+		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;
+			}
+		}
+
+		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;
+				}
+			}
+		}
+
+		// 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];
+
+			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;
+
+		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<unsigned int>(length);
-        tex->mHeight = 0;
-        tex->pcData = reinterpret_cast<aiTexel*>(data);
+		tex->mWidth = static_cast<unsigned int>(length);
+		tex->mHeight = 0;
+		tex->pcData = reinterpret_cast<aiTexel *>(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
-

+ 46 - 0
samples/SimpleTexturedDirectx11/CMakeLists.txt

@@ -0,0 +1,46 @@
+FIND_PACKAGE(DirectX)
+
+IF ( MSVC )
+  SET(M_LIB)
+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
+)

+ 0 - 28
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln

@@ -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

+ 2 - 0
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)

+ 0 - 146
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj

@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <VCProjectVersion>15.0</VCProjectVersion>
-    <ProjectGuid>{E3B160B5-E71F-4F3F-9310-B8F156F736D8}</ProjectGuid>
-    <RootNamespace>SimpleTexturedDirectx11</RootNamespace>
-    <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
-    <CharacterSet>MultiByte</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>MultiByte</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
-    <CharacterSet>MultiByte</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>MultiByte</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <IncludePath>$(IncludePath);E:\OpenGL VS Files\include</IncludePath>
-    <LibraryPath>$(LibraryPath);E:\OpenGL VS Files\lib</LibraryPath>
-  </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
-    </ClCompile>
-    <Link>
-      <AdditionalDependencies>assimp-vc140-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
-    </ClCompile>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-    </ClCompile>
-    <Link>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-    </ClCompile>
-    <Link>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemGroup>
-    <ClCompile Include="main.cpp" />
-    <ClCompile Include="ModelLoader.cpp" />
-    <ClCompile Include="TextureLoader.cpp" />
-  </ItemGroup>
-  <ItemGroup>
-    <FxCompile Include="PixelShader.hlsl">
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
-    </FxCompile>
-    <FxCompile Include="VertexShader.hlsl">
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Vertex</ShaderType>
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Vertex</ShaderType>
-      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Vertex</ShaderType>
-    </FxCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="Mesh.h" />
-    <ClInclude Include="ModelLoader.h" />
-    <ClInclude Include="TextureLoader.h" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-</Project>

+ 0 - 50
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters

@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Filter Include="Source Files">
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
-    </Filter>
-    <Filter Include="Header Files">
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
-      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
-    </Filter>
-    <Filter Include="Resource Files">
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
-    </Filter>
-    <Filter Include="Shaders">
-      <UniqueIdentifier>{b6a86d3e-70a5-4d1e-ba05-c20902300206}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="main.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="ModelLoader.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="TextureLoader.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <FxCompile Include="VertexShader.hlsl">
-      <Filter>Shaders</Filter>
-    </FxCompile>
-    <FxCompile Include="PixelShader.hlsl">
-      <Filter>Shaders</Filter>
-    </FxCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="ModelLoader.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="Mesh.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="TextureLoader.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-  </ItemGroup>
-</Project>

BIN
test/models/glTF2/textureTransform/Arrow.png


BIN
test/models/glTF2/textureTransform/Correct.png


BIN
test/models/glTF2/textureTransform/Error.png


+ 0 - 0
test/models/glTF2/textureTransform/License.txt


BIN
test/models/glTF2/textureTransform/NotSupported.png


BIN
test/models/glTF2/textureTransform/TextureTransformTest.bin


+ 540 - 0
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
+    }
+  ]
+}

BIN
test/models/glTF2/textureTransform/UV.png


+ 7 - 0
test/unit/utglTF2ImportExport.cpp

@@ -405,6 +405,13 @@ TEST_F(utglTF2ImportExport, incorrect_vertex_arrays) {
     EXPECT_EQ(scene->mMeshes[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() );