From b307ec643d37c964cbc423c713770465683c48e3 Mon Sep 17 00:00:00 2001 From: Otger Date: Fri, 27 Nov 2015 01:16:48 +0100 Subject: [PATCH] Created exporter class and fixed a few bugs --- code/CMakeLists.txt | 3 + code/Exporter.cpp | 9 + code/glTFExporter.cpp | 401 ++++++++++++++++++++++++++++++++++++++++++ code/glTFExporter.h | 87 +++++++++ code/glTFImporter.cpp | 39 ++-- code/glTFImporter.h | 18 -- code/glTFUtil.h | 18 ++ 7 files changed, 546 insertions(+), 29 deletions(-) create mode 100644 code/glTFExporter.cpp create mode 100644 code/glTFExporter.h diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 9a577fa1b..69ee3d7c7 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -568,6 +568,9 @@ ADD_ASSIMP_IMPORTER(GLTF glTFUtil.cpp glTFUtil.h glTFFileData.h + + glTFExporter.h + glTFExporter.cpp ) SET( Step_SRCS diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 42044b111..1d84e0dd0 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -87,6 +87,8 @@ void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportPro void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*); void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); @@ -135,6 +137,13 @@ Exporter::ExportFormatEntry gExporters[] = aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices), #endif +#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER + Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, + aiProcess_JoinIdenticalVertices), + Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, + aiProcess_JoinIdenticalVertices), +#endif + #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0), #endif diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp new file mode 100644 index 000000000..6e878165c --- /dev/null +++ b/code/glTFExporter.cpp @@ -0,0 +1,401 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2015, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + + + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER + +#include "glTFExporter.h" +#include "Exceptional.h" +#include "StringComparison.h" +#include "ByteSwapper.h" + +#include +#include +#include +#include +#include + +#include +#include + +#define RAPIDJSON_HAS_STDSTRING 1 +#include +#include +#include +#include + +#include "glTFFileData.h" +#include "glTFUtil.h" + +using namespace rapidjson; + +using namespace Assimp; +using namespace Assimp::glTF; + +namespace Assimp { + + // ------------------------------------------------------------------------------------------------ + // Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp + void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) + { + // invoke the exporter + glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false); + } + + // ------------------------------------------------------------------------------------------------ + // Worker function for exporting a scene to GLB. Prototyped and registered in Exporter.cpp + void ExportSceneGLB(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) + { + // invoke the exporter + glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, true); + } + +} // end of namespace Assimp + + + +class glTFSceneExporter +{ + typedef std::gltf_unordered_map IdMap; + + Document& mDoc; + MemoryPoolAllocator<>& mAl; + + const aiScene* mScene; + + std::string mRootNodeId; + + std::vector mMeshIds; + + IdMap mUsedIds; + +public: + glTFSceneExporter(Document& doc, const aiScene* pScene) + : mDoc(doc) + , mAl(doc.GetAllocator()) + , mScene(pScene) + { + doc.SetObject(); + + for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) { + + } + + for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { + + } + + for (unsigned int i = 0; i < pScene->mNumLights; ++i) { + + } + + for (unsigned int i = 0; i < pScene->mNumLights; ++i) { + + } + + for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { + + } + + + AddMeshes(); + + for (unsigned int i = 0; i < pScene->mNumTextures; ++i) { + + } + + AddNodes(); + + CreateScene(); + } + + inline void Pushf(Value& val, float f) + { + val.PushBack(Value(f).Move(), mAl); + } + + inline void SetMatrix(Value& v, const aiMatrix4x4& m) + { + v.SetArray(); + v.Reserve(16, mAl); + + Pushf(v, m.a1); Pushf(v, m.b1); Pushf(v, m.c1); Pushf(v, m.d1); + Pushf(v, m.a2); Pushf(v, m.b2); Pushf(v, m.c2); Pushf(v, m.d2); + Pushf(v, m.a3); Pushf(v, m.b3); Pushf(v, m.c3); Pushf(v, m.d3); + Pushf(v, m.a4); Pushf(v, m.b4); Pushf(v, m.c4); Pushf(v, m.d4); + } + + void AddMeshes() + { + if (mScene->mNumMeshes == 0) return; + + Value meshes; + meshes.SetObject(); + + mMeshIds.reserve(mScene->mNumMeshes); + for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { + aiMesh* m = mScene->mMeshes[i]; + std::string meshId = FindID(m->mName, "mesh"); + mMeshIds.push_back(meshId); + + Value mesh; + mesh.SetObject(); + { + Value primitives; + primitives.SetObject(); + + + mesh.AddMember("primitives", primitives, mAl); + } + + meshes.AddMember(StringRef(mMeshIds.back()), mesh, mAl); + } + + mDoc.AddMember("meshes", meshes, mAl); + } + + void AddNodes() + { + if (!mScene->mRootNode) return; + + Value nodes; + nodes.SetObject(); + + mRootNodeId = AddNode(nodes, mScene->mRootNode); + + mDoc.AddMember("nodes", nodes, mAl); + } + + + std::string AddNode(Value& nodes, const aiNode* n) + { + std::string nodeId = FindID(n->mName, "node"); + + Value node; + node.SetObject(); + + if (!n->mTransformation.IsIdentity()) { + Value matrix; + SetMatrix(matrix, n->mTransformation); + node.AddMember("matrix", matrix, mAl); + } + + if (n->mNumMeshes > 0) { + Value meshes; + meshes.SetArray(); + for (unsigned int i = 0; i < n->mNumMeshes; ++i) { + meshes.PushBack(StringRef(mMeshIds[n->mMeshes[i]]), mAl); + } + node.AddMember("meshes", meshes, mAl); + } + + if (n->mNumChildren > 0) { + Value children; + children.SetArray(); + for (unsigned int i = 0; i < n->mNumChildren; ++i) { + std::string id = AddNode(nodes, n->mChildren[i]); + children.PushBack(Value(id, mAl), mAl); + } + node.AddMember("children", children, mAl); + } + + nodes.AddMember(Value(nodeId, mAl), node, mAl); + + return nodeId; + } + + void CreateScene() + { + const char* sceneName = "defaultScene"; + + mDoc.AddMember("scene", Value(sceneName, mAl), mAl); + + Value scenes; + scenes.SetObject(); + { + Value scene; + scene.SetObject(); + { + Value nodes; + nodes.SetArray(); + + if (!mRootNodeId.empty()) { + nodes.PushBack(StringRef(mRootNodeId), mAl); + } + + scene.AddMember("nodes", nodes, mAl); + } + scenes.AddMember(Value(sceneName, mAl), scene, mAl); + } + mDoc.AddMember("scenes", scenes, mAl); + } + + std::string FindID(const aiString& str, const char* suffix) + { + std::string id = str.C_Str(); + + IdMap::iterator it; + + if (!id.empty()) { + it = mUsedIds.find(id); + if (it == mUsedIds.end()) goto found; + + id += "-"; + } + + id += suffix; + + it = mUsedIds.find(id); + if (it == mUsedIds.end()) goto found; + + char buffer[256]; + int offset = sprintf(buffer, "%s-", id.c_str()); + for (int i = 0; ; ++i) { + ASSIMP_itoa10(buffer + offset, sizeof(buffer), i); + + id = buffer; + it = mUsedIds.find(id); + if (it == mUsedIds.end()) goto found; + } + + found: + mUsedIds[id] = true; + return id; + } +}; + + + +glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, + const ExportProperties* pProperties, bool isBinary) + : mFilename(filename) + , mIOSystem(pIOSystem) + , mScene(pScene) + , mProperties(pProperties) + , mIsBinary(isBinary) +{ + boost::scoped_ptr outfile(pIOSystem->Open(mFilename, "wt")); + if (outfile == 0) { + throw DeadlyExportError("Could not open output file: " + std::string(mFilename)); + } + + if (isBinary) { + // we will write the header later, skip its size + outfile->Seek(sizeof(GLB_Header), aiOrigin_SET); + } + + + Document doc; + StringBuffer docBuffer; + { + glTFSceneExporter exportScene(doc, mScene); + + bool pretty = true; + if (!isBinary && pretty) { + PrettyWriter writer(docBuffer); + doc.Accept(writer); + } + else { + Writer writer(docBuffer); + doc.Accept(writer); + } + } + + if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { + throw DeadlyExportError("Failed to write scene data!"); + } + + if (isBinary) { + WriteBinaryData(outfile.get(), docBuffer.GetSize()); + } +} + + +void glTFExporter::WriteBinaryData(IOStream* outfile, std::size_t sceneLength) +{ + // + // write the body data + // + + if (!mBodyData.empty()) { + std::size_t bodyOffset = sizeof(GLB_Header) + sceneLength; + bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4 + + outfile->Seek(bodyOffset, aiOrigin_SET); + + if (outfile->Write(&mBodyData[0], mBodyData.size(), 1) != 1) { + throw DeadlyExportError("Failed to write body data!"); + } + } + + + // + // write the header + // + + outfile->Seek(0, aiOrigin_SET); + + GLB_Header header; + memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)); + + header.version = 1; + AI_SWAP4(header.version); + + header.length = sizeof(header) + sceneLength + mBodyData.size(); + AI_SWAP4(header.length); + + header.sceneLength = sceneLength; + AI_SWAP4(header.sceneLength); + + header.sceneFormat = SceneFormat_JSON; + AI_SWAP4(header.sceneFormat); + + if (outfile->Write(&header, sizeof(header), 1) != 1) { + throw DeadlyExportError("Failed to write the header!"); + } +} + + + + +#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/glTFExporter.h b/code/glTFExporter.h new file mode 100644 index 000000000..39dbf04d6 --- /dev/null +++ b/code/glTFExporter.h @@ -0,0 +1,87 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2015, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file GltfExporter.h +* Declares the exporter class to write a scene to a gltf/glb file +*/ +#ifndef AI_GLTFEXPORTER_H_INC +#define AI_GLTFEXPORTER_H_INC + +#include +#include +#include +#include + +struct aiScene; + +namespace Assimp +{ + class IOSystem; + class IOStream; + class ExportProperties; + + + // ------------------------------------------------------------------------------------------------ + /** Helper class to export a given scene to an glTF file. */ + // ------------------------------------------------------------------------------------------------ + class glTFExporter + { + public: + /// Constructor for a specific scene to export + glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, + const ExportProperties* pProperties, bool binary); + + private: + + const char* mFilename; + IOSystem* mIOSystem; + const aiScene* mScene; + const ExportProperties* mProperties; + bool mIsBinary; + + std::vector mBodyData; + + void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); + + }; + +} + +#endif diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index 374556af1..cc3b5dcf9 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "glTFFileData.h" #include "glTFUtil.h" +#define RAPIDJSON_HAS_STDSTRING 1 #include #include #include @@ -290,6 +291,10 @@ class glTFReader mScene->mRootNode = root; } } + + //if (!mScene->mRootNode) { + //mScene->mRootNode = new aiNode("EMPTY"); + //} } void SetMaterialColorProperty(aiMaterial* mat, Value& vals, const char* propName, aiTextureType texType, @@ -550,13 +555,15 @@ struct Accessor template void ExtractData(T*& outData, unsigned int* outCount = 0, unsigned int* outComponents = 0) { - if (!data) return; + ai_assert(data); const std::size_t totalSize = elemSize * count; const std::size_t targetElemSize = sizeof(T); ai_assert(elemSize <= targetElemSize); + ai_assert(count*byteStride <= bufferView->byteLength); + outData = new T[count]; if (byteStride == elemSize && targetElemSize == elemSize) { memcpy(outData, data, totalSize); @@ -574,6 +581,8 @@ struct Accessor template T GetValue(int i) { + ai_assert(data); + ai_assert(i*byteStride < bufferView->byteLength); T value = T(); memcpy(&value, data + i*byteStride, elemSize); //value >>= 8 * (sizeof(T) - elemSize); @@ -708,9 +717,11 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) else if (strcmp(attr, "NORMAL") == 0) { accessor->ExtractData(aimesh->mNormals); } - else if (strncmp(attr, "TEXCOORD_", 9) == 0) { + else if (strncmp(attr, "TEXCOORD_", 9) == 0) { int idx = attr[9] - '0'; - accessor->ExtractData(aimesh->mTextureCoords[idx], 0, &aimesh->mNumUVComponents[idx]); + if (idx >= 0 && idx <= AI_MAX_NUMBER_OF_TEXTURECOORDS) { + accessor->ExtractData(aimesh->mTextureCoords[idx], 0, &aimesh->mNumUVComponents[idx]); + } } } } @@ -727,7 +738,7 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) case PrimitiveMode_POINTS: { nFaces = acc->count; faces = new aiFace[nFaces]; - for (unsigned i = 0; i < acc->count; ++i) { + for (unsigned int i = 0; i < acc->count; ++i) { setFace(faces[i], acc->GetValue(i)); } break; @@ -736,7 +747,7 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) case PrimitiveMode_LINES: { nFaces = acc->count / 2; faces = new aiFace[nFaces]; - for (unsigned i = 0; i < acc->count; i += 2) { + for (unsigned int i = 0; i < acc->count; i += 2) { setFace(faces[i / 2], acc->GetValue(i), acc->GetValue(i + 1)); } break; @@ -747,7 +758,7 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) nFaces = acc->count - ((primitiveMode == PrimitiveMode_LINE_STRIP) ? 1 : 0); faces = new aiFace[nFaces]; setFace(faces[0], acc->GetValue(0), acc->GetValue(1)); - for (unsigned i = 2; i < acc->count; ++i) { + for (unsigned int i = 2; i < acc->count; ++i) { setFace(faces[i - 1], faces[i - 2].mIndices[1], acc->GetValue(i)); } if (primitiveMode == PrimitiveMode_LINE_LOOP) { // close the loop @@ -759,7 +770,7 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) case PrimitiveMode_TRIANGLES: { nFaces = acc->count / 3; faces = new aiFace[nFaces]; - for (unsigned i = 0; i < acc->count; i += 3) { + for (unsigned int i = 0; i < acc->count; i += 3) { setFace(faces[i / 3], acc->GetValue(i), acc->GetValue(i + 1), acc->GetValue(i + 2)); } break; @@ -768,7 +779,7 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) nFaces = acc->count - 2; faces = new aiFace[nFaces]; setFace(faces[0], acc->GetValue(0), acc->GetValue(1), acc->GetValue(2)); - for (unsigned i = 3; i < acc->count; ++i) { + for (unsigned int i = 3; i < acc->count; ++i) { setFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], acc->GetValue(i)); } break; @@ -777,7 +788,7 @@ Range glTFReader::LoadMesh(const char* id, Value& mesh) nFaces = acc->count - 2; faces = new aiFace[nFaces]; setFace(faces[0], acc->GetValue(0), acc->GetValue(1), acc->GetValue(2)); - for (unsigned i = 3; i < acc->count; ++i) { + for (unsigned int i = 3; i < acc->count; ++i) { setFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], acc->GetValue(i)); } break; @@ -986,8 +997,10 @@ aiNode* glTFReader::LoadNode(const char* id, Value& node) if (child.IsString()) { // get/create the child node aiNode* aichild = mNodes.Get(child.GetString()); - aichild->mParent = ainode; - ainode->mChildren[ainode->mNumChildren++] = aichild; + if (aichild) { + aichild->mParent = ainode; + ainode->mChildren[ainode->mNumChildren++] = aichild; + } } } } @@ -1185,4 +1198,8 @@ void glTFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IO // import the data glTFReader reader(pScene, doc, *pIOHandler, bodyBuffer); reader.Load(); + + if (pScene->mNumMeshes == 0) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } } diff --git a/code/glTFImporter.h b/code/glTFImporter.h index 9254040c1..3de899915 100644 --- a/code/glTFImporter.h +++ b/code/glTFImporter.h @@ -44,24 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "LogAux.h" #include "DefaultIOSystem.h" -#if _MSC_VER > 1500 || (defined __GNUC___) -# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP -# else -# define gltf_unordered_map map -# define gltf_unordered_multimap multimap -#endif - -#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP -# include -# if _MSC_VER > 1600 -# define gltf_unordered_map unordered_map -# define gltf_unordered_multimap unordered_multimap -# else -# define gltf_unordered_map tr1::unordered_map -# define gltf_unordered_multimap tr1::unordered_multimap -# endif -#endif - namespace Assimp { /** diff --git a/code/glTFUtil.h b/code/glTFUtil.h index 010d50ee3..089632ca1 100644 --- a/code/glTFUtil.h +++ b/code/glTFUtil.h @@ -44,6 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#include "MemoryIOWrapper.h" #include "StringComparison.h" +#if _MSC_VER > 1500 || (defined __GNUC___) +# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# else +# define gltf_unordered_map map +# define gltf_unordered_multimap multimap +#endif + +#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# include +# if _MSC_VER > 1600 +# define gltf_unordered_map unordered_map +# define gltf_unordered_multimap unordered_multimap +# else +# define gltf_unordered_map tr1::unordered_map +# define gltf_unordered_multimap tr1::unordered_multimap +# endif +#endif + namespace Assimp { namespace glTF {