|
|
@@ -39,7 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
*/
|
|
|
|
|
|
#include "AssimpPCH.h"
|
|
|
+#ifndef ASSIMP_BUILD_NO_M3_IMPORTER
|
|
|
+
|
|
|
#include "M3Importer.h"
|
|
|
+#include <sstream>
|
|
|
|
|
|
namespace Assimp {
|
|
|
namespace M3 {
|
|
|
@@ -76,16 +79,272 @@ bool M3Importer::CanRead( const std::string &rFile, IOSystem* /*pIOHandler*/, bo
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
void M3Importer::GetExtensionList(std::set<std::string>& extensions)
|
|
|
{
|
|
|
-
|
|
|
+ extensions.insert("m3");
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
void M3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
|
|
|
{
|
|
|
+ const std::string mode = "rb";
|
|
|
+ boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode ) );
|
|
|
+ if ( NULL == file.get() )
|
|
|
+ throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
|
|
+
|
|
|
+ // Get the file-size and validate it, throwing an exception when it fails
|
|
|
+ size_t filesize = file->FileSize();
|
|
|
+ if( filesize < 1 )
|
|
|
+ throw DeadlyImportError( "M3-file is too small.");
|
|
|
+
|
|
|
+ m_Buffer.resize( filesize );
|
|
|
+ size_t readsize = file->Read( &m_Buffer[ 0 ], sizeof( unsigned char ), filesize );
|
|
|
+ ai_assert( readsize == filesize );
|
|
|
+
|
|
|
+ m_pHead = (MD33*)( &m_Buffer[ 0 ] );
|
|
|
+ m_pRefs = (ReferenceEntry*)( &m_Buffer[ 0 ] + m_pHead->ofsRefs );
|
|
|
+
|
|
|
+ MODL20* pMODL20( NULL );
|
|
|
+ MODL23* pMODL23( NULL );
|
|
|
+
|
|
|
+ VertexExt* pVerts1( NULL );
|
|
|
+ Vertex* pVerts2( NULL );
|
|
|
+
|
|
|
+ DIV *pViews( NULL );
|
|
|
+ Region* regions( NULL );
|
|
|
+ uint16* faces( NULL );
|
|
|
+
|
|
|
+ uint32 nVertices = 0;
|
|
|
+ uint32 nFaces = 0;
|
|
|
+
|
|
|
+ bool ok = true;
|
|
|
+ switch( m_pRefs[ m_pHead->MODL.ref ].type )
|
|
|
+ {
|
|
|
+ case 20:
|
|
|
+ pMODL20 = GetEntries<MODL20>( m_pHead->MODL );
|
|
|
+ if ( ( pMODL20->flags & 0x20000) != 0 ) // Has vertices
|
|
|
+ {
|
|
|
+ if( (pMODL20->flags & 0x40000) != 0 ) // Has extra 4 byte
|
|
|
+ {
|
|
|
+ pVerts1 = GetEntries<VertexExt>( pMODL20->vertexData );
|
|
|
+ nVertices = pMODL20->vertexData.nEntries/sizeof(VertexExt);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ pVerts2 = GetEntries<Vertex>(pMODL20->vertexData);
|
|
|
+ nVertices = pMODL20->vertexData.nEntries/sizeof(Vertex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pViews = GetEntries<DIV>( pMODL20->views );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 23:
|
|
|
+ pMODL23 = GetEntries<MODL23>(m_pHead->MODL );
|
|
|
+ if( (pMODL23->flags & 0x20000) != 0 ) // Has vertices
|
|
|
+ {
|
|
|
+ if( (pMODL23->flags & 0x40000) != 0 ) // Has extra 4 byte
|
|
|
+ {
|
|
|
+ pVerts1 = GetEntries<VertexExt>(pMODL23->vertexData);
|
|
|
+ nVertices = pMODL23->vertexData.nEntries/sizeof(VertexExt);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ pVerts2 = GetEntries<Vertex>(pMODL23->vertexData);
|
|
|
+ nVertices = pMODL23->vertexData.nEntries/sizeof(Vertex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pViews = GetEntries<DIV>( pMODL23->views );
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ ok = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get all region data
|
|
|
+ regions = GetEntries<Region>( pViews->regions );
|
|
|
+
|
|
|
+ // Get the face data
|
|
|
+ faces = GetEntries<uint16>( pViews->faces );
|
|
|
+ nFaces = pViews->faces.nEntries;
|
|
|
+
|
|
|
+ // Everything ok, if not throw an exception
|
|
|
+ if ( !ok )
|
|
|
+ throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
|
|
+
|
|
|
+ // Convert the vertices
|
|
|
+ std::vector<aiVector3D> vertices;
|
|
|
+ vertices.resize( nVertices );
|
|
|
+ unsigned int offset = 0;
|
|
|
+ for ( unsigned int i = 0; i < nVertices; i++ )
|
|
|
+ {
|
|
|
+ if ( pVerts1 )
|
|
|
+ {
|
|
|
+ vertices[ offset ].Set( pVerts1[i].pos.x, pVerts1[i].pos.y, pVerts1[i].pos.z );
|
|
|
+ offset++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( pVerts2 )
|
|
|
+ {
|
|
|
+ vertices[ offset ].Set( pVerts2[ i ].pos.x, pVerts2[ i ].pos.y, pVerts2[ i ].pos.z );
|
|
|
+ offset++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Compute the normals
|
|
|
+ std::vector<aiVector3D> normals;
|
|
|
+ normals.resize( nVertices );
|
|
|
+ float w = 0.0f;
|
|
|
+ Vec3D norm;
|
|
|
+ for( unsigned int i = 0; i < nVertices; i++ )
|
|
|
+ {
|
|
|
+ w = 0.0f;
|
|
|
+ if( pVerts1 )
|
|
|
+ {
|
|
|
+ norm.x = (float) 2*pVerts1[ i ].normal[ 0 ]/255.0f - 1;
|
|
|
+ norm.y = (float) 2*pVerts1[ i ].normal[ 1 ]/255.0f - 1;
|
|
|
+ norm.z = (float) 2*pVerts1[ i ].normal[ 2 ]/255.0f - 1;
|
|
|
+ w = (float) pVerts1[ i ].normal[ 3 ]/255.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ if( pVerts2 )
|
|
|
+ {
|
|
|
+ norm.x = (float) 2*pVerts2[ i ].normal[ 0 ]/255.0f - 1;
|
|
|
+ norm.y = (float) 2*pVerts2[ i ].normal[ 1 ]/255.0f - 1;
|
|
|
+ norm.z = (float) 2*pVerts2[ i ].normal[ 2 ]/255.0f - 1;
|
|
|
+
|
|
|
+ w = (float) pVerts2[ i ].normal[ 3 ] / 255.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( w )
|
|
|
+ {
|
|
|
+ const float invW = 1.0f / w;
|
|
|
+ norm.x = norm.x * invW;
|
|
|
+ norm.y = norm.y * invW;
|
|
|
+ norm.z = norm.z * invW;
|
|
|
+ }
|
|
|
+
|
|
|
+ normals[ i ].Set( norm.x, norm.y, norm.z );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Convert the data into the assimp specific data structures
|
|
|
+ convertToAssimp( pFile, pScene, pViews, regions, faces, vertices, normals );
|
|
|
+}
|
|
|
+
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
+//
|
|
|
+void M3Importer::convertToAssimp( const std::string& pFile, aiScene* pScene, DIV *pViews,
|
|
|
+ Region *pRegions, uint16 *pFaces,
|
|
|
+ const std::vector<aiVector3D> &vertices,
|
|
|
+ const std::vector<aiVector3D> &normals )
|
|
|
+{
|
|
|
+ std::vector<aiMesh*> MeshArray;
|
|
|
+
|
|
|
+ // Create the root node
|
|
|
+ pScene->mRootNode = createNode( NULL );
|
|
|
+
|
|
|
+ // Set the name of the scene
|
|
|
+ ai_assert( !pFile.empty() );
|
|
|
+ pScene->mRootNode->mName.Set( pFile );
|
|
|
+
|
|
|
+ aiNode *pRootNode = pScene->mRootNode;
|
|
|
+ aiNode *pCurrentNode = NULL;
|
|
|
+
|
|
|
+ // Lets create the nodes
|
|
|
+ pRootNode->mNumChildren = pViews->regions.nEntries;
|
|
|
+ if ( pRootNode->mNumChildren > 0 )
|
|
|
+ pRootNode->mChildren = new aiNode*[ pRootNode->mNumChildren ];
|
|
|
+
|
|
|
+ for ( unsigned int i=0; i<pViews->regions.nEntries; ++i )
|
|
|
+ {
|
|
|
+ // Create a new node
|
|
|
+ pCurrentNode = createNode( pRootNode );
|
|
|
+ std::stringstream stream;
|
|
|
+ stream << "Node_" << i;
|
|
|
+ pCurrentNode->mName.Set( stream.str().c_str() );
|
|
|
+ pRootNode->mChildren[ i ] = pCurrentNode;
|
|
|
+
|
|
|
+ // Loop over the faces of the nodes
|
|
|
+ unsigned int numFaces = ( pRegions[ i ].ofsIndices + pRegions[ i ].nIndices ) - pRegions[ i ].ofsIndices;
|
|
|
+ aiMesh *pMesh = new aiMesh;
|
|
|
+ MeshArray.push_back( pMesh );
|
|
|
+
|
|
|
+ pMesh->mNumFaces = numFaces;
|
|
|
+ pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
|
|
|
+ aiFace *pCurrentFace = NULL;
|
|
|
+ unsigned int faceIdx = 0;
|
|
|
+ for ( unsigned int j = pRegions[ i ].ofsIndices; j < ( pRegions[ i ].ofsIndices + pRegions[ i ].nIndices ); j += 3 )
|
|
|
+ {
|
|
|
+ pCurrentFace = &( pMesh->mFaces[ faceIdx ] );
|
|
|
+ faceIdx++;
|
|
|
+ pCurrentFace->mNumIndices = 3;
|
|
|
+ pCurrentFace->mIndices = new unsigned int[ 3 ];
|
|
|
+ pCurrentFace->mIndices[ 0 ] = pFaces[ j ]+1;
|
|
|
+ pCurrentFace->mIndices[ 1 ] = pFaces[ j+1 ] + 1;
|
|
|
+ pCurrentFace->mIndices[ 2 ] = pFaces[ j+2 ] + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now we can create the vertex data itself
|
|
|
+ pCurrentNode->mNumMeshes = 1;
|
|
|
+ pCurrentNode->mMeshes = new unsigned int[ 1 ];
|
|
|
+ pCurrentNode->mMeshes[ 0 ] = MeshArray.size() - 1;
|
|
|
+ createVertexData( pMesh, vertices, normals );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy the meshes into the scene
|
|
|
+ pScene->mNumMeshes = MeshArray.size();
|
|
|
+ pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
|
|
|
+ unsigned int pos = 0;
|
|
|
+ for ( std::vector<aiMesh*>::iterator it = MeshArray.begin(); it != MeshArray.end(); ++it )
|
|
|
+ {
|
|
|
+ pScene->mMeshes[ pos ] = *it;
|
|
|
+ pos++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
+//
|
|
|
+void M3Importer::createVertexData( aiMesh *pMesh, const std::vector<aiVector3D> &vertices,
|
|
|
+ const std::vector<aiVector3D> &normals )
|
|
|
+{
|
|
|
+ unsigned int numIndices = 0;
|
|
|
+
|
|
|
+ pMesh->mNumVertices = pMesh->mNumFaces * 3;
|
|
|
+ pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
|
|
|
+ pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ];
|
|
|
+ unsigned int pos = 0;
|
|
|
+ for ( unsigned int currentFace = 0; currentFace < pMesh->mNumFaces; currentFace++ )
|
|
|
+ {
|
|
|
+ aiFace *pFace = &( pMesh->mFaces[ currentFace ] );
|
|
|
+ for ( unsigned int currentIdx=0; currentIdx<pFace->mNumIndices; currentIdx++ )
|
|
|
+ {
|
|
|
+ unsigned int idx = pFace->mIndices[ currentIdx ];
|
|
|
+ if ( vertices.size() > idx )
|
|
|
+ {
|
|
|
+ pMesh->mVertices[ pos ] = vertices[ idx ];
|
|
|
+ pMesh->mNormals[ pos ] = normals[ idx ];
|
|
|
|
|
|
+ pFace->mIndices[ currentIdx ] = pos;
|
|
|
+ pos++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
+//
|
|
|
+aiNode *M3Importer::createNode( aiNode *pParent )
|
|
|
+{
|
|
|
+ aiNode *pNode = new aiNode;
|
|
|
+ if ( pParent )
|
|
|
+ pNode->mParent = pParent;
|
|
|
+ else
|
|
|
+ pNode->mParent = NULL;
|
|
|
+
|
|
|
+ return pNode;
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
|
|
} // Namespace M3
|
|
|
} // Namespace Assimp
|
|
|
+
|
|
|
+#endif // ASSIMP_BUILD_NO_M3_IMPORTER
|