nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2008, assimp team 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 nuclear@0: following 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: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER nuclear@0: nuclear@0: //#include nuclear@0: #include "DefaultIOSystem.h" nuclear@0: #include "Q3BSPFileImporter.h" nuclear@0: #include "Q3BSPZipArchive.h" nuclear@0: #include "Q3BSPFileParser.h" nuclear@0: #include "Q3BSPFileData.h" nuclear@0: nuclear@0: #ifdef ASSIMP_BUILD_NO_OWN_ZLIB nuclear@0: # include nuclear@0: #else nuclear@0: # include "../contrib/zlib/zlib.h" nuclear@0: #endif nuclear@0: nuclear@0: #include "assimp/types.h" nuclear@0: #include "assimp/mesh.h" nuclear@0: #include nuclear@0: nuclear@0: nuclear@0: static const aiImporterDesc desc = { nuclear@0: "Quake III BSP Importer", nuclear@0: "", nuclear@0: "", nuclear@0: "", nuclear@0: aiImporterFlags_SupportBinaryFlavour, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: "pk3" nuclear@0: }; nuclear@0: nuclear@0: namespace Assimp nuclear@0: { nuclear@0: nuclear@0: using namespace Q3BSP; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Local function to create a material key name. nuclear@0: static void createKey( int id1, int id2, std::string &rKey ) nuclear@0: { nuclear@0: std::ostringstream str; nuclear@0: str << id1 << "." << id2; nuclear@0: rKey = str.str(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Local function to extract the texture ids from a material keyname. nuclear@0: static void extractIds( const std::string &rKey, int &rId1, int &rId2 ) nuclear@0: { nuclear@0: rId1 = -1; nuclear@0: rId2 = -1; nuclear@0: if ( rKey.empty() ) nuclear@0: return; nuclear@0: nuclear@0: std::string::size_type pos = rKey.find( "." ); nuclear@0: if ( std::string::npos == pos ) nuclear@0: return; nuclear@0: nuclear@0: std::string tmp1 = rKey.substr( 0, pos ); nuclear@0: std::string tmp2 = rKey.substr( pos + 1, rKey.size() - pos - 1 ); nuclear@0: rId1 = atoi( tmp1.c_str() ); nuclear@0: rId2 = atoi( tmp2.c_str() ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Local helper function to normalize filenames. nuclear@0: static void normalizePathName( const std::string &rPath, std::string &rNormalizedPath ) nuclear@0: { nuclear@0: rNormalizedPath = ""; nuclear@0: if ( rPath.empty() ) nuclear@0: return; nuclear@0: nuclear@0: #ifdef _WIN32 nuclear@0: std::string sep = "\\"; nuclear@0: #else nuclear@0: std::string sep = "/"; nuclear@0: #endif nuclear@0: nuclear@0: static const unsigned int numDelimiters = 2; nuclear@0: const char delimiters[ numDelimiters ] = { '/', '\\' }; nuclear@0: rNormalizedPath = rPath; nuclear@0: for ( unsigned int i=0; i *pCurFaceArray = (*it).second; nuclear@0: delete pCurFaceArray; nuclear@0: } nuclear@0: m_MaterialLookupMap.clear(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns true, if the loader can read this. nuclear@0: bool Q3BSPFileImporter::CanRead( const std::string& rFile, IOSystem* /*pIOHandler*/, bool checkSig ) const nuclear@0: { nuclear@0: if(!checkSig) { nuclear@0: return SimpleExtensionCheck( rFile, "pk3" ); nuclear@0: } nuclear@0: // TODO perhaps add keyword based detection nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Adds extensions. nuclear@0: const aiImporterDesc* Q3BSPFileImporter::GetInfo () const nuclear@0: { nuclear@0: return &desc; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Import method. nuclear@0: void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* pScene, IOSystem* /*pIOHandler*/) nuclear@0: { nuclear@0: Q3BSPZipArchive Archive( rFile ); nuclear@0: if ( !Archive.isOpen() ) nuclear@0: { nuclear@0: throw DeadlyImportError( "Failed to open file " + rFile + "." ); nuclear@0: } nuclear@0: nuclear@0: std::string archiveName( "" ), mapName( "" ); nuclear@0: separateMapName( rFile, archiveName, mapName ); nuclear@0: nuclear@0: if ( mapName.empty() ) nuclear@0: { nuclear@0: if ( !findFirstMapInArchive( Archive, mapName ) ) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: Q3BSPFileParser fileParser( mapName, &Archive ); nuclear@0: Q3BSPModel *pBSPModel = fileParser.getModel(); nuclear@0: if ( NULL != pBSPModel ) nuclear@0: { nuclear@0: CreateDataFromImport( pBSPModel, pScene, &Archive ); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Separates the map name from the import name. nuclear@0: void Q3BSPFileImporter::separateMapName( const std::string &rImportName, std::string &rArchiveName, nuclear@0: std::string &rMapName ) nuclear@0: { nuclear@0: rArchiveName = ""; nuclear@0: rMapName = ""; nuclear@0: if ( rImportName.empty() ) nuclear@0: return; nuclear@0: nuclear@0: std::string::size_type pos = rImportName.rfind( "," ); nuclear@0: if ( std::string::npos == pos ) nuclear@0: { nuclear@0: rArchiveName = rImportName; nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: rArchiveName = rImportName.substr( 0, pos ); nuclear@0: rMapName = rImportName.substr( pos, rImportName.size() - pos - 1 ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns the first map in the map archive. nuclear@0: bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &rArchive, std::string &rMapName ) nuclear@0: { nuclear@0: rMapName = ""; nuclear@0: std::vector fileList; nuclear@0: rArchive.getFileList( fileList ); nuclear@0: if ( fileList.empty() ) nuclear@0: return false; nuclear@0: nuclear@0: for ( std::vector::iterator it = fileList.begin(); it != fileList.end(); nuclear@0: ++it ) nuclear@0: { nuclear@0: std::string::size_type pos = (*it).find( "maps/" ); nuclear@0: if ( std::string::npos != pos ) nuclear@0: { nuclear@0: std::string::size_type extPos = (*it).find( ".bsp" ); nuclear@0: if ( std::string::npos != extPos ) nuclear@0: { nuclear@0: rMapName = *it; nuclear@0: return true; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Creates the assimp specific data. nuclear@0: void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, nuclear@0: Q3BSPZipArchive *pArchive ) nuclear@0: { nuclear@0: if ( NULL == pModel || NULL == pScene ) nuclear@0: return; nuclear@0: nuclear@0: pScene->mRootNode = new aiNode; nuclear@0: if ( !pModel->m_ModelName.empty() ) nuclear@0: { nuclear@0: pScene->mRootNode->mName.Set( pModel->m_ModelName ); nuclear@0: } nuclear@0: nuclear@0: // Create the face to material relation map nuclear@0: createMaterialMap( pModel ); nuclear@0: nuclear@0: // Create all nodes nuclear@0: CreateNodes( pModel, pScene, pScene->mRootNode ); nuclear@0: nuclear@0: // Create the assigned materials nuclear@0: createMaterials( pModel, pScene, pArchive ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Creates all assimp nodes. nuclear@0: void Q3BSPFileImporter::CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, nuclear@0: aiNode *pParent ) nuclear@0: { nuclear@0: ai_assert( NULL != pModel ); nuclear@0: if ( NULL == pModel ) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: unsigned int matIdx = 0; nuclear@0: std::vector MeshArray; nuclear@0: std::vector NodeArray; nuclear@0: for ( FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it ) nuclear@0: { nuclear@0: std::vector *pArray = (*it).second; nuclear@0: size_t numVerts = countData( *pArray ); nuclear@0: if ( 0 != numVerts ) nuclear@0: { nuclear@0: aiMesh* pMesh = new aiMesh; nuclear@0: aiNode *pNode = CreateTopology( pModel, matIdx, *pArray, pMesh ); nuclear@0: if ( NULL != pNode ) nuclear@0: { nuclear@0: NodeArray.push_back( pNode ); nuclear@0: MeshArray.push_back( pMesh ); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: delete pMesh; nuclear@0: } nuclear@0: } nuclear@0: matIdx++; nuclear@0: } nuclear@0: nuclear@0: pScene->mNumMeshes = MeshArray.size(); nuclear@0: if ( pScene->mNumMeshes > 0 ) nuclear@0: { nuclear@0: pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; nuclear@0: for ( size_t i = 0; i < MeshArray.size(); i++ ) nuclear@0: { nuclear@0: aiMesh *pMesh = MeshArray[ i ]; nuclear@0: if ( NULL != pMesh ) nuclear@0: { nuclear@0: pScene->mMeshes[ i ] = pMesh; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: pParent->mNumChildren = MeshArray.size(); nuclear@0: pParent->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren ]; nuclear@0: for ( size_t i=0; imParent = pParent; nuclear@0: pParent->mChildren[ i ] = pNode; nuclear@0: pParent->mChildren[ i ]->mMeshes[ 0 ] = i; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Creates the topology. nuclear@0: aiNode *Q3BSPFileImporter::CreateTopology( const Q3BSP::Q3BSPModel *pModel, nuclear@0: unsigned int materialIdx, nuclear@0: std::vector &rArray, nuclear@0: aiMesh* pMesh ) nuclear@0: { nuclear@0: size_t numVerts = countData( rArray ); nuclear@0: if ( 0 == numVerts ) nuclear@0: { nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: size_t numFaces = countFaces( rArray ); nuclear@0: if ( 0 == numFaces ) nuclear@0: { nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: size_t numTriangles = countTriangles( rArray ); nuclear@0: pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; nuclear@0: nuclear@0: pMesh->mFaces = new aiFace[ numTriangles ]; nuclear@0: pMesh->mNumFaces = numTriangles; nuclear@0: nuclear@0: pMesh->mNumVertices = numVerts; nuclear@0: pMesh->mVertices = new aiVector3D[ numVerts ]; nuclear@0: pMesh->mNormals = new aiVector3D[ numVerts ]; nuclear@0: pMesh->mTextureCoords[ 0 ] = new aiVector3D[ numVerts ]; nuclear@0: pMesh->mTextureCoords[ 1 ] = new aiVector3D[ numVerts ]; nuclear@0: pMesh->mMaterialIndex = materialIdx; nuclear@0: nuclear@0: unsigned int faceIdx = 0; nuclear@0: unsigned int vertIdx = 0; nuclear@0: pMesh->mNumUVComponents[ 0 ] = 2; nuclear@0: pMesh->mNumUVComponents[ 1 ] = 2; nuclear@0: for ( std::vector::const_iterator it = rArray.begin(); it != rArray.end(); ++it ) nuclear@0: { nuclear@0: Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; nuclear@0: ai_assert( NULL != pQ3BSPFace ); nuclear@0: if ( NULL == pQ3BSPFace ) nuclear@0: { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: if ( pQ3BSPFace->iNumOfFaceVerts > 0 ) nuclear@0: { nuclear@0: if ( pQ3BSPFace->iType == Polygon || pQ3BSPFace->iType == TriangleMesh ) nuclear@0: { nuclear@0: createTriangleTopology( pModel, pQ3BSPFace, pMesh, faceIdx, vertIdx ); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: aiNode *pNode = new aiNode; nuclear@0: pNode->mNumMeshes = 1; nuclear@0: pNode->mMeshes = new unsigned int[ 1 ]; nuclear@0: nuclear@0: return pNode; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Creates the triangle topology from a face array. nuclear@0: void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, nuclear@0: Q3BSP::sQ3BSPFace *pQ3BSPFace, nuclear@0: aiMesh* pMesh, nuclear@0: unsigned int &rFaceIdx, nuclear@0: unsigned int &rVertIdx ) nuclear@0: { nuclear@0: ai_assert( rFaceIdx < pMesh->mNumFaces ); nuclear@0: nuclear@0: m_pCurrentFace = getNextFace( pMesh, rFaceIdx ); nuclear@0: ai_assert( NULL != m_pCurrentFace ); nuclear@0: if ( NULL == m_pCurrentFace ) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: m_pCurrentFace->mNumIndices = 3; nuclear@0: m_pCurrentFace->mIndices = new unsigned int[ m_pCurrentFace->mNumIndices ]; nuclear@0: nuclear@0: size_t idx = 0; nuclear@0: for ( size_t i = 0; i < (size_t) pQ3BSPFace->iNumOfFaceVerts; i++ ) nuclear@0: { nuclear@0: const size_t index = pQ3BSPFace->iVertexIndex + pModel->m_Indices[ pQ3BSPFace->iFaceVertexIndex + i ]; nuclear@0: ai_assert( index < pModel->m_Vertices.size() ); nuclear@0: if ( index >= pModel->m_Vertices.size() ) nuclear@0: { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: sQ3BSPVertex *pVertex = pModel->m_Vertices[ index ]; nuclear@0: ai_assert( NULL != pVertex ); nuclear@0: if ( NULL == pVertex ) nuclear@0: { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: pMesh->mVertices[ rVertIdx ].Set( pVertex->vPosition.x, pVertex->vPosition.y, pVertex->vPosition.z ); nuclear@0: pMesh->mNormals[ rVertIdx ].Set( pVertex->vNormal.x, pVertex->vNormal.y, pVertex->vNormal.z ); nuclear@0: nuclear@0: pMesh->mTextureCoords[ 0 ][ rVertIdx ].Set( pVertex->vTexCoord.x, pVertex->vTexCoord.y, 0.0f ); nuclear@0: pMesh->mTextureCoords[ 1 ][ rVertIdx ].Set( pVertex->vLightmap.x, pVertex->vLightmap.y, 0.0f ); nuclear@0: nuclear@0: m_pCurrentFace->mIndices[ idx ] = rVertIdx; nuclear@0: rVertIdx++; nuclear@0: nuclear@0: idx++; nuclear@0: if ( idx > 2 ) nuclear@0: { nuclear@0: idx = 0; nuclear@0: m_pCurrentFace = getNextFace( pMesh, rFaceIdx ); nuclear@0: if ( NULL != m_pCurrentFace ) nuclear@0: { nuclear@0: m_pCurrentFace->mNumIndices = 3; nuclear@0: m_pCurrentFace->mIndices = new unsigned int[ 3 ]; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: rFaceIdx--; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Creates all referenced materials. nuclear@0: void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, nuclear@0: Q3BSPZipArchive *pArchive ) nuclear@0: { nuclear@0: if ( m_MaterialLookupMap.empty() ) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: pScene->mMaterials = new aiMaterial*[ m_MaterialLookupMap.size() ]; nuclear@0: aiString aiMatName; nuclear@0: int textureId( -1 ), lightmapId( -1 ); nuclear@0: for ( FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); nuclear@0: ++it ) nuclear@0: { nuclear@0: const std::string matName = (*it).first; nuclear@0: if ( matName.empty() ) nuclear@0: { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: aiMatName.Set( matName ); nuclear@0: aiMaterial *pMatHelper = new aiMaterial; nuclear@0: pMatHelper->AddProperty( &aiMatName, AI_MATKEY_NAME ); nuclear@0: nuclear@0: extractIds( matName, textureId, lightmapId ); nuclear@0: nuclear@0: // Adding the texture nuclear@0: if ( -1 != textureId ) nuclear@0: { nuclear@0: sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ]; nuclear@0: if ( NULL != pTexture ) nuclear@0: { nuclear@0: std::string tmp( "*" ), texName( "" ); nuclear@0: tmp += pTexture->strName; nuclear@0: tmp += ".jpg"; nuclear@0: normalizePathName( tmp, texName ); nuclear@0: nuclear@0: if ( !importTextureFromArchive( pModel, pArchive, pScene, pMatHelper, textureId ) ) nuclear@0: { nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: } nuclear@0: if ( -1 != lightmapId ) nuclear@0: { nuclear@0: importLightmap( pModel, pScene, pMatHelper, lightmapId ); nuclear@0: } nuclear@0: pScene->mMaterials[ pScene->mNumMaterials ] = pMatHelper; nuclear@0: pScene->mNumMaterials++; nuclear@0: } nuclear@0: pScene->mNumTextures = mTextures.size(); nuclear@0: pScene->mTextures = new aiTexture*[ pScene->mNumTextures ]; nuclear@0: std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Counts the number of referenced vertices. nuclear@0: size_t Q3BSPFileImporter::countData( const std::vector &rArray ) const nuclear@0: { nuclear@0: size_t numVerts = 0; nuclear@0: for ( std::vector::const_iterator it = rArray.begin(); it != rArray.end(); nuclear@0: ++it ) nuclear@0: { nuclear@0: sQ3BSPFace *pQ3BSPFace = *it; nuclear@0: if ( pQ3BSPFace->iType == Polygon || pQ3BSPFace->iType == TriangleMesh ) nuclear@0: { nuclear@0: Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; nuclear@0: ai_assert( NULL != pQ3BSPFace ); nuclear@0: numVerts += pQ3BSPFace->iNumOfFaceVerts; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return numVerts; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Counts the faces with vertices. nuclear@0: size_t Q3BSPFileImporter::countFaces( const std::vector &rArray ) const nuclear@0: { nuclear@0: size_t numFaces = 0; nuclear@0: for ( std::vector::const_iterator it = rArray.begin(); it != rArray.end(); nuclear@0: ++it ) nuclear@0: { nuclear@0: Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; nuclear@0: if ( pQ3BSPFace->iNumOfFaceVerts > 0 ) nuclear@0: { nuclear@0: numFaces++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return numFaces; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Counts the number of triangles in a Q3-facearray. nuclear@0: size_t Q3BSPFileImporter::countTriangles( const std::vector &rArray ) const nuclear@0: { nuclear@0: size_t numTriangles = 0; nuclear@0: for ( std::vector::const_iterator it = rArray.begin(); it != rArray.end(); nuclear@0: ++it ) nuclear@0: { nuclear@0: const Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; nuclear@0: if ( NULL != pQ3BSPFace ) nuclear@0: { nuclear@0: numTriangles += pQ3BSPFace->iNumOfFaceVerts / 3; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return numTriangles; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Creates the faces-to-material map. nuclear@0: void Q3BSPFileImporter::createMaterialMap( const Q3BSP::Q3BSPModel *pModel ) nuclear@0: { nuclear@0: std::string key( "" ); nuclear@0: std::vector *pCurFaceArray = NULL; nuclear@0: for ( size_t idx = 0; idx < pModel->m_Faces.size(); idx++ ) nuclear@0: { nuclear@0: Q3BSP::sQ3BSPFace *pQ3BSPFace = pModel->m_Faces[ idx ]; nuclear@0: const int texId = pQ3BSPFace->iTextureID; nuclear@0: const int lightMapId = pQ3BSPFace->iLightmapID; nuclear@0: createKey( texId, lightMapId, key ); nuclear@0: FaceMapIt it = m_MaterialLookupMap.find( key ); nuclear@0: if ( m_MaterialLookupMap.end() == it ) nuclear@0: { nuclear@0: pCurFaceArray = new std::vector; nuclear@0: m_MaterialLookupMap[ key ] = pCurFaceArray; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: pCurFaceArray = (*it).second; nuclear@0: } nuclear@0: ai_assert( NULL != pCurFaceArray ); nuclear@0: if ( NULL != pCurFaceArray ) nuclear@0: { nuclear@0: pCurFaceArray->push_back( pQ3BSPFace ); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns the next face. nuclear@0: aiFace *Q3BSPFileImporter::getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx ) nuclear@0: { nuclear@0: aiFace *pFace = NULL; nuclear@0: if ( rFaceIdx < pMesh->mNumFaces ) nuclear@0: { nuclear@0: pFace = &pMesh->mFaces[ rFaceIdx ]; nuclear@0: rFaceIdx++; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: pFace = NULL; nuclear@0: } nuclear@0: nuclear@0: return pFace; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Imports a texture file. nuclear@0: bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, nuclear@0: Q3BSP::Q3BSPZipArchive *pArchive, aiScene* /*pScene*/, nuclear@0: aiMaterial *pMatHelper, int textureId ) nuclear@0: { nuclear@0: std::vector supportedExtensions; nuclear@0: supportedExtensions.push_back( ".jpg" ); nuclear@0: supportedExtensions.push_back( ".png" ); nuclear@0: supportedExtensions.push_back( ".tga" ); nuclear@0: if ( NULL == pArchive || NULL == pArchive || NULL == pMatHelper ) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if ( textureId < 0 || textureId >= static_cast( pModel->m_Textures.size() ) ) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: bool res = true; nuclear@0: sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ]; nuclear@0: if ( NULL == pTexture ) nuclear@0: return false; nuclear@0: nuclear@0: std::string textureName, ext; nuclear@0: if ( expandFile( pArchive, pTexture->strName, supportedExtensions, textureName, ext ) ) nuclear@0: { nuclear@0: IOStream *pTextureStream = pArchive->Open( textureName.c_str() ); nuclear@0: if ( NULL != pTextureStream ) nuclear@0: { nuclear@0: size_t texSize = pTextureStream->FileSize(); nuclear@0: aiTexture *pTexture = new aiTexture; nuclear@0: pTexture->mHeight = 0; nuclear@0: pTexture->mWidth = texSize; nuclear@0: unsigned char *pData = new unsigned char[ pTexture->mWidth ]; nuclear@0: size_t readSize = pTextureStream->Read( pData, sizeof( unsigned char ), pTexture->mWidth ); nuclear@0: (void)readSize; nuclear@0: ai_assert( readSize == pTexture->mWidth ); nuclear@0: pTexture->pcData = reinterpret_cast( pData ); nuclear@0: pTexture->achFormatHint[ 0 ] = ext[ 1 ]; nuclear@0: pTexture->achFormatHint[ 1 ] = ext[ 2 ]; nuclear@0: pTexture->achFormatHint[ 2 ] = ext[ 3 ]; nuclear@0: pTexture->achFormatHint[ 3 ] = '\0'; nuclear@0: res = true; nuclear@0: nuclear@0: aiString name; nuclear@0: name.data[ 0 ] = '*'; nuclear@0: name.length = 1 + ASSIMP_itoa10( name.data + 1, MAXLEN-1, mTextures.size() ); nuclear@0: nuclear@0: pArchive->Close( pTextureStream ); nuclear@0: nuclear@0: pMatHelper->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) ); nuclear@0: mTextures.push_back( pTexture ); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // If it doesn't exist in the archive, it is probably just a reference to an external file. nuclear@0: // We'll leave it up to the user to figure out which extension the file has. nuclear@0: aiString name; nuclear@0: strncpy( name.data, pTexture->strName, sizeof name.data ); nuclear@0: name.length = strlen( name.data ); nuclear@0: pMatHelper->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) ); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return res; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Imports a light map file. nuclear@0: bool Q3BSPFileImporter::importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, nuclear@0: aiMaterial *pMatHelper, int lightmapId ) nuclear@0: { nuclear@0: if ( NULL == pModel || NULL == pScene || NULL == pMatHelper ) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if ( lightmapId < 0 || lightmapId >= static_cast( pModel->m_Lightmaps.size() ) ) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: sQ3BSPLightmap *pLightMap = pModel->m_Lightmaps[ lightmapId ]; nuclear@0: if ( NULL == pLightMap ) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: aiTexture *pTexture = new aiTexture; nuclear@0: nuclear@0: pTexture->mWidth = CE_BSP_LIGHTMAPWIDTH; nuclear@0: pTexture->mHeight = CE_BSP_LIGHTMAPHEIGHT; nuclear@0: pTexture->pcData = new aiTexel[CE_BSP_LIGHTMAPWIDTH * CE_BSP_LIGHTMAPHEIGHT]; nuclear@0: nuclear@0: ::memcpy( pTexture->pcData, pLightMap->bLMapData, pTexture->mWidth ); nuclear@0: size_t p = 0; nuclear@0: for ( size_t i = 0; i < CE_BSP_LIGHTMAPWIDTH * CE_BSP_LIGHTMAPHEIGHT; ++i ) nuclear@0: { nuclear@0: pTexture->pcData[ i ].r = pLightMap->bLMapData[ p++ ]; nuclear@0: pTexture->pcData[ i ].g = pLightMap->bLMapData[ p++ ]; nuclear@0: pTexture->pcData[ i ].b = pLightMap->bLMapData[ p++ ]; nuclear@0: pTexture->pcData[ i ].a = 0xFF; nuclear@0: } nuclear@0: nuclear@0: aiString name; nuclear@0: name.data[ 0 ] = '*'; nuclear@0: name.length = 1 + ASSIMP_itoa10( name.data + 1, MAXLEN-1, mTextures.size() ); nuclear@0: nuclear@0: pMatHelper->AddProperty( &name,AI_MATKEY_TEXTURE_LIGHTMAP( 1 ) ); nuclear@0: mTextures.push_back( pTexture ); nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Will search for a supported extension. nuclear@0: bool Q3BSPFileImporter::expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, nuclear@0: const std::vector &rExtList, std::string &rFile, nuclear@0: std::string &rExt ) nuclear@0: { nuclear@0: ai_assert( NULL != pArchive ); nuclear@0: ai_assert( !rFilename.empty() ); nuclear@0: nuclear@0: if ( rExtList.empty() ) nuclear@0: { nuclear@0: rFile = rFilename; nuclear@0: rExt = ""; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: bool found = false; nuclear@0: for ( std::vector::const_iterator it = rExtList.begin(); it != rExtList.end(); ++it ) nuclear@0: { nuclear@0: const std::string textureName = rFilename + *it; nuclear@0: if ( pArchive->Exists( textureName.c_str() ) ) nuclear@0: { nuclear@0: rExt = *it; nuclear@0: rFile = textureName; nuclear@0: found = true; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return found; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: nuclear@0: } // Namespace Assimp nuclear@0: nuclear@0: #endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER