- changing Assimp's coordinate system from RH z-up to RH y-up
 - fixing coordinate system for LWO, 3DS, ASE, MD5, MDL, B3D, IRR, IRRMESH 
 - converttolh moved to three separate steps -> flipuv, flipwinding, makelh

LWO 
 - fixing texture coordinate generation -> mapping axis is correct now 
 - fixing z-fighting bug

ASE 
 - fixing crash due to invalid normal setup 
 - fixing parenting bug 
 - code cleanup

IRR 
 - code cleanup
 - fixing placement of externally loaded meshes 

MDL 
 - fixing texture coordinate space

PLY 
 - cleanup 
 - two-sided maat property is now set 

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@366 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2009-03-15 00:40:30 +00:00
parent 68d7e43056
commit c2d8881549
48 changed files with 1518 additions and 1802 deletions

View File

@ -774,20 +774,13 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m);
} }
// We used the first vertex color set to store some // We used the first vertex color set to store some emporary values so we need to cleanup here
// temporary values so we need to cleanup here
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
pcOut->mMeshes[a]->mColors[0] = NULL; pcOut->mMeshes[a]->mColors[0] = NULL;
// if the root node has only one child ... set the child as root node // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
if (1 == pcOut->mRootNode->mNumChildren) pcOut->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
{ 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
aiNode* pcOld = pcOut->mRootNode;
pcOut->mRootNode = pcOut->mRootNode->mChildren[0];
pcOut->mRootNode->mParent = NULL;
pcOld->mChildren[0] = NULL;
delete pcOld;
}
// If the root node is unnamed name it "<3DSRoot>" // If the root node is unnamed name it "<3DSRoot>"
if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||

File diff suppressed because it is too large Load Diff

View File

