Quellcode durchsuchen

Adds in missing assimp OBJ importer/exporter folder
Corrects highlighting behavior on ToolsGuiTextEditProfile

Areloch vor 5 Jahren
Ursprung
Commit
c1e99364b7

+ 414 - 0
Engine/lib/assimp/code/Obj/ObjExporter.cpp

@@ -0,0 +1,414 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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_OBJ_EXPORTER
+
+#include "ObjExporter.h"
+#include <assimp/Exceptional.h>
+#include <assimp/StringComparison.h>
+#include <assimp/version.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/material.h>
+#include <assimp/scene.h>
+#include <memory>
+
+using namespace Assimp;
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+// Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
+void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
+    // invoke the exporter
+    ObjExporter exporter(pFile, pScene);
+
+    if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) {
+        throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
+    }
+
+    // we're still here - export successfully completed. Write both the main OBJ file and the material script
+    {
+        std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
+        if(outfile == NULL) {
+            throw DeadlyExportError("could not open output .obj file: " + std::string(pFile));
+        }
+        outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
+    }
+    {
+        std::unique_ptr<IOStream> outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt"));
+        if(outfile == NULL) {
+            throw DeadlyExportError("could not open output .mtl file: " + std::string(exporter.GetMaterialLibFileName()));
+        }
+        outfile->Write( exporter.mOutputMat.str().c_str(), static_cast<size_t>(exporter.mOutputMat.tellp()),1);
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Worker function for exporting a scene to Wavefront OBJ without the material file. Prototyped and registered in Exporter.cpp
+void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) {
+    // invoke the exporter
+    ObjExporter exporter(pFile, pScene, true);
+
+    if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) {
+        throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
+    }
+
+    // we're still here - export successfully completed. Write both the main OBJ file and the material script
+    {
+        std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
+        if(outfile == NULL) {
+            throw DeadlyExportError("could not open output .obj file: " + std::string(pFile));
+        }
+        outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
+    }
+
+
+}
+
+} // end of namespace Assimp
+
+static const std::string MaterialExt = ".mtl";
+
+// ------------------------------------------------------------------------------------------------
+ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl)
+: filename(_filename)
+, pScene(pScene)
+, vn()
+, vt()
+, vp()
+, useVc(false)
+, mVnMap()
+, mVtMap()
+, mVpMap()
+, mMeshes()
+, endl("\n") {
+    // make sure that all formatting happens using the standard, C locale and not the user's current locale
+    const std::locale& l = std::locale("C");
+    mOutput.imbue(l);
+    mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
+    mOutputMat.imbue(l);
+    mOutputMat.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
+
+    WriteGeometryFile(noMtl);
+    if ( !noMtl ) {
+        WriteMaterialFile();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+ObjExporter::~ObjExporter() {
+    // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+std::string ObjExporter::GetMaterialLibName() {
+    // within the Obj file, we use just the relative file name with the path stripped
+    const std::string& s = GetMaterialLibFileName();
+    std::string::size_type il = s.find_last_of("/\\");
+    if (il != std::string::npos) {
+        return s.substr(il + 1);
+    }
+
+    return s;
+}
+
+// ------------------------------------------------------------------------------------------------
+std::string ObjExporter::GetMaterialLibFileName() {
+    // Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
+    size_t lastdot = filename.find_last_of('.');
+    if ( lastdot != std::string::npos ) {
+        return filename.substr( 0, lastdot ) + MaterialExt;
+    }
+
+    return filename + MaterialExt;
+}
+
+// ------------------------------------------------------------------------------------------------
+void ObjExporter::WriteHeader(std::ostringstream& out) {
+    out << "# File produced by Open Asset Import Library (http://www.assimp.sf.net)" << endl;
+    out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.'
+        << aiGetVersionRevision() << ")" << endl  << endl;
+}
+
+// ------------------------------------------------------------------------------------------------
+std::string ObjExporter::GetMaterialName(unsigned int index) {
+    const aiMaterial* const mat = pScene->mMaterials[index];
+    if ( nullptr == mat ) {
+        static const std::string EmptyStr;
+        return EmptyStr;
+    }
+
+    aiString s;
+    if(AI_SUCCESS == mat->Get(AI_MATKEY_NAME,s)) {
+        return std::string(s.data,s.length);
+    }
+
+    char number[ sizeof(unsigned int) * 3 + 1 ];
+    ASSIMP_itoa10(number,index);
+    return "$Material_" + std::string(number);
+}
+
+// ------------------------------------------------------------------------------------------------
+void ObjExporter::WriteMaterialFile() {
+    WriteHeader(mOutputMat);
+
+    for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
+        const aiMaterial* const mat = pScene->mMaterials[i];
+
+        int illum = 1;
+        mOutputMat << "newmtl " << GetMaterialName(i)  << endl;
+
+        aiColor4D c;
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) {
+            mOutputMat << "Kd " << c.r << " " << c.g << " " << c.b << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) {
+            mOutputMat << "Ka " << c.r << " " << c.g << " " << c.b << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
+            mOutputMat << "Ks " << c.r << " " << c.g << " " << c.b << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_EMISSIVE,c)) {
+            mOutputMat << "Ke " << c.r << " " << c.g << " " << c.b << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_TRANSPARENT,c)) {
+            mOutputMat << "Tf " << c.r << " " << c.g << " " << c.b << endl;
+        }
+
+        ai_real o;
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
+            mOutputMat << "d " << o << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_REFRACTI,o)) {
+            mOutputMat << "Ni " << o << endl;
+        }
+
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS,o) && o) {
+            mOutputMat << "Ns " << o << endl;
+            illum = 2;
+        }
+
+        mOutputMat << "illum " << illum << endl;
+
+        aiString s;
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) {
+            mOutputMat << "map_Kd " << s.data << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) {
+            mOutputMat << "map_Ka " << s.data << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) {
+            mOutputMat << "map_Ks " << s.data << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) {
+            mOutputMat << "map_Ns " << s.data << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_OPACITY(0),s)) {
+            mOutputMat << "map_d " << s.data << endl;
+        }
+        if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) {
+            // implementations seem to vary here, so write both variants
+            mOutputMat << "bump " << s.data << endl;
+            mOutputMat << "map_bump " << s.data << endl;
+        }
+
+        mOutputMat << endl;
+    }
+}
+
+void ObjExporter::WriteGeometryFile(bool noMtl) {
+    WriteHeader(mOutput);
+    if (!noMtl)
+        mOutput << "mtllib "  << GetMaterialLibName() << endl << endl;
+
+    // collect mesh geometry
+    aiMatrix4x4 mBase;
+    AddNode(pScene->mRootNode, mBase);
+
+    // write vertex positions with colors, if any
+    mVpMap.getKeys( vp );
+    if ( !useVc ) {
+        mOutput << "# " << vp.size() << " vertex positions" << endl;
+        for ( const vertexData& v : vp ) {
+            mOutput << "v  " << v.vp.x << " " << v.vp.y << " " << v.vp.z << endl;
+        }
+    } else {
+        mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
+        for ( const vertexData& v : vp ) {
+            mOutput << "v  " << v.vp.x << " " << v.vp.y << " " << v.vp.z << " " << v.vc.r << " " << v.vc.g << " " << v.vc.b << endl;
+        }
+    }
+    mOutput << endl;
+
+    // write uv coordinates
+    mVtMap.getKeys(vt);
+    mOutput << "# " << vt.size() << " UV coordinates" << endl;
+    for(const aiVector3D& v : vt) {
+        mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl;
+    }
+    mOutput << endl;
+
+    // write vertex normals
+    mVnMap.getKeys(vn);
+    mOutput << "# " << vn.size() << " vertex normals" << endl;
+    for(const aiVector3D& v : vn) {
+        mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl;
+    }
+    mOutput << endl;
+
+    // now write all mesh instances
+    for(const MeshInstance& m : mMeshes) {
+        mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
+        if (!m.name.empty()) {
+            mOutput << "g " << m.name << endl;
+        }
+        if ( !noMtl ) {
+            mOutput << "usemtl " << m.matname << endl;
+        }
+
+        for(const Face& f : m.faces) {
+            mOutput << f.kind << ' ';
+            for(const FaceVertex& fv : f.indices) {
+                mOutput << ' ' << fv.vp;
+
+                if (f.kind != 'p') {
+                    if (fv.vt || f.kind == 'f') {
+                        mOutput << '/';
+                    }
+                    if (fv.vt) {
+                        mOutput << fv.vt;
+                    }
+                    if (f.kind == 'f' && fv.vn) {
+                        mOutput << '/' << fv.vn;
+                    }
+                }
+            }
+
+            mOutput << endl;
+        }
+        mOutput << endl;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
+    mMeshes.push_back(MeshInstance() );
+    MeshInstance& mesh = mMeshes.back();
+
+    if ( nullptr != m->mColors[ 0 ] ) {
+        useVc = true;
+    }
+
+    mesh.name = std::string( name.data, name.length );
+    mesh.matname = GetMaterialName(m->mMaterialIndex);
+
+    mesh.faces.resize(m->mNumFaces);
+
+    for(unsigned int i = 0; i < m->mNumFaces; ++i) {
+        const aiFace& f = m->mFaces[i];
+
+        Face& face = mesh.faces[i];
+        switch (f.mNumIndices) {
+            case 1:
+                face.kind = 'p';
+                break;
+            case 2:
+                face.kind = 'l';
+                break;
+            default:
+                face.kind = 'f';
+        }
+        face.indices.resize(f.mNumIndices);
+
+        for(unsigned int a = 0; a < f.mNumIndices; ++a) {
+            const unsigned int idx = f.mIndices[a];
+
+            aiVector3D vert = mat * m->mVertices[idx];
+
+            if ( nullptr != m->mColors[ 0 ] ) {
+                aiColor4D col4 = m->mColors[ 0 ][ idx ];
+                face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b)});
+            } else {
+                face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0)});
+            }
+
+            if (m->mNormals) {
+                aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
+                face.indices[a].vn = mVnMap.getIndex(norm);
+            } else {
+                face.indices[a].vn = 0;
+            }
+
+            if ( m->mTextureCoords[ 0 ] ) {
+                face.indices[a].vt = mVtMap.getIndex(m->mTextureCoords[0][idx]);
+            } else {
+                face.indices[a].vt = 0;
+            }
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) {
+    const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
+
+    aiMesh *cm( nullptr );
+    for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
+        cm = pScene->mMeshes[nd->mMeshes[i]];
+        if (nullptr != cm) {
+            AddMesh(cm->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs);
+        } else {
+            AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs);
+        }
+    }
+
+    for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
+        AddNode(nd->mChildren[i], mAbs);
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+
+#endif // ASSIMP_BUILD_NO_OBJ_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 190 - 0
Engine/lib/assimp/code/Obj/ObjExporter.h

@@ -0,0 +1,190 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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 ObjExporter.h
+ * Declares the exporter class to write a scene to a Collada file
+ */
+#ifndef AI_OBJEXPORTER_H_INC
+#define AI_OBJEXPORTER_H_INC
+
+#include <assimp/types.h>
+#include <sstream>
+#include <vector>
+#include <map>
+
+struct aiScene;
+struct aiNode;
+struct aiMesh;
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+/** Helper class to export a given scene to an OBJ file. */
+// ------------------------------------------------------------------------------------------------
+class ObjExporter {
+public:
+    /// Constructor for a specific scene to export
+    ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false);
+    ~ObjExporter();
+    std::string GetMaterialLibName();
+    std::string GetMaterialLibFileName();
+    
+    /// public string-streams to write all output into
+    std::ostringstream mOutput, mOutputMat;
+
+private:
+    // intermediate data structures
+    struct FaceVertex {
+        FaceVertex()
+        : vp()
+        , vn()
+        , vt() {
+            // empty
+        }
+
+        // one-based, 0 means: 'does not exist'
+        unsigned int vp, vn, vt;
+    };
+
+    struct Face {
+        char kind;
+        std::vector<FaceVertex> indices;
+    };
+
+    struct MeshInstance {
+        std::string name, matname;
+        std::vector<Face> faces;
+    };
+
+    void WriteHeader(std::ostringstream& out);
+    void WriteMaterialFile();
+    void WriteGeometryFile(bool noMtl=false);
+    std::string GetMaterialName(unsigned int index);
+    void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat);
+    void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);
+
+private:
+    std::string filename;
+    const aiScene* const pScene;
+
+    struct vertexData {
+        aiVector3D vp;
+        aiColor3D vc; // OBJ does not support 4D color
+    };
+
+    std::vector<aiVector3D> vn, vt;
+    std::vector<aiColor4D> vc;
+    std::vector<vertexData> vp;
+    bool useVc;
+
+    struct vertexDataCompare {
+        bool operator() ( const vertexData& a, const vertexData& b ) const {
+            // position
+            if (a.vp.x < b.vp.x) return true;
+            if (a.vp.x > b.vp.x) return false;
+            if (a.vp.y < b.vp.y) return true;
+            if (a.vp.y > b.vp.y) return false;
+            if (a.vp.z < b.vp.z) return true;
+            if (a.vp.z > b.vp.z) return false;
+
+            // color
+            if (a.vc.r < b.vc.r) return true;
+            if (a.vc.r > b.vc.r) return false;
+            if (a.vc.g < b.vc.g) return true;
+            if (a.vc.g > b.vc.g) return false;
+            if (a.vc.b < b.vc.b) return true;
+            if (a.vc.b > b.vc.b) return false;
+            return false;
+        }
+    };
+
+    struct aiVectorCompare { 
+        bool operator() (const aiVector3D& a, const aiVector3D& b) const { 
+            if(a.x < b.x) return true; 
+            if(a.x > b.x) return false; 
+            if(a.y < b.y) return true; 
+            if(a.y > b.y) return false; 
+            if(a.z < b.z) return true; 
+            return false;
+        }
+    };
+
+    template <class T, class Compare = std::less<T>>
+    class indexMap {
+        int mNextIndex;
+        typedef std::map<T, int, Compare> dataType;
+        dataType vecMap;
+    
+    public:
+        indexMap()
+        : mNextIndex(1) {
+            // empty
+        }
+
+        int getIndex(const T& key) {
+            typename dataType::iterator vertIt = vecMap.find(key);
+            // vertex already exists, so reference it
+            if(vertIt != vecMap.end()){
+                return vertIt->second;
+            }
+            return vecMap[key] = mNextIndex++;
+        };
+
+        void getKeys( std::vector<T>& keys ) {
+            keys.resize(vecMap.size());
+            for(typename dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){
+                keys[it->second-1] = it->first;
+            }
+        };
+    };
+
+    indexMap<aiVector3D, aiVectorCompare> mVnMap, mVtMap;
+    indexMap<vertexData, vertexDataCompare> mVpMap;
+    std::vector<MeshInstance> mMeshes;
+
+    // this endl() doesn't flush() the stream
+    const std::string endl;
+};
+
+}
+
+#endif

+ 339 - 0
Engine/lib/assimp/code/Obj/ObjFileData.h

@@ -0,0 +1,339 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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.
+
+----------------------------------------------------------------------
+*/
+
+#pragma once
+#ifndef OBJ_FILEDATA_H_INC
+#define OBJ_FILEDATA_H_INC
+
+#include <vector>
+#include <map>
+#include <assimp/types.h>
+#include <assimp/mesh.h>
+
+namespace Assimp {
+namespace ObjFile {
+
+struct Object;
+struct Face;
+struct Material;
+
+// ------------------------------------------------------------------------------------------------
+//! \struct Face
+//! \brief  Data structure for a simple obj-face, describes discredit,l.ation and materials
+// ------------------------------------------------------------------------------------------------
+struct Face {
+    typedef std::vector<unsigned int> IndexArray;
+
+    //! Primitive type
+    aiPrimitiveType m_PrimitiveType;
+    //! Vertex indices
+    IndexArray m_vertices;
+    //! Normal indices
+    IndexArray m_normals;
+    //! Texture coordinates indices
+    IndexArray m_texturCoords;
+    //! Pointer to assigned material
+    Material *m_pMaterial;
+
+    //! \brief  Default constructor
+    Face( aiPrimitiveType pt = aiPrimitiveType_POLYGON) 
+    : m_PrimitiveType( pt )
+    , m_vertices()
+    , m_normals()
+    , m_texturCoords()
+    , m_pMaterial( 0L ) {
+        // empty
+    }
+
+    //! \brief  Destructor
+    ~Face() {
+        // empty
+    }
+};
+
+// ------------------------------------------------------------------------------------------------
+//! \struct Object
+//! \brief  Stores all objects of an obj-file object definition
+// ------------------------------------------------------------------------------------------------
+struct Object {
+    enum ObjectType {
+        ObjType,
+        GroupType
+    };
+
+    //! Object name
+    std::string m_strObjName;
+    //! Transformation matrix, stored in OpenGL format
+    aiMatrix4x4 m_Transformation;
+    //! All sub-objects referenced by this object
+    std::vector<Object*> m_SubObjects;
+    /// Assigned meshes
+    std::vector<unsigned int> m_Meshes;
+
+    //! \brief  Default constructor
+    Object() 
+    : m_strObjName("") {
+        // empty
+    }
+
+    //! \brief  Destructor
+    ~Object() {
+        for ( std::vector<Object*>::iterator it = m_SubObjects.begin(); it != m_SubObjects.end(); ++it) {
+            delete *it;
+        }
+    }
+};
+
+// ------------------------------------------------------------------------------------------------
+//! \struct Material
+//! \brief  Data structure to store all material specific data
+// ------------------------------------------------------------------------------------------------
+struct Material {
+    //! Name of material description
+    aiString MaterialName;
+
+    //! Texture names
+    aiString texture;
+    aiString textureSpecular;
+    aiString textureAmbient;
+    aiString textureEmissive;
+    aiString textureBump;
+    aiString textureNormal;
+    aiString textureReflection[6];
+    aiString textureSpecularity;
+    aiString textureOpacity;
+    aiString textureDisp;
+
+    enum TextureType {
+        TextureDiffuseType = 0,
+        TextureSpecularType,
+        TextureAmbientType,
+        TextureEmissiveType,
+        TextureBumpType,
+        TextureNormalType,
+        TextureReflectionSphereType,
+        TextureReflectionCubeTopType,
+        TextureReflectionCubeBottomType,
+        TextureReflectionCubeFrontType,
+        TextureReflectionCubeBackType,
+        TextureReflectionCubeLeftType,
+        TextureReflectionCubeRightType,
+        TextureSpecularityType,
+        TextureOpacityType,
+        TextureDispType,
+        TextureTypeCount
+    };
+    bool clamp[TextureTypeCount];
+
+    //! Ambient color
+    aiColor3D ambient;
+    //! Diffuse color
+    aiColor3D diffuse;
+    //! Specular color
+    aiColor3D specular;
+    //! Emissive color
+    aiColor3D emissive;
+    //! Alpha value
+    ai_real alpha;
+    //! Shineness factor
+    ai_real shineness;
+    //! Illumination model
+    int illumination_model;
+    //! Index of refraction
+    ai_real ior;
+    //! Transparency color
+    aiColor3D transparent;
+
+    //! Constructor
+    Material()
+    :   diffuse ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) )
+    ,   alpha   (ai_real( 1.0 ) )
+    ,   shineness ( ai_real( 0.0) )
+    ,   illumination_model (1)
+    ,   ior     ( ai_real( 1.0 ) )
+    ,   transparent( ai_real( 1.0), ai_real (1.0), ai_real(1.0)) {
+        // empty
+        for (size_t i = 0; i < TextureTypeCount; ++i) {
+            clamp[ i ] = false;
+        }
+    }
+
+    // Destructor
+    ~Material() {
+        // empty
+    }
+};
+
+// ------------------------------------------------------------------------------------------------
+//! \struct Mesh
+//! \brief  Data structure to store a mesh
+// ------------------------------------------------------------------------------------------------
+struct Mesh {
+    static const unsigned int NoMaterial = ~0u;
+    /// The name for the mesh
+    std::string m_name;
+    /// Array with pointer to all stored faces
+    std::vector<Face*> m_Faces;
+    /// Assigned material
+    Material *m_pMaterial;
+    /// Number of stored indices.
+    unsigned int m_uiNumIndices;
+    /// Number of UV
+    unsigned int m_uiUVCoordinates[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
+    /// Material index.
+    unsigned int m_uiMaterialIndex;
+    /// True, if normals are stored.
+    bool m_hasNormals;
+    /// True, if vertex colors are stored.
+    bool m_hasVertexColors;
+
+    /// Constructor
+    explicit Mesh( const std::string &name )
+    : m_name( name )
+    , m_pMaterial(NULL)
+    , m_uiNumIndices(0)
+    , m_uiMaterialIndex( NoMaterial )
+    , m_hasNormals(false) {
+        memset(m_uiUVCoordinates, 0, sizeof( unsigned int ) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
+    }
+
+    /// Destructor
+    ~Mesh() {
+        for (std::vector<Face*>::iterator it = m_Faces.begin();
+            it != m_Faces.end(); ++it)
+        {
+            delete *it;
+        }
+    }
+};
+
+// ------------------------------------------------------------------------------------------------
+//! \struct Model
+//! \brief  Data structure to store all obj-specific model datas
+// ------------------------------------------------------------------------------------------------
+struct Model {
+    typedef std::map<std::string, std::vector<unsigned int>* > GroupMap;
+    typedef std::map<std::string, std::vector<unsigned int>* >::iterator GroupMapIt;
+    typedef std::map<std::string, std::vector<unsigned int>* >::const_iterator ConstGroupMapIt;
+
+    //! Model name
+    std::string m_ModelName;
+    //! List ob assigned objects
+    std::vector<Object*> m_Objects;
+    //! Pointer to current object
+    ObjFile::Object *m_pCurrent;
+    //! Pointer to current material
+    ObjFile::Material *m_pCurrentMaterial;
+    //! Pointer to default material
+    ObjFile::Material *m_pDefaultMaterial;
+    //! Vector with all generated materials
+    std::vector<std::string> m_MaterialLib;
+    //! Vector with all generated vertices
+    std::vector<aiVector3D> m_Vertices;
+    //! vector with all generated normals
+    std::vector<aiVector3D> m_Normals;
+    //! vector with all vertex colors
+    std::vector<aiVector3D> m_VertexColors;
+    //! Group map
+    GroupMap m_Groups;
+    //! Group to face id assignment
+    std::vector<unsigned int> *m_pGroupFaceIDs;
+    //! Active group
+    std::string m_strActiveGroup;
+    //! Vector with generated texture coordinates
+    std::vector<aiVector3D> m_TextureCoord;
+    //! Maximum dimension of texture coordinates
+    unsigned int m_TextureCoordDim;
+    //! Current mesh instance
+    Mesh *m_pCurrentMesh;
+    //! Vector with stored meshes
+    std::vector<Mesh*> m_Meshes;
+    //! Material map
+    std::map<std::string, Material*> m_MaterialMap;
+
+    //! \brief  The default class constructor
+    Model() :
+        m_ModelName(""),
+        m_pCurrent(NULL),
+        m_pCurrentMaterial(NULL),
+        m_pDefaultMaterial(NULL),
+        m_pGroupFaceIDs(NULL),
+        m_strActiveGroup(""),
+        m_TextureCoordDim(0),
+        m_pCurrentMesh(NULL)
+    {
+        // empty
+    }
+
+    //! \brief  The class destructor
+    ~Model() {
+        // Clear all stored object instances
+        for (std::vector<Object*>::iterator it = m_Objects.begin();
+            it != m_Objects.end(); ++it) {
+            delete *it;
+        }
+        m_Objects.clear();
+
+        // Clear all stored mesh instances
+        for (std::vector<Mesh*>::iterator it = m_Meshes.begin();
+            it != m_Meshes.end(); ++it) {
+            delete *it;
+        }
+        m_Meshes.clear();
+
+        for(GroupMapIt it = m_Groups.begin(); it != m_Groups.end(); ++it) {
+            delete it->second;
+        }
+        m_Groups.clear();
+
+        for ( std::map<std::string, Material*>::iterator it = m_MaterialMap.begin(); it != m_MaterialMap.end(); ++it ) {
+            delete it->second;
+        }
+    }
+};
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace ObjFile
+} // Namespace Assimp
+
+#endif // OBJ_FILEDATA_H_INC

+ 784 - 0
Engine/lib/assimp/code/Obj/ObjFileImporter.cpp

@@ -0,0 +1,784 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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_OBJ_IMPORTER
+
+#include "ObjFileImporter.h"
+#include "ObjFileParser.h"
+#include "ObjFileData.h"
+#include <assimp/IOStreamBuffer.h>
+#include <memory>
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <assimp/ai_assert.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/importerdesc.h>
+
+static const aiImporterDesc desc = {
+    "Wavefront Object Importer",
+    "",
+    "",
+    "surfaces not supported",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "obj"
+};
+
+static const unsigned int ObjMinSize = 16;
+
+namespace Assimp {
+
+using namespace std;
+
+// ------------------------------------------------------------------------------------------------
+//  Default constructor
+ObjFileImporter::ObjFileImporter()
+: m_Buffer()
+, m_pRootObject( nullptr )
+, m_strAbsPath( std::string(1, DefaultIOSystem().getOsSeparator()) ) {}
+
+// ------------------------------------------------------------------------------------------------
+//  Destructor.
+ObjFileImporter::~ObjFileImporter() {
+    delete m_pRootObject;
+    m_pRootObject = nullptr;
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Returns true, if file is an obj file.
+bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem*  pIOHandler , bool checkSig ) const {
+    if(!checkSig)  {
+        //Check File Extension
+        return SimpleExtensionCheck(pFile,"obj");
+    } else {
+        // Check file Header
+        static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
+        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9, 200, false, true );
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiImporterDesc* ObjFileImporter::GetInfo() const {
+    return &desc;
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Obj-file import implementation
+void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) {
+    // Read file into memory
+    static const std::string mode = "rb";
+    std::unique_ptr<IOStream> fileStream( pIOHandler->Open( file, mode));
+    if( !fileStream.get() ) {
+        throw DeadlyImportError( "Failed to open file " + file + "." );
+    }
+
+    // Get the file-size and validate it, throwing an exception when fails
+    size_t fileSize = fileStream->FileSize();
+    if( fileSize < ObjMinSize ) {
+        throw DeadlyImportError( "OBJ-file is too small.");
+    }
+
+    IOStreamBuffer<char> streamedBuffer;
+    streamedBuffer.open( fileStream.get() );
+
+    // Allocate buffer and read file into it
+    //TextFileToBuffer( fileStream.get(),m_Buffer);
+
+    // Get the model name
+    std::string  modelName, folderName;
+    std::string::size_type pos = file.find_last_of( "\\/" );
+    if ( pos != std::string::npos ) {
+        modelName = file.substr(pos+1, file.size() - pos - 1);
+        folderName = file.substr( 0, pos );
+        if ( !folderName.empty() ) {
+            pIOHandler->PushDirectory( folderName );
+        }
+    } else {
+        modelName = file;
+    }
+
+    // parse the file into a temporary representation
+    ObjFileParser parser( streamedBuffer, modelName, pIOHandler, m_progress, file);
+
+    // And create the proper return structures out of it
+    CreateDataFromImport(parser.GetModel(), pScene);
+
+    streamedBuffer.close();
+
+    // Clean up allocated storage for the next import
+    m_Buffer.clear();
+
+    // Pop directory stack
+    if ( pIOHandler->StackSize() > 0 ) {
+        pIOHandler->PopDirectory();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Create the data from parsed obj-file
+void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene) {
+    if( 0L == pModel ) {
+        return;
+    }
+
+    // Create the root node of the scene
+    pScene->mRootNode = new aiNode;
+    if ( !pModel->m_ModelName.empty() ) {
+        // Set the name of the scene
+        pScene->mRootNode->mName.Set(pModel->m_ModelName);
+    } else {
+        // This is a fatal error, so break down the application
+        ai_assert(false);
+    }
+
+    if (pModel->m_Objects.size() > 0) {
+
+        unsigned int meshCount = 0;
+        unsigned int childCount = 0;
+
+        for(size_t index = 0; index < pModel->m_Objects.size(); ++index) {
+            if(pModel->m_Objects[index]) {
+                ++childCount;
+                meshCount += (unsigned int)pModel->m_Objects[index]->m_Meshes.size();
+            }
+        }
+
+        // Allocate space for the child nodes on the root node
+        pScene->mRootNode->mChildren = new aiNode*[ childCount ];
+
+        // Create nodes for the whole scene
+        std::vector<aiMesh*> MeshArray;
+        MeshArray.reserve(meshCount);
+        for (size_t index = 0; index < pModel->m_Objects.size(); ++index) {
+            createNodes(pModel, pModel->m_Objects[index], pScene->mRootNode, pScene, MeshArray);
+        }
+
+        ai_assert(pScene->mRootNode->mNumChildren == childCount);
+
+        // Create mesh pointer buffer for this scene
+        if (pScene->mNumMeshes > 0) {
+            pScene->mMeshes = new aiMesh*[MeshArray.size()];
+            for (size_t index = 0; index < MeshArray.size(); ++index) {
+                pScene->mMeshes[index] = MeshArray[index];
+            }
+        }
+
+        // Create all materials
+        createMaterials(pModel, pScene);
+    }else {
+		if (pModel->m_Vertices.empty()){
+			return;
+		}
+
+		std::unique_ptr<aiMesh> mesh( new aiMesh );
+        mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
+        unsigned int n = (unsigned int)pModel->m_Vertices.size();
+        mesh->mNumVertices = n;
+
+        mesh->mVertices = new aiVector3D[n];
+        memcpy(mesh->mVertices, pModel->m_Vertices.data(), n*sizeof(aiVector3D) );
+
+        if ( !pModel->m_Normals.empty() ) {
+            mesh->mNormals = new aiVector3D[n];
+            if (pModel->m_Normals.size() < n) {
+                throw DeadlyImportError("OBJ: vertex normal index out of range");
+            }
+            memcpy(mesh->mNormals, pModel->m_Normals.data(), n*sizeof(aiVector3D));
+        }
+
+        if ( !pModel->m_VertexColors.empty() ){
+            mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
+            for (unsigned int i = 0; i < n; ++i) {
+                if (i < pModel->m_VertexColors.size() ) {
+                    const aiVector3D& color = pModel->m_VertexColors[i];
+                    mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
+                }else {
+                    throw DeadlyImportError("OBJ: vertex color index out of range");
+                }
+            }
+        }
+
+        pScene->mRootNode->mNumMeshes = 1;
+        pScene->mRootNode->mMeshes = new unsigned int[1];
+        pScene->mRootNode->mMeshes[0] = 0;
+        pScene->mMeshes = new aiMesh*[1];
+        pScene->mNumMeshes = 1;
+        pScene->mMeshes[0] = mesh.release();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Creates all nodes of the model
+aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject,
+                                     aiNode *pParent, aiScene* pScene,
+                                     std::vector<aiMesh*> &MeshArray )
+{
+    ai_assert( NULL != pModel );
+    if( NULL == pObject ) {
+        return NULL;
+    }
+
+    // Store older mesh size to be able to computes mesh offsets for new mesh instances
+    const size_t oldMeshSize = MeshArray.size();
+    aiNode *pNode = new aiNode;
+
+    pNode->mName = pObject->m_strObjName;
+
+    // If we have a parent node, store it
+    ai_assert( NULL != pParent );
+    appendChildToParentNode( pParent, pNode );
+
+    for ( size_t i=0; i< pObject->m_Meshes.size(); ++i ) {
+        unsigned int meshId = pObject->m_Meshes[ i ];
+        aiMesh *pMesh = createTopology( pModel, pObject, meshId );
+        if( pMesh ) {
+            if (pMesh->mNumFaces > 0) {
+                MeshArray.push_back( pMesh );
+            } else {
+                delete pMesh;
+            }
+        }
+    }
+
+    // Create all nodes from the sub-objects stored in the current object
+    if ( !pObject->m_SubObjects.empty() ) {
+        size_t numChilds = pObject->m_SubObjects.size();
+        pNode->mNumChildren = static_cast<unsigned int>( numChilds );
+        pNode->mChildren = new aiNode*[ numChilds ];
+        pNode->mNumMeshes = 1;
+        pNode->mMeshes = new unsigned int[ 1 ];
+    }
+
+    // Set mesh instances into scene- and node-instances
+    const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
+    if ( meshSizeDiff > 0 ) {
+        pNode->mMeshes = new unsigned int[ meshSizeDiff ];
+        pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
+        size_t index = 0;
+        for (size_t i = oldMeshSize; i < MeshArray.size(); ++i ) {
+            pNode->mMeshes[ index ] = pScene->mNumMeshes;
+            pScene->mNumMeshes++;
+            ++index;
+        }
+    }
+
+    return pNode;
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Create topology data
+aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData, unsigned int meshIndex ) {
+    // Checking preconditions
+    ai_assert( NULL != pModel );
+
+    if( NULL == pData ) {
+        return NULL;
+    }
+
+    // Create faces
+    ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ meshIndex ];
+    if( !pObjMesh ) {
+        return NULL;
+    }
+
+    if( pObjMesh->m_Faces.empty() ) {
+        return NULL;
+    }
+
+    std::unique_ptr<aiMesh> pMesh(new aiMesh);
+    if( !pObjMesh->m_name.empty() ) {
+        pMesh->mName.Set( pObjMesh->m_name );
+    }
+
+    for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
+    {
+        ObjFile::Face *const inp = pObjMesh->m_Faces[ index ];
+        ai_assert( NULL != inp  );
+
+        if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
+            pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
+            pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
+        } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+            pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size());
+            pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
+        } else {
+            ++pMesh->mNumFaces;
+            if (inp->m_vertices.size() > 3) {
+                pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+            } else {
+                pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+            }
+        }
+    }
+
+    unsigned int uiIdxCount( 0u );
+    if ( pMesh->mNumFaces > 0 ) {
+        pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
+        if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial ) {
+            pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
+        }
+
+        unsigned int outIndex( 0 );
+
+        // Copy all data from all stored meshes
+        for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
+            ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
+            if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
+                for(size_t i = 0; i < inp->m_vertices.size() - 1; ++i) {
+                    aiFace& f = pMesh->mFaces[ outIndex++ ];
+                    uiIdxCount += f.mNumIndices = 2;
+                    f.mIndices = new unsigned int[2];
+                }
+                continue;
+            }
+            else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+                for(size_t i = 0; i < inp->m_vertices.size(); ++i) {
+                    aiFace& f = pMesh->mFaces[ outIndex++ ];
+                    uiIdxCount += f.mNumIndices = 1;
+                    f.mIndices = new unsigned int[1];
+                }
+                continue;
+            }
+
+            aiFace *pFace = &pMesh->mFaces[ outIndex++ ];
+            const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_vertices.size();
+            uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices;
+            if (pFace->mNumIndices > 0) {
+                pFace->mIndices = new unsigned int[ uiNumIndices ];
+            }
+        }
+    }
+
+    // Create mesh vertices
+    createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
+
+    return pMesh.release();
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Creates a vertex array
+void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
+                                        const ObjFile::Object* pCurrentObject,
+                                        unsigned int uiMeshIndex,
+                                        aiMesh* pMesh,
+                                        unsigned int numIndices) {
+    // Checking preconditions
+    ai_assert( NULL != pCurrentObject );
+
+    // Break, if no faces are stored in object
+    if ( pCurrentObject->m_Meshes.empty() )
+        return;
+
+    // Get current mesh
+    ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
+    if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1 ) {
+        return;
+    }
+
+    // Copy vertices of this mesh instance
+    pMesh->mNumVertices = numIndices;
+    if (pMesh->mNumVertices == 0) {
+        throw DeadlyImportError( "OBJ: no vertices" );
+    } else if (pMesh->mNumVertices > AI_MAX_VERTICES) {
+        throw DeadlyImportError( "OBJ: Too many vertices" );
+    }
+    pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
+
+    // Allocate buffer for normal vectors
+    if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals )
+        pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ];
+
+    // Allocate buffer for vertex-color vectors
+    if ( !pModel->m_VertexColors.empty() )
+        pMesh->mColors[0] = new aiColor4D[ pMesh->mNumVertices ];
+
+    // Allocate buffer for texture coordinates
+    if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] )
+    {
+        pMesh->mNumUVComponents[ 0 ] = pModel->m_TextureCoordDim;
+        pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ];
+    }
+
+    // Copy vertices, normals and textures into aiMesh instance
+    bool normalsok = true, uvok = true;
+    unsigned int newIndex = 0, outIndex = 0;
+    for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ ) {
+        // Get source face
+        ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ];
+
+        // Copy all index arrays
+        for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_vertices.size(); vertexIndex++ ) {
+            const unsigned int vertex = pSourceFace->m_vertices.at( vertexIndex );
+            if ( vertex >= pModel->m_Vertices.size() ) {
+                throw DeadlyImportError( "OBJ: vertex index out of range" );
+            }
+
+            if ( pMesh->mNumVertices <= newIndex ) {
+                throw DeadlyImportError("OBJ: bad vertex index");
+            }
+
+            pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
+
+            // Copy all normals
+            if ( normalsok && !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_normals.size()) {
+                const unsigned int normal = pSourceFace->m_normals.at( vertexIndex );
+                if ( normal >= pModel->m_Normals.size() )
+                {
+                    normalsok = false;
+                }
+                else
+                {
+                    pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ];
+                }
+            }
+
+            // Copy all vertex colors
+            if ( !pModel->m_VertexColors.empty())
+            {
+                const aiVector3D& color = pModel->m_VertexColors[ vertex ];
+                pMesh->mColors[0][ newIndex ] = aiColor4D(color.x, color.y, color.z, 1.0);
+            }
+
+            // Copy all texture coordinates
+            if ( uvok && !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_texturCoords.size())
+            {
+                const unsigned int tex = pSourceFace->m_texturCoords.at( vertexIndex );
+
+                if ( tex >= pModel->m_TextureCoord.size() )
+                {
+                    uvok = false;
+                }
+                else
+                {
+                    const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ];
+                    pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z );
+                }
+            }
+
+            // Get destination face
+            aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
+
+            const bool last = ( vertexIndex == pSourceFace->m_vertices.size() - 1 );
+            if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) {
+                pDestFace->mIndices[ outVertexIndex ] = newIndex;
+                outVertexIndex++;
+            }
+
+            if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT) {
+                outIndex++;
+                outVertexIndex = 0;
+            } else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE) {
+                outVertexIndex = 0;
+
+                if(!last)
+                    outIndex++;
+
+                if (vertexIndex) {
+                    if(!last) {
+                        pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ];
+                        if ( !pSourceFace->m_normals.empty() && !pModel->m_Normals.empty()) {
+                            pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ];
+                        }
+                        if ( !pModel->m_TextureCoord.empty() ) {
+                            for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) {
+                                pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ];
+                            }
+                        }
+                        ++newIndex;
+                    }
+
+                    pDestFace[-1].mIndices[1] = newIndex;
+                }
+            }
+            else if (last) {
+                outIndex++;
+            }
+            ++newIndex;
+        }
+    }
+
+    if (!normalsok)
+    {
+        delete [] pMesh->mNormals;
+        pMesh->mNormals = nullptr;
+    }
+
+    if (!uvok)
+    {
+        delete [] pMesh->mTextureCoords[0];
+        pMesh->mTextureCoords[0] = nullptr;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Counts all stored meshes
+void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes)
+{
+    iNumMeshes = 0;
+    if ( rObjects.empty() )
+        return;
+
+    iNumMeshes += static_cast<unsigned int>( rObjects.size() );
+    for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
+        it != rObjects.end();
+        ++it)
+    {
+        if (!(*it)->m_SubObjects.empty())
+        {
+            countObjects((*it)->m_SubObjects, iNumMeshes);
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+//   Add clamp mode property to material if necessary
+void ObjFileImporter::addTextureMappingModeProperty( aiMaterial* mat, aiTextureType type, int clampMode, int index) {
+    if ( nullptr == mat ) {
+        return;
+    }
+
+    mat->AddProperty<int>( &clampMode, 1, AI_MATKEY_MAPPINGMODE_U( type, index ) );
+    mat->AddProperty<int>( &clampMode, 1, AI_MATKEY_MAPPINGMODE_V( type, index ) );
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Creates the material
+void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pScene ) {
+    if ( NULL == pScene ) {
+        return;
+    }
+
+    const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size();
+    pScene->mNumMaterials = 0;
+    if ( pModel->m_MaterialLib.empty() ) {
+        ASSIMP_LOG_DEBUG("OBJ: no materials specified");
+        return;
+    }
+
+    pScene->mMaterials = new aiMaterial*[ numMaterials ];
+    for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ )
+    {
+        // Store material name
+        std::map<std::string, ObjFile::Material*>::const_iterator it;
+        it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
+
+        // No material found, use the default material
+        if ( pModel->m_MaterialMap.end() == it )
+            continue;
+
+        aiMaterial* mat = new aiMaterial;
+        ObjFile::Material *pCurrentMaterial = (*it).second;
+        mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
+
+        // convert illumination model
+        int sm = 0;
+        switch (pCurrentMaterial->illumination_model)
+        {
+        case 0:
+            sm = aiShadingMode_NoShading;
+            break;
+        case 1:
+            sm = aiShadingMode_Gouraud;
+            break;
+        case 2:
+            sm = aiShadingMode_Phong;
+            break;
+        default:
+            sm = aiShadingMode_Gouraud;
+            ASSIMP_LOG_ERROR("OBJ: unexpected illumination model (0-2 recognized)");
+        }
+
+        mat->AddProperty<int>( &sm, 1, AI_MATKEY_SHADING_MODEL);
+
+        // Adding material colors
+        mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
+        mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
+        mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
+        mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE );
+        mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
+        mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
+        mat->AddProperty( &pCurrentMaterial->transparent,1,AI_MATKEY_COLOR_TRANSPARENT);
+
+        // Adding refraction index
+        mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI );
+
+        // Adding textures
+        const int uvwIndex = 0;
+
+        if ( 0 != pCurrentMaterial->texture.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_DIFFUSE(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureAmbient.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_AMBIENT(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_AMBIENT);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureEmissive.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_EMISSIVE(0) );
+        }
+
+        if ( 0 != pCurrentMaterial->textureSpecular.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_SPECULAR(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_SPECULAR);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureBump.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureNormal.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
+            }
+        }
+
+        if( 0 != pCurrentMaterial->textureReflection[0].length )
+        {
+            ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ?
+                ObjFile::Material::TextureReflectionCubeTopType :
+                ObjFile::Material::TextureReflectionSphereType;
+
+            unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6;
+            for( unsigned i = 0; i < count; i++ )
+            {
+                mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i));
+                mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_REFLECTION(i) );
+
+                if(pCurrentMaterial->clamp[type])
+                    addTextureMappingModeProperty(mat, aiTextureType_REFLECTION, 1, i);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureDisp.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_DISPLACEMENT(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureOpacity.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_OPACITY(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_OPACITY);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureSpecularity.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
+            mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_SHININESS(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_SHININESS);
+            }
+        }
+
+        // Store material property info in material array in scene
+        pScene->mMaterials[ pScene->mNumMaterials ] = mat;
+        pScene->mNumMaterials++;
+    }
+
+    // Test number of created materials.
+    ai_assert( pScene->mNumMaterials == numMaterials );
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Appends this node to the parent node
+void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
+{
+    // Checking preconditions
+    ai_assert( NULL != pParent );
+    ai_assert( NULL != pChild );
+
+    // Assign parent to child
+    pChild->mParent = pParent;
+
+    // Copy node instances into parent node
+    pParent->mNumChildren++;
+    pParent->mChildren[ pParent->mNumChildren-1 ] = pChild;
+}
+
+// ------------------------------------------------------------------------------------------------
+
+}   // Namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER

+ 123 - 0
Engine/lib/assimp/code/Obj/ObjFileImporter.h

@@ -0,0 +1,123 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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 OBJ_FILE_IMPORTER_H_INC
+#define OBJ_FILE_IMPORTER_H_INC
+
+#include <assimp/BaseImporter.h>
+#include <assimp/material.h>
+#include <vector>
+
+struct aiMesh;
+struct aiNode;
+
+namespace Assimp {
+
+namespace ObjFile {
+    struct Object;
+    struct Model;
+}
+
+// ------------------------------------------------------------------------------------------------
+/// \class  ObjFileImporter
+/// \brief  Imports a waveform obj file
+// ------------------------------------------------------------------------------------------------
+class ObjFileImporter : public BaseImporter {
+public:
+    /// \brief  Default constructor
+    ObjFileImporter();
+
+    /// \brief  Destructor
+    ~ObjFileImporter();
+
+public:
+    /// \brief  Returns whether the class can handle the format of the given file.
+    /// \remark See BaseImporter::CanRead() for details.
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
+
+private:
+    //! \brief  Appends the supported extension.
+    const aiImporterDesc* GetInfo () const;
+
+    //! \brief  File import implementation.
+    void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+
+    //! \brief  Create the data from imported content.
+    void CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene);
+
+    //! \brief  Creates all nodes stored in imported content.
+    aiNode *createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pData,
+        aiNode *pParent, aiScene* pScene, std::vector<aiMesh*> &MeshArray);
+
+    //! \brief  Creates topology data like faces and meshes for the geometry.
+    aiMesh *createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData,
+        unsigned int uiMeshIndex );
+
+    //! \brief  Creates vertices from model.
+    void createVertexArray(const ObjFile::Model* pModel, const ObjFile::Object* pCurrentObject,
+        unsigned int uiMeshIndex, aiMesh* pMesh, unsigned int numIndices );
+
+    //! \brief  Object counter helper method.
+    void countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes);
+
+    //! \brief  Material creation.
+    void createMaterials(const ObjFile::Model* pModel, aiScene* pScene);
+
+    /// @brief  Adds special property for the used texture mapping mode of the model.
+    void addTextureMappingModeProperty(aiMaterial* mat, aiTextureType type, int clampMode = 1, int index = 0);
+
+    //! \brief  Appends a child node to a parent node and updates the data structures.
+    void appendChildToParentNode(aiNode *pParent, aiNode *pChild);
+
+private:
+    //! Data buffer
+    std::vector<char> m_Buffer;
+    //! Pointer to root object instance
+    ObjFile::Object *m_pRootObject;
+    //! Absolute pathname of model in file system
+    std::string m_strAbsPath;
+};
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif

+ 494 - 0
Engine/lib/assimp/code/Obj/ObjFileMtlImporter.cpp

@@ -0,0 +1,494 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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_OBJ_IMPORTER
+
+#include <stdlib.h>
+#include "ObjFileMtlImporter.h"
+#include "ObjTools.h"
+#include "ObjFileData.h"
+#include <assimp/fast_atof.h>
+#include <assimp/ParsingUtils.h>
+#include <assimp/material.h>
+#include <assimp/DefaultLogger.hpp>
+
+namespace Assimp    {
+
+// Material specific token (case insensitive compare)
+static const std::string DiffuseTexture       = "map_Kd";
+static const std::string AmbientTexture       = "map_Ka";
+static const std::string SpecularTexture      = "map_Ks";
+static const std::string OpacityTexture       = "map_d";
+static const std::string EmissiveTexture1     = "map_emissive";
+static const std::string EmissiveTexture2     = "map_Ke";
+static const std::string BumpTexture1         = "map_bump";
+static const std::string BumpTexture2         = "bump";
+static const std::string NormalTexture        = "map_Kn";
+static const std::string ReflectionTexture    = "refl";
+static const std::string DisplacementTexture1 = "map_disp";
+static const std::string DisplacementTexture2 = "disp";
+static const std::string SpecularityTexture   = "map_ns";
+
+// texture option specific token
+static const std::string BlendUOption       = "-blendu";
+static const std::string BlendVOption       = "-blendv";
+static const std::string BoostOption        = "-boost";
+static const std::string ModifyMapOption    = "-mm";
+static const std::string OffsetOption       = "-o";
+static const std::string ScaleOption        = "-s";
+static const std::string TurbulenceOption   = "-t";
+static const std::string ResolutionOption   = "-texres";
+static const std::string ClampOption        = "-clamp";
+static const std::string BumpOption         = "-bm";
+static const std::string ChannelOption      = "-imfchan";
+static const std::string TypeOption         = "-type";
+
+// -------------------------------------------------------------------
+//  Constructor
+ObjFileMtlImporter::ObjFileMtlImporter( std::vector<char> &buffer,
+                                       const std::string &,
+                                       ObjFile::Model *pModel ) :
+    m_DataIt( buffer.begin() ),
+    m_DataItEnd( buffer.end() ),
+    m_pModel( pModel ),
+    m_uiLine( 0 )
+{
+    ai_assert( NULL != m_pModel );
+    if ( NULL == m_pModel->m_pDefaultMaterial )
+    {
+        m_pModel->m_pDefaultMaterial = new ObjFile::Material;
+        m_pModel->m_pDefaultMaterial->MaterialName.Set( "default" );
+    }
+    load();
+}
+
+// -------------------------------------------------------------------
+//  Destructor
+ObjFileMtlImporter::~ObjFileMtlImporter()
+{
+    // empty
+}
+
+// -------------------------------------------------------------------
+//  Private copy constructor
+ObjFileMtlImporter::ObjFileMtlImporter(const ObjFileMtlImporter & )
+{
+    // empty
+}
+
+// -------------------------------------------------------------------
+//  Private copy constructor
+ObjFileMtlImporter &ObjFileMtlImporter::operator = ( const ObjFileMtlImporter & )
+{
+    return *this;
+}
+
+// -------------------------------------------------------------------
+//  Loads the material description
+void ObjFileMtlImporter::load()
+{
+    if ( m_DataIt == m_DataItEnd )
+        return;
+
+    while ( m_DataIt != m_DataItEnd )
+    {
+        switch (*m_DataIt)
+        {
+        case 'k':
+        case 'K':
+            {
+                ++m_DataIt;
+                if (*m_DataIt == 'a') // Ambient color
+                {
+                    ++m_DataIt;
+                    getColorRGBA( &m_pModel->m_pCurrentMaterial->ambient );
+                }
+                else if (*m_DataIt == 'd')  // Diffuse color
+                {
+                    ++m_DataIt;
+                    getColorRGBA( &m_pModel->m_pCurrentMaterial->diffuse );
+                }
+                else if (*m_DataIt == 's')
+                {
+                    ++m_DataIt;
+                    getColorRGBA( &m_pModel->m_pCurrentMaterial->specular );
+                }
+                else if (*m_DataIt == 'e')
+                {
+                    ++m_DataIt;
+                    getColorRGBA( &m_pModel->m_pCurrentMaterial->emissive );
+                }
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+        case 'T':
+            {
+                ++m_DataIt;
+                if (*m_DataIt == 'f') // Material transmission
+                {
+                    ++m_DataIt;
+                    getColorRGBA( &m_pModel->m_pCurrentMaterial->transparent);
+                }
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+        case 'd':
+            {
+                if( *(m_DataIt+1) == 'i' && *( m_DataIt + 2 ) == 's' && *( m_DataIt + 3 ) == 'p' ) {
+                    // A displacement map
+                    getTexture();
+                } else {
+                    // Alpha value
+                    ++m_DataIt;
+                    getFloatValue( m_pModel->m_pCurrentMaterial->alpha );
+                    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+                }
+            }
+            break;
+
+        case 'N':
+        case 'n':
+            {
+                ++m_DataIt;
+                switch(*m_DataIt)
+                {
+                case 's':   // Specular exponent
+                    ++m_DataIt;
+                    getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
+                    break;
+                case 'i':   // Index Of refraction
+                    ++m_DataIt;
+                    getFloatValue(m_pModel->m_pCurrentMaterial->ior);
+                    break;
+                case 'e':   // New material
+                    createMaterial();
+                    break;
+                }
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+
+        case 'm':   // Texture
+        case 'b':   // quick'n'dirty - for 'bump' sections
+        case 'r':   // quick'n'dirty - for 'refl' sections
+            {
+                getTexture();
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+
+        case 'i':   // Illumination model
+            {
+                m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+                getIlluminationModel( m_pModel->m_pCurrentMaterial->illumination_model );
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+
+        default:
+            {
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+        }
+    }
+}
+
+// -------------------------------------------------------------------
+//  Loads a color definition
+void ObjFileMtlImporter::getColorRGBA( aiColor3D *pColor )
+{
+    ai_assert( NULL != pColor );
+
+    ai_real r( 0.0 ), g( 0.0 ), b( 0.0 );
+    m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, r );
+    pColor->r = r;
+
+    // we have to check if color is default 0 with only one token
+    if( !IsLineEnd( *m_DataIt ) ) {
+        m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, g );
+        m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, b );
+    }
+    pColor->g = g;
+    pColor->b = b;
+}
+
+// -------------------------------------------------------------------
+//  Loads the kind of illumination model.
+void ObjFileMtlImporter::getIlluminationModel( int &illum_model )
+{
+    m_DataIt = CopyNextWord<DataArrayIt>( m_DataIt, m_DataItEnd, m_buffer, BUFFERSIZE );
+    illum_model = atoi(m_buffer);
+}
+
+// -------------------------------------------------------------------
+//  Loads a single float value.
+void ObjFileMtlImporter::getFloatValue( ai_real &value )
+{
+    m_DataIt = CopyNextWord<DataArrayIt>( m_DataIt, m_DataItEnd, m_buffer, BUFFERSIZE );
+    value = (ai_real) fast_atof(m_buffer);
+}
+
+// -------------------------------------------------------------------
+//  Creates a material from loaded data.
+void ObjFileMtlImporter::createMaterial()
+{
+    std::string line( "" );
+    while( !IsLineEnd( *m_DataIt ) ) {
+        line += *m_DataIt;
+        ++m_DataIt;
+    }
+
+    std::vector<std::string> token;
+    const unsigned int numToken = tokenize<std::string>( line, token, " \t" );
+    std::string name( "" );
+    if ( numToken == 1 ) {
+        name = AI_DEFAULT_MATERIAL_NAME;
+    } else {
+        // skip newmtl and all following white spaces
+        std::size_t first_ws_pos = line.find_first_of(" \t");
+        std::size_t first_non_ws_pos = line.find_first_not_of(" \t", first_ws_pos);
+        if (first_non_ws_pos != std::string::npos) {
+            name = line.substr(first_non_ws_pos);
+        }
+    }
+
+    name = trim_whitespaces(name);
+
+    std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( name );
+    if ( m_pModel->m_MaterialMap.end() == it) {
+        // New Material created
+        m_pModel->m_pCurrentMaterial = new ObjFile::Material();
+        m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
+        m_pModel->m_MaterialLib.push_back( name );
+        m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
+
+        if (m_pModel->m_pCurrentMesh) {
+            m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
+        }
+    } else {
+        // Use older material
+        m_pModel->m_pCurrentMaterial = (*it).second;
+    }
+}
+
+// -------------------------------------------------------------------
+//  Gets a texture name from data.
+void ObjFileMtlImporter::getTexture() {
+    aiString *out( NULL );
+    int clampIndex = -1;
+
+    const char *pPtr( &(*m_DataIt) );
+    if ( !ASSIMP_strincmp( pPtr, DiffuseTexture.c_str(), static_cast<unsigned int>(DiffuseTexture.size()) ) ) {
+        // Diffuse texture
+        out = & m_pModel->m_pCurrentMaterial->texture;
+        clampIndex = ObjFile::Material::TextureDiffuseType;
+    } else if ( !ASSIMP_strincmp( pPtr,AmbientTexture.c_str(), static_cast<unsigned int>(AmbientTexture.size()) ) ) {
+        // Ambient texture
+        out = & m_pModel->m_pCurrentMaterial->textureAmbient;
+        clampIndex = ObjFile::Material::TextureAmbientType;
+    } else if ( !ASSIMP_strincmp( pPtr, SpecularTexture.c_str(), static_cast<unsigned int>(SpecularTexture.size()) ) ) {
+        // Specular texture
+        out = & m_pModel->m_pCurrentMaterial->textureSpecular;
+        clampIndex = ObjFile::Material::TextureSpecularType;
+    } else if ( !ASSIMP_strincmp( pPtr, DisplacementTexture1.c_str(), static_cast<unsigned int>(DisplacementTexture1.size()) ) ||
+                !ASSIMP_strincmp( pPtr, DisplacementTexture2.c_str(), static_cast<unsigned int>(DisplacementTexture2.size()) ) ) {
+        // Displacement texture
+        out = &m_pModel->m_pCurrentMaterial->textureDisp;
+        clampIndex = ObjFile::Material::TextureDispType;
+    } else if ( !ASSIMP_strincmp( pPtr, OpacityTexture.c_str(), static_cast<unsigned int>(OpacityTexture.size()) ) ) {
+        // Opacity texture
+        out = & m_pModel->m_pCurrentMaterial->textureOpacity;
+        clampIndex = ObjFile::Material::TextureOpacityType;
+    } else if ( !ASSIMP_strincmp( pPtr, EmissiveTexture1.c_str(), static_cast<unsigned int>(EmissiveTexture1.size()) ) ||
+                !ASSIMP_strincmp( pPtr, EmissiveTexture2.c_str(), static_cast<unsigned int>(EmissiveTexture2.size()) ) ) {
+        // Emissive texture
+        out = & m_pModel->m_pCurrentMaterial->textureEmissive;
+        clampIndex = ObjFile::Material::TextureEmissiveType;
+    } else if ( !ASSIMP_strincmp( pPtr, BumpTexture1.c_str(), static_cast<unsigned int>(BumpTexture1.size()) ) ||
+                !ASSIMP_strincmp( pPtr, BumpTexture2.c_str(), static_cast<unsigned int>(BumpTexture2.size()) ) ) {
+        // Bump texture
+        out = & m_pModel->m_pCurrentMaterial->textureBump;
+        clampIndex = ObjFile::Material::TextureBumpType;
+    } else if ( !ASSIMP_strincmp( pPtr,NormalTexture.c_str(), static_cast<unsigned int>(NormalTexture.size()) ) ) {
+        // Normal map
+        out = & m_pModel->m_pCurrentMaterial->textureNormal;
+        clampIndex = ObjFile::Material::TextureNormalType;
+    } else if( !ASSIMP_strincmp( pPtr, ReflectionTexture.c_str(), static_cast<unsigned int>(ReflectionTexture.size()) ) ) {
+        // Reflection texture(s)
+        //Do nothing here
+        return;
+    } else if ( !ASSIMP_strincmp( pPtr, SpecularityTexture.c_str(), static_cast<unsigned int>(SpecularityTexture.size()) ) ) {
+        // Specularity scaling (glossiness)
+        out = & m_pModel->m_pCurrentMaterial->textureSpecularity;
+        clampIndex = ObjFile::Material::TextureSpecularityType;
+    } else {
+        ASSIMP_LOG_ERROR("OBJ/MTL: Encountered unknown texture type");
+        return;
+    }
+
+    bool clamp = false;
+    getTextureOption(clamp, clampIndex, out);
+    m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
+
+    std::string texture;
+    m_DataIt = getName<DataArrayIt>( m_DataIt, m_DataItEnd, texture );
+    if ( NULL!=out ) {
+        out->Set( texture );
+    }
+}
+
+/* /////////////////////////////////////////////////////////////////////////////
+ * Texture Option
+ * /////////////////////////////////////////////////////////////////////////////
+ * According to http://en.wikipedia.org/wiki/Wavefront_.obj_file#Texture_options
+ * Texture map statement can contains various texture option, for example:
+ *
+ *  map_Ka -o 1 1 1 some.png
+ *  map_Kd -clamp on some.png
+ *
+ * So we need to parse and skip these options, and leave the last part which is
+ * the url of image, otherwise we will get a wrong url like "-clamp on some.png".
+ *
+ * Because aiMaterial supports clamp option, so we also want to return it
+ * /////////////////////////////////////////////////////////////////////////////
+ */
+void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) {
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+
+    // If there is any more texture option
+    while (!isEndOfBuffer(m_DataIt, m_DataItEnd) && *m_DataIt == '-')
+    {
+        const char *pPtr( &(*m_DataIt) );
+        //skip option key and value
+        int skipToken = 1;
+
+        if (!ASSIMP_strincmp(pPtr, ClampOption.c_str(), static_cast<unsigned int>(ClampOption.size())))
+        {
+            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+            char value[3];
+            CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
+            if (!ASSIMP_strincmp(value, "on", 2))
+            {
+                clamp = true;
+            }
+
+            skipToken = 2;
+        }
+        else if( !ASSIMP_strincmp( pPtr, TypeOption.c_str(), static_cast<unsigned int>(TypeOption.size()) ) )
+        {
+            DataArrayIt it = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
+            char value[ 12 ];
+            CopyNextWord( it, m_DataItEnd, value, sizeof( value ) / sizeof( *value ) );
+            if( !ASSIMP_strincmp( value, "cube_top", 8 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_bottom", 11 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[1];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_front", 10 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[2];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_back", 9 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[3];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_left", 9 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[4];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_right", 10 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[5];
+            }
+            else if( !ASSIMP_strincmp( value, "sphere", 6 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionSphereType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
+            }
+
+            skipToken = 2;
+        }
+        else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size()))
+                || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size()))
+                || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size()))
+                || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size()))
+                || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))
+                || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size())))
+        {
+            skipToken = 2;
+        }
+        else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size())))
+        {
+            skipToken = 3;
+        }
+        else if (  !ASSIMP_strincmp(pPtr, OffsetOption.c_str(), static_cast<unsigned int>(OffsetOption.size()))
+                || !ASSIMP_strincmp(pPtr, ScaleOption.c_str(), static_cast<unsigned int>(ScaleOption.size()))
+                || !ASSIMP_strincmp(pPtr, TurbulenceOption.c_str(), static_cast<unsigned int>(TurbulenceOption.size()))
+                )
+        {
+            skipToken = 4;
+        }
+
+        for (int i = 0; i < skipToken; ++i)
+        {
+            m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+        }
+    }
+}
+
+// -------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER

+ 117 - 0
Engine/lib/assimp/code/Obj/ObjFileMtlImporter.h

