nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file B3DImporter.cpp nuclear@0: * @brief Implementation of the b3d importer class nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER nuclear@0: nuclear@0: // internal headers nuclear@0: #include "B3DImporter.h" nuclear@0: #include "TextureTransform.h" nuclear@0: #include "ConvertToLHProcess.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: using namespace std; nuclear@0: nuclear@0: static const aiImporterDesc desc = { nuclear@0: "BlitzBasic 3D Importer", nuclear@0: "", nuclear@0: "", nuclear@0: "http://www.blitzbasic.com/", nuclear@0: aiImporterFlags_SupportBinaryFlavour, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: "b3d" nuclear@0: }; nuclear@0: nuclear@0: // (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings nuclear@0: #ifdef _MSC_VER nuclear@0: # pragma warning (disable: 4018) nuclear@0: #endif nuclear@0: nuclear@0: //#define DEBUG_B3D nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ nuclear@0: nuclear@0: size_t pos=pFile.find_last_of( '.' ); nuclear@0: if( pos==string::npos ) return false; nuclear@0: nuclear@0: string ext=pFile.substr( pos+1 ); nuclear@0: if( ext.size()!=3 ) return false; nuclear@0: nuclear@0: return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Loader meta information nuclear@0: const aiImporterDesc* B3DImporter::GetInfo () const nuclear@0: { nuclear@0: return &desc; nuclear@0: } nuclear@0: nuclear@0: #ifdef DEBUG_B3D nuclear@0: extern "C"{ void _stdcall AllocConsole(); } nuclear@0: #endif nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ nuclear@0: nuclear@0: #ifdef DEBUG_B3D nuclear@0: AllocConsole(); nuclear@0: freopen( "conin$","r",stdin ); nuclear@0: freopen( "conout$","w",stdout ); nuclear@0: freopen( "conout$","w",stderr ); nuclear@0: cout<<"Hello world from the B3DImporter!"< file( pIOHandler->Open( pFile)); nuclear@0: nuclear@0: // Check whether we can read from the file nuclear@0: if( file.get() == NULL) nuclear@0: throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); nuclear@0: nuclear@0: // check whether the .b3d file is large enough to contain nuclear@0: // at least one chunk. nuclear@0: size_t fileSize = file->FileSize(); nuclear@0: if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); nuclear@0: nuclear@0: _pos=0; nuclear@0: _buf.resize( fileSize ); nuclear@0: file->Read( &_buf[0],1,fileSize ); nuclear@0: _stack.clear(); nuclear@0: nuclear@0: ReadBB3D( pScene ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::Oops(){ nuclear@0: throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::Fail( string str ){ nuclear@0: #ifdef DEBUG_B3D nuclear@0: cout<<"Error in B3D file data: "< nuclear@0: T *B3DImporter::to_array( const vector &v ){ nuclear@0: if( !v.size() ) return 0; nuclear@0: T *p=new T[v.size()]; nuclear@0: for( size_t i=0;i8 ){ nuclear@0: Fail( "Bad texture count" ); nuclear@0: } nuclear@0: while( ChunkSize() ){ nuclear@0: string name=ReadString(); nuclear@0: aiVector3D color=ReadVec3(); nuclear@0: float alpha=ReadFloat(); nuclear@0: float shiny=ReadFloat(); nuclear@0: /*int blend=**/ReadInt(); nuclear@0: int fx=ReadInt(); nuclear@0: nuclear@0: aiMaterial *mat=new aiMaterial; nuclear@0: _materials.push_back( mat ); nuclear@0: nuclear@0: // Name nuclear@0: aiString ainame( name ); nuclear@0: mat->AddProperty( &ainame,AI_MATKEY_NAME ); nuclear@0: nuclear@0: // Diffuse color nuclear@0: mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE ); nuclear@0: nuclear@0: // Opacity nuclear@0: mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY ); nuclear@0: nuclear@0: // Specular color nuclear@0: aiColor3D speccolor( shiny,shiny,shiny ); nuclear@0: mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR ); nuclear@0: nuclear@0: // Specular power nuclear@0: float specpow=shiny*128; nuclear@0: mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS ); nuclear@0: nuclear@0: // Double sided nuclear@0: if( fx & 0x10 ){ nuclear@0: int i=1; nuclear@0: mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED ); nuclear@0: } nuclear@0: nuclear@0: //Textures nuclear@0: for( int i=0;i=0 && texid>=static_cast(_textures.size())) ){ nuclear@0: Fail( "Bad texture id" ); nuclear@0: } nuclear@0: if( i==0 && texid>=0 ){ nuclear@0: aiString texname( _textures[texid] ); nuclear@0: mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) ); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::ReadVRTS(){ nuclear@0: _vflags=ReadInt(); nuclear@0: _tcsets=ReadInt(); nuclear@0: _tcsize=ReadInt(); nuclear@0: if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){ nuclear@0: Fail( "Bad texcoord data" ); nuclear@0: } nuclear@0: nuclear@0: int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4); nuclear@0: int n_verts=ChunkSize()/sz; nuclear@0: nuclear@0: int v0=_vertices.size(); nuclear@0: _vertices.resize( v0+n_verts ); nuclear@0: nuclear@0: for( int i=0;i=(int)_materials.size() ){ nuclear@0: #ifdef DEBUG_B3D nuclear@0: cout<<"material id="<mMaterialIndex=matid; nuclear@0: mesh->mNumFaces=0; nuclear@0: mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; nuclear@0: nuclear@0: int n_tris=ChunkSize()/12; nuclear@0: aiFace *face=mesh->mFaces=new aiFace[n_tris]; nuclear@0: nuclear@0: for( int i=0;i=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ nuclear@0: #ifdef DEBUG_B3D nuclear@0: cout<<"Bad triangle index: i0="<mNumIndices=3; nuclear@0: face->mIndices=new unsigned[3]; nuclear@0: face->mIndices[0]=i0; nuclear@0: face->mIndices[1]=i1; nuclear@0: face->mIndices[2]=i2; nuclear@0: ++mesh->mNumFaces; nuclear@0: ++face; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::ReadMESH(){ nuclear@0: /*int matid=*/ReadInt(); nuclear@0: nuclear@0: int v0=_vertices.size(); nuclear@0: nuclear@0: while( ChunkSize() ){ nuclear@0: string t=ReadChunk(); nuclear@0: if( t=="VRTS" ){ nuclear@0: ReadVRTS(); nuclear@0: }else if( t=="TRIS" ){ nuclear@0: ReadTRIS( v0 ); nuclear@0: } nuclear@0: ExitChunk(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::ReadBONE( int id ){ nuclear@0: while( ChunkSize() ){ nuclear@0: int vertex=ReadInt(); nuclear@0: float weight=ReadFloat(); nuclear@0: if( vertex<0 || vertex>=(int)_vertices.size() ){ nuclear@0: Fail( "Bad vertex index" ); nuclear@0: } nuclear@0: nuclear@0: Vertex &v=_vertices[vertex]; nuclear@0: int i; nuclear@0: for( i=0;i<4;++i ){ nuclear@0: if( !v.weights[i] ){ nuclear@0: v.bones[i]=id; nuclear@0: v.weights[i]=weight; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: #ifdef DEBUG_B3D nuclear@0: if( i==4 ){ nuclear@0: cout<<"Too many bone weights"< trans,scale; nuclear@0: vector rot; nuclear@0: int flags=ReadInt(); nuclear@0: while( ChunkSize() ){ nuclear@0: int frame=ReadInt(); nuclear@0: if( flags & 1 ){ nuclear@0: trans.push_back( aiVectorKey( frame,ReadVec3() ) ); nuclear@0: } nuclear@0: if( flags & 2 ){ nuclear@0: scale.push_back( aiVectorKey( frame,ReadVec3() ) ); nuclear@0: } nuclear@0: if( flags & 4 ){ nuclear@0: rot.push_back( aiQuatKey( frame,ReadQuat() ) ); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if( flags & 1 ){ nuclear@0: nodeAnim->mNumPositionKeys=trans.size(); nuclear@0: nodeAnim->mPositionKeys=to_array( trans ); nuclear@0: } nuclear@0: nuclear@0: if( flags & 2 ){ nuclear@0: nodeAnim->mNumScalingKeys=scale.size(); nuclear@0: nodeAnim->mScalingKeys=to_array( scale ); nuclear@0: } nuclear@0: nuclear@0: if( flags & 4 ){ nuclear@0: nodeAnim->mNumRotationKeys=rot.size(); nuclear@0: nodeAnim->mRotationKeys=to_array( rot ); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::ReadANIM(){ nuclear@0: /*int flags=*/ReadInt(); nuclear@0: int frames=ReadInt(); nuclear@0: float fps=ReadFloat(); nuclear@0: nuclear@0: aiAnimation *anim=new aiAnimation; nuclear@0: _animations.push_back( anim ); nuclear@0: nuclear@0: anim->mDuration=frames; nuclear@0: anim->mTicksPerSecond=fps; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiNode *B3DImporter::ReadNODE( aiNode *parent ){ nuclear@0: nuclear@0: string name=ReadString(); nuclear@0: aiVector3D t=ReadVec3(); nuclear@0: aiVector3D s=ReadVec3(); nuclear@0: aiQuaternion r=ReadQuat(); nuclear@0: nuclear@0: aiMatrix4x4 trans,scale,rot; nuclear@0: nuclear@0: aiMatrix4x4::Translation( t,trans ); nuclear@0: aiMatrix4x4::Scaling( s,scale ); nuclear@0: rot=aiMatrix4x4( r.GetMatrix() ); nuclear@0: nuclear@0: aiMatrix4x4 tform=trans * rot * scale; nuclear@0: nuclear@0: int nodeid=_nodes.size(); nuclear@0: nuclear@0: aiNode *node=new aiNode( name ); nuclear@0: _nodes.push_back( node ); nuclear@0: nuclear@0: node->mParent=parent; nuclear@0: node->mTransformation=tform; nuclear@0: nuclear@0: aiNodeAnim *nodeAnim=0; nuclear@0: vector meshes; nuclear@0: vector children; nuclear@0: nuclear@0: while( ChunkSize() ){ nuclear@0: string t=ReadChunk(); nuclear@0: if( t=="MESH" ){ nuclear@0: int n=_meshes.size(); nuclear@0: ReadMESH(); nuclear@0: for( int i=n;i<(int)_meshes.size();++i ){ nuclear@0: meshes.push_back( i ); nuclear@0: } nuclear@0: }else if( t=="BONE" ){ nuclear@0: ReadBONE( nodeid ); nuclear@0: }else if( t=="ANIM" ){ nuclear@0: ReadANIM(); nuclear@0: }else if( t=="KEYS" ){ nuclear@0: if( !nodeAnim ){ nuclear@0: nodeAnim=new aiNodeAnim; nuclear@0: _nodeAnims.push_back( nodeAnim ); nuclear@0: nodeAnim->mNodeName=node->mName; nuclear@0: } nuclear@0: ReadKEYS( nodeAnim ); nuclear@0: }else if( t=="NODE" ){ nuclear@0: aiNode *child=ReadNODE( node ); nuclear@0: children.push_back( child ); nuclear@0: } nuclear@0: ExitChunk(); nuclear@0: } nuclear@0: nuclear@0: node->mNumMeshes=meshes.size(); nuclear@0: node->mMeshes=to_array( meshes ); nuclear@0: nuclear@0: node->mNumChildren=children.size(); nuclear@0: node->mChildren=to_array( children ); nuclear@0: nuclear@0: return node; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void B3DImporter::ReadBB3D( aiScene *scene ){ nuclear@0: nuclear@0: _textures.clear(); nuclear@0: _materials.size(); nuclear@0: nuclear@0: _vertices.clear(); nuclear@0: _meshes.clear(); nuclear@0: nuclear@0: _nodes.clear(); nuclear@0: _nodeAnims.clear(); nuclear@0: _animations.clear(); nuclear@0: nuclear@0: string t=ReadChunk(); nuclear@0: if( t=="BB3D" ){ nuclear@0: int version=ReadInt(); nuclear@0: nuclear@0: if (!DefaultLogger::isNullLogger()) { nuclear@0: char dmp[128]; nuclear@0: sprintf(dmp,"B3D file format version: %i",version); nuclear@0: DefaultLogger::get()->info(dmp); nuclear@0: } nuclear@0: nuclear@0: while( ChunkSize() ){ nuclear@0: string t=ReadChunk(); nuclear@0: if( t=="TEXS" ){ nuclear@0: ReadTEXS(); nuclear@0: }else if( t=="BRUS" ){ nuclear@0: ReadBRUS(); nuclear@0: }else if( t=="NODE" ){ nuclear@0: ReadNODE( 0 ); nuclear@0: } nuclear@0: ExitChunk(); nuclear@0: } nuclear@0: } nuclear@0: ExitChunk(); nuclear@0: nuclear@0: if( !_nodes.size() ) Fail( "No nodes" ); nuclear@0: nuclear@0: if( !_meshes.size() ) Fail( "No meshes" ); nuclear@0: nuclear@0: //Fix nodes/meshes/bones nuclear@0: for(size_t i=0;i<_nodes.size();++i ){ nuclear@0: aiNode *node=_nodes[i]; nuclear@0: nuclear@0: for( size_t j=0;jmNumMeshes;++j ){ nuclear@0: aiMesh *mesh=_meshes[node->mMeshes[j]]; nuclear@0: nuclear@0: int n_tris=mesh->mNumFaces; nuclear@0: int n_verts=mesh->mNumVertices=n_tris * 3; nuclear@0: nuclear@0: aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; nuclear@0: if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; nuclear@0: if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; nuclear@0: nuclear@0: aiFace *face=mesh->mFaces; nuclear@0: nuclear@0: vector< vector > vweights( _nodes.size() ); nuclear@0: nuclear@0: for( int i=0;imIndices[j]]; nuclear@0: nuclear@0: *mv++=v.vertex; nuclear@0: if( mn ) *mn++=v.normal; nuclear@0: if( mc ) *mc++=v.texcoords; nuclear@0: nuclear@0: face->mIndices[j]=i+j; nuclear@0: nuclear@0: for( int k=0;k<4;++k ){ nuclear@0: if( !v.weights[k] ) break; nuclear@0: nuclear@0: int bone=v.bones[k]; nuclear@0: float weight=v.weights[k]; nuclear@0: nuclear@0: vweights[bone].push_back( aiVertexWeight(i+j,weight) ); nuclear@0: } nuclear@0: } nuclear@0: ++face; nuclear@0: } nuclear@0: nuclear@0: vector bones; nuclear@0: for(size_t i=0;i &weights=vweights[i]; nuclear@0: if( !weights.size() ) continue; nuclear@0: nuclear@0: aiBone *bone=new aiBone; nuclear@0: bones.push_back( bone ); nuclear@0: nuclear@0: aiNode *bnode=_nodes[i]; nuclear@0: nuclear@0: bone->mName=bnode->mName; nuclear@0: bone->mNumWeights=weights.size(); nuclear@0: bone->mWeights=to_array( weights ); nuclear@0: nuclear@0: aiMatrix4x4 mat=bnode->mTransformation; nuclear@0: while( bnode->mParent ){ nuclear@0: bnode=bnode->mParent; nuclear@0: mat=bnode->mTransformation * mat; nuclear@0: } nuclear@0: bone->mOffsetMatrix=mat.Inverse(); nuclear@0: } nuclear@0: mesh->mNumBones=bones.size(); nuclear@0: mesh->mBones=to_array( bones ); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: //nodes nuclear@0: scene->mRootNode=_nodes[0]; nuclear@0: nuclear@0: //material nuclear@0: if( !_materials.size() ){ nuclear@0: _materials.push_back( new aiMaterial ); nuclear@0: } nuclear@0: scene->mNumMaterials=_materials.size(); nuclear@0: scene->mMaterials=to_array( _materials ); nuclear@0: nuclear@0: //meshes nuclear@0: scene->mNumMeshes=_meshes.size(); nuclear@0: scene->mMeshes=to_array( _meshes ); nuclear@0: nuclear@0: //animations nuclear@0: if( _animations.size()==1 && _nodeAnims.size() ){ nuclear@0: nuclear@0: aiAnimation *anim=_animations.back(); nuclear@0: anim->mNumChannels=_nodeAnims.size(); nuclear@0: anim->mChannels=to_array( _nodeAnims ); nuclear@0: nuclear@0: scene->mNumAnimations=_animations.size(); nuclear@0: scene->mAnimations=to_array( _animations ); nuclear@0: } nuclear@0: nuclear@0: // convert to RH nuclear@0: MakeLeftHandedProcess makeleft; nuclear@0: makeleft.Execute( scene ); nuclear@0: nuclear@0: FlipWindingOrderProcess flip; nuclear@0: flip.Execute( scene ); nuclear@0: } nuclear@0: nuclear@0: #endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER