2009-09-05 12:04:32 +00:00
# include "AssimpPCH.h"
# ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
# include <vector>
# include <sstream>
using namespace std ;
2009-09-21 17:41:57 +00:00
//#include "boost/format.hpp"
//#include "boost/foreach.hpp"
2009-09-05 12:04:32 +00:00
using namespace boost ;
# include "OgreImporter.h"
# include "irrXMLWrapper.h"
namespace Assimp
{
namespace Ogre
{
bool OgreImporter : : CanRead ( const std : : string & pFile , Assimp : : IOSystem * pIOHandler , bool checkSig ) const
{
if ( ! checkSig ) //Check File Extension
{
std : : string extension ( " mesh.xml " ) ;
int l = extension . length ( ) ;
return pFile . substr ( pFile . length ( ) - l , l ) = = extension ;
}
else //Check file Header
{
const char * tokens [ ] = { " <mesh> " } ;
return BaseImporter : : SearchFileHeaderForToken ( pIOHandler , pFile , tokens , 1 ) ;
}
}
void OgreImporter : : InternReadFile ( const std : : string & pFile , aiScene * pScene , Assimp : : IOSystem * pIOHandler )
{
m_CurrentFilename = pFile ;
m_CurrentIOHandler = pIOHandler ;
m_CurrentScene = pScene ;
//Open the File:
boost : : scoped_ptr < IOStream > file ( pIOHandler - > Open ( pFile ) ) ;
if ( file . get ( ) = = NULL )
throw new ImportErrorException ( " Failed to open file " + pFile + " . " ) ;
//Read the Mesh File:
boost : : scoped_ptr < CIrrXML_IOStreamReader > mIOWrapper ( new CIrrXML_IOStreamReader ( file . get ( ) ) ) ;
XmlReader * MeshFile = irr : : io : : createIrrXMLReader ( mIOWrapper . get ( ) ) ;
if ( ! MeshFile ) //parse the xml file
throw new ImportErrorException ( " Failed to create XML Reader for " + pFile ) ;
2009-09-05 15:49:23 +00:00
DefaultLogger : : get ( ) - > debug ( " Mesh File opened " ) ;
2009-09-05 12:04:32 +00:00
//Read root Node:
if ( ! ( XmlRead ( MeshFile ) & & string ( MeshFile - > getNodeName ( ) ) = = " mesh " ) )
{
throw new ImportErrorException ( " Root Node is not <mesh>! " + pFile + " " + MeshFile - > getNodeName ( ) ) ;
}
//Go to the submeshs:
if ( ! ( XmlRead ( MeshFile ) & & string ( MeshFile - > getNodeName ( ) ) = = " submeshes " ) )
{
throw new ImportErrorException ( " No <submeshes> node in <mesh> node! " + pFile ) ;
}
2009-09-28 16:53:33 +00:00
//-------------------Read the submesh:-----------------------
SubMesh theSubMesh ;
2009-09-05 12:04:32 +00:00
XmlRead ( MeshFile ) ;
2009-09-28 16:53:33 +00:00
if ( MeshFile - > getNodeName ( ) = = string ( " submesh " ) )
2009-09-05 12:04:32 +00:00
{
2009-09-28 16:53:33 +00:00
theSubMesh . MaterialName = GetAttribute < string > ( MeshFile , " material " ) ;
DefaultLogger : : get ( ) - > debug ( " Loading Submehs with Material: " + theSubMesh . MaterialName ) ;
ReadSubMesh ( theSubMesh , MeshFile ) ;
//Load the Material:
aiMaterial * MeshMat = LoadMaterial ( theSubMesh . MaterialName ) ;
//Set the Material:
if ( m_CurrentScene - > mMaterials )
throw new ImportErrorException ( " only 1 material supported at this time! " ) ;
m_CurrentScene - > mMaterials = new aiMaterial * [ 1 ] ;
m_CurrentScene - > mNumMaterials = 1 ;
m_CurrentScene - > mMaterials [ 0 ] = MeshMat ;
theSubMesh . MaterialIndex = 0 ;
2009-09-05 12:04:32 +00:00
}
2009-09-28 16:53:33 +00:00
//check for second root node:
if ( MeshFile - > getNodeName ( ) = = string ( " submesh " ) )
throw new ImportErrorException ( " more than one submesh in the file, abording! " ) ;
2009-09-13 18:26:54 +00:00
//____________________________________________________________
2009-09-05 12:04:32 +00:00
2009-09-13 18:26:54 +00:00
//-----------------Create the root node-----------------------
2009-09-05 12:04:32 +00:00
pScene - > mRootNode = new aiNode ( " root " ) ;
//link the mesh with the root node:
pScene - > mRootNode - > mMeshes = new unsigned int [ 1 ] ;
pScene - > mRootNode - > mMeshes [ 0 ] = 0 ;
pScene - > mRootNode - > mNumMeshes = 1 ;
2009-09-13 18:26:54 +00:00
//____________________________________________________________
//----------------Load the skeleton: -------------------------------
2009-09-28 16:53:33 +00:00
vector < Bone > Bones ;
vector < Animation > Animations ;
2009-09-13 18:26:54 +00:00
if ( MeshFile - > getNodeName ( ) = = string ( " skeletonlink " ) )
{
string SkeletonFile = GetAttribute < string > ( MeshFile , " name " ) ;
2009-09-28 16:53:33 +00:00
LoadSkeleton ( SkeletonFile , Bones , Animations ) ;
2009-09-13 18:26:54 +00:00
}
2009-09-17 19:05:46 +00:00
else
2009-09-28 16:53:33 +00:00
{
DefaultLogger : : get ( ) - > warn ( " No skeleton file will be loaded " ) ;
2009-09-17 19:05:46 +00:00
DefaultLogger : : get ( ) - > warn ( MeshFile - > getNodeName ( ) ) ;
2009-09-28 16:53:33 +00:00
}
2009-09-13 18:26:54 +00:00
//__________________________________________________________________
2009-09-28 16:53:33 +00:00
CreateAssimpSubMesh ( theSubMesh , Bones ) ;
CreateAssimpSkeleton ( Bones , Animations ) ;
2009-09-05 12:04:32 +00:00
}
void OgreImporter : : GetExtensionList ( std : : string & append )
{
append + = " *.mesh.xml " ;
}
void OgreImporter : : SetupProperties ( const Importer * pImp )
{
m_MaterialLibFilename = pImp - > GetPropertyString ( AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE , " Scene.material " ) ;
}
void OgreImporter : : ReadSubMesh ( SubMesh & theSubMesh , XmlReader * Reader )
{
XmlRead ( Reader ) ;
2009-09-13 18:26:54 +00:00
//TODO: maybe we have alsways just 1 faces and 1 geometry and always in this order. this loop will only work correct, wenn the order
2009-09-05 12:04:32 +00:00
//of faces and geometry changed, and not if we habe more than one of one
2009-09-13 18:26:54 +00:00
while ( Reader - > getNodeName ( ) = = string ( " faces " ) | | string ( Reader - > getNodeName ( ) ) = = " geometry " | | Reader - > getNodeName ( ) = = string ( " boneassignments " ) )
2009-09-05 12:04:32 +00:00
{
if ( string ( Reader - > getNodeName ( ) ) = = " faces " ) //Read the face list
{
//some info logging:
unsigned int NumFaces = GetAttribute < int > ( Reader , " count " ) ;
stringstream ss ; ss < < " Submesh has " < < NumFaces < < " Faces. " ;
2009-09-05 15:49:23 +00:00
DefaultLogger : : get ( ) - > debug ( ss . str ( ) ) ;
2009-09-05 12:04:32 +00:00
while ( XmlRead ( Reader ) & & Reader - > getNodeName ( ) = = string ( " face " ) )
{
Face NewFace ;
NewFace . VertexIndices [ 0 ] = GetAttribute < int > ( Reader , " v1 " ) ;
NewFace . VertexIndices [ 1 ] = GetAttribute < int > ( Reader , " v2 " ) ;
NewFace . VertexIndices [ 2 ] = GetAttribute < int > ( Reader , " v3 " ) ;
if ( Reader - > getAttributeValue ( " v4 " ) ) //this should be supported in the future
{
throw new ImportErrorException ( " Submesh has quads, only traingles are supported! " ) ;
}
2009-09-28 16:53:33 +00:00
theSubMesh . FaceList . push_back ( NewFace ) ;
2009-09-05 12:04:32 +00:00
}
2009-09-13 18:26:54 +00:00
} //end of faces
2009-09-05 12:04:32 +00:00
else if ( string ( Reader - > getNodeName ( ) ) = = " geometry " ) //Read the vertexdata
{
//some info logging:
unsigned int NumVertices = GetAttribute < int > ( Reader , " vertexcount " ) ;
stringstream ss ; ss < < " VertexCount: " < < NumVertices ;
2009-09-05 15:49:23 +00:00
DefaultLogger : : get ( ) - > debug ( ss . str ( ) ) ;
2009-09-05 12:04:32 +00:00
//General Informations about vertices
XmlRead ( Reader ) ;
if ( ! ( Reader - > getNodeName ( ) = = string ( " vertexbuffer " ) ) )
{
throw new ImportErrorException ( " vertexbuffer node is not first in geometry node! " ) ;
}
2009-09-28 16:53:33 +00:00
theSubMesh . HasPositions = GetAttribute < bool > ( Reader , " positions " ) ;
theSubMesh . HasNormals = GetAttribute < bool > ( Reader , " normals " ) ;
2009-09-17 19:05:46 +00:00
if ( ! Reader - > getAttributeValue ( " texture_coords " ) ) //we can have 1 or 0 uv channels, and if the mesh has no uvs, it also doesn't have the attribute
2009-09-28 16:53:33 +00:00
theSubMesh . NumUvs = 0 ;
2009-09-17 19:05:46 +00:00
else
2009-09-28 16:53:33 +00:00
theSubMesh . NumUvs = GetAttribute < int > ( Reader , " texture_coords " ) ;
if ( theSubMesh . NumUvs > 1 )
2009-09-05 12:04:32 +00:00
throw new ImportErrorException ( " too many texcoords (just 1 supported!) " ) ;
//read all the vertices:
XmlRead ( Reader ) ;
while ( Reader - > getNodeName ( ) = = string ( " vertex " ) )
{
//read all vertex attributes:
//Position
2009-09-28 16:53:33 +00:00
if ( theSubMesh . HasPositions )
2009-09-05 12:04:32 +00:00
{
XmlRead ( Reader ) ;
aiVector3D NewPos ;
NewPos . x = GetAttribute < float > ( Reader , " x " ) ;
NewPos . y = GetAttribute < float > ( Reader , " y " ) ;
NewPos . z = GetAttribute < float > ( Reader , " z " ) ;
2009-09-28 16:53:33 +00:00
theSubMesh . Positions . push_back ( NewPos ) ;
2009-09-05 12:04:32 +00:00
}
//Normal
2009-09-28 16:53:33 +00:00
if ( theSubMesh . HasNormals )
2009-09-05 12:04:32 +00:00
{
XmlRead ( Reader ) ;
aiVector3D NewNormal ;
NewNormal . x = GetAttribute < float > ( Reader , " x " ) ;
NewNormal . y = GetAttribute < float > ( Reader , " y " ) ;
NewNormal . z = GetAttribute < float > ( Reader , " z " ) ;
2009-09-28 16:53:33 +00:00
theSubMesh . Normals . push_back ( NewNormal ) ;
2009-09-05 12:04:32 +00:00
}
//Uv:
2009-09-28 16:53:33 +00:00
if ( 1 = = theSubMesh . NumUvs )
2009-09-05 12:04:32 +00:00
{
XmlRead ( Reader ) ;
aiVector3D NewUv ;
NewUv . x = GetAttribute < float > ( Reader , " u " ) ;
2009-09-05 15:49:23 +00:00
NewUv . y = GetAttribute < float > ( Reader , " v " ) * ( - 1 ) + 1 ; //flip the uv vertikal, blender exports them so!
2009-09-28 16:53:33 +00:00
theSubMesh . Uvs . push_back ( NewUv ) ;
2009-09-05 12:04:32 +00:00
}
XmlRead ( Reader ) ;
}
2009-09-13 18:26:54 +00:00
} //end of "geometry
else if ( string ( Reader - > getNodeName ( ) ) = = " boneassignments " )
{
2009-09-28 16:53:33 +00:00
theSubMesh . Weights . resize ( theSubMesh . Positions . size ( ) ) ;
2009-09-13 18:26:54 +00:00
while ( XmlRead ( Reader ) & & Reader - > getNodeName ( ) = = string ( " vertexboneassignment " ) )
{
Weight NewWeight ;
unsigned int VertexId = GetAttribute < int > ( Reader , " vertexindex " ) ;
NewWeight . BoneId = GetAttribute < int > ( Reader , " boneindex " ) ;
NewWeight . Value = GetAttribute < float > ( Reader , " weight " ) ;
2009-09-28 16:53:33 +00:00
theSubMesh . BonesUsed = max ( theSubMesh . BonesUsed , NewWeight . BoneId + 1 ) ; //calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0)
2009-09-13 18:26:54 +00:00
2009-09-28 16:53:33 +00:00
theSubMesh . Weights [ VertexId ] . push_back ( NewWeight ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//XmlRead(Reader);//Once i had this line, and than i got only every second boneassignment, but my first test models had even boneassignment counts, so i thougt, everything would work. And yes, i HATE irrXML!!!
2009-09-13 18:26:54 +00:00
}
} //end of boneassignments
2009-09-05 12:04:32 +00:00
}
2009-09-28 16:53:33 +00:00
DefaultLogger : : get ( ) - > debug ( str ( format ( " Positionen: %1% Normale: %2% TexCoords: %3% " ) % theSubMesh . Positions . size ( ) % theSubMesh . Normals . size ( ) % theSubMesh . Uvs . size ( ) ) ) ;
2009-09-17 19:05:46 +00:00
DefaultLogger : : get ( ) - > warn ( Reader - > getNodeName ( ) ) ;
2009-09-13 18:26:54 +00:00
2009-09-05 12:04:32 +00:00
2009-09-13 18:26:54 +00:00
//---------------Make all Vertexes unique: (this is required by assimp)-----------------------
2009-09-28 16:53:33 +00:00
vector < Face > UniqueFaceList ( theSubMesh . FaceList . size ( ) ) ;
unsigned int UniqueVertexCount = theSubMesh . FaceList . size ( ) * 3 ; //*3 because each face consists of 3 vertexes, because we only support triangles^^
vector < aiVector3D > UniquePositions ( UniqueVertexCount ) ;
vector < aiVector3D > UniqueNormals ( UniqueVertexCount ) ;
vector < aiVector3D > UniqueUvs ( UniqueVertexCount ) ;
vector < vector < Weight > > UniqueWeights ( UniqueVertexCount ) ;
for ( unsigned int i = 0 ; i < theSubMesh . FaceList . size ( ) ; + + i )
2009-09-05 12:04:32 +00:00
{
2009-09-28 16:53:33 +00:00
//We precalculate the index vlaues her, because we need them in all vertex attributes
unsigned int Vertex1 = theSubMesh . FaceList [ i ] . VertexIndices [ 0 ] ;
unsigned int Vertex2 = theSubMesh . FaceList [ i ] . VertexIndices [ 1 ] ;
unsigned int Vertex3 = theSubMesh . FaceList [ i ] . VertexIndices [ 2 ] ;
UniquePositions [ 3 * i + 0 ] = theSubMesh . Positions [ Vertex1 ] ;
UniquePositions [ 3 * i + 1 ] = theSubMesh . Positions [ Vertex2 ] ;
UniquePositions [ 3 * i + 2 ] = theSubMesh . Positions [ Vertex3 ] ;
2009-09-05 12:04:32 +00:00
2009-09-28 16:53:33 +00:00
UniqueNormals [ 3 * i + 0 ] = theSubMesh . Normals [ Vertex1 ] ;
UniqueNormals [ 3 * i + 1 ] = theSubMesh . Normals [ Vertex2 ] ;
UniqueNormals [ 3 * i + 2 ] = theSubMesh . Normals [ Vertex3 ] ;
2009-09-05 12:04:32 +00:00
2009-09-28 16:53:33 +00:00
if ( 1 = = theSubMesh . NumUvs )
2009-09-17 19:05:46 +00:00
{
2009-09-28 16:53:33 +00:00
UniqueUvs [ 3 * i + 0 ] = theSubMesh . Uvs [ Vertex1 ] ;
UniqueUvs [ 3 * i + 1 ] = theSubMesh . Uvs [ Vertex2 ] ;
UniqueUvs [ 3 * i + 2 ] = theSubMesh . Uvs [ Vertex3 ] ;
2009-09-17 19:05:46 +00:00
}
2009-09-05 12:04:32 +00:00
2009-09-28 16:53:33 +00:00
UniqueWeights [ 3 * i + 0 ] = theSubMesh . Weights [ Vertex1 ] ;
UniqueWeights [ 3 * i + 1 ] = theSubMesh . Weights [ Vertex2 ] ;
UniqueWeights [ 3 * i + 2 ] = theSubMesh . Weights [ Vertex3 ] ;
2009-09-13 18:26:54 +00:00
2009-09-28 16:53:33 +00:00
//The indexvalues a just continuous numbers (0, 1, 2, 3, 4, 5, 6...)
2009-09-05 12:04:32 +00:00
UniqueFaceList [ i ] . VertexIndices [ 0 ] = 3 * i + 0 ;
UniqueFaceList [ i ] . VertexIndices [ 1 ] = 3 * i + 1 ;
UniqueFaceList [ i ] . VertexIndices [ 2 ] = 3 * i + 2 ;
}
2009-09-13 18:26:54 +00:00
//_________________________________________________________________________________________
2009-09-05 12:04:32 +00:00
2009-09-28 16:53:33 +00:00
//now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
theSubMesh . FaceList . swap ( UniqueFaceList ) ;
theSubMesh . Positions . swap ( UniquePositions ) ;
theSubMesh . Normals . swap ( UniqueNormals ) ;
theSubMesh . Uvs . swap ( UniqueUvs ) ;
theSubMesh . Weights . swap ( UniqueWeights ) ;
}
2009-09-05 12:04:32 +00:00
2009-09-13 18:26:54 +00:00
2009-09-28 16:53:33 +00:00
void OgreImporter : : CreateAssimpSubMesh ( const SubMesh & theSubMesh , const vector < Bone > & Bones )
{
2009-09-05 12:04:32 +00:00
//Mesh is fully loaded, copy it into the aiScene:
if ( m_CurrentScene - > mNumMeshes ! = 0 )
throw new ImportErrorException ( " Currently only one mesh per File is allowed!! " ) ;
aiMesh * NewAiMesh = new aiMesh ( ) ;
2009-09-28 16:53:33 +00:00
//Attach the mesh to the scene:
m_CurrentScene - > mNumMeshes = 1 ;
m_CurrentScene - > mMeshes = new aiMesh * ;
m_CurrentScene - > mMeshes [ 0 ] = NewAiMesh ;
2009-09-05 12:04:32 +00:00
//Positions
2009-09-28 16:53:33 +00:00
NewAiMesh - > mVertices = new aiVector3D [ theSubMesh . Positions . size ( ) ] ;
memcpy ( NewAiMesh - > mVertices , & theSubMesh . Positions [ 0 ] , theSubMesh . Positions . size ( ) * sizeof ( aiVector3D ) ) ;
NewAiMesh - > mNumVertices = theSubMesh . Positions . size ( ) ;
2009-09-05 12:04:32 +00:00
//Normals
2009-09-28 16:53:33 +00:00
NewAiMesh - > mNormals = new aiVector3D [ theSubMesh . Normals . size ( ) ] ;
memcpy ( NewAiMesh - > mNormals , & theSubMesh . Normals [ 0 ] , theSubMesh . Normals . size ( ) * sizeof ( aiVector3D ) ) ;
2009-09-05 12:04:32 +00:00
//Uvs
2009-09-28 16:53:33 +00:00
if ( 0 ! = theSubMesh . NumUvs )
2009-09-17 19:05:46 +00:00
{
NewAiMesh - > mNumUVComponents [ 0 ] = 2 ;
2009-09-28 16:53:33 +00:00
NewAiMesh - > mTextureCoords [ 0 ] = new aiVector3D [ theSubMesh . Uvs . size ( ) ] ;
memcpy ( NewAiMesh - > mTextureCoords [ 0 ] , & theSubMesh . Uvs [ 0 ] , theSubMesh . Uvs . size ( ) * sizeof ( aiVector3D ) ) ;
2009-09-17 19:05:46 +00:00
}
2009-09-05 12:04:32 +00:00
2009-09-28 16:53:33 +00:00
//---------------------------------------- Bones --------------------------------------------
//Copy the weights in in Bone-Vertices Struktur
//(we have them in a Vertex-Bones Struktur, this is much easier for making them unique, which is required by assimp
vector < vector < aiVertexWeight > > aiWeights ( theSubMesh . BonesUsed ) ; //now the outer list are the bones, and the inner vector the vertices
for ( unsigned int VertexId = 0 ; VertexId < theSubMesh . Weights . size ( ) ; + + VertexId ) //iterate over all vertices
{
for ( unsigned int BoneId = 0 ; BoneId < theSubMesh . Weights [ VertexId ] . size ( ) ; + + BoneId ) //iterate over all bones
{
aiVertexWeight NewWeight ;
NewWeight . mVertexId = VertexId ; //the current Vertex, we can't use the Id form the submehs weights, because they are bone id's
NewWeight . mWeight = theSubMesh . Weights [ VertexId ] [ BoneId ] . Value ;
aiWeights [ theSubMesh . Weights [ VertexId ] [ BoneId ] . BoneId ] . push_back ( NewWeight ) ;
}
}
vector < aiBone * > aiBones ;
aiBones . reserve ( theSubMesh . BonesUsed ) ; //the vector might be smaller, because there might be empty bones (bones that are not attached to any vertex)
//create all the bones and fill them with informations
for ( unsigned int i = 0 ; i < theSubMesh . BonesUsed ; + + i )
{
if ( aiWeights [ i ] . size ( ) > 0 )
{
aiBone * NewBone = new aiBone ( ) ;
NewBone - > mNumWeights = aiWeights [ i ] . size ( ) ;
NewBone - > mWeights = new aiVertexWeight [ aiWeights [ i ] . size ( ) ] ;
memcpy ( NewBone - > mWeights , & ( aiWeights [ i ] [ 0 ] ) , sizeof ( aiVertexWeight ) * aiWeights [ i ] . size ( ) ) ;
NewBone - > mName = Bones [ i ] . Name ; //The bone list should be sorted after its ids, this was done in LoadSkeleton
NewBone - > mOffsetMatrix = aiMatrix4x4 ( Bones [ i ] . WorldToBoneSpace ) . Inverse ( ) ; //we suggest, that the mesh space is the world space!
aiBones . push_back ( NewBone ) ;
}
}
NewAiMesh - > mNumBones = aiBones . size ( ) ;
NewAiMesh - > mBones = new aiBone * [ aiBones . size ( ) ] ;
memcpy ( NewAiMesh - > mBones , & ( aiBones [ 0 ] ) , aiBones . size ( ) * sizeof ( aiBone * ) ) ;
//______________________________________________________________________________________________________
2009-09-13 18:26:54 +00:00
2009-09-05 12:04:32 +00:00
//Faces
2009-09-28 16:53:33 +00:00
NewAiMesh - > mFaces = new aiFace [ theSubMesh . FaceList . size ( ) ] ;
for ( unsigned int i = 0 ; i < theSubMesh . FaceList . size ( ) ; + + i )
2009-09-05 12:04:32 +00:00
{
NewAiMesh - > mFaces [ i ] . mNumIndices = 3 ;
NewAiMesh - > mFaces [ i ] . mIndices = new unsigned int [ 3 ] ;
2009-09-28 16:53:33 +00:00
NewAiMesh - > mFaces [ i ] . mIndices [ 0 ] = theSubMesh . FaceList [ i ] . VertexIndices [ 0 ] ;
NewAiMesh - > mFaces [ i ] . mIndices [ 1 ] = theSubMesh . FaceList [ i ] . VertexIndices [ 1 ] ;
NewAiMesh - > mFaces [ i ] . mIndices [ 2 ] = theSubMesh . FaceList [ i ] . VertexIndices [ 2 ] ;
2009-09-05 12:04:32 +00:00
}
2009-09-28 16:53:33 +00:00
NewAiMesh - > mNumFaces = theSubMesh . FaceList . size ( ) ;
2009-09-05 12:04:32 +00:00
2009-09-28 16:53:33 +00:00
//Link the material:
NewAiMesh - > mMaterialIndex = theSubMesh . MaterialIndex ; //the index is set by the function who called ReadSubMesh
2009-09-05 12:04:32 +00:00
}
2009-09-28 16:53:33 +00:00
aiMaterial * OgreImporter : : LoadMaterial ( const std : : string MaterialName )
2009-09-05 12:04:32 +00:00
{
MaterialHelper * NewMaterial = new MaterialHelper ( ) ;
2009-09-21 17:41:57 +00:00
aiString ts ( MaterialName . c_str ( ) ) ;
NewMaterial - > AddProperty ( & ts , AI_MATKEY_NAME ) ;
2009-09-05 12:04:32 +00:00
/*For bettetr understanding of the material parser, here is a material example file:
material Sarg
{
receive_shadows on
technique
{
pass
{
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 0.640000 0.640000 0.640000 1.000000
specular 0.500000 0.500000 0.500000 1.000000 12.500000
emissive 0.000000 0.000000 0.000000 1.000000
texture_unit
{
texture SargTextur . tga
tex_address_mode wrap
filtering linear linear none
}
}
}
}
*/
string MaterialFileName = m_CurrentFilename . substr ( 0 , m_CurrentFilename . find ( ' . ' ) ) + " .material " ;
DefaultLogger : : get ( ) - > info ( str ( format ( " Trying to load %1% " ) % MaterialFileName ) ) ;
//Read the file into memory and put it in a stringstream
stringstream ss ;
{ // after this block, the temporarly loaded data will be released
IOStream * MatFilePtr = m_CurrentIOHandler - > Open ( MaterialFileName ) ;
if ( NULL = = MatFilePtr )
{
MatFilePtr = m_CurrentIOHandler - > Open ( m_MaterialLibFilename ) ;
if ( NULL = = MatFilePtr )
{
DefaultLogger : : get ( ) - > error ( m_MaterialLibFilename + " and " + MaterialFileName + " could not be opned, Material will not be loaded! " ) ;
return NewMaterial ;
}
}
scoped_ptr < IOStream > MaterialFile ( MatFilePtr ) ;
vector < char > FileData ( MaterialFile - > FileSize ( ) ) ;
MaterialFile - > Read ( & FileData [ 0 ] , MaterialFile - > FileSize ( ) , 1 ) ;
BaseImporter : : ConvertToUTF8 ( FileData ) ;
ss < < & FileData [ 0 ] ;
}
string Line ;
ss > > Line ;
unsigned int Level = 0 ; //Hierarchielevels in the material file, like { } blocks into another
while ( ! ss . eof ( ) )
{
if ( Line = = " material " )
{
ss > > Line ;
if ( Line = = MaterialName ) //Load the next material
{
ss > > Line ;
if ( Line ! = " { " )
throw new ImportErrorException ( " empty material! " ) ;
while ( Line ! = " } " ) //read until the end of the material
{
//Proceed to the first technique
ss > > Line ;
if ( Line = = " technique " )
{
ss > > Line ;
if ( Line ! = " { " )
throw new ImportErrorException ( " empty technique! " ) ;
while ( Line ! = " } " ) //read until the end of the technique
{
ss > > Line ;
if ( Line = = " pass " )
{
ss > > Line ;
if ( Line ! = " { " )
throw new ImportErrorException ( " empty pass! " ) ;
while ( Line ! = " } " ) //read until the end of the pass
{
ss > > Line ;
if ( Line = = " ambient " )
{
//read the ambient light values:
}
else if ( Line = = " diffuse " )
{
}
else if ( Line = = " specular " )
{
}
else if ( Line = = " emmisive " )
{
}
else if ( Line = = " texture_unit " )
{
ss > > Line ;
if ( Line ! = " { " )
throw new ImportErrorException ( " empty texture unit! " ) ;
while ( Line ! = " } " ) //read until the end of the texture_unit
{
ss > > Line ;
if ( Line = = " texture " )
{
ss > > Line ;
2009-09-21 17:41:57 +00:00
aiString ts ( Line . c_str ( ) ) ;
NewMaterial - > AddProperty ( & ts , AI_MATKEY_TEXTURE ( aiTextureType_DIFFUSE , 0 ) ) ;
2009-09-05 12:04:32 +00:00
}
} //end of texture unit
}
}
}
} //end of technique
2009-09-05 15:49:23 +00:00
2009-09-05 12:04:32 +00:00
}
2009-09-05 15:49:23 +00:00
DefaultLogger : : get ( ) - > info ( Line ) ;
//read informations from a custom material:
if ( Line = = " set " )
{
ss > > Line ;
if ( Line = = " $specular " ) //todo load this values:
{
}
if ( Line = = " $diffuse " )
{
}
if ( Line = = " $ambient " )
{
}
if ( Line = = " $colormap " )
{
ss > > Line ;
2009-09-21 17:41:57 +00:00
aiString ts ( Line . c_str ( ) ) ;
NewMaterial - > AddProperty ( & ts , AI_MATKEY_TEXTURE ( aiTextureType_DIFFUSE , 0 ) ) ;
2009-09-05 15:49:23 +00:00
}
if ( Line = = " $normalmap " )
{
ss > > Line ;
2009-09-21 17:41:57 +00:00
aiString ts ( Line . c_str ( ) ) ;
NewMaterial - > AddProperty ( & ts , AI_MATKEY_TEXTURE ( aiTextureType_NORMALS , 0 ) ) ;
2009-09-05 15:49:23 +00:00
}
}
2009-09-05 12:04:32 +00:00
} //end of material
}
else { } //this is the wrong material, proceed the file until we reach the next material
}
ss > > Line ;
}
return NewMaterial ;
}
2009-09-28 16:53:33 +00:00
void OgreImporter : : LoadSkeleton ( std : : string FileName , vector < Bone > & Bones , vector < Animation > & Animations )
2009-09-13 18:26:54 +00:00
{
//most likely the skeleton file will only end with .skeleton
//But this is a xml reader, so we need: .skeleton.xml
FileName + = " .xml " ;
DefaultLogger : : get ( ) - > debug ( string ( " Loading Skeleton: " ) + FileName ) ;
//Open the File:
boost : : scoped_ptr < IOStream > File ( m_CurrentIOHandler - > Open ( FileName ) ) ;
if ( NULL = = File . get ( ) )
throw new ImportErrorException ( " Failed to open skeleton file " + FileName + " . " ) ;
//Read the Mesh File:
boost : : scoped_ptr < CIrrXML_IOStreamReader > mIOWrapper ( new CIrrXML_IOStreamReader ( File . get ( ) ) ) ;
XmlReader * SkeletonFile = irr : : io : : createIrrXMLReader ( mIOWrapper . get ( ) ) ;
if ( ! SkeletonFile )
throw new ImportErrorException ( string ( " Failed to create XML Reader for " ) + FileName ) ;
//Quick note: Whoever read this should know this one thing: irrXml fucking sucks!!!
XmlRead ( SkeletonFile ) ;
if ( string ( " skeleton " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " No <skeleton> node in SkeletonFile: " + FileName ) ;
2009-09-17 19:05:46 +00:00
//------------------------------------load bones-----------------------------------------
XmlRead ( SkeletonFile ) ;
if ( string ( " bones " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " No bones node in skeleton " + FileName ) ;
2009-09-13 18:26:54 +00:00
XmlRead ( SkeletonFile ) ;
2009-09-17 19:05:46 +00:00
while ( string ( " bone " ) = = SkeletonFile - > getNodeName ( ) )
2009-09-13 18:26:54 +00:00
{
2009-09-17 19:05:46 +00:00
//TODO: Maybe we can have bone ids for the errrors, but normaly, they should never appera, so what....
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//read a new bone:
Bone NewBone ;
NewBone . Id = GetAttribute < int > ( SkeletonFile , " id " ) ;
NewBone . Name = GetAttribute < string > ( SkeletonFile , " name " ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//load the position:
XmlRead ( SkeletonFile ) ;
if ( string ( " position " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " Position is not first node in Bone! " ) ;
NewBone . Position . x = GetAttribute < float > ( SkeletonFile , " x " ) ;
NewBone . Position . y = GetAttribute < float > ( SkeletonFile , " y " ) ;
NewBone . Position . z = GetAttribute < float > ( SkeletonFile , " z " ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//Rotation:
XmlRead ( SkeletonFile ) ;
if ( string ( " rotation " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " Rotation is not the second node in Bone! " ) ;
NewBone . RotationAngle = GetAttribute < float > ( SkeletonFile , " angle " ) ;
XmlRead ( SkeletonFile ) ;
if ( string ( " axis " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " No axis specified for bone rotation! " ) ;
NewBone . RotationAxis . x = GetAttribute < float > ( SkeletonFile , " x " ) ;
NewBone . RotationAxis . y = GetAttribute < float > ( SkeletonFile , " y " ) ;
NewBone . RotationAxis . z = GetAttribute < float > ( SkeletonFile , " z " ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//append the newly loaded bone to the bone list
Bones . push_back ( NewBone ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//Proceed to the next bone:
XmlRead ( SkeletonFile ) ;
2009-09-13 18:26:54 +00:00
}
//The bones in the file a not neccesarly ordered by there id's so we do it now:
2009-09-21 17:41:57 +00:00
std : : sort ( Bones . begin ( ) , Bones . end ( ) ) ;
2009-09-13 18:26:54 +00:00
//now the id of each bone should be equal to its position in the vector:
//so we do a simple check:
{
bool IdsOk = true ;
for ( int i = 0 ; i < static_cast < signed int > ( Bones . size ( ) ) ; + + i ) //i is signed, because all Id's are also signed!
{
if ( Bones [ i ] . Id ! = i )
IdsOk = false ;
}
if ( ! IdsOk )
throw new ImportErrorException ( " Bone Ids are not valid! " + FileName ) ;
}
DefaultLogger : : get ( ) - > debug ( str ( format ( " Number of bones: %1% " ) % Bones . size ( ) ) ) ;
2009-09-17 19:05:46 +00:00
//________________________________________________________________________________
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//----------------------------load bonehierarchy--------------------------------
if ( string ( " bonehierarchy " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " no bonehierarchy node in " + FileName ) ;
DefaultLogger : : get ( ) - > debug ( " loading bonehierarchy... " ) ;
XmlRead ( SkeletonFile ) ;
while ( string ( " boneparent " ) = = SkeletonFile - > getNodeName ( ) )
2009-09-13 18:26:54 +00:00
{
2009-09-17 19:05:46 +00:00
string Child , Parent ;
Child = GetAttribute < string > ( SkeletonFile , " bone " ) ;
Parent = GetAttribute < string > ( SkeletonFile , " parent " ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
unsigned int ChildId , ParentId ;
ChildId = find ( Bones . begin ( ) , Bones . end ( ) , Child ) - > Id ;
ParentId = find ( Bones . begin ( ) , Bones . end ( ) , Parent ) - > Id ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
Bones [ ChildId ] . ParentId = ParentId ;
Bones [ ParentId ] . Children . push_back ( ChildId ) ;
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
XmlRead ( SkeletonFile ) ; //i once forget this line, which led to an endless loop, did i mentioned, that irrxml sucks??
2009-09-13 18:26:54 +00:00
}
2009-09-17 19:05:46 +00:00
//_____________________________________________________________________________
2009-09-13 18:26:54 +00:00
2009-09-28 16:53:33 +00:00
//--------- Calculate the WorldToBoneSpace Matrix recursivly for all bones: ------------------
BOOST_FOREACH ( Bone theBone , Bones )
{
if ( - 1 = = theBone . ParentId ) //the bone is a root bone
{
theBone . CalculateWorldToBoneSpaceMatrix ( Bones ) ;
}
}
//_______________________________________________________________________
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
//---------------------------load animations-----------------------------
if ( string ( " animations " ) = = SkeletonFile - > getNodeName ( ) ) //animations are optional values
{
DefaultLogger : : get ( ) - > debug ( " Loading Animations " ) ;
XmlRead ( SkeletonFile ) ;
while ( string ( " animation " ) = = SkeletonFile - > getNodeName ( ) )
{
Animation NewAnimation ;
NewAnimation . Name = GetAttribute < string > ( SkeletonFile , " name " ) ;
NewAnimation . Length = GetAttribute < float > ( SkeletonFile , " length " ) ;
//Load all Tracks
XmlRead ( SkeletonFile ) ;
if ( string ( " tracks " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " no tracks node in animation " ) ;
XmlRead ( SkeletonFile ) ;
while ( string ( " track " ) = = SkeletonFile - > getNodeName ( ) )
{
Track NewTrack ;
NewTrack . BoneName = GetAttribute < string > ( SkeletonFile , " bone " ) ;
//Load all keyframes;
XmlRead ( SkeletonFile ) ;
if ( string ( " keyframes " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " no keyframes node! " ) ;
XmlRead ( SkeletonFile ) ;
while ( string ( " keyframe " ) = = SkeletonFile - > getNodeName ( ) )
{
Keyframe NewKeyframe ;
NewKeyframe . Time = GetAttribute < float > ( SkeletonFile , " time " ) ;
//Position:
XmlRead ( SkeletonFile ) ;
if ( string ( " translate " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " translate node not first in keyframe " ) ;
NewKeyframe . Position . x = GetAttribute < float > ( SkeletonFile , " x " ) ;
NewKeyframe . Position . y = GetAttribute < float > ( SkeletonFile , " y " ) ;
NewKeyframe . Position . z = GetAttribute < float > ( SkeletonFile , " z " ) ;
//Rotation:
XmlRead ( SkeletonFile ) ;
if ( string ( " rotate " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " rotate is not second node in keyframe " ) ;
float RotationAngle = GetAttribute < float > ( SkeletonFile , " angle " ) ;
aiVector3D RotationAxis ;
XmlRead ( SkeletonFile ) ;
if ( string ( " axis " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " No axis for keyframe rotation! " ) ;
RotationAxis . x = GetAttribute < float > ( SkeletonFile , " x " ) ;
RotationAxis . y = GetAttribute < float > ( SkeletonFile , " y " ) ;
RotationAxis . z = GetAttribute < float > ( SkeletonFile , " z " ) ;
NewKeyframe . Rotation = aiQuaternion ( RotationAxis , RotationAngle ) ;
//Scaling:
XmlRead ( SkeletonFile ) ;
if ( string ( " scale " ) ! = SkeletonFile - > getNodeName ( ) )
throw new ImportErrorException ( " no scalling key in keyframe! " ) ;
NewKeyframe . Scaling . x = GetAttribute < float > ( SkeletonFile , " x " ) ;
NewKeyframe . Scaling . y = GetAttribute < float > ( SkeletonFile , " y " ) ;
NewKeyframe . Scaling . z = GetAttribute < float > ( SkeletonFile , " z " ) ;
NewTrack . Keyframes . push_back ( NewKeyframe ) ;
XmlRead ( SkeletonFile ) ;
}
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
NewAnimation . Tracks . push_back ( NewTrack ) ;
}
2009-09-13 18:26:54 +00:00
2009-09-17 19:05:46 +00:00
Animations . push_back ( NewAnimation ) ;
}
}
//_____________________________________________________________________________
2009-09-13 18:26:54 +00:00
2009-09-28 16:53:33 +00:00
}
2009-09-13 18:26:54 +00:00
2009-09-28 16:53:33 +00:00
void OgreImporter : : CreateAssimpSkeleton ( const std : : vector < Bone > & Bones , const std : : vector < Animation > & Animations )
{
2009-09-13 18:26:54 +00:00
//-----------------skeleton is completly loaded, now but it in the assimp scene:-------------------------------
if ( ! m_CurrentScene - > mRootNode )
throw new ImportErrorException ( " No root node exists!! " ) ;
if ( 0 ! = m_CurrentScene - > mRootNode - > mNumChildren )
throw new ImportErrorException ( " Root Node already has childnodes! " ) ;
2009-09-28 16:53:33 +00:00
//--------------Createt the assimp bone hierarchy-----------------
2009-09-13 18:26:54 +00:00
DefaultLogger : : get ( ) - > debug ( " Root Bones " ) ;
vector < aiNode * > RootBoneNodes ;
BOOST_FOREACH ( Bone theBone , Bones )
{
if ( - 1 = = theBone . ParentId ) //the bone is a root bone
{
DefaultLogger : : get ( ) - > debug ( theBone . Name ) ;
RootBoneNodes . push_back ( CreateAiNodeFromBone ( theBone . Id , Bones , m_CurrentScene - > mRootNode ) ) ;
}
}
m_CurrentScene - > mRootNode - > mNumChildren = RootBoneNodes . size ( ) ;
m_CurrentScene - > mRootNode - > mChildren = new aiNode * [ RootBoneNodes . size ( ) ] ;
memcpy ( m_CurrentScene - > mRootNode - > mChildren , & RootBoneNodes [ 0 ] , sizeof ( aiNode * ) * RootBoneNodes . size ( ) ) ;
2009-09-17 19:05:46 +00:00
//_______________________________________________________________
//-----------------Create the Assimp Animations --------------------
if ( Animations . size ( ) > 0 ) //Maybe the model had only a skeleton and no animations. (If it also has no skeleton, this function would'nt have benn called
{
m_CurrentScene - > mNumAnimations = Animations . size ( ) ;
m_CurrentScene - > mAnimations = new aiAnimation * [ Animations . size ( ) ] ;
for ( unsigned int i = 0 ; i < Animations . size ( ) ; + + i ) //create all animations
{
aiAnimation * NewAnimation = new aiAnimation ( ) ;
NewAnimation - > mName = Animations [ i ] . Name ;
NewAnimation - > mDuration = Animations [ i ] . Length ;
2009-09-28 16:53:33 +00:00
NewAnimation - > mTicksPerSecond = 1.0f ;
2009-09-17 19:05:46 +00:00
//Create all tracks in this animation
NewAnimation - > mNumChannels = Animations [ i ] . Tracks . size ( ) ;
NewAnimation - > mChannels = new aiNodeAnim * [ Animations [ i ] . Tracks . size ( ) ] ;
for ( unsigned int j = 0 ; j < Animations [ i ] . Tracks . size ( ) ; + + j )
{
aiNodeAnim * NewNodeAnim = new aiNodeAnim ( ) ;
NewNodeAnim - > mNodeName = Animations [ i ] . Tracks [ j ] . BoneName ;
//Create the keyframe arrays...
unsigned int KeyframeCount = Animations [ i ] . Tracks [ j ] . Keyframes . size ( ) ;
NewNodeAnim - > mNumPositionKeys = KeyframeCount ;
NewNodeAnim - > mPositionKeys = new aiVectorKey [ KeyframeCount ] ;
NewNodeAnim - > mNumRotationKeys = KeyframeCount ;
NewNodeAnim - > mRotationKeys = new aiQuatKey [ KeyframeCount ] ;
NewNodeAnim - > mNumScalingKeys = KeyframeCount ;
NewNodeAnim - > mScalingKeys = new aiVectorKey [ KeyframeCount ] ;
//...and fill them
for ( unsigned int k = 0 ; k < KeyframeCount ; + + k )
{
NewNodeAnim - > mPositionKeys [ k ] . mTime = Animations [ i ] . Tracks [ j ] . Keyframes [ k ] . Time ;
NewNodeAnim - > mPositionKeys [ k ] . mValue = Animations [ i ] . Tracks [ j ] . Keyframes [ k ] . Position ;
NewNodeAnim - > mRotationKeys [ k ] . mTime = Animations [ i ] . Tracks [ j ] . Keyframes [ k ] . Time ;
NewNodeAnim - > mRotationKeys [ k ] . mValue = Animations [ i ] . Tracks [ j ] . Keyframes [ k ] . Rotation ;
NewNodeAnim - > mScalingKeys [ k ] . mTime = Animations [ i ] . Tracks [ j ] . Keyframes [ k ] . Time ;
NewNodeAnim - > mScalingKeys [ k ] . mValue = Animations [ i ] . Tracks [ j ] . Keyframes [ k ] . Scaling ;
}
NewAnimation - > mChannels [ j ] = NewNodeAnim ;
}
m_CurrentScene - > mAnimations [ i ] = NewAnimation ;
}
}
//__________________________________________________________________
2009-09-13 18:26:54 +00:00
}
2009-09-17 19:05:46 +00:00
2009-09-28 16:53:33 +00:00
aiNode * OgreImporter : : CreateAiNodeFromBone ( int BoneId , const std : : vector < Bone > & Bones , aiNode * ParentNode )
2009-09-13 18:26:54 +00:00
{
//----Create the node for this bone and set its values-----
aiNode * NewNode = new aiNode ( Bones [ BoneId ] . Name ) ;
NewNode - > mParent = ParentNode ;
2009-09-21 17:41:57 +00:00
aiMatrix4x4 t0 , t1 ;
2009-09-13 18:26:54 +00:00
//create a matrix from the transformation values of the ogre bone
2009-09-21 17:41:57 +00:00
NewNode - > mTransformation = aiMatrix4x4 : : Translation ( Bones [ BoneId ] . Position , t0 )
2009-09-13 18:26:54 +00:00
*
2009-09-21 17:41:57 +00:00
aiMatrix4x4 : : Rotation ( Bones [ BoneId ] . RotationAngle , Bones [ BoneId ] . RotationAxis , t1 )
2009-09-13 18:26:54 +00:00
;
//__________________________________________________________
2009-09-28 16:53:33 +00:00
//---------- recursivly create all children Nodes: ----------
2009-09-13 18:26:54 +00:00
NewNode - > mNumChildren = Bones [ BoneId ] . Children . size ( ) ;
NewNode - > mChildren = new aiNode * [ Bones [ BoneId ] . Children . size ( ) ] ;
for ( unsigned int i = 0 ; i < Bones [ BoneId ] . Children . size ( ) ; + + i )
{
NewNode - > mChildren [ i ] = CreateAiNodeFromBone ( Bones [ BoneId ] . Children [ i ] , Bones , NewNode ) ;
}
//____________________________________________________
return NewNode ;
}
2009-09-28 16:53:33 +00:00
void Bone : : CalculateWorldToBoneSpaceMatrix ( vector < Bone > & Bones )
{
//Calculate the matrix for this bone:
2009-09-29 10:39:17 +00:00
aiMatrix4x4 t0 , t1 ;
2009-09-28 16:53:33 +00:00
if ( - 1 = = ParentId )
{
2009-09-29 10:39:17 +00:00
WorldToBoneSpace = aiMatrix4x4 : : Translation ( Position , t0 )
* aiMatrix4x4 : : Rotation ( RotationAngle , RotationAxis , t1 )
2009-09-28 16:53:33 +00:00
;
}
else
{
WorldToBoneSpace = Bones [ ParentId ] . WorldToBoneSpace
2009-09-29 10:39:17 +00:00
* aiMatrix4x4 : : Translation ( Position , t0 )
* aiMatrix4x4 : : Rotation ( RotationAngle , RotationAxis , t1 )
2009-09-28 16:53:33 +00:00
;
}
//and recursivly for all children:
BOOST_FOREACH ( int theChildren , Children )
{
Bones [ theChildren ] . CalculateWorldToBoneSpaceMatrix ( Bones ) ;
}
}
2009-09-05 12:04:32 +00:00
} //namespace Ogre
} //namespace Assimp
# endif // !! ASSIMP_BUILD_NO_OGRE_IMPORTER