@@ -0,0 +1,117 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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 OBJFILEMTLIMPORTER_H_INC
+#define OBJFILEMTLIMPORTER_H_INC
+
+#include <vector>
+#include <string>
+#include <assimp/defs.h>
+
+struct aiColor3D;
+struct aiString;
+
+namespace Assimp {
+
+namespace ObjFile {
+    struct Model;
+    struct Material;
+}
+
+
+/**
+ *  @class  ObjFileMtlImporter
+ *  @brief  Loads the material description from a mtl file.
+ */
+class ObjFileMtlImporter
+{
+public:
+    static const size_t BUFFERSIZE = 2048;
+    typedef std::vector<char> DataArray;
+    typedef std::vector<char>::iterator DataArrayIt;
+    typedef std::vector<char>::const_iterator ConstDataArrayIt;
+
+public:
+    //! \brief  Default constructor
+    ObjFileMtlImporter( std::vector<char> &buffer, const std::string &strAbsPath,
+        ObjFile::Model *pModel );
+
+    //! \brief  DEstructor
+    ~ObjFileMtlImporter();
+
+private:
+    /// Copy constructor, empty.
+    ObjFileMtlImporter(const ObjFileMtlImporter &rOther);
+    /// \brief  Assignment operator, returns only a reference of this instance.
+    ObjFileMtlImporter &operator = (const ObjFileMtlImporter &rOther);
+    /// Load the whole material description
+    void load();
+    /// Get color data.
+    void getColorRGBA( aiColor3D *pColor);
+    /// Get illumination model from loaded data
+    void getIlluminationModel( int &illum_model );
+    /// Gets a float value from data.
+    void getFloatValue( ai_real &value );
+    /// Creates a new material from loaded data.
+    void createMaterial();
+    /// Get texture name from loaded data.
+    void getTexture();
+    void getTextureOption(bool &clamp, int &clampIndex, aiString *&out);
+
+private:
+    //! Absolute pathname
+    std::string m_strAbsPath;
+    //! Data iterator showing to the current position in data buffer
+    DataArrayIt m_DataIt;
+    //! Data iterator to end of buffer
+    DataArrayIt m_DataItEnd;
+    //! USed model instance
+    ObjFile::Model *m_pModel;
+    //! Current line in file
+    unsigned int m_uiLine;
+    //! Helper buffer
+    char m_buffer[BUFFERSIZE];
+};
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif // OBJFILEMTLIMPORTER_H_INC

+ 880 - 0
Engine/lib/assimp/code/Obj/ObjFileParser.cpp

@@ -0,0 +1,880 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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_OBJ_IMPORTER
+
+#include "ObjFileParser.h"
+#include "ObjFileMtlImporter.h"
+#include "ObjTools.h"
+#include "ObjFileData.h"
+#include <assimp/ParsingUtils.h>
+#include <assimp/BaseImporter.h>
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/material.h>
+#include <assimp/Importer.hpp>
+#include <cstdlib>
+
+namespace Assimp {
+
+const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
+
+ObjFileParser::ObjFileParser()
+: m_DataIt()
+, m_DataItEnd()
+, m_pModel( nullptr )
+, m_uiLine( 0 )
+, m_pIO( nullptr )
+, m_progress( nullptr )
+, m_originalObjFileName() {
+    // empty
+}
+
+ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::string &modelName,
+                              IOSystem *io, ProgressHandler* progress,
+                              const std::string &originalObjFileName) :
+    m_DataIt(),
+    m_DataItEnd(),
+    m_pModel(nullptr),
+    m_uiLine(0),
+    m_pIO( io ),
+    m_progress(progress),
+    m_originalObjFileName(originalObjFileName)
+{
+    std::fill_n(m_buffer,Buffersize,0);
+
+    // Create the model instance to store all the data
+    m_pModel.reset(new ObjFile::Model());
+    m_pModel->m_ModelName = modelName;
+
+    // create default material and store it
+    m_pModel->m_pDefaultMaterial = new ObjFile::Material;
+    m_pModel->m_pDefaultMaterial->MaterialName.Set( DEFAULT_MATERIAL );
+    m_pModel->m_MaterialLib.push_back( DEFAULT_MATERIAL );
+    m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
+
+    // Start parsing the file
+    parseFile( streamBuffer );
+}
+
+ObjFileParser::~ObjFileParser() {
+}
+
+void ObjFileParser::setBuffer( std::vector<char> &buffer ) {
+    m_DataIt = buffer.begin();
+    m_DataItEnd = buffer.end();
+}
+
+ObjFile::Model *ObjFileParser::GetModel() const {
+    return m_pModel.get();
+}
+
+void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
+    // only update every 100KB or it'll be too slow
+    //const unsigned int updateProgressEveryBytes = 100 * 1024;
+    unsigned int progressCounter = 0;
+    const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
+    const unsigned int progressTotal = bytesToProcess;
+    unsigned int processed = 0;
+    size_t lastFilePos( 0 );
+
+    std::vector<char> buffer;
+    while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) {
+        m_DataIt = buffer.begin();
+        m_DataItEnd = buffer.end();
+
+        // Handle progress reporting
+        const size_t filePos( streamBuffer.getFilePos() );
+        if ( lastFilePos < filePos ) {
+            processed = static_cast<unsigned int>(filePos);
+            lastFilePos = filePos;
+            progressCounter++;
+            m_progress->UpdateFileRead( processed, progressTotal );
+        }
+
+        // parse line
+        switch (*m_DataIt) {
+        case 'v': // Parse a vertex texture coordinate
+            {
+                ++m_DataIt;
+                if (*m_DataIt == ' ' || *m_DataIt == '\t') {
+                    size_t numComponents = getNumComponentsInDataDefinition();
+                    if (numComponents == 3) {
+                        // read in vertex definition
+                        getVector3(m_pModel->m_Vertices);
+                    } else if (numComponents == 4) {
+                        // read in vertex definition (homogeneous coords)
+                        getHomogeneousVector3(m_pModel->m_Vertices);
+                    } else if (numComponents == 6) {
+                        // read vertex and vertex-color
+                        getTwoVectors3(m_pModel->m_Vertices, m_pModel->m_VertexColors);
+                    }
+                } else if (*m_DataIt == 't') {
+                    // read in texture coordinate ( 2D or 3D )
+                    ++m_DataIt;
+                    size_t dim = getTexCoordVector(m_pModel->m_TextureCoord);
+                    m_pModel->m_TextureCoordDim = std::max(m_pModel->m_TextureCoordDim, (unsigned int)dim);
+                } else if (*m_DataIt == 'n') {
+                    // Read in normal vector definition
+                    ++m_DataIt;
+                    getVector3( m_pModel->m_Normals );
+                }
+            }
+            break;
+
+        case 'p': // Parse a face, line or point statement
+        case 'l':
+        case 'f':
+            {
+                getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l'
+                    ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
+            }
+            break;
+
+        case '#': // Parse a comment
+            {
+                getComment();
+            }
+            break;
+
+        case 'u': // Parse a material desc. setter
+            {
+                std::string name;
+
+                getNameNoSpace(m_DataIt, m_DataItEnd, name);
+
+                size_t nextSpace = name.find(" ");
+                if (nextSpace != std::string::npos)
+                    name = name.substr(0, nextSpace);
+
+                if(name == "usemtl")
+                {
+                    getMaterialDesc();
+                }
+            }
+            break;
+
+        case 'm': // Parse a material library or merging group ('mg')
+            {
+                std::string name;
+
+                getNameNoSpace(m_DataIt, m_DataItEnd, name);
+
+                size_t nextSpace = name.find(" ");
+                if (nextSpace != std::string::npos)
+                    name = name.substr(0, nextSpace);
+
+                if (name == "mg")
+                    getGroupNumberAndResolution();
+                else if(name == "mtllib")
+                    getMaterialLib();
+				else
+					goto pf_skip_line;
+            }
+            break;
+
+        case 'g': // Parse group name
+            {
+                getGroupName();
+            }
+            break;
+
+        case 's': // Parse group number
+            {
+                getGroupNumber();
+            }
+            break;
+
+        case 'o': // Parse object name
+            {
+                getObjectName();
+            }
+            break;
+
+        default:
+            {
+pf_skip_line:
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+        }
+    }
+}
+
+void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
+    size_t index = 0;
+    m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
+    if ( *m_DataIt == '\\' ) {
+        ++m_DataIt;
+        ++m_DataIt;
+        m_DataIt = getNextWord<DataArrayIt>( m_DataIt, m_DataItEnd );
+    }
+    while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
+        pBuffer[index] = *m_DataIt;
+        index++;
+        if( index == length - 1 ) {
+            break;
+        }
+        ++m_DataIt;
+    }
+
+    ai_assert(index < length);
+    pBuffer[index] = '\0';
+}
+
+static bool isDataDefinitionEnd( const char *tmp ) {
+    if ( *tmp == '\\' ) {
+        tmp++;
+        if ( IsLineEnd( *tmp ) ) {
+            tmp++;
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool isNanOrInf(const char * in) {
+    // Look for "nan" or "inf", case insensitive
+    if ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) {
+        return true;
+    }
+    else if ((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0) {
+        return true;
+    }
+    return false;
+}
+
+size_t ObjFileParser::getNumComponentsInDataDefinition() {
+    size_t numComponents( 0 );
+    const char* tmp( &m_DataIt[0] );
+    bool end_of_definition = false;
+    while ( !end_of_definition ) {
+        if ( isDataDefinitionEnd( tmp ) ) {
+            tmp += 2;
+        } else if ( IsLineEnd( *tmp ) ) {
+            end_of_definition = true;
+        }
+        if ( !SkipSpaces( &tmp ) ) {
+            break;
+        }
+        const bool isNum( IsNumeric( *tmp ) || isNanOrInf(tmp));
+        SkipToken( tmp );
+        if ( isNum ) {
+            ++numComponents;
+        }
+        if ( !SkipSpaces( &tmp ) ) {
+            break;
+        }
+    }
+    return numComponents;
+}
+
+size_t ObjFileParser::getTexCoordVector( std::vector<aiVector3D> &point3d_array ) {
+    size_t numComponents = getNumComponentsInDataDefinition();
+    ai_real x, y, z;
+    if( 2 == numComponents ) {
+        copyNextWord( m_buffer, Buffersize );
+        x = ( ai_real ) fast_atof( m_buffer );
+
+        copyNextWord( m_buffer, Buffersize );
+        y = ( ai_real ) fast_atof( m_buffer );
+        z = 0.0;
+    } else if( 3 == numComponents ) {
+        copyNextWord( m_buffer, Buffersize );
+        x = ( ai_real ) fast_atof( m_buffer );
+
+        copyNextWord( m_buffer, Buffersize );
+        y = ( ai_real ) fast_atof( m_buffer );
+
+        copyNextWord( m_buffer, Buffersize );
+        z = ( ai_real ) fast_atof( m_buffer );
+    } else {
+        throw DeadlyImportError( "OBJ: Invalid number of components" );
+    }
+
+    // Coerce nan and inf to 0 as is the OBJ default value
+    if (!std::isfinite(x))
+        x = 0;
+
+    if (!std::isfinite(y))
+        y = 0;
+
+    if (!std::isfinite(z))
+        z = 0;
+
+    point3d_array.push_back( aiVector3D( x, y, z ) );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    return numComponents;
+}
+
+void ObjFileParser::getVector3( std::vector<aiVector3D> &point3d_array ) {
+    ai_real x, y, z;
+    copyNextWord(m_buffer, Buffersize);
+    x = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord(m_buffer, Buffersize);
+    y = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord( m_buffer, Buffersize );
+    z = ( ai_real ) fast_atof( m_buffer );
+
+    point3d_array.push_back( aiVector3D( x, y, z ) );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+void ObjFileParser::getHomogeneousVector3( std::vector<aiVector3D> &point3d_array ) {
+    ai_real x, y, z, w;
+    copyNextWord(m_buffer, Buffersize);
+    x = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord(m_buffer, Buffersize);
+    y = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord( m_buffer, Buffersize );
+    z = ( ai_real ) fast_atof( m_buffer );
+
+    copyNextWord( m_buffer, Buffersize );
+    w = ( ai_real ) fast_atof( m_buffer );
+
+    if (w == 0)
+      throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
+
+    point3d_array.push_back( aiVector3D( x/w, y/w, z/w ) );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+void ObjFileParser::getTwoVectors3( std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b ) {
+    ai_real x, y, z;
+    copyNextWord(m_buffer, Buffersize);
+    x = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord(m_buffer, Buffersize);
+    y = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord( m_buffer, Buffersize );
+    z = ( ai_real ) fast_atof( m_buffer );
+
+    point3d_array_a.push_back( aiVector3D( x, y, z ) );
+
+    copyNextWord(m_buffer, Buffersize);
+    x = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord(m_buffer, Buffersize);
+    y = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord( m_buffer, Buffersize );
+    z = ( ai_real ) fast_atof( m_buffer );
+
+    point3d_array_b.push_back( aiVector3D( x, y, z ) );
+
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
+    ai_real x, y;
+    copyNextWord(m_buffer, Buffersize);
+    x = (ai_real) fast_atof(m_buffer);
+
+    copyNextWord(m_buffer, Buffersize);
+    y = (ai_real) fast_atof(m_buffer);
+
+    point2d_array.push_back(aiVector2D(x, y));
+
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+static const std::string DefaultObjName = "defaultobject";
+
+void ObjFileParser::getFace( aiPrimitiveType type ) {
+    m_DataIt = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
+    if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) {
+        return;
+    }
+
+    ObjFile::Face *face = new ObjFile::Face( type );
+    bool hasNormal = false;
+
+    const int vSize = static_cast<unsigned int>(m_pModel->m_Vertices.size());
+    const int vtSize = static_cast<unsigned int>(m_pModel->m_TextureCoord.size());
+    const int vnSize = static_cast<unsigned int>(m_pModel->m_Normals.size());
+
+    const bool vt = (!m_pModel->m_TextureCoord.empty());
+    const bool vn = (!m_pModel->m_Normals.empty());
+    int iStep = 0, iPos = 0;
+    while ( m_DataIt != m_DataItEnd ) {
+        iStep = 1;
+
+        if ( IsLineEnd( *m_DataIt ) ) {
+            break;
+        }
+
+        if ( *m_DataIt =='/' ) {
+            if (type == aiPrimitiveType_POINT) {
+                ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement");
+            }
+            iPos++;
+        } else if( IsSpaceOrNewLine( *m_DataIt ) ) {
+            iPos = 0;
+        } else {
+            //OBJ USES 1 Base ARRAYS!!!!
+            const int iVal( ::atoi( & ( *m_DataIt ) ) );
+
+            // increment iStep position based off of the sign and # of digits
+            int tmp = iVal;
+            if ( iVal < 0 ) {
+                ++iStep;
+            }
+            while ( ( tmp = tmp / 10 ) != 0 ) {
+                ++iStep;
+            }
+
+            if (iPos == 1 && !vt && vn)
+                iPos = 2; // skip texture coords for normals if there are no tex coords
+
+            if ( iVal > 0 ) {
+                // Store parsed index
+                if ( 0 == iPos ) {
+                    face->m_vertices.push_back( iVal - 1 );
+                } else if ( 1 == iPos ) {
+                    face->m_texturCoords.push_back( iVal - 1 );
+                } else if ( 2 == iPos ) {
+                    face->m_normals.push_back( iVal - 1 );
+                    hasNormal = true;
+                } else {
+                    reportErrorTokenInFace();
+                }
+            } else if ( iVal < 0 ) {
+                // Store relatively index
+                if ( 0 == iPos ) {
+                    face->m_vertices.push_back( vSize + iVal );
+                } else if ( 1 == iPos ) {
+                    face->m_texturCoords.push_back( vtSize + iVal );
+                } else if ( 2 == iPos ) {
+                    face->m_normals.push_back( vnSize + iVal );
+                    hasNormal = true;
+                } else {
+                    reportErrorTokenInFace();
+                }
+            } else {
+                //On error, std::atoi will return 0 which is not a valid value
+                delete face;
+                throw DeadlyImportError("OBJ: Invalid face indice");
+            }
+
+        }
+        m_DataIt += iStep;
+    }
+
+    if ( face->m_vertices.empty() ) {
+        ASSIMP_LOG_ERROR("Obj: Ignoring empty face");
+        // skip line and clean up
+        m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+        delete face;
+        return;
+    }
+
+    // Set active material, if one set
+    if( NULL != m_pModel->m_pCurrentMaterial ) {
+        face->m_pMaterial = m_pModel->m_pCurrentMaterial;
+    } else {
+        face->m_pMaterial = m_pModel->m_pDefaultMaterial;
+    }
+
+    // Create a default object, if nothing is there
+    if( NULL == m_pModel->m_pCurrent ) {
+        createObject( DefaultObjName );
+    }
+
+    // Assign face to mesh
+    if ( NULL == m_pModel->m_pCurrentMesh ) {
+        createMesh( DefaultObjName );
+    }
+
+    // Store the face
+    m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
+    m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int) face->m_vertices.size();
+    m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int) face->m_texturCoords.size();
+    if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) {
+        m_pModel->m_pCurrentMesh->m_hasNormals = true;
+    }
+    // Skip the rest of the line
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+void ObjFileParser::getMaterialDesc() {
+    // Get next data for material data
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    if (m_DataIt == m_DataItEnd) {
+        return;
+    }
+
+    char *pStart = &(*m_DataIt);
+    while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
+
+    // In some cases we should ignore this 'usemtl' command, this variable helps us to do so
+    bool skip = false;
+
+    // Get name
+    std::string strName(pStart, &(*m_DataIt));
+    strName = trim_whitespaces(strName);
+    if (strName.empty())
+        skip = true;
+
+    // If the current mesh has the same material, we simply ignore that 'usemtl' command
+    // There is no need to create another object or even mesh here
+    if ( m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString( strName ) ) {
+        skip = true;
+    }
+
+    if (!skip) {
+        // Search for material
+        std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find(strName);
+        if (it == m_pModel->m_MaterialMap.end()) {
+			// Not found, so we don't know anything about the material except for its name.
+			// This may be the case if the material library is missing. We don't want to lose all
+			// materials if that happens, so create a new named material instead of discarding it
+			// completely.
+            ASSIMP_LOG_ERROR("OBJ: failed to locate material " + strName + ", creating new material");
+			m_pModel->m_pCurrentMaterial = new ObjFile::Material();
+			m_pModel->m_pCurrentMaterial->MaterialName.Set(strName);
+			m_pModel->m_MaterialLib.push_back(strName);
+			m_pModel->m_MaterialMap[strName] = m_pModel->m_pCurrentMaterial;
+        } else {
+            // Found, using detected material
+            m_pModel->m_pCurrentMaterial = (*it).second;
+        }
+
+        if ( needsNewMesh( strName ) ) {
+            createMesh( strName );
+        }
+
+        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
+    }
+
+    // Skip rest of line
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+// -------------------------------------------------------------------
+//  Get a comment, values will be skipped
+void ObjFileParser::getComment() {
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+// -------------------------------------------------------------------
+//  Get material library from file.
+void ObjFileParser::getMaterialLib() {
+    // Translate tuple
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    if( m_DataIt == m_DataItEnd ) {
+        return;
+    }
+
+    char *pStart = &(*m_DataIt);
+    while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
+
+    // Check for existence
+    const std::string strMatName(pStart, &(*m_DataIt));
+    std::string absName;
+
+	// Check if directive is valid.
+    if ( 0 == strMatName.length() ) {
+        ASSIMP_LOG_WARN( "OBJ: no name for material library specified." );
+        return;
+    }
+
+    if ( m_pIO->StackSize() > 0 ) {
+        std::string path = m_pIO->CurrentDirectory();
+        if ( '/' != *path.rbegin() ) {
+          path += '/';
+        }
+        absName += path;
+        absName += strMatName;
+    } else {
+        absName = strMatName;
+    }
+
+    IOStream *pFile = m_pIO->Open( absName );
+    if ( nullptr == pFile ) {
+        ASSIMP_LOG_ERROR("OBJ: Unable to locate material file " + strMatName);
+        std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
+        ASSIMP_LOG_INFO("OBJ: Opening fallback material file " + strMatFallbackName);
+        pFile = m_pIO->Open(strMatFallbackName);
+        if (!pFile) {
+            ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file " + strMatFallbackName);
+            m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
+            return;
+        }
+    }
+
+    // Import material library data from file.
+    // Some exporters (e.g. Silo) will happily write out empty
+    // material files if the model doesn't use any materials, so we
+    // allow that.
+    std::vector<char> buffer;
+    BaseImporter::TextFileToBuffer( pFile, buffer, BaseImporter::ALLOW_EMPTY );
+    m_pIO->Close( pFile );
+
+    // Importing the material library
+    ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel.get() );
+}
+
+// -------------------------------------------------------------------
+//  Set a new material definition as the current material.
+void ObjFileParser::getNewMaterial() {
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
+    if( m_DataIt == m_DataItEnd ) {
+        return;
+    }
+
+    char *pStart = &(*m_DataIt);
+    std::string strMat( pStart, *m_DataIt );
+    while( m_DataIt != m_DataItEnd && IsSpaceOrNewLine( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
+    std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
+    if ( it == m_pModel->m_MaterialMap.end() ) {
+        // Show a warning, if material was not found
+        ASSIMP_LOG_WARN("OBJ: Unsupported material requested: " + strMat);
+        m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
+    } else {
+        // Set new material
+        if ( needsNewMesh( strMat ) ) {
+            createMesh( strMat );
+        }
+        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
+    }
+
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+// -------------------------------------------------------------------
+int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
+{
+    int mat_index = -1;
+    if( strMaterialName.empty() ) {
+        return mat_index;
+    }
+    for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index)
+    {
+        if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
+        {
+            mat_index = (int)index;
+            break;
+        }
+    }
+    return mat_index;
+}
+
+// -------------------------------------------------------------------
+//  Getter for a group name.
+void ObjFileParser::getGroupName() {
+    std::string groupName;
+
+    // here we skip 'g ' from line
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, groupName);
+    if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) {
+        return;
+    }
+
+    // Change active group, if necessary
+    if ( m_pModel->m_strActiveGroup != groupName ) {
+        // Search for already existing entry
+        ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(groupName);
+
+        // We are mapping groups into the object structure
+        createObject( groupName );
+
+        // New group name, creating a new entry
+        if (it == m_pModel->m_Groups.end())
+        {
+            std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
+            m_pModel->m_Groups[ groupName ] = pFaceIDArray;
+            m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
+        }
+        else
+        {
+            m_pModel->m_pGroupFaceIDs = (*it).second;
+        }
+        m_pModel->m_strActiveGroup = groupName;
+    }
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+// -------------------------------------------------------------------
+//  Not supported
+void ObjFileParser::getGroupNumber()
+{
+    // Not used
+
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+// -------------------------------------------------------------------
+//  Not supported
+void ObjFileParser::getGroupNumberAndResolution()
+{
+    // Not used
+
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
+// -------------------------------------------------------------------
+//  Stores values for a new object instance, name will be used to
+//  identify it.
+void ObjFileParser::getObjectName()
+{
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    if( m_DataIt == m_DataItEnd ) {
+        return;
+    }
+    char *pStart = &(*m_DataIt);
+    while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
+
+    std::string strObjectName(pStart, &(*m_DataIt));
+    if (!strObjectName.empty())
+    {
+        // Reset current object
+        m_pModel->m_pCurrent = NULL;
+
+        // Search for actual object
+        for (std::vector<ObjFile::Object*>::const_iterator it = m_pModel->m_Objects.begin();
+            it != m_pModel->m_Objects.end();
+            ++it)
+        {
+            if ((*it)->m_strObjName == strObjectName)
+            {
+                m_pModel->m_pCurrent = *it;
+                break;
+            }
+        }
+
+        // Allocate a new object, if current one was not found before
+        if( NULL == m_pModel->m_pCurrent ) {
+            createObject( strObjectName );
+        }
+    }
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+// -------------------------------------------------------------------
+//  Creates a new object instance
+void ObjFileParser::createObject(const std::string &objName)
+{
+    ai_assert( NULL != m_pModel );
+
+    m_pModel->m_pCurrent = new ObjFile::Object;
+    m_pModel->m_pCurrent->m_strObjName = objName;
+    m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
+
+    createMesh( objName  );
+
+    if( m_pModel->m_pCurrentMaterial )
+    {
+        m_pModel->m_pCurrentMesh->m_uiMaterialIndex =
+            getMaterialIndex( m_pModel->m_pCurrentMaterial->MaterialName.data );
+        m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
+    }
+}
+// -------------------------------------------------------------------
+//  Creates a new mesh
+void ObjFileParser::createMesh( const std::string &meshName )
+{
+    ai_assert( NULL != m_pModel );
+    m_pModel->m_pCurrentMesh = new ObjFile::Mesh( meshName );
+    m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
+    unsigned int meshId = static_cast<unsigned int>(m_pModel->m_Meshes.size()-1);
+    if ( NULL != m_pModel->m_pCurrent )
+    {
+        m_pModel->m_pCurrent->m_Meshes.push_back( meshId );
+    }
+    else
+    {
+        ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
+    }
+}
+
+// -------------------------------------------------------------------
+//  Returns true, if a new mesh must be created.
+bool ObjFileParser::needsNewMesh( const std::string &materialName )
+{
+    // If no mesh data yet
+    if(m_pModel->m_pCurrentMesh == 0)
+    {
+        return true;
+    }
+    bool newMat = false;
+    int matIdx = getMaterialIndex( materialName );
+    int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
+    if ( curMatIdx != int(ObjFile::Mesh::NoMaterial)
+        && curMatIdx != matIdx
+        // no need create a new mesh if no faces in current
+        // lets say 'usemtl' goes straight after 'g'
+        && m_pModel->m_pCurrentMesh->m_Faces.size() > 0 )
+    {
+        // New material -> only one material per mesh, so we need to create a new
+        // material
+        newMat = true;
+    }
+    return newMat;
+}
+
+// -------------------------------------------------------------------
+//  Shows an error in parsing process.
+void ObjFileParser::reportErrorTokenInFace()
+{
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    ASSIMP_LOG_ERROR("OBJ: Not supported token in face description detected");
+}
+
+// -------------------------------------------------------------------
+
+}   // Namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER

+ 165 - 0
Engine/lib/assimp/code/Obj/ObjFileParser.h

@@ -0,0 +1,165 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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 OBJ_FILEPARSER_H_INC
+#define OBJ_FILEPARSER_H_INC
+
+#include <vector>
+#include <string>
+#include <map>
+#include <memory>
+#include <assimp/vector2.h>
+#include <assimp/vector3.h>
+#include <assimp/mesh.h>
+#include <assimp/IOStreamBuffer.h>
+
+namespace Assimp {
+
+namespace ObjFile {
+    struct Model;
+    struct Object;
+    struct Material;
+    struct Point3;
+    struct Point2;
+}
+
+class ObjFileImporter;
+class IOSystem;
+class ProgressHandler;
+
+/// \class  ObjFileParser
+/// \brief  Parser for a obj waveform file
+class ASSIMP_API ObjFileParser {
+public:
+    static const size_t Buffersize = 4096;
+    typedef std::vector<char> DataArray;
+    typedef std::vector<char>::iterator DataArrayIt;
+    typedef std::vector<char>::const_iterator ConstDataArrayIt;
+
+public:
+    /// @brief  The default constructor.
+    ObjFileParser();
+    /// @brief  Constructor with data array.
+    ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::string &modelName, IOSystem* io, ProgressHandler* progress, const std::string &originalObjFileName);
+    /// @brief  Destructor
+    ~ObjFileParser();
+    /// @brief  If you want to load in-core data.
+    void setBuffer( std::vector<char> &buffer );
+    /// @brief  Model getter.
+    ObjFile::Model *GetModel() const;
+
+protected:
+    /// Parse the loaded file
+    void parseFile( IOStreamBuffer<char> &streamBuffer );
+    /// Method to copy the new delimited word in the current line.
+    void copyNextWord(char *pBuffer, size_t length);
+    /// Method to copy the new line.
+//    void copyNextLine(char *pBuffer, size_t length);
+    /// Get the number of components in a line.
+    size_t getNumComponentsInDataDefinition();
+    /// Stores the vector
+    size_t getTexCoordVector( std::vector<aiVector3D> &point3d_array );
+    /// Stores the following 3d vector.
+    void getVector3( std::vector<aiVector3D> &point3d_array );
+    /// Stores the following homogeneous vector as a 3D vector
+    void getHomogeneousVector3( std::vector<aiVector3D> &point3d_array );
+    /// Stores the following two 3d vectors on the line.
+    void getTwoVectors3( std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b );
+    /// Stores the following 3d vector.
+    void getVector2(std::vector<aiVector2D> &point2d_array);
+    /// Stores the following face.
+    void getFace(aiPrimitiveType type);
+    /// Reads the material description.
+    void getMaterialDesc();
+    /// Gets a comment.
+    void getComment();
+    /// Gets a a material library.
+    void getMaterialLib();
+    /// Creates a new material.
+    void getNewMaterial();
+    /// Gets the group name from file.
+    void getGroupName();
+    /// Gets the group number from file.
+    void getGroupNumber();
+    /// Gets the group number and resolution from file.
+    void getGroupNumberAndResolution();
+    /// Returns the index of the material. Is -1 if not material was found.
+    int getMaterialIndex( const std::string &strMaterialName );
+    /// Parse object name
+    void getObjectName();
+    /// Creates a new object.
+    void createObject( const std::string &strObjectName );
+    /// Creates a new mesh.
+    void createMesh( const std::string &meshName );
+    /// Returns true, if a new mesh instance must be created.
+    bool needsNewMesh( const std::string &rMaterialName );
+    /// Error report in token
+    void reportErrorTokenInFace();
+
+private:
+    // Copy and assignment constructor should be private
+    // because the class contains pointer to allocated memory
+    ObjFileParser(const ObjFileParser& rhs);
+    ObjFileParser& operator=(const ObjFileParser& rhs);
+
+    /// Default material name
+    static const std::string DEFAULT_MATERIAL;
+    //! Iterator to current position in buffer
+    DataArrayIt m_DataIt;
+    //! Iterator to end position of buffer
+    DataArrayIt m_DataItEnd;
+    //! Pointer to model instance
+    std::unique_ptr<ObjFile::Model> m_pModel;
+    //! Current line (for debugging)
+    unsigned int m_uiLine;
+    //! Helper buffer
+    char m_buffer[Buffersize];
+    /// Pointer to IO system instance.
+    IOSystem *m_pIO;
+    //! Pointer to progress handler
+    ProgressHandler* m_progress;
+    /// Path to the current model, name of the obj file where the buffer comes from
+    const std::string m_originalObjFileName;
+};
+
+}   // Namespace Assimp
+
+#endif

+ 308 - 0
Engine/lib/assimp/code/Obj/ObjTools.h

@@ -0,0 +1,308 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+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   ObjTools.h
+ *  @brief  Some helpful templates for text parsing
+ */
+#ifndef OBJ_TOOLS_H_INC
+#define OBJ_TOOLS_H_INC
+
+#include <assimp/fast_atof.h>
+#include <assimp/ParsingUtils.h>
+#include <vector>
+
+namespace Assimp {
+
+/** @brief  Returns true, if the last entry of the buffer is reached.
+ *  @param  it  Iterator of current position.
+ *  @param  end Iterator with end of buffer.
+ *  @return true, if the end of the buffer is reached.
+ */
+template<class char_t>
+inline bool isEndOfBuffer(  char_t it, char_t end ) {
+    if ( it == end )
+    {
+        return true;
+    }
+    else
+    {
+        --end;
+    }
+    return ( it == end );
+}
+
+/** @brief  Returns next word separated by a space
+ *  @param  pBuffer Pointer to data buffer
+ *  @param  pEnd    Pointer to end of buffer
+ *  @return Pointer to next space
+ */
+template<class Char_T>
+inline Char_T getNextWord( Char_T pBuffer, Char_T pEnd )
+{
+    while ( !isEndOfBuffer( pBuffer, pEnd ) )
+    {
+        if ( !IsSpaceOrNewLine( *pBuffer ) || IsLineEnd( *pBuffer ) ) {
+            //if ( *pBuffer != '\\' )
+                break;
+        }
+        pBuffer++;
+    }
+    return pBuffer;
+}
+
+/** @brief  Returns pointer a next token
+ *  @param  pBuffer Pointer to data buffer
+ *  @param  pEnd    Pointer to end of buffer
+ *  @return Pointer to next token
+ */
+template<class Char_T>
+inline Char_T getNextToken( Char_T pBuffer, Char_T pEnd )
+{
+    while ( !isEndOfBuffer( pBuffer, pEnd ) )
+    {
+        if( IsSpaceOrNewLine( *pBuffer ) )
+            break;
+        pBuffer++;
+    }
+    return getNextWord( pBuffer, pEnd );
+}
+
+/** @brief  Skips a line
+ *  @param  it      Iterator set to current position
+ *  @param  end     Iterator set to end of scratch buffer for readout
+ *  @param  uiLine  Current line number in format
+ *  @return Current-iterator with new position
+ */
+template<class char_t>
+inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) {
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
+        ++it;
+    }
+    
+    if ( it != end ) {
+        ++it;
+        ++uiLine;
+    }
+    // fix .. from time to time there are spaces at the beginning of a material line
+    while ( it != end && ( *it == '\t' || *it == ' ' ) ) {
+        ++it;
+    }
+
+    return it;
+}
+
+/** @brief  Get a name from the current line. Preserve space in the middle,
+ *    but trim it at the end.
+ *  @param  it      set to current position
+ *  @param  end     set to end of scratch buffer for readout
+ *  @param  name    Separated name
+ *  @return Current-iterator with new position
+ */
+template<class char_t>
+inline char_t getName( char_t it, char_t end, std::string &name )
+{
+    name = "";
+    if( isEndOfBuffer( it, end ) ) {
+        return end;
+    }
+
+    char *pStart = &( *it );
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it )) {
+        ++it;
+    }
+
+    while(IsSpace( *it ) ) {
+        --it;
+    }
+    // Get name
+    // if there is no name, and the previous char is a separator, come back to start
+    while (&(*it) < pStart) {
+        ++it;
+    }
+    std::string strName( pStart, &(*it) );
+    if ( strName.empty() )
+        return it;
+    else
+        name = strName;
+
+    return it;
+}
+
+/** @brief  Get a name from the current line. Do not preserve space
+ *    in the middle, but trim it at the end.
+ *  @param  it      set to current position
+ *  @param  end     set to end of scratch buffer for readout
+ *  @param  name    Separated name
+ *  @return Current-iterator with new position
+ */
+template<class char_t>
+inline char_t getNameNoSpace( char_t it, char_t end, std::string &name )
+{
+    name = "";
+    if( isEndOfBuffer( it, end ) ) {
+        return end;
+    }
+
+    char *pStart = &( *it );
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it )
+          && !IsSpaceOrNewLine( *it ) ) {
+        ++it;
+    }
+
+    while( isEndOfBuffer( it, end ) || IsLineEnd( *it )
+          || IsSpaceOrNewLine( *it ) ) {
+        --it;
+    }
+    ++it;
+
+    // Get name
+    // if there is no name, and the previous char is a separator, come back to start
+    while (&(*it) < pStart) {
+        ++it;
+    }
+    std::string strName( pStart, &(*it) );
+    if ( strName.empty() )
+        return it;
+    else
+        name = strName;
+
+    return it;
+}
+
+/** @brief  Get next word from given line
+ *  @param  it      set to current position
+ *  @param  end     set to end of scratch buffer for readout
+ *  @param  pBuffer Buffer for next word
+ *  @param  length  Buffer length
+ *  @return Current-iterator with new position
+ */
+template<class char_t>
+inline char_t CopyNextWord( char_t it, char_t end, char *pBuffer, size_t length )
+{
+    size_t index = 0;
+    it = getNextWord<char_t>( it, end );
+    while( !IsSpaceOrNewLine( *it ) && !isEndOfBuffer( it, end ) )
+    {
+        pBuffer[index] = *it ;
+        index++;
+        if (index == length-1)
+            break;
+        ++it;
+    }
+    pBuffer[ index ] = '\0';
+    return it;
+}
+
+/** @brief  Get next float from given line
+ *  @param  it      set to current position
+ *  @param  end     set to end of scratch buffer for readout
+ *  @param  value   Separated float value.
+ *  @return Current-iterator with new position
+ */
+template<class char_t>
+inline char_t getFloat( char_t it, char_t end, ai_real &value )
+{
+    static const size_t BUFFERSIZE = 1024;
+    char buffer[ BUFFERSIZE ];
+    it = CopyNextWord<char_t>( it, end, buffer, BUFFERSIZE );
+    value = (ai_real) fast_atof( buffer );
+
+    return it;
+}
+
+/** @brief  Will perform a simple tokenize.
+ *  @param  str         String to tokenize.
+ *  @param  tokens      Array with tokens, will be empty if no token was found.
+ *  @param  delimiters  Delimiter for tokenize.
+ *  @return Number of found token.
+ */
+template<class string_type>
+unsigned int tokenize( const string_type& str, std::vector<string_type>& tokens,
+                         const string_type& delimiters )
+{
+    // Skip delimiters at beginning.
+    typename string_type::size_type lastPos = str.find_first_not_of( delimiters, 0 );
+
+    // Find first "non-delimiter".
+    typename string_type::size_type pos = str.find_first_of( delimiters, lastPos );
+    while ( string_type::npos != pos || string_type::npos != lastPos )
+    {
+        // Found a token, add it to the vector.
+        string_type tmp = str.substr(lastPos, pos - lastPos);
+        if ( !tmp.empty() && ' ' != tmp[ 0 ] )
+            tokens.push_back( tmp );
+
+        // Skip delimiters.  Note the "not_of"
+        lastPos = str.find_first_not_of( delimiters, pos );
+
+        // Find next "non-delimiter"
+        pos = str.find_first_of( delimiters, lastPos );
+    }
+
+    return static_cast<unsigned int>( tokens.size() );
+}
+
+template <class string_type>
+string_type trim_whitespaces(string_type str)
+{
+    while (!str.empty() && IsSpace(str[0])) str.erase(0);
+    while (!str.empty() && IsSpace(str[str.length() - 1])) str.erase(str.length() - 1);
+    return str;
+}
+
+template<class T>
+bool hasLineEnd( T it, T end ) {
+    bool hasLineEnd( false );
+    while ( !isEndOfBuffer( it, end ) ) {
+        it++;
+        if ( IsLineEnd( it ) ) {
+            hasLineEnd = true;
+            break;
+        }
+    }
+
+    return hasLineEnd;
+}
+
+} // Namespace Assimp
+
+#endif // OBJ_TOOLS_H_INC

