From c1e99364b7cdc2484d548a4e7d65fefb8e24d1e0 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 18 Nov 2019 21:42:55 -0600 Subject: [PATCH] Adds in missing assimp OBJ importer/exporter folder Corrects highlighting behavior on ToolsGuiTextEditProfile --- Engine/lib/assimp/code/Obj/ObjExporter.cpp | 414 ++++++++ Engine/lib/assimp/code/Obj/ObjExporter.h | 190 ++++ Engine/lib/assimp/code/Obj/ObjFileData.h | 339 +++++++ .../lib/assimp/code/Obj/ObjFileImporter.cpp | 784 ++++++++++++++++ Engine/lib/assimp/code/Obj/ObjFileImporter.h | 123 +++ .../assimp/code/Obj/ObjFileMtlImporter.cpp | 494 ++++++++++ .../lib/assimp/code/Obj/ObjFileMtlImporter.h | 117 +++ Engine/lib/assimp/code/Obj/ObjFileParser.cpp | 880 ++++++++++++++++++ Engine/lib/assimp/code/Obj/ObjFileParser.h | 165 ++++ Engine/lib/assimp/code/Obj/ObjTools.h | 308 ++++++ .../BaseGame/game/tools/gui/profiles.ed.cs | 6 +- Templates/BaseGame/game/tools/settings.xml | 432 ++++----- Tools/CMake/libraries/assimp.cmake | 1 - 13 files changed, 4033 insertions(+), 220 deletions(-) create mode 100644 Engine/lib/assimp/code/Obj/ObjExporter.cpp create mode 100644 Engine/lib/assimp/code/Obj/ObjExporter.h create mode 100644 Engine/lib/assimp/code/Obj/ObjFileData.h create mode 100644 Engine/lib/assimp/code/Obj/ObjFileImporter.cpp create mode 100644 Engine/lib/assimp/code/Obj/ObjFileImporter.h create mode 100644 Engine/lib/assimp/code/Obj/ObjFileMtlImporter.cpp create mode 100644 Engine/lib/assimp/code/Obj/ObjFileMtlImporter.h create mode 100644 Engine/lib/assimp/code/Obj/ObjFileParser.cpp create mode 100644 Engine/lib/assimp/code/Obj/ObjFileParser.h create mode 100644 Engine/lib/assimp/code/Obj/ObjTools.h diff --git a/Engine/lib/assimp/code/Obj/ObjExporter.cpp b/Engine/lib/assimp/code/Obj/ObjExporter.cpp new file mode 100644 index 000000000..0a0dbd62c --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include + +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 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(exporter.mOutput.tellp()),1); + } + { + std::unique_ptr 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(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 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(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 diff --git a/Engine/lib/assimp/code/Obj/ObjExporter.h b/Engine/lib/assimp/code/Obj/ObjExporter.h new file mode 100644 index 000000000..0d2b48d6b --- /dev/null +++ b/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 +#include +#include +#include + +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 indices; + }; + + struct MeshInstance { + std::string name, matname; + std::vector 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 vn, vt; + std::vector vc; + std::vector 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 indexMap { + int mNextIndex; + typedef std::map 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& keys ) { + keys.resize(vecMap.size()); + for(typename dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){ + keys[it->second-1] = it->first; + } + }; + }; + + indexMap mVnMap, mVtMap; + indexMap mVpMap; + std::vector mMeshes; + + // this endl() doesn't flush() the stream + const std::string endl; +}; + +} + +#endif diff --git a/Engine/lib/assimp/code/Obj/ObjFileData.h b/Engine/lib/assimp/code/Obj/ObjFileData.h new file mode 100644 index 000000000..a2d9f2cc7 --- /dev/null +++ b/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 +#include +#include +#include + +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 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 m_SubObjects; + /// Assigned meshes + std::vector m_Meshes; + + //! \brief Default constructor + Object() + : m_strObjName("") { + // empty + } + + //! \brief Destructor + ~Object() { + for ( std::vector::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 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::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* > GroupMap; + typedef std::map* >::iterator GroupMapIt; + typedef std::map* >::const_iterator ConstGroupMapIt; + + //! Model name + std::string m_ModelName; + //! List ob assigned objects + std::vector 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 m_MaterialLib; + //! Vector with all generated vertices + std::vector m_Vertices; + //! vector with all generated normals + std::vector m_Normals; + //! vector with all vertex colors + std::vector m_VertexColors; + //! Group map + GroupMap m_Groups; + //! Group to face id assignment + std::vector *m_pGroupFaceIDs; + //! Active group + std::string m_strActiveGroup; + //! Vector with generated texture coordinates + std::vector m_TextureCoord; + //! Maximum dimension of texture coordinates + unsigned int m_TextureCoordDim; + //! Current mesh instance + Mesh *m_pCurrentMesh; + //! Vector with stored meshes + std::vector m_Meshes; + //! Material map + std::map 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::iterator it = m_Objects.begin(); + it != m_Objects.end(); ++it) { + delete *it; + } + m_Objects.clear(); + + // Clear all stored mesh instances + for (std::vector::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::iterator it = m_MaterialMap.begin(); it != m_MaterialMap.end(); ++it ) { + delete it->second; + } + } +}; + +// ------------------------------------------------------------------------------------------------ + +} // Namespace ObjFile +} // Namespace Assimp + +#endif // OBJ_FILEDATA_H_INC diff --git a/Engine/lib/assimp/code/Obj/ObjFileImporter.cpp b/Engine/lib/assimp/code/Obj/ObjFileImporter.cpp new file mode 100644 index 000000000..26cc6d1f9 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include + +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 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 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 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 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 &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( 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( 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 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(inp->m_vertices.size() - 1); + pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) { + pMesh->mNumFaces += static_cast(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 &rObjects, int &iNumMeshes) +{ + iNumMeshes = 0; + if ( rObjects.empty() ) + return; + + iNumMeshes += static_cast( rObjects.size() ); + for (std::vector::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( &clampMode, 1, AI_MATKEY_MAPPINGMODE_U( type, index ) ); + mat->AddProperty( &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::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( &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 diff --git a/Engine/lib/assimp/code/Obj/ObjFileImporter.h b/Engine/lib/assimp/code/Obj/ObjFileImporter.h new file mode 100644 index 000000000..0df2ef731 --- /dev/null +++ b/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 +#include +#include + +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 &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 &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 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 diff --git a/Engine/lib/assimp/code/Obj/ObjFileMtlImporter.cpp b/Engine/lib/assimp/code/Obj/ObjFileMtlImporter.cpp new file mode 100644 index 000000000..dd9cc3ce2 --- /dev/null +++ b/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 +#include "ObjFileMtlImporter.h" +#include "ObjTools.h" +#include "ObjFileData.h" +#include +#include +#include +#include + +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 &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( 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( 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( 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( 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( m_DataIt, m_DataItEnd, m_uiLine ); + } + break; + + case 'i': // Illumination model + { + m_DataIt = getNextToken(m_DataIt, m_DataItEnd); + getIlluminationModel( m_pModel->m_pCurrentMaterial->illumination_model ); + m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); + } + break; + + default: + { + m_DataIt = skipLine( 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( 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( m_DataIt, m_DataItEnd, g ); + m_DataIt = getFloat( 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( 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( 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 token; + const unsigned int numToken = tokenize( 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::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(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(DiffuseTexture.size()) ) ) { + // Diffuse texture + out = & m_pModel->m_pCurrentMaterial->texture; + clampIndex = ObjFile::Material::TextureDiffuseType; + } else if ( !ASSIMP_strincmp( pPtr,AmbientTexture.c_str(), static_cast(AmbientTexture.size()) ) ) { + // Ambient texture + out = & m_pModel->m_pCurrentMaterial->textureAmbient; + clampIndex = ObjFile::Material::TextureAmbientType; + } else if ( !ASSIMP_strincmp( pPtr, SpecularTexture.c_str(), static_cast(SpecularTexture.size()) ) ) { + // Specular texture + out = & m_pModel->m_pCurrentMaterial->textureSpecular; + clampIndex = ObjFile::Material::TextureSpecularType; + } else if ( !ASSIMP_strincmp( pPtr, DisplacementTexture1.c_str(), static_cast(DisplacementTexture1.size()) ) || + !ASSIMP_strincmp( pPtr, DisplacementTexture2.c_str(), static_cast(DisplacementTexture2.size()) ) ) { + // Displacement texture + out = &m_pModel->m_pCurrentMaterial->textureDisp; + clampIndex = ObjFile::Material::TextureDispType; + } else if ( !ASSIMP_strincmp( pPtr, OpacityTexture.c_str(), static_cast(OpacityTexture.size()) ) ) { + // Opacity texture + out = & m_pModel->m_pCurrentMaterial->textureOpacity; + clampIndex = ObjFile::Material::TextureOpacityType; + } else if ( !ASSIMP_strincmp( pPtr, EmissiveTexture1.c_str(), static_cast(EmissiveTexture1.size()) ) || + !ASSIMP_strincmp( pPtr, EmissiveTexture2.c_str(), static_cast(EmissiveTexture2.size()) ) ) { + // Emissive texture + out = & m_pModel->m_pCurrentMaterial->textureEmissive; + clampIndex = ObjFile::Material::TextureEmissiveType; + } else if ( !ASSIMP_strincmp( pPtr, BumpTexture1.c_str(), static_cast(BumpTexture1.size()) ) || + !ASSIMP_strincmp( pPtr, BumpTexture2.c_str(), static_cast(BumpTexture2.size()) ) ) { + // Bump texture + out = & m_pModel->m_pCurrentMaterial->textureBump; + clampIndex = ObjFile::Material::TextureBumpType; + } else if ( !ASSIMP_strincmp( pPtr,NormalTexture.c_str(), static_cast(NormalTexture.size()) ) ) { + // Normal map + out = & m_pModel->m_pCurrentMaterial->textureNormal; + clampIndex = ObjFile::Material::TextureNormalType; + } else if( !ASSIMP_strincmp( pPtr, ReflectionTexture.c_str(), static_cast(ReflectionTexture.size()) ) ) { + // Reflection texture(s) + //Do nothing here + return; + } else if ( !ASSIMP_strincmp( pPtr, SpecularityTexture.c_str(), static_cast(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( 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(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(ClampOption.size()))) + { + DataArrayIt it = getNextToken(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(TypeOption.size()) ) ) + { + DataArrayIt it = getNextToken( 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(BlendUOption.size())) + || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast(BlendVOption.size())) + || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast(BoostOption.size())) + || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast(ResolutionOption.size())) + || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast(BumpOption.size())) + || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast(ChannelOption.size()))) + { + skipToken = 2; + } + else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast(ModifyMapOption.size()))) + { + skipToken = 3; + } + else if ( !ASSIMP_strincmp(pPtr, OffsetOption.c_str(), static_cast(OffsetOption.size())) + || !ASSIMP_strincmp(pPtr, ScaleOption.c_str(), static_cast(ScaleOption.size())) + || !ASSIMP_strincmp(pPtr, TurbulenceOption.c_str(), static_cast(TurbulenceOption.size())) + ) + { + skipToken = 4; + } + + for (int i = 0; i < skipToken; ++i) + { + m_DataIt = getNextToken(m_DataIt, m_DataItEnd); + } + } +} + +// ------------------------------------------------------------------- + +} // Namespace Assimp + +#endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER diff --git a/Engine/lib/assimp/code/Obj/ObjFileMtlImporter.h b/Engine/lib/assimp/code/Obj/ObjFileMtlImporter.h new file mode 100644 index 000000000..731952359 --- /dev/null +++ b/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 +#include +#include + +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 DataArray; + typedef std::vector::iterator DataArrayIt; + typedef std::vector::const_iterator ConstDataArrayIt; + +public: + //! \brief Default constructor + ObjFileMtlImporter( std::vector &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 diff --git a/Engine/lib/assimp/code/Obj/ObjFileParser.cpp b/Engine/lib/assimp/code/Obj/ObjFileParser.cpp new file mode 100644 index 000000000..699aafe6a --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +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 &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 &buffer ) { + m_DataIt = buffer.begin(); + m_DataItEnd = buffer.end(); +} + +ObjFile::Model *ObjFileParser::GetModel() const { + return m_pModel.get(); +} + +void ObjFileParser::parseFile( IOStreamBuffer &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(streamBuffer.size()); + const unsigned int progressTotal = bytesToProcess; + unsigned int processed = 0; + size_t lastFilePos( 0 ); + + std::vector 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(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( m_DataIt, m_DataItEnd, m_uiLine ); + } + break; + } + } +} + +void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { + size_t index = 0; + m_DataIt = getNextWord(m_DataIt, m_DataItEnd); + if ( *m_DataIt == '\\' ) { + ++m_DataIt; + ++m_DataIt; + m_DataIt = getNextWord( 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 &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( m_DataIt, m_DataItEnd, m_uiLine ); + return numComponents; +} + +void ObjFileParser::getVector3( std::vector &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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +void ObjFileParser::getHomogeneousVector3( std::vector &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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +void ObjFileParser::getTwoVectors3( std::vector &point3d_array_a, std::vector &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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +void ObjFileParser::getVector2( std::vector &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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +static const std::string DefaultObjName = "defaultobject"; + +void ObjFileParser::getFace( aiPrimitiveType type ) { + m_DataIt = getNextToken( 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(m_pModel->m_Vertices.size()); + const int vtSize = static_cast(m_pModel->m_TextureCoord.size()); + const int vnSize = static_cast(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( 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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +void ObjFileParser::getMaterialDesc() { + // Get next data for material data + m_DataIt = getNextToken(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::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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +// ------------------------------------------------------------------- +// Get a comment, values will be skipped +void ObjFileParser::getComment() { + m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); +} + +// ------------------------------------------------------------------- +// Get material library from file. +void ObjFileParser::getMaterialLib() { + // Translate tuple + m_DataIt = getNextToken(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(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 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(m_DataIt, m_DataItEnd); + m_DataIt = getNextWord(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::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( 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(m_DataIt, m_DataItEnd); + m_DataIt = getName(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 *pFaceIDArray = new std::vector; + 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( m_DataIt, m_DataItEnd, m_uiLine ); +} + +// ------------------------------------------------------------------- +// Not supported +void ObjFileParser::getGroupNumber() +{ + // Not used + + m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); +} + +// ------------------------------------------------------------------- +// Not supported +void ObjFileParser::getGroupNumberAndResolution() +{ + // Not used + + m_DataIt = skipLine( 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(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::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( 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(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( 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 diff --git a/Engine/lib/assimp/code/Obj/ObjFileParser.h b/Engine/lib/assimp/code/Obj/ObjFileParser.h new file mode 100644 index 000000000..7d1b806ce --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include + +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 DataArray; + typedef std::vector::iterator DataArrayIt; + typedef std::vector::const_iterator ConstDataArrayIt; + +public: + /// @brief The default constructor. + ObjFileParser(); + /// @brief Constructor with data array. + ObjFileParser( IOStreamBuffer &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 &buffer ); + /// @brief Model getter. + ObjFile::Model *GetModel() const; + +protected: + /// Parse the loaded file + void parseFile( IOStreamBuffer &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 &point3d_array ); + /// Stores the following 3d vector. + void getVector3( std::vector &point3d_array ); + /// Stores the following homogeneous vector as a 3D vector + void getHomogeneousVector3( std::vector &point3d_array ); + /// Stores the following two 3d vectors on the line. + void getTwoVectors3( std::vector &point3d_array_a, std::vector &point3d_array_b ); + /// Stores the following 3d vector. + void getVector2(std::vector &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 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 diff --git a/Engine/lib/assimp/code/Obj/ObjTools.h b/Engine/lib/assimp/code/Obj/ObjTools.h new file mode 100644 index 000000000..3f4c41033 --- /dev/null +++ b/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 +#include +#include + +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 +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 +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 +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 +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 +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 +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 +inline char_t CopyNextWord( char_t it, char_t end, char *pBuffer, size_t length ) +{ + size_t index = 0; + it = getNextWord( 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 +inline char_t getFloat( char_t it, char_t end, ai_real &value ) +{ + static const size_t BUFFERSIZE = 1024; + char buffer[ BUFFERSIZE ]; + it = CopyNextWord( 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 +unsigned int tokenize( const string_type& str, std::vector& 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( tokens.size() ); +} + +template +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 +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 diff --git a/Templates/BaseGame/game/tools/gui/profiles.ed.cs b/Templates/BaseGame/game/tools/gui/profiles.ed.cs index ba636263f..f76e1b572 100644 --- a/Templates/BaseGame/game/tools/gui/profiles.ed.cs +++ b/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; diff --git a/Templates/BaseGame/game/tools/settings.xml b/Templates/BaseGame/game/tools/settings.xml index 53d9a8704..540f128a4 100644 --- a/Templates/BaseGame/game/tools/settings.xml +++ b/Templates/BaseGame/game/tools/settings.xml @@ -1,254 +1,254 @@ - - 72 70 68 255 - 234 232 230 255 - 32 31 30 255 - 43 43 43 255 - 37 36 35 255 - 255 255 255 255 - 50 49 48 255 - 50 49 48 255 - 17 16 15 255 - 77 77 77 255 - 72 70 68 255 - 100 98 96 255 - 178 175 172 255 - 236 234 232 255 - 59 58 57 255 - 50 49 48 255 - 96 94 92 255 - 59 58 57 255 - 255 255 255 255 + + DefaultPlayerData + 1 + AIPlayer - - 1 - 135 - 0 0 0 100 - 1 - 1 - 0 - 180 180 180 255 - 1 - 1 - 255 255 255 255 - 0.1 - 40 40 - 1 - 0 - 45 + + 1024 768 + tools/gui/messageBoxes + + 2 + 1 + 8 + 1 + 1 + 0 + 1 + 1 + + + 1 + 1 + + + http://www.garagegames.com/products/torque-3d/documentation/user + ../../../Documentation/Official Documentation.html + ../../../Documentation/Torque 3D - Script Manual.chm + + + 0 + + + 0 + 0 + 0 + + + Categorized + + + + lowerHeight + + 100 + 10 + 0.1 + 50 + 1 + 0 + 1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000 + 1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000 + 1 + 90 + + + 40 40 + 40 40 + 1 + ellipse + 1 + + + + 0.8 + 100 + 15 + 0.8 + 0 + 1 + 0 + + 0 + 1 1 1 + 0 + 1 + 255 255 255 20 + 500 + - Modern - screenCenter - 1 - 6 WorldEditorInspectorPlugin - 0 AssetWork_Debug.exe - 50 40 - - 1 - 8 - 20 - 0 - 255 - - - 1 - 1 - 1 - 1 - 1 - - - 50 50 50 255 - 180 180 180 255 - 255 255 255 255 - 215 215 215 255 - 48 48 48 255 + screenCenter + 6 + 0 + 50 + Modern + 1 + + 255 255 0 255 + 255 0 0 255 + 0 255 0 255 + 100 100 100 255 + 255 255 0 255 + 255 255 255 255 + 0 0 255 255 1 - 1 102 102 102 100 - 255 255 255 100 51 51 51 100 + 1 + 255 255 255 100 + + + 180 180 180 255 + 48 48 48 255 + 50 50 50 255 + 215 215 215 255 + 255 255 255 255 - ../../../Documentation/Torque 3D - Script Manual.chm - http://www.garagegames.com/products/torque-3d/forums - ../../../Documentation/Official Documentation.html http://www.garagegames.com/products/torque-3d/documentation/user + ../../../Documentation/Torque 3D - Script Manual.chm + ../../../Documentation/Official Documentation.html + http://www.garagegames.com/products/torque-3d/forums - - 255 255 255 255 - 100 100 100 255 - 255 0 0 255 - 0 0 255 255 - 255 255 0 255 - 0 255 0 255 - 255 255 0 255 + + 1 + 1 + 1 + 1 + 1 - - 0 - 0 - 0 - 2 - 0 - 100 - 1 - 1 - 0.01 + + 0 + 20 + 8 + 1 + 255 - tools/worldEditor/images/LockedHandle - tools/worldEditor/images/DefaultHandle tools/worldEditor/images/SelectHandle + tools/worldEditor/images/DefaultHandle + tools/worldEditor/images/LockedHandle + + + 0.01 + 0 + 0 + 1 + 2 + 0 + 1 + 0 + 100 Classic - - 15 - 0 - 0.8 - 0.8 - 0 - 100 - 1 - - 1 - 0 - 255 255 255 20 - 1 1 1 - 500 - 0 - - - - 255 0 0 255 - 10 - 5 - 0 255 0 255 - 255 255 255 255 - 0 0 1 - - - lowerHeight - - 40 40 - 1 - 1 - 40 40 - ellipse - - - 50 - 10 - 90 - 1 - 0 - 0.1 - 100 - 1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000 - 1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000 - 1 - - - - <AssetType>/ - <AssetType>/ - 1 - <AssetType>/ - <AssetType>/<SpecialAssetTag>/ - <AssetType>/OtherFolder/ - <AssetType>/ - <AssetType>/ - <AssetType>/<AssetName>/ - <AssetType>/<SpecialAssetTag>/ - TestConfig - - - tools/gui/messageBoxes - 1024 768 - - 0 - 0 - 0 - - - ../../../Documentation/Official Documentation.html - http://www.garagegames.com/products/torque-3d/documentation/user - ../../../Documentation/Torque 3D - Script Manual.chm - - - 1 - 1 - - - 1 - 1 - 2 - 0 - 8 - 1 - 1 - 1 - - - Categorized - - - 0 - - - - 10 - DefaultRoadMaterialTop - DefaultRoadMaterialOther - 0 0 1 - 255 0 0 255 - 0 255 0 255 - - - 1 - TestConfig - - small - - - - data/FPSGameplay/levels - - - 5 - - - 25 - - + + 135 + 0.1 + 1 + 1 + 0 + 45 + 1 + 1 + 255 255 255 255 + 0 0 0 100 + 40 40 + 1 + 0 + 180 180 180 255 + 1 Grid_512_Orange - - DefaultDecalRoadMaterial + + 10 + 0 255 0 255 + DefaultRoadMaterialOther + 255 0 0 255 + DefaultRoadMaterialTop + 0 0 1 + + + TestConfig + <AssetType>/ + <AssetType>/<SpecialAssetTag>/ + <AssetType>/<SpecialAssetTag>/ + <AssetType>/ + <AssetType>/<AssetName>/ + <AssetType>/ + <AssetType>/ + 1 + <AssetType>/ + <AssetType>/OtherFolder/ + + + 5 255 255 255 255 10 0 255 0 255 - - - AIPlayer - 1 - DefaultPlayerData - - - 1 + 0 0 1 + 255 0 0 255 Small + + 255 255 255 255 + 0 255 0 255 + DefaultDecalRoadMaterial + 10 + + + data/FPSGameplay/levels + + + 25 + + + 5 + + + + + 234 232 230 255 + 255 255 255 255 + 77 77 77 255 + 50 49 48 255 + 43 43 43 255 + 100 98 96 255 + 59 58 57 255 + 50 49 48 255 + 236 234 232 255 + 72 70 68 255 + 32 31 30 255 + 17 16 15 255 + 50 49 48 255 + 72 70 68 255 + 37 36 35 255 + 255 255 255 255 + 96 94 92 255 + 178 175 172 255 + 59 58 57 255 + + + TestConfig + 1 + + small + + + + 1 + diff --git a/Tools/CMake/libraries/assimp.cmake b/Tools/CMake/libraries/assimp.cmake index d9871b630..e15687721 100644 --- a/Tools/CMake/libraries/assimp.cmake +++ b/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)