2014-05-18 08:57:44 +00:00
/*
Open Asset Import Library ( assimp )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Copyright ( c ) 2006 - 2012 , assimp team
All rights reserved .
Redistribution and use of this software in source and binary forms ,
with or without modification , are permitted provided that the
following conditions are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the
following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the
following disclaimer in the documentation and / or other
materials provided with the distribution .
* Neither the name of the assimp team , nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# include "OgreBinarySerializer.h"
2014-05-21 01:00:11 +00:00
# include "OgreXmlSerializer.h"
# include "OgreParsingUtils.h"
2014-05-18 08:57:44 +00:00
# include "TinyFormatter.h"
# ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
2014-05-18 09:30:16 +00:00
// Define as 1 to get verbose logging.
# define OGRE_BINARY_SERIALIZER_DEBUG 0
2014-05-18 08:57:44 +00:00
namespace Assimp
{
namespace Ogre
{
2014-05-21 01:00:11 +00:00
const std : : string MESH_VERSION_1_8 = " [MeshSerializer_v1.8] " ;
const std : : string SKELETON_VERSION_1_8 = " [Serializer_v1.80] " ;
const std : : string SKELETON_VERSION_1_1 = " [Serializer_v1.10] " ;
const unsigned short HEADER_CHUNK_ID = 0x1000 ;
const long MSTREAM_OVERHEAD_SIZE = sizeof ( uint16_t ) + sizeof ( uint32_t ) ;
const long MSTREAM_BONE_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + sizeof ( unsigned short ) + ( sizeof ( float ) * 7 ) ;
const long MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + ( sizeof ( float ) * 8 ) ;
2014-05-18 08:57:44 +00:00
template < >
inline bool OgreBinarySerializer : : Read < bool > ( )
{
return ( m_reader - > GetU1 ( ) > 0 ) ;
}
template < >
inline char OgreBinarySerializer : : Read < char > ( )
{
return static_cast < char > ( m_reader - > GetU1 ( ) ) ;
}
template < >
inline uint8_t OgreBinarySerializer : : Read < uint8_t > ( )
{
return m_reader - > GetU1 ( ) ;
}
template < >
inline uint16_t OgreBinarySerializer : : Read < uint16_t > ( )
{
return m_reader - > GetU2 ( ) ;
}
template < >
inline uint32_t OgreBinarySerializer : : Read < uint32_t > ( )
{
return m_reader - > GetU4 ( ) ;
}
template < >
inline float OgreBinarySerializer : : Read < float > ( )
{
return m_reader - > GetF4 ( ) ;
}
void OgreBinarySerializer : : ReadBytes ( char * dest , size_t numBytes )
{
ReadBytes ( static_cast < void * > ( dest ) , numBytes ) ;
}
void OgreBinarySerializer : : ReadBytes ( uint8_t * dest , size_t numBytes )
{
ReadBytes ( static_cast < void * > ( dest ) , numBytes ) ;
}
void OgreBinarySerializer : : ReadBytes ( void * dest , size_t numBytes )
{
m_reader - > CopyAndAdvance ( dest , numBytes ) ;
}
uint8_t * OgreBinarySerializer : : ReadBytes ( size_t numBytes )
{
uint8_t * bytes = new uint8_t [ numBytes ] ;
ReadBytes ( bytes , numBytes ) ;
return bytes ;
}
void OgreBinarySerializer : : ReadVector ( aiVector3D & vec )
{
m_reader - > CopyAndAdvance ( & vec . x , sizeof ( float ) * 3 ) ;
}
2014-05-21 01:00:11 +00:00
void OgreBinarySerializer : : ReadQuaternion ( aiQuaternion & quat )
{
float temp [ 4 ] ;
m_reader - > CopyAndAdvance ( temp , sizeof ( float ) * 4 ) ;
quat . x = temp [ 0 ] ;
quat . y = temp [ 1 ] ;
quat . z = temp [ 2 ] ;
quat . w = temp [ 3 ] ;
}
2014-05-18 08:57:44 +00:00
bool OgreBinarySerializer : : AtEnd ( ) const
{
return ( m_reader - > GetRemainingSize ( ) = = 0 ) ;
}
std : : string OgreBinarySerializer : : ReadString ( size_t len )
{
std : : string str ;
str . resize ( len ) ;
ReadBytes ( & str [ 0 ] , len ) ;
return str ;
}
std : : string OgreBinarySerializer : : ReadLine ( )
{
std : : string str ;
while ( ! AtEnd ( ) )
{
char c = Read < char > ( ) ;
if ( c = = ' \n ' )
break ;
str + = c ;
}
return str ;
}
uint16_t OgreBinarySerializer : : ReadHeader ( bool readLen )
{
uint16_t id = Read < uint16_t > ( ) ;
if ( readLen )
m_currentLen = Read < uint32_t > ( ) ;
2014-05-18 09:30:16 +00:00
# if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
if ( id ! = HEADER_CHUNK_ID )
2014-05-21 01:00:11 +00:00
{
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < ( assetMode = = AM_Mesh
? MeshHeaderToString ( static_cast < MeshChunkId > ( id ) ) : SkeletonHeaderToString ( static_cast < SkeletonChunkId > ( id ) ) ) ) ;
}
2014-05-18 09:30:16 +00:00
# endif
2014-05-18 08:57:44 +00:00
return id ;
}
void OgreBinarySerializer : : RollbackHeader ( )
{
m_reader - > IncPtr ( - MSTREAM_OVERHEAD_SIZE ) ;
}
2014-05-18 09:30:16 +00:00
void OgreBinarySerializer : : SkipBytes ( size_t numBytes )
2014-05-18 08:57:44 +00:00
{
2014-05-18 09:30:16 +00:00
# if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " Skipping " < < numBytes < < " bytes " ) ;
# endif
m_reader - > IncPtr ( numBytes ) ;
2014-05-18 08:57:44 +00:00
}
2014-05-21 01:00:11 +00:00
// Mesh
2014-05-18 08:57:44 +00:00
Mesh * OgreBinarySerializer : : ImportMesh ( MemoryStreamReader * stream )
{
2014-05-21 01:00:11 +00:00
OgreBinarySerializer serializer ( stream , OgreBinarySerializer : : AM_Mesh ) ;
2014-05-18 08:57:44 +00:00
uint16_t id = serializer . ReadHeader ( false ) ;
2014-05-18 09:30:16 +00:00
if ( id ! = HEADER_CHUNK_ID ) {
throw DeadlyExportError ( " Invalid Ogre Mesh file header. " ) ;
}
2014-05-18 08:57:44 +00:00
/// @todo Check what we can actually support.
std : : string version = serializer . ReadLine ( ) ;
2014-05-21 01:00:11 +00:00
if ( version ! = MESH_VERSION_1_8 )
{
throw DeadlyExportError ( Formatter : : format ( ) < < " Mesh version " < < version < < " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again. "
< < " Supported versions: " < < MESH_VERSION_1_8 ) ;
}
2014-05-18 08:57:44 +00:00
Mesh * mesh = new Mesh ( ) ;
while ( ! serializer . AtEnd ( ) )
{
id = serializer . ReadHeader ( ) ;
switch ( id )
{
case M_MESH :
{
serializer . ReadMesh ( mesh ) ;
break ;
}
}
}
return mesh ;
}
void OgreBinarySerializer : : ReadMesh ( Mesh * mesh )
{
mesh - > hasSkeletalAnimations = Read < bool > ( ) ;
2014-05-20 01:52:53 +00:00
DefaultLogger : : get ( ) - > debug ( " Reading Mesh " ) ;
2014-05-18 08:57:44 +00:00
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - Skeletal animations: " < < ( mesh - > hasSkeletalAnimations ? " true " : " false " ) ) ;
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & &
( id = = M_GEOMETRY | |
id = = M_SUBMESH | |
id = = M_MESH_SKELETON_LINK | |
id = = M_MESH_BONE_ASSIGNMENT | |
id = = M_MESH_LOD | |
id = = M_MESH_BOUNDS | |
id = = M_SUBMESH_NAME_TABLE | |
id = = M_EDGE_LISTS | |
id = = M_POSES | |
id = = M_ANIMATIONS | |
id = = M_TABLE_EXTREMES ) )
{
switch ( id )
{
case M_GEOMETRY :
{
mesh - > sharedVertexData = new VertexData ( ) ;
2014-05-20 01:52:53 +00:00
ReadGeometry ( mesh - > sharedVertexData ) ;
2014-05-18 08:57:44 +00:00
break ;
}
case M_SUBMESH :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadSubMesh ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_MESH_SKELETON_LINK :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadMeshSkeletonLink ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_MESH_BONE_ASSIGNMENT :
2014-05-18 09:30:16 +00:00
{
2014-05-20 01:52:53 +00:00
ReadBoneAssignment ( mesh - > sharedVertexData ) ;
2014-05-18 08:57:44 +00:00
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_MESH_LOD :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadMeshLodInfo ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_MESH_BOUNDS :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadMeshBounds ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_SUBMESH_NAME_TABLE :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadSubMeshNames ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_EDGE_LISTS :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadEdgeList ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_POSES :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadPoses ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_ANIMATIONS :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadAnimations ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
case M_TABLE_EXTREMES :
2014-05-18 09:30:16 +00:00
{
2014-05-18 08:57:44 +00:00
ReadMeshExtremes ( mesh ) ;
break ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
}
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
2014-05-20 01:52:53 +00:00
NormalizeBoneWeights ( mesh - > sharedVertexData ) ;
2014-05-18 08:57:44 +00:00
}
void OgreBinarySerializer : : ReadMeshLodInfo ( Mesh * mesh )
{
// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
// @todo Put this stuff to scene/mesh custom properties. If manual mesh the app can use the information.
ReadLine ( ) ; // strategy name
uint16_t numLods = Read < uint16_t > ( ) ;
bool manual = Read < bool > ( ) ;
/// @note Main mesh is considered as LOD 0, start from index 1.
for ( size_t i = 1 ; i < numLods ; + + i )
{
uint16_t id = ReadHeader ( ) ;
2014-05-18 09:30:16 +00:00
if ( id ! = M_MESH_LOD_USAGE ) {
2014-05-18 08:57:44 +00:00
throw DeadlyImportError ( " M_MESH_LOD does not contain a M_MESH_LOD_USAGE for each LOD level " ) ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
m_reader - > IncPtr ( sizeof ( float ) ) ; // user value
if ( manual )
{
id = ReadHeader ( ) ;
2014-05-18 09:30:16 +00:00
if ( id ! = M_MESH_LOD_MANUAL ) {
2014-05-18 08:57:44 +00:00
throw DeadlyImportError ( " Manual M_MESH_LOD_USAGE does not contain M_MESH_LOD_MANUAL " ) ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
ReadLine ( ) ; // manual mesh name (ref to another mesh)
}
else
{
for ( size_t si = 0 , silen = mesh - > NumSubMeshes ( ) ; si < silen ; + + si )
{
id = ReadHeader ( ) ;
2014-05-18 09:30:16 +00:00
if ( id ! = M_MESH_LOD_GENERATED ) {
2014-05-18 08:57:44 +00:00
throw DeadlyImportError ( " Generated M_MESH_LOD_USAGE does not contain M_MESH_LOD_GENERATED " ) ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
uint32_t indexCount = Read < uint32_t > ( ) ;
bool is32bit = Read < bool > ( ) ;
if ( indexCount > 0 )
{
uint32_t len = indexCount * ( is32bit ? sizeof ( uint32_t ) : sizeof ( uint16_t ) ) ;
m_reader - > IncPtr ( len ) ;
}
}
}
}
}
void OgreBinarySerializer : : ReadMeshSkeletonLink ( Mesh * mesh )
{
mesh - > skeletonRef = ReadLine ( ) ;
}
void OgreBinarySerializer : : ReadMeshBounds ( Mesh * mesh )
{
// Skip bounds, not compatible with Assimp.
// 2x float vec3 + 1x float sphere radius
SkipBytes ( sizeof ( float ) * 7 ) ;
}
void OgreBinarySerializer : : ReadMeshExtremes ( Mesh * mesh )
{
// Skip extremes, not compatible with Assimp.
size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE ;
SkipBytes ( numBytes ) ;
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadBoneAssignment ( VertexData * dest )
2014-05-18 08:57:44 +00:00
{
2014-05-20 01:52:53 +00:00
if ( ! dest ) {
throw DeadlyImportError ( " Cannot read bone assignments, vertex data is null. " ) ;
}
2014-05-18 08:57:44 +00:00
VertexBoneAssignment ba ;
ba . vertexIndex = Read < uint32_t > ( ) ;
ba . boneIndex = Read < uint16_t > ( ) ;
ba . weight = Read < float > ( ) ;
dest - > boneAssignments . push_back ( ba ) ;
}
void OgreBinarySerializer : : ReadSubMesh ( Mesh * mesh )
{
uint16_t id = 0 ;
2014-05-20 01:52:53 +00:00
SubMesh * submesh = new SubMesh ( ) ;
2014-05-18 08:57:44 +00:00
submesh - > materialRef = ReadLine ( ) ;
submesh - > usesSharedVertexData = Read < bool > ( ) ;
submesh - > indexData - > count = Read < uint32_t > ( ) ;
submesh - > indexData - > faceCount = static_cast < uint32_t > ( submesh - > indexData - > count / 3 ) ;
submesh - > indexData - > is32bit = Read < bool > ( ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " Reading SubMesh " < < mesh - > subMeshes . size ( ) ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - Material: ' " < < submesh - > materialRef < < " ' " ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - Uses shared geometry: " < < ( submesh - > usesSharedVertexData ? " true " : " false " ) ) ;
// Index buffer
if ( submesh - > indexData - > count > 0 )
{
uint32_t numBytes = submesh - > indexData - > count * ( submesh - > indexData - > is32bit ? sizeof ( uint32_t ) : sizeof ( uint16_t ) ) ;
uint8_t * indexBuffer = ReadBytes ( numBytes ) ;
submesh - > indexData - > buffer = MemoryStreamPtr ( new Assimp : : MemoryIOStream ( indexBuffer , numBytes , true ) ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - " < < submesh - > indexData - > faceCount
< < " faces from " < < submesh - > indexData - > count < < ( submesh - > indexData - > is32bit ? " 32bit " : " 16bit " )
< < " indexes of " < < numBytes < < " bytes " ) ;
}
// Vertex buffer if not referencing the shared geometry
if ( ! submesh - > usesSharedVertexData )
{
id = ReadHeader ( ) ;
2014-05-18 09:30:16 +00:00
if ( id ! = M_GEOMETRY ) {
2014-05-18 08:57:44 +00:00
throw DeadlyImportError ( " M_SUBMESH does not contain M_GEOMETRY, but shader geometry is set to false " ) ;
2014-05-18 09:30:16 +00:00
}
2014-05-18 08:57:44 +00:00
submesh - > vertexData = new VertexData ( ) ;
2014-05-20 01:52:53 +00:00
ReadGeometry ( submesh - > vertexData ) ;
2014-05-18 08:57:44 +00:00
}
// Bone assignment, submesh operation and texture aliases
if ( ! AtEnd ( ) )
{
id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & &
( id = = M_SUBMESH_OPERATION | |
id = = M_SUBMESH_BONE_ASSIGNMENT | |
id = = M_SUBMESH_TEXTURE_ALIAS ) )
{
switch ( id )
{
case M_SUBMESH_OPERATION :
{
ReadSubMeshOperation ( submesh ) ;
break ;
}
case M_SUBMESH_BONE_ASSIGNMENT :
{
2014-05-20 01:52:53 +00:00
ReadBoneAssignment ( submesh - > vertexData ) ;
2014-05-18 08:57:44 +00:00
break ;
}
case M_SUBMESH_TEXTURE_ALIAS :
{
ReadSubMeshTextureAlias ( submesh ) ;
break ;
}
}
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
2014-05-20 01:52:53 +00:00
NormalizeBoneWeights ( submesh - > vertexData ) ;
2014-05-18 08:57:44 +00:00
submesh - > index = mesh - > subMeshes . size ( ) ;
mesh - > subMeshes . push_back ( submesh ) ;
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : NormalizeBoneWeights ( VertexData * vertexData ) const
{
if ( ! vertexData | | vertexData - > boneAssignments . empty ( ) )
return ;
std : : set < uint32_t > influencedVertices ;
for ( VertexBoneAssignmentList : : const_iterator baIter = vertexData - > boneAssignments . begin ( ) , baEnd = vertexData - > boneAssignments . end ( ) ; baIter ! = baEnd ; + + baIter ) {
influencedVertices . insert ( baIter - > vertexIndex ) ;
}
/** Normalize bone weights.
Some exporters wont care if the sum of all bone weights
for a single vertex equals 1 or not , so validate here . */
const float epsilon = 0.05f ;
for ( std : : set < uint32_t > : : const_iterator iter = influencedVertices . begin ( ) , end = influencedVertices . end ( ) ; iter ! = end ; + + iter )
{
const uint32_t vertexIndex = ( * iter ) ;
float sum = 0.0f ;
for ( VertexBoneAssignmentList : : const_iterator baIter = vertexData - > boneAssignments . begin ( ) , baEnd = vertexData - > boneAssignments . end ( ) ; baIter ! = baEnd ; + + baIter )
{
if ( baIter - > vertexIndex = = vertexIndex )
sum + = baIter - > weight ;
}
if ( ( sum < ( 1.0f - epsilon ) ) | | ( sum > ( 1.0f + epsilon ) ) )
{
for ( VertexBoneAssignmentList : : iterator baIter = vertexData - > boneAssignments . begin ( ) , baEnd = vertexData - > boneAssignments . end ( ) ; baIter ! = baEnd ; + + baIter )
{
if ( baIter - > vertexIndex = = vertexIndex )
baIter - > weight / = sum ;
}
}
}
}
void OgreBinarySerializer : : ReadSubMeshOperation ( SubMesh * submesh )
2014-05-18 08:57:44 +00:00
{
2014-05-20 01:52:53 +00:00
submesh - > operationType = static_cast < SubMesh : : OperationType > ( Read < uint16_t > ( ) ) ;
2014-05-18 08:57:44 +00:00
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadSubMeshTextureAlias ( SubMesh * submesh )
2014-05-18 08:57:44 +00:00
{
submesh - > textureAliasName = ReadLine ( ) ;
submesh - > textureAliasRef = ReadLine ( ) ;
}
void OgreBinarySerializer : : ReadSubMeshNames ( Mesh * mesh )
{
uint16_t id = 0 ;
if ( ! AtEnd ( ) )
{
id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_SUBMESH_NAME_TABLE_ELEMENT )
{
2014-05-18 09:30:16 +00:00
uint16_t submeshIndex = Read < uint16_t > ( ) ;
2014-05-20 01:52:53 +00:00
SubMesh * submesh = mesh - > GetSubMesh ( submeshIndex ) ;
2014-05-18 09:30:16 +00:00
if ( ! submesh ) {
throw DeadlyImportError ( Formatter : : format ( ) < < " Ogre Mesh does not include submesh " < < submeshIndex < < " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file. " ) ;
2014-05-18 08:57:44 +00:00
}
2014-05-18 09:30:16 +00:00
submesh - > name = ReadLine ( ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - SubMesh " < < submesh - > index < < " name ' " < < submesh - > name < < " ' " ) ;
2014-05-18 08:57:44 +00:00
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadGeometry ( VertexData * dest )
2014-05-18 08:57:44 +00:00
{
dest - > count = Read < uint32_t > ( ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - Reading geometry of " < < dest - > count < < " vertices " ) ;
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & &
( id = = M_GEOMETRY_VERTEX_DECLARATION | |
id = = M_GEOMETRY_VERTEX_BUFFER ) )
{
switch ( id )
{
case M_GEOMETRY_VERTEX_DECLARATION :
{
2014-05-20 01:52:53 +00:00
ReadGeometryVertexDeclaration ( dest ) ;
2014-05-18 08:57:44 +00:00
break ;
}
case M_GEOMETRY_VERTEX_BUFFER :
{
2014-05-20 01:52:53 +00:00
ReadGeometryVertexBuffer ( dest ) ;
2014-05-18 08:57:44 +00:00
break ;
}
}
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadGeometryVertexDeclaration ( VertexData * dest )
2014-05-18 08:57:44 +00:00
{
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_GEOMETRY_VERTEX_ELEMENT )
{
2014-05-20 01:52:53 +00:00
ReadGeometryVertexElement ( dest ) ;
2014-05-18 08:57:44 +00:00
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadGeometryVertexElement ( VertexData * dest )
2014-05-18 08:57:44 +00:00
{
VertexElement element ;
element . source = Read < uint16_t > ( ) ;
element . type = static_cast < VertexElement : : Type > ( Read < uint16_t > ( ) ) ;
element . semantic = static_cast < VertexElement : : Semantic > ( Read < uint16_t > ( ) ) ;
element . offset = Read < uint16_t > ( ) ;
element . index = Read < uint16_t > ( ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - Vertex element " < < element . SemanticToString ( ) < < " of type "
< < element . TypeToString ( ) < < " index= " < < element . index < < " source= " < < element . source ) ;
dest - > vertexElements . push_back ( element ) ;
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadGeometryVertexBuffer ( VertexData * dest )
2014-05-18 08:57:44 +00:00
{
uint16_t bindIndex = Read < uint16_t > ( ) ;
uint16_t vertexSize = Read < uint16_t > ( ) ;
uint16_t id = ReadHeader ( ) ;
if ( id ! = M_GEOMETRY_VERTEX_BUFFER_DATA )
throw DeadlyImportError ( " M_GEOMETRY_VERTEX_BUFFER_DATA not found in M_GEOMETRY_VERTEX_BUFFER " ) ;
if ( dest - > VertexSize ( bindIndex ) ! = vertexSize )
throw DeadlyImportError ( " Vertex buffer size does not agree with vertex declaration in M_GEOMETRY_VERTEX_BUFFER " ) ;
size_t numBytes = dest - > count * vertexSize ;
uint8_t * vertexBuffer = ReadBytes ( numBytes ) ;
dest - > vertexBindings [ bindIndex ] = MemoryStreamPtr ( new Assimp : : MemoryIOStream ( vertexBuffer , numBytes , true ) ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " - Read vertex buffer for source " < < bindIndex < < " of " < < numBytes < < " bytes " ) ;
}
void OgreBinarySerializer : : ReadEdgeList ( Mesh * mesh )
{
// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_EDGE_LIST_LOD )
{
m_reader - > IncPtr ( sizeof ( uint16_t ) ) ; // lod index
bool manual = Read < bool > ( ) ;
if ( ! manual )
{
m_reader - > IncPtr ( sizeof ( uint8_t ) ) ;
uint32_t numTriangles = Read < uint32_t > ( ) ;
uint32_t numEdgeGroups = Read < uint32_t > ( ) ;
size_t skipBytes = ( sizeof ( uint32_t ) * 8 + sizeof ( float ) * 4 ) * numTriangles ;
m_reader - > IncPtr ( skipBytes ) ;
for ( size_t i = 0 ; i < numEdgeGroups ; + + i )
{
uint16_t id = ReadHeader ( ) ;
if ( id ! = M_EDGE_GROUP )
throw DeadlyImportError ( " M_EDGE_GROUP not found in M_EDGE_LIST_LOD " ) ;
m_reader - > IncPtr ( sizeof ( uint32_t ) * 3 ) ;
uint32_t numEdges = Read < uint32_t > ( ) ;
for ( size_t j = 0 ; j < numEdges ; + + j )
{
m_reader - > IncPtr ( sizeof ( uint32_t ) * 6 + sizeof ( uint8_t ) ) ;
}
}
}
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
void OgreBinarySerializer : : ReadPoses ( Mesh * mesh )
{
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_POSE )
{
Pose * pose = new Pose ( ) ;
pose - > name = ReadLine ( ) ;
pose - > target = Read < uint16_t > ( ) ;
pose - > hasNormals = Read < bool > ( ) ;
ReadPoseVertices ( pose ) ;
mesh - > poses . push_back ( pose ) ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
void OgreBinarySerializer : : ReadPoseVertices ( Pose * pose )
{
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_POSE_VERTEX )
{
Pose : : Vertex v ;
v . index = Read < uint32_t > ( ) ;
ReadVector ( v . offset ) ;
if ( pose - > hasNormals )
ReadVector ( v . normal ) ;
pose - > vertices [ v . index ] = v ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
void OgreBinarySerializer : : ReadAnimations ( Mesh * mesh )
{
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_ANIMATION )
{
2014-05-20 01:52:53 +00:00
Animation * anim = new Animation ( mesh ) ;
2014-05-18 08:57:44 +00:00
anim - > name = ReadLine ( ) ;
anim - > length = Read < float > ( ) ;
ReadAnimation ( anim ) ;
mesh - > animations . push_back ( anim ) ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadAnimation ( Animation * anim )
2014-05-21 01:00:11 +00:00
{
2014-05-18 08:57:44 +00:00
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
if ( id = = M_ANIMATION_BASEINFO )
{
anim - > baseName = ReadLine ( ) ;
anim - > baseTime = Read < float > ( ) ;
// Advance to first track
id = ReadHeader ( ) ;
}
while ( ! AtEnd ( ) & & id = = M_ANIMATION_TRACK )
{
VertexAnimationTrack track ;
track . type = static_cast < VertexAnimationTrack : : Type > ( Read < uint16_t > ( ) ) ;
track . target = Read < uint16_t > ( ) ;
ReadAnimationKeyFrames ( anim , & track ) ;
anim - > tracks . push_back ( track ) ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
2014-05-20 01:52:53 +00:00
void OgreBinarySerializer : : ReadAnimationKeyFrames ( Animation * anim , VertexAnimationTrack * track )
2014-05-18 08:57:44 +00:00
{
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & &
( id = = M_ANIMATION_MORPH_KEYFRAME | |
id = = M_ANIMATION_POSE_KEYFRAME ) )
{
if ( id = = M_ANIMATION_MORPH_KEYFRAME )
{
MorphKeyFrame kf ;
kf . timePos = Read < float > ( ) ;
bool hasNormals = Read < bool > ( ) ;
size_t vertexCount = anim - > AssociatedVertexData ( track ) - > count ;
size_t vertexSize = sizeof ( float ) * ( hasNormals ? 6 : 3 ) ;
size_t numBytes = vertexCount * vertexSize ;
uint8_t * morphBuffer = ReadBytes ( numBytes ) ;
kf . buffer = MemoryStreamPtr ( new Assimp : : MemoryIOStream ( morphBuffer , numBytes , true ) ) ;
track - > morphKeyFrames . push_back ( kf ) ;
}
else if ( id = = M_ANIMATION_POSE_KEYFRAME )
{
PoseKeyFrame kf ;
kf . timePos = Read < float > ( ) ;
if ( ! AtEnd ( ) )
{
id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = M_ANIMATION_POSE_REF )
{
PoseRef pr ;
pr . index = Read < uint16_t > ( ) ;
pr . influence = Read < float > ( ) ;
kf . references . push_back ( pr ) ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
track - > poseKeyFrames . push_back ( kf ) ;
}
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
}
2014-05-21 01:00:11 +00:00
// Skeleton
bool OgreBinarySerializer : : ImportSkeleton ( Assimp : : IOSystem * pIOHandler , Mesh * mesh )
{
if ( ! mesh | | mesh - > skeletonRef . empty ( ) )
return false ;
// Highly unusual to see in read world cases but support
// binary mesh referencing a XML skeleton file.
if ( EndsWith ( mesh - > skeletonRef , " .skeleton.xml " , false ) )
{
OgreXmlSerializer : : ImportSkeleton ( pIOHandler , mesh ) ;
return false ;
}
MemoryStreamReaderPtr reader = OpenReader ( pIOHandler , mesh - > skeletonRef ) ;
Skeleton * skeleton = new Skeleton ( ) ;
OgreBinarySerializer serializer ( reader . get ( ) , OgreBinarySerializer : : AM_Skeleton ) ;
serializer . ReadSkeleton ( skeleton ) ;
mesh - > skeleton = skeleton ;
return true ;
}
bool OgreBinarySerializer : : ImportSkeleton ( Assimp : : IOSystem * pIOHandler , MeshXml * mesh )
{
if ( ! mesh | | mesh - > skeletonRef . empty ( ) )
return false ;
MemoryStreamReaderPtr reader = OpenReader ( pIOHandler , mesh - > skeletonRef ) ;
if ( ! reader . get ( ) )
return false ;
Skeleton * skeleton = new Skeleton ( ) ;
OgreBinarySerializer serializer ( reader . get ( ) , OgreBinarySerializer : : AM_Skeleton ) ;
serializer . ReadSkeleton ( skeleton ) ;
mesh - > skeleton = skeleton ;
return true ;
}
MemoryStreamReaderPtr OgreBinarySerializer : : OpenReader ( Assimp : : IOSystem * pIOHandler , const std : : string & filename )
{
if ( ! EndsWith ( filename , " .skeleton " , false ) )
{
DefaultLogger : : get ( ) - > error ( " Imported Mesh is referencing to unsupported ' " + filename + " ' skeleton file. " ) ;
return MemoryStreamReaderPtr ( ) ;
}
if ( ! pIOHandler - > Exists ( filename ) )
{
DefaultLogger : : get ( ) - > error ( " Failed to find skeleton file ' " + filename + " ' that is referenced by imported Mesh. " ) ;
return MemoryStreamReaderPtr ( ) ;
}
IOStream * f = pIOHandler - > Open ( filename , " rb " ) ;
if ( ! f ) {
throw DeadlyImportError ( " Failed to open skeleton file " + filename ) ;
}
return MemoryStreamReaderPtr ( new MemoryStreamReader ( f ) ) ;
}
void OgreBinarySerializer : : ReadSkeleton ( Skeleton * skeleton )
{
uint16_t id = ReadHeader ( false ) ;
if ( id ! = HEADER_CHUNK_ID ) {
throw DeadlyExportError ( " Invalid Ogre Skeleton file header. " ) ;
}
// This deserialization supports both versions of the skeleton spec
std : : string version = ReadLine ( ) ;
if ( version ! = SKELETON_VERSION_1_8 & & version ! = SKELETON_VERSION_1_1 )
{
throw DeadlyExportError ( Formatter : : format ( ) < < " Skeleton version " < < version < < " not supported by this importer. "
< < " Supported versions: " < < SKELETON_VERSION_1_8 < < " and " < < SKELETON_VERSION_1_1 ) ;
}
DefaultLogger : : get ( ) - > debug ( " Reading Skeleton " ) ;
bool firstBone = true ;
bool firstAnim = true ;
while ( ! AtEnd ( ) )
{
id = ReadHeader ( ) ;
switch ( id )
{
case SKELETON_BLENDMODE :
{
skeleton - > blendMode = static_cast < Skeleton : : BlendMode > ( Read < uint16_t > ( ) ) ;
break ;
}
case SKELETON_BONE :
{
if ( firstBone )
{
DefaultLogger : : get ( ) - > debug ( " - Bones " ) ;
firstBone = false ;
}
ReadBone ( skeleton ) ;
break ;
}
case SKELETON_BONE_PARENT :
{
ReadBoneParent ( skeleton ) ;
break ;
}
case SKELETON_ANIMATION :
{
if ( firstAnim )
{
DefaultLogger : : get ( ) - > debug ( " - Animations " ) ;
firstAnim = false ;
}
ReadSkeletonAnimation ( skeleton ) ;
break ;
}
case SKELETON_ANIMATION_LINK :
{
ReadSkeletonAnimationLink ( skeleton ) ;
break ;
}
}
}
// Calculate bone matrices for root bones. Recursively calculates their children.
for ( size_t i = 0 , len = skeleton - > bones . size ( ) ; i < len ; + + i )
{
Bone * bone = skeleton - > bones [ i ] ;
if ( ! bone - > IsParented ( ) )
bone - > CalculateWorldMatrixAndDefaultPose ( skeleton ) ;
}
}
void OgreBinarySerializer : : ReadBone ( Skeleton * skeleton )
{
Bone * bone = new Bone ( ) ;
bone - > name = ReadLine ( ) ;
bone - > id = Read < uint16_t > ( ) ;
// Pos and rot
ReadVector ( bone - > position ) ;
ReadQuaternion ( bone - > rotation ) ;
// Scale (optional)
if ( m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE )
ReadVector ( bone - > scale ) ;
// Bone indexes need to start from 0 and be contiguous
if ( bone - > id ! = skeleton - > bones . size ( ) ) {
throw DeadlyImportError ( Formatter : : format ( ) < < " Ogre Skeleton bone indexes not contiguous. Error at bone index " < < bone - > id ) ;
}
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " " < < bone - > id < < " " < < bone - > name ) ;
skeleton - > bones . push_back ( bone ) ;
}
void OgreBinarySerializer : : ReadBoneParent ( Skeleton * skeleton )
{
uint16_t childId = Read < uint16_t > ( ) ;
uint16_t parentId = Read < uint16_t > ( ) ;
Bone * child = skeleton - > BoneById ( childId ) ;
Bone * parent = skeleton - > BoneById ( parentId ) ;
if ( child & & parent )
parent - > AddChild ( child ) ;
else
throw DeadlyImportError ( Formatter : : format ( ) < < " Failed to find bones for parenting: Child id " < < childId < < " for parent id " < < parentId ) ;
}
void OgreBinarySerializer : : ReadSkeletonAnimation ( Skeleton * skeleton )
{
Animation * anim = new Animation ( skeleton ) ;
anim - > name = ReadLine ( ) ;
anim - > length = Read < float > ( ) ;
if ( ! AtEnd ( ) )
{
uint16_t id = ReadHeader ( ) ;
if ( id = = SKELETON_ANIMATION_BASEINFO )
{
anim - > baseName = ReadLine ( ) ;
anim - > baseTime = Read < float > ( ) ;
// Advance to first track
id = ReadHeader ( ) ;
}
while ( ! AtEnd ( ) & & id = = SKELETON_ANIMATION_TRACK )
{
ReadSkeletonAnimationTrack ( skeleton , anim ) ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
}
skeleton - > animations . push_back ( anim ) ;
DefaultLogger : : get ( ) - > debug ( Formatter : : format ( ) < < " " < < anim - > name < < " ( " < < anim - > length < < " sec, " < < anim - > tracks . size ( ) < < " tracks) " ) ;
}
void OgreBinarySerializer : : ReadSkeletonAnimationTrack ( Skeleton * skeleton , Animation * dest )
{
uint16_t boneId = Read < uint16_t > ( ) ;
Bone * bone = dest - > parentSkeleton - > BoneById ( boneId ) ;
if ( ! bone ) {
throw DeadlyImportError ( Formatter : : format ( ) < < " Cannot read animation track, target bone " < < boneId < < " not in target Skeleton " ) ;
}
VertexAnimationTrack track ;
track . type = VertexAnimationTrack : : VAT_TRANSFORM ;
track . boneName = bone - > name ;
uint16_t id = ReadHeader ( ) ;
while ( ! AtEnd ( ) & & id = = SKELETON_ANIMATION_TRACK_KEYFRAME )
{
ReadSkeletonAnimationKeyFrame ( & track ) ;
if ( ! AtEnd ( ) )
id = ReadHeader ( ) ;
}
if ( ! AtEnd ( ) )
RollbackHeader ( ) ;
dest - > tracks . push_back ( track ) ;
}
void OgreBinarySerializer : : ReadSkeletonAnimationKeyFrame ( VertexAnimationTrack * dest )
{
TransformKeyFrame keyframe ;
keyframe . timePos = Read < float > ( ) ;
// Rot and pos
ReadQuaternion ( keyframe . rotation ) ;
ReadVector ( keyframe . position ) ;
// Scale (optional)
if ( m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE )
ReadVector ( keyframe . scale ) ;
dest - > transformKeyFrames . push_back ( keyframe ) ;
}
void OgreBinarySerializer : : ReadSkeletonAnimationLink ( Skeleton * skeleton )
{
// Skip bounds, not compatible with Assimp.
ReadLine ( ) ; // skeleton name
SkipBytes ( sizeof ( float ) * 3 ) ; // scale
}
2014-05-18 08:57:44 +00:00
} // Ogre
} // Assimp
# endif // ASSIMP_BUILD_NO_OGRE_IMPORTER