+ 3 - 3
Templates/BaseGame/game/tools/gui/profiles.ed.cs

@@ -282,9 +282,9 @@ new GuiControlProfile( ToolsGuiTextEditProfile )
    fillColorSEL = EditorSettings.value("Theme/fieldBGSELColor");
    
    fontColor = EditorSettings.value("Theme/fieldTextColor");
-   fontColorHL = EditorSettings.value("Theme/fieldTextHLColor");
-   fontColorSEL = EditorSettings.value("Theme/fieldTextSELColor");
-   fontColorNA = "200 200 200";
+   fontColorSEL = EditorSettings.value("Theme/fieldBGSELColor");
+   fontColorHL = EditorSettings.value("Theme/fieldTextSELColor");
+   fontColorNA = EditorSettings.value("Theme/fieldTextSELColor");
    textOffset = "4 2";
    autoSizeWidth = false;
    autoSizeHeight = true;

+ 196 - 196
Templates/BaseGame/game/tools/settings.xml

@@ -1,254 +1,254 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <EditorSettings>
-    <Group name="Theme">
-        <Setting name="tooltipDividerColor">72 70 68 255</Setting>
-        <Setting name="fieldTextHLColor">234 232 230 255</Setting>
-        <Setting name="windowBackgroundColor">32 31 30 255</Setting>
-        <Setting name="tooltipBGColor">43 43 43 255</Setting>
-        <Setting name="tabsColor">37 36 35 255</Setting>
-        <Setting name="tooltipTextColor">255 255 255 255</Setting>
-        <Setting name="dividerMidColor">50 49 48 255</Setting>
-        <Setting name="tabsHLColor">50 49 48 255</Setting>
-        <Setting name="dividerDarkColor">17 16 15 255</Setting>
-        <Setting name="fieldTextNAColor">77 77 77 255</Setting>
-        <Setting name="fieldBGHLColor">72 70 68 255</Setting>
-        <Setting name="fieldBGSELColor">100 98 96 255</Setting>
-        <Setting name="fieldTextColor">178 175 172 255</Setting>
-        <Setting name="headerTextColor">236 234 232 255</Setting>
-        <Setting name="fieldBGColor">59 58 57 255</Setting>
-        <Setting name="headerColor">50 49 48 255</Setting>
-        <Setting name="dividerLightColor">96 94 92 255</Setting>
-        <Setting name="tabsSELColor">59 58 57 255</Setting>
-        <Setting name="fieldTextSELColor">255 255 255 255</Setting>
+    <Group name="NavEditor">
+        <Setting name="spawnDatablock">DefaultPlayerData</Setting>
+        <Setting name="backgroundBuild">1</Setting>
+        <Setting name="SpawnClass">AIPlayer</Setting>
     </Group>
