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