@ -1889,18 +1889,20 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f ));
unsigned int index, faceIdx = 0xffffffff; unsigned int index, faceIdx = 0xffffffff;
// FIXME: rewrite this and find out how to interpret the normals
// correctly. This is crap.
// Smooth the vertex and face normals together. The result // Smooth the vertex and face normals together. The result
// will be edgy then, but otherwise everything would be soft ... // will be edgy then, but otherwise everything would be soft ...
while (true) while (true) {
{ if ('*' == *filePtr) {
if ('*' == *filePtr)
{
++filePtr; ++filePtr;
if (faceIdx != 0xffffffff && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) if (faceIdx != 0xffffffff && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) {
{
aiVector3D vNormal; aiVector3D vNormal;
ParseLV4MeshFloatTriple(&vNormal.x,index); ParseLV4MeshFloatTriple(&vNormal.x,index);
if (faceIdx >= sMesh.mFaces.size())
continue;
// Make sure we assign it to the correct face // Make sure we assign it to the correct face
const ASE::Face& face = sMesh.mFaces[faceIdx]; const ASE::Face& face = sMesh.mFaces[faceIdx];
if (index == face.mIndices[0]) if (index == face.mIndices[0])
@ -1909,29 +1911,27 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
index = 1; index = 1;
else if (index == face.mIndices[2]) else if (index == face.mIndices[2])
index = 2; index = 2;
else else {
{
DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
continue; continue;
} }
// We'll renormalize later // We'll renormalize later
sMesh.mNormals[faceIdx*3+index] += vNormal; sMesh.mNormals[faceIdx*3+index] += vNormal;
continue; continue;
} }
if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) {
{
aiVector3D vNormal; aiVector3D vNormal;
ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
if (faceIdx >= sMesh.mFaces.size()) if (faceIdx >= sMesh.mFaces.size()) {
{
DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section");
continue; continue;
} }
// We'll renormalize later // We'll renormalize later
sMesh.mNormals[faceIdx*3] += vNormal; sMesh.mNormals[faceIdx*3] += vNormal;
sMesh.mNormals[faceIdx*3+1] += vNormal;
sMesh.mNormals[faceIdx*3+2] += vNormal;
continue; continue;
} }
} }

View File

@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// internal headers // internal headers
#include "B3DImporter.h" #include "B3DImporter.h"
#include "TextureTransform.h" #include "TextureTransform.h"
#include "ConvertToLHProcess.h"
using namespace Assimp; using namespace Assimp;
using namespace std; using namespace std;
@ -119,11 +120,6 @@ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
//create root node //create root node
aiNode *node=new aiNode( "root" ); aiNode *node=new aiNode( "root" );
node->mTransformation=aiMatrix4x4(
1,0,0,0,
0,0,1,0,
0,1,0,0,
0,0,0,1 );
node->mNumMeshes=_meshes.size(); node->mNumMeshes=_meshes.size();
node->mMeshes=new unsigned[_meshes.size()]; node->mMeshes=new unsigned[_meshes.size()];
@ -131,6 +127,10 @@ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
node->mMeshes[i]=i; node->mMeshes[i]=i;
} }
pScene->mRootNode=node; pScene->mRootNode=node;
// convert to RH
MakeLeftHandedProcess monster_maker;
monster_maker.Execute(pScene);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -348,8 +348,8 @@ void B3DImporter::ReadTRIS(){
unsigned *ip=face->mIndices=new unsigned[3]; unsigned *ip=face->mIndices=new unsigned[3];
int v[3]; int v[3];
v[0]=ReadInt(); v[0]=ReadInt();
v[2]=ReadInt();
v[1]=ReadInt(); v[1]=ReadInt();
v[2]=ReadInt();
for( unsigned j=0;j<3;++j ){ for( unsigned j=0;j<3;++j ){
int k=v[j]; int k=v[j];
const Vertex &v=_vertices[k]; const Vertex &v=_vertices[k];

View File

@ -39,136 +39,220 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file Implementation of the post processing step to convert all imported data /** @file MakeLeftHandedProcess.cpp
* to a left-handed coordinate system. * @brief Implementation of the post processing step to convert all
* imported data to a left-handed coordinate system.
*
* Face order & UV flip are also implemented here, for the sake of a
* better location.
*/ */
#include "AssimpPCH.h" #include "AssimpPCH.h"
#include "ConvertToLHProcess.h" #include "ConvertToLHProcess.h"
using namespace Assimp; using namespace Assimp;
// The transformation matrix to convert from DirectX coordinates to OpenGL coordinates. #ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
const aiMatrix3x3 Assimp::ConvertToLHProcess::sToOGLTransform(
1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f
);
// The transformation matrix to convert from OpenGL coordinates to DirectX coordinates.
const aiMatrix3x3 Assimp::ConvertToLHProcess::sToDXTransform(
1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f
);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ConvertToLHProcess::ConvertToLHProcess() MakeLeftHandedProcess::MakeLeftHandedProcess()
{ {}
bTransformVertices = false;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
ConvertToLHProcess::~ConvertToLHProcess() MakeLeftHandedProcess::~MakeLeftHandedProcess()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool ConvertToLHProcess::IsActive( unsigned int pFlags) const bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const
{ {
if (pFlags & aiProcess_ConvertToLeftHanded) return 0 != (pFlags & aiProcess_MakeLeftHanded);
{
bTransformVertices = (0 != (pFlags & aiProcess_PreTransformVertices) ? true : false);
return true;
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void ConvertToLHProcess::Execute( aiScene* pScene) void MakeLeftHandedProcess::Execute( aiScene* pScene)
{ {
// Check for an existent root node to proceed // Check for an existent root node to proceed
if (NULL == pScene->mRootNode) ai_assert(pScene->mRootNode != NULL);
{ DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
DefaultLogger::get()->error("ConvertToLHProcess fails, there is no root node");
return;
}
DefaultLogger::get()->debug("ConvertToLHProcess begin"); // recursively convert all the nodes
ProcessNode( pScene->mRootNode, aiMatrix4x4());
// transform vertex by vertex or change the root transform? // process the meshes accordingly
// We can't do the coordinate system transformation earlier for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
// in the pipeline - most steps assume that we're in OGL
// space. So we need to transform all vertices a second time
// here.
if (bTransformVertices)
{
aiMatrix4x4 mTransform;
ConvertToDX(mTransform);
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiMesh* pcMesh = pScene->mMeshes[i];
// transform all vertices
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
pcMesh->mVertices[n] = mTransform * pcMesh->mVertices[n];
// transform all normals
if (pcMesh->HasNormals())
{
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
pcMesh->mNormals[n] = mTransform * pcMesh->mNormals[n];
}
// transform all tangents and all bitangents
if (pcMesh->HasTangentsAndBitangents())
{
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
{
pcMesh->mTangents[n] = mTransform * pcMesh->mTangents[n];
pcMesh->mBitangents[n] = mTransform * pcMesh->mBitangents[n];
}
}
}
}
else
{
// transform the root node of the scene, the other nodes will follow then
ConvertToDX( pScene->mRootNode->mTransformation);
}
// transform all meshes accordingly
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
ProcessMesh( pScene->mMeshes[a]); ProcessMesh( pScene->mMeshes[a]);
// process all materials - we need to adjust UV transformations // process the materials accordingly
for( unsigned int a = 0; a < pScene->mNumMaterials; a++) for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
ProcessMaterial( pScene->mMaterials[a]); ProcessMaterial( pScene->mMaterials[a]);
// transform all animation channels affecting the root node as well // transform all animation channels as well
for( unsigned int a = 0; a < pScene->mNumAnimations; a++) for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
{ {
aiAnimation* anim = pScene->mAnimations[a]; aiAnimation* anim = pScene->mAnimations[a];
for( unsigned int b = 0; b < anim->mNumChannels; b++) for( unsigned int b = 0; b < anim->mNumChannels; b++)
{ {
aiNodeAnim* nodeAnim = anim->mChannels[b]; aiNodeAnim* nodeAnim = anim->mChannels[b];
if( strcmp( nodeAnim->mNodeName.data, pScene->mRootNode->mName.data) == 0) ProcessAnimation( nodeAnim);
ProcessAnimation( nodeAnim);
} }
} }
DefaultLogger::get()->debug("ConvertToLHProcess finished");
// flipping a single vector component means inverting face order ...
FlipWindingOrderProcess flipper;
flipper.Execute(pScene);
DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
}
// ------------------------------------------------------------------------------------------------
// Recursively converts a node, all of its children and all of its meshes
void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation)
{
// mirror all base vectors at the local Z axis
pNode->mTransformation.c1 = -pNode->mTransformation.c1;
pNode->mTransformation.c2 = -pNode->mTransformation.c2;
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
pNode->mTransformation.c4 = -pNode->mTransformation.c4;
// now invert the Z axis again to keep the matrix determinant positive.
// The local meshes will be inverted accordingly so that the result should look just fine again.
pNode->mTransformation.a3 = -pNode->mTransformation.a3;
pNode->mTransformation.b3 = -pNode->mTransformation.b3;
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
// continue for all children
for( size_t a = 0; a < pNode->mNumChildren; ++a)
ProcessNode( pNode->mChildren[a], pParentGlobalRotation * pNode->mTransformation);
}
// ------------------------------------------------------------------------------------------------
// Converts a single mesh to left handed coordinates.
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
{
// mirror positions, normals and stuff along the Z axis
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
{
pMesh->mVertices[a].z *= -1.0f;
if( pMesh->HasNormals())
pMesh->mNormals[a].z *= -1.0f;
if( pMesh->HasTangentsAndBitangents())
{
pMesh->mTangents[a].z *= -1.0f;
pMesh->mBitangents[a].z *= -1.0f;
}
}
// mirror offset matrices of all bones
for( size_t a = 0; a < pMesh->mNumBones; ++a)
{
aiBone* bone = pMesh->mBones[a];
bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
}
// mirror bitangents as well as they're derived from the texture coords
if( pMesh->HasTangentsAndBitangents())
{
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
pMesh->mBitangents[a] *= -1.0f;
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Converts a single material to left handed coordinates. // Converts a single material to left handed coordinates.
void ConvertToLHProcess::ProcessMaterial (aiMaterial* mat) void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
{ {
for (unsigned int a = 0; a < mat->mNumProperties;++a) MaterialHelper* mat = (MaterialHelper*)_mat;
{ for (unsigned int a = 0; a < mat->mNumProperties;++a) {
aiMaterialProperty* prop = mat->mProperties[a]; aiMaterialProperty* prop = mat->mProperties[a];
if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))
{ // Mapping axis for UV mappings?
ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
aiVector3D* pff = (aiVector3D*)prop->mData;
pff->z *= -1.f;
}
}
}
// ------------------------------------------------------------------------------------------------
// Converts the given animation to LH coordinates.
void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
{
// position keys
for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
pAnim->mPositionKeys[a].mValue.z *= -1.0f;
// rotation keys
for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
{
/* That's the safe version, but the float errors add up. So we try the short version instead
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
aiQuaternion rotquat( rotmat);
pAnim->mRotationKeys[a].mValue = rotquat;
*/
pAnim->mRotationKeys[a].mValue.x *= -1.0f;
pAnim->mRotationKeys[a].mValue.y *= -1.0f;
}
}
#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS
// # FlipUVsProcess
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
FlipUVsProcess::FlipUVsProcess()
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FlipUVsProcess::~FlipUVsProcess()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool FlipUVsProcess::IsActive( unsigned int pFlags) const
{
return 0 != (pFlags & aiProcess_FlipUVs);
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void FlipUVsProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("FlipUVsProcess begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
ProcessMesh(pScene->mMeshes[i]);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
ProcessMaterial(pScene->mMaterials[i]);
DefaultLogger::get()->debug("FlipUVsProcess finished");
}
// ------------------------------------------------------------------------------------------------
// Converts a single material
void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
{
MaterialHelper* mat = (MaterialHelper*)_mat;
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
aiMaterialProperty* prop = mat->mProperties[a];
// UV transformation key?
if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) {
ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */
aiUVTransform* uv = (aiUVTransform*)prop->mData; aiUVTransform* uv = (aiUVTransform*)prop->mData;
// just flip it, that's everything // just flip it, that's everything
@ -179,8 +263,53 @@ void ConvertToLHProcess::ProcessMaterial (aiMaterial* mat)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Converts a single mesh to left handed coordinates. // Converts a single mesh
void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh) void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
{
// mirror texture y coordinate
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
if( !pMesh->HasTextureCoords( a))
break;
for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
pMesh->mTextureCoords[a][b].y = 1.0f - pMesh->mTextureCoords[a][b].y;
}
}
#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS
#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
// # FlipWindingOrderProcess
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
FlipWindingOrderProcess::FlipWindingOrderProcess()
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FlipWindingOrderProcess::~FlipWindingOrderProcess()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
{
return 0 != (pFlags & aiProcess_FlipWindingOrder);
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void FlipWindingOrderProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
ProcessMesh(pScene->mMeshes[i]);
DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
}
// ------------------------------------------------------------------------------------------------
// Converts a single mesh
void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
{ {
// invert the order of all faces in this mesh // invert the order of all faces in this mesh
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
@ -189,77 +318,6 @@ void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh)
for( unsigned int b = 0; b < face.mNumIndices / 2; b++) for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]); std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
} }
// mirror texture y coordinate
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
{
if( pMesh->HasTextureCoords( a))
{
for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
pMesh->mTextureCoords[a][b].y = 1.0f - pMesh->mTextureCoords[a][b].y;
}
}
// mirror bitangents as well as they're derived from the texture coords
if( pMesh->HasTangentsAndBitangents())
{
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
pMesh->mBitangents[a] = -pMesh->mBitangents[a];
}
} }
// ------------------------------------------------------------------------------------------------ #endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
// Converts the given animation to LH coordinates.
void ConvertToLHProcess::ProcessAnimation( aiNodeAnim* pAnim)
{
// position keys
for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
ConvertToDX( pAnim->mPositionKeys[a].mValue);
return;
// rotation keys
for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
{
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
ConvertToDX( rotmat);
pAnim->mRotationKeys[a].mValue = aiQuaternion( rotmat);
}
}
// ------------------------------------------------------------------------------------------------
// Static helper function to convert a vector/matrix from DX to OGL coords
void ConvertToLHProcess::ConvertToOGL( aiVector3D& poVector)
{
poVector = sToOGLTransform * poVector;
}
// ------------------------------------------------------------------------------------------------
void ConvertToLHProcess::ConvertToOGL( aiMatrix3x3& poMatrix)
{
poMatrix = sToOGLTransform * poMatrix;
}
// ------------------------------------------------------------------------------------------------
void ConvertToLHProcess::ConvertToOGL( aiMatrix4x4& poMatrix)
{
poMatrix = aiMatrix4x4( sToOGLTransform) * poMatrix;
}
// ------------------------------------------------------------------------------------------------
// Static helper function to convert a vector/matrix from OGL back to DX coords
void ConvertToLHProcess::ConvertToDX( aiVector3D& poVector)
{
poVector = sToDXTransform * poVector;
}
// ------------------------------------------------------------------------------------------------
void ConvertToLHProcess::ConvertToDX( aiMatrix3x3& poMatrix)
{
poMatrix = sToDXTransform * poMatrix;
}
// ------------------------------------------------------------------------------------------------
void ConvertToLHProcess::ConvertToDX( aiMatrix4x4& poMatrix)
{
poMatrix = aiMatrix4x4(sToDXTransform) * poMatrix;
}

View File

@ -38,7 +38,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file Defines a post processing step to convert all data to a left-handed coordinate system.*/ /** @file MakeLeftHandedProcess.h
* @brief Defines a bunch of post-processing steps to handle
* coordinate system conversions.
*
* - LH to RH
* - UV origin upper-left to lower-left
* - face order cw to ccw
*/
#ifndef AI_CONVERTTOLHPROCESS_H_INC #ifndef AI_CONVERTTOLHPROCESS_H_INC
#define AI_CONVERTTOLHPROCESS_H_INC #define AI_CONVERTTOLHPROCESS_H_INC
@ -48,72 +55,55 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiMesh; struct aiMesh;
struct aiNodeAnim; struct aiNodeAnim;
namespace Assimp namespace Assimp {
{
// --------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
/** The ConvertToLHProcess converts all imported data to a left-handed coordinate /** @brief The MakeLeftHandedProcess converts all imported data to a left-handed
* system. This implies inverting the Z axis for all transformation matrices * coordinate system.
* invert the orientation of all faces, and adapting skinning and animation *
* data in a similar way. * This implies a mirroring of the Z axis of the coordinate system. But to keep
* transformation matrices free from reflections we shift the reflection to other
* places. We mirror the meshes and adapt the rotations.
*
* @note RH-LH and LH-RH is the same, so this class can be used for both
*/ */
class ASSIMP_API ConvertToLHProcess : public BaseProcess class ASSIMP_API MakeLeftHandedProcess : public BaseProcess
{ {
friend class Importer; friend class Importer;
protected: public:
/** Constructor to be privately used by Importer */ /** Constructor to be privately used by Importer */
ConvertToLHProcess(); MakeLeftHandedProcess();
/** Destructor, private as well */ /** Destructor, private as well */
~ConvertToLHProcess(); ~MakeLeftHandedProcess();
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field.
* @param pFlags The processing flags the importer was called with. A bitwise
* combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not.
*/
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail.
* @param pScene The imported data to work at.
*/
void Execute( aiScene* pScene); void Execute( aiScene* pScene);
// -------------------------------------------------------------------
/** Static helper function to convert a vector/matrix from DX coords to OGL coords.
* @param poMatrix The matrix to convert.
*/
static void ConvertToOGL( aiVector3D& poVector);
static void ConvertToOGL( aiMatrix3x3& poMatrix);
static void ConvertToOGL( aiMatrix4x4& poMatrix);
// -------------------------------------------------------------------
/** Static helper function to convert a vector/matrix from OGL coords back to DX coords.
* @param poMatrix The matrix to convert.
*/
static void ConvertToDX( aiVector3D& poVector);
static void ConvertToDX( aiMatrix3x3& poMatrix);
static void ConvertToDX( aiMatrix4x4& poMatrix);
protected: protected:
// -------------------------------------------------------------------
/** Recursively converts a node and all of its children
*/
void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Converts a single mesh to left handed coordinates. /** Converts a single mesh to left handed coordinates.
* This simply means the order of all faces is inverted. * This means that positions, normals and tangents are mirrored at
* the local Z axis and the order of all faces are inverted.
* @param pMesh The mesh to convert. * @param pMesh The mesh to convert.
*/ */
void ProcessMesh( aiMesh* pMesh); void ProcessMesh( aiMesh* pMesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Converts a single material to left handed coordinates. /** Converts a single material to left-handed coordinates
* This simply means all UV offsets are inverted. * @param pMat Material to convert
* @param mat The material to convert.
*/ */
void ProcessMaterial (aiMaterial* mat); void ProcessMaterial( aiMaterial* pMat);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Converts the given animation to LH coordinates. /** Converts the given animation to LH coordinates.
@ -122,16 +112,56 @@ protected:
* @param pAnim The bone animation to transform * @param pAnim The bone animation to transform
*/ */
void ProcessAnimation( aiNodeAnim* pAnim); void ProcessAnimation( aiNodeAnim* pAnim);
};
//! true if the transformation matrix for the OGL-to-DX is
//! directly used to transform all vertices. // ---------------------------------------------------------------------------
mutable bool bTransformVertices; /** Postprocessing step to flip the face order of the imported data
*/
class ASSIMP_API FlipWindingOrderProcess : public BaseProcess
{
friend class Importer;
public: public:
/** The transformation matrix to convert from DirectX coordinates to OpenGL coordinates. */ /** Constructor to be privately used by Importer */
static const aiMatrix3x3 sToOGLTransform; FlipWindingOrderProcess();
/** The transformation matrix to convert from OpenGL coordinates to DirectX coordinates. */
static const aiMatrix3x3 sToDXTransform; /** Destructor, private as well */
~FlipWindingOrderProcess();
// -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
void Execute( aiScene* pScene);
protected:
void ProcessMesh( aiMesh* pMesh);
};
// ---------------------------------------------------------------------------
/** Postprocessing step to flip the UV coordinate system of the import data
*/
class ASSIMP_API FlipUVsProcess : public BaseProcess
{
friend class Importer;
public:
/** Constructor to be privately used by Importer */
FlipUVsProcess();
/** Destructor, private as well */
~FlipUVsProcess();
// -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
void Execute( aiScene* pScene);
protected:
void ProcessMesh( aiMesh* pMesh);
void ProcessMaterial( aiMaterial* mat);
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -84,16 +84,12 @@ aiColor4D g_clrInvalid = aiColor4D(get_qnan(),0.f,0.f,1.f);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
DXFImporter::DXFImporter() DXFImporter::DXFImporter()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
DXFImporter::~DXFImporter() DXFImporter::~DXFImporter()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
@ -103,6 +99,7 @@ bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a list of all supported file extensions
void DXFImporter::GetExtensionList(std::string& append) void DXFImporter::GetExtensionList(std::string& append)
{ {
append.append("*.dxf"); append.append("*.dxf");
@ -115,8 +112,7 @@ bool DXFImporter::GetNextLine()
if(!SkipLine(&buffer)) if(!SkipLine(&buffer))
return false; return false;
if(!SkipSpaces(&buffer))return GetNextLine(); if(!SkipSpaces(&buffer))return GetNextLine();
else if (*buffer == '{') else if (*buffer == '{') {
{
// some strange meta data ... // some strange meta data ...
while (true) while (true)
{ {
@ -135,8 +131,7 @@ bool DXFImporter::GetNextLine()
// Get the next token in the file // Get the next token in the file
bool DXFImporter::GetNextToken() bool DXFImporter::GetNextToken()
{ {
if (bRepeat) if (bRepeat) {
{
bRepeat = false; bRepeat = false;
return true; return true;
} }
@ -181,26 +176,23 @@ void DXFImporter::InternReadFile( const std::string& pFile,
throw new ImportErrorException("DXF: Binary files are not supported at the moment"); throw new ImportErrorException("DXF: Binary files are not supported at the moment");
// now get all lines of the file // now get all lines of the file
while (GetNextToken()) while (GetNextToken()) {
{
if (2 == groupCode) if (2 == groupCode) {
{
// ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them // ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them
if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS")) if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS"))
if (!ParseEntities())break; else bRepeat = true; if (!ParseEntities())break; else bRepeat = true;
// other sections - skip them to make sure there will be no name conflicts // other sections - skip them to make sure there will be no name conflicts
else else {
{ while (GetNextToken()) {
while (GetNextToken())
{
if (!groupCode && !::strcmp(cursor,"ENDSEC"))break; if (!groupCode && !::strcmp(cursor,"ENDSEC"))break;
} }
} }
} }
// print comment strings // print comment strings
else if (999 == groupCode) else if (999 == groupCode) {
{
DefaultLogger::get()->info(std::string( cursor )); DefaultLogger::get()->info(std::string( cursor ));
} }
else if (!groupCode && !::strcmp(cursor,"EOF")) else if (!groupCode && !::strcmp(cursor,"EOF"))
@ -208,9 +200,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
} }
// find out how many valud layers we have // find out how many valud layers we have
for (std::vector<LayerInfo>::const_iterator it = mLayers.begin(),end = mLayers.end(); for (std::vector<LayerInfo>::const_iterator it = mLayers.begin(),end = mLayers.end(); it != end;++it) {
it != end;++it)
{
if (!(*it).vPositions.empty())++pScene->mNumMeshes; if (!(*it).vPositions.empty())++pScene->mNumMeshes;
} }
@ -219,11 +209,10 @@ void DXFImporter::InternReadFile( const std::string& pFile,
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
m = 0; m = 0;
for (std::vector<LayerInfo>::const_iterator it = mLayers.begin(),end = mLayers.end(); for (std::vector<LayerInfo>::const_iterator it = mLayers.begin(),end = mLayers.end();it != end;++it) {
it != end;++it) if ((*it).vPositions.empty()) {
{ continue;
if ((*it).vPositions.empty())continue; }
// generate the output mesh // generate the output mesh
aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh(); aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh();
const std::vector<aiVector3D>& vPositions = (*it).vPositions; const std::vector<aiVector3D>& vPositions = (*it).vPositions;
@ -232,11 +221,9 @@ void DXFImporter::InternReadFile( const std::string& pFile,
// check whether we need vertex colors here // check whether we need vertex colors here
aiColor4D* clrOut = NULL; aiColor4D* clrOut = NULL;
const aiColor4D* clr = NULL; const aiColor4D* clr = NULL;
for (std::vector<aiColor4D>::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end(); for (std::vector<aiColor4D>::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end();it2 != end2; ++it2) {
it2 != end2; ++it2)
{ if ((*it2).r == (*it2).r) /* qnan? */ {
if ((*it2).r == (*it2).r) // check against qnan
{
clrOut = pMesh->mColors[0] = new aiColor4D[vPositions.size()]; clrOut = pMesh->mColors[0] = new aiColor4D[vPositions.size()];
for (unsigned int i = 0; i < vPositions.size();++i) for (unsigned int i = 0; i < vPositions.size();++i)
clrOut[i] = aiColor4D(0.6f,0.6f,0.6f,1.0f); clrOut[i] = aiColor4D(0.6f,0.6f,0.6f,1.0f);
@ -252,30 +239,25 @@ void DXFImporter::InternReadFile( const std::string& pFile,
aiVector3D* vpOut = pMesh->mVertices = new aiVector3D[vPositions.size()]; aiVector3D* vpOut = pMesh->mVertices = new aiVector3D[vPositions.size()];
const aiVector3D* vp = &vPositions[0]; const aiVector3D* vp = &vPositions[0];
for (unsigned int i = 0; i < pMesh->mNumFaces;++i) for (unsigned int i = 0; i < pMesh->mNumFaces;++i) {
{
aiFace& face = pMesh->mFaces[i]; aiFace& face = pMesh->mFaces[i];
// check whether we need four, three or two indices here // check whether we need four, three or two indices here
if (vp[1] == vp[2]) if (vp[1] == vp[2]) {
{
face.mNumIndices = 2; face.mNumIndices = 2;
} }
else if (vp[3] == vp[2]) else if (vp[3] == vp[2]) {
{
face.mNumIndices = 3; face.mNumIndices = 3;
} }
else face.mNumIndices = 4; else face.mNumIndices = 4;
face.mIndices = new unsigned int[face.mNumIndices]; face.mIndices = new unsigned int[face.mNumIndices];
for (unsigned int a = 0; a < face.mNumIndices;++a) for (unsigned int a = 0; a < face.mNumIndices;++a) {
{
*vpOut++ = vp[a]; *vpOut++ = vp[a];
if (clr) if (clr) {
{ if (is_not_qnan( clr[a].r )) {
if (is_not_qnan( clr[a].r ))
*clrOut = clr[a]; *clrOut = clr[a];
}
++clrOut; ++clrOut;
} }
face.mIndices[a] = pMesh->mNumVertices++; face.mIndices[a] = pMesh->mNumVertices++;
@ -288,16 +270,14 @@ void DXFImporter::InternReadFile( const std::string& pFile,
pScene->mRootNode = new aiNode(); pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("<DXF_ROOT>"); pScene->mRootNode->mName.Set("<DXF_ROOT>");
if (1 == pScene->mNumMeshes) if (1 == pScene->mNumMeshes) {
{
pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ]; pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ];
pScene->mRootNode->mMeshes[0] = 0; pScene->mRootNode->mMeshes[0] = 0;
} }
else else
{ {
pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ]; pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ];
for (m = 0; m < pScene->mRootNode->mNumChildren;++m) for (m = 0; m < pScene->mRootNode->mNumChildren;++m) {
{
aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode(); aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode();
p->mName.length = ::strlen( mLayers[m].name ); p->mName.length = ::strlen( mLayers[m].name );
::strcpy(p->mName.data, mLayers[m].name); ::strcpy(p->mName.data, mLayers[m].name);
@ -333,10 +313,8 @@ void DXFImporter::InternReadFile( const std::string& pFile,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool DXFImporter::ParseEntities() bool DXFImporter::ParseEntities()
{ {
while (GetNextToken()) while (GetNextToken()) {
{ if (!groupCode) {
if (!groupCode)
{
if (!::strcmp(cursor,"3DFACE") || !::strcmp(cursor,"LINE") || !::strcmp(cursor,"3DLINE")) if (!::strcmp(cursor,"3DFACE") || !::strcmp(cursor,"LINE") || !::strcmp(cursor,"3DLINE"))
if (!Parse3DFace()) return false; else bRepeat = true; if (!Parse3DFace()) return false; else bRepeat = true;
@ -353,17 +331,13 @@ bool DXFImporter::ParseEntities()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::SetLayer(LayerInfo*& out) void DXFImporter::SetLayer(LayerInfo*& out)
{ {
for (std::vector<LayerInfo>::iterator it = mLayers.begin(),end = mLayers.end(); for (std::vector<LayerInfo>::iterator it = mLayers.begin(),end = mLayers.end();it != end;++it) {
it != end;++it) if (!::strcmp( (*it).name, cursor )) {
{
if (!::strcmp( (*it).name, cursor ))
{
out = &(*it); out = &(*it);
break; break;
} }
} }
if (!out) if (!out) {
{
// we don't have this layer yet // we don't have this layer yet
mLayers.push_back(LayerInfo()); mLayers.push_back(LayerInfo());
out = &mLayers.back(); out = &mLayers.back();
@ -374,8 +348,7 @@ void DXFImporter::SetLayer(LayerInfo*& out)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::SetDefaultLayer(LayerInfo*& out) void DXFImporter::SetDefaultLayer(LayerInfo*& out)
{ {
if (!mDefaultLayer) if (!mDefaultLayer) {
{
mLayers.push_back(LayerInfo()); mLayers.push_back(LayerInfo());
mDefaultLayer = &mLayers.back(); mDefaultLayer = &mLayers.back();
} }
@ -393,27 +366,22 @@ bool DXFImporter::ParsePolyLine()
std::vector<unsigned int> indices; std::vector<unsigned int> indices;
unsigned int flags = 0; unsigned int flags = 0;
while (GetNextToken()) while (GetNextToken()) {
{
switch (groupCode) switch (groupCode)
{ {
case 0: case 0:
{ {
if (!::strcmp(cursor,"VERTEX")) if (!::strcmp(cursor,"VERTEX")) {
{
aiVector3D v;aiColor4D clr(g_clrInvalid); aiVector3D v;aiColor4D clr(g_clrInvalid);
unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff}; unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff};
ParsePolyLineVertex(v, clr, idx); ParsePolyLineVertex(v, clr, idx);
if (0xffffffff == idx[0]) if (0xffffffff == idx[0]) {
{
positions.push_back(v); positions.push_back(v);
colors.push_back(clr); colors.push_back(clr);
} }
else else {
{
// check whether we have a fourth coordinate // check whether we have a fourth coordinate
if (0xffffffff == idx[3]) if (0xffffffff == idx[3]) {
{
idx[3] = idx[2]; idx[3] = idx[2];
} }
@ -423,8 +391,7 @@ bool DXFImporter::ParsePolyLine()
} }
bRepeat = true; bRepeat = true;
} }
else if (!::strcmp(cursor,"ENDSEQ")) else if (!::strcmp(cursor,"ENDSEQ")) {
{
ret = true; ret = true;
} }
break; break;
@ -433,8 +400,7 @@ bool DXFImporter::ParsePolyLine()
// flags --- important that we know whether it is a polyface mesh // flags --- important that we know whether it is a polyface mesh
case 70: case 70:
{ {
if (!flags) if (!flags) {
{
flags = strtol10(cursor); flags = strtol10(cursor);
} }
break; break;
@ -462,32 +428,29 @@ bool DXFImporter::ParsePolyLine()
} }
} }
} }
if (!(flags & 64)) if (!(flags & 64)) {
{
DefaultLogger::get()->warn("DXF: Only polyface meshes are currently supported"); DefaultLogger::get()->warn("DXF: Only polyface meshes are currently supported");
return ret; return ret;
} }
if (positions.size() < 3 || indices.size() < 3) if (positions.size() < 3 || indices.size() < 3) {
{
DefaultLogger::get()->warn("DXF: Unable to parse POLYLINE element - not enough vertices"); DefaultLogger::get()->warn("DXF: Unable to parse POLYLINE element - not enough vertices");
return ret; return ret;
} }
// use a default layer if necessary // use a default layer if necessary
if (!out)SetDefaultLayer(out); if (!out) {
SetDefaultLayer(out);
}
flags = (unsigned int)(out->vPositions.size()+indices.size()); flags = (unsigned int)(out->vPositions.size()+indices.size());
out->vPositions.reserve(flags); out->vPositions.reserve(flags);
out->vColors.reserve(flags); out->vColors.reserve(flags);
// generate unique vertices // generate unique vertices
for (std::vector<unsigned int>::const_iterator it = indices.begin(), end = indices.end(); for (std::vector<unsigned int>::const_iterator it = indices.begin(), end = indices.end();it != end; ++it) {
it != end; ++it)
{
unsigned int idx = *it; unsigned int idx = *it;
if (idx > positions.size() || !idx) if (idx > positions.size() || !idx) {
{
DefaultLogger::get()->error("DXF: Polyface mesh index os out of range"); DefaultLogger::get()->error("DXF: Polyface mesh index os out of range");
idx = (unsigned int) positions.size(); idx = (unsigned int) positions.size();
} }
@ -502,11 +465,11 @@ bool DXFImporter::ParsePolyLine()
bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned int* outIdx) bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned int* outIdx)
{ {
bool ret = false; bool ret = false;
while (GetNextToken()) while (GetNextToken()) {
{
switch (groupCode) switch (groupCode)
{ {
case 0: ret = true;break; case 0: ret = true;
break;
// todo - handle the correct layer for the vertex // todo - handle the correct layer for the vertex
// At the moment it is assumed that all vertices of // At the moment it is assumed that all vertices of
@ -530,7 +493,9 @@ bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned i
// color // color
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break; case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
}; };
if (ret)break; if (ret) {
break;
}
} }
return ret; return ret;
} }
@ -547,15 +512,12 @@ bool DXFImporter::Parse3DFace()
// this is also used for for parsing line entities // this is also used for for parsing line entities
bool bThird = false; bool bThird = false;
while (GetNextToken()) while (GetNextToken()) {
{ switch (groupCode) {
switch (groupCode)
{
case 0: ret = true;break; case 0: ret = true;break;
// 8 specifies the layer // 8 specifies the layer
case 8: case 8: {
{
SetLayer(out); SetLayer(out);
break; break;
} }
@ -611,8 +573,9 @@ bool DXFImporter::Parse3DFace()
if (!bThird)vip[2] = vip[1]; if (!bThird)vip[2] = vip[1];
// use a default layer if necessary // use a default layer if necessary
if (!out)SetDefaultLayer(out); if (!out) {
SetDefaultLayer(out);
}
// add the faces to the face list for this layer // add the faces to the face list for this layer
out->vPositions.push_back(vip[0]); out->vPositions.push_back(vip[0]);
out->vPositions.push_back(vip[1]); out->vPositions.push_back(vip[1]);

View File

@ -70,16 +70,12 @@ using namespace boost::math;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
IRRImporter::IRRImporter() IRRImporter::IRRImporter()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
IRRImporter::~IRRImporter() IRRImporter::~IRRImporter()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
@ -174,17 +170,14 @@ aiMesh* IRRImporter::BuildSingleQuadMesh(const SkyboxVertex& v1,
*vec++ = v2.uv; *vec++ = v2.uv;
*vec++ = v3.uv; *vec++ = v3.uv;
*vec = v4.uv; *vec = v4.uv;
return out; return out;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void IRRImporter::BuildSkybox(std::vector<aiMesh*>& meshes, std::vector<aiMaterial*> materials) void IRRImporter::BuildSkybox(std::vector<aiMesh*>& meshes, std::vector<aiMaterial*> materials)
{ {
// Update the material of the skybox - replace the name // Update the material of the skybox - replace the name and disable shading for skyboxes.
// and disable shading for skyboxes. for (unsigned int i = 0; i < 6;++i) {
for (unsigned int i = 0; i < 6;++i)
{
MaterialHelper* out = ( MaterialHelper* ) (*(materials.end()-(6-i))); MaterialHelper* out = ( MaterialHelper* ) (*(materials.end()-(6-i)));
aiString s; aiString s;
@ -256,8 +249,7 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial*>& materials,
unsigned int& defMatIdx, unsigned int& defMatIdx,
aiMesh* mesh) aiMesh* mesh)
{ {
if (inmaterials.empty()) if (inmaterials.empty()) {
{
// Do we have a default material? If not we need to create one // Do we have a default material? If not we need to create one
if (0xffffffff == defMatIdx) if (0xffffffff == defMatIdx)
{ {
@ -274,8 +266,7 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial*>& materials,
mesh->mMaterialIndex = defMatIdx; mesh->mMaterialIndex = defMatIdx;
return; return;
} }
else if (inmaterials.size() > 1) else if (inmaterials.size() > 1) {
{
DefaultLogger::get()->info("IRR: Skipping additional materials"); DefaultLogger::get()->info("IRR: Skipping additional materials");
} }
@ -307,24 +298,20 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
{ {
ai_assert(NULL != root && NULL != real); ai_assert(NULL != root && NULL != real);
if (root->animators.empty())return; if (root->animators.empty()) {
// const aiMatrix4x4& transform = real->mTransformation; return;
}
unsigned int total = 0; unsigned int total = 0;
for (std::list<Animator>::iterator it = root->animators.begin(); for (std::list<Animator>::iterator it = root->animators.begin();it != root->animators.end(); ++it) {
it != root->animators.end(); ++it) if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) {
{
if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER)
{
DefaultLogger::get()->warn("IRR: Skipping unknown or unsupported animator"); DefaultLogger::get()->warn("IRR: Skipping unknown or unsupported animator");
continue; continue;
} }
++total; ++total;
} }
if (!total)return; if (!total)return;
else if (1 == total) else if (1 == total) {
{ DefaultLogger::get()->warn("IRR: Adding dummy nodes to simulate multiple animators");
DefaultLogger::get()->warn("IRR: Generating dummy nodes to simulate multiple animators");
} }
// NOTE: 1 tick == i millisecond // NOTE: 1 tick == i millisecond
@ -338,8 +325,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
Animator& in = *it ; Animator& in = *it ;
aiNodeAnim* anim = new aiNodeAnim(); aiNodeAnim* anim = new aiNodeAnim();
if (cur != total-1) if (cur != total-1) {
{
// Build a new name - a prefix instead of a suffix because it is // Build a new name - a prefix instead of a suffix because it is
// easier to check against // easier to check against
anim->mNodeName.length = ::sprintf(anim->mNodeName.data, anim->mNodeName.length = ::sprintf(anim->mNodeName.data,
@ -367,8 +353,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
else anim->mNodeName.Set(root->name); else anim->mNodeName.Set(root->name);
++cur; ++cur;
switch (in.type) switch (in.type) {
{
case Animator::ROTATION: case Animator::ROTATION:
{ {
// ----------------------------------------------------- // -----------------------------------------------------
@ -463,8 +448,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
// from Irrlicht, what else should we do than copying it? // from Irrlicht, what else should we do than copying it?
aiVector3D vecU,vecV; aiVector3D vecU,vecV;
if (in.direction.y) if (in.direction.y) {
{
vecV = aiVector3D(50,0,0) ^ in.direction; vecV = aiVector3D(50,0,0) ^ in.direction;
} }
else vecV = aiVector3D(0,50,00) ^ in.direction; else vecV = aiVector3D(0,50,00) ^ in.direction;
@ -472,8 +456,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
vecU = (vecV ^ in.direction).Normalize(); vecU = (vecV ^ in.direction).Normalize();
// build the output keys // build the output keys
for (unsigned int i = 0; i < anim->mNumPositionKeys;++i) for (unsigned int i = 0; i < anim->mNumPositionKeys;++i) {
{
aiVectorKey& key = anim->mPositionKeys[i]; aiVectorKey& key = anim->mPositionKeys[i];
key.mTime = i * tdelta; key.mTime = i * tdelta;
@ -502,8 +485,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
const double timeFactor = lengthOfWay / in.timeForWay; const double timeFactor = lengthOfWay / in.timeForWay;
// build the output keys // build the output keys
for (unsigned int i = 0; i < anim->mNumPositionKeys;++i) for (unsigned int i = 0; i < anim->mNumPositionKeys;++i) {
{
aiVectorKey& key = anim->mPositionKeys[i]; aiVectorKey& key = anim->mPositionKeys[i];
key.mTime = i * tdelta; key.mTime = i * tdelta;
key.mValue = in.circleCenter + diff * float(timeFactor * key.mTime); key.mValue = in.circleCenter + diff * float(timeFactor * key.mTime);
@ -516,16 +498,14 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
// repeat outside the defined time range // repeat outside the defined time range
anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT; anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
const int size = (int)in.splineKeys.size(); const int size = (int)in.splineKeys.size();
if (!size) if (!size) {
{
// We have no point in the spline. That's bad. Really bad. // We have no point in the spline. That's bad. Really bad.
DefaultLogger::get()->warn("IRR: Spline animators with no points defined"); DefaultLogger::get()->warn("IRR: Spline animators with no points defined");
delete anim;anim = NULL; delete anim;anim = NULL;
break; break;
} }
else if (size == 1) else if (size == 1) {
{
// We have just one point in the spline so we don't need the full calculation // We have just one point in the spline so we don't need the full calculation
anim->mNumPositionKeys = 1; anim->mNumPositionKeys = 1;
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
@ -576,8 +556,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
} }
break; break;
}; };
if (anim) if (anim) {
{
anims.push_back(anim); anims.push_back(anim);
++total; ++total;
} }
@ -598,8 +577,7 @@ void SetupMapping (MaterialHelper* mat, aiTextureMapping mode, const aiVector3D&
for (unsigned int i = 0; i < mat->mNumProperties;++i) for (unsigned int i = 0; i < mat->mNumProperties;++i)
{ {
aiMaterialProperty* prop = mat->mProperties[i]; aiMaterialProperty* prop = mat->mProperties[i];
if (!::strcmp( prop->mKey.data, "$tex.file")) if (!::strcmp( prop->mKey.data, "$tex.file")) {
{
// Setup the mapping key // Setup the mapping key
aiMaterialProperty* m = new aiMaterialProperty(); aiMaterialProperty* m = new aiMaterialProperty();
m->mKey.Set("$tex.mapping"); m->mKey.Set("$tex.mapping");
@ -615,9 +593,7 @@ void SetupMapping (MaterialHelper* mat, aiTextureMapping mode, const aiVector3D&
p.push_back(m); p.push_back(m);
// Setup the mapping axis // Setup the mapping axis
if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || mode == aiTextureMapping_SPHERE) {
mode == aiTextureMapping_SPHERE)
{
m = new aiMaterialProperty(); m = new aiMaterialProperty();
m->mKey.Set("$tex.mapaxis"); m->mKey.Set("$tex.mapaxis");
m->mIndex = prop->mIndex; m->mIndex = prop->mIndex;
@ -674,63 +650,24 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// the list of all scenes to be attached to the // the list of all scenes to be attached to the
// graph we're currently building // graph we're currently building
aiScene* scene = batch.GetImport(root->id); aiScene* scene = batch.GetImport(root->id);
if (!scene) if (!scene) {
{ DefaultLogger::get()->error("IRR: Unable to load external file: " + root->meshPath);
DefaultLogger::get()->error("IRR: Unable to load external file: "
+ root->meshPath);
break; break;
} }
attach.push_back(AttachmentInfo(scene,rootOut)); attach.push_back(AttachmentInfo(scene,rootOut));
#if 0 /* currently unused */
meshTrafoAssign = 1;
// If the root node of the scene is animated - and *this* node
// is animated, too, we need to insert a dummy node into the
// hierarchy in order to avoid interferences with animations
for (unsigned int i = 0; i < scene->mNumAnimations;++i)
{
aiAnimation* anim = scene->mAnimations[i];
for (unsigned int a = 0; a < anim->mNumChannels;++a) {
if (scene->mRootNode->mName == anim->mChannels[a]->mNodeName) {
if (root->animators.empty()) {
meshTrafoAssign = 2;
}
else {
meshTrafoAssign = 3;
aiNode* dummy = new aiNode();
dummy->mName.Set("$CSpaceSeam$");
dummy->mNumChildren = 1;
dummy->mChildren = new aiNode*[1];
dummy->mChildren[0] = scene->mRootNode;
scene->mRootNode->mParent = dummy;
scene->mRootNode = dummy;
scene->mRootNode->mTransformation = AI_TO_IRR_MATRIX;
}
break;
}
}
}
#endif
// if (1 == meshTrafoAssign)
// scene->mRootNode->mTransformation = AI_TO_IRR_MATRIX * scene->mRootNode->mTransformation;
// Now combine the material we've loaded for this mesh // Now combine the material we've loaded for this mesh
// with the real materials we got from the file. As we // with the real materials we got from the file. As we
// don't execute any pp-steps on the file, the numbers // don't execute any pp-steps on the file, the numbers
// should be equal. If they are not, we can impossibly // should be equal. If they are not, we can impossibly
// do this ... // do this ...
if (root->materials.size() != (unsigned int)scene->mNumMaterials) if (root->materials.size() != (unsigned int)scene->mNumMaterials) {
{
DefaultLogger::get()->warn("IRR: Failed to match imported materials " DefaultLogger::get()->warn("IRR: Failed to match imported materials "
"with the materials found in the IRR scene file"); "with the materials found in the IRR scene file");
break; break;
} }
for (unsigned int i = 0; i < scene->mNumMaterials;++i) for (unsigned int i = 0; i < scene->mNumMaterials;++i) {
{
// Delete the old material, we don't need it anymore // Delete the old material, we don't need it anymore
delete scene->mMaterials[i]; delete scene->mMaterials[i];
@ -741,8 +678,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// NOTE: Each mesh should have exactly one material assigned, // NOTE: Each mesh should have exactly one material assigned,
// but we do it in a separate loop if this behaviour changes // but we do it in a separate loop if this behaviour changes
// in future. // in future.
for (unsigned int i = 0; i < scene->mNumMeshes;++i) for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
{
// Process material flags // Process material flags
aiMesh* mesh = scene->mMeshes[i]; aiMesh* mesh = scene->mMeshes[i];
@ -751,25 +687,21 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// and check whether they have a common alpha value. This is quite // and check whether they have a common alpha value. This is quite
// often the case so we can simply extract it to a shared oacity // often the case so we can simply extract it to a shared oacity
// value. // value.
std::pair<aiMaterial*, unsigned int>& src = root->materials[ std::pair<aiMaterial*, unsigned int>& src = root->materials[mesh->mMaterialIndex];
mesh->mMaterialIndex];
MaterialHelper* mat = (MaterialHelper*)src.first; MaterialHelper* mat = (MaterialHelper*)src.first;
if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha) if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha)
{ {
bool bdo = true; bool bdo = true;
for (unsigned int a = 1; a < mesh->mNumVertices;++a) for (unsigned int a = 1; a < mesh->mNumVertices;++a) {
{
if (mesh->mColors[0][a].a != mesh->mColors[0][a-1].a) if (mesh->mColors[0][a].a != mesh->mColors[0][a-1].a) {
{
bdo = false; bdo = false;
break; break;
} }
} }
if (bdo) if (bdo) {
{ DefaultLogger::get()->info("IRR: Replacing mesh vertex alpha with common opacity");
DefaultLogger::get()->info("IRR: Replacing mesh vertex "
"alpha with common opacity");
for (unsigned int a = 0; a < mesh->mNumVertices;++a) for (unsigned int a = 0; a < mesh->mNumVertices;++a)
mesh->mColors[0][a].a = 1.f; mesh->mColors[0][a].a = 1.f;
@ -782,8 +714,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// (either lightmap, normalmap, 2layered material) we need to // (either lightmap, normalmap, 2layered material) we need to
// setup the correct UV index for it. The texture can either // setup the correct UV index for it. The texture can either
// be diffuse (lightmap & 2layer) or a normal map (normal & parallax) // be diffuse (lightmap & 2layer) or a normal map (normal & parallax)
if (mesh->HasTextureCoords(1)) if (mesh->HasTextureCoords(1)) {
{
int idx = 1; int idx = 1;
if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) { if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) {
mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(0)); mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
@ -852,11 +784,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
case Node::SKYBOX: case Node::SKYBOX:
{ {
// A skybox is defined by six materials // A skybox is defined by six materials
if (root->materials.size() < 6) if (root->materials.size() < 6) {
{ DefaultLogger::get()->error("IRR: There should be six materials for a skybox");
DefaultLogger::get()->error("IRR: There should be six materials "
"for a skybox");
break; break;
} }
@ -888,8 +817,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// Check whether we added a mesh (or more than one ...). In this case // Check whether we added a mesh (or more than one ...). In this case
// we'll also need to attach it to the node // we'll also need to attach it to the node
if (oldMeshSize != (unsigned int) meshes.size()) if (oldMeshSize != (unsigned int) meshes.size()) {
{
rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize; rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize;
rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes]; rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes];
@ -904,7 +833,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// Now compute the final local transformation matrix of the // Now compute the final local transformation matrix of the
// node from the given translation, rotation and scaling values. // node from the given translation, rotation and scaling values.
// (the rotation is given in Euler angles, XYZ order) // (the rotation is given in Euler angles, XYZ order)
std::swap((float&)root->rotation.z,(float&)root->rotation.y); //std::swap((float&)root->rotation.z,(float&)root->rotation.y);
rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation) ); rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation) );
// apply scaling // apply scaling
@ -912,20 +841,17 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
mat.a1 *= root->scaling.x; mat.a1 *= root->scaling.x;
mat.b1 *= root->scaling.x; mat.b1 *= root->scaling.x;
mat.c1 *= root->scaling.x; mat.c1 *= root->scaling.x;
mat.a2 *= root->scaling.z; mat.a2 *= root->scaling.y;
mat.b2 *= root->scaling.z; mat.b2 *= root->scaling.y;
mat.c2 *= root->scaling.z; mat.c2 *= root->scaling.y;
mat.a3 *= root->scaling.y; mat.a3 *= root->scaling.z;
mat.b3 *= root->scaling.y; mat.b3 *= root->scaling.z;
mat.c3 *= root->scaling.y; mat.c3 *= root->scaling.z;
// apply translation // apply translation
mat.a4 += root->position.x; mat.a4 += root->position.x;
mat.b4 += root->position.z; mat.b4 += root->position.y;
mat.c4 += root->position.y; mat.c4 += root->position.z;
//if (meshTrafoAssign == 2)
// mat *= AI_TO_IRR_MATRIX;
// now compute animations for the node // now compute animations for the node
ComputeAnimations(root,rootOut, anims); ComputeAnimations(root,rootOut, anims);
@ -933,11 +859,11 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// Add all children recursively. First allocate enough storage // Add all children recursively. First allocate enough storage
// for them, then call us again // for them, then call us again
rootOut->mNumChildren = (unsigned int)root->children.size(); rootOut->mNumChildren = (unsigned int)root->children.size();
if (rootOut->mNumChildren) if (rootOut->mNumChildren) {
{
rootOut->mChildren = new aiNode*[rootOut->mNumChildren]; rootOut->mChildren = new aiNode*[rootOut->mNumChildren];
for (unsigned int i = 0; i < rootOut->mNumChildren;++i) for (unsigned int i = 0; i < rootOut->mNumChildren;++i) {
{
aiNode* node = rootOut->mChildren[i] = new aiNode(); aiNode* node = rootOut->mChildren[i] = new aiNode();
node->mParent = rootOut; node->mParent = rootOut;
GenerateGraph(root->children[i],node,scene,batch,meshes, GenerateGraph(root->children[i],node,scene,batch,meshes,
@ -989,14 +915,11 @@ void IRRImporter::InternReadFile( const std::string& pFile,
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0; unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
// Parse the XML file // Parse the XML file
while (reader->read()) while (reader->read()) {
{ switch (reader->getNodeType()) {
switch (reader->getNodeType())
{
case EXN_ELEMENT: case EXN_ELEMENT:
if (!ASSIMP_stricmp(reader->getNodeName(),"node")) if (!ASSIMP_stricmp(reader->getNodeName(),"node")) {
{
// *********************************************************************** // ***********************************************************************
/* What we're going to do with the node depends /* What we're going to do with the node depends
* on its type: * on its type:
@ -1019,24 +942,20 @@ void IRRImporter::InternReadFile( const std::string& pFile,
// *********************************************************************** // ***********************************************************************
const char* sz = reader->getAttributeValueSafe("type"); const char* sz = reader->getAttributeValueSafe("type");
Node* nd; Node* nd;
if (!ASSIMP_stricmp(sz,"mesh") || !ASSIMP_stricmp(sz,"octTree")) if (!ASSIMP_stricmp(sz,"mesh") || !ASSIMP_stricmp(sz,"octTree")) {
{
// OctTree's and meshes are treated equally // OctTree's and meshes are treated equally
nd = new Node(Node::MESH); nd = new Node(Node::MESH);
} }
else if (!ASSIMP_stricmp(sz,"cube")) else if (!ASSIMP_stricmp(sz,"cube")) {
{
nd = new Node(Node::CUBE); nd = new Node(Node::CUBE);
++guessedMeshCnt; ++guessedMeshCnt;
// meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron)); // meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron));
} }
else if (!ASSIMP_stricmp(sz,"skybox")) else if (!ASSIMP_stricmp(sz,"skybox")) {
{
nd = new Node(Node::SKYBOX); nd = new Node(Node::SKYBOX);
guessedMeshCnt += 6; guessedMeshCnt += 6;
} }
else if (!ASSIMP_stricmp(sz,"camera")) else if (!ASSIMP_stricmp(sz,"camera")) {
{
nd = new Node(Node::CAMERA); nd = new Node(Node::CAMERA);
// Setup a temporary name for the camera // Setup a temporary name for the camera
@ -1044,8 +963,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
cam->mName.Set( nd->name ); cam->mName.Set( nd->name );
cameras.push_back(cam); cameras.push_back(cam);
} }
else if (!ASSIMP_stricmp(sz,"light")) else if (!ASSIMP_stricmp(sz,"light")) {
{
nd = new Node(Node::LIGHT); nd = new Node(Node::LIGHT);
// Setup a temporary name for the light // Setup a temporary name for the light
@ -1053,31 +971,25 @@ void IRRImporter::InternReadFile( const std::string& pFile,
cam->mName.Set( nd->name ); cam->mName.Set( nd->name );
lights.push_back(cam); lights.push_back(cam);
} }
else if (!ASSIMP_stricmp(sz,"sphere")) else if (!ASSIMP_stricmp(sz,"sphere")) {
{
nd = new Node(Node::SPHERE); nd = new Node(Node::SPHERE);
++guessedMeshCnt; ++guessedMeshCnt;
} }
else if (!ASSIMP_stricmp(sz,"animatedMesh")) else if (!ASSIMP_stricmp(sz,"animatedMesh")) {
{
nd = new Node(Node::ANIMMESH); nd = new Node(Node::ANIMMESH);
} }
else if (!ASSIMP_stricmp(sz,"empty")) else if (!ASSIMP_stricmp(sz,"empty")) {
{
nd = new Node(Node::DUMMY); nd = new Node(Node::DUMMY);
} }
else if (!ASSIMP_stricmp(sz,"terrain")) else if (!ASSIMP_stricmp(sz,"terrain")) {
{
nd = new Node(Node::TERRAIN); nd = new Node(Node::TERRAIN);
} }
else if (!ASSIMP_stricmp(sz,"billBoard")) else if (!ASSIMP_stricmp(sz,"billBoard")) {
{
// We don't support billboards, so ignore them // We don't support billboards, so ignore them
DefaultLogger::get()->error("IRR: Billboards are not supported by Assimp"); DefaultLogger::get()->error("IRR: Billboards are not supported by Assimp");
nd = new Node(Node::DUMMY); nd = new Node(Node::DUMMY);
} }
else else {
{
DefaultLogger::get()->warn("IRR: Found unknown node: " + std::string(sz)); DefaultLogger::get()->warn("IRR: Found unknown node: " + std::string(sz));
/* We skip the contents of nodes we don't know. /* We skip the contents of nodes we don't know.
@ -1093,21 +1005,17 @@ void IRRImporter::InternReadFile( const std::string& pFile,
nd->parent = curParent; nd->parent = curParent;
curParent->children.push_back(nd); curParent->children.push_back(nd);
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) {
{
inMaterials = true; inMaterials = true;
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) {
{
inAnimator = true; inAnimator = true;
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes")) else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes")) {
{
/* We should have a valid node here /* We should have a valid node here
* FIX: no ... the scene root node is also contained in an attributes block * FIX: no ... the scene root node is also contained in an attributes block
*/ */
if (!curNode) if (!curNode) {
{
#if 0 #if 0
DefaultLogger::get()->error("IRR: Encountered <attributes> element, but " DefaultLogger::get()->error("IRR: Encountered <attributes> element, but "
"there is no node active"); "there is no node active");
@ -1118,8 +1026,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
Animator* curAnim = NULL; Animator* curAnim = NULL;
// Materials can occur for nearly any type of node // Materials can occur for nearly any type of node
if (inMaterials && curNode->type != Node::DUMMY) if (inMaterials && curNode->type != Node::DUMMY) {
{
/* This is a material description - parse it! /* This is a material description - parse it!
*/ */
curNode->materials.push_back(std::pair< aiMaterial*, unsigned int > () ); curNode->materials.push_back(std::pair< aiMaterial*, unsigned int > () );
@ -1130,8 +1037,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
++guessedMatCnt; ++guessedMatCnt;
continue; continue;
} }
else if (inAnimator) else if (inAnimator) {
{
/* This is an animation path - add a new animator /* This is an animation path - add a new animator
* to the list. * to the list.
*/ */
@ -1144,28 +1050,21 @@ void IRRImporter::InternReadFile( const std::string& pFile,
/* Parse all elements in the attributes block /* Parse all elements in the attributes block
* and process them. * and process them.
*/ */
while (reader->read()) while (reader->read()) {
{ if (reader->getNodeType() == EXN_ELEMENT) {
if (reader->getNodeType() == EXN_ELEMENT) if (!ASSIMP_stricmp(reader->getNodeName(),"vector3d")) {
{
if (!ASSIMP_stricmp(reader->getNodeName(),"vector3d"))
{
VectorProperty prop; VectorProperty prop;
ReadVectorProperty(prop); ReadVectorProperty(prop);
if (inAnimator) if (inAnimator) {
{ if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
if (curAnim->type == Animator::ROTATION && prop.name == "Rotation")
{
// We store the rotation euler angles in 'direction' // We store the rotation euler angles in 'direction'
curAnim->direction = prop.value; curAnim->direction = prop.value;
} }
else if (curAnim->type == Animator::FOLLOW_SPLINE) else if (curAnim->type == Animator::FOLLOW_SPLINE) {
{
// Check whether the vector follows the PointN naming scheme, // Check whether the vector follows the PointN naming scheme,
// here N is the ONE-based index of the point // here N is the ONE-based index of the point
if (prop.name.length() >= 6 && prop.name.substr(0,5) == "Point") if (prop.name.length() >= 6 && prop.name.substr(0,5) == "Point") {
{
// Add a new key to the list // Add a new key to the list
curAnim->splineKeys.push_back(aiVectorKey()); curAnim->splineKeys.push_back(aiVectorKey());
aiVectorKey& key = curAnim->splineKeys.back(); aiVectorKey& key = curAnim->splineKeys.back();
@ -1175,203 +1074,158 @@ void IRRImporter::InternReadFile( const std::string& pFile,
key.mTime = strtol10(&prop.name[5]); key.mTime = strtol10(&prop.name[5]);
} }
} }
else if (curAnim->type == Animator::FLY_CIRCLE) else if (curAnim->type == Animator::FLY_CIRCLE) {
{ if (prop.name == "Center") {
if (prop.name == "Center")
{
curAnim->circleCenter = prop.value; curAnim->circleCenter = prop.value;
} }
else if (prop.name == "Direction") else if (prop.name == "Direction") {
{
curAnim->direction = prop.value; curAnim->direction = prop.value;
// From Irrlicht source - a workaround for backward // From Irrlicht's source - a workaround for backward compatibility with Irrlicht 1.1
// compatibility with Irrlicht 1.1 if (curAnim->direction == aiVector3D()) {
if (curAnim->direction == aiVector3D())
{
curAnim->direction = aiVector3D(0.f,1.f,0.f); curAnim->direction = aiVector3D(0.f,1.f,0.f);
} }
else curAnim->direction.Normalize(); else curAnim->direction.Normalize();
} }
} }
else if (curAnim->type == Animator::FLY_STRAIGHT) else if (curAnim->type == Animator::FLY_STRAIGHT) {
{ if (prop.name == "Start") {
if (prop.name == "Start")
{
// We reuse the field here // We reuse the field here
curAnim->circleCenter = prop.value; curAnim->circleCenter = prop.value;
} }
else if (prop.name == "End") else if (prop.name == "End") {
{
// We reuse the field here // We reuse the field here
curAnim->direction = prop.value; curAnim->direction = prop.value;
} }
} }
} }
else else {
{ if (prop.name == "Position") {
if (prop.name == "Position")
{
curNode->position = prop.value; curNode->position = prop.value;
} }
else if (prop.name == "Rotation") else if (prop.name == "Rotation") {
{
curNode->rotation = prop.value; curNode->rotation = prop.value;
} }
else if (prop.name == "Scale") else if (prop.name == "Scale") {
{
curNode->scaling = prop.value; curNode->scaling = prop.value;
} }
else if (Node::CAMERA == curNode->type) else if (Node::CAMERA == curNode->type)
{ {
aiCamera* cam = cameras.back(); aiCamera* cam = cameras.back();
if (prop.name == "Target") if (prop.name == "Target") {
{
cam->mLookAt = prop.value; cam->mLookAt = prop.value;
} }
else if (prop.name == "UpVector") else if (prop.name == "UpVector") {
{
cam->mUp = prop.value; cam->mUp = prop.value;
} }
} }
} }
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"bool")) else if (!ASSIMP_stricmp(reader->getNodeName(),"bool")) {
{
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop);
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
{
curAnim->loop = prop.value; curAnim->loop = prop.value;
} }
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"float")) else if (!ASSIMP_stricmp(reader->getNodeName(),"float")) {
{
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop);
if (inAnimator) if (inAnimator) {
{
// The speed property exists for several animators // The speed property exists for several animators
if (prop.name == "Speed") if (prop.name == "Speed") {
{
curAnim->speed = prop.value; curAnim->speed = prop.value;
} }
else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") {
{
curAnim->circleRadius = prop.value; curAnim->circleRadius = prop.value;
} }
else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
{
curAnim->tightness = prop.value; curAnim->tightness = prop.value;
} }
} }
else else {
{ if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) {
if (prop.name == "FramesPerSecond" &&
Node::ANIMMESH == curNode->type)
{
curNode->framesPerSecond = prop.value; curNode->framesPerSecond = prop.value;
} }
else if (Node::CAMERA == curNode->type) else if (Node::CAMERA == curNode->type) {
{
/* This is the vertical, not the horizontal FOV. /* This is the vertical, not the horizontal FOV.
* We need to compute the right FOV from the * We need to compute the right FOV from the
* screen aspect which we don't know yet. * screen aspect which we don't know yet.
*/ */
if (prop.name == "Fovy") if (prop.name == "Fovy") {
{
cameras.back()->mHorizontalFOV = prop.value; cameras.back()->mHorizontalFOV = prop.value;
} }
else if (prop.name == "Aspect") else if (prop.name == "Aspect") {
{
cameras.back()->mAspect = prop.value; cameras.back()->mAspect = prop.value;
} }
else if (prop.name == "ZNear") else if (prop.name == "ZNear") {
{
cameras.back()->mClipPlaneNear = prop.value; cameras.back()->mClipPlaneNear = prop.value;
} }
else if (prop.name == "ZFar") else if (prop.name == "ZFar") {
{
cameras.back()->mClipPlaneFar = prop.value; cameras.back()->mClipPlaneFar = prop.value;
} }
} }
else if (Node::LIGHT == curNode->type) else if (Node::LIGHT == curNode->type) {
{
/* Additional light information /* Additional light information
*/ */
if (prop.name == "Attenuation") if (prop.name == "Attenuation") {
{
lights.back()->mAttenuationLinear = prop.value; lights.back()->mAttenuationLinear = prop.value;
} }
else if (prop.name == "OuterCone") else if (prop.name == "OuterCone") {
{
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD( prop.value ); lights.back()->mAngleOuterCone = AI_DEG_TO_RAD( prop.value );
} }
else if (prop.name == "InnerCone") else if (prop.name == "InnerCone") {
{
lights.back()->mAngleInnerCone = AI_DEG_TO_RAD( prop.value ); lights.back()->mAngleInnerCone = AI_DEG_TO_RAD( prop.value );
} }
} }
// radius of the sphere to be generated - // radius of the sphere to be generated -
// or alternatively, size of the cube // or alternatively, size of the cube
else if (Node::SPHERE == curNode->type && prop.name == "Radius" || else if (Node::SPHERE == curNode->type && prop.name == "Radius"
Node::CUBE == curNode->type && prop.name == "Size" ) || Node::CUBE == curNode->type && prop.name == "Size" ) {
{
curNode->sphereRadius = prop.value; curNode->sphereRadius = prop.value;
} }
} }
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"int")) else if (!ASSIMP_stricmp(reader->getNodeName(),"int")) {
{
IntProperty prop; IntProperty prop;
ReadIntProperty(prop); ReadIntProperty(prop);
if (inAnimator) if (inAnimator) {
{ if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay")
{
curAnim->timeForWay = prop.value; curAnim->timeForWay = prop.value;
} }
} }
else else {
{
// sphere polgon numbers in each direction // sphere polgon numbers in each direction
if (Node::SPHERE == curNode->type) if (Node::SPHERE == curNode->type) {
{
if (prop.name == "PolyCountX") if (prop.name == "PolyCountX") {
{
curNode->spherePolyCountX = prop.value; curNode->spherePolyCountX = prop.value;
} }
else if (prop.name == "PolyCountY") else if (prop.name == "PolyCountY") {
{
curNode->spherePolyCountY = prop.value; curNode->spherePolyCountY = prop.value;
} }
} }
} }
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"string") || else if (!ASSIMP_stricmp(reader->getNodeName(),"string") ||!ASSIMP_stricmp(reader->getNodeName(),"enum")) {
!ASSIMP_stricmp(reader->getNodeName(),"enum"))
{
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop);
if (prop.value.length()) if (prop.value.length()) {
{ if (prop.name == "Name") {
if (prop.name == "Name")
{
curNode->name = prop.value; curNode->name = prop.value;
/* If we're either a camera or a light source /* If we're either a camera or a light source
* we need to update the name in the aiLight/ * we need to update the name in the aiLight/
* aiCamera structure, too. * aiCamera structure, too.
*/ */
if (Node::CAMERA == curNode->type) if (Node::CAMERA == curNode->type) {
{
cameras.back()->mName.Set(prop.value); cameras.back()->mName.Set(prop.value);
} }
else if (Node::LIGHT == curNode->type) else if (Node::LIGHT == curNode->type) {
{
lights.back()->mName.Set(prop.value); lights.back()->mName.Set(prop.value);
} }
} }
@ -1404,10 +1258,9 @@ void IRRImporter::InternReadFile( const std::string& pFile,
unsigned int pp = 0; unsigned int pp = 0;
BatchLoader::PropertyMap map; BatchLoader::PropertyMap map;
/* If the mesh is a static one remove all animations /* If the mesh is a static one remove all animations from the impor data
*/ */
if (Node::ANIMMESH != curNode->type) if (Node::ANIMMESH != curNode->type) {
{
pp |= aiProcess_RemoveComponent; pp |= aiProcess_RemoveComponent;
SetGenericProperty<int>(map.ints,AI_CONFIG_PP_RVC_FLAGS, SetGenericProperty<int>(map.ints,AI_CONFIG_PP_RVC_FLAGS,
aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS); aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
@ -1419,51 +1272,33 @@ void IRRImporter::InternReadFile( const std::string& pFile,
* file referencing each other *could* cause the system to * file referencing each other *could* cause the system to
* recurse forever. * recurse forever.
*/ */
std::string::size_type pos = prop.value.find_last_of('.');
// no file extension - can't read, so we don't need to try it const std::string extension = GetExtension(prop.value);
if( pos == std::string::npos) if ("irr" == extension) {
{ DefaultLogger::get()->error("IRR: Can't load another IRR file recursively");
DefaultLogger::get()->error("IRR: Can't load files without a file extension");
} }
else else
{ {
std::string extension = prop.value.substr( pos); curNode->id = batch.AddLoadRequest(prop.value,pp,&map);
for (std::string::iterator i = extension.begin(); i != extension.end();++i) curNode->meshPath = prop.value;
*i = ::tolower(*i);
if (".irr" == prop.value)
{
DefaultLogger::get()->error("IRR: Can't load another IRR file recursively");
}
else
{
curNode->id = batch.AddLoadRequest(prop.value,pp,&map);
curNode->meshPath = prop.value;
}
} }
} }
else if (inAnimator && prop.name == "Type") else if (inAnimator && prop.name == "Type")
{ {
// type of the animator // type of the animator
if (prop.value == "rotation") if (prop.value == "rotation") {
{
curAnim->type = Animator::ROTATION; curAnim->type = Animator::ROTATION;
} }
else if (prop.value == "flyCircle") else if (prop.value == "flyCircle") {
{
curAnim->type = Animator::FLY_CIRCLE; curAnim->type = Animator::FLY_CIRCLE;
} }
else if (prop.value == "flyStraight") else if (prop.value == "flyStraight") {
{
curAnim->type = Animator::FLY_CIRCLE; curAnim->type = Animator::FLY_CIRCLE;
} }
else if (prop.value == "followSpline") else if (prop.value == "followSpline") {
{
curAnim->type = Animator::FOLLOW_SPLINE; curAnim->type = Animator::FOLLOW_SPLINE;
} }
else else {
{
DefaultLogger::get()->warn("IRR: Ignoring unknown animator: " DefaultLogger::get()->warn("IRR: Ignoring unknown animator: "
+ prop.value); + prop.value);
@ -1473,9 +1308,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
} }
} }
} }
else if (reader->getNodeType() == EXN_ELEMENT_END && else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),"attributes")) {
!ASSIMP_stricmp(reader->getNodeName(),"attributes"))
{
break; break;
} }
} }
@ -1485,14 +1318,11 @@ void IRRImporter::InternReadFile( const std::string& pFile,
case EXN_ELEMENT_END: case EXN_ELEMENT_END:
// If we reached the end of a node, we need to continue processing its parent // If we reached the end of a node, we need to continue processing its parent
if (!ASSIMP_stricmp(reader->getNodeName(),"node")) if (!ASSIMP_stricmp(reader->getNodeName(),"node")) {
{ if (!curNode) {
if (!curNode)
{
// currently is no node set. We need to go // currently is no node set. We need to go
// back in the node hierarchy // back in the node hierarchy
if (!curParent) if (!curParent) {
{
curParent = root; curParent = root;
DefaultLogger::get()->error("IRR: Too many closing <node> elements"); DefaultLogger::get()->error("IRR: Too many closing <node> elements");
} }
@ -1501,12 +1331,10 @@ void IRRImporter::InternReadFile( const std::string& pFile,
else curNode = NULL; else curNode = NULL;
} }
// clear all flags // clear all flags
else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) {
{
inMaterials = false; inMaterials = false;
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) {
{
inAnimator = false; inAnimator = false;
} }
break; break;
@ -1519,11 +1347,11 @@ void IRRImporter::InternReadFile( const std::string& pFile,
/* Now iterate through all cameras and compute their final (horizontal) FOV /* Now iterate through all cameras and compute their final (horizontal) FOV
*/ */
for (std::vector<aiCamera*>::iterator it = cameras.begin(), end = cameras.end(); for (std::vector<aiCamera*>::iterator it = cameras.begin(), end = cameras.end();it != end; ++it) {
it != end; ++it) {
aiCamera* cam = *it; aiCamera* cam = *it;
if (cam->mAspect) // screen aspect could be missing
{ // screen aspect could be missing
if (cam->mAspect) {
cam->mHorizontalFOV *= cam->mAspect; cam->mHorizontalFOV *= cam->mAspect;
} }
else DefaultLogger::get()->warn("IRR: Camera aspect is not given, can't compute horizontal FOV"); else DefaultLogger::get()->warn("IRR: Camera aspect is not given, can't compute horizontal FOV");
@ -1539,8 +1367,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
/* Copy the cameras to the output array /* Copy the cameras to the output array
*/ */
if (!cameras.empty()) if (!cameras.empty()) {
{
tempScene->mNumCameras = (unsigned int)cameras.size(); tempScene->mNumCameras = (unsigned int)cameras.size();
tempScene->mCameras = new aiCamera*[tempScene->mNumCameras]; tempScene->mCameras = new aiCamera*[tempScene->mNumCameras];
::memcpy(tempScene->mCameras,&cameras[0],sizeof(void*)*tempScene->mNumCameras); ::memcpy(tempScene->mCameras,&cameras[0],sizeof(void*)*tempScene->mNumCameras);
@ -1548,8 +1375,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
/* Copy the light sources to the output array /* Copy the light sources to the output array
*/ */
if (!lights.empty()) if (!lights.empty()) {
{
tempScene->mNumLights = (unsigned int)lights.size(); tempScene->mNumLights = (unsigned int)lights.size();
tempScene->mLights = new aiLight*[tempScene->mNumLights]; tempScene->mLights = new aiLight*[tempScene->mNumLights];
::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights); ::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights);
@ -1593,8 +1419,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
an->mChannels = new aiNodeAnim*[an->mNumChannels]; an->mChannels = new aiNodeAnim*[an->mNumChannels];
::memcpy(an->mChannels, & anims [0], sizeof(void*)*an->mNumChannels); ::memcpy(an->mChannels, & anims [0], sizeof(void*)*an->mNumChannels);
} }
if (!meshes.empty()) if (!meshes.empty()) {
{
// copy all meshes to the temporary scene // copy all meshes to the temporary scene
tempScene->mNumMeshes = (unsigned int)meshes.size(); tempScene->mNumMeshes = (unsigned int)meshes.size();
tempScene->mMeshes = new aiMesh*[tempScene->mNumMeshes]; tempScene->mMeshes = new aiMesh*[tempScene->mNumMeshes];
@ -1604,8 +1429,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
/* Copy all materials to the output array /* Copy all materials to the output array
*/ */
if (!materials.empty()) if (!materials.empty()) {
{
tempScene->mNumMaterials = (unsigned int)materials.size(); tempScene->mNumMaterials = (unsigned int)materials.size();
tempScene->mMaterials = new aiMaterial*[tempScene->mNumMaterials]; tempScene->mMaterials = new aiMaterial*[tempScene->mNumMaterials];
::memcpy(tempScene->mMaterials,&materials[0],sizeof(void*)* ::memcpy(tempScene->mMaterials,&materials[0],sizeof(void*)*
@ -1624,8 +1448,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
* scene flag. This is necessary if we failed to load all * scene flag. This is necessary if we failed to load all
* models from external files * models from external files
*/ */
if (!pScene->mNumMeshes || !pScene->mNumMaterials) if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
{
DefaultLogger::get()->warn("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE"); DefaultLogger::get()->warn("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }

View File

@ -54,16 +54,12 @@ using namespace irr::io;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
IRRMeshImporter::IRRMeshImporter() IRRMeshImporter::IRRMeshImporter()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
IRRMeshImporter::~IRRMeshImporter() IRRMeshImporter::~IRRMeshImporter()
{ {}
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
@ -134,23 +130,18 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
bool useColors = false; bool useColors = false;
// Parse the XML file // Parse the XML file
while (reader->read()) while (reader->read()) {
{ switch (reader->getNodeType()) {
switch (reader->getNodeType())
{
case EXN_ELEMENT: case EXN_ELEMENT:
if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) {
{
// end of previous buffer. A material and a mesh should be there // end of previous buffer. A material and a mesh should be there
if ( !curMat || !curMesh) if ( !curMat || !curMesh) {
{
DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material"); DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material");
delete curMat; delete curMat;
delete curMesh; delete curMesh;
} }
else else {
{
materials.push_back(curMat); materials.push_back(curMat);
meshes.push_back(curMesh); meshes.push_back(curMesh);
} }
@ -167,10 +158,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
} }
if (!ASSIMP_stricmp(reader->getNodeName(),"material")) if (!ASSIMP_stricmp(reader->getNodeName(),"material")) {
{ if (curMat) {
if (curMat)
{
DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please"); DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please");
delete curMat;curMat = NULL; delete curMat;curMat = NULL;
} }
@ -180,11 +169,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
{ {
int num = reader->getAttributeValueAsInt("vertexCount"); int num = reader->getAttributeValueAsInt("vertexCount");
if (!num) if (!num) {
{ // This is possible ... remove the mesh from the list and skip further reading
// This is possible ... remove the mesh from the list
// and skip further reading
DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices"); DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices");
delete curMat;curMat = NULL; delete curMat;curMat = NULL;
@ -201,13 +187,11 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
// Determine the file format // Determine the file format
const char* t = reader->getAttributeValueSafe("type"); const char* t = reader->getAttributeValueSafe("type");
if (!ASSIMP_stricmp("2tcoords", t)) if (!ASSIMP_stricmp("2tcoords", t)) {
{
curUV2s.reserve (num); curUV2s.reserve (num);
vertexFormat = 1; vertexFormat = 1;
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
{
// ********************************************************* // *********************************************************
// We have a second texture! So use this UV channel // We have a second texture! So use this UV channel
// for it. The 2nd texture can be either a normal // for it. The 2nd texture can be either a normal
@ -228,24 +212,20 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
} }
} }
} }
else if (!ASSIMP_stricmp("tangents", t)) else if (!ASSIMP_stricmp("tangents", t)) {
{
curTangents.reserve (num); curTangents.reserve (num);
curBitangents.reserve (num); curBitangents.reserve (num);
vertexFormat = 2; vertexFormat = 2;
} }
else if (ASSIMP_stricmp("standard", t)) else if (ASSIMP_stricmp("standard", t)) {
{
delete curMat; delete curMat;
DefaultLogger::get()->warn("IRRMESH: Unknown vertex format"); DefaultLogger::get()->warn("IRRMESH: Unknown vertex format");
} }
else vertexFormat = 0; else vertexFormat = 0;
textMeaning = 1; textMeaning = 1;
} }
else if (!ASSIMP_stricmp(reader->getNodeName(),"indices")) else if (!ASSIMP_stricmp(reader->getNodeName(),"indices")) {
{ if (curVertices.empty() && curMat) {
if (curVertices.empty() && curMat)
{
delete curMat; delete curMat;
throw new ImportErrorException("IRRMESH: indices must come after vertices"); throw new ImportErrorException("IRRMESH: indices must come after vertices");
} }
@ -257,11 +237,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
// allocate storage for all faces // allocate storage for all faces
curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount"); curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount");
if (!curMesh->mNumVertices) if (!curMesh->mNumVertices) {
{ // This is possible ... remove the mesh from the list and skip further reading
// This is possible ... remove the mesh from the list
// and skip further reading
DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices"); DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices");
// mesh - away // mesh - away
@ -274,8 +251,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
continue; continue;
} }
if (curMesh->mNumVertices % 3) if (curMesh->mNumVertices % 3) {
{
DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3"); DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3");
} }
@ -289,28 +265,22 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
// allocate storage for all vertices // allocate storage for all vertices
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices]; curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
if (curNormals.size() == curVertices.size()) if (curNormals.size() == curVertices.size()) {
{
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices]; curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
} }
if (curTangents.size() == curVertices.size()) if (curTangents.size() == curVertices.size()) {
{
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices]; curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
} }
if (curBitangents.size() == curVertices.size()) if (curBitangents.size() == curVertices.size()) {
{
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices]; curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
} }
if (curColors.size() == curVertices.size() && useColors) if (curColors.size() == curVertices.size() && useColors) {
{
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices]; curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
} }
if (curUVs.size() == curVertices.size()) if (curUVs.size() == curVertices.size()) {
{
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices]; curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
} }
if (curUV2s.size() == curVertices.size()) if (curUV2s.size() == curVertices.size()) {
{
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices]; curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
} }
} }
@ -319,13 +289,11 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
case EXN_TEXT: case EXN_TEXT:
{ {
const char* sz = reader->getNodeData(); const char* sz = reader->getNodeData();
if (textMeaning == 1) if (textMeaning == 1) {
{
textMeaning = 0; textMeaning = 0;
// read vertices // read vertices
do do {
{
SkipSpacesAndLineEnd(&sz); SkipSpacesAndLineEnd(&sz);
aiVector3D temp;aiColor4D c; aiVector3D temp;aiColor4D c;
@ -373,8 +341,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curUVs.push_back(temp); curUVs.push_back(temp);
// read the (optional) second UV coordinate set // read the (optional) second UV coordinate set
if (vertexFormat == 1) if (vertexFormat == 1) {
{
sz = fast_atof_move(sz,(float&)temp.x); sz = fast_atof_move(sz,(float&)temp.x);
SkipSpaces(&sz); SkipSpaces(&sz);
@ -383,8 +350,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curUV2s.push_back(temp); curUV2s.push_back(temp);
} }
// read optional tangent and bitangent vectors // read optional tangent and bitangent vectors
else if (vertexFormat == 2) else if (vertexFormat == 2) {
{
// tangents // tangents
sz = fast_atof_move(sz,(float&)temp.x); sz = fast_atof_move(sz,(float&)temp.x);
SkipSpaces(&sz); SkipSpaces(&sz);
@ -418,8 +384,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
while (SkipLine(&sz)); while (SkipLine(&sz));
} }
else if (textMeaning == 2) else if (textMeaning == 2) {
{
textMeaning = 0; textMeaning = 0;
// read indices // read indices
@ -436,22 +401,18 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
unsigned int curIdx = 0; unsigned int curIdx = 0;
unsigned int total = 0; unsigned int total = 0;
while(SkipSpacesAndLineEnd(&sz)) while(SkipSpacesAndLineEnd(&sz)) {
{ if (curFace >= faceEnd) {
if (curFace >= faceEnd)
{
DefaultLogger::get()->error("IRRMESH: Too many indices"); DefaultLogger::get()->error("IRRMESH: Too many indices");
break; break;
} }
if (!curIdx) if (!curIdx) {
{
curFace->mNumIndices = 3; curFace->mNumIndices = 3;
curFace->mIndices = new unsigned int[3]; curFace->mIndices = new unsigned int[3];
} }
unsigned int idx = strtol10(sz,&sz); unsigned int idx = strtol10(sz,&sz);
if (idx >= curVertices.size()) if (idx >= curVertices.size()) {
{
DefaultLogger::get()->error("IRRMESH: Index out of range"); DefaultLogger::get()->error("IRRMESH: Index out of range");
idx = 0; idx = 0;
} }
@ -466,8 +427,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
if (pcT0)*pcT0++ = curUVs[idx]; if (pcT0)*pcT0++ = curUVs[idx];
if (pcT1)*pcT1++ = curUV2s[idx]; if (pcT1)*pcT1++ = curUV2s[idx];
if (++curIdx == 3) if (++curIdx == 3) {
{
++curFace; ++curFace;
curIdx = 0; curIdx = 0;
} }
@ -477,8 +437,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
DefaultLogger::get()->error("IRRMESH: Not enough indices"); DefaultLogger::get()->error("IRRMESH: Not enough indices");
// Finish processing the mesh - do some small material workarounds // Finish processing the mesh - do some small material workarounds
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
{
// Take the opacity value of the current material // Take the opacity value of the current material
// from the common vertex color alpha // from the common vertex color alpha
MaterialHelper* mat = (MaterialHelper*)curMat; MaterialHelper* mat = (MaterialHelper*)curMat;
@ -496,16 +455,13 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
} }
// End of the last buffer. A material and a mesh should be there // End of the last buffer. A material and a mesh should be there
if (curMat || curMesh) if (curMat || curMesh) {
{ if ( !curMat || !curMesh) {
if ( !curMat || !curMesh)
{
DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material"); DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material");
delete curMat; delete curMat;
delete curMesh; delete curMesh;
} }
else else {
{
materials.push_back(curMat); materials.push_back(curMat);
meshes.push_back(curMesh); meshes.push_back(curMesh);
} }
@ -518,8 +474,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
// now generate the output scene // now generate the output scene
pScene->mNumMeshes = (unsigned int)meshes.size(); pScene->mNumMeshes = (unsigned int)meshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
{
pScene->mMeshes[i] = meshes[i]; pScene->mMeshes[i] = meshes[i];
// clean this value ... // clean this value ...
@ -538,9 +493,6 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mRootNode->mMeshes[i] = i; pScene->mRootNode->mMeshes[i] = i;
// transformation matrix to convert from IRRMESH to ASSIMP coordinates
pScene->mRootNode->mTransformation *= AI_TO_IRR_MATRIX;
// clean up and return // clean up and return
delete reader; delete reader;
AI_DEBUG_INVALIDATE_PTR(reader); AI_DEBUG_INVALIDATE_PTR(reader);

View File

@ -167,7 +167,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_BUILD_NO_JOINVERTICES_PROCESS #ifndef AI_BUILD_NO_JOINVERTICES_PROCESS
# include "JoinVerticesProcess.h" # include "JoinVerticesProcess.h"
#endif #endif
#ifndef AI_BUILD_NO_CONVERTTOLH_PROCESS #if !(defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS && defined AI_BUILD_NO_FLIPUVS_PROCESS && defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS)
# include "ConvertToLHProcess.h" # include "ConvertToLHProcess.h"
#endif #endif
#ifndef AI_BUILD_NO_TRIANGULATE_PROCESS #ifndef AI_BUILD_NO_TRIANGULATE_PROCESS
@ -436,8 +436,14 @@ Importer::Importer()
#if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS) #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS)
mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex()); mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex());
#endif #endif
#if (!defined AI_BUILD_NO_CONVERTTOLH_PROCESS) #if (!defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS)
mPostProcessingSteps.push_back( new ConvertToLHProcess()); mPostProcessingSteps.push_back( new MakeLeftHandedProcess());
#endif
#if (!defined AI_BUILD_NO_FLIPUVS_PROCESS)
mPostProcessingSteps.push_back( new FlipUVsProcess());
#endif
#if (!defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS)
mPostProcessingSteps.push_back( new FlipWindingOrderProcess());
#endif #endif
#if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS) #if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
mPostProcessingSteps.push_back( new LimitBoneWeightsProcess()); mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());

View File

@ -549,7 +549,7 @@ void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0
for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
aiQuatKey& qk = anim->mRotationKeys[i]; aiQuatKey& qk = anim->mRotationKeys[i];
qk.mTime = keys[i].mTime; qk.mTime = keys[i].mTime;
qk.mValue = aiQuaternion( keys[i].mValue.x ,keys[i].mValue.y ,keys[i].mValue.z ); qk.mValue = aiQuaternion( keys[i].mValue.x ,keys[i].mValue.z ,keys[i].mValue.y );
} }
} }

View File

@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SGSpatialSort.h" #include "SGSpatialSort.h"
#include "ByteSwap.h" #include "ByteSwap.h"
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include "ConvertToLHProcess.h"
using namespace Assimp; using namespace Assimp;
@ -314,24 +315,20 @@ void LWOImporter::InternReadFile( const std::string& pFile,
// now convert all faces // now convert all faces
unsigned int vert = 0; unsigned int vert = 0;
std::vector<unsigned int>::iterator outIt = smoothingGroups.begin(); std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
for (it = sorted.begin(); it != end;++it,++outIt) for (it = sorted.begin(); it != end;++it,++outIt) {
{
const LWO::Face& face = layer.mFaces[*it]; const LWO::Face& face = layer.mFaces[*it];
*outIt = face.smoothGroup; *outIt = face.smoothGroup;
// copy all vertices // copy all vertices
for (unsigned int q = 0; q < face.mNumIndices;++q) for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) {
{
register unsigned int idx = face.mIndices[q]; register unsigned int idx = face.mIndices[q];
*pv = layer.mTempPoints[idx] + layer.mPivot; *pv = layer.mTempPoints[idx] + layer.mPivot;
pv->z *= -1.0f; // DX to OGL
//std::swap(pv->z,pv->y);
pv++; pv++;
// process UV coordinates // process UV coordinates
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) {
{ if (0xffffffff == vUVChannelIndices[w])
if (0xffffffff == vUVChannelIndices[w])break; break;
aiVector3D*& pp = pvUV[w]; aiVector3D*& pp = pvUV[w];
const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx]; const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
pp->x = src.x; pp->x = src.x;
@ -345,9 +342,9 @@ void LWOImporter::InternReadFile( const std::string& pFile,
} }
// process vertex colors // process vertex colors
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) {
{ if (0xffffffff == vVColorIndices[w])
if (0xffffffff == vVColorIndices[w])break; break;
*pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx]; *pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
// If a RGB color map is explicitly requested delete the // If a RGB color map is explicitly requested delete the
@ -364,10 +361,8 @@ void LWOImporter::InternReadFile( const std::string& pFile,
{ {
} }
#endif #endif
face.mIndices[q] = vert + (face.mNumIndices-q-1); face.mIndices[q] = vert;
} }
vert += face.mNumIndices;
pf->mIndices = face.mIndices; pf->mIndices = face.mIndices;
pf->mNumIndices = face.mNumIndices; pf->mNumIndices = face.mNumIndices;
unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted
@ -568,8 +563,7 @@ void LWOImporter::GenerateNodeGraph(std::vector<aiNode*>& apcNodes)
for (unsigned int i = 0; i < apcNodes.size();++i) for (unsigned int i = 0; i < apcNodes.size();++i)
if (apcNodes[i] && apcNodes[i]->mNumMeshes)++extra; if (apcNodes[i] && apcNodes[i]->mNumMeshes)++extra;
if (extra) if (extra) {
{
// we need to add extra nodes to the root // we need to add extra nodes to the root
const unsigned int newSize = extra + pScene->mRootNode->mNumChildren; const unsigned int newSize = extra + pScene->mRootNode->mNumChildren;
aiNode** const apcNewNodes = new aiNode*[newSize]; aiNode** const apcNewNodes = new aiNode*[newSize];
@ -596,15 +590,17 @@ void LWOImporter::GenerateNodeGraph(std::vector<aiNode*>& apcNodes)
if (!pScene->mRootNode->mNumChildren) if (!pScene->mRootNode->mNumChildren)
throw new ImportErrorException("LWO: Unable to build a valid node graph"); throw new ImportErrorException("LWO: Unable to build a valid node graph");
// remove a single root node // Remove a single root node with no meshes assigned ...
// TODO: implement directly in the above loop, no need to deallocate here if (1 == pScene->mRootNode->mNumChildren) {
if (1 == pScene->mRootNode->mNumChildren)
{
aiNode* pc = pScene->mRootNode->mChildren[0]; aiNode* pc = pScene->mRootNode->mChildren[0];
pc->mParent = pScene->mRootNode->mChildren[0] = NULL; pc->mParent = pScene->mRootNode->mChildren[0] = NULL;
delete pScene->mRootNode; delete pScene->mRootNode;
pScene->mRootNode = pc; pScene->mRootNode = pc;
} }
// convert the whole stuff to RH
MakeLeftHandedProcess maker;
maker.Execute(pScene);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -136,12 +136,10 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a
break; break;
}; };
if (mapping != aiTextureMapping_UV) if (mapping != aiTextureMapping_UV) {
{
// Setup the main axis // Setup the main axis
aiVector3D v; aiVector3D v;
switch ((*it).majorAxis) switch ((*it).majorAxis) {
{
case Texture::AXIS_X: case Texture::AXIS_X:
v = aiVector3D(1.f,0.f,0.f); v = aiVector3D(1.f,0.f,0.f);
break; break;
@ -156,8 +154,7 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a
pcMat->AddProperty(&v,1,AI_MATKEY_TEXMAP_AXIS(type,cur)); pcMat->AddProperty(&v,1,AI_MATKEY_TEXMAP_AXIS(type,cur));
// Setup UV scalings for cylindric and spherical projections // Setup UV scalings for cylindric and spherical projections
if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) {
{
aiUVTransform trafo; aiUVTransform trafo;
trafo.mScaling.x = (*it).wrapAmountW; trafo.mScaling.x = (*it).wrapAmountW;
trafo.mScaling.y = (*it).wrapAmountH; trafo.mScaling.y = (*it).wrapAmountH;

View File

@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SceneCombiner.h" #include "SceneCombiner.h"
#include "GenericProperty.h" #include "GenericProperty.h"
#include "SkeletonMeshBuilder.h" #include "SkeletonMeshBuilder.h"
#include "ConvertToLHProcess.h"
using namespace Assimp; using namespace Assimp;
@ -858,6 +859,10 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
std::copy(anims.begin(),anims.end(),anim->mChannels); std::copy(anims.begin(),anims.end(),anim->mChannels);
} }
// convert the master scene to RH
MakeLeftHandedProcess monster_cheat;
monster_cheat.Execute(master);
// OK ... finally build the output graph // OK ... finally build the output graph
SceneCombiner::MergeScenes(&pScene,master,attach, SceneCombiner::MergeScenes(&pScene,master,attach,
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
@ -872,4 +877,5 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
SkeletonMeshBuilder builder(pScene); SkeletonMeshBuilder builder(pScene);
} }
} }
} }

View File

@ -144,7 +144,11 @@ void MD5Importer::InternReadFile( const std::string& pFile,
// make sure we have at least one file // make sure we have at least one file
if (!bHadMD5Mesh && !bHadMD5Anim && !bHadMD5Camera) if (!bHadMD5Mesh && !bHadMD5Anim && !bHadMD5Camera)
throw new ImportErrorException("Failed to read valid contents from this MD5 data set"); throw new ImportErrorException("Failed to read valid contents from this MD5* file");
// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
// the output scene wouldn't pass the validation without this flag // the output scene wouldn't pass the validation without this flag
if (!bHadMD5Mesh) if (!bHadMD5Mesh)
@ -156,7 +160,6 @@ void MD5Importer::InternReadFile( const std::string& pFile,
void MD5Importer::LoadFileIntoMemory (IOStream* file) void MD5Importer::LoadFileIntoMemory (IOStream* file)
{ {
ai_assert(NULL != file); ai_assert(NULL != file);
fileSize = (unsigned int)file->FileSize(); fileSize = (unsigned int)file->FileSize();
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer
@ -211,6 +214,8 @@ void MD5Importer::MakeDataUnique (MD5::MeshDesc& meshSrc)
} }
else abHad[face.mIndices[i]] = true; else abHad[face.mIndices[i]] = true;
} }
// swap face order
std::swap(face.mIndices[0],face.mIndices[2]);
} }
} }
@ -443,8 +448,7 @@ void MD5Importer::LoadMD5MeshFile ()
} }
// process bone weights // process bone weights
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w) for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w) {
{
if (w >= meshSrc.mWeights.size()) if (w >= meshSrc.mWeights.size())
throw new ImportErrorException("MD5MESH: Invalid weight index"); throw new ImportErrorException("MD5MESH: Invalid weight index");
@ -478,8 +482,7 @@ void MD5Importer::LoadMD5MeshFile ()
// (however, take care that the aiFace destructor doesn't delete the mIndices array) // (however, take care that the aiFace destructor doesn't delete the mIndices array)
mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size(); mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size();
mesh->mFaces = new aiFace[mesh->mNumFaces]; mesh->mFaces = new aiFace[mesh->mNumFaces];
for (unsigned int c = 0; c < mesh->mNumFaces;++c) for (unsigned int c = 0; c < mesh->mNumFaces;++c) {
{
mesh->mFaces[c].mNumIndices = 3; mesh->mFaces[c].mNumIndices = 3;
mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices; mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices;
meshSrc.mFaces[c].mIndices = NULL; meshSrc.mFaces[c].mIndices = NULL;
@ -621,6 +624,7 @@ void MD5Importer::LoadMD5AnimFile ()
if (!pScene->mRootNode) { if (!pScene->mRootNode) {
pScene->mRootNode = new aiNode(); pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("<MD5_Hierarchy>"); pScene->mRootNode->mName.Set("<MD5_Hierarchy>");
AttachChilds_Anim(-1,pScene->mRootNode,animParser.mAnimatedBones,(const aiNodeAnim**)anim->mChannels); AttachChilds_Anim(-1,pScene->mRootNode,animParser.mAnimatedBones,(const aiNodeAnim**)anim->mChannels);
// Call SkeletonMeshBuilder to construct a mesh to represent the shape // Call SkeletonMeshBuilder to construct a mesh to represent the shape
@ -659,14 +663,17 @@ void MD5Importer::LoadMD5CameraFile ()
std::vector<unsigned int>& cuts = cameraParser.cuts; std::vector<unsigned int>& cuts = cameraParser.cuts;
std::vector<MD5::CameraAnimFrameDesc>& frames = cameraParser.frames; std::vector<MD5::CameraAnimFrameDesc>& frames = cameraParser.frames;
// Construct output graph - a simple dummy node // Construct output graph - a simple root with a dummy child.
aiNode* root = pScene->mRootNode = new aiNode(); // The root node performs the coordinate system conversion
root->mName.Set("<MD5Camera>"); aiNode* root = pScene->mRootNode = new aiNode("<MD5CameraRoot>");
root->mChildren = new aiNode*[root->mNumChildren = 1];
root->mChildren[0] = new aiNode("<MD5Camera>");
root->mChildren[0]->mParent = root;
// ... but with one camera assigned to it // ... but with one camera assigned to it
pScene->mCameras = new aiCamera*[pScene->mNumCameras = 1]; pScene->mCameras = new aiCamera*[pScene->mNumCameras = 1];
aiCamera* cam = pScene->mCameras[0] = new aiCamera(); aiCamera* cam = pScene->mCameras[0] = new aiCamera();
cam->mName = root->mName; cam->mName = "<MD5Camera>";
// FIXME: Fov is currently set to the first frame's value // FIXME: Fov is currently set to the first frame's value
cam->mHorizontalFOV = AI_DEG_TO_RAD( frames.front().fFOV ); cam->mHorizontalFOV = AI_DEG_TO_RAD( frames.front().fFOV );

File diff suppressed because it is too large Load Diff

View File

@ -338,23 +338,18 @@ void PLYImporter::ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
{ {
bool bNeedDefaultMat = false; bool bNeedDefaultMat = false;
for (std::vector<PLY::Face>::iterator for (std::vector<PLY::Face>::iterator i = avFaces->begin();i != avFaces->end();++i) {
i = avFaces->begin();i != avFaces->end();++i) if (0xFFFFFFFF == (*i).iMaterialIndex) {
{
if (0xFFFFFFFF == (*i).iMaterialIndex)
{
bNeedDefaultMat = true; bNeedDefaultMat = true;
(*i).iMaterialIndex = (unsigned int)avMaterials->size(); (*i).iMaterialIndex = (unsigned int)avMaterials->size();
} }
else if ((*i).iMaterialIndex >= avMaterials->size() ) else if ((*i).iMaterialIndex >= avMaterials->size() ) {
{
// clamp the index // clamp the index
(*i).iMaterialIndex = (unsigned int)avMaterials->size()-1; (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1;
} }
} }
if (bNeedDefaultMat) if (bNeedDefaultMat) {
{
// generate a default material // generate a default material
MaterialHelper* pcHelper = new MaterialHelper(); MaterialHelper* pcHelper = new MaterialHelper();
@ -370,6 +365,11 @@ void PLYImporter::ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
clr.b = clr.g = clr.r = 0.05f; clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT); pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
// The face order is absolutely undefined for PLY, so we have to
// use two-sided rendering to be sure it's ok.
const int two_sided = 1;
pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
avMaterials->push_back(pcHelper); avMaterials->push_back(pcHelper);
} }
} }
@ -997,11 +997,8 @@ void PLYImporter::LoadMaterial(std::vector<MaterialHelper*>* pvOut)
} }
} }
// check whether we have a valid source for the material data // check whether we have a valid source for the material data
if (NULL != pcList) if (NULL != pcList) {
{ for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
i != pcList->alInstances.end();++i)
{
aiColor4D clrOut; aiColor4D clrOut;
MaterialHelper* pcHelper = new MaterialHelper(); MaterialHelper* pcHelper = new MaterialHelper();
@ -1019,16 +1016,12 @@ void PLYImporter::LoadMaterial(std::vector<MaterialHelper*>* pvOut)
// handle phong power and shading mode // handle phong power and shading mode
int iMode; int iMode;
if (0xFFFFFFFF != iPhong) if (0xFFFFFFFF != iPhong) {
{ float fSpec = PLY::PropertyInstance::ConvertTo<float>((*i).alProperties[iPhong].avList.front(),ePhong);
float fSpec = PLY::PropertyInstance::ConvertTo<float>(
(*i).alProperties[iPhong].avList.front(),ePhong);
// if shininess is 0 (and the pow() calculation would therefore always // if shininess is 0 (and the pow() calculation would therefore always
// become 1, not depending on the angle) use gouraud lighting // become 1, not depending on the angle), use gouraud lighting
if (fSpec) if (fSpec) {
{
// scale this with 15 ... hopefully this is correct // scale this with 15 ... hopefully this is correct
fSpec *= 15; fSpec *= 15;
pcHelper->AddProperty<float>(&fSpec, 1, AI_MATKEY_SHININESS); pcHelper->AddProperty<float>(&fSpec, 1, AI_MATKEY_SHININESS);
@ -1041,14 +1034,16 @@ void PLYImporter::LoadMaterial(std::vector<MaterialHelper*>* pvOut)
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// handle opacity // handle opacity
if (0xFFFFFFFF != iOpacity) if (0xFFFFFFFF != iOpacity) {
{ float fOpacity = PLY::PropertyInstance::ConvertTo<float>((*i).alProperties[iPhong].avList.front(),eOpacity);
float fOpacity = PLY::PropertyInstance::ConvertTo<float>(
(*i).alProperties[iPhong].avList.front(),eOpacity);
pcHelper->AddProperty<float>(&fOpacity, 1, AI_MATKEY_OPACITY); pcHelper->AddProperty<float>(&fOpacity, 1, AI_MATKEY_OPACITY);
} }
// The face order is absolutely undefined for PLY, so we have to
// use two-sided rendering to be sure it's ok.
const int two_sided = 1;
pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
// add the newly created material instance to the list // add the newly created material instance to the list
pvOut->push_back(pcHelper); pvOut->push_back(pcHelper);
} }

View File

@ -62,8 +62,7 @@ void ScenePreprocessor::ProcessScene ()
ProcessAnimation(scene->mAnimations[i]); ProcessAnimation(scene->mAnimations[i]);
// Generate a default material if none was specified // Generate a default material if none was specified
if (!scene->mNumMaterials && scene->mNumMeshes) if (!scene->mNumMaterials && scene->mNumMeshes) {
{
scene->mMaterials = new aiMaterial*[2]; scene->mMaterials = new aiMaterial*[2];
MaterialHelper* helper; MaterialHelper* helper;
@ -76,13 +75,11 @@ void ScenePreprocessor::ProcessScene ()
if (scene->mMeshes[i]->mTextureCoords[0]) { if (scene->mMeshes[i]->mTextureCoords[0]) {
if (mat0 == 0xffffffff) { if (mat0 == 0xffffffff) {
scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper();
// dummy texture scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper();
name.Set("texture.png"); name.Set("$texture.png");
helper->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(0)); helper->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(0));
// setup default name
name.Set(AI_DEFAULT_TEXTURED_MATERIAL_NAME); name.Set(AI_DEFAULT_TEXTURED_MATERIAL_NAME);
helper->AddProperty(&name,AI_MATKEY_NAME); helper->AddProperty(&name,AI_MATKEY_NAME);
@ -94,16 +91,11 @@ void ScenePreprocessor::ProcessScene ()
else else
{ {
if (mat1 == 0xffffffff) { if (mat1 == 0xffffffff) {
scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper();
// gray scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper();
aiColor3D clr(0.6f,0.6f,0.6f); aiColor3D clr(0.6f,0.6f,0.6f);
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
// add a small ambient color value
clr = aiColor3D(0.05f,0.05f,0.05f);
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT);
// setup the default name // setup the default name
name.Set(AI_DEFAULT_MATERIAL_NAME); name.Set(AI_DEFAULT_MATERIAL_NAME);
helper->AddProperty(&name,AI_MATKEY_NAME); helper->AddProperty(&name,AI_MATKEY_NAME);
@ -121,8 +113,7 @@ void ScenePreprocessor::ProcessScene ()
void ScenePreprocessor::ProcessMesh (aiMesh* mesh) void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
{ {
// If aiMesh::mNumUVComponents is *not* set assign the default value of 2 // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
{
if (!mesh->mTextureCoords[i]) if (!mesh->mTextureCoords[i])
mesh->mNumUVComponents[i] = 0; mesh->mNumUVComponents[i] = 0;
@ -146,10 +137,8 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
// If the information which primitive types are there in the // If the information which primitive types are there in the
// mesh is currently not available, compute it. // mesh is currently not available, compute it.
if (!mesh->mPrimitiveTypes) if (!mesh->mPrimitiveTypes) {
{ for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
{
aiFace& face = mesh->mFaces[a]; aiFace& face = mesh->mFaces[a];
switch (face.mNumIndices) switch (face.mNumIndices)
{ {
@ -173,8 +162,8 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
} }
// If tangents and normals are given but no bitangents compute them // If tangents and normals are given but no bitangents compute them
if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
{
mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
for (unsigned int i = 0; i < mesh->mNumVertices;++i) { for (unsigned int i = 0; i < mesh->mNumVertices;++i) {
mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i];
@ -186,34 +175,30 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
{ {
double first = 10e10, last = -10e10; double first = 10e10, last = -10e10;
for (unsigned int i = 0; i < anim->mNumChannels;++i) for (unsigned int i = 0; i < anim->mNumChannels;++i) {
{
aiNodeAnim* channel = anim->mChannels[i]; aiNodeAnim* channel = anim->mChannels[i];
/* If the exact duration of the animation is not given /* If the exact duration of the animation is not given
* compute it now. * compute it now.
*/ */
if (anim->mDuration == -1.) if (anim->mDuration == -1.) {
{
// Position keys // Position keys
for (unsigned int i = 0; i < channel->mNumPositionKeys;++i) for (unsigned int i = 0; i < channel->mNumPositionKeys;++i) {
{
aiVectorKey& key = channel->mPositionKeys[i]; aiVectorKey& key = channel->mPositionKeys[i];
first = std::min (first, key.mTime); first = std::min (first, key.mTime);
last = std::max (last, key.mTime); last = std::max (last, key.mTime);
} }
// Scaling keys // Scaling keys
for (unsigned int i = 0; i < channel->mNumScalingKeys;++i) for (unsigned int i = 0; i < channel->mNumScalingKeys;++i) {
{
aiVectorKey& key = channel->mScalingKeys[i]; aiVectorKey& key = channel->mScalingKeys[i];
first = std::min (first, key.mTime); first = std::min (first, key.mTime);
last = std::max (last, key.mTime); last = std::max (last, key.mTime);
} }
// Rotation keys // Rotation keys
for (unsigned int i = 0; i < channel->mNumRotationKeys;++i) for (unsigned int i = 0; i < channel->mNumRotationKeys;++i) {
{
aiQuatKey& key = channel->mRotationKeys[i]; aiQuatKey& key = channel->mRotationKeys[i];
first = std::min (first, key.mTime); first = std::min (first, key.mTime);
last = std::max (last, key.mTime); last = std::max (last, key.mTime);
@ -225,8 +210,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
* track from the information we have in the transformation * track from the information we have in the transformation
* matrix of the corresponding node. * matrix of the corresponding node.
*/ */
if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
{
// Find the node that belongs to this animation // Find the node that belongs to this animation
aiNode* node = scene->mRootNode->FindNode(channel->mNodeName); aiNode* node = scene->mRootNode->FindNode(channel->mNodeName);
if (node) // ValidateDS will complain later if 'node' is NULL if (node) // ValidateDS will complain later if 'node' is NULL
@ -238,8 +222,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
node->mTransformation.Decompose(scaling, rotation,position); node->mTransformation.Decompose(scaling, rotation,position);
// No rotation keys? Generate a dummy track // No rotation keys? Generate a dummy track
if (!channel->mNumRotationKeys) if (!channel->mNumRotationKeys) {
{
channel->mNumRotationKeys = 1; channel->mNumRotationKeys = 1;
channel->mRotationKeys = new aiQuatKey[1]; channel->mRotationKeys = new aiQuatKey[1];
aiQuatKey& q = channel->mRotationKeys[0]; aiQuatKey& q = channel->mRotationKeys[0];
@ -251,8 +234,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
} }
// No scaling keys? Generate a dummy track // No scaling keys? Generate a dummy track
if (!channel->mNumScalingKeys) if (!channel->mNumScalingKeys) {
{
channel->mNumScalingKeys = 1; channel->mNumScalingKeys = 1;
channel->mScalingKeys = new aiVectorKey[1]; channel->mScalingKeys = new aiVectorKey[1];
aiVectorKey& q = channel->mScalingKeys[0]; aiVectorKey& q = channel->mScalingKeys[0];
@ -264,8 +246,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
} }
// No position keys? Generate a dummy track // No position keys? Generate a dummy track
if (!channel->mNumPositionKeys) if (!channel->mNumPositionKeys) {
{
channel->mNumPositionKeys = 1; channel->mNumPositionKeys = 1;
channel->mPositionKeys = new aiVectorKey[1]; channel->mPositionKeys = new aiVectorKey[1];
aiVectorKey& q = channel->mPositionKeys[0]; aiVectorKey& q = channel->mPositionKeys[0];
@ -278,9 +259,9 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
} }
} }
} }
if (anim->mDuration == -1.)
{ if (anim->mDuration == -1.) {
DefaultLogger::get()->debug("Setting animation duration"); DefaultLogger::get()->debug("ScenePreprocessor: Setting animation duration");
anim->mDuration = last - std::min( first, 0. ); anim->mDuration = last - std::min( first, 0. );
} }
} }

View File

@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "StreamReader.h" #include "StreamReader.h"
#include "ParsingUtils.h" #include "ParsingUtils.h"
#include "fast_atof.h" #include "fast_atof.h"
#include "ConvertToLHProcess.h"
using namespace Assimp; using namespace Assimp;
@ -107,14 +108,10 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
// For any of the 3 files being passed get the three correct paths // For any of the 3 files being passed get the three correct paths
// First of all, determine file extension // First of all, determine file extension
std::string::size_type pos = pFile.find_last_of('.'); std::string::size_type pos = pFile.find_last_of('.');
std::string extension = pFile.substr( pos); std::string extension = GetExtension(pFile);
for( std::string::iterator it = extension.begin(); it != extension.end(); ++it)
*it = tolower( *it);
std::string d_path,a_path,uc_path; std::string d_path,a_path,uc_path;
if (extension == ".3d") if (extension == "3d") {
{
// jjjj_d.3d // jjjj_d.3d
// jjjj_a.3d // jjjj_a.3d
pos = pFile.find_last_of('_'); pos = pFile.find_last_of('_');
@ -123,8 +120,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
} }
extension = pFile.substr(0,pos); extension = pFile.substr(0,pos);
} }
else // if (extension == ".uc") else {
{
extension = pFile.substr(0,pos); extension = pFile.substr(0,pos);
} }
@ -154,16 +150,13 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
// collect triangles // collect triangles
std::vector<Unreal::Triangle> triangles(numTris); std::vector<Unreal::Triangle> triangles(numTris);
for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end(); for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
it != end; ++it)
{
Unreal::Triangle& tri = *it; Unreal::Triangle& tri = *it;
for (unsigned int i = 0; i < 3;++i) for (unsigned int i = 0; i < 3;++i) {
{
tri.mVertex[i] = d_reader.GetI2(); tri.mVertex[i] = d_reader.GetI2();
if (tri.mVertex[i] >= numTris) if (tri.mVertex[i] >= numTris) {
{
DefaultLogger::get()->warn("UNREAL: vertex index out of range"); DefaultLogger::get()->warn("UNREAL: vertex index out of range");
tri.mVertex[i] = 0; tri.mVertex[i] = 0;
} }
@ -208,9 +201,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
// collect vertices // collect vertices
std::vector<aiVector3D> vertices(numVert); std::vector<aiVector3D> vertices(numVert);
for (std::vector<aiVector3D>::iterator it = vertices.begin(), end = vertices.end(); for (std::vector<aiVector3D>::iterator it = vertices.begin(), end = vertices.end(); it != end; ++it) {
it != end; ++it)
{
int32_t val = a_reader.GetI4(); int32_t val = a_reader.GetI4();
Unreal::DecompressVertex(*it,val); Unreal::DecompressVertex(*it,val);
} }
@ -236,8 +227,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
std::vector< std::pair< std::string,std::string > > tempTextures; std::vector< std::pair< std::string,std::string > > tempTextures;
// do a quick search in the UC file for some known, usually texture-related, tags // do a quick search in the UC file for some known, usually texture-related, tags
for (;*data;++data) for (;*data;++data) {
{
if (TokenMatchI(data,"#exec",5)) { if (TokenMatchI(data,"#exec",5)) {
SkipSpacesAndLineEnd(&data); SkipSpacesAndLineEnd(&data);
@ -245,20 +235,16 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
if (TokenMatchI(data,"TEXTURE",7)) { if (TokenMatchI(data,"TEXTURE",7)) {
SkipSpacesAndLineEnd(&data); SkipSpacesAndLineEnd(&data);
if (TokenMatchI(data,"IMPORT",6)) if (TokenMatchI(data,"IMPORT",6)) {
{
tempTextures.push_back(std::pair< std::string,std::string >()); tempTextures.push_back(std::pair< std::string,std::string >());
std::pair< std::string,std::string >& me = tempTextures.back(); std::pair< std::string,std::string >& me = tempTextures.back();
for (;!IsLineEnd(*data);++data) for (;!IsLineEnd(*data);++data) {
{ if (!::ASSIMP_strincmp(data,"NAME=",5)) {
if (!::ASSIMP_strincmp(data,"NAME=",5))
{
const char *d = data+=5; const char *d = data+=5;
for (;!IsSpaceOrNewLine(*data);++data); for (;!IsSpaceOrNewLine(*data);++data);
me.first = std::string(d,(size_t)(data-d)); me.first = std::string(d,(size_t)(data-d));
} }
else if (!::ASSIMP_strincmp(data,"FILE=",5)) else if (!::ASSIMP_strincmp(data,"FILE=",5)) {
{
const char *d = data+=5; const char *d = data+=5;
for (;!IsSpaceOrNewLine(*data);++data); for (;!IsSpaceOrNewLine(*data);++data);
me.second = std::string(d,(size_t)(data-d)); me.second = std::string(d,(size_t)(data-d));
@ -279,13 +265,11 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
std::pair<unsigned int, std::string>& me = textures.back(); std::pair<unsigned int, std::string>& me = textures.back();
for (;!IsLineEnd(*data);++data) { for (;!IsLineEnd(*data);++data) {
if (!::ASSIMP_strincmp(data,"NUM=",4)) if (!::ASSIMP_strincmp(data,"NUM=",4)) {
{
data += 4; data += 4;
me.first = strtol10(data,&data); me.first = strtol10(data,&data);
} }
else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) {
{
data += 8; data += 8;
const char *d = data; const char *d = data;
for (;!IsSpaceOrNewLine(*data);++data); for (;!IsSpaceOrNewLine(*data);++data);
@ -293,10 +277,8 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
// try to find matching path names, doesn't care if we don't find them // try to find matching path names, doesn't care if we don't find them
for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin(); for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin();
it != tempTextures.end(); ++it) it != tempTextures.end(); ++it) {
{ if ((*it).first == me.second) {
if ((*it).first == me.second)
{
me.second = (*it).second; me.second = (*it).second;
break; break;
} }
@ -330,9 +312,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
materials.reserve(textures.size()*2+5); materials.reserve(textures.size()*2+5);
// find out how many output meshes and materials we'll have and build material indices // find out how many output meshes and materials we'll have and build material indices
for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end(); for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
it != end; ++it)
{
Unreal::Triangle& tri = *it; Unreal::Triangle& tri = *it;
Unreal::TempMat mat(tri); Unreal::TempMat mat(tri);
std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat); std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat);
@ -389,8 +369,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
else ::strcat(s.data,"os_"); else ::strcat(s.data,"os_");
// make TRANS faces 90% opaque that RemRedundantMaterials won't catch us // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us
if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) {
{
const float opac = 0.9f; const float opac = 0.9f;
mat->AddProperty(&opac,1,AI_MATKEY_OPACITY); mat->AddProperty(&opac,1,AI_MATKEY_OPACITY);
::strcat(s.data,"tran_"); ::strcat(s.data,"tran_");
@ -398,8 +377,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
else ::strcat(s.data,"opaq_"); else ::strcat(s.data,"opaq_");
// a special name for the weapon attachment point // a special name for the weapon attachment point
if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) {
{
s.length = ::sprintf(s.data,"$WeaponTag$"); s.length = ::sprintf(s.data,"$WeaponTag$");
color = aiColor3D(0.f,0.f,0.f); color = aiColor3D(0.f,0.f,0.f);
} }
@ -411,11 +389,8 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
// set texture, if any // set texture, if any
const unsigned int tex = materials[i].tex; const unsigned int tex = materials[i].tex;
for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin(); for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin();it != textures.end();++it) {
it != textures.end();++it) if ((*it).first == tex) {
{
if ((*it).first == tex)
{
s.Set((*it).second); s.Set((*it).second);
mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
break; break;
@ -424,9 +399,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
} }
// fill them. // fill them.
for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end(); for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
it != end; ++it)
{
Unreal::Triangle& tri = *it; Unreal::Triangle& tri = *it;
Unreal::TempMat mat(tri); Unreal::TempMat mat(tri);
std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat); std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat);
@ -435,14 +408,17 @@ void UnrealImporter::InternReadFile( const std::string& pFile,
aiFace& f = mesh->mFaces[mesh->mNumFaces++]; aiFace& f = mesh->mFaces[mesh->mNumFaces++];
f.mIndices = new unsigned int[f.mNumIndices = 3]; f.mIndices = new unsigned int[f.mNumIndices = 3];
for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) {
{
f.mIndices[i] = mesh->mNumVertices; f.mIndices[i] = mesh->mNumVertices;
mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ]; mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ];
mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f); mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f);
} }
} }
// convert to RH
MakeLeftHandedProcess hero;
hero.Execute(pScene);
} }
#endif // !! AI_BUILD_NO_3D_IMPORTER #endif // !! AI_BUILD_NO_3D_IMPORTER

View File

@ -47,7 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "XFileImporter.h" #include "XFileImporter.h"
#include "XFileParser.h" #include "XFileParser.h"
#include "MaterialSystem.h"
#include "ConvertToLHProcess.h" #include "ConvertToLHProcess.h"
using namespace Assimp; using namespace Assimp;
@ -141,9 +140,9 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, const X
CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes); CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes);
} }
// convert the root node's transformation to OGL coords // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly
if( pScene->mRootNode) MakeLeftHandedProcess convertProcess;
ConvertToLHProcess::ConvertToOGL( pScene->mRootNode->mTransformation); convertProcess.Execute( pScene);
// finally: create a dummy material if not material was imported // finally: create a dummy material if not material was imported
if( pScene->mNumMaterials == 0) if( pScene->mNumMaterials == 0)
@ -305,7 +304,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// collect vertex data for indices of this face // collect vertex data for indices of this face
for( unsigned int d = 0; d < df.mNumIndices; d++) for( unsigned int d = 0; d < df.mNumIndices; d++)
{ {
df.mIndices[df.mNumIndices - 1 - d] = newIndex; // inverted face orientation for OGL df.mIndices[d] = newIndex;
orgPoints[newIndex] = pf.mIndices[d]; orgPoints[newIndex] = pf.mIndices[d];
// Position // Position
@ -313,6 +312,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// Normal, if present // Normal, if present
if( mesh->HasNormals()) if( mesh->HasNormals())
mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]]; mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]];
// texture coord sets // texture coord sets
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++) for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++)
{ {
@ -413,9 +413,9 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
for( unsigned int a = 0; a < pData->mAnims.size(); a++) for( unsigned int a = 0; a < pData->mAnims.size(); a++)
{ {
const XFile::Animation* anim = pData->mAnims[a]; const XFile::Animation* anim = pData->mAnims[a];
// some exporters mock me with empty animation tags. // some exporters mock me with empty animation tags.
if( anim->mAnims.size() == 0) if( anim->mAnims.size() == 0)
continue; continue;
// create a new animation to hold the data // create a new animation to hold the data
aiAnimation* nanim = new aiAnimation; aiAnimation* nanim = new aiAnimation;
@ -434,9 +434,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
nbone->mNodeName.Set( bone->mBoneName); nbone->mNodeName.Set( bone->mBoneName);
nanim->mChannels[b] = nbone; nanim->mChannels[b] = nbone;
// apply the LH->RH conversion if the animation affects the root bone
bool isRootAnim = (bone->mBoneName == pScene->mRootNode->mName.data);
// keyframes are given as combined transformation matrix keys // keyframes are given as combined transformation matrix keys
if( bone->mTrafoKeys.size() > 0) if( bone->mTrafoKeys.size() > 0)
{ {
@ -455,8 +452,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
// extract position // extract position
aiVector3D pos( trafo.a4, trafo.b4, trafo.c4); aiVector3D pos( trafo.a4, trafo.b4, trafo.c4);
if( isRootAnim)
ConvertToLHProcess::ConvertToOGL( pos);
nbone->mPositionKeys[c].mTime = time; nbone->mPositionKeys[c].mTime = time;
nbone->mPositionKeys[c].mValue = pos; nbone->mPositionKeys[c].mValue = pos;
@ -475,9 +470,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / 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); trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
if( isRootAnim)
ConvertToLHProcess::ConvertToOGL( rotmat);
// and convert it into a quaternion // and convert it into a quaternion
nbone->mRotationKeys[c].mTime = time; nbone->mRotationKeys[c].mTime = time;
nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat); nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
@ -493,8 +485,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++) for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++)
{ {
aiVector3D pos = bone->mPosKeys[c].mValue; aiVector3D pos = bone->mPosKeys[c].mValue;
if( isRootAnim)
ConvertToLHProcess::ConvertToOGL( pos);
nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime; nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
nbone->mPositionKeys[c].mValue = pos; nbone->mPositionKeys[c].mValue = pos;
@ -506,8 +496,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++) for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++)
{ {
aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix(); aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
if( isRootAnim)
ConvertToLHProcess::ConvertToOGL( rotmat);
nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime; nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat); nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);

Binary file not shown.

View File

@ -31,7 +31,7 @@ PROJECT_NAME = assimp
# This could be handy for archiving the generated documentation or # This could be handy for archiving the generated documentation or
# if some version control system is used. # if some version control system is used.
PROJECT_NUMBER = r281 PROJECT_NUMBER = r350
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.

View File

@ -17,7 +17,7 @@ processing steps to the imported data such as conversion to indexed meshes, calc
or conversion from right-handed to left-handed coordinate systems. or conversion from right-handed to left-handed coordinate systems.
ASSIMP currently supports the following file formats (note that some loaders lack some features of their formats because ASSIMP currently supports the following file formats (note that some loaders lack some features of their formats because
some file formats contain data not supported by Assimp, some stuff would require so much conversion work some file formats contain data not supported by ASSIMP, some stuff would require so much conversion work
that it has not yet been implemented, and some formats have not completely been documented by their inventors): that it has not yet been implemented, and some formats have not completely been documented by their inventors):
<hr> <hr>
<br><tt> <br><tt>
@ -37,7 +37,7 @@ that it has not yet been implemented, and some formats have not completely been
<b>Quake II</b> ( <i>*.md2</i> ) <br> <b>Quake II</b> ( <i>*.md2</i> ) <br>
<b>Quake III</b> ( <i>*.md3</i> ) <br> <b>Quake III</b> ( <i>*.md3</i> ) <br>
<b>RtCW</b> ( <i>*.mdc</i> )<br> <b>RtCW</b> ( <i>*.mdc</i> )<br>
<b>Doom 3</b> ( <i>*.md5</i> ) <sup>3</sup> <br> <b>Doom 3</b> ( <i>*.md5mesh;*.md5anim;*.md5camera</i> ) <br>
<b>DirectX X </b> ( <i>*.x</i> ). <br> <b>DirectX X </b> ( <i>*.x</i> ). <br>
<b>Quick3D </b> ( <i>*.q3o;*q3s</i> ). <br> <b>Quick3D </b> ( <i>*.q3o;*q3s</i> ). <br>
<b>Raw Triangles </b> ( <i>*.raw</i> ). <br> <b>Raw Triangles </b> ( <i>*.raw</i> ). <br>
@ -51,7 +51,7 @@ that it has not yet been implemented, and some formats have not completely been
<b>3D GameStudio Model </b> ( <i>*.mdl</i> ) <br> <b>3D GameStudio Model </b> ( <i>*.mdl</i> ) <br>
<b>3D GameStudio Terrain</b> ( <i>*.hmp</i> )<br><br><br> <b>3D GameStudio Terrain</b> ( <i>*.hmp</i> )<br><br><br>
</tt> </tt>
<sup>3</sup>: These formats support animations, but Assimp doesn't yet support them (or they're buggy) <sup>3</sup>: These formats support animations, but ASSIMP doesn't yet support them (or they're buggy)
<br> <br>
<hr> <hr>
@ -115,9 +115,9 @@ assimp-discussions</a>.
@section install_prebuilt Using the pre-built libraries with Visual C++ 8/9 @section install_prebuilt Using the pre-built libraries with Visual C++ 8/9
If you develop at Visual Studio 2005 or 2008, you can simply use the pre-built linker libraries provided in the distribution. If you develop at Visual Studio 2005 or 2008, you can simply use the pre-built linker libraries provided in the distribution.
Extract all files to a place of your choice. A directory called "Assimp" will be created there. Add the Assimp/include path Extract all files to a place of your choice. A directory called "ASSIMP" will be created there. Add the ASSIMP/include path
to your include paths (Menu-&gt;Extras-&gt;Options-&gt;Projects and Solutions-&gt;VC++ Directories-&gt;Include files) to your include paths (Menu-&gt;Extras-&gt;Options-&gt;Projects and Solutions-&gt;VC++ Directories-&gt;Include files)
and the Assimp/lib/&lt;Compiler&gt; path to your linker paths (Menu-&gt;Extras-&gt;Options-&gt;Projects and Solutions-&gt;VC++ Directories-&gt;Library files). and the ASSIMP/lib/&lt;Compiler&gt; path to your linker paths (Menu-&gt;Extras-&gt;Options-&gt;Projects and Solutions-&gt;VC++ Directories-&gt;Library files).
This is neccessary only once to setup all paths inside you IDE. This is neccessary only once to setup all paths inside you IDE.
To use the library in your C++ project you have to include either &lt;assimp.hpp&gt; or &lt;assimp.h&gt; plus some others starting with &lt;aiTypes.h&gt;. To use the library in your C++ project you have to include either &lt;assimp.hpp&gt; or &lt;assimp.h&gt; plus some others starting with &lt;aiTypes.h&gt;.
@ -140,7 +140,7 @@ various useful debug checks. Actually they are really helpful for debugging, but
so extremely slow that they can make the STL up to 100 times slower (imagine a <i>std::vector<T>::operator[] </i> so extremely slow that they can make the STL up to 100 times slower (imagine a <i>std::vector<T>::operator[] </i>
performing 3 or 4 single checks! scary ...). performing 3 or 4 single checks! scary ...).
These security enhancements are - thanks MS! - also active in release builds, rendering Assimp several times These security enhancements are - thanks MS! - also active in release builds, rendering ASSIMP several times
slower. However, it is possible to disable them by defining slower. However, it is possible to disable them by defining
@code @code
@ -149,14 +149,14 @@ _SECURE_SCL=0
@endcode @endcode
in the preprocessor options (or alternatively in the source code, just before the STL is included for the first time). in the preprocessor options (or alternatively in the source code, just before the STL is included for the first time).
<b>Assimp's vc8 and vc9 configs enable these flags by default</b>. <b>ASSIMP's vc8 and vc9 configs enable these flags by default</b>.
<i>If you're linking statically against Assimp:</i> Make sure your applications uses the same STl settings! <i>If you're linking statically against ASSIMP:</i> Make sure your applications uses the same STl settings!
If you do not, there are two binary incompatible STL versions mangled together and you'll crash. If you do not, there are two binary incompatible STL versions mangled together and you'll crash.
Alternatively you can disable the fast STL settings for Assimp by removing the 'FastSTL' property sheet from Alternatively you can disable the fast STL settings for ASSIMP by removing the 'FastSTL' property sheet from
the vc project file. the vc project file.
<i>If you're using Assimp in a DLL:</i> It's ok. There's no STL used in the DLL interface, so it doesn't care whether <i>If you're using ASSIMP in a DLL:</i> It's ok. There's no STL used in the DLL interface, so it doesn't care whether
your application uses the same STL settings or not. your application uses the same STL settings or not.
<br><br> <br><br>
Another option is to build against a different STL implementation, for example STlport. There's a special Another option is to build against a different STL implementation, for example STlport. There's a special
@ -200,7 +200,7 @@ The Boost-Workaround consists of dummy replacements for some boost utility templ
<li><i>boost.foreach</i> </li> <li><i>boost.foreach</i> </li>
<li><i>boost.tuple</i></li> <li><i>boost.tuple</i></li>
</ul> </ul>
These implementations are very limited and are not intended for use outside Assimp. A compiler These implementations are very limited and are not intended for use outside ASSIMP. A compiler
with full support for partial template specializations is required. To enable the workaround, put the following in with full support for partial template specializations is required. To enable the workaround, put the following in
your compiler's list of predefined macros: your compiler's list of predefined macros:
@code @code
@ -220,26 +220,26 @@ for more details.
@section assimp_dll DLL build @section assimp_dll DLL build
Assimp can be built as DLL. You just need to select a -dll config from the list of project ASSIMP can be built as DLL. You just need to select a -dll config from the list of project
configs and you're fine. Don't forget to copy the DLL to the directory of your executable :-) configs and you're fine. Don't forget to copy the DLL to the directory of your executable :-)
<b>NOTE:</b> Theoretically Assimp-dll can be used with multithreaded (non-dll) runtime libraries, <b>NOTE:</b> Theoretically ASSIMP-dll can be used with multithreaded (non-dll) runtime libraries,
as long as you don't utilize any non-public stuff from the code dir. However, if you happen as long as you don't utilize any non-public stuff from the code dir. However, if you happen
to encounter *very* strange problems try changing the runtime to multithreaded (Debug) DLL. to encounter *very* strange problems try changing the runtime to multithreaded (Debug) DLL.
@section assimp_stlport Building against STLport @section assimp_stlport Building against STLport
If your compiler's default implementation of the STL is too slow, lacks some features, If your compiler's default implementation of the STL is too slow, lacks some features,
contains bugs or if you just want to tweak Assimp's performance a little try a build contains bugs or if you just want to tweak ASSIMP's performance a little try a build
against STLport. STLport is a free, fast and secure STL replacement that works with against STLport. STLport is a free, fast and secure STL replacement that works with
all major compilers and platforms. To get it visit their website at all major compilers and platforms. To get it visit their website at
<a href="http://www.stlport.org"/><stlport.org></a> and download the latest STLport release. <a href="http://www.stlport.org"/><stlport.org></a> and download the latest STLport release.
Usually you'll just need to run 'configure' + a makefile (see the README for more details). Usually you'll just need to run 'configure' + a makefile (see the README for more details).
Don't miss to add <stlport_root>/stlport to your compiler's default include paths - <b>prior</b> Don't miss to add <stlport_root>/stlport to your compiler's default include paths - <b>prior</b>
to the directory where the compiler vendor's STL lies. Do the same for <stlport_root>/lib and to the directory where the compiler vendor's STL lies. Do the same for <stlport_root>/lib and
recompile Assimp. To ensure you're really building against STLport see aiGetCompileFlags(). recompile ASSIMP. To ensure you're really building against STLport see aiGetCompileFlags().
<br> <br>
Usually building Assimp against STLport yields a better overall performance so it might be Usually building ASSIMP against STLport yields a better overall performance so it might be
worth a try if the library is too slow for you. worth a try if the library is too slow for you.
*/ */
@ -251,8 +251,8 @@ worth a try if the library is too slow for you.
@section access_cpp Access by C++ class interface @section access_cpp Access by C++ class interface
The ASSIMP library can be accessed by both a class or flat function interface. The C++ class The ASSIMP library can be accessed by both a class or flat function interface. The C++ class
interface is the preferred way of interaction: you create an instance of class Assimp::Importer, interface is the preferred way of interaction: you create an instance of class ASSIMP::Importer,
maybe adjust some settings of it and then call Assimp::Importer::ReadFile(). The class will maybe adjust some settings of it and then call ASSIMP::Importer::ReadFile(). The class will
read the files and process its data, handing back the imported data as a pointer to an aiScene read the files and process its data, handing back the imported data as a pointer to an aiScene
to you. You can now extract the data you need from the file. The importer manages all the resources to you. You can now extract the data you need from the file. The importer manages all the resources
for itsself. If the importer is destroyed, all the data that was created/read by it will be for itsself. If the importer is destroyed, all the data that was created/read by it will be
@ -269,7 +269,7 @@ C++ example:
bool DoTheImportThing( const std::string& pFile) bool DoTheImportThing( const std::string& pFile)
{ {
// Create an instance of the Importer class // Create an instance of the Importer class
Assimp::Importer importer; ASSIMP::Importer importer;
// And have it read the given file with some example postprocessing // And have it read the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll // Usually - if speed is not the most important aspect for you - you'll
@ -358,7 +358,7 @@ custom implementations of IOStream and IOSystem. A shortened example might look
#include <IOSystem.h> #include <IOSystem.h>
// My own implementation of IOStream // My own implementation of IOStream
class MyIOStream : public Assimp::IOStream class MyIOStream : public ASSIMP::IOStream
{ {
friend class MyIOSystem; friend class MyIOSystem;
@ -377,7 +377,7 @@ public:
}; };
// Fisher Price - My First Filesystem // Fisher Price - My First Filesystem
class MyIOSystem : public Assimp::IOSystem class MyIOSystem : public ASSIMP::IOSystem
{ {
MyIOSystem() { ... } MyIOSystem() { ... }
~MyIOSystem() { ... } ~MyIOSystem() { ... }
@ -402,12 +402,12 @@ class MyIOSystem : public Assimp::IOSystem
@endcode @endcode
Now that your IO system is implemented, supply an instance of it to the Importer object by calling Now that your IO system is implemented, supply an instance of it to the Importer object by calling
Assimp::Importer::SetIOHandler(). ASSIMP::Importer::SetIOHandler().
@code @code
void DoTheImportThing( const std::string& pFile) void DoTheImportThing( const std::string& pFile)
{ {
Assimp::Importer importer; ASSIMP::Importer importer;
// put my custom IO handling in place // put my custom IO handling in place
importer.SetIOHandler( new MyIOSystem()); importer.SetIOHandler( new MyIOSystem());
@ -435,7 +435,7 @@ following prerequisites are fulfilled:
</ul> </ul>
See the @link assimp_st Single-threaded build section @endlink to learn how to build a lightweight variant See the @link assimp_st Single-threaded build section @endlink to learn how to build a lightweight variant
of Assimp which is not thread-safe and does not utilize multiple threads for loading. of ASSIMP which is not thread-safe and does not utilize multiple threads for loading.
@section logging Logging in the AssetImporter @section logging Logging in the AssetImporter
@ -448,13 +448,13 @@ by calling it as a singleton with the requested logging-type. To see how this wo
@code @code
// Create a logger instance // Create a logger instance
Assimp::DefaultLogger::create("",Assimp::Logger::VERBOSE); ASSIMP::DefaultLogger::create("",ASSIMP::Logger::VERBOSE);
// Now I am ready for logging my stuff // Now I am ready for logging my stuff
Assimp::DefaultLogger::get()->info("this is my info-call"); ASSIMP::DefaultLogger::get()->info("this is my info-call");
// Kill it after the work is done // Kill it after the work is done
Assimp::DefaultLogger::kill(); ASSIMP::DefaultLogger::kill();
@endcode @endcode
At first you have to create the default-logger-instance (create). Now you are ready to rock and can log a At first you have to create the default-logger-instance (create). Now you are ready to rock and can log a
@ -498,7 +498,7 @@ severity |= Logger::WARN;
severity |= Logger::ERR; severity |= Logger::ERR;
// Attaching it to the default logger // Attaching it to the default logger
Assimp::DefaultLogger::get()->attachStream( new myStream(), severity ); ASSIMP::DefaultLogger::get()->attachStream( new myStream(), severity );
@endcode @endcode
@ -514,7 +514,7 @@ unsigned int severity = 0;
severity |= Logger::DEBUGGING; severity |= Logger::DEBUGGING;
// Detach debug messages from you self defined stream // Detach debug messages from you self defined stream
Assimp::DefaultLogger::get()->attachStream( new myStream(), severity ); ASSIMP::DefaultLogger::get()->attachStream( new myStream(), severity );
@endcode @endcode
@ -541,7 +541,7 @@ In the verbose level debug messages will be logged, too.
The ASSIMP library returns the imported data in a collection of structures. aiScene forms the root The ASSIMP library returns the imported data in a collection of structures. aiScene forms the root
of the data, from here you gain access to all the nodes, meshes, materials, animations or textures of the data, from here you gain access to all the nodes, meshes, materials, animations or textures
that were read from the imported file. The aiScene is returned from a successful call to that were read from the imported file. The aiScene is returned from a successful call to
Assimp::Importer::ReadFile(), aiImportFile() or aiImportFileEx() - see the @link usage Usage page @endlink ASSIMP::Importer::ReadFile(), aiImportFile() or aiImportFileEx() - see the @link usage Usage page @endlink
for further information on how to use the library. for further information on how to use the library.
By default, all 3D data is provided in a right-handed coordinate system such as OpenGL uses. In By default, all 3D data is provided in a right-handed coordinate system such as OpenGL uses. In
@ -549,7 +549,25 @@ this coordinate system, +X points to the right, +Y points away from the viewer i
+Z points upwards. Several modeling packages such as 3D Studio Max use this coordinate system as well. +Z points upwards. Several modeling packages such as 3D Studio Max use this coordinate system as well.
By contrast, some other environments use left-handed coordinate systems, a prominent example being By contrast, some other environments use left-handed coordinate systems, a prominent example being
DirectX. If you need the imported data to be in a left-handed coordinate system, supply the DirectX. If you need the imported data to be in a left-handed coordinate system, supply the
aiProcess_ConvertToLeftHanded flag to the ReadFile() function call. #aiProcess_MakeLeftHanded flag to the ReadFile() function call.
The output face winding is counter-clockwise. Use #aiProcess_FlipWindingOrder to get CW data.
@code
x0
x2
x1
@endcode
The output UV coordinate system has its origin in the lower-left corner:
@code
0y|1y ---------- 1x|1y
| |
| |
| |
0x|0y ---------- 1x|0y
@endcode
Use the #aiProcess_FlipUVs flag to get UV coordinates with the upper-left corner als origin.
All matrices in the library are row-major. That means that the matrices are stored row by row in memory, All matrices in the library are row-major. That means that the matrices are stored row by row in memory,
which is similar to the OpenGL matrix layout. A typical 4x4 matrix including a translational part looks like this: which is similar to the OpenGL matrix layout. A typical 4x4 matrix including a translational part looks like this:
@ -650,7 +668,7 @@ a set of properties accessible by their names. Have a look at aiMaterial.h to se
properties are defined. In this file there are also various functions defined to test for the properties are defined. In this file there are also various functions defined to test for the
presence of certain properties in a material and retrieve their values. presence of certain properties in a material and retrieve their values.
Example to convert from an Assimp material to a Direct3D 9 material for use with the fixed Example to convert from an ASSIMP material to a Direct3D 9 material for use with the fixed
function pipeline. Textures are not handled, only colors and the specular power, sometimes function pipeline. Textures are not handled, only colors and the specular power, sometimes
also refered to as "shininess": also refered to as "shininess":
@code @code

View File

@ -65,12 +65,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific // Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific
// post-processing step. The spe will be excluded from the // post-processing step.
// build in this case. 'XX' stands for the name of the loader. // Full list of all 'XX':
// List of defines:
// CALCTANGENTS // CALCTANGENTS
// JOINVERTICES // JOINVERTICES
// CONVERTTOLH
// TRIANGULATE // TRIANGULATE
// GENFACENORMALS // GENFACENORMALS
// GENVERTEXNORMALS // GENVERTEXNORMALS
@ -88,6 +86,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TRANSFORMTEXCOORDS // TRANSFORMTEXCOORDS
// GENUVCOORDS // GENUVCOORDS
// ENTITYMESHBUILDER // ENTITYMESHBUILDER
// MAKELEFTHANDED
// FLIPUVS
// FLIPWINDINGORDER
// *OPTIMIZEMESHES
// *OPTIMIZEANIMS
// *OPTIMIZENODES
// *GENENTITYMESHES
// Compiler specific includes and definitions // Compiler specific includes and definitions
#if (defined _MSC_VER) #if (defined _MSC_VER)

View File

@ -50,89 +50,152 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
extern "C" { extern "C" {
#endif #endif
/** Defines the flags for all possible post processing steps. */ // -----------------------------------------------------------------------------------
/** @enum aiPostProcessSteps
* @brief Defines the flags for all possible post processing steps.
*
* @see Importer::ReadFile
* @see aiImportFile
* @see aiImportFileEx
*/
// -----------------------------------------------------------------------------------
enum aiPostProcessSteps enum aiPostProcessSteps
{ {
/** <hr>Calculates the tangents and bitangents for the imported meshes. Does nothing
* if a mesh does not have normals. You might want this post processing step to be
* executed if you plan to use tangent space calculations such as normal mapping
* applied to the meshes. There exists a configuration option,
* #AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE that allows you to specify
* an angle maximum for the step.
*/
aiProcess_CalcTangentSpace = 1,
/** <hr>Identifies and joins identical vertex data sets within all imported meshes. // -------------------------------------------------------------------------
/** <hr>Calculates the tangents and bitangents for the imported meshes.
*
* Does nothing if a mesh does not have normals. You might want this post
* processing step to be executed if you plan to use tangent space calculations
* such as normal mapping applied to the meshes. There's a config setting,
* <tt>#AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE</tt>, which allows you to specify
* a maximum smoothing angle for the algorithm. However, usually you'll
* want to let the default value. Thanks.
*/
aiProcess_CalcTangentSpace = 0x1,
// -------------------------------------------------------------------------
/** <hr>Identifies and joins identical vertex data sets within all
* imported meshes.
*
* After this step is run each mesh does contain only unique vertices anymore, * After this step is run each mesh does contain only unique vertices anymore,
* so a vertex is possibly used by multiple faces. You usually want * so a vertex is possibly used by multiple faces. You usually want
* to use this post processing step.*/ * to use this post processing step. If your application deals with
aiProcess_JoinIdenticalVertices = 2, * indexed geometry, this step is compulsory or you'll just waste rendering
* time. <b>If this flag is not specified</b>, no vertices are referenced by
* more than one face and <b>no index buffer is required</b> for rendering.
*/
aiProcess_JoinIdenticalVertices = 0x2,
/** <hr>Converts all the imported data to a left-handed coordinate space such as // -------------------------------------------------------------------------
* the DirectX coordinate system. By default the data is returned in a right-handed /** <hr>Converts all the imported data to a left-handed coordinate space.
* coordinate space which for example OpenGL prefers. In this space, +X points to the *
* right, +Y points towards the viewer and and +Z points upwards. In the DirectX * By default the data is returned in a right-handed coordinate space which
* for example OpenGL prefers. In this space, +X points to the right,
* +Z points towards the viewer and and +Y points upwards. In the DirectX
* coordinate space +X points to the right, +Y points upwards and +Z points * coordinate space +X points to the right, +Y points upwards and +Z points
* away from the viewer. * away from the viewer.
*
* You'll probably want to consider this flag if you use Direct3D for
* rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this
* setting and boundles all conversions typically required for D3D-based
* applications.
*/ */
aiProcess_ConvertToLeftHanded = 4, aiProcess_MakeLeftHanded = 0x4,
/** <hr>Triangulates all faces of all meshes. By default the imported mesh data might // -------------------------------------------------------------------------
* contain faces with more than 3 indices. For rendering a mesh you usually need /** <hr>Triangulates all faces of all meshes.
* all faces to be triangles. This post processing step splits up all higher faces *
* to triangles. This step won't modify line and point primitives. If you need * By default the imported mesh data might contain faces with more than 3
* only triangles, do the following:<br> * indices. For rendering you'll usually want all faces to be triangles.
* 1. Specify both the aiProcess_Triangulate and the aiProcess_SortByPType * This post processing step splits up all higher faces to triangles.
* step. <br> * Line and point primitives are *not* modified!. If you want
* 2. Ignore all point and line meshes when you process assimp's output data. * 'triangles only' with no other kinds of primitives, try the following
* solution:
* <ul>
* <li>Specify both #aiProcess_Triangulate and #aiProcess_SortByPType </li>
* </li>Ignore all point and line meshes when you process assimp's output</li>
* </ul>
*/ */
aiProcess_Triangulate = 8, aiProcess_Triangulate = 0x8,
// -------------------------------------------------------------------------
/** <hr>Removes some parts of the data structure (animations, materials, /** <hr>Removes some parts of the data structure (animations, materials,
* light sources, cameras, textures, vertex components). * light sources, cameras, textures, vertex components).
* *
* The components to be removed are specified in a separate * The components to be removed are specified in a separate
* configuration option, #AI_CONFIG_PP_RVC_FLAGS. This is quite useful * configuration option, <tt>#AI_CONFIG_PP_RVC_FLAGS</tt>. This is quite useful
* if you don't need all parts of the output structure. Especially vertex * if you don't need all parts of the output structure. Especially vertex
* colors are rarely used today ... . Calling this step to exclude non-required * colors are rarely used today ... . Calling this step to remove unrequired
* stuff from the pipeline as early as possible results in an increased * stuff from the pipeline as early as possible results in an increased
* performance and a better optimized output data structure. * performance and a better optimized output data structure.
* This step is also useful if you want to force Assimp to recompute * This step is also useful if you want to force Assimp to recompute
* normals or tangents. The corresponding steps don't recompute them if * normals or tangents. The corresponding steps don't recompute them if
* they're already there ( loaded from the source asset). By using this * they're already there (loaded from the source asset). By using this
* step you can make sure they are NOT there. * step you can make sure they are NOT there.
*
* This flag is a poor one, mainly because it's purpose is usually
* misunderstood. Consider the following case: a 3d model has been exported
* from a CAD app, it has per-face vertex colors. Vertex positions can't be
* shared, thus the #aiProcess_JoinIdenticalVertices step fails to
* optimize the data. Just because these nasty, little vertex colors.
* Most apps don't even process them, so it's all for nothing. By using
* this step, unneeded components are excluded as early as possible
* thus opening more room for internal optimzations.
*/ */
aiProcess_RemoveComponent = 0x10, aiProcess_RemoveComponent = 0x10,
/** <hr>Generates normals for all faces of all meshes. The normals are shared // -------------------------------------------------------------------------
* between the three vertices of a face. This is ignored /** <hr>Generates normals for all faces of all meshes.
* if normals are already existing. This flag may not be specified together *
* with aiProcess_GenSmoothNormals. * This is ignored if normals are already there at the time where this flag
*/ * is evaluated. Model importers try to load them from the source file, so
* they're usually already there. Face normals are shared between all points
* of a single face, so a single point can have multiple normals, which in
* other words, enforces the library to duplicate vertices in some cases.
* #aiProcess_JoinIdenticalVertices is *senseless* then.
*
* This flag may not be specified together with #aiProcess_GenSmoothNormals.
*/
aiProcess_GenNormals = 0x20, aiProcess_GenNormals = 0x20,
/** <hr>Generates smooth normals for all vertices in the mesh. This is ignored // -------------------------------------------------------------------------
* if normals are already existing. This flag may not be specified together /** <hr>Generates smooth normals for all vertices in the mesh.
* with aiProcess_GenNormals. There's a configuration option, *
* #AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE that allows you to specify * This is ignored if normals are already there at the time where this flag
* is evaluated. Model importers try to load them from the source file, so
* they're usually already there.
*
* This flag may (of course) not be specified together with
* #aiProcess_GenNormals. There's a configuration option,
* <tt>#AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE</tt> which allows you to specify
* an angle maximum for the normal smoothing algorithm. Normals exceeding * an angle maximum for the normal smoothing algorithm. Normals exceeding
* this limit are not smoothed, resulting in a a 'hard' seam between two faces. * this limit are not smoothed, resulting in a a 'hard' seam between two faces.
* Using a decent angle here (e.g. 80°) results in very good visual
* appearance.
*/ */
aiProcess_GenSmoothNormals = 0x40, aiProcess_GenSmoothNormals = 0x40,
/** <hr>Splits large meshes into submeshes // -------------------------------------------------------------------------
* This is quite useful for realtime rendering where the number of triangles /** <hr>Splits large meshes into smaller submeshes
* to be maximally rendered in one drawcall is usually limited by the video driver.
* The maximum vertex buffer size suffers from limitations, too. Both
* requirements are met with this step: you can specify both a triangle and vertex
* limit for a single mesh.
* *
* The split limits can be set through the <tt>AI_CONFIG_PP_SLM_VERTEX_LIMIT</tt> * This is quite useful for realtime rendering where the number of triangles
* and <tt>AI_CONFIG_PP_SLM_TRIANGLE_LIMIT</tt> The default values are * which can be maximally processed in a single draw-call is usually limited
* <tt>AI_SLM_DEFAULT_MAX_VERTICES</tt> and <tt>AI_SLM_DEFAULT_MAX_TRIANGLES</tt>. * by the video driver/hardware. The maximum vertex buffer is usually limited,
* too. Both requirements can be met with this step: you may specify both a
* triangle and vertex limit for a single mesh.
*
* The split limits can (and should!) be set through the
* <tt>#AI_CONFIG_PP_SLM_VERTEX_LIMIT</tt> and <tt>#AI_CONFIG_PP_SLM_TRIANGLE_LIMIT</tt>
* settings. The default values are <tt>#AI_SLM_DEFAULT_MAX_VERTICES</tt> and
* <tt>#AI_SLM_DEFAULT_MAX_TRIANGLES</tt>.
*
* Note that splitting is generally a time-consuming task, but not if there's
* nothing to split. The use of this step is recommended for most users.
*/ */
aiProcess_SplitLargeMeshes = 0x80, aiProcess_SplitLargeMeshes = 0x80,
// -------------------------------------------------------------------------
/** <hr>Removes the node graph and pre-transforms all vertices with /** <hr>Removes the node graph and pre-transforms all vertices with
* the local transformation matrices of their nodes. The output * the local transformation matrices of their nodes. The output
* scene does still contain nodes, however, there is only a * scene does still contain nodes, however, there is only a
@ -149,44 +212,87 @@ enum aiPostProcessSteps
*/ */
aiProcess_PreTransformVertices = 0x100, aiProcess_PreTransformVertices = 0x100,
// -------------------------------------------------------------------------
/** <hr>Limits the number of bones simultaneously affecting a single vertex /** <hr>Limits the number of bones simultaneously affecting a single vertex
* to a maximum value. If any vertex is affected by more than that number * to a maximum value.
* of bones, the least important vertex weights are removed and the remaining *
* vertex weights are renormalized so that the weights still sum up to 1. * If any vertex is affected by more than that number of bones, the least
* The default bone weight limit is 4 (defined as AI_LMW_MAX_WEIGHTS in * important vertex weights are removed and the remaining vertex weights are
* LimitBoneWeightsProcess.h), but you can use the aiSetBoneWeightLimit * renormalized so that the weights still sum up to 1.
* function to supply your own limit to the post processing step. * The default bone weight limit is 4 (defined as <tt>#AI_LMW_MAX_WEIGHTS</tt> in
* * aiConfig.h), but you can use the <tt>#AI_CONFIG_PP_LBW_MAX_WEIGHTS</tt> setting to
* If you intend to perform the skinning in hardware, this post processing step * supply your own limit to the post processing step.
* might be of interest for you. *
* If you intend to perform the skinning in hardware, this post processing
* step might be of interest for you.
*/ */
aiProcess_LimitBoneWeights = 0x200, aiProcess_LimitBoneWeights = 0x200,
/** <hr>Validates the aiScene data structure before it is returned. // -------------------------------------------------------------------------
/** <hr>Validates the imported scene data structure
* This makes sure that all indices are valid, all animations and * This makes sure that all indices are valid, all animations and
* bones are linked correctly, all material are correct and so on ... * bones are linked correctly, all material references are correct .. etc.
* This is primarily intended for our internal debugging stuff, *
* however, it could be of interest for applications like editors * It is recommended to capture Assimp's log output if you use this flag,
* where stability is more important than loading performance. * so you can easily find ot what's actually wrong if a file fails the
* validation. The validator is quite rude and will find *all*
* inconsistencies in the data structure ... plugin developers are
* recommended to use it to debug their loaders. There are two types of
* validation failures:
* <ul>
* <li>Error: There's something wrong with the imported data. Further
* postprocessing is not possible and the data is not usable at all.
* The import fails. #Importer::GetErrorString() or #aiGetErrorString()
* carry the error message around.</li>
* <li>Warning: There are some minor issues (e.g. 1000000 animation
* keyframes with the same time), but further postprocessing and use
* of the data structure is still safe. Warning details are written
* to the log file, <tt>#AI_SCENE_FLAGS_VALIDATION_WARNING</tt> is set
* in #aiScene::mFlags</li>
* </ul>
*
* This post-processing step is not time-consuming. It's use is not
* compulsory, but recommended.
*/ */
aiProcess_ValidateDataStructure = 0x400, aiProcess_ValidateDataStructure = 0x400,
/** <hr>Reorders triangles for vertex cache locality and thus better performance. // -------------------------------------------------------------------------
/** <hr>Reorders triangles for better vertex cache locality.
*
* The step tries to improve the ACMR (average post-transform vertex cache * The step tries to improve the ACMR (average post-transform vertex cache
* miss ratio) for all meshes. The step runs in O(n) and is roughly * miss ratio) for all meshes. The implementation runs in O(n) and is
* basing on the algorithm described in this paper: * roughly based on the 'tipsify' algorithm (see <a href="
* http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf">this
* paper</a>).
*
* If you intend to render huge models in hardware, this step might
* be of interest for you. The <tt>#AI_CONFIG_PP_ICL_PTCACHE_SIZE</tt>config
* setting can be used to fine-tune the cache optimization.
*/ */
aiProcess_ImproveCacheLocality = 0x800, aiProcess_ImproveCacheLocality = 0x800,
/** <hr>Searches for redundant materials and removes them. // -------------------------------------------------------------------------
/** <hr>Searches for redundant/unreferenced materials and removes them.
* *
* This is especially useful in combination with the PretransformVertices * This is especially useful in combination with the
* and OptimizeGraph steps. Both steps join small meshes, but they * #aiProcess_PretransformVertices and #aiProcess_OptimizeMeshes flags.
* can't do that if two meshes have different materials. * Both join small meshes with equal characteristics, but they can't do
*/ * their work if two meshes have different materials. Because several
* material settings are always lost during Assimp's import filters,
* (and because many exporters don't check for redundant materials), huge
* models often have materials which are are defined several times with
* exactly the same settings ..
*
* Several material settings not contributing to the final appearance of
* a surface are ignored in all comparisons ... the material name is
* one of them. So, if you're passing additional information through the
* content pipeline (probably using using *magic* material names), don't
* specify this flag. Alternatively take a look at the
* <tt>#AI_CONFIG_PP_RRM_EXCLUDE_LIST</tt> setting.
*/
aiProcess_RemoveRedundantMaterials = 0x1000, aiProcess_RemoveRedundantMaterials = 0x1000,
// -------------------------------------------------------------------------
/** <hr>This step tries to determine which meshes have normal vectors /** <hr>This step tries to determine which meshes have normal vectors
* that are facing inwards. The algorithm is simple but effective: * that are facing inwards. The algorithm is simple but effective:
* the bounding box of all vertices + their normals is compared against * the bounding box of all vertices + their normals is compared against
@ -198,7 +304,7 @@ enum aiPostProcessSteps
*/ */
aiProcess_FixInfacingNormals = 0x2000, aiProcess_FixInfacingNormals = 0x2000,
// -------------------------------------------------------------------------
/** <hr>This step splits meshes with more than one primitive type in /** <hr>This step splits meshes with more than one primitive type in
* homogeneous submeshes. * homogeneous submeshes.
* *
@ -206,16 +312,17 @@ enum aiPostProcessSteps
* returns, just one bit is set in aiMesh::mPrimitiveTypes. This is * returns, just one bit is set in aiMesh::mPrimitiveTypes. This is
* especially useful for real-time rendering where point and line * especially useful for real-time rendering where point and line
* primitives are often ignored or rendered separately. * primitives are often ignored or rendered separately.
* You can use the AI_CONFIG_PP_SBP_REMOVE option to specify which * You can use the <tt>#AI_CONFIG_PP_SBP_REMOVE</tt> option to specify which
* primitive types you need. This can be used to easily exclude * primitive types you need. This can be used to easily exclude
* lines and points, which are rarely used, from the import. * lines and points, which are rarely used, from the import.
*/ */
aiProcess_SortByPType = 0x8000, aiProcess_SortByPType = 0x8000,
// -------------------------------------------------------------------------
/** <hr>This step searches all meshes for degenerated primitives and /** <hr>This step searches all meshes for degenerated primitives and
* converts them to proper lines or points. * converts them to proper lines or points.
* *
* A face is degenerated if one or more of its points are identical. * A face is 'degenerated' if one or more of its points are identical.
* To have the degenerated stuff not only detected and collapsed but * To have the degenerated stuff not only detected and collapsed but
* also removed, try one of the following procedures: * also removed, try one of the following procedures:
* <br><b>1.</b> (if you support lines&points for rendering but don't * <br><b>1.</b> (if you support lines&points for rendering but don't
@ -224,7 +331,7 @@ enum aiPostProcessSteps
* <li>Specify the #aiProcess_FindDegenerates flag. * <li>Specify the #aiProcess_FindDegenerates flag.
* </li> * </li>
* <li>Set the <tt>AI_CONFIG_PP_FD_REMOVE</tt> option to 1. This will * <li>Set the <tt>AI_CONFIG_PP_FD_REMOVE</tt> option to 1. This will
* cause the step to remove degenerated triangles rom the import * cause the step to remove degenerated triangles from the import
* as soon as they're detected. They won't pass any further * as soon as they're detected. They won't pass any further
* pipeline steps. * pipeline steps.
* </li> * </li>
@ -249,6 +356,7 @@ enum aiPostProcessSteps
*/ */
aiProcess_FindDegenerates = 0x10000, aiProcess_FindDegenerates = 0x10000,
// -------------------------------------------------------------------------
/** <hr>This step searches all meshes for invalid data, such as zeroed /** <hr>This step searches all meshes for invalid data, such as zeroed
* normal vectors or invalid UV coords and removes them. * normal vectors or invalid UV coords and removes them.
* *
@ -259,35 +367,88 @@ enum aiPostProcessSteps
*/ */
aiProcess_FindInvalidData = 0x20000, aiProcess_FindInvalidData = 0x20000,
// -------------------------------------------------------------------------
/** <hr>This step converts non-UV mappings (such as spherical or /** <hr>This step converts non-UV mappings (such as spherical or
* cylindrical) to proper UV mapping channels. * cylindrical apping) to proper texture coordinate channels.
* *
* Most applications will support UV mapping only, so you will * Most applications will support UV mapping only, so you will
* probably want to specify this step in every case. * probably want to specify this step in every case. Note tha Assimp is not
*/ * always able to match the original mapping implementation of the
* 3d app which produced a model perfectly. It's always better to let the
* father app compute the UV channels, at least 3ds max, maja, blender,
* lightwave, modo, ... are able to achieve this.
*
* @note If this step is not requested, you'll need to process the
* <tt>#AI_MATKEY_MAPPING<7tt> material property in order to display all assets
* properly.
*/
aiProcess_GenUVCoords = 0x40000, aiProcess_GenUVCoords = 0x40000,
/** <hr>This step pre-transforms UV coordinates by the UV transformations // -------------------------------------------------------------------------
* (such as scalings or rotations). /** <hr>This step applies per-texture UV transformations and bakes
* * them to stand-alone vtexture coordinate channelss.
* UV transformations are specified per-texture - see the *
* AI_MATKEY_UVTRANSFORM key for more information on this topic. * UV transformations are specified per-texture - see the
* This step finds all textures with transformed input UV * <tt>#AI_MATKEY_UVTRANSFORM</tt> material key for more information.
* coordinates and generates a new, transformed, UV channel for it. * This step processes all textures with
* Most applications won't support UV transformations, so you will * transformed input UV coordinates and generates new (pretransformed) UV channel
* probably want to specify this step in every case. * which replace the old channel. Most applications won't support UV
* transformations, so you will probably want to specify this step.
* todo ... rewrite doc *
* @note UV transformations are usually implemented in realtime apps by
* transforming texture coordinates at vertex shader stage with a 3x3
* (homogenous) transformation matrix.
*/ */
aiProcess_TransformUVCoords = 0x80000, aiProcess_TransformUVCoords = 0x80000,
// -------------------------------------------------------------------------
/** <hr>This step searches for duplicate meshes and replaces duplicates /** <hr>This step searches for duplicate meshes and replaces duplicates
* with references to the first mesh. * with references to the first mesh.
* *
* todo ... add more doc * This step takes a while, don't use it if you have no time.
* It's main purpose is to workaround the limitation that many export
* file formats don't support instanced meshes, so exporters need to
* duplicate meshes. This step removes the duplicates again. Please
* note that Assimp does currently not support per-node material
* assignment to meshes, which means that identical meshes with
* differnent materials are currently *not* joined, although this is
* planned for future versions.
*/
aiProcess_FindInstances = 0x100000,
// -------------------------------------------------------------------------
/** <hr>This step flips all UV coordinates along the y-axis and adjusts
* material settings and bitangents accordingly.
* <br><b>Output UV coordinate system:</b>
* @code
* 0y|0y ---------- 1x|0y
* | |
* | |
* | |
* 0x|1y ---------- 1x|1y
* @endcode
*
* You'll probably want to consider this flag if you use Direct3D for
* rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this
* setting and boundles all conversions typically required for D3D-based
* applications.
*/ */
aiProcess_FindInstances = 0x100000 aiProcess_FlipUVs = 0x80000000, /* don't change */
// -------------------------------------------------------------------------
/** <hr>This step adjusts the output face winding order to be clock-wise.
*
* The default face winding order is counter-clockwise.
* <br><b>Output face order:</b>
* @code
* x0
*
* x1
* x2
* @endcode
*/
aiProcess_FlipWindingOrder = 0x40000000 /* don't change */
// aiProcess_GenEntityMeshes = 0x100000, // aiProcess_GenEntityMeshes = 0x100000,
@ -296,6 +457,23 @@ enum aiPostProcessSteps
}; };
// ---------------------------------------------------------------------------------------
/** @def aiProcess_ConvertToLeftHanded
* @brief Shortcut flag for Direct3D-based applications.
*
* Supersedes the #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and
* #aiProcess_FlipWindingOrder flags. The output data matches Direct3D's conventions:
* left-handed geometry, upper-left origin for UV coordinates and finally clockwise
* face order, suitable for CCW culling.
*
* @deprecated
*/
#define aiProcess_ConvertToLeftHanded ( \
aiProcess_MakeLeftHanded | \
aiProcess_FlipUVs | \
0 )
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
/** @def aiProcessPreset_TargetRealtimeUse_Fast /** @def aiProcessPreset_TargetRealtimeUse_Fast
* @brief Default postprocess configuration optimizing the data for real-time rendering. * @brief Default postprocess configuration optimizing the data for real-time rendering.
@ -310,14 +488,14 @@ enum aiPostProcessSteps
* Some of them offer further configurable properties, some of them might not be of * Some of them offer further configurable properties, some of them might not be of
* use for you so it might be better to not specify them. * use for you so it might be better to not specify them.
*/ */
#define aiProcessPreset_TargetRealtime_Fast \ #define aiProcessPreset_TargetRealtime_Fast ( \
aiProcess_CalcTangentSpace | \ aiProcess_CalcTangentSpace | \
aiProcess_GenNormals | \ aiProcess_GenNormals | \
aiProcess_JoinIdenticalVertices | \ aiProcess_JoinIdenticalVertices | \
aiProcess_Triangulate | \ aiProcess_Triangulate | \
aiProcess_GenUVCoords | \ aiProcess_GenUVCoords | \
aiProcess_SortByPType | \ aiProcess_SortByPType | \
0 0 )
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
/** @def aiProcessPreset_TargetRealtime_Quality /** @def aiProcessPreset_TargetRealtime_Quality
@ -331,11 +509,11 @@ enum aiPostProcessSteps
* If you're using DirectX, don't forget to combine this value with * If you're using DirectX, don't forget to combine this value with
* the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations
* in your application apply the #aiProcess_TransformUVCoords step, too. * in your application apply the #aiProcess_TransformUVCoords step, too.
* @note Please take the time to read the doc to the steps enabled by this preset. * @note Please take the time to read the doc for the steps enabled by this preset.
* Some of them offer further configurable properties, some of them might not be of * Some of them offer further configurable properties, some of them might not be of
* use for you so it might be better to not specify them. * use for you so it might be better to not specify them.
*/ */
#define aiProcessPreset_TargetRealtime_Quality \ #define aiProcessPreset_TargetRealtime_Quality ( \
aiProcess_CalcTangentSpace | \ aiProcess_CalcTangentSpace | \
aiProcess_GenSmoothNormals | \ aiProcess_GenSmoothNormals | \
aiProcess_JoinIdenticalVertices | \ aiProcess_JoinIdenticalVertices | \
@ -348,7 +526,7 @@ enum aiPostProcessSteps
aiProcess_SortByPType | \ aiProcess_SortByPType | \
aiProcess_FindDegenerates | \ aiProcess_FindDegenerates | \
aiProcess_FindInvalidData | \ aiProcess_FindInvalidData | \
0 0 )
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
/** @def aiProcessPreset_TargetRealtime_MaxQuality /** @def aiProcessPreset_TargetRealtime_MaxQuality
@ -360,16 +538,16 @@ enum aiPostProcessSteps
* *
* If you're using DirectX, don't forget to combine this value with * If you're using DirectX, don't forget to combine this value with
* the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations
* in your application apply the #aiProcess_TransformUVCoords step, too. * in your application, apply the #aiProcess_TransformUVCoords step, too.
* @note Please take the time to read the doc to the steps enabled by this preset. * @note Please take the time to read the doc for the steps enabled by this preset.
* Some of them offer further configurable properties, some of them might not be of * Some of them offer further configurable properties, some of them might not be of
* use for you so it might be better to not specify them. * use for you so it might be better to not specify them.
*/ */
#define aiProcessPreset_TargetRealtime_MaxQuality \ #define aiProcessPreset_TargetRealtime_MaxQuality ( \
aiProcessPreset_TargetRealtime_Quality | \ aiProcessPreset_TargetRealtime_Quality | \
aiProcess_FindInstances | \ aiProcess_FindInstances | \
aiProcess_ValidateDataStructure | \ aiProcess_ValidateDataStructure | \
0 0 )
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -221,11 +221,11 @@ void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vector<ai
{ {
ai_assert( pNode->mChannelIndex < pTransforms.size()); ai_assert( pNode->mChannelIndex < pTransforms.size());
pNode->mLocalTransform = pTransforms[pNode->mChannelIndex]; pNode->mLocalTransform = pTransforms[pNode->mChannelIndex];
// update global transform as well
CalculateGlobalTransform( pNode);
} }
// update global transform as well
CalculateGlobalTransform( pNode);
// continue for all children // continue for all children
for( std::vector<SceneAnimNode*>::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it) for( std::vector<SceneAnimNode*>::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it)
UpdateTransforms( *it, pTransforms); UpdateTransforms( *it, pTransforms);

View File

@ -2255,10 +2255,6 @@
RelativePath="..\..\code\ValidateDataStructure.h" RelativePath="..\..\code\ValidateDataStructure.h"
> >
</File> </File>
<Filter
Name="util"
>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="PCH" Name="PCH"