mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
need to unhide OBJ for this one
This commit is contained in:
parent
82e608f990
commit
7716663346
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -108,7 +108,7 @@ publish
|
|||
|
||||
# Others
|
||||
[Bb]in
|
||||
[Oo]bj
|
||||
# [Oo]bj
|
||||
sql
|
||||
TestResults
|
||||
*.Cache
|
||||
|
|
|
|||
414
Engine/lib/assimp/code/AssetLib/Obj/ObjExporter.cpp
Normal file
414
Engine/lib/assimp/code/AssetLib/Obj/ObjExporter.cpp
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
|
||||
#include "ObjExporter.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/version.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
|
||||
void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
|
||||
// invoke the exporter
|
||||
ObjExporter exporter(pFile, pScene);
|
||||
|
||||
if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) {
|
||||
throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
|
||||
}
|
||||
|
||||
// we're still here - export successfully completed. Write both the main OBJ file and the material script
|
||||
{
|
||||
std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
|
||||
if (outfile == nullptr) {
|
||||
throw DeadlyExportError("could not open output .obj file: " + std::string(pFile));
|
||||
}
|
||||
outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
|
||||
}
|
||||
{
|
||||
std::unique_ptr<IOStream> outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt"));
|
||||
if (outfile == nullptr) {
|
||||
throw DeadlyExportError("could not open output .mtl file: " + std::string(exporter.GetMaterialLibFileName()));
|
||||
}
|
||||
outfile->Write( exporter.mOutputMat.str().c_str(), static_cast<size_t>(exporter.mOutputMat.tellp()),1);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to Wavefront OBJ without the material file. Prototyped and registered in Exporter.cpp
|
||||
void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* ) {
|
||||
// invoke the exporter
|
||||
ObjExporter exporter(pFile, pScene, true);
|
||||
|
||||
if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) {
|
||||
throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
|
||||
}
|
||||
|
||||
// we're still here - export successfully completed. Write both the main OBJ file and the material script
|
||||
{
|
||||
std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
|
||||
if (outfile == nullptr) {
|
||||
throw DeadlyExportError("could not open output .obj file: " + std::string(pFile));
|
||||
}
|
||||
outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
static const std::string MaterialExt = ".mtl";
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl)
|
||||
: filename(_filename)
|
||||
, pScene(pScene)
|
||||
, vn()
|
||||
, vt()
|
||||
, vp()
|
||||
, useVc(false)
|
||||
, mVnMap()
|
||||
, mVtMap()
|
||||
, mVpMap()
|
||||
, mMeshes()
|
||||
, endl("\n") {
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
const std::locale& l = std::locale("C");
|
||||
mOutput.imbue(l);
|
||||
mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
|
||||
mOutputMat.imbue(l);
|
||||
mOutputMat.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
|
||||
|
||||
WriteGeometryFile(noMtl);
|
||||
if ( !noMtl ) {
|
||||
WriteMaterialFile();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ObjExporter::~ObjExporter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string ObjExporter::GetMaterialLibName() {
|
||||
// within the Obj file, we use just the relative file name with the path stripped
|
||||
const std::string& s = GetMaterialLibFileName();
|
||||
std::string::size_type il = s.find_last_of("/\\");
|
||||
if (il != std::string::npos) {
|
||||
return s.substr(il + 1);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string ObjExporter::GetMaterialLibFileName() {
|
||||
// Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
|
||||
size_t lastdot = filename.find_last_of('.');
|
||||
if ( lastdot != std::string::npos ) {
|
||||
return filename.substr( 0, lastdot ) + MaterialExt;
|
||||
}
|
||||
|
||||
return filename + MaterialExt;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter::WriteHeader(std::ostringstream& out) {
|
||||
out << "# File produced by Open Asset Import Library (http://www.assimp.sf.net)" << endl;
|
||||
out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.'
|
||||
<< aiGetVersionRevision() << ")" << endl << endl;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string ObjExporter::GetMaterialName(unsigned int index) {
|
||||
const aiMaterial* const mat = pScene->mMaterials[index];
|
||||
if ( nullptr == mat ) {
|
||||
static const std::string EmptyStr;
|
||||
return EmptyStr;
|
||||
}
|
||||
|
||||
aiString s;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_NAME,s)) {
|
||||
return std::string(s.data,s.length);
|
||||
}
|
||||
|
||||
char number[ sizeof(unsigned int) * 3 + 1 ];
|
||||
ASSIMP_itoa10(number,index);
|
||||
return "$Material_" + std::string(number);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter::WriteMaterialFile() {
|
||||
WriteHeader(mOutputMat);
|
||||
|
||||
for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||
const aiMaterial* const mat = pScene->mMaterials[i];
|
||||
|
||||
int illum = 1;
|
||||
mOutputMat << "newmtl " << GetMaterialName(i) << endl;
|
||||
|
||||
aiColor4D c;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) {
|
||||
mOutputMat << "Kd " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) {
|
||||
mOutputMat << "Ka " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
|
||||
mOutputMat << "Ks " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_EMISSIVE,c)) {
|
||||
mOutputMat << "Ke " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_TRANSPARENT,c)) {
|
||||
mOutputMat << "Tf " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
|
||||
ai_real o;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
|
||||
mOutputMat << "d " << o << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_REFRACTI,o)) {
|
||||
mOutputMat << "Ni " << o << endl;
|
||||
}
|
||||
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS,o) && o) {
|
||||
mOutputMat << "Ns " << o << endl;
|
||||
illum = 2;
|
||||
}
|
||||
|
||||
mOutputMat << "illum " << illum << endl;
|
||||
|
||||
aiString s;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) {
|
||||
mOutputMat << "map_Kd " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) {
|
||||
mOutputMat << "map_Ka " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) {
|
||||
mOutputMat << "map_Ks " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) {
|
||||
mOutputMat << "map_Ns " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_OPACITY(0),s)) {
|
||||
mOutputMat << "map_d " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) {
|
||||
// implementations seem to vary here, so write both variants
|
||||
mOutputMat << "bump " << s.data << endl;
|
||||
mOutputMat << "map_bump " << s.data << endl;
|
||||
}
|
||||
|
||||
mOutputMat << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjExporter::WriteGeometryFile(bool noMtl) {
|
||||
WriteHeader(mOutput);
|
||||
if (!noMtl)
|
||||
mOutput << "mtllib " << GetMaterialLibName() << endl << endl;
|
||||
|
||||
// collect mesh geometry
|
||||
aiMatrix4x4 mBase;
|
||||
AddNode(pScene->mRootNode, mBase);
|
||||
|
||||
// write vertex positions with colors, if any
|
||||
mVpMap.getKeys( vp );
|
||||
if ( !useVc ) {
|
||||
mOutput << "# " << vp.size() << " vertex positions" << endl;
|
||||
for ( const vertexData& v : vp ) {
|
||||
mOutput << "v " << v.vp.x << " " << v.vp.y << " " << v.vp.z << endl;
|
||||
}
|
||||
} else {
|
||||
mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
|
||||
for ( const vertexData& v : vp ) {
|
||||
mOutput << "v " << v.vp.x << " " << v.vp.y << " " << v.vp.z << " " << v.vc.r << " " << v.vc.g << " " << v.vc.b << endl;
|
||||
}
|
||||
}
|
||||
mOutput << endl;
|
||||
|
||||
// write uv coordinates
|
||||
mVtMap.getKeys(vt);
|
||||
mOutput << "# " << vt.size() << " UV coordinates" << endl;
|
||||
for(const aiVector3D& v : vt) {
|
||||
mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
|
||||
// write vertex normals
|
||||
mVnMap.getKeys(vn);
|
||||
mOutput << "# " << vn.size() << " vertex normals" << endl;
|
||||
for(const aiVector3D& v : vn) {
|
||||
mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
|
||||
// now write all mesh instances
|
||||
for(const MeshInstance& m : mMeshes) {
|
||||
mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
|
||||
if (!m.name.empty()) {
|
||||
mOutput << "g " << m.name << endl;
|
||||
}
|
||||
if ( !noMtl ) {
|
||||
mOutput << "usemtl " << m.matname << endl;
|
||||
}
|
||||
|
||||
for(const Face& f : m.faces) {
|
||||
mOutput << f.kind << ' ';
|
||||
for(const FaceVertex& fv : f.indices) {
|
||||
mOutput << ' ' << fv.vp;
|
||||
|
||||
if (f.kind != 'p') {
|
||||
if (fv.vt || f.kind == 'f') {
|
||||
mOutput << '/';
|
||||
}
|
||||
if (fv.vt) {
|
||||
mOutput << fv.vt;
|
||||
}
|
||||
if (f.kind == 'f' && fv.vn) {
|
||||
mOutput << '/' << fv.vn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mOutput << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
|
||||
mMeshes.push_back(MeshInstance() );
|
||||
MeshInstance& mesh = mMeshes.back();
|
||||
|
||||
if ( nullptr != m->mColors[ 0 ] ) {
|
||||
useVc = true;
|
||||
}
|
||||
|
||||
mesh.name = std::string( name.data, name.length );
|
||||
mesh.matname = GetMaterialName(m->mMaterialIndex);
|
||||
|
||||
mesh.faces.resize(m->mNumFaces);
|
||||
|
||||
for(unsigned int i = 0; i < m->mNumFaces; ++i) {
|
||||
const aiFace& f = m->mFaces[i];
|
||||
|
||||
Face& face = mesh.faces[i];
|
||||
switch (f.mNumIndices) {
|
||||
case 1:
|
||||
face.kind = 'p';
|
||||
break;
|
||||
case 2:
|
||||
face.kind = 'l';
|
||||
break;
|
||||
default:
|
||||
face.kind = 'f';
|
||||
}
|
||||
face.indices.resize(f.mNumIndices);
|
||||
|
||||
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
||||
const unsigned int idx = f.mIndices[a];
|
||||
|
||||
aiVector3D vert = mat * m->mVertices[idx];
|
||||
|
||||
if ( nullptr != m->mColors[ 0 ] ) {
|
||||
aiColor4D col4 = m->mColors[ 0 ][ idx ];
|
||||
face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b)});
|
||||
} else {
|
||||
face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0)});
|
||||
}
|
||||
|
||||
if (m->mNormals) {
|
||||
aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
|
||||
face.indices[a].vn = mVnMap.getIndex(norm);
|
||||
} else {
|
||||
face.indices[a].vn = 0;
|
||||
}
|
||||
|
||||
if ( m->mTextureCoords[ 0 ] ) {
|
||||
face.indices[a].vt = mVtMap.getIndex(m->mTextureCoords[0][idx]);
|
||||
} else {
|
||||
face.indices[a].vt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) {
|
||||
const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
|
||||
|
||||
aiMesh *cm( nullptr );
|
||||
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
||||
cm = pScene->mMeshes[nd->mMeshes[i]];
|
||||
if (nullptr != cm) {
|
||||
AddMesh(cm->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs);
|
||||
} else {
|
||||
AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
|
||||
AddNode(nd->mChildren[i], mAbs);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
||||
190
Engine/lib/assimp/code/AssetLib/Obj/ObjExporter.h
Normal file
190
Engine/lib/assimp/code/AssetLib/Obj/ObjExporter.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file ObjExporter.h
|
||||
* Declares the exporter class to write a scene to a Collada file
|
||||
*/
|
||||
#ifndef AI_OBJEXPORTER_H_INC
|
||||
#define AI_OBJEXPORTER_H_INC
|
||||
|
||||
#include <assimp/types.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
struct aiScene;
|
||||
struct aiNode;
|
||||
struct aiMesh;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Helper class to export a given scene to an OBJ file. */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class ObjExporter {
|
||||
public:
|
||||
/// Constructor for a specific scene to export
|
||||
ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false);
|
||||
~ObjExporter();
|
||||
std::string GetMaterialLibName();
|
||||
std::string GetMaterialLibFileName();
|
||||
|
||||
/// public string-streams to write all output into
|
||||
std::ostringstream mOutput, mOutputMat;
|
||||
|
||||
private:
|
||||
// intermediate data structures
|
||||
struct FaceVertex {
|
||||
FaceVertex()
|
||||
: vp()
|
||||
, vn()
|
||||
, vt() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// one-based, 0 means: 'does not exist'
|
||||
unsigned int vp, vn, vt;
|
||||
};
|
||||
|
||||
struct Face {
|
||||
char kind;
|
||||
std::vector<FaceVertex> indices;
|
||||
};
|
||||
|
||||
struct MeshInstance {
|
||||
std::string name, matname;
|
||||
std::vector<Face> faces;
|
||||
};
|
||||
|
||||
void WriteHeader(std::ostringstream& out);
|
||||
void WriteMaterialFile();
|
||||
void WriteGeometryFile(bool noMtl=false);
|
||||
std::string GetMaterialName(unsigned int index);
|
||||
void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat);
|
||||
void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
const aiScene* const pScene;
|
||||
|
||||
struct vertexData {
|
||||
aiVector3D vp;
|
||||
aiColor3D vc; // OBJ does not support 4D color
|
||||
};
|
||||
|
||||
std::vector<aiVector3D> vn, vt;
|
||||
std::vector<aiColor4D> vc;
|
||||
std::vector<vertexData> vp;
|
||||
bool useVc;
|
||||
|
||||
struct vertexDataCompare {
|
||||
bool operator() ( const vertexData& a, const vertexData& b ) const {
|
||||
// position
|
||||
if (a.vp.x < b.vp.x) return true;
|
||||
if (a.vp.x > b.vp.x) return false;
|
||||
if (a.vp.y < b.vp.y) return true;
|
||||
if (a.vp.y > b.vp.y) return false;
|
||||
if (a.vp.z < b.vp.z) return true;
|
||||
if (a.vp.z > b.vp.z) return false;
|
||||
|
||||
// color
|
||||
if (a.vc.r < b.vc.r) return true;
|
||||
if (a.vc.r > b.vc.r) return false;
|
||||
if (a.vc.g < b.vc.g) return true;
|
||||
if (a.vc.g > b.vc.g) return false;
|
||||
if (a.vc.b < b.vc.b) return true;
|
||||
if (a.vc.b > b.vc.b) return false;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct aiVectorCompare {
|
||||
bool operator() (const aiVector3D& a, const aiVector3D& b) const {
|
||||
if(a.x < b.x) return true;
|
||||
if(a.x > b.x) return false;
|
||||
if(a.y < b.y) return true;
|
||||
if(a.y > b.y) return false;
|
||||
if(a.z < b.z) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class Compare = std::less<T>>
|
||||
class indexMap {
|
||||
int mNextIndex;
|
||||
typedef std::map<T, int, Compare> dataType;
|
||||
dataType vecMap;
|
||||
|
||||
public:
|
||||
indexMap()
|
||||
: mNextIndex(1) {
|
||||
// empty
|
||||
}
|
||||
|
||||
int getIndex(const T& key) {
|
||||
typename dataType::iterator vertIt = vecMap.find(key);
|
||||
// vertex already exists, so reference it
|
||||
if(vertIt != vecMap.end()){
|
||||
return vertIt->second;
|
||||
}
|
||||
return vecMap[key] = mNextIndex++;
|
||||
};
|
||||
|
||||
void getKeys( std::vector<T>& keys ) {
|
||||
keys.resize(vecMap.size());
|
||||
for(typename dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){
|
||||
keys[it->second-1] = it->first;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
indexMap<aiVector3D, aiVectorCompare> mVnMap, mVtMap;
|
||||
indexMap<vertexData, vertexDataCompare> mVpMap;
|
||||
std::vector<MeshInstance> mMeshes;
|
||||
|
||||
// this endl() doesn't flush() the stream
|
||||
const std::string endl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
344
Engine/lib/assimp/code/AssetLib/Obj/ObjFileData.h
Normal file
344
Engine/lib/assimp/code/AssetLib/Obj/ObjFileData.h
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 <assimp/mesh.h>
|
||||
#include <assimp/types.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
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 {
|
||||
using IndexArray = std::vector<unsigned int>;
|
||||
|
||||
//! Primitive type
|
||||
aiPrimitiveType m_PrimitiveType;
|
||||
//! Vertex indices
|
||||
IndexArray m_vertices;
|
||||
//! Normal indices
|
||||
IndexArray m_normals;
|
||||
//! Texture coordinates indices
|
||||
IndexArray m_texturCoords;
|
||||
//! Pointer to assigned material
|
||||
Material *m_pMaterial;
|
||||
|
||||
//! \brief Default constructor
|
||||
Face(aiPrimitiveType pt = aiPrimitiveType_POLYGON) :
|
||||
m_PrimitiveType(pt), m_vertices(), m_normals(), m_texturCoords(), m_pMaterial(0L) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! \brief Destructor
|
||||
~Face() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
//! \struct Object
|
||||
//! \brief Stores all objects of an obj-file object definition
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct Object {
|
||||
enum ObjectType {
|
||||
ObjType,
|
||||
GroupType
|
||||
};
|
||||
|
||||
//! Object name
|
||||
std::string m_strObjName;
|
||||
//! Transformation matrix, stored in OpenGL format
|
||||
aiMatrix4x4 m_Transformation;
|
||||
//! All sub-objects referenced by this object
|
||||
std::vector<Object *> m_SubObjects;
|
||||
/// Assigned meshes
|
||||
std::vector<unsigned int> m_Meshes;
|
||||
|
||||
//! \brief Default constructor
|
||||
Object() = default;
|
||||
|
||||
//! \brief Destructor
|
||||
~Object() {
|
||||
for (std::vector<Object *>::iterator it = m_SubObjects.begin(); it != m_SubObjects.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
//! \struct Material
|
||||
//! \brief Data structure to store all material specific data
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct Material {
|
||||
//! Name of material description
|
||||
aiString MaterialName;
|
||||
//! Texture names
|
||||
aiString texture;
|
||||
aiString textureSpecular;
|
||||
aiString textureAmbient;
|
||||
aiString textureEmissive;
|
||||
aiString textureBump;
|
||||
aiString textureNormal;
|
||||
aiString textureReflection[6];
|
||||
aiString textureSpecularity;
|
||||
aiString textureOpacity;
|
||||
aiString textureDisp;
|
||||
aiString textureRoughness;
|
||||
aiString textureMetallic;
|
||||
aiString textureSheen;
|
||||
aiString textureRMA;
|
||||
|
||||
enum TextureType {
|
||||
TextureDiffuseType = 0,
|
||||
TextureSpecularType,
|
||||
TextureAmbientType,
|
||||
TextureEmissiveType,
|
||||
TextureBumpType,
|
||||
TextureNormalType,
|
||||
TextureReflectionSphereType,
|
||||
TextureReflectionCubeTopType,
|
||||
TextureReflectionCubeBottomType,
|
||||
TextureReflectionCubeFrontType,
|
||||
TextureReflectionCubeBackType,
|
||||
TextureReflectionCubeLeftType,
|
||||
TextureReflectionCubeRightType,
|
||||
TextureSpecularityType,
|
||||
TextureOpacityType,
|
||||
TextureDispType,
|
||||
TextureRoughnessType,
|
||||
TextureMetallicType,
|
||||
TextureSheenType,
|
||||
TextureRMAType,
|
||||
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;
|
||||
|
||||
//! PBR Roughness
|
||||
ai_real roughness;
|
||||
//! PBR Metallic
|
||||
ai_real metallic;
|
||||
//! PBR Metallic
|
||||
aiColor3D sheen;
|
||||
//! PBR Clearcoat Thickness
|
||||
ai_real clearcoat_thickness;
|
||||
//! PBR Clearcoat Rougness
|
||||
ai_real clearcoat_roughness;
|
||||
//! PBR Anisotropy
|
||||
ai_real anisotropy;
|
||||
|
||||
//! bump map multipler (normal map scalar)(-bm)
|
||||
ai_real bump_multiplier;
|
||||
|
||||
//! 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)),
|
||||
roughness(ai_real(1.0)),
|
||||
metallic(ai_real(0.0)),
|
||||
sheen(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
|
||||
clearcoat_thickness(ai_real(0.0)),
|
||||
clearcoat_roughness(ai_real(0.0)),
|
||||
anisotropy(ai_real(0.0)),
|
||||
bump_multiplier(ai_real(1.0)) {
|
||||
std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~Material() = default;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
//! \struct Mesh
|
||||
//! \brief Data structure to store a mesh
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct Mesh {
|
||||
static const unsigned int NoMaterial = ~0u;
|
||||
/// The name for the mesh
|
||||
std::string m_name;
|
||||
/// Array with pointer to all stored faces
|
||||
std::vector<Face *> m_Faces;
|
||||
/// Assigned material
|
||||
Material *m_pMaterial;
|
||||
/// Number of stored indices.
|
||||
unsigned int m_uiNumIndices;
|
||||
/// Number of UV
|
||||
unsigned int m_uiUVCoordinates[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
/// Material index.
|
||||
unsigned int m_uiMaterialIndex;
|
||||
/// True, if normals are stored.
|
||||
bool m_hasNormals;
|
||||
/// True, if vertex colors are stored.
|
||||
bool m_hasVertexColors;
|
||||
|
||||
/// Constructor
|
||||
explicit Mesh(const std::string &name) :
|
||||
m_name(name),
|
||||
m_pMaterial(nullptr),
|
||||
m_uiNumIndices(0),
|
||||
m_uiMaterialIndex(NoMaterial),
|
||||
m_hasNormals(false) {
|
||||
memset(m_uiUVCoordinates, 0, sizeof(unsigned int) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~Mesh() {
|
||||
for (std::vector<Face *>::iterator it = m_Faces.begin();
|
||||
it != m_Faces.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
//! \struct Model
|
||||
//! \brief Data structure to store all obj-specific model data
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct Model {
|
||||
using GroupMap = std::map<std::string, std::vector<unsigned int> *>;
|
||||
using GroupMapIt = std::map<std::string, std::vector<unsigned int> *>::iterator;
|
||||
using ConstGroupMapIt = std::map<std::string, std::vector<unsigned int> *>::const_iterator;
|
||||
|
||||
//! Model name
|
||||
std::string m_ModelName;
|
||||
//! List ob assigned objects
|
||||
std::vector<Object *> m_Objects;
|
||||
//! Pointer to current object
|
||||
ObjFile::Object *m_pCurrent;
|
||||
//! Pointer to current material
|
||||
ObjFile::Material *m_pCurrentMaterial;
|
||||
//! Pointer to default material
|
||||
ObjFile::Material *m_pDefaultMaterial;
|
||||
//! Vector with all generated materials
|
||||
std::vector<std::string> m_MaterialLib;
|
||||
//! Vector with all generated vertices
|
||||
std::vector<aiVector3D> m_Vertices;
|
||||
//! vector with all generated normals
|
||||
std::vector<aiVector3D> m_Normals;
|
||||
//! vector with all vertex colors
|
||||
std::vector<aiVector3D> m_VertexColors;
|
||||
//! Group map
|
||||
GroupMap m_Groups;
|
||||
//! Group to face id assignment
|
||||
std::vector<unsigned int> *m_pGroupFaceIDs;
|
||||
//! Active group
|
||||
std::string m_strActiveGroup;
|
||||
//! Vector with generated texture coordinates
|
||||
std::vector<aiVector3D> m_TextureCoord;
|
||||
//! Maximum dimension of texture coordinates
|
||||
unsigned int m_TextureCoordDim;
|
||||
//! Current mesh instance
|
||||
Mesh *m_pCurrentMesh;
|
||||
//! Vector with stored meshes
|
||||
std::vector<Mesh *> m_Meshes;
|
||||
//! Material map
|
||||
std::map<std::string, Material *> m_MaterialMap;
|
||||
|
||||
//! \brief The default class constructor
|
||||
Model() :
|
||||
m_ModelName(),
|
||||
m_pCurrent(nullptr),
|
||||
m_pCurrentMaterial(nullptr),
|
||||
m_pDefaultMaterial(nullptr),
|
||||
m_pGroupFaceIDs(nullptr),
|
||||
m_strActiveGroup(),
|
||||
m_TextureCoordDim(0),
|
||||
m_pCurrentMesh(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! \brief The class destructor
|
||||
~Model() {
|
||||
for (auto & it : m_Objects) {
|
||||
delete it;
|
||||
}
|
||||
for (auto & Meshe : m_Meshes) {
|
||||
delete Meshe;
|
||||
}
|
||||
for (auto & Group : m_Groups) {
|
||||
delete Group.second;
|
||||
}
|
||||
for (auto & it : m_MaterialMap) {
|
||||
delete it.second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
} // Namespace ObjFile
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // OBJ_FILEDATA_H_INC
|
||||
783
Engine/lib/assimp/code/AssetLib/Obj/ObjFileImporter.cpp
Normal file
783
Engine/lib/assimp/code/AssetLib/Obj/ObjFileImporter.cpp
Normal file
|
|
@ -0,0 +1,783 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 "ObjFileData.h"
|
||||
#include "ObjFileParser.h"
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/IOStreamBuffer.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/ObjMaterial.h>
|
||||
#include <memory>
|
||||
|
||||
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 {
|
||||
static const char *tokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
|
||||
return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens), 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";
|
||||
auto streamCloser = [&](IOStream *pStream) {
|
||||
pIOHandler->Close(pStream);
|
||||
};
|
||||
std::unique_ptr<IOStream, decltype(streamCloser)> fileStream(pIOHandler->Open(file, mode), streamCloser);
|
||||
if (!fileStream.get()) {
|
||||
throw DeadlyImportError("Failed to open file ", file, ".");
|
||||
}
|
||||
|
||||
// Get the file-size and validate it, throwing an exception when fails
|
||||
size_t fileSize = fileStream->FileSize();
|
||||
if (fileSize < ObjMinSize) {
|
||||
throw DeadlyImportError("OBJ-file is too small.");
|
||||
}
|
||||
|
||||
IOStreamBuffer<char> streamedBuffer;
|
||||
streamedBuffer.open(fileStream.get());
|
||||
|
||||
// Allocate buffer and read file into it
|
||||
//TextFileToBuffer( fileStream.get(),m_Buffer);
|
||||
|
||||
// Get the model name
|
||||
std::string modelName, folderName;
|
||||
std::string::size_type pos = file.find_last_of("\\/");
|
||||
if (pos != std::string::npos) {
|
||||
modelName = file.substr(pos + 1, file.size() - pos - 1);
|
||||
folderName = file.substr(0, pos);
|
||||
if (!folderName.empty()) {
|
||||
pIOHandler->PushDirectory(folderName);
|
||||
}
|
||||
} else {
|
||||
modelName = file;
|
||||
}
|
||||
|
||||
// parse the file into a temporary representation
|
||||
ObjFileParser parser(streamedBuffer, modelName, pIOHandler, m_progress, file);
|
||||
|
||||
// And create the proper return structures out of it
|
||||
CreateDataFromImport(parser.GetModel(), pScene);
|
||||
|
||||
streamedBuffer.close();
|
||||
|
||||
// Clean up allocated storage for the next import
|
||||
m_Buffer.clear();
|
||||
|
||||
// Pop directory stack
|
||||
if (pIOHandler->StackSize() > 0) {
|
||||
pIOHandler->PopDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Create the data from parsed obj-file
|
||||
void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene) {
|
||||
if (nullptr == 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.empty()) {
|
||||
|
||||
unsigned int meshCount = 0;
|
||||
unsigned int childCount = 0;
|
||||
|
||||
for (auto object : pModel->m_Objects) {
|
||||
if (object) {
|
||||
++childCount;
|
||||
meshCount += (unsigned int)object->m_Meshes.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate space for the child nodes on the root node
|
||||
pScene->mRootNode->mChildren = new aiNode *[childCount];
|
||||
|
||||
// Create nodes for the whole scene
|
||||
std::vector<aiMesh *> MeshArray;
|
||||
MeshArray.reserve(meshCount);
|
||||
for (size_t index = 0; index < pModel->m_Objects.size(); ++index) {
|
||||
createNodes(pModel, pModel->m_Objects[index], pScene->mRootNode, pScene, MeshArray);
|
||||
}
|
||||
|
||||
ai_assert(pScene->mRootNode->mNumChildren == childCount);
|
||||
|
||||
// Create mesh pointer buffer for this scene
|
||||
if (pScene->mNumMeshes > 0) {
|
||||
pScene->mMeshes = new aiMesh *[MeshArray.size()];
|
||||
for (size_t index = 0; index < MeshArray.size(); ++index) {
|
||||
pScene->mMeshes[index] = MeshArray[index];
|
||||
}
|
||||
}
|
||||
|
||||
// Create all materials
|
||||
createMaterials(pModel, pScene);
|
||||
} else {
|
||||
if (pModel->m_Vertices.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<aiMesh> mesh(new aiMesh);
|
||||
mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
|
||||
unsigned int n = (unsigned int)pModel->m_Vertices.size();
|
||||
mesh->mNumVertices = n;
|
||||
|
||||
mesh->mVertices = new aiVector3D[n];
|
||||
memcpy(mesh->mVertices, pModel->m_Vertices.data(), n * sizeof(aiVector3D));
|
||||
|
||||
if (!pModel->m_Normals.empty()) {
|
||||
mesh->mNormals = new aiVector3D[n];
|
||||
if (pModel->m_Normals.size() < n) {
|
||||
throw DeadlyImportError("OBJ: vertex normal index out of range");
|
||||
}
|
||||
memcpy(mesh->mNormals, pModel->m_Normals.data(), n * sizeof(aiVector3D));
|
||||
}
|
||||
|
||||
if (!pModel->m_VertexColors.empty()) {
|
||||
mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < n; ++i) {
|
||||
if (i < pModel->m_VertexColors.size()) {
|
||||
const aiVector3D &color = pModel->m_VertexColors[i];
|
||||
mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
|
||||
} else {
|
||||
throw DeadlyImportError("OBJ: vertex color index out of range");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pScene->mRootNode->mNumMeshes = 1;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
pScene->mRootNode->mMeshes[0] = 0;
|
||||
pScene->mMeshes = new aiMesh *[1];
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes[0] = mesh.release();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates all nodes of the model
|
||||
aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pObject,
|
||||
aiNode *pParent, aiScene *pScene,
|
||||
std::vector<aiMesh *> &MeshArray) {
|
||||
ai_assert(nullptr != pModel);
|
||||
if (nullptr == pObject) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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(nullptr != pParent);
|
||||
appendChildToParentNode(pParent, pNode);
|
||||
|
||||
for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
|
||||
unsigned int meshId = pObject->m_Meshes[i];
|
||||
aiMesh *pMesh = createTopology(pModel, pObject, meshId);
|
||||
if (pMesh) {
|
||||
if (pMesh->mNumFaces > 0) {
|
||||
MeshArray.push_back(pMesh);
|
||||
} else {
|
||||
delete pMesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create all nodes from the sub-objects stored in the current object
|
||||
if (!pObject->m_SubObjects.empty()) {
|
||||
size_t numChilds = pObject->m_SubObjects.size();
|
||||
pNode->mNumChildren = static_cast<unsigned int>(numChilds);
|
||||
pNode->mChildren = new aiNode *[numChilds];
|
||||
pNode->mNumMeshes = 1;
|
||||
pNode->mMeshes = new unsigned int[1];
|
||||
}
|
||||
|
||||
// Set mesh instances into scene- and node-instances
|
||||
const size_t meshSizeDiff = MeshArray.size() - oldMeshSize;
|
||||
if (meshSizeDiff > 0) {
|
||||
pNode->mMeshes = new unsigned int[meshSizeDiff];
|
||||
pNode->mNumMeshes = static_cast<unsigned int>(meshSizeDiff);
|
||||
size_t index = 0;
|
||||
for (size_t i = oldMeshSize; i < MeshArray.size(); ++i) {
|
||||
pNode->mMeshes[index] = pScene->mNumMeshes;
|
||||
pScene->mNumMeshes++;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
return pNode;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Create topology data
|
||||
aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) {
|
||||
// Checking preconditions
|
||||
ai_assert(nullptr != pModel);
|
||||
|
||||
if (nullptr == pData) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create faces
|
||||
ObjFile::Mesh *pObjMesh = pModel->m_Meshes[meshIndex];
|
||||
if (!pObjMesh) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pObjMesh->m_Faces.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<aiMesh> pMesh(new aiMesh);
|
||||
if (!pObjMesh->m_name.empty()) {
|
||||
pMesh->mName.Set(pObjMesh->m_name);
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
|
||||
ObjFile::Face *const inp = pObjMesh->m_Faces[index];
|
||||
ai_assert(nullptr != inp);
|
||||
|
||||
if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
|
||||
pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
|
||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
} else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
|
||||
pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size());
|
||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
} else {
|
||||
++pMesh->mNumFaces;
|
||||
if (inp->m_vertices.size() > 3) {
|
||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
} else {
|
||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int uiIdxCount(0u);
|
||||
if (pMesh->mNumFaces > 0) {
|
||||
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
|
||||
if (pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial) {
|
||||
pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
|
||||
}
|
||||
|
||||
unsigned int outIndex(0);
|
||||
|
||||
// Copy all data from all stored meshes
|
||||
for (auto &face : pObjMesh->m_Faces) {
|
||||
ObjFile::Face *const inp = face;
|
||||
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)face->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(nullptr != 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 (nullptr == 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 (auto sourceFace : pObjMesh->m_Faces) {
|
||||
// Copy all index arrays
|
||||
for (size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < sourceFace->m_vertices.size(); vertexIndex++) {
|
||||
const unsigned int vertex = sourceFace->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 < sourceFace->m_normals.size()) {
|
||||
const unsigned int normal = sourceFace->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 (vertex < pModel->m_VertexColors.size()) {
|
||||
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 < sourceFace->m_texturCoords.size()) {
|
||||
const unsigned int tex = sourceFace->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 == sourceFace->m_vertices.size() - 1);
|
||||
if (sourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) {
|
||||
pDestFace->mIndices[outVertexIndex] = newIndex;
|
||||
outVertexIndex++;
|
||||
}
|
||||
|
||||
if (sourceFace->m_PrimitiveType == aiPrimitiveType_POINT) {
|
||||
outIndex++;
|
||||
outVertexIndex = 0;
|
||||
} else if (sourceFace->m_PrimitiveType == aiPrimitiveType_LINE) {
|
||||
outVertexIndex = 0;
|
||||
|
||||
if (!last)
|
||||
outIndex++;
|
||||
|
||||
if (vertexIndex) {
|
||||
if (!last) {
|
||||
pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
|
||||
if (!sourceFace->m_normals.empty() && !pModel->m_Normals.empty()) {
|
||||
pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];
|
||||
}
|
||||
if (!pModel->m_TextureCoord.empty()) {
|
||||
for (size_t i = 0; i < pMesh->GetNumUVChannels(); i++) {
|
||||
pMesh->mTextureCoords[i][newIndex + 1] = pMesh->mTextureCoords[i][newIndex];
|
||||
}
|
||||
}
|
||||
++newIndex;
|
||||
}
|
||||
|
||||
pDestFace[-1].mIndices[1] = newIndex;
|
||||
}
|
||||
} else if (last) {
|
||||
outIndex++;
|
||||
}
|
||||
++newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!normalsok) {
|
||||
delete[] pMesh->mNormals;
|
||||
pMesh->mNormals = nullptr;
|
||||
}
|
||||
|
||||
if (!uvok) {
|
||||
delete[] pMesh->mTextureCoords[0];
|
||||
pMesh->mTextureCoords[0] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Counts all stored meshes
|
||||
void ObjFileImporter::countObjects(const std::vector<ObjFile::Object *> &rObjects, int &iNumMeshes) {
|
||||
iNumMeshes = 0;
|
||||
if (rObjects.empty())
|
||||
return;
|
||||
|
||||
iNumMeshes += static_cast<unsigned int>(rObjects.size());
|
||||
for (auto object : rObjects) {
|
||||
if (!object->m_SubObjects.empty()) {
|
||||
countObjects(object->m_SubObjects, iNumMeshes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Add clamp mode property to material if necessary
|
||||
void ObjFileImporter::addTextureMappingModeProperty(aiMaterial *mat, aiTextureType type, int clampMode, int index) {
|
||||
if (nullptr == mat) {
|
||||
return;
|
||||
}
|
||||
|
||||
mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, index));
|
||||
mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, index));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates the material
|
||||
void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pScene) {
|
||||
if (nullptr == pScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int numMaterials = (unsigned int)pModel->m_MaterialLib.size();
|
||||
pScene->mNumMaterials = 0;
|
||||
if (pModel->m_MaterialLib.empty()) {
|
||||
ASSIMP_LOG_DEBUG("OBJ: no materials specified");
|
||||
return;
|
||||
}
|
||||
|
||||
pScene->mMaterials = new aiMaterial *[numMaterials];
|
||||
for (unsigned int matIndex = 0; matIndex < numMaterials; matIndex++) {
|
||||
// Store material name
|
||||
std::map<std::string, ObjFile::Material *>::const_iterator it;
|
||||
it = pModel->m_MaterialMap.find(pModel->m_MaterialLib[matIndex]);
|
||||
|
||||
// No material found, use the default material
|
||||
if (pModel->m_MaterialMap.end() == it)
|
||||
continue;
|
||||
|
||||
aiMaterial *mat = new aiMaterial;
|
||||
ObjFile::Material *pCurrentMaterial = (*it).second;
|
||||
mat->AddProperty(&pCurrentMaterial->MaterialName, AI_MATKEY_NAME);
|
||||
|
||||
// convert illumination model
|
||||
int sm = 0;
|
||||
switch (pCurrentMaterial->illumination_model) {
|
||||
case 0:
|
||||
sm = aiShadingMode_NoShading;
|
||||
break;
|
||||
case 1:
|
||||
sm = aiShadingMode_Gouraud;
|
||||
break;
|
||||
case 2:
|
||||
sm = aiShadingMode_Phong;
|
||||
break;
|
||||
default:
|
||||
sm = aiShadingMode_Gouraud;
|
||||
ASSIMP_LOG_ERROR("OBJ: unexpected illumination model (0-2 recognized)");
|
||||
}
|
||||
|
||||
mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
// Preserve the original illum value
|
||||
mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
|
||||
|
||||
// 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);
|
||||
mat->AddProperty(&pCurrentMaterial->roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
|
||||
mat->AddProperty(&pCurrentMaterial->metallic, 1, AI_MATKEY_METALLIC_FACTOR);
|
||||
mat->AddProperty(&pCurrentMaterial->sheen, 1, AI_MATKEY_SHEEN_COLOR_FACTOR);
|
||||
mat->AddProperty(&pCurrentMaterial->clearcoat_thickness, 1, AI_MATKEY_CLEARCOAT_FACTOR);
|
||||
mat->AddProperty(&pCurrentMaterial->clearcoat_roughness, 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
|
||||
mat->AddProperty(&pCurrentMaterial->anisotropy, 1, AI_MATKEY_ANISOTROPY_FACTOR);
|
||||
|
||||
// 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->bump_multiplier != 1.0) {
|
||||
mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_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->bump_multiplier != 1.0) {
|
||||
mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != pCurrentMaterial->textureRoughness.length) {
|
||||
mat->AddProperty(&pCurrentMaterial->textureRoughness, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE_ROUGHNESS, 0);
|
||||
mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_DIFFUSE_ROUGHNESS, 0 );
|
||||
if (pCurrentMaterial->clamp[ObjFile::Material::TextureRoughnessType]) {
|
||||
addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE_ROUGHNESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != pCurrentMaterial->textureMetallic.length) {
|
||||
mat->AddProperty(&pCurrentMaterial->textureMetallic, _AI_MATKEY_TEXTURE_BASE, aiTextureType_METALNESS, 0);
|
||||
mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_METALNESS, 0 );
|
||||
if (pCurrentMaterial->clamp[ObjFile::Material::TextureMetallicType]) {
|
||||
addTextureMappingModeProperty(mat, aiTextureType_METALNESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != pCurrentMaterial->textureSheen.length) {
|
||||
mat->AddProperty(&pCurrentMaterial->textureSheen, _AI_MATKEY_TEXTURE_BASE, aiTextureType_SHEEN, 0);
|
||||
mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_SHEEN, 0 );
|
||||
if (pCurrentMaterial->clamp[ObjFile::Material::TextureSheenType]) {
|
||||
addTextureMappingModeProperty(mat, aiTextureType_SHEEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != pCurrentMaterial->textureRMA.length) {
|
||||
// NOTE: glTF importer places Rough/Metal/AO texture in Unknown so doing the same here for consistency.
|
||||
mat->AddProperty(&pCurrentMaterial->textureRMA, _AI_MATKEY_TEXTURE_BASE, aiTextureType_UNKNOWN, 0);
|
||||
mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_UNKNOWN, 0 );
|
||||
if (pCurrentMaterial->clamp[ObjFile::Material::TextureRMAType]) {
|
||||
addTextureMappingModeProperty(mat, aiTextureType_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
// 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(nullptr != pParent);
|
||||
ai_assert(nullptr != 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
|
||||
122
Engine/lib/assimp/code/AssetLib/Obj/ObjFileImporter.h
Normal file
122
Engine/lib/assimp/code/AssetLib/Obj/ObjFileImporter.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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_FILE_IMPORTER_H_INC
|
||||
#define OBJ_FILE_IMPORTER_H_INC
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/material.h>
|
||||
#include <vector>
|
||||
|
||||
struct aiMesh;
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace ObjFile {
|
||||
struct Object;
|
||||
struct Model;
|
||||
} // namespace ObjFile
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/// \class ObjFileImporter
|
||||
/// \brief Imports a waveform obj file
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class ObjFileImporter : public BaseImporter {
|
||||
public:
|
||||
/// \brief Default constructor
|
||||
ObjFileImporter();
|
||||
|
||||
/// \brief Destructor
|
||||
~ObjFileImporter() override;
|
||||
|
||||
/// \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 override;
|
||||
|
||||
protected:
|
||||
//! \brief Appends the supported extension.
|
||||
const aiImporterDesc *GetInfo() const override;
|
||||
|
||||
//! \brief File import implementation.
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||
|
||||
//! \brief Create the data from imported content.
|
||||
void CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene);
|
||||
|
||||
//! \brief Creates all nodes stored in imported content.
|
||||
aiNode *createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pData,
|
||||
aiNode *pParent, aiScene *pScene, std::vector<aiMesh *> &MeshArray);
|
||||
|
||||
//! \brief Creates topology data like faces and meshes for the geometry.
|
||||
aiMesh *createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData,
|
||||
unsigned int uiMeshIndex);
|
||||
|
||||
//! \brief Creates vertices from model.
|
||||
void createVertexArray(const ObjFile::Model *pModel, const ObjFile::Object *pCurrentObject,
|
||||
unsigned int uiMeshIndex, aiMesh *pMesh, unsigned int numIndices);
|
||||
|
||||
//! \brief Object counter helper method.
|
||||
void countObjects(const std::vector<ObjFile::Object *> &rObjects, int &iNumMeshes);
|
||||
|
||||
//! \brief Material creation.
|
||||
void createMaterials(const ObjFile::Model *pModel, aiScene *pScene);
|
||||
|
||||
/// @brief Adds special property for the used texture mapping mode of the model.
|
||||
void addTextureMappingModeProperty(aiMaterial *mat, aiTextureType type, int clampMode = 1, int index = 0);
|
||||
|
||||
//! \brief Appends a child node to a parent node and updates the data structures.
|
||||
void appendChildToParentNode(aiNode *pParent, aiNode *pChild);
|
||||
|
||||
private:
|
||||
//! Data buffer
|
||||
std::vector<char> m_Buffer;
|
||||
//! Pointer to root object instance
|
||||
ObjFile::Object *m_pRootObject;
|
||||
//! Absolute pathname of model in file system
|
||||
std::string m_strAbsPath;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif
|
||||
498
Engine/lib/assimp/code/AssetLib/Obj/ObjFileMtlImporter.cpp
Normal file
498
Engine/lib/assimp/code/AssetLib/Obj/ObjFileMtlImporter.cpp
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 "ObjFileMtlImporter.h"
|
||||
#include "ObjFileData.h"
|
||||
#include "ObjTools.h"
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/material.h>
|
||||
#include <stdlib.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// Material specific token (case insensitive compare)
|
||||
static const std::string DiffuseTexture = "map_Kd";
|
||||
static const std::string AmbientTexture = "map_Ka";
|
||||
static const std::string SpecularTexture = "map_Ks";
|
||||
static const std::string OpacityTexture = "map_d";
|
||||
static const std::string EmissiveTexture1 = "map_emissive";
|
||||
static const std::string EmissiveTexture2 = "map_Ke";
|
||||
static const std::string BumpTexture1 = "map_bump";
|
||||
static const std::string BumpTexture2 = "bump";
|
||||
static const std::string NormalTextureV1 = "map_Kn";
|
||||
static const std::string NormalTextureV2 = "norm";
|
||||
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";
|
||||
static const std::string RoughnessTexture = "map_Pr";
|
||||
static const std::string MetallicTexture = "map_Pm";
|
||||
static const std::string SheenTexture = "map_Ps";
|
||||
static const std::string RMATexture = "map_Ps";
|
||||
|
||||
// texture option specific token
|
||||
static const std::string BlendUOption = "-blendu";
|
||||
static const std::string BlendVOption = "-blendv";
|
||||
static const std::string BoostOption = "-boost";
|
||||
static const std::string ModifyMapOption = "-mm";
|
||||
static const std::string OffsetOption = "-o";
|
||||
static const std::string ScaleOption = "-s";
|
||||
static const std::string TurbulenceOption = "-t";
|
||||
static const std::string ResolutionOption = "-texres";
|
||||
static const std::string ClampOption = "-clamp";
|
||||
static const std::string BumpOption = "-bm";
|
||||
static const std::string ChannelOption = "-imfchan";
|
||||
static const std::string TypeOption = "-type";
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Constructor
|
||||
ObjFileMtlImporter::ObjFileMtlImporter(std::vector<char> &buffer,
|
||||
const std::string &,
|
||||
ObjFile::Model *pModel) :
|
||||
m_DataIt(buffer.begin()),
|
||||
m_DataItEnd(buffer.end()),
|
||||
m_pModel(pModel),
|
||||
m_uiLine(0),
|
||||
m_buffer() {
|
||||
ai_assert(nullptr != m_pModel);
|
||||
m_buffer.resize(BUFFERSIZE);
|
||||
std::fill(m_buffer.begin(), m_buffer.end(), '\0');
|
||||
if (nullptr == m_pModel->m_pDefaultMaterial) {
|
||||
m_pModel->m_pDefaultMaterial = new ObjFile::Material;
|
||||
m_pModel->m_pDefaultMaterial->MaterialName.Set("default");
|
||||
}
|
||||
load();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Destructor
|
||||
ObjFileMtlImporter::~ObjFileMtlImporter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Loads the material description
|
||||
void ObjFileMtlImporter::load() {
|
||||
if (m_DataIt == m_DataItEnd)
|
||||
return;
|
||||
|
||||
while (m_DataIt != m_DataItEnd) {
|
||||
switch (*m_DataIt) {
|
||||
case 'k':
|
||||
case 'K': {
|
||||
++m_DataIt;
|
||||
if (*m_DataIt == 'a') // Ambient color
|
||||
{
|
||||
++m_DataIt;
|
||||
getColorRGBA(&m_pModel->m_pCurrentMaterial->ambient);
|
||||
} else if (*m_DataIt == 'd') {
|
||||
// Diffuse color
|
||||
++m_DataIt;
|
||||
getColorRGBA(&m_pModel->m_pCurrentMaterial->diffuse);
|
||||
} else if (*m_DataIt == 's') {
|
||||
++m_DataIt;
|
||||
getColorRGBA(&m_pModel->m_pCurrentMaterial->specular);
|
||||
} else if (*m_DataIt == 'e') {
|
||||
++m_DataIt;
|
||||
getColorRGBA(&m_pModel->m_pCurrentMaterial->emissive);
|
||||
}
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
case 'T': {
|
||||
++m_DataIt;
|
||||
// Material transmission color
|
||||
if (*m_DataIt == 'f') {
|
||||
++m_DataIt;
|
||||
getColorRGBA(&m_pModel->m_pCurrentMaterial->transparent);
|
||||
} else if (*m_DataIt == 'r') {
|
||||
// Material transmission alpha value
|
||||
++m_DataIt;
|
||||
ai_real d;
|
||||
getFloatValue(d);
|
||||
m_pModel->m_pCurrentMaterial->alpha = static_cast<ai_real>(1.0) - d;
|
||||
}
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
case 'd': {
|
||||
if (*(m_DataIt + 1) == 'i' && *(m_DataIt + 2) == 's' && *(m_DataIt + 3) == 'p') {
|
||||
// A displacement map
|
||||
getTexture();
|
||||
} else {
|
||||
// Alpha value
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->alpha);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
} break;
|
||||
|
||||
case 'N':
|
||||
case 'n': {
|
||||
++m_DataIt;
|
||||
switch (*m_DataIt) {
|
||||
case 's': // Specular exponent
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
|
||||
break;
|
||||
case 'i': // Index Of refraction
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->ior);
|
||||
break;
|
||||
case 'e': // New material
|
||||
createMaterial();
|
||||
break;
|
||||
case 'o': // Norm texture
|
||||
--m_DataIt;
|
||||
getTexture();
|
||||
break;
|
||||
}
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
|
||||
case 'P':
|
||||
{
|
||||
++m_DataIt;
|
||||
switch(*m_DataIt)
|
||||
{
|
||||
case 'r':
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->roughness);
|
||||
break;
|
||||
case 'm':
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->metallic);
|
||||
break;
|
||||
case 's':
|
||||
++m_DataIt;
|
||||
getColorRGBA(&m_pModel->m_pCurrentMaterial->sheen);
|
||||
break;
|
||||
case 'c':
|
||||
++m_DataIt;
|
||||
if (*m_DataIt == 'r') {
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->clearcoat_roughness);
|
||||
} else {
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->clearcoat_thickness);
|
||||
}
|
||||
break;
|
||||
}
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': // Texture
|
||||
case 'b': // quick'n'dirty - for 'bump' sections
|
||||
case 'r': // quick'n'dirty - for 'refl' sections
|
||||
{
|
||||
getTexture();
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
|
||||
case 'i': // Illumination model
|
||||
{
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
getIlluminationModel(m_pModel->m_pCurrentMaterial->illumination_model);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
|
||||
case 'a': // Anisotropy
|
||||
{
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->anisotropy);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Loads a color definition
|
||||
void ObjFileMtlImporter::getColorRGBA(aiColor3D *pColor) {
|
||||
ai_assert(nullptr != pColor);
|
||||
|
||||
ai_real r(0.0), g(0.0), b(0.0);
|
||||
m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, r);
|
||||
pColor->r = r;
|
||||
|
||||
// we have to check if color is default 0 with only one token
|
||||
if (!IsLineEnd(*m_DataIt)) {
|
||||
m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, g);
|
||||
m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, b);
|
||||
}
|
||||
pColor->g = g;
|
||||
pColor->b = b;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Loads the kind of illumination model.
|
||||
void ObjFileMtlImporter::getIlluminationModel(int &illum_model) {
|
||||
m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
|
||||
illum_model = atoi(&m_buffer[0]);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Loads a single float value.
|
||||
void ObjFileMtlImporter::getFloatValue(ai_real &value) {
|
||||
m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
|
||||
size_t len = std::strlen(&m_buffer[0]);
|
||||
if (0 == len) {
|
||||
value = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
value = (ai_real)fast_atof(&m_buffer[0]);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Creates a material from loaded data.
|
||||
void ObjFileMtlImporter::createMaterial() {
|
||||
std::string line;
|
||||
while (!IsLineEnd(*m_DataIt)) {
|
||||
line += *m_DataIt;
|
||||
++m_DataIt;
|
||||
}
|
||||
|
||||
std::vector<std::string> token;
|
||||
const unsigned int numToken = tokenize<std::string>(line, token, " \t");
|
||||
std::string name;
|
||||
if (numToken == 1) {
|
||||
name = AI_DEFAULT_MATERIAL_NAME;
|
||||
} else {
|
||||
// skip newmtl and all following white spaces
|
||||
std::size_t first_ws_pos = line.find_first_of(" \t");
|
||||
std::size_t first_non_ws_pos = line.find_first_not_of(" \t", first_ws_pos);
|
||||
if (first_non_ws_pos != std::string::npos) {
|
||||
name = line.substr(first_non_ws_pos);
|
||||
}
|
||||
}
|
||||
|
||||
name = trim_whitespaces(name);
|
||||
|
||||
std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->m_MaterialMap.find(name);
|
||||
if (m_pModel->m_MaterialMap.end() == it) {
|
||||
// New Material created
|
||||
m_pModel->m_pCurrentMaterial = new ObjFile::Material();
|
||||
m_pModel->m_pCurrentMaterial->MaterialName.Set(name);
|
||||
m_pModel->m_MaterialLib.push_back(name);
|
||||
m_pModel->m_MaterialMap[name] = m_pModel->m_pCurrentMaterial;
|
||||
|
||||
if (m_pModel->m_pCurrentMesh) {
|
||||
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
|
||||
}
|
||||
} else {
|
||||
// Use older material
|
||||
m_pModel->m_pCurrentMaterial = (*it).second;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Gets a texture name from data.
|
||||
void ObjFileMtlImporter::getTexture() {
|
||||
aiString *out(nullptr);
|
||||
int clampIndex = -1;
|
||||
|
||||
const char *pPtr(&(*m_DataIt));
|
||||
if (!ASSIMP_strincmp(pPtr, DiffuseTexture.c_str(), static_cast<unsigned int>(DiffuseTexture.size()))) {
|
||||
// Diffuse texture
|
||||
out = &m_pModel->m_pCurrentMaterial->texture;
|
||||
clampIndex = ObjFile::Material::TextureDiffuseType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, AmbientTexture.c_str(), static_cast<unsigned int>(AmbientTexture.size()))) {
|
||||
// Ambient texture
|
||||
out = &m_pModel->m_pCurrentMaterial->textureAmbient;
|
||||
clampIndex = ObjFile::Material::TextureAmbientType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, SpecularTexture.c_str(), static_cast<unsigned int>(SpecularTexture.size()))) {
|
||||
// Specular texture
|
||||
out = &m_pModel->m_pCurrentMaterial->textureSpecular;
|
||||
clampIndex = ObjFile::Material::TextureSpecularType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, DisplacementTexture1.c_str(), static_cast<unsigned int>(DisplacementTexture1.size())) ||
|
||||
!ASSIMP_strincmp(pPtr, DisplacementTexture2.c_str(), static_cast<unsigned int>(DisplacementTexture2.size()))) {
|
||||
// Displacement texture
|
||||
out = &m_pModel->m_pCurrentMaterial->textureDisp;
|
||||
clampIndex = ObjFile::Material::TextureDispType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, OpacityTexture.c_str(), static_cast<unsigned int>(OpacityTexture.size()))) {
|
||||
// Opacity texture
|
||||
out = &m_pModel->m_pCurrentMaterial->textureOpacity;
|
||||
clampIndex = ObjFile::Material::TextureOpacityType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, EmissiveTexture1.c_str(), static_cast<unsigned int>(EmissiveTexture1.size())) ||
|
||||
!ASSIMP_strincmp(pPtr, EmissiveTexture2.c_str(), static_cast<unsigned int>(EmissiveTexture2.size()))) {
|
||||
// Emissive texture
|
||||
out = &m_pModel->m_pCurrentMaterial->textureEmissive;
|
||||
clampIndex = ObjFile::Material::TextureEmissiveType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, BumpTexture1.c_str(), static_cast<unsigned int>(BumpTexture1.size())) ||
|
||||
!ASSIMP_strincmp(pPtr, BumpTexture2.c_str(), static_cast<unsigned int>(BumpTexture2.size()))) {
|
||||
// Bump texture
|
||||
out = &m_pModel->m_pCurrentMaterial->textureBump;
|
||||
clampIndex = ObjFile::Material::TextureBumpType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, NormalTextureV1.c_str(), static_cast<unsigned int>(NormalTextureV1.size())) || !ASSIMP_strincmp(pPtr, NormalTextureV2.c_str(), static_cast<unsigned int>(NormalTextureV2.size()))) {
|
||||
// Normal map
|
||||
out = &m_pModel->m_pCurrentMaterial->textureNormal;
|
||||
clampIndex = ObjFile::Material::TextureNormalType;
|
||||
} else if (!ASSIMP_strincmp(pPtr, ReflectionTexture.c_str(), static_cast<unsigned int>(ReflectionTexture.size()))) {
|
||||
// Reflection texture(s)
|
||||
//Do nothing here
|
||||
return;
|
||||
} else if (!ASSIMP_strincmp(pPtr, SpecularityTexture.c_str(), static_cast<unsigned int>(SpecularityTexture.size()))) {
|
||||
// Specularity scaling (glossiness)
|
||||
out = &m_pModel->m_pCurrentMaterial->textureSpecularity;
|
||||
clampIndex = ObjFile::Material::TextureSpecularityType;
|
||||
} else if ( !ASSIMP_strincmp( pPtr, RoughnessTexture.c_str(), static_cast<unsigned int>(RoughnessTexture.size()))) {
|
||||
// PBR Roughness texture
|
||||
out = & m_pModel->m_pCurrentMaterial->textureRoughness;
|
||||
clampIndex = ObjFile::Material::TextureRoughnessType;
|
||||
} else if ( !ASSIMP_strincmp( pPtr, MetallicTexture.c_str(), static_cast<unsigned int>(MetallicTexture.size()))) {
|
||||
// PBR Metallic texture
|
||||
out = & m_pModel->m_pCurrentMaterial->textureMetallic;
|
||||
clampIndex = ObjFile::Material::TextureMetallicType;
|
||||
} else if (!ASSIMP_strincmp( pPtr, SheenTexture.c_str(), static_cast<unsigned int>(SheenTexture.size()))) {
|
||||
// PBR Sheen (reflectance) texture
|
||||
out = & m_pModel->m_pCurrentMaterial->textureSheen;
|
||||
clampIndex = ObjFile::Material::TextureSheenType;
|
||||
} else if (!ASSIMP_strincmp( pPtr, RMATexture.c_str(), static_cast<unsigned int>(RMATexture.size()))) {
|
||||
// PBR Rough/Metal/AO texture
|
||||
out = & m_pModel->m_pCurrentMaterial->textureRMA;
|
||||
clampIndex = ObjFile::Material::TextureRMAType;
|
||||
} else {
|
||||
ASSIMP_LOG_ERROR("OBJ/MTL: Encountered unknown texture type");
|
||||
return;
|
||||
}
|
||||
|
||||
bool clamp = false;
|
||||
getTextureOption(clamp, clampIndex, out);
|
||||
m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
|
||||
|
||||
std::string texture;
|
||||
m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, texture);
|
||||
if (nullptr != out) {
|
||||
out->Set(texture);
|
||||
}
|
||||
}
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////////////
|
||||
* Texture Option
|
||||
* /////////////////////////////////////////////////////////////////////////////
|
||||
* According to http://en.wikipedia.org/wiki/Wavefront_.obj_file#Texture_options
|
||||
* Texture map statement can contains various texture option, for example:
|
||||
*
|
||||
* map_Ka -o 1 1 1 some.png
|
||||
* map_Kd -clamp on some.png
|
||||
*
|
||||
* So we need to parse and skip these options, and leave the last part which is
|
||||
* the url of image, otherwise we will get a wrong url like "-clamp on some.png".
|
||||
*
|
||||
* Because aiMaterial supports clamp option, so we also want to return it
|
||||
* /////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) {
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
|
||||
// If there is any more texture option
|
||||
while (!isEndOfBuffer(m_DataIt, m_DataItEnd) && *m_DataIt == '-') {
|
||||
const char *pPtr(&(*m_DataIt));
|
||||
//skip option key and value
|
||||
int skipToken = 1;
|
||||
|
||||
if (!ASSIMP_strincmp(pPtr, ClampOption.c_str(), static_cast<unsigned int>(ClampOption.size()))) {
|
||||
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
char value[3];
|
||||
CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
|
||||
if (!ASSIMP_strincmp(value, "on", 2)) {
|
||||
clamp = true;
|
||||
}
|
||||
|
||||
skipToken = 2;
|
||||
} else if (!ASSIMP_strincmp(pPtr, TypeOption.c_str(), static_cast<unsigned int>(TypeOption.size()))) {
|
||||
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
char value[12];
|
||||
CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
|
||||
if (!ASSIMP_strincmp(value, "cube_top", 8)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
|
||||
} else if (!ASSIMP_strincmp(value, "cube_bottom", 11)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[1];
|
||||
} else if (!ASSIMP_strincmp(value, "cube_front", 10)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[2];
|
||||
} else if (!ASSIMP_strincmp(value, "cube_back", 9)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[3];
|
||||
} else if (!ASSIMP_strincmp(value, "cube_left", 9)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[4];
|
||||
} else if (!ASSIMP_strincmp(value, "cube_right", 10)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[5];
|
||||
} else if (!ASSIMP_strincmp(value, "sphere", 6)) {
|
||||
clampIndex = ObjFile::Material::TextureReflectionSphereType;
|
||||
out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
|
||||
}
|
||||
|
||||
skipToken = 2;
|
||||
} else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))) {
|
||||
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
getFloat(it, m_DataItEnd, m_pModel->m_pCurrentMaterial->bump_multiplier);
|
||||
skipToken = 2;
|
||||
} else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
|
||||
skipToken = 2;
|
||||
} else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size()))) {
|
||||
skipToken = 3;
|
||||
} else if (!ASSIMP_strincmp(pPtr, OffsetOption.c_str(), static_cast<unsigned int>(OffsetOption.size())) || !ASSIMP_strincmp(pPtr, ScaleOption.c_str(), static_cast<unsigned int>(ScaleOption.size())) || !ASSIMP_strincmp(pPtr, TurbulenceOption.c_str(), static_cast<unsigned int>(TurbulenceOption.size()))) {
|
||||
skipToken = 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < skipToken; ++i) {
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER
|
||||
113
Engine/lib/assimp/code/AssetLib/Obj/ObjFileMtlImporter.h
Normal file
113
Engine/lib/assimp/code/AssetLib/Obj/ObjFileMtlImporter.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 <assimp/defs.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct aiColor3D;
|
||||
struct aiString;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace ObjFile {
|
||||
struct Model;
|
||||
struct Material;
|
||||
} // namespace ObjFile
|
||||
|
||||
/**
|
||||
* @class ObjFileMtlImporter
|
||||
* @brief Loads the material description from a mtl file.
|
||||
*/
|
||||
class ObjFileMtlImporter {
|
||||
public:
|
||||
static const size_t BUFFERSIZE = 2048;
|
||||
using DataArray = std::vector<char>;
|
||||
using DataArrayIt = std::vector<char>::iterator;
|
||||
using ConstDataArrayIt = std::vector<char>::const_iterator;
|
||||
|
||||
//! \brief The class default constructor
|
||||
ObjFileMtlImporter(std::vector<char> &buffer, const std::string &strAbsPath,
|
||||
ObjFile::Model *pModel);
|
||||
|
||||
//! \brief The class destructor
|
||||
~ObjFileMtlImporter();
|
||||
|
||||
ObjFileMtlImporter(const ObjFileMtlImporter &rOther) = delete;
|
||||
ObjFileMtlImporter &operator=(const ObjFileMtlImporter &rOther) = delete;
|
||||
|
||||
private:
|
||||
/// Copy constructor, empty.
|
||||
/// 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
|
||||
std::vector<char> m_buffer;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // OBJFILEMTLIMPORTER_H_INC
|
||||
859
Engine/lib/assimp/code/AssetLib/Obj/ObjFileParser.cpp
Normal file
859
Engine/lib/assimp/code/AssetLib/Obj/ObjFileParser.cpp
Normal file
|
|
@ -0,0 +1,859 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 "ObjFileData.h"
|
||||
#include "ObjFileMtlImporter.h"
|
||||
#include "ObjTools.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
constexpr char ObjFileParser::DEFAULT_MATERIAL[];
|
||||
|
||||
ObjFileParser::ObjFileParser() :
|
||||
m_DataIt(),
|
||||
m_DataItEnd(),
|
||||
m_pModel(nullptr),
|
||||
m_uiLine(0),
|
||||
m_buffer(),
|
||||
m_pIO(nullptr),
|
||||
m_progress(nullptr),
|
||||
m_originalObjFileName() {
|
||||
std::fill_n(m_buffer, Buffersize, '\0');
|
||||
}
|
||||
|
||||
ObjFileParser::ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName,
|
||||
IOSystem *io, ProgressHandler *progress,
|
||||
const std::string &originalObjFileName) :
|
||||
m_DataIt(),
|
||||
m_DataItEnd(),
|
||||
m_pModel(nullptr),
|
||||
m_uiLine(0),
|
||||
m_buffer(),
|
||||
m_pIO(io),
|
||||
m_progress(progress),
|
||||
m_originalObjFileName(originalObjFileName) {
|
||||
std::fill_n(m_buffer, Buffersize, '\0');
|
||||
|
||||
// Create the model instance to store all the data
|
||||
m_pModel.reset(new ObjFile::Model());
|
||||
m_pModel->m_ModelName = modelName;
|
||||
|
||||
// create default material and store it
|
||||
m_pModel->m_pDefaultMaterial = new ObjFile::Material;
|
||||
m_pModel->m_pDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
|
||||
m_pModel->m_MaterialLib.push_back(DEFAULT_MATERIAL);
|
||||
m_pModel->m_MaterialMap[DEFAULT_MATERIAL] = m_pModel->m_pDefaultMaterial;
|
||||
|
||||
// Start parsing the file
|
||||
parseFile(streamBuffer);
|
||||
}
|
||||
|
||||
ObjFileParser::~ObjFileParser() {
|
||||
}
|
||||
|
||||
void ObjFileParser::setBuffer(std::vector<char> &buffer) {
|
||||
m_DataIt = buffer.begin();
|
||||
m_DataItEnd = buffer.end();
|
||||
}
|
||||
|
||||
ObjFile::Model *ObjFileParser::GetModel() const {
|
||||
return m_pModel.get();
|
||||
}
|
||||
|
||||
void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||
// only update every 100KB or it'll be too slow
|
||||
//const unsigned int updateProgressEveryBytes = 100 * 1024;
|
||||
unsigned int progressCounter = 0;
|
||||
const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
|
||||
const unsigned int progressTotal = bytesToProcess;
|
||||
unsigned int processed = 0;
|
||||
size_t lastFilePos(0);
|
||||
|
||||
bool insideCstype = false;
|
||||
std::vector<char> buffer;
|
||||
while (streamBuffer.getNextDataLine(buffer, '\\')) {
|
||||
m_DataIt = buffer.begin();
|
||||
m_DataItEnd = buffer.end();
|
||||
|
||||
// Handle progress reporting
|
||||
const size_t filePos(streamBuffer.getFilePos());
|
||||
if (lastFilePos < filePos) {
|
||||
processed = static_cast<unsigned int>(filePos);
|
||||
lastFilePos = filePos;
|
||||
progressCounter++;
|
||||
m_progress->UpdateFileRead(processed, progressTotal);
|
||||
}
|
||||
|
||||
// handle cstype section end (http://paulbourke.net/dataformats/obj/)
|
||||
if (insideCstype) {
|
||||
switch (*m_DataIt) {
|
||||
case 'e': {
|
||||
std::string name;
|
||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
||||
insideCstype = name != "end";
|
||||
} break;
|
||||
}
|
||||
goto pf_skip_line;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
case 'c': // handle cstype section start
|
||||
{
|
||||
std::string name;
|
||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
||||
insideCstype = name == "cstype";
|
||||
goto pf_skip_line;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
pf_skip_line:
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
|
||||
size_t index = 0;
|
||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if (*m_DataIt == '\\') {
|
||||
++m_DataIt;
|
||||
++m_DataIt;
|
||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
}
|
||||
while (m_DataIt != m_DataItEnd && !IsSpaceOrNewLine(*m_DataIt)) {
|
||||
pBuffer[index] = *m_DataIt;
|
||||
index++;
|
||||
if (index == length - 1) {
|
||||
break;
|
||||
}
|
||||
++m_DataIt;
|
||||
}
|
||||
|
||||
ai_assert(index < length);
|
||||
pBuffer[index] = '\0';
|
||||
}
|
||||
|
||||
static bool isDataDefinitionEnd(const char *tmp) {
|
||||
if (*tmp == '\\') {
|
||||
tmp++;
|
||||
if (IsLineEnd(*tmp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isNanOrInf(const char *in) {
|
||||
// Look for "nan" or "inf", case insensitive
|
||||
return ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) ||
|
||||
((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0);
|
||||
}
|
||||
|
||||
size_t ObjFileParser::getNumComponentsInDataDefinition() {
|
||||
size_t numComponents(0);
|
||||
const char *tmp(&m_DataIt[0]);
|
||||
bool end_of_definition = false;
|
||||
while (!end_of_definition) {
|
||||
if (isDataDefinitionEnd(tmp)) {
|
||||
tmp += 2;
|
||||
} else if (IsLineEnd(*tmp)) {
|
||||
end_of_definition = true;
|
||||
}
|
||||
if (!SkipSpaces(&tmp)) {
|
||||
break;
|
||||
}
|
||||
const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp));
|
||||
SkipToken(tmp);
|
||||
if (isNum) {
|
||||
++numComponents;
|
||||
}
|
||||
if (!SkipSpaces(&tmp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return numComponents;
|
||||
}
|
||||
|
||||
size_t ObjFileParser::getTexCoordVector(std::vector<aiVector3D> &point3d_array) {
|
||||
size_t numComponents = getNumComponentsInDataDefinition();
|
||||
ai_real x, y, z;
|
||||
if (2 == numComponents) {
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
x = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
y = (ai_real)fast_atof(m_buffer);
|
||||
z = 0.0;
|
||||
} else if (3 == numComponents) {
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
x = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
y = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
z = (ai_real)fast_atof(m_buffer);
|
||||
} else {
|
||||
throw DeadlyImportError("OBJ: Invalid number of components");
|
||||
}
|
||||
|
||||
// Coerce nan and inf to 0 as is the OBJ default value
|
||||
if (!std::isfinite(x))
|
||||
x = 0;
|
||||
|
||||
if (!std::isfinite(y))
|
||||
y = 0;
|
||||
|
||||
if (!std::isfinite(z))
|
||||
z = 0;
|
||||
|
||||
point3d_array.emplace_back(x, y, z);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
return numComponents;
|
||||
}
|
||||
|
||||
void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
|
||||
ai_real x, y, z;
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
x = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
y = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
z = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
point3d_array.emplace_back(x, y, z);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
void ObjFileParser::getHomogeneousVector3(std::vector<aiVector3D> &point3d_array) {
|
||||
ai_real x, y, z, w;
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
x = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
y = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
z = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
w = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
if (w == 0)
|
||||
throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
|
||||
|
||||
point3d_array.emplace_back(x / w, y / w, z / w);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
void ObjFileParser::getTwoVectors3(std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b) {
|
||||
ai_real x, y, z;
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
x = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
y = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
z = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
point3d_array_a.emplace_back(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.emplace_back(x, y, z);
|
||||
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
void ObjFileParser::getVector2(std::vector<aiVector2D> &point2d_array) {
|
||||
ai_real x, y;
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
x = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
copyNextWord(m_buffer, Buffersize);
|
||||
y = (ai_real)fast_atof(m_buffer);
|
||||
|
||||
point2d_array.emplace_back(x, y);
|
||||
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
static const std::string DefaultObjName = "defaultobject";
|
||||
|
||||
void ObjFileParser::getFace(aiPrimitiveType type) {
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if (m_DataIt == m_DataItEnd || *m_DataIt == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
ObjFile::Face *face = new ObjFile::Face(type);
|
||||
bool hasNormal = false;
|
||||
|
||||
const int vSize = static_cast<unsigned int>(m_pModel->m_Vertices.size());
|
||||
const int vtSize = static_cast<unsigned int>(m_pModel->m_TextureCoord.size());
|
||||
const int vnSize = static_cast<unsigned int>(m_pModel->m_Normals.size());
|
||||
|
||||
const bool vt = (!m_pModel->m_TextureCoord.empty());
|
||||
const bool vn = (!m_pModel->m_Normals.empty());
|
||||
int iPos = 0;
|
||||
while (m_DataIt != m_DataItEnd) {
|
||||
int iStep = 1;
|
||||
|
||||
if (IsLineEnd(*m_DataIt)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*m_DataIt == '/') {
|
||||
if (type == aiPrimitiveType_POINT) {
|
||||
ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement");
|
||||
}
|
||||
iPos++;
|
||||
} else if (IsSpaceOrNewLine(*m_DataIt)) {
|
||||
iPos = 0;
|
||||
} else {
|
||||
//OBJ USES 1 Base ARRAYS!!!!
|
||||
const int iVal(::atoi(&(*m_DataIt)));
|
||||
|
||||
// increment iStep position based off of the sign and # of digits
|
||||
int tmp = iVal;
|
||||
if (iVal < 0) {
|
||||
++iStep;
|
||||
}
|
||||
while ((tmp = tmp / 10) != 0) {
|
||||
++iStep;
|
||||
}
|
||||
|
||||
if (iPos == 1 && !vt && vn)
|
||||
iPos = 2; // skip texture coords for normals if there are no tex coords
|
||||
|
||||
if (iVal > 0) {
|
||||
// Store parsed index
|
||||
if (0 == iPos) {
|
||||
face->m_vertices.push_back(iVal - 1);
|
||||
} else if (1 == iPos) {
|
||||
face->m_texturCoords.push_back(iVal - 1);
|
||||
} else if (2 == iPos) {
|
||||
face->m_normals.push_back(iVal - 1);
|
||||
hasNormal = true;
|
||||
} else {
|
||||
reportErrorTokenInFace();
|
||||
}
|
||||
} else if (iVal < 0) {
|
||||
// Store relatively index
|
||||
if (0 == iPos) {
|
||||
face->m_vertices.push_back(vSize + iVal);
|
||||
} else if (1 == iPos) {
|
||||
face->m_texturCoords.push_back(vtSize + iVal);
|
||||
} else if (2 == iPos) {
|
||||
face->m_normals.push_back(vnSize + iVal);
|
||||
hasNormal = true;
|
||||
} else {
|
||||
reportErrorTokenInFace();
|
||||
}
|
||||
} else {
|
||||
//On error, std::atoi will return 0 which is not a valid value
|
||||
delete face;
|
||||
throw DeadlyImportError("OBJ: Invalid face indice");
|
||||
}
|
||||
}
|
||||
m_DataIt += iStep;
|
||||
}
|
||||
|
||||
if (face->m_vertices.empty()) {
|
||||
ASSIMP_LOG_ERROR("Obj: Ignoring empty face");
|
||||
// skip line and clean up
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
delete face;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set active material, if one set
|
||||
if (nullptr != 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 (nullptr == m_pModel->m_pCurrent) {
|
||||
createObject(DefaultObjName);
|
||||
}
|
||||
|
||||
// Assign face to mesh
|
||||
if (nullptr == m_pModel->m_pCurrentMesh) {
|
||||
createMesh(DefaultObjName);
|
||||
}
|
||||
|
||||
// Store the face
|
||||
m_pModel->m_pCurrentMesh->m_Faces.push_back(face);
|
||||
m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_vertices.size();
|
||||
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[0] += (unsigned int)face->m_texturCoords.size();
|
||||
if (!m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal) {
|
||||
m_pModel->m_pCurrentMesh->m_hasNormals = true;
|
||||
}
|
||||
// Skip the rest of the line
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
void ObjFileParser::getMaterialDesc() {
|
||||
// Get next data for material data
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if (m_DataIt == m_DataItEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *pStart = &(*m_DataIt);
|
||||
while (m_DataIt != m_DataItEnd && !IsLineEnd(*m_DataIt)) {
|
||||
++m_DataIt;
|
||||
}
|
||||
|
||||
// In some cases we should ignore this 'usemtl' command, this variable helps us to do so
|
||||
bool skip = false;
|
||||
|
||||
// Get name
|
||||
std::string strName(pStart, &(*m_DataIt));
|
||||
strName = trim_whitespaces(strName);
|
||||
if (strName.empty())
|
||||
skip = true;
|
||||
|
||||
// If the current mesh has the same material, we simply ignore that 'usemtl' command
|
||||
// There is no need to create another object or even mesh here
|
||||
if (m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString(strName)) {
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
// Search for material
|
||||
std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->m_MaterialMap.find(strName);
|
||||
if (it == m_pModel->m_MaterialMap.end()) {
|
||||
// Not found, so we don't know anything about the material except for its name.
|
||||
// This may be the case if the material library is missing. We don't want to lose all
|
||||
// materials if that happens, so create a new named material instead of discarding it
|
||||
// completely.
|
||||
ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
|
||||
m_pModel->m_pCurrentMaterial = new ObjFile::Material();
|
||||
m_pModel->m_pCurrentMaterial->MaterialName.Set(strName);
|
||||
m_pModel->m_MaterialLib.push_back(strName);
|
||||
m_pModel->m_MaterialMap[strName] = m_pModel->m_pCurrentMaterial;
|
||||
} else {
|
||||
// Found, using detected material
|
||||
m_pModel->m_pCurrentMaterial = (*it).second;
|
||||
}
|
||||
|
||||
if (needsNewMesh(strName)) {
|
||||
createMesh(strName);
|
||||
}
|
||||
|
||||
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
|
||||
}
|
||||
|
||||
// Skip rest of line
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get a comment, values will be skipped
|
||||
void ObjFileParser::getComment() {
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get material library from file.
|
||||
void ObjFileParser::getMaterialLib() {
|
||||
// Translate tuple
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if (m_DataIt == m_DataItEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *pStart = &(*m_DataIt);
|
||||
while (m_DataIt != m_DataItEnd && !IsLineEnd(*m_DataIt)) {
|
||||
++m_DataIt;
|
||||
}
|
||||
|
||||
// Check for existence
|
||||
const std::string strMatName(pStart, &(*m_DataIt));
|
||||
std::string absName;
|
||||
|
||||
// Check if directive is valid.
|
||||
if (0 == strMatName.length()) {
|
||||
ASSIMP_LOG_WARN("OBJ: no name for material library specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pIO->StackSize() > 0) {
|
||||
std::string path = m_pIO->CurrentDirectory();
|
||||
if ('/' != *path.rbegin()) {
|
||||
path += '/';
|
||||
}
|
||||
absName += path;
|
||||
absName += strMatName;
|
||||
} else {
|
||||
absName = strMatName;
|
||||
}
|
||||
|
||||
IOStream *pFile = m_pIO->Open(absName);
|
||||
if (nullptr == pFile) {
|
||||
ASSIMP_LOG_ERROR("OBJ: Unable to locate material file ", strMatName);
|
||||
std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
|
||||
ASSIMP_LOG_INFO("OBJ: Opening fallback material file ", strMatFallbackName);
|
||||
pFile = m_pIO->Open(strMatFallbackName);
|
||||
if (!pFile) {
|
||||
ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file ", strMatFallbackName);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Import material library data from file.
|
||||
// Some exporters (e.g. Silo) will happily write out empty
|
||||
// material files if the model doesn't use any materials, so we
|
||||
// allow that.
|
||||
std::vector<char> buffer;
|
||||
BaseImporter::TextFileToBuffer(pFile, buffer, BaseImporter::ALLOW_EMPTY);
|
||||
m_pIO->Close(pFile);
|
||||
|
||||
// Importing the material library
|
||||
ObjFileMtlImporter mtlImporter(buffer, strMatName, m_pModel.get());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Set a new material definition as the current material.
|
||||
void ObjFileParser::getNewMaterial() {
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if (m_DataIt == m_DataItEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *pStart = &(*m_DataIt);
|
||||
std::string strMat(pStart, *m_DataIt);
|
||||
while (m_DataIt != m_DataItEnd && IsSpaceOrNewLine(*m_DataIt)) {
|
||||
++m_DataIt;
|
||||
}
|
||||
std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->m_MaterialMap.find(strMat);
|
||||
if (it == m_pModel->m_MaterialMap.end()) {
|
||||
// Show a warning, if material was not found
|
||||
ASSIMP_LOG_WARN("OBJ: Unsupported material requested: ", strMat);
|
||||
m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
|
||||
} else {
|
||||
// Set new material
|
||||
if (needsNewMesh(strMat)) {
|
||||
createMesh(strMat);
|
||||
}
|
||||
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strMat);
|
||||
}
|
||||
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
int ObjFileParser::getMaterialIndex(const std::string &strMaterialName) {
|
||||
int mat_index = -1;
|
||||
if (strMaterialName.empty()) {
|
||||
return mat_index;
|
||||
}
|
||||
for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index) {
|
||||
if (strMaterialName == m_pModel->m_MaterialLib[index]) {
|
||||
mat_index = (int)index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mat_index;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Getter for a group name.
|
||||
void ObjFileParser::getGroupName() {
|
||||
std::string groupName;
|
||||
|
||||
// here we skip 'g ' from line
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, groupName);
|
||||
if (isEndOfBuffer(m_DataIt, m_DataItEnd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Change active group, if necessary
|
||||
if (m_pModel->m_strActiveGroup != groupName) {
|
||||
// Search for already existing entry
|
||||
ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(groupName);
|
||||
|
||||
// We are mapping groups into the object structure
|
||||
createObject(groupName);
|
||||
|
||||
// New group name, creating a new entry
|
||||
if (it == m_pModel->m_Groups.end()) {
|
||||
std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
|
||||
m_pModel->m_Groups[groupName] = pFaceIDArray;
|
||||
m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
|
||||
} else {
|
||||
m_pModel->m_pGroupFaceIDs = (*it).second;
|
||||
}
|
||||
m_pModel->m_strActiveGroup = groupName;
|
||||
}
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Not supported
|
||||
void ObjFileParser::getGroupNumber() {
|
||||
// Not used
|
||||
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Not supported
|
||||
void ObjFileParser::getGroupNumberAndResolution() {
|
||||
// Not used
|
||||
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Stores values for a new object instance, name will be used to
|
||||
// identify it.
|
||||
void ObjFileParser::getObjectName() {
|
||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if (m_DataIt == m_DataItEnd) {
|
||||
return;
|
||||
}
|
||||
char *pStart = &(*m_DataIt);
|
||||
while (m_DataIt != m_DataItEnd && !IsSpaceOrNewLine(*m_DataIt)) {
|
||||
++m_DataIt;
|
||||
}
|
||||
|
||||
std::string strObjectName(pStart, &(*m_DataIt));
|
||||
if (!strObjectName.empty()) {
|
||||
// Reset current object
|
||||
m_pModel->m_pCurrent = nullptr;
|
||||
|
||||
// Search for actual object
|
||||
for (std::vector<ObjFile::Object *>::const_iterator it = m_pModel->m_Objects.begin();
|
||||
it != m_pModel->m_Objects.end();
|
||||
++it) {
|
||||
if ((*it)->m_strObjName == strObjectName) {
|
||||
m_pModel->m_pCurrent = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new object, if current one was not found before
|
||||
if (nullptr == m_pModel->m_pCurrent) {
|
||||
createObject(strObjectName);
|
||||
}
|
||||
}
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
// Creates a new object instance
|
||||
void ObjFileParser::createObject(const std::string &objName) {
|
||||
ai_assert(nullptr != 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(nullptr != m_pModel);
|
||||
|
||||
m_pModel->m_pCurrentMesh = new ObjFile::Mesh(meshName);
|
||||
m_pModel->m_Meshes.push_back(m_pModel->m_pCurrentMesh);
|
||||
unsigned int meshId = static_cast<unsigned int>(m_pModel->m_Meshes.size() - 1);
|
||||
if (nullptr != 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 == nullptr) {
|
||||
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.empty()) {
|
||||
// New material -> only one material per mesh, so we need to create a new
|
||||
// material
|
||||
newMat = true;
|
||||
}
|
||||
return newMat;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Shows an error in parsing process.
|
||||
void ObjFileParser::reportErrorTokenInFace() {
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
ASSIMP_LOG_ERROR("OBJ: Not supported token in face description detected");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER
|
||||
165
Engine/lib/assimp/code/AssetLib/Obj/ObjFileParser.h
Normal file
165
Engine/lib/assimp/code/AssetLib/Obj/ObjFileParser.h
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 <assimp/IOStreamBuffer.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/vector2.h>
|
||||
#include <assimp/vector3.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace ObjFile {
|
||||
struct Model;
|
||||
struct Object;
|
||||
struct Material;
|
||||
struct Point3;
|
||||
struct Point2;
|
||||
} // namespace ObjFile
|
||||
|
||||
class ObjFileImporter;
|
||||
class IOSystem;
|
||||
class ProgressHandler;
|
||||
|
||||
/// \class ObjFileParser
|
||||
/// \brief Parser for a obj waveform file
|
||||
class ASSIMP_API ObjFileParser {
|
||||
public:
|
||||
static const size_t Buffersize = 4096;
|
||||
typedef std::vector<char> DataArray;
|
||||
typedef std::vector<char>::iterator DataArrayIt;
|
||||
typedef std::vector<char>::const_iterator ConstDataArrayIt;
|
||||
|
||||
/// @brief The default constructor.
|
||||
ObjFileParser();
|
||||
/// @brief Constructor with data array.
|
||||
ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName, IOSystem *io, ProgressHandler *progress, const std::string &originalObjFileName);
|
||||
/// @brief Destructor
|
||||
~ObjFileParser();
|
||||
/// @brief If you want to load in-core data.
|
||||
void setBuffer(std::vector<char> &buffer);
|
||||
/// @brief Model getter.
|
||||
ObjFile::Model *GetModel() const;
|
||||
|
||||
ObjFileParser(const ObjFileParser&) = delete;
|
||||
ObjFileParser &operator=(const ObjFileParser& ) = delete;
|
||||
|
||||
protected:
|
||||
/// Parse the loaded file
|
||||
void parseFile(IOStreamBuffer<char> &streamBuffer);
|
||||
/// Method to copy the new delimited word in the current line.
|
||||
void copyNextWord(char *pBuffer, size_t length);
|
||||
/// Method to copy the new line.
|
||||
// void copyNextLine(char *pBuffer, size_t length);
|
||||
/// Get the number of components in a line.
|
||||
size_t getNumComponentsInDataDefinition();
|
||||
/// Stores the vector
|
||||
size_t getTexCoordVector(std::vector<aiVector3D> &point3d_array);
|
||||
/// Stores the following 3d vector.
|
||||
void getVector3(std::vector<aiVector3D> &point3d_array);
|
||||
/// Stores the following homogeneous vector as a 3D vector
|
||||
void getHomogeneousVector3(std::vector<aiVector3D> &point3d_array);
|
||||
/// Stores the following two 3d vectors on the line.
|
||||
void getTwoVectors3(std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b);
|
||||
/// Stores the following 3d vector.
|
||||
void getVector2(std::vector<aiVector2D> &point2d_array);
|
||||
/// Stores the following face.
|
||||
void getFace(aiPrimitiveType type);
|
||||
/// Reads the material description.
|
||||
void getMaterialDesc();
|
||||
/// Gets a comment.
|
||||
void getComment();
|
||||
/// Gets a a material library.
|
||||
void getMaterialLib();
|
||||
/// Creates a new material.
|
||||
void getNewMaterial();
|
||||
/// Gets the group name from file.
|
||||
void getGroupName();
|
||||
/// Gets the group number from file.
|
||||
void getGroupNumber();
|
||||
/// Gets the group number and resolution from file.
|
||||
void getGroupNumberAndResolution();
|
||||
/// Returns the index of the material. Is -1 if not material was found.
|
||||
int getMaterialIndex(const std::string &strMaterialName);
|
||||
/// Parse object name
|
||||
void getObjectName();
|
||||
/// Creates a new object.
|
||||
void createObject(const std::string &strObjectName);
|
||||
/// Creates a new mesh.
|
||||
void createMesh(const std::string &meshName);
|
||||
/// Returns true, if a new mesh instance must be created.
|
||||
bool needsNewMesh(const std::string &rMaterialName);
|
||||
/// Error report in token
|
||||
void reportErrorTokenInFace();
|
||||
|
||||
private:
|
||||
// Copy and assignment constructor should be private
|
||||
// because the class contains pointer to allocated memory
|
||||
|
||||
/// Default material name
|
||||
static constexpr char DEFAULT_MATERIAL[] = AI_DEFAULT_MATERIAL_NAME;
|
||||
//! Iterator to current position in buffer
|
||||
DataArrayIt m_DataIt;
|
||||
//! Iterator to end position of buffer
|
||||
DataArrayIt m_DataItEnd;
|
||||
//! Pointer to model instance
|
||||
std::unique_ptr<ObjFile::Model> m_pModel;
|
||||
//! Current line (for debugging)
|
||||
unsigned int m_uiLine;
|
||||
//! Helper buffer
|
||||
char m_buffer[Buffersize];
|
||||
/// Pointer to IO system instance.
|
||||
IOSystem *m_pIO;
|
||||
//! Pointer to progress handler
|
||||
ProgressHandler *m_progress;
|
||||
/// Path to the current model, name of the obj file where the buffer comes from
|
||||
const std::string m_originalObjFileName;
|
||||
};
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif
|
||||
284
Engine/lib/assimp/code/AssetLib/Obj/ObjTools.h
Normal file
284
Engine/lib/assimp/code/AssetLib/Obj/ObjTools.h
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2021, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file ObjTools.h
|
||||
* @brief Some helpful templates for text parsing
|
||||
*/
|
||||
#ifndef OBJ_TOOLS_H_INC
|
||||
#define OBJ_TOOLS_H_INC
|
||||
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the last entry of the buffer is reached.
|
||||
* @param[in] it Iterator of current position.
|
||||
* @param[in] end Iterator with end of buffer.
|
||||
* @return true, if the end of the buffer is reached.
|
||||
*/
|
||||
template <class char_t>
|
||||
inline bool isEndOfBuffer(char_t it, char_t end) {
|
||||
if (it == end) {
|
||||
return true;
|
||||
}
|
||||
--end;
|
||||
|
||||
return (it == end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns next word separated by a space
|
||||
* @param[in] pBuffer Pointer to data buffer
|
||||
* @param[in] pEnd Pointer to end of buffer
|
||||
* @return Pointer to next space
|
||||
*/
|
||||
template <class Char_T>
|
||||
inline Char_T getNextWord(Char_T pBuffer, Char_T pEnd) {
|
||||
while (!isEndOfBuffer(pBuffer, pEnd)) {
|
||||
if (!IsSpaceOrNewLine(*pBuffer) || IsLineEnd(*pBuffer)) {
|
||||
break;
|
||||
}
|
||||
++pBuffer;
|
||||
}
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns pointer a next token
|
||||
* @param[in] pBuffer Pointer to data buffer
|
||||
* @param[in] pEnd Pointer to end of buffer
|
||||
* @return Pointer to next token
|
||||
*/
|
||||
template <class Char_T>
|
||||
inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) {
|
||||
while (!isEndOfBuffer(pBuffer, pEnd)) {
|
||||
if (IsSpaceOrNewLine(*pBuffer)) {
|
||||
break;
|
||||
}
|
||||
++pBuffer;
|
||||
}
|
||||
return getNextWord(pBuffer, pEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skips a line
|
||||
* @param[in] it Iterator set to current position
|
||||
* @param[in] end Iterator set to end of scratch buffer for readout
|
||||
* @param[out] uiLine Current line number in format
|
||||
* @return Current-iterator with new position
|
||||
*/
|
||||
template <class char_t>
|
||||
inline char_t skipLine(char_t it, char_t end, unsigned int &uiLine) {
|
||||
while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) {
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != end) {
|
||||
++it;
|
||||
++uiLine;
|
||||
}
|
||||
// fix .. from time to time there are spaces at the beginning of a material line
|
||||
while (it != end && (*it == '\t' || *it == ' ')) {
|
||||
++it;
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a name from the current line. Preserve space in the middle,
|
||||
* but trim it at the end.
|
||||
* @param[in] it set to current position
|
||||
* @param[in] end set to end of scratch buffer for readout
|
||||
* @param[out] name Separated name
|
||||
* @return Current-iterator with new position
|
||||
*/
|
||||
template <class char_t>
|
||||
inline char_t getName(char_t it, char_t end, std::string &name) {
|
||||
name = "";
|
||||
if (isEndOfBuffer(it, end)) {
|
||||
return end;
|
||||
}
|
||||
|
||||
char *pStart = &(*it);
|
||||
while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) {
|
||||
++it;
|
||||
}
|
||||
|
||||
while (IsSpace(*it)) {
|
||||
--it;
|
||||
}
|
||||
// Get name
|
||||
// if there is no name, and the previous char is a separator, come back to start
|
||||
while (&(*it) < pStart) {
|
||||
++it;
|
||||
}
|
||||
std::string strName(pStart, &(*it));
|
||||
if (!strName.empty()) {
|
||||
name = strName;
|
||||
}
|
||||
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a name from the current line. Do not preserve space
|
||||
* in the middle, but trim it at the end.
|
||||
* @param it set to current position
|
||||
* @param end set to end of scratch buffer for readout
|
||||
* @param name Separated name
|
||||
* @return Current-iterator with new position
|
||||
*/
|
||||
template <class char_t>
|
||||
inline char_t getNameNoSpace(char_t it, char_t end, std::string &name) {
|
||||
name = "";
|
||||
if (isEndOfBuffer(it, end)) {
|
||||
return end;
|
||||
}
|
||||
|
||||
char *pStart = &(*it);
|
||||
while (!isEndOfBuffer(it, end) && !IsLineEnd(*it) && !IsSpaceOrNewLine(*it)) {
|
||||
++it;
|
||||
}
|
||||
|
||||
while (isEndOfBuffer(it, end) || IsLineEnd(*it) || IsSpaceOrNewLine(*it)) {
|
||||
--it;
|
||||
}
|
||||
++it;
|
||||
|
||||
// Get name
|
||||
// if there is no name, and the previous char is a separator, come back to start
|
||||
while (&(*it) < pStart) {
|
||||
++it;
|
||||
}
|
||||
std::string strName(pStart, &(*it));
|
||||
if (!strName.empty()) {
|
||||
name = strName;
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get next word from given line
|
||||
* @param[in] it set to current position
|
||||
* @param[in] end set to end of scratch buffer for readout
|
||||
* @param[in] pBuffer Buffer for next word
|
||||
* @param[in] length Buffer length
|
||||
* @return Current-iterator with new position
|
||||
*/
|
||||
template <class char_t>
|
||||
inline char_t CopyNextWord(char_t it, char_t end, char *pBuffer, size_t length) {
|
||||
size_t index = 0;
|
||||
it = getNextWord<char_t>(it, end);
|
||||
while (!IsSpaceOrNewLine(*it) && !isEndOfBuffer(it, end)) {
|
||||
pBuffer[index] = *it;
|
||||
++index;
|
||||
if (index == length - 1) {
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
pBuffer[index] = '\0';
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get next float from given line
|
||||
* @param[in] it set to current position
|
||||
* @param[in] end set to end of scratch buffer for readout
|
||||
* @param[out] value Separated float value.
|
||||
* @return Current-iterator with new position
|
||||
*/
|
||||
template <class char_t>
|
||||
inline char_t getFloat(char_t it, char_t end, ai_real &value) {
|
||||
static const size_t BUFFERSIZE = 1024;
|
||||
char buffer[BUFFERSIZE];
|
||||
it = CopyNextWord<char_t>(it, end, buffer, BUFFERSIZE);
|
||||
value = (ai_real)fast_atof(buffer);
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Will remove white-spaces for a string.
|
||||
* @param[in] str The string to clean
|
||||
* @return The trimmed string.
|
||||
*/
|
||||
template <class string_type>
|
||||
inline 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks for a line-end.
|
||||
* @param[in] it Current iterator in string.
|
||||
* @param[in] end End of the string.
|
||||
* @return The trimmed string.
|
||||
*/
|
||||
template <class T>
|
||||
bool hasLineEnd(T it, T end) {
|
||||
bool hasLineEnd = false;
|
||||
while (!isEndOfBuffer(it, end)) {
|
||||
++it;
|
||||
if (IsLineEnd(it)) {
|
||||
hasLineEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hasLineEnd;
|
||||
}
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // OBJ_TOOLS_H_INC
|
||||
Loading…
Reference in a new issue