-    <Group name="ShapeEditor">
-        <Setting name="AdvancedWndVisible">1</Setting>
-        <Setting name="SunAngleZ">135</Setting>
-        <Setting name="backgroundColor">0 0 0 100</Setting>
-        <Setting name="showNodes">1</Setting>
-        <Setting name="renderMounts">1</Setting>
-        <Setting name="showBounds">0</Setting>
-        <Setting name="SunAmbientColor">180 180 180 255</Setting>
-        <Setting name="ShowGrid">1</Setting>
-        <Setting name="highlightMaterial">1</Setting>
-        <Setting name="SunDiffuseColor">255 255 255 255</Setting>
-        <Setting name="gridSize">0.1</Setting>
-        <Setting name="gridDimension">40 40</Setting>
-        <Setting name="showObjBox">1</Setting>
-        <Setting name="RenderCollision">0</Setting>
-        <Setting name="SunAngleX">45</Setting>
+    <Group name="GuiEditor">
+        <Setting name="previewResolution">1024 768</Setting>
+        <Setting name="lastPath">tools/gui/messageBoxes</Setting>
+        <Group name="Snapping">
+            <Setting name="sensitivity">2</Setting>
+            <Setting name="snapToGuides">1</Setting>
+            <Setting name="snap2GridSize">8</Setting>
+            <Setting name="snapToCenters">1</Setting>
+            <Setting name="snapToEdges">1</Setting>
+            <Setting name="snap2Grid">0</Setting>
+            <Setting name="snapToCanvas">1</Setting>
+            <Setting name="snapToControls">1</Setting>
+        </Group>
+        <Group name="Rendering">
+            <Setting name="drawBorderLines">1</Setting>
+            <Setting name="drawGuides">1</Setting>
+        </Group>
+        <Group name="Help">
+            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
+            <Setting name="documentationLocal">../../../Documentation/Official Documentation.html</Setting>
+            <Setting name="documentationReference">../../../Documentation/Torque 3D - Script Manual.chm</Setting>
+        </Group>
+        <Group name="Selection">
+            <Setting name="fullBox">0</Setting>
+        </Group>
+        <Group name="EngineDevelopment">
+            <Setting name="showEditorProfiles">0</Setting>
+            <Setting name="showEditorGuis">0</Setting>
+            <Setting name="toggleIntoEditor">0</Setting>
+        </Group>
+        <Group name="Library">
+            <Setting name="viewType">Categorized</Setting>
+        </Group>
+    </Group>
+    <Group name="TerrainEditor">
+        <Setting name="currentAction">lowerHeight</Setting>
+        <Group name="ActionValues">
+            <Setting name="setHeightVal">100</Setting>
+            <Setting name="adjustHeightVal">10</Setting>
+            <Setting name="smoothFactor">0.1</Setting>
+            <Setting name="softSelectRadius">50</Setting>
+            <Setting name="scaleVal">1</Setting>
+            <Setting name="SlopeMinAngle">0</Setting>
+            <Setting name="softSelectDefaultFilter">1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000</Setting>
+            <Setting name="softSelectFilter">1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000</Setting>
+            <Setting name="noiseFactor">1</Setting>
+            <Setting name="SlopeMaxAngle">90</Setting>
+        </Group>
+        <Group name="Brush">
+            <Setting name="maxBrushSize">40 40</Setting>
+            <Setting name="brushSize">40 40</Setting>
+            <Setting name="brushPressure">1</Setting>
+            <Setting name="brushType">ellipse</Setting>
+            <Setting name="brushSoftness">1</Setting>
+        </Group>
+    </Group>
+    <Group name="AxisGizmo">
+        <Setting name="mouseRotateScalar">0.8</Setting>
+        <Setting name="axisGizmoMaxScreenLen">100</Setting>
+        <Setting name="rotationSnap">15</Setting>
+        <Setting name="mouseScaleScalar">0.8</Setting>
+        <Setting name="renderWhenUsed">0</Setting>
+        <Setting name="renderInfoText">1</Setting>
+        <Setting name="snapRotations">0</Setting>
+        <Group name="Grid">
+            <Setting name="renderPlane">0</Setting>
+            <Setting name="gridSize">1 1 1</Setting>
+            <Setting name="renderPlaneHashes">0</Setting>
+            <Setting name="snapToGrid">1</Setting>
+            <Setting name="gridColor">255 255 255 20</Setting>
+            <Setting name="planeDim">500</Setting>
+        </Group>
     </Group>
     <Group name="WorldEditor">
-        <Setting name="EditorLayoutMode">Modern</Setting>
+        <Setting name="currentEditor">WorldEditorInspectorPlugin</Setting>
+        <Setting name="torsionPath">AssetWork_Debug.exe</Setting>
+        <Setting name="undoLimit">40</Setting>
         <Setting name="dropType">screenCenter</Setting>
-        <Setting name="orthoShowGrid">1</Setting>
         <Setting name="displayType">6</Setting>
-        <Setting name="currentEditor">WorldEditorInspectorPlugin</Setting>
         <Setting name="forceLoadDAE">0</Setting>
-        <Setting name="torsionPath">AssetWork_Debug.exe</Setting>
         <Setting name="orthoFOV">50</Setting>
-        <Setting name="undoLimit">40</Setting>
-        <Group name="ObjectIcons">
-            <Setting name="fadeIcons">1</Setting>
-            <Setting name="fadeIconsStartDist">8</Setting>
-            <Setting name="fadeIconsEndDist">20</Setting>
-            <Setting name="fadeIconsEndAlpha">0</Setting>
-            <Setting name="fadeIconsStartAlpha">255</Setting>
-        </Group>
-        <Group name="Render">
-            <Setting name="showMousePopupInfo">1</Setting>
-            <Setting name="renderObjHandle">1</Setting>
-            <Setting name="renderSelectionBox">1</Setting>
-            <Setting name="renderPopupBackground">1</Setting>
-            <Setting name="renderObjText">1</Setting>
-        </Group>
-        <Group name="Theme">
-            <Setting name="windowTitleBGColor">50 50 50 255</Setting>
-            <Setting name="windowTitleBGNAColor">180 180 180 255</Setting>
-            <Setting name="windowTitleFontHLColor">255 255 255 255</Setting>
-            <Setting name="windowTitleFontColor">215 215 215 255</Setting>
-            <Setting name="windowTitleBGHLColor">48 48 48 255</Setting>
+        <Setting name="EditorLayoutMode">Modern</Setting>
+        <Setting name="orthoShowGrid">1</Setting>
+        <Group name="Color">
+            <Setting name="dragRectColor">255 255 0 255</Setting>
+            <Setting name="objSelectColor">255 0 0 255</Setting>
+            <Setting name="objMouseOverColor">0 255 0 255</Setting>
+            <Setting name="popupBackgroundColor">100 100 100 255</Setting>
+            <Setting name="selectionBoxColor">255 255 0 255</Setting>
+            <Setting name="objectTextColor">255 255 255 255</Setting>
+            <Setting name="objMouseOverSelectColor">0 0 255 255</Setting>
         </Group>
         <Group name="Grid">
             <Setting name="gridSize">1</Setting>
-            <Setting name="gridSnap">1</Setting>
             <Setting name="gridColor">102 102 102 100</Setting>
-            <Setting name="gridOriginColor">255 255 255 100</Setting>
             <Setting name="gridMinorColor">51 51 51 100</Setting>
