Model loading and texturing
This commit is contained in:
541
thirdparty/assimp/code/X/XFileExporter.cpp
vendored
Normal file
541
thirdparty/assimp/code/X/XFileExporter.cpp
vendored
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@author: Richard Steffen, 2014
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
|
||||
|
||||
#include "X/XFileExporter.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
|
||||
#include <assimp/Bitmap.h>
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/light.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
|
||||
void ExportSceneXFile(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
||||
{
|
||||
std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
|
||||
std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
|
||||
|
||||
// create/copy Properties
|
||||
ExportProperties props(*pProperties);
|
||||
|
||||
// set standard properties if not set
|
||||
if (!props.HasPropertyBool(AI_CONFIG_EXPORT_XFILE_64BIT)) props.SetPropertyBool(AI_CONFIG_EXPORT_XFILE_64BIT, false);
|
||||
|
||||
// invoke the exporter
|
||||
XFileExporter iDoTheExportThing( pScene, pIOSystem, path, file, &props);
|
||||
|
||||
if (iDoTheExportThing.mOutput.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 result to the given IOSYstem
|
||||
std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
|
||||
if(outfile == NULL) {
|
||||
throw DeadlyExportError("could not open output .x file: " + std::string(pFile));
|
||||
}
|
||||
|
||||
// XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
|
||||
outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor for a specific scene to export
|
||||
XFileExporter::XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file, const ExportProperties* pProperties)
|
||||
: mProperties(pProperties),
|
||||
mIOSystem(pIOSystem),
|
||||
mPath(path),
|
||||
mFile(file),
|
||||
mScene(pScene),
|
||||
mSceneOwned(false),
|
||||
endstr("\n")
|
||||
{
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
mOutput.imbue( std::locale("C") );
|
||||
mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
|
||||
|
||||
// start writing
|
||||
WriteFile();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
XFileExporter::~XFileExporter()
|
||||
{
|
||||
if(mSceneOwned) {
|
||||
delete mScene;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Starts writing the contents
|
||||
void XFileExporter::WriteFile()
|
||||
{
|
||||
// note, that all realnumber values must be comma separated in x files
|
||||
mOutput.setf(std::ios::fixed);
|
||||
mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); // precision for ai_real
|
||||
|
||||
// entry of writing the file
|
||||
WriteHeader();
|
||||
|
||||
mOutput << startstr << "Frame DXCC_ROOT {" << endstr;
|
||||
PushTag();
|
||||
|
||||
aiMatrix4x4 I; // identity
|
||||
WriteFrameTransform(I);
|
||||
|
||||
WriteNode(mScene->mRootNode);
|
||||
PopTag();
|
||||
|
||||
mOutput << startstr << "}" << endstr;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Writes the asset header
|
||||
void XFileExporter::WriteHeader()
|
||||
{
|
||||
if (mProperties->GetPropertyBool(AI_CONFIG_EXPORT_XFILE_64BIT) == true)
|
||||
mOutput << startstr << "xof 0303txt 0064" << endstr;
|
||||
else
|
||||
mOutput << startstr << "xof 0303txt 0032" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Frame {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab46-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "[...]" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Matrix4x4 {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f45-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "array FLOAT matrix[16];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template FrameTransformMatrix {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f41-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "Matrix4x4 frameMatrix;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Vector {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab5e-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "FLOAT x;" << endstr;
|
||||
mOutput << startstr << "FLOAT y;" << endstr;
|
||||
mOutput << startstr << "FLOAT z;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshFace {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab5f-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "DWORD nFaceVertexIndices;" << endstr;
|
||||
mOutput << startstr << "array DWORD faceVertexIndices[nFaceVertexIndices];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Mesh {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab44-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "DWORD nVertices;" << endstr;
|
||||
mOutput << startstr << "array Vector vertices[nVertices];" << endstr;
|
||||
mOutput << startstr << "DWORD nFaces;" << endstr;
|
||||
mOutput << startstr << "array MeshFace faces[nFaces];" << endstr;
|
||||
mOutput << startstr << "[...]" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshNormals {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f43-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD nNormals;" << endstr;
|
||||
mOutput << startstr << "array Vector normals[nNormals];" << endstr;
|
||||
mOutput << startstr << "DWORD nFaceNormals;" << endstr;
|
||||
mOutput << startstr << "array MeshFace faceNormals[nFaceNormals];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Coords2d {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f44-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "FLOAT u;" << endstr;
|
||||
mOutput << startstr << "FLOAT v;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshTextureCoords {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f40-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD nTextureCoords;" << endstr;
|
||||
mOutput << startstr << "array Coords2d textureCoords[nTextureCoords];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template ColorRGBA {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<35ff44e0-6c7c-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "FLOAT red;" << endstr;
|
||||
mOutput << startstr << "FLOAT green;" << endstr;
|
||||
mOutput << startstr << "FLOAT blue;" << endstr;
|
||||
mOutput << startstr << "FLOAT alpha;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template IndexedColor {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<1630b820-7842-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD index;" << endstr;
|
||||
mOutput << startstr << "ColorRGBA indexColor;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshVertexColors {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<1630b821-7842-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD nVertexColors;" << endstr;
|
||||
mOutput << startstr << "array IndexedColor vertexColors[nVertexColors];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template VertexElement {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f752461c-1e23-48f6-b9f8-8350850f336f>" << endstr;
|
||||
mOutput << startstr << "DWORD Type;" << endstr;
|
||||
mOutput << startstr << "DWORD Method;" << endstr;
|
||||
mOutput << startstr << "DWORD Usage;" << endstr;
|
||||
mOutput << startstr << "DWORD UsageIndex;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template DeclData {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<bf22e553-292c-4781-9fea-62bd554bdd93>" << endstr;
|
||||
mOutput << startstr << "DWORD nElements;" << endstr;
|
||||
mOutput << startstr << "array VertexElement Elements[nElements];" << endstr;
|
||||
mOutput << startstr << "DWORD nDWords;" << endstr;
|
||||
mOutput << startstr << "array DWORD data[nDWords];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
}
|
||||
|
||||
|
||||
// Writes the material setup
|
||||
void XFileExporter::WriteFrameTransform(aiMatrix4x4& m)
|
||||
{
|
||||
mOutput << startstr << "FrameTransformMatrix {" << endstr << " ";
|
||||
PushTag();
|
||||
mOutput << startstr << m.a1 << ", " << m.b1 << ", " << m.c1 << ", " << m.d1 << "," << endstr;
|
||||
mOutput << startstr << m.a2 << ", " << m.b2 << ", " << m.c2 << ", " << m.d2 << "," << endstr;
|
||||
mOutput << startstr << m.a3 << ", " << m.b3 << ", " << m.c3 << ", " << m.d3 << "," << endstr;
|
||||
mOutput << startstr << m.a4 << ", " << m.b4 << ", " << m.c4 << ", " << m.d4 << ";;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr << endstr;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively writes the given node
|
||||
void XFileExporter::WriteNode( aiNode* pNode)
|
||||
{
|
||||
if (pNode->mName.length==0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Node_" << pNode;
|
||||
pNode->mName.Set(ss.str());
|
||||
}
|
||||
mOutput << startstr << "Frame " << toXFileString(pNode->mName) << " {" << endstr;
|
||||
|
||||
PushTag();
|
||||
|
||||
aiMatrix4x4 m = pNode->mTransformation;
|
||||
|
||||
WriteFrameTransform(m);
|
||||
|
||||
for (size_t i = 0; i < pNode->mNumMeshes; ++i)
|
||||
WriteMesh(mScene->mMeshes[pNode->mMeshes[i]]);
|
||||
|
||||
// recursive call the Nodes
|
||||
for (size_t i = 0; i < pNode->mNumChildren; ++i)
|
||||
WriteNode(pNode->mChildren[i]);
|
||||
|
||||
PopTag();
|
||||
|
||||
mOutput << startstr << "}" << endstr << endstr;
|
||||
}
|
||||
|
||||
void XFileExporter::WriteMesh(aiMesh* mesh)
|
||||
{
|
||||
mOutput << startstr << "Mesh " << toXFileString(mesh->mName) << "_mShape" << " {" << endstr;
|
||||
|
||||
PushTag();
|
||||
|
||||
// write all the vertices
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiVector3D &v = mesh->mVertices[a];
|
||||
mOutput << startstr << v[0] << ";"<< v[1] << ";" << v[2] << ";";
|
||||
if (a < mesh->mNumVertices - 1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
|
||||
// write all the faces
|
||||
mOutput << startstr << mesh->mNumFaces << ";" << endstr;
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
mOutput << startstr << face.mNumIndices << ";";
|
||||
// must be counter clockwise triangle
|
||||
//for(int b = face.mNumIndices - 1; b >= 0 ; --b)
|
||||
for(size_t b = 0; b < face.mNumIndices ; ++b)
|
||||
{
|
||||
mOutput << face.mIndices[b];
|
||||
//if (b > 0)
|
||||
if (b<face.mNumIndices-1)
|
||||
mOutput << ",";
|
||||
else
|
||||
mOutput << ";";
|
||||
}
|
||||
|
||||
if (a < mesh->mNumFaces - 1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
|
||||
mOutput << endstr;
|
||||
|
||||
if (mesh->HasTextureCoords(0))
|
||||
{
|
||||
const aiMaterial* mat = mScene->mMaterials[mesh->mMaterialIndex];
|
||||
aiString relpath;
|
||||
mat->Get(_AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0, relpath);
|
||||
|
||||
mOutput << startstr << "MeshMaterialList {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "1;" << endstr; // number of materials
|
||||
mOutput << startstr << mesh->mNumFaces << ";" << endstr; // number of faces
|
||||
mOutput << startstr;
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
mOutput << "0"; // the material index
|
||||
if (a < mesh->mNumFaces - 1)
|
||||
mOutput << ", ";
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "Material {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "1.0; 1.0; 1.0; 1.000000;;" << endstr;
|
||||
mOutput << startstr << "1.000000;" << endstr; // power
|
||||
mOutput << startstr << "0.000000; 0.000000; 0.000000;;" << endstr; // specularity
|
||||
mOutput << startstr << "0.000000; 0.000000; 0.000000;;" << endstr; // emission
|
||||
mOutput << startstr << "TextureFilename { \"";
|
||||
|
||||
writePath(relpath);
|
||||
|
||||
mOutput << "\"; }" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
|
||||
// write normals (every vertex has one)
|
||||
if (mesh->HasNormals())
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshNormals {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiVector3D &v = mesh->mNormals[a];
|
||||
// because we have a LHS and also changed wth winding, we need to invert the normals again
|
||||
mOutput << startstr << -v[0] << ";"<< -v[1] << ";" << -v[2] << ";";
|
||||
if (a < mesh->mNumVertices - 1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
|
||||
mOutput << startstr << mesh->mNumFaces << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
mOutput << startstr << face.mNumIndices << ";";
|
||||
|
||||
//for(int b = face.mNumIndices-1; b >= 0 ; --b)
|
||||
for(size_t b = 0; b < face.mNumIndices ; ++b)
|
||||
{
|
||||
mOutput << face.mIndices[b];
|
||||
//if (b > 0)
|
||||
if (b<face.mNumIndices-1)
|
||||
mOutput << ",";
|
||||
else
|
||||
mOutput << ";";
|
||||
}
|
||||
|
||||
if (a < mesh->mNumFaces-1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
|
||||
// write texture UVs if available
|
||||
if (mesh->HasTextureCoords(0))
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshTextureCoords {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
//for (int a = (int)mesh->mNumVertices-1; a >=0 ; a--)
|
||||
{
|
||||
aiVector3D& uv = mesh->mTextureCoords[0][a]; // uv of first uv layer for the vertex
|
||||
mOutput << startstr << uv.x << ";" << uv.y;
|
||||
if (a < mesh->mNumVertices-1)
|
||||
//if (a >0 )
|
||||
mOutput << ";," << endstr;
|
||||
else
|
||||
mOutput << ";;" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
|
||||
// write color channel if available
|
||||
if (mesh->HasVertexColors(0))
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshVertexColors {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiColor4D& mColors = mesh->mColors[0][a]; // color of first vertex color set for the vertex
|
||||
mOutput << startstr << a << ";" << mColors.r << ";" << mColors.g << ";" << mColors.b << ";" << mColors.a << ";;";
|
||||
if (a < mesh->mNumVertices-1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshVertexColors {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiColor4D* mColors = mesh->mColors[a];
|
||||
mOutput << startstr << a << ";0.500000;0.000000;0.000000;0.500000;;";
|
||||
if (a < mesh->mNumVertices-1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
*/
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr << endstr;
|
||||
|
||||
}
|
||||
|
||||
std::string XFileExporter::toXFileString(aiString &name)
|
||||
{
|
||||
std::string pref = ""; // node name prefix to prevent unexpected start of string
|
||||
std::string str = pref + std::string(name.C_Str());
|
||||
for (int i=0; i < (int) str.length(); ++i)
|
||||
{
|
||||
if ((str[i] >= '0' && str[i] <= '9') || // 0-9
|
||||
(str[i] >= 'A' && str[i] <= 'Z') || // A-Z
|
||||
(str[i] >= 'a' && str[i] <= 'z')) // a-z
|
||||
continue;
|
||||
str[i] = '_';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void XFileExporter::writePath(const aiString &path)
|
||||
{
|
||||
std::string str = std::string(path.C_Str());
|
||||
BaseImporter::ConvertUTF8toISO8859_1(str);
|
||||
|
||||
while( str.find( "\\\\") != std::string::npos)
|
||||
str.replace( str.find( "\\\\"), 2, "\\");
|
||||
|
||||
while( str.find( "\\") != std::string::npos)
|
||||
str.replace( str.find( "\\"), 1, "/");
|
||||
|
||||
mOutput << str;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
140
thirdparty/assimp/code/X/XFileExporter.h
vendored
Normal file
140
thirdparty/assimp/code/X/XFileExporter.h
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@author: Richard Steffen, 2014
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file XFileExporter.h
|
||||
* Declares the exporter class to write a scene to a Collada file
|
||||
*/
|
||||
#ifndef AI_XFILEEXPORTER_H_INC
|
||||
#define AI_XFILEEXPORTER_H_INC
|
||||
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/matrix4x4.h>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <sstream>
|
||||
|
||||
struct aiScene;
|
||||
struct aiNode;
|
||||
struct aiMesh;
|
||||
struct aiString;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
class IOSystem;
|
||||
|
||||
|
||||
/// Helper class to export a given scene to a X-file.
|
||||
/// Note: an xFile uses a left hand system. Assimp used a right hand system (OpenGL), therefore we have to transform everything
|
||||
class XFileExporter
|
||||
{
|
||||
public:
|
||||
/// Constructor for a specific scene to export
|
||||
XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file, const ExportProperties* pProperties);
|
||||
|
||||
/// Destructor
|
||||
virtual ~XFileExporter();
|
||||
|
||||
protected:
|
||||
/// Starts writing the contents
|
||||
void WriteFile();
|
||||
|
||||
/// Writes the asset header
|
||||
void WriteHeader();
|
||||
|
||||
/// write a frame transform
|
||||
void WriteFrameTransform(aiMatrix4x4& m);
|
||||
|
||||
/// Recursively writes the given node
|
||||
void WriteNode( aiNode* pNode );
|
||||
|
||||
/// write a mesh entry of the scene
|
||||
void WriteMesh( aiMesh* mesh);
|
||||
|
||||
/// Enters a new xml element, which increases the indentation
|
||||
void PushTag() { startstr.append( " "); }
|
||||
|
||||
/// Leaves an element, decreasing the indentation
|
||||
void PopTag() {
|
||||
ai_assert( startstr.length() > 1);
|
||||
startstr.erase( startstr.length() - 2);
|
||||
}
|
||||
|
||||
public:
|
||||
/// Stringstream to write all output into
|
||||
std::stringstream mOutput;
|
||||
|
||||
protected:
|
||||
|
||||
/// normalize the name to be accepted by xfile readers
|
||||
std::string toXFileString(aiString &name);
|
||||
|
||||
/// hold the properties pointer
|
||||
const ExportProperties* mProperties;
|
||||
|
||||
/// write a path
|
||||
void writePath(const aiString &path);
|
||||
|
||||
/// The IOSystem for output
|
||||
IOSystem* mIOSystem;
|
||||
|
||||
/// Path of the directory where the scene will be exported
|
||||
const std::string mPath;
|
||||
|
||||
/// Name of the file (without extension) where the scene will be exported
|
||||
const std::string mFile;
|
||||
|
||||
/// The scene to be written
|
||||
const aiScene* mScene;
|
||||
bool mSceneOwned;
|
||||
|
||||
/// current line start string, contains the current indentation for simple stream insertion
|
||||
std::string startstr;
|
||||
|
||||
/// current line end string for simple stream insertion
|
||||
std::string endstr;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // !! AI_XFILEEXPORTER_H_INC
|
||||
245
thirdparty/assimp/code/X/XFileHelper.h
vendored
Normal file
245
thirdparty/assimp/code/X/XFileHelper.h
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/** @file Defines the helper data structures for importing XFiles */
|
||||
#ifndef AI_XFILEHELPER_H_INC
|
||||
#define AI_XFILEHELPER_H_INC
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/quaternion.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/Defines.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace XFile {
|
||||
|
||||
/** Helper structure representing a XFile mesh face */
|
||||
struct Face {
|
||||
std::vector<unsigned int> mIndices;
|
||||
};
|
||||
|
||||
/** Helper structure representing a texture filename inside a material and its potential source */
|
||||
struct TexEntry {
|
||||
std::string mName;
|
||||
bool mIsNormalMap; // true if the texname was specified in a NormalmapFilename tag
|
||||
|
||||
TexEntry() AI_NO_EXCEPT
|
||||
: mName()
|
||||
, mIsNormalMap(false) {
|
||||
// empty
|
||||
}
|
||||
TexEntry(const std::string& pName, bool pIsNormalMap = false)
|
||||
: mName(pName)
|
||||
, mIsNormalMap(pIsNormalMap) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
/** Helper structure representing a XFile material */
|
||||
struct Material {
|
||||
std::string mName;
|
||||
bool mIsReference; // if true, mName holds a name by which the actual material can be found in the material list
|
||||
aiColor4D mDiffuse;
|
||||
ai_real mSpecularExponent;
|
||||
aiColor3D mSpecular;
|
||||
aiColor3D mEmissive;
|
||||
std::vector<TexEntry> mTextures;
|
||||
size_t sceneIndex; ///< the index under which it was stored in the scene's material list
|
||||
|
||||
Material() AI_NO_EXCEPT
|
||||
: mIsReference(false)
|
||||
, mSpecularExponent()
|
||||
, sceneIndex(SIZE_MAX) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
/** Helper structure to represent a bone weight */
|
||||
struct BoneWeight {
|
||||
unsigned int mVertex;
|
||||
ai_real mWeight;
|
||||
};
|
||||
|
||||
/** Helper structure to represent a bone in a mesh */
|
||||
struct Bone
|
||||
{
|
||||
std::string mName;
|
||||
std::vector<BoneWeight> mWeights;
|
||||
aiMatrix4x4 mOffsetMatrix;
|
||||
};
|
||||
|
||||
/** Helper structure to represent an XFile mesh */
|
||||
struct Mesh {
|
||||
std::string mName;
|
||||
std::vector<aiVector3D> mPositions;
|
||||
std::vector<Face> mPosFaces;
|
||||
std::vector<aiVector3D> mNormals;
|
||||
std::vector<Face> mNormFaces;
|
||||
unsigned int mNumTextures;
|
||||
std::vector<aiVector2D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
unsigned int mNumColorSets;
|
||||
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
|
||||
std::vector<unsigned int> mFaceMaterials;
|
||||
std::vector<Material> mMaterials;
|
||||
|
||||
std::vector<Bone> mBones;
|
||||
|
||||
explicit Mesh(const std::string &pName = "") AI_NO_EXCEPT
|
||||
: mName( pName )
|
||||
, mPositions()
|
||||
, mPosFaces()
|
||||
, mNormals()
|
||||
, mNormFaces()
|
||||
, mNumTextures(0)
|
||||
, mTexCoords{}
|
||||
, mNumColorSets(0)
|
||||
, mColors{}
|
||||
, mFaceMaterials()
|
||||
, mMaterials()
|
||||
, mBones() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
/** Helper structure to represent a XFile frame */
|
||||
struct Node {
|
||||
std::string mName;
|
||||
aiMatrix4x4 mTrafoMatrix;
|
||||
Node* mParent;
|
||||
std::vector<Node*> mChildren;
|
||||
std::vector<Mesh*> mMeshes;
|
||||
|
||||
Node() AI_NO_EXCEPT
|
||||
: mName()
|
||||
, mTrafoMatrix()
|
||||
, mParent(nullptr)
|
||||
, mChildren()
|
||||
, mMeshes() {
|
||||
// empty
|
||||
}
|
||||
explicit Node( Node* pParent)
|
||||
: mName()
|
||||
, mTrafoMatrix()
|
||||
, mParent(pParent)
|
||||
, mChildren()
|
||||
, mMeshes() {
|
||||
// empty
|
||||
}
|
||||
|
||||
~Node() {
|
||||
for (unsigned int a = 0; a < mChildren.size(); ++a ) {
|
||||
delete mChildren[a];
|
||||
}
|
||||
for (unsigned int a = 0; a < mMeshes.size(); ++a) {
|
||||
delete mMeshes[a];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MatrixKey {
|
||||
double mTime;
|
||||
aiMatrix4x4 mMatrix;
|
||||
};
|
||||
|
||||
/** Helper structure representing a single animated bone in a XFile */
|
||||
struct AnimBone {
|
||||
std::string mBoneName;
|
||||
std::vector<aiVectorKey> mPosKeys; // either three separate key sequences for position, rotation, scaling
|
||||
std::vector<aiQuatKey> mRotKeys;
|
||||
std::vector<aiVectorKey> mScaleKeys;
|
||||
std::vector<MatrixKey> mTrafoKeys; // or a combined key sequence of transformation matrices.
|
||||
};
|
||||
|
||||
/** Helper structure to represent an animation set in a XFile */
|
||||
struct Animation
|
||||
{
|
||||
std::string mName;
|
||||
std::vector<AnimBone*> mAnims;
|
||||
|
||||
~Animation()
|
||||
{
|
||||
for( unsigned int a = 0; a < mAnims.size(); a++)
|
||||
delete mAnims[a];
|
||||
}
|
||||
};
|
||||
|
||||
/** Helper structure analogue to aiScene */
|
||||
struct Scene
|
||||
{
|
||||
Node* mRootNode;
|
||||
|
||||
std::vector<Mesh*> mGlobalMeshes; // global meshes found outside of any frames
|
||||
std::vector<Material> mGlobalMaterials; // global materials found outside of any meshes.
|
||||
|
||||
std::vector<Animation*> mAnims;
|
||||
unsigned int mAnimTicksPerSecond;
|
||||
|
||||
Scene() AI_NO_EXCEPT
|
||||
: mRootNode(nullptr)
|
||||
, mGlobalMeshes()
|
||||
, mGlobalMaterials()
|
||||
, mAnimTicksPerSecond(0) {
|
||||
// empty
|
||||
}
|
||||
~Scene() {
|
||||
delete mRootNode;
|
||||
mRootNode = nullptr;
|
||||
for (unsigned int a = 0; a < mGlobalMeshes.size(); ++a ) {
|
||||
delete mGlobalMeshes[a];
|
||||
}
|
||||
for (unsigned int a = 0; a < mAnims.size(); ++a ) {
|
||||
delete mAnims[a];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // end of namespace XFile
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_XFILEHELPER_H_INC
|
||||
696
thirdparty/assimp/code/X/XFileImporter.cpp
vendored
Normal file
696
thirdparty/assimp/code/X/XFileImporter.cpp
vendored
Normal file
@@ -0,0 +1,696 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
/** @file XFileImporter.cpp
|
||||
* @brief Implementation of the XFile importer class
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
||||
|
||||
#include "X/XFileImporter.h"
|
||||
#include "X/XFileParser.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/Defines.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Direct3D XFile Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
|
||||
1,
|
||||
3,
|
||||
1,
|
||||
5,
|
||||
"x"
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
XFileImporter::XFileImporter()
|
||||
: mBuffer() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
XFileImporter::~XFileImporter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||
std::string extension = GetExtension(pFile);
|
||||
if(extension == "x") {
|
||||
return true;
|
||||
}
|
||||
if (!extension.length() || checkSig) {
|
||||
uint32_t token[1];
|
||||
token[0] = AI_MAKE_MAGIC("xof ");
|
||||
return CheckMagicToken(pIOHandler,pFile,token,1,0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get file extension list
|
||||
const aiImporterDesc* XFileImporter::GetInfo () const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
||||
// read file into memory
|
||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||
if ( file.get() == NULL ) {
|
||||
throw DeadlyImportError( "Failed to open file " + pFile + "." );
|
||||
}
|
||||
|
||||
static const size_t MinSize = 16;
|
||||
size_t fileSize = file->FileSize();
|
||||
if ( fileSize < MinSize ) {
|
||||
throw DeadlyImportError( "XFile is too small." );
|
||||
}
|
||||
|
||||
// in the hope that binary files will never start with a BOM ...
|
||||
mBuffer.resize( fileSize + 1);
|
||||
file->Read( &mBuffer.front(), 1, fileSize);
|
||||
ConvertToUTF8(mBuffer);
|
||||
|
||||
// parse the file into a temporary representation
|
||||
XFileParser parser( mBuffer);
|
||||
|
||||
// and create the proper return structures out of it
|
||||
CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
|
||||
|
||||
// if nothing came from it, report it as error
|
||||
if ( !pScene->mRootNode ) {
|
||||
throw DeadlyImportError( "XFile is ill-formatted - no content imported." );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs the return data structure out of the imported data.
|
||||
void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::Scene* pData)
|
||||
{
|
||||
// Read the global materials first so that meshes referring to them can find them later
|
||||
ConvertMaterials( pScene, pData->mGlobalMaterials);
|
||||
|
||||
// copy nodes, extracting meshes and materials on the way
|
||||
pScene->mRootNode = CreateNodes( pScene, nullptr, pData->mRootNode);
|
||||
|
||||
// extract animations
|
||||
CreateAnimations( pScene, pData);
|
||||
|
||||
// read the global meshes that were stored outside of any node
|
||||
if( !pData->mGlobalMeshes.empty() ) {
|
||||
// create a root node to hold them if there isn't any, yet
|
||||
if( pScene->mRootNode == nullptr ) {
|
||||
pScene->mRootNode = new aiNode;
|
||||
pScene->mRootNode->mName.Set( "$dummy_node");
|
||||
}
|
||||
|
||||
// convert all global meshes and store them in the root node.
|
||||
// If there was one before, the global meshes now suddenly have its transformation matrix...
|
||||
// Don't know what to do there, I don't want to insert another node under the present root node
|
||||
// just to avoid this.
|
||||
CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes);
|
||||
}
|
||||
|
||||
if (!pScene->mRootNode) {
|
||||
throw DeadlyImportError( "No root node" );
|
||||
}
|
||||
|
||||
// Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly
|
||||
MakeLeftHandedProcess convertProcess;
|
||||
convertProcess.Execute( pScene);
|
||||
|
||||
FlipWindingOrderProcess flipper;
|
||||
flipper.Execute(pScene);
|
||||
|
||||
// finally: create a dummy material if not material was imported
|
||||
if( pScene->mNumMaterials == 0) {
|
||||
pScene->mNumMaterials = 1;
|
||||
// create the Material
|
||||
aiMaterial* mat = new aiMaterial;
|
||||
int shadeMode = (int) aiShadingMode_Gouraud;
|
||||
mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
// material colours
|
||||
int specExp = 1;
|
||||
|
||||
aiColor3D clr = aiColor3D( 0, 0, 0);
|
||||
mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
|
||||
clr = aiColor3D( 0.5f, 0.5f, 0.5f);
|
||||
mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
|
||||
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = mat;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively creates scene nodes from the imported hierarchy.
|
||||
aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) {
|
||||
if ( !pNode ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create node
|
||||
aiNode* node = new aiNode;
|
||||
node->mName.length = pNode->mName.length();
|
||||
node->mParent = pParent;
|
||||
memcpy( node->mName.data, pNode->mName.c_str(), pNode->mName.length());
|
||||
node->mName.data[node->mName.length] = 0;
|
||||
node->mTransformation = pNode->mTrafoMatrix;
|
||||
|
||||
// convert meshes from the source node
|
||||
CreateMeshes( pScene, node, pNode->mMeshes);
|
||||
|
||||
// handle childs
|
||||
if( !pNode->mChildren.empty() ) {
|
||||
node->mNumChildren = (unsigned int)pNode->mChildren.size();
|
||||
node->mChildren = new aiNode* [node->mNumChildren];
|
||||
|
||||
for ( unsigned int a = 0; a < pNode->mChildren.size(); ++a ) {
|
||||
node->mChildren[ a ] = CreateNodes( pScene, node, pNode->mChildren[ a ] );
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates the meshes for the given node.
|
||||
void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) {
|
||||
if (pMeshes.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create a mesh for each mesh-material combination in the source node
|
||||
std::vector<aiMesh*> meshes;
|
||||
for( unsigned int a = 0; a < pMeshes.size(); ++a ) {
|
||||
XFile::Mesh* sourceMesh = pMeshes[a];
|
||||
if ( nullptr == sourceMesh ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// first convert its materials so that we can find them with their index afterwards
|
||||
ConvertMaterials( pScene, sourceMesh->mMaterials);
|
||||
|
||||
unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
|
||||
for( unsigned int b = 0; b < numMaterials; ++b ) {
|
||||
// collect the faces belonging to this material
|
||||
std::vector<unsigned int> faces;
|
||||
unsigned int numVertices = 0;
|
||||
if( !sourceMesh->mFaceMaterials.empty() ) {
|
||||
// if there is a per-face material defined, select the faces with the corresponding material
|
||||
for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); ++c ) {
|
||||
if( sourceMesh->mFaceMaterials[c] == b) {
|
||||
faces.push_back( c);
|
||||
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if there is no per-face material, place everything into one mesh
|
||||
for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); ++c ) {
|
||||
faces.push_back( c);
|
||||
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
||||
}
|
||||
}
|
||||
|
||||
// no faces/vertices using this material? strange...
|
||||
if ( numVertices == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create a submesh using this material
|
||||
aiMesh* mesh = new aiMesh;
|
||||
meshes.push_back( mesh);
|
||||
|
||||
// find the material in the scene's material list. Either own material
|
||||
// or referenced material, it should already have a valid index
|
||||
if( !sourceMesh->mFaceMaterials.empty() ) {
|
||||
mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
|
||||
} else {
|
||||
mesh->mMaterialIndex = 0;
|
||||
}
|
||||
|
||||
// Create properly sized data arrays in the mesh. We store unique vertices per face,
|
||||
// as specified
|
||||
mesh->mNumVertices = numVertices;
|
||||
mesh->mVertices = new aiVector3D[numVertices];
|
||||
mesh->mNumFaces = (unsigned int)faces.size();
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
|
||||
// name
|
||||
mesh->mName.Set(sourceMesh->mName);
|
||||
|
||||
// normals?
|
||||
if ( sourceMesh->mNormals.size() > 0 ) {
|
||||
mesh->mNormals = new aiVector3D[ numVertices ];
|
||||
}
|
||||
// texture coords
|
||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) {
|
||||
if ( !sourceMesh->mTexCoords[ c ].empty() ) {
|
||||
mesh->mTextureCoords[ c ] = new aiVector3D[ numVertices ];
|
||||
}
|
||||
}
|
||||
// vertex colors
|
||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) {
|
||||
if ( !sourceMesh->mColors[ c ].empty() ) {
|
||||
mesh->mColors[ c ] = new aiColor4D[ numVertices ];
|
||||
}
|
||||
}
|
||||
|
||||
// now collect the vertex data of all data streams present in the imported mesh
|
||||
unsigned int newIndex( 0 );
|
||||
std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
|
||||
orgPoints.resize( numVertices, 0);
|
||||
|
||||
for( unsigned int c = 0; c < faces.size(); ++c ) {
|
||||
unsigned int f = faces[c]; // index of the source face
|
||||
const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
|
||||
|
||||
// create face. either triangle or triangle fan depending on the index count
|
||||
aiFace& df = mesh->mFaces[c]; // destination face
|
||||
df.mNumIndices = (unsigned int)pf.mIndices.size();
|
||||
df.mIndices = new unsigned int[ df.mNumIndices];
|
||||
|
||||
// collect vertex data for indices of this face
|
||||
for( unsigned int d = 0; d < df.mNumIndices; ++d ) {
|
||||
df.mIndices[ d ] = newIndex;
|
||||
const unsigned int newIdx( pf.mIndices[ d ] );
|
||||
if ( newIdx > sourceMesh->mPositions.size() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
orgPoints[newIndex] = pf.mIndices[d];
|
||||
|
||||
// Position
|
||||
mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
|
||||
// Normal, if present
|
||||
if ( mesh->HasNormals() ) {
|
||||
if ( sourceMesh->mNormFaces[ f ].mIndices.size() > d ) {
|
||||
const size_t idx( sourceMesh->mNormFaces[ f ].mIndices[ d ] );
|
||||
mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ idx ];
|
||||
}
|
||||
}
|
||||
|
||||
// texture coord sets
|
||||
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++e ) {
|
||||
if( mesh->HasTextureCoords( e)) {
|
||||
aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
|
||||
mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
|
||||
}
|
||||
}
|
||||
// vertex color sets
|
||||
for ( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; ++e ) {
|
||||
if ( mesh->HasVertexColors( e ) ) {
|
||||
mesh->mColors[ e ][ newIndex ] = sourceMesh->mColors[ e ][ pf.mIndices[ d ] ];
|
||||
}
|
||||
}
|
||||
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// there should be as much new vertices as we calculated before
|
||||
ai_assert( newIndex == numVertices);
|
||||
|
||||
// convert all bones of the source mesh which influence vertices in this newly created mesh
|
||||
const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
|
||||
std::vector<aiBone*> newBones;
|
||||
for( unsigned int c = 0; c < bones.size(); ++c ) {
|
||||
const XFile::Bone& obone = bones[c];
|
||||
// set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
|
||||
std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0);
|
||||
for ( unsigned int d = 0; d < obone.mWeights.size(); ++d ) {
|
||||
oldWeights[ obone.mWeights[ d ].mVertex ] = obone.mWeights[ d ].mWeight;
|
||||
}
|
||||
|
||||
// collect all vertex weights that influence a vertex in the new mesh
|
||||
std::vector<aiVertexWeight> newWeights;
|
||||
newWeights.reserve( numVertices);
|
||||
for( unsigned int d = 0; d < orgPoints.size(); ++d ) {
|
||||
// does the new vertex stem from an old vertex which was influenced by this bone?
|
||||
ai_real w = oldWeights[orgPoints[d]];
|
||||
if ( w > 0.0 ) {
|
||||
newWeights.push_back( aiVertexWeight( d, w ) );
|
||||
}
|
||||
}
|
||||
|
||||
// if the bone has no weights in the newly created mesh, ignore it
|
||||
if ( newWeights.empty() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create
|
||||
aiBone* nbone = new aiBone;
|
||||
newBones.push_back( nbone);
|
||||
// copy name and matrix
|
||||
nbone->mName.Set( obone.mName);
|
||||
nbone->mOffsetMatrix = obone.mOffsetMatrix;
|
||||
nbone->mNumWeights = (unsigned int)newWeights.size();
|
||||
nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
|
||||
for ( unsigned int d = 0; d < newWeights.size(); ++d ) {
|
||||
nbone->mWeights[ d ] = newWeights[ d ];
|
||||
}
|
||||
}
|
||||
|
||||
// store the bones in the mesh
|
||||
mesh->mNumBones = (unsigned int)newBones.size();
|
||||
if( !newBones.empty()) {
|
||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||
std::copy( newBones.begin(), newBones.end(), mesh->mBones);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reallocate scene mesh array to be large enough
|
||||
aiMesh** prevArray = pScene->mMeshes;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
|
||||
if( prevArray) {
|
||||
memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
|
||||
delete [] prevArray;
|
||||
}
|
||||
|
||||
// allocate mesh index array in the node
|
||||
pNode->mNumMeshes = (unsigned int)meshes.size();
|
||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||
|
||||
// store all meshes in the mesh library of the scene and store their indices in the node
|
||||
for( unsigned int a = 0; a < meshes.size(); a++) {
|
||||
pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
|
||||
pNode->mMeshes[a] = pScene->mNumMeshes;
|
||||
pScene->mNumMeshes++;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts the animations from the given imported data and creates them in the scene.
|
||||
void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) {
|
||||
std::vector<aiAnimation*> newAnims;
|
||||
|
||||
for( unsigned int a = 0; a < pData->mAnims.size(); ++a ) {
|
||||
const XFile::Animation* anim = pData->mAnims[a];
|
||||
// some exporters mock me with empty animation tags.
|
||||
if ( anim->mAnims.empty() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create a new animation to hold the data
|
||||
aiAnimation* nanim = new aiAnimation;
|
||||
newAnims.push_back( nanim);
|
||||
nanim->mName.Set( anim->mName);
|
||||
// duration will be determined by the maximum length
|
||||
nanim->mDuration = 0;
|
||||
nanim->mTicksPerSecond = pData->mAnimTicksPerSecond;
|
||||
nanim->mNumChannels = (unsigned int)anim->mAnims.size();
|
||||
nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
|
||||
|
||||
for( unsigned int b = 0; b < anim->mAnims.size(); ++b ) {
|
||||
const XFile::AnimBone* bone = anim->mAnims[b];
|
||||
aiNodeAnim* nbone = new aiNodeAnim;
|
||||
nbone->mNodeName.Set( bone->mBoneName);
|
||||
nanim->mChannels[b] = nbone;
|
||||
|
||||
// key-frames are given as combined transformation matrix keys
|
||||
if( !bone->mTrafoKeys.empty() )
|
||||
{
|
||||
nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
|
||||
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
||||
nbone->mNumRotationKeys = (unsigned int)bone->mTrafoKeys.size();
|
||||
nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
|
||||
nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
|
||||
nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
|
||||
|
||||
for( unsigned int c = 0; c < bone->mTrafoKeys.size(); ++c) {
|
||||
// deconstruct each matrix into separate position, rotation and scaling
|
||||
double time = bone->mTrafoKeys[c].mTime;
|
||||
aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
|
||||
|
||||
// extract position
|
||||
aiVector3D pos( trafo.a4, trafo.b4, trafo.c4);
|
||||
|
||||
nbone->mPositionKeys[c].mTime = time;
|
||||
nbone->mPositionKeys[c].mValue = pos;
|
||||
|
||||
// extract scaling
|
||||
aiVector3D scale;
|
||||
scale.x = aiVector3D( trafo.a1, trafo.b1, trafo.c1).Length();
|
||||
scale.y = aiVector3D( trafo.a2, trafo.b2, trafo.c2).Length();
|
||||
scale.z = aiVector3D( trafo.a3, trafo.b3, trafo.c3).Length();
|
||||
nbone->mScalingKeys[c].mTime = time;
|
||||
nbone->mScalingKeys[c].mValue = scale;
|
||||
|
||||
// reconstruct rotation matrix without scaling
|
||||
aiMatrix3x3 rotmat(
|
||||
trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z,
|
||||
trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z,
|
||||
trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
|
||||
|
||||
// and convert it into a quaternion
|
||||
nbone->mRotationKeys[c].mTime = time;
|
||||
nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
|
||||
}
|
||||
|
||||
// longest lasting key sequence determines duration
|
||||
nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
|
||||
} else {
|
||||
// separate key sequences for position, rotation, scaling
|
||||
nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
|
||||
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
||||
for( unsigned int c = 0; c < nbone->mNumPositionKeys; ++c ) {
|
||||
aiVector3D pos = bone->mPosKeys[c].mValue;
|
||||
|
||||
nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
|
||||
nbone->mPositionKeys[c].mValue = pos;
|
||||
}
|
||||
|
||||
// rotation
|
||||
nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
|
||||
nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
|
||||
for( unsigned int c = 0; c < nbone->mNumRotationKeys; ++c ) {
|
||||
aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
|
||||
|
||||
nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
|
||||
nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
|
||||
nbone->mRotationKeys[c].mValue.w *= -1.0f; // needs quat inversion
|
||||
}
|
||||
|
||||
// scaling
|
||||
nbone->mNumScalingKeys = (unsigned int)bone->mScaleKeys.size();
|
||||
nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
|
||||
for( unsigned int c = 0; c < nbone->mNumScalingKeys; c++)
|
||||
nbone->mScalingKeys[c] = bone->mScaleKeys[c];
|
||||
|
||||
// longest lasting key sequence determines duration
|
||||
if( bone->mPosKeys.size() > 0)
|
||||
nanim->mDuration = std::max( nanim->mDuration, bone->mPosKeys.back().mTime);
|
||||
if( bone->mRotKeys.size() > 0)
|
||||
nanim->mDuration = std::max( nanim->mDuration, bone->mRotKeys.back().mTime);
|
||||
if( bone->mScaleKeys.size() > 0)
|
||||
nanim->mDuration = std::max( nanim->mDuration, bone->mScaleKeys.back().mTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store all converted animations in the scene
|
||||
if( newAnims.size() > 0)
|
||||
{
|
||||
pScene->mNumAnimations = (unsigned int)newAnims.size();
|
||||
pScene->mAnimations = new aiAnimation* [pScene->mNumAnimations];
|
||||
for( unsigned int a = 0; a < newAnims.size(); a++)
|
||||
pScene->mAnimations[a] = newAnims[a];
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts all materials in the given array and stores them in the scene's material list.
|
||||
void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
|
||||
{
|
||||
// count the non-referrer materials in the array
|
||||
unsigned int numNewMaterials( 0 );
|
||||
for ( unsigned int a = 0; a < pMaterials.size(); ++a ) {
|
||||
if ( !pMaterials[ a ].mIsReference ) {
|
||||
++numNewMaterials;
|
||||
}
|
||||
}
|
||||
|
||||
// resize the scene's material list to offer enough space for the new materials
|
||||
if( numNewMaterials > 0 ) {
|
||||
aiMaterial** prevMats = pScene->mMaterials;
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
|
||||
if( nullptr != prevMats) {
|
||||
::memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
|
||||
delete [] prevMats;
|
||||
}
|
||||
}
|
||||
|
||||
// convert all the materials given in the array
|
||||
for( unsigned int a = 0; a < pMaterials.size(); ++a ) {
|
||||
XFile::Material& oldMat = pMaterials[a];
|
||||
if( oldMat.mIsReference) {
|
||||
// find the material it refers to by name, and store its index
|
||||
for( size_t a = 0; a < pScene->mNumMaterials; ++a ) {
|
||||
aiString name;
|
||||
pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
|
||||
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) {
|
||||
oldMat.sceneIndex = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( oldMat.sceneIndex == SIZE_MAX ) {
|
||||
ASSIMP_LOG_WARN_F( "Could not resolve global material reference \"", oldMat.mName, "\"" );
|
||||
oldMat.sceneIndex = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
aiMaterial* mat = new aiMaterial;
|
||||
aiString name;
|
||||
name.Set( oldMat.mName);
|
||||
mat->AddProperty( &name, AI_MATKEY_NAME);
|
||||
|
||||
// Shading model: hard-coded to PHONG, there is no such information in an XFile
|
||||
// FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
|
||||
// for some models in the SDK (e.g. good old tiny.x)
|
||||
int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
|
||||
? aiShadingMode_Gouraud : aiShadingMode_Phong;
|
||||
|
||||
mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
// material colours
|
||||
// Unclear: there's no ambient colour, but emissive. What to put for ambient?
|
||||
// Probably nothing at all, let the user select a suitable default.
|
||||
mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
mat->AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
|
||||
|
||||
// texture, if there is one
|
||||
if (1 == oldMat.mTextures.size() ) {
|
||||
const XFile::TexEntry& otex = oldMat.mTextures.back();
|
||||
if (otex.mName.length()) {
|
||||
// if there is only one texture assume it contains the diffuse color
|
||||
aiString tex( otex.mName);
|
||||
if ( otex.mIsNormalMap ) {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS( 0 ) );
|
||||
} else {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise ... try to search for typical strings in the
|
||||
// texture's file name like 'bump' or 'diffuse'
|
||||
unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
|
||||
for( unsigned int b = 0; b < oldMat.mTextures.size(); ++b ) {
|
||||
const XFile::TexEntry& otex = oldMat.mTextures[b];
|
||||
std::string sz = otex.mName;
|
||||
if ( !sz.length() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the file name
|
||||
std::string::size_type s = sz.find_last_of("\\/");
|
||||
if ( std::string::npos == s ) {
|
||||
s = 0;
|
||||
}
|
||||
|
||||
// cut off the file extension
|
||||
std::string::size_type sExt = sz.find_last_of('.');
|
||||
if (std::string::npos != sExt){
|
||||
sz[sExt] = '\0';
|
||||
}
|
||||
|
||||
// convert to lower case for easier comparison
|
||||
for ( unsigned int c = 0; c < sz.length(); ++c ) {
|
||||
if ( isalpha( sz[ c ] ) ) {
|
||||
sz[ c ] = tolower( sz[ c ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Place texture filename property under the corresponding name
|
||||
aiString tex( oldMat.mTextures[b].mName);
|
||||
|
||||
// bump map
|
||||
if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
|
||||
} else if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s)) {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
|
||||
} else if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s)) {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
|
||||
} else if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s)) {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
|
||||
} else if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s)) {
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
|
||||
} else {
|
||||
// Assume it is a diffuse texture
|
||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pScene->mMaterials[pScene->mNumMaterials] = mat;
|
||||
oldMat.sceneIndex = pScene->mNumMaterials;
|
||||
pScene->mNumMaterials++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_X_IMPORTER
|
||||
149
thirdparty/assimp/code/X/XFileImporter.h
vendored
Normal file
149
thirdparty/assimp/code/X/XFileImporter.h
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file XFileImporter.h
|
||||
* @brief Definition of the XFile importer class.
|
||||
*/
|
||||
#ifndef AI_XFILEIMPORTER_H_INC
|
||||
#define AI_XFILEIMPORTER_H_INC
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "XFileHelper.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
|
||||
#include <assimp/types.h>
|
||||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace XFile {
|
||||
struct Scene;
|
||||
struct Node;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** The XFileImporter is a worker class capable of importing a scene from a
|
||||
* DirectX file .x
|
||||
*/
|
||||
class XFileImporter : public BaseImporter {
|
||||
public:
|
||||
XFileImporter();
|
||||
~XFileImporter();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool CheckSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Constructs the return data structure out of the imported data.
|
||||
* @param pScene The scene to construct the return data in.
|
||||
* @param pData The imported data in the internal temporary
|
||||
* representation.
|
||||
*/
|
||||
void CreateDataRepresentationFromImport( aiScene* pScene, XFile::Scene* pData);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Recursively creates scene nodes from the imported hierarchy.
|
||||
* The meshes and materials of the nodes will be extracted on the way.
|
||||
* @param pScene The scene to construct the return data in.
|
||||
* @param pParent The parent node where to create new child nodes
|
||||
* @param pNode The temporary node to copy.
|
||||
* @return The created node
|
||||
*/
|
||||
aiNode* CreateNodes( aiScene* pScene, aiNode* pParent,
|
||||
const XFile::Node* pNode);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts all meshes in the given mesh array. Each mesh is split
|
||||
* up per material, the indices of the generated meshes are stored in
|
||||
* the node structure.
|
||||
* @param pScene The scene to construct the return data in.
|
||||
* @param pNode The target node structure that references the
|
||||
* constructed meshes.
|
||||
* @param pMeshes The array of meshes to convert
|
||||
*/
|
||||
void CreateMeshes( aiScene* pScene, aiNode* pNode,
|
||||
const std::vector<XFile::Mesh*>& pMeshes);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts the animations from the given imported data and creates
|
||||
* them in the scene.
|
||||
* @param pScene The scene to hold to converted animations
|
||||
* @param pData The data to read the animations from
|
||||
*/
|
||||
void CreateAnimations( aiScene* pScene, const XFile::Scene* pData);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts all materials in the given array and stores them in the
|
||||
* scene's material list.
|
||||
* @param pScene The scene to hold the converted materials.
|
||||
* @param pMaterials The material array to convert.
|
||||
*/
|
||||
void ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials);
|
||||
|
||||
protected:
|
||||
/** Buffer to hold the loaded file */
|
||||
std::vector<char> mBuffer;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_BASEIMPORTER_H_INC
|
||||
1512
thirdparty/assimp/code/X/XFileParser.cpp
vendored
Normal file
1512
thirdparty/assimp/code/X/XFileParser.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
157
thirdparty/assimp/code/X/XFileParser.h
vendored
Normal file
157
thirdparty/assimp/code/X/XFileParser.h
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Helper class to parse a XFile into a temporary structure */
|
||||
#ifndef AI_XFILEPARSER_H_INC
|
||||
#define AI_XFILEPARSER_H_INC
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <assimp/types.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace XFile {
|
||||
struct Node;
|
||||
struct Mesh;
|
||||
struct Scene;
|
||||
struct Material;
|
||||
struct Animation;
|
||||
struct AnimBone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The XFileParser reads a XFile either in text or binary form and builds a temporary
|
||||
* data structure out of it.
|
||||
*/
|
||||
class XFileParser {
|
||||
public:
|
||||
/// Constructor. Creates a data structure out of the XFile given in the memory block.
|
||||
/// @param pBuffer Null-terminated memory buffer containing the XFile
|
||||
explicit XFileParser( const std::vector<char>& pBuffer);
|
||||
|
||||
/// Destructor. Destroys all imported data along with it
|
||||
~XFileParser();
|
||||
|
||||
/// Returns the temporary representation of the imported data.
|
||||
XFile::Scene* GetImportedData() const { return mScene; }
|
||||
|
||||
protected:
|
||||
void ParseFile();
|
||||
void ParseDataObjectTemplate();
|
||||
void ParseDataObjectFrame( XFile::Node *pParent);
|
||||
void ParseDataObjectTransformationMatrix( aiMatrix4x4& pMatrix);
|
||||
void ParseDataObjectMesh( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectSkinWeights( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectSkinMeshHeader( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectMeshNormals( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectMeshTextureCoords( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectMeshVertexColors( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectMeshMaterialList( XFile::Mesh* pMesh);
|
||||
void ParseDataObjectMaterial( XFile::Material* pMaterial);
|
||||
void ParseDataObjectAnimTicksPerSecond();
|
||||
void ParseDataObjectAnimationSet();
|
||||
void ParseDataObjectAnimation( XFile::Animation* pAnim);
|
||||
void ParseDataObjectAnimationKey( XFile::AnimBone *pAnimBone);
|
||||
void ParseDataObjectTextureFilename( std::string& pName);
|
||||
void ParseUnknownDataObject();
|
||||
|
||||
//! places pointer to next begin of a token, and ignores comments
|
||||
void FindNextNoneWhiteSpace();
|
||||
|
||||
//! returns next valid token. Returns empty string if no token there
|
||||
std::string GetNextToken();
|
||||
|
||||
//! reads header of data object including the opening brace.
|
||||
//! returns false if error happened, and writes name of object
|
||||
//! if there is one
|
||||
void readHeadOfDataObject( std::string* poName = NULL);
|
||||
|
||||
//! checks for closing curly brace, throws exception if not there
|
||||
void CheckForClosingBrace();
|
||||
|
||||
//! checks for one following semicolon, throws exception if not there
|
||||
void CheckForSemicolon();
|
||||
|
||||
//! checks for a separator char, either a ',' or a ';'
|
||||
void CheckForSeparator();
|
||||
|
||||
/// tests and possibly consumes a separator char, but does nothing if there was no separator
|
||||
void TestForSeparator();
|
||||
|
||||
//! reads a x file style string
|
||||
void GetNextTokenAsString( std::string& poString);
|
||||
|
||||
void ReadUntilEndOfLine();
|
||||
|
||||
unsigned short ReadBinWord();
|
||||
unsigned int ReadBinDWord();
|
||||
unsigned int ReadInt();
|
||||
ai_real ReadFloat();
|
||||
aiVector2D ReadVector2();
|
||||
aiVector3D ReadVector3();
|
||||
aiColor3D ReadRGB();
|
||||
aiColor4D ReadRGBA();
|
||||
|
||||
/** Throws an exception with a line number and the given text. */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
/**
|
||||
* @brief Filters the imported hierarchy for some degenerated cases that some exporters produce.
|
||||
* @param pData The sub-hierarchy to filter
|
||||
*/
|
||||
void FilterHierarchy( XFile::Node* pNode);
|
||||
|
||||
protected:
|
||||
unsigned int mMajorVersion, mMinorVersion; ///< version numbers
|
||||
bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
|
||||
unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8
|
||||
unsigned int mBinaryNumCount; /// < counter for number arrays in binary format
|
||||
const char* mP;
|
||||
const char* mEnd;
|
||||
unsigned int mLineNumber; ///< Line number when reading in text format
|
||||
XFile::Scene* mScene; ///< Imported data
|
||||
};
|
||||
|
||||
} //! ns Assimp
|
||||
|
||||
#endif // AI_XFILEPARSER_H_INC
|
||||
Reference in New Issue
Block a user