Model loading and texturing

This commit is contained in:
Dane Johnson
2021-01-18 18:25:47 -06:00
parent 66bf7776c7
commit 155b572aca
1283 changed files with 533814 additions and 42 deletions

View 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
View 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
View 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

View 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
View 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

File diff suppressed because it is too large Load Diff

157
thirdparty/assimp/code/X/XFileParser.h vendored Normal file
View 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