+            <Setting name="gridSnap">1</Setting>
+            <Setting name="gridOriginColor">255 255 255 100</Setting>
+        </Group>
+        <Group name="Theme">
+            <Setting name="windowTitleBGNAColor">180 180 180 255</Setting>
+            <Setting name="windowTitleBGHLColor">48 48 48 255</Setting>
+            <Setting name="windowTitleBGColor">50 50 50 255</Setting>
+            <Setting name="windowTitleFontColor">215 215 215 255</Setting>
+            <Setting name="windowTitleFontHLColor">255 255 255 255</Setting>
         </Group>
         <Group name="Docs">
+            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
             <Setting name="documentationReference">../../../Documentation/Torque 3D - Script Manual.chm</Setting>
-            <Setting name="forumURL">http://www.garagegames.com/products/torque-3d/forums</Setting>
             <Setting name="documentationLocal">../../../Documentation/Official Documentation.html</Setting>
-            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
+            <Setting name="forumURL">http://www.garagegames.com/products/torque-3d/forums</Setting>
         </Group>
-        <Group name="Color">
-            <Setting name="objectTextColor">255 255 255 255</Setting>
-            <Setting name="popupBackgroundColor">100 100 100 255</Setting>
-            <Setting name="objSelectColor">255 0 0 255</Setting>
-            <Setting name="objMouseOverSelectColor">0 0 255 255</Setting>
-            <Setting name="selectionBoxColor">255 255 0 255</Setting>
-            <Setting name="objMouseOverColor">0 255 0 255</Setting>
-            <Setting name="dragRectColor">255 255 0 255</Setting>
+        <Group name="Render">
+            <Setting name="renderSelectionBox">1</Setting>
+            <Setting name="renderObjHandle">1</Setting>
+            <Setting name="renderObjText">1</Setting>
+            <Setting name="showMousePopupInfo">1</Setting>
+            <Setting name="renderPopupBackground">1</Setting>
+        </Group>
+        <Group name="ObjectIcons">
+            <Setting name="fadeIconsEndAlpha">0</Setting>
+            <Setting name="fadeIconsEndDist">20</Setting>
+            <Setting name="fadeIconsStartDist">8</Setting>
+            <Setting name="fadeIcons">1</Setting>
+            <Setting name="fadeIconsStartAlpha">255</Setting>
+        </Group>
+        <Group name="Images">
+            <Setting name="selectHandle">tools/worldEditor/images/SelectHandle</Setting>
+            <Setting name="defaultHandle">tools/worldEditor/images/DefaultHandle</Setting>
+            <Setting name="lockedHandle">tools/worldEditor/images/LockedHandle</Setting>
         </Group>
         <Group name="Tools">
-            <Setting name="snapSoft">0</Setting>
+            <Setting name="OffsetZValue">0.01</Setting>
+            <Setting name="boundingBoxCollision">0</Setting>
             <Setting name="snapGround">0</Setting>
-            <Setting name="TerrainSnapOffsetZ">0</Setting>
+            <Setting name="objectsUseBoxCenter">1</Setting>
             <Setting name="snapSoftSize">2</Setting>
-            <Setting name="boundingBoxCollision">0</Setting>
-            <Setting name="dropAtScreenCenterMax">100</Setting>
+            <Setting name="snapSoft">0</Setting>
             <Setting name="dropAtScreenCenterScalar">1</Setting>
-            <Setting name="objectsUseBoxCenter">1</Setting>
-            <Setting name="OffsetZValue">0.01</Setting>
-        </Group>
-        <Group name="Images">
-            <Setting name="lockedHandle">tools/worldEditor/images/LockedHandle</Setting>
-            <Setting name="defaultHandle">tools/worldEditor/images/DefaultHandle</Setting>
-            <Setting name="selectHandle">tools/worldEditor/images/SelectHandle</Setting>
+            <Setting name="TerrainSnapOffsetZ">0</Setting>
+            <Setting name="dropAtScreenCenterMax">100</Setting>
         </Group>
         <Group name="Layout">
             <Setting name="LayoutMode">Classic</Setting>
         </Group>
     </Group>
-    <Group name="AxisGizmo">
-        <Setting name="rotationSnap">15</Setting>
-        <Setting name="snapRotations">0</Setting>
-        <Setting name="mouseScaleScalar">0.8</Setting>
-        <Setting name="mouseRotateScalar">0.8</Setting>
-        <Setting name="renderWhenUsed">0</Setting>
-        <Setting name="axisGizmoMaxScreenLen">100</Setting>
-        <Setting name="renderInfoText">1</Setting>
-        <Group name="Grid">
-            <Setting name="snapToGrid">1</Setting>
-            <Setting name="renderPlane">0</Setting>
-            <Setting name="gridColor">255 255 255 20</Setting>
-            <Setting name="gridSize">1 1 1</Setting>
-            <Setting name="planeDim">500</Setting>
-            <Setting name="renderPlaneHashes">0</Setting>
-        </Group>
+    <Group name="ShapeEditor">
+        <Setting name="SunAngleZ">135</Setting>
+        <Setting name="gridSize">0.1</Setting>
+        <Setting name="showNodes">1</Setting>
+        <Setting name="showObjBox">1</Setting>
+        <Setting name="showBounds">0</Setting>
+        <Setting name="SunAngleX">45</Setting>
+        <Setting name="ShowGrid">1</Setting>
+        <Setting name="AdvancedWndVisible">1</Setting>
+        <Setting name="SunDiffuseColor">255 255 255 255</Setting>
+        <Setting name="backgroundColor">0 0 0 100</Setting>
+        <Setting name="gridDimension">40 40</Setting>
+        <Setting name="renderMounts">1</Setting>
+        <Setting name="RenderCollision">0</Setting>
+        <Setting name="SunAmbientColor">180 180 180 255</Setting>
+        <Setting name="highlightMaterial">1</Setting>
     </Group>
-    <Group name="RiverEditor">
-        <Setting name="HoverSplineColor">255 0 0 255</Setting>
+    <Group name="ConvexEditor">
+        <Setting name="materialName">Grid_512_Orange</Setting>
+    </Group>
+    <Group name="MeshRoadEditor">
         <Setting name="DefaultWidth">10</Setting>
-        <Setting name="DefaultDepth">5</Setting>
         <Setting name="SelectedSplineColor">0 255 0 255</Setting>
-        <Setting name="HoverNodeColor">255 255 255 255</Setting>
+        <Setting name="sideMaterialName">DefaultRoadMaterialOther</Setting>
+        <Setting name="HoverSplineColor">255 0 0 255</Setting>
+        <Setting name="topMaterialName">DefaultRoadMaterialTop</Setting>
         <Setting name="DefaultNormal">0 0 1</Setting>
     </Group>
-    <Group name="TerrainEditor">
-        <Setting name="currentAction">lowerHeight</Setting>
-        <Group name="Brush">
-            <Setting name="maxBrushSize">40 40</Setting>
-            <Setting name="brushSoftness">1</Setting>
-            <Setting name="brushPressure">1</Setting>
-            <Setting name="brushSize">40 40</Setting>
-            <Setting name="brushType">ellipse</Setting>
-        </Group>
-        <Group name="ActionValues">
-            <Setting name="softSelectRadius">50</Setting>
-            <Setting name="adjustHeightVal">10</Setting>
-            <Setting name="SlopeMaxAngle">90</Setting>
-            <Setting name="noiseFactor">1</Setting>
-            <Setting name="SlopeMinAngle">0</Setting>
-            <Setting name="smoothFactor">0.1</Setting>
-            <Setting name="setHeightVal">100</Setting>
-            <Setting name="softSelectFilter">1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000</Setting>
-            <Setting name="softSelectDefaultFilter">1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000</Setting>
-            <Setting name="scaleVal">1</Setting>
-        </Group>
-    </Group>
     <Group name="AssetCreation">
+        <Setting name="AssetImporDefaultConfig">TestConfig</Setting>
         <Setting name="PostFXAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
-        <Setting name="TerrainAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
-        <Setting name="AutoImport">1</Setting>
-        <Setting name="TerrainMatAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
         <Setting name="CppAssetSubdirectoryFormat">&lt;AssetType&gt;/&lt;SpecialAssetTag&gt;/</Setting>
-        <Setting name="GUIAssetSubdirectoryFormat">&lt;AssetType&gt;/OtherFolder/</Setting>
-        <Setting name="StatemachineAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
-        <Setting name="CubemapAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
-        <Setting name="LevelAssetSubdirectoryFormat">&lt;AssetType&gt;/&lt;AssetName&gt;/</Setting>
         <Setting name="ScriptAssetSubdirectoryFormat">&lt;AssetType&gt;/&lt;SpecialAssetTag&gt;/</Setting>
-        <Setting name="AssetImporDefaultConfig">TestConfig</Setting>
-    </Group>
-    <Group name="GuiEditor">
-        <Setting name="lastPath">tools/gui/messageBoxes</Setting>
-        <Setting name="previewResolution">1024 768</Setting>
-        <Group name="EngineDevelopment">
-            <Setting name="toggleIntoEditor">0</Setting>
-            <Setting name="showEditorGuis">0</Setting>
-            <Setting name="showEditorProfiles">0</Setting>
-        </Group>
-        <Group name="Help">
-            <Setting name="documentationLocal">../../../Documentation/Official Documentation.html</Setting>
-            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
-            <Setting name="documentationReference">../../../Documentation/Torque 3D - Script Manual.chm</Setting>
-        </Group>
-        <Group name="Rendering">
-            <Setting name="drawGuides">1</Setting>
-            <Setting name="drawBorderLines">1</Setting>
-        </Group>
-        <Group name="Snapping">
-            <Setting name="snapToCanvas">1</Setting>
-            <Setting name="snapToCenters">1</Setting>
-            <Setting name="sensitivity">2</Setting>
-            <Setting name="snap2Grid">0</Setting>
-            <Setting name="snap2GridSize">8</Setting>
-            <Setting name="snapToControls">1</Setting>
-            <Setting name="snapToEdges">1</Setting>
-            <Setting name="snapToGuides">1</Setting>
-        </Group>
-        <Group name="Library">
-            <Setting name="viewType">Categorized</Setting>
-        </Group>
-        <Group name="Selection">
-            <Setting name="fullBox">0</Setting>
-        </Group>
+        <Setting name="TerrainMatAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
+        <Setting name="LevelAssetSubdirectoryFormat">&lt;AssetType&gt;/&lt;AssetName&gt;/</Setting>
+        <Setting name="CubemapAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
+        <Setting name="StatemachineAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
+        <Setting name="AutoImport">1</Setting>
+        <Setting name="TerrainAssetSubdirectoryFormat">&lt;AssetType&gt;/</Setting>
+        <Setting name="GUIAssetSubdirectoryFormat">&lt;AssetType&gt;/OtherFolder/</Setting>
     </Group>
-    <Group name="MeshRoadEditor">
+    <Group name="RiverEditor">
+        <Setting name="DefaultDepth">5</Setting>
+        <Setting name="HoverNodeColor">255 255 255 255</Setting>
         <Setting name="DefaultWidth">10</Setting>
-        <Setting name="topMaterialName">DefaultRoadMaterialTop</Setting>
-        <Setting name="sideMaterialName">DefaultRoadMaterialOther</Setting>
+        <Setting name="SelectedSplineColor">0 255 0 255</Setting>
         <Setting name="DefaultNormal">0 0 1</Setting>
         <Setting name="HoverSplineColor">255 0 0 255</Setting>
-        <Setting name="SelectedSplineColor">0 255 0 255</Setting>
     </Group>
-    <Group name="Assets">
-        <Setting name="AutoImport">1</Setting>
-        <Setting name="AssetImporDefaultConfig">TestConfig</Setting>
-        <Group name="Browser">
-            <Setting name="previewTileSize">small</Setting>
-        </Group>
+    <Group name="AssetBrowser">
+        <Setting name="previewSize">Small</Setting>
+    </Group>
+    <Group name="RoadEditor">
+        <Setting name="HoverNodeColor">255 255 255 255</Setting>
+        <Setting name="SelectedSplineColor">0 255 0 255</Setting>
+        <Setting name="materialName">DefaultDecalRoadMaterial</Setting>
+        <Setting name="DefaultWidth">10</Setting>
     </Group>
     <Group name="LevelInformation">
         <Setting name="levelsDirectory">data/FPSGameplay/levels</Setting>
         <Group name="levels">
-            <Group name="PbrMatTest.mis">
-                <Setting name="cameraSpeed">5</Setting>
-            </Group>
             <Group name="BlankRoom.mis">
                 <Setting name="cameraSpeed">25</Setting>
             </Group>
+            <Group name="PbrMatTest.mis">
+                <Setting name="cameraSpeed">5</Setting>
+            </Group>
         </Group>
     </Group>
-    <Group name="ConvexEditor">
-        <Setting name="materialName">Grid_512_Orange</Setting>
-    </Group>
-    <Group name="RoadEditor">
-        <Setting name="materialName">DefaultDecalRoadMaterial</Setting>
-        <Setting name="HoverNodeColor">255 255 255 255</Setting>
-        <Setting name="DefaultWidth">10</Setting>
-        <Setting name="SelectedSplineColor">0 255 0 255</Setting>
+    <Group name="Theme">
+        <Setting name="fieldTextHLColor">234 232 230 255</Setting>
+        <Setting name="tooltipTextColor">255 255 255 255</Setting>
+        <Setting name="fieldTextNAColor">77 77 77 255</Setting>
+        <Setting name="tabsHLColor">50 49 48 255</Setting>
+        <Setting name="tooltipBGColor">43 43 43 255</Setting>
+        <Setting name="fieldBGSELColor">100 98 96 255</Setting>
+        <Setting name="tabsSELColor">59 58 57 255</Setting>
+        <Setting name="headerColor">50 49 48 255</Setting>
+        <Setting name="headerTextColor">236 234 232 255</Setting>
+        <Setting name="tooltipDividerColor">72 70 68 255</Setting>
+        <Setting name="windowBackgroundColor">32 31 30 255</Setting>
+        <Setting name="dividerDarkColor">17 16 15 255</Setting>
+        <Setting name="dividerMidColor">50 49 48 255</Setting>
+        <Setting name="fieldBGHLColor">72 70 68 255</Setting>
+        <Setting name="tabsColor">37 36 35 255</Setting>
+        <Setting name="fieldTextSELColor">255 255 255 255</Setting>
+        <Setting name="dividerLightColor">96 94 92 255</Setting>
+        <Setting name="fieldTextColor">178 175 172 255</Setting>
+        <Setting name="fieldBGColor">59 58 57 255</Setting>
     </Group>
-    <Group name="NavEditor">
-        <Setting name="SpawnClass">AIPlayer</Setting>
-        <Setting name="backgroundBuild">1</Setting>
-        <Setting name="spawnDatablock">DefaultPlayerData</Setting>
+    <Group name="Assets">
+        <Setting name="AssetImporDefaultConfig">TestConfig</Setting>
+        <Setting name="AutoImport">1</Setting>
+        <Group name="Browser">
+            <Setting name="previewTileSize">small</Setting>
+        </Group>
     </Group>
     <Group name="DatablockEditor">
         <Setting name="libraryTab">1</Setting>
     </Group>
-    <Group name="AssetBrowser">
-        <Setting name="previewSize">Small</Setting>
-    </Group>
 </EditorSettings>

+ 0 - 1
Tools/CMake/libraries/assimp.cmake

@@ -85,7 +85,6 @@ addDef(ASSIMP_BUILD_NO_MDL_IMPORTER)
 addDef(ASSIMP_BUILD_NO_MMD_IMPORTER)
 addDef(ASSIMP_BUILD_NO_NDO_IMPORTER)
 addDef(ASSIMP_BUILD_NO_NFF_IMPORTER)
-#addDef(ASSIMP_BUILD_NO_OBJ_IMPORTER)
 addDef(ASSIMP_BUILD_NO_OFF_IMPORTER)
 addDef(ASSIMP_BUILD_NO_OGRE_IMPORTER)
 addDef(ASSIMP_BUILD_NO_OPENGEX_IMPORTER)