vrshoot

annotate libs/assimp/Q3BSPFileImporter.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ---------------------------------------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2008, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ---------------------------------------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40 #include "AssimpPCH.h"
nuclear@0 41 #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
nuclear@0 42
nuclear@0 43 //#include <windows.h>
nuclear@0 44 #include "DefaultIOSystem.h"
nuclear@0 45 #include "Q3BSPFileImporter.h"
nuclear@0 46 #include "Q3BSPZipArchive.h"
nuclear@0 47 #include "Q3BSPFileParser.h"
nuclear@0 48 #include "Q3BSPFileData.h"
nuclear@0 49
nuclear@0 50 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
nuclear@0 51 # include <zlib.h>
nuclear@0 52 #else
nuclear@0 53 # include "../contrib/zlib/zlib.h"
nuclear@0 54 #endif
nuclear@0 55
nuclear@0 56 #include "assimp/types.h"
nuclear@0 57 #include "assimp/mesh.h"
nuclear@0 58 #include <vector>
nuclear@0 59
nuclear@0 60
nuclear@0 61 static const aiImporterDesc desc = {
nuclear@0 62 "Quake III BSP Importer",
nuclear@0 63 "",
nuclear@0 64 "",
nuclear@0 65 "",
nuclear@0 66 aiImporterFlags_SupportBinaryFlavour,
nuclear@0 67 0,
nuclear@0 68 0,
nuclear@0 69 0,
nuclear@0 70 0,
nuclear@0 71 "pk3"
nuclear@0 72 };
nuclear@0 73
nuclear@0 74 namespace Assimp
nuclear@0 75 {
nuclear@0 76
nuclear@0 77 using namespace Q3BSP;
nuclear@0 78
nuclear@0 79 // ------------------------------------------------------------------------------------------------
nuclear@0 80 // Local function to create a material key name.
nuclear@0 81 static void createKey( int id1, int id2, std::string &rKey )
nuclear@0 82 {
nuclear@0 83 std::ostringstream str;
nuclear@0 84 str << id1 << "." << id2;
nuclear@0 85 rKey = str.str();
nuclear@0 86 }
nuclear@0 87
nuclear@0 88 // ------------------------------------------------------------------------------------------------
nuclear@0 89 // Local function to extract the texture ids from a material keyname.
nuclear@0 90 static void extractIds( const std::string &rKey, int &rId1, int &rId2 )
nuclear@0 91 {
nuclear@0 92 rId1 = -1;
nuclear@0 93 rId2 = -1;
nuclear@0 94 if ( rKey.empty() )
nuclear@0 95 return;
nuclear@0 96
nuclear@0 97 std::string::size_type pos = rKey.find( "." );
nuclear@0 98 if ( std::string::npos == pos )
nuclear@0 99 return;
nuclear@0 100
nuclear@0 101 std::string tmp1 = rKey.substr( 0, pos );
nuclear@0 102 std::string tmp2 = rKey.substr( pos + 1, rKey.size() - pos - 1 );
nuclear@0 103 rId1 = atoi( tmp1.c_str() );
nuclear@0 104 rId2 = atoi( tmp2.c_str() );
nuclear@0 105 }
nuclear@0 106
nuclear@0 107 // ------------------------------------------------------------------------------------------------
nuclear@0 108 // Local helper function to normalize filenames.
nuclear@0 109 static void normalizePathName( const std::string &rPath, std::string &rNormalizedPath )
nuclear@0 110 {
nuclear@0 111 rNormalizedPath = "";
nuclear@0 112 if ( rPath.empty() )
nuclear@0 113 return;
nuclear@0 114
nuclear@0 115 #ifdef _WIN32
nuclear@0 116 std::string sep = "\\";
nuclear@0 117 #else
nuclear@0 118 std::string sep = "/";
nuclear@0 119 #endif
nuclear@0 120
nuclear@0 121 static const unsigned int numDelimiters = 2;
nuclear@0 122 const char delimiters[ numDelimiters ] = { '/', '\\' };
nuclear@0 123 rNormalizedPath = rPath;
nuclear@0 124 for ( unsigned int i=0; i<numDelimiters; i++ )
nuclear@0 125 {
nuclear@0 126 for ( size_t j=0; j<rNormalizedPath.size(); j++ )
nuclear@0 127 {
nuclear@0 128 if ( rNormalizedPath[j] == delimiters[ i ] )
nuclear@0 129 {
nuclear@0 130 rNormalizedPath[ j ] = sep[ 0 ];
nuclear@0 131 }
nuclear@0 132 }
nuclear@0 133 }
nuclear@0 134 }
nuclear@0 135
nuclear@0 136 // ------------------------------------------------------------------------------------------------
nuclear@0 137 // Constructor.
nuclear@0 138 Q3BSPFileImporter::Q3BSPFileImporter() :
nuclear@0 139 m_pCurrentMesh( NULL ),
nuclear@0 140 m_pCurrentFace( NULL ),
nuclear@0 141 m_MaterialLookupMap(),
nuclear@0 142 mTextures()
nuclear@0 143 {
nuclear@0 144 // empty
nuclear@0 145 }
nuclear@0 146
nuclear@0 147 // ------------------------------------------------------------------------------------------------
nuclear@0 148 // Destructor.
nuclear@0 149 Q3BSPFileImporter::~Q3BSPFileImporter()
nuclear@0 150 {
nuclear@0 151 // For lint
nuclear@0 152 m_pCurrentMesh = NULL;
nuclear@0 153 m_pCurrentFace = NULL;
nuclear@0 154
nuclear@0 155 // Clear face-to-material map
nuclear@0 156 for ( FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end();
nuclear@0 157 ++it )
nuclear@0 158 {
nuclear@0 159 const std::string matName = (*it).first;
nuclear@0 160 if ( matName.empty() )
nuclear@0 161 {
nuclear@0 162 continue;
nuclear@0 163 }
nuclear@0 164
nuclear@0 165 std::vector<Q3BSP::sQ3BSPFace*> *pCurFaceArray = (*it).second;
nuclear@0 166 delete pCurFaceArray;
nuclear@0 167 }
nuclear@0 168 m_MaterialLookupMap.clear();
nuclear@0 169 }
nuclear@0 170
nuclear@0 171 // ------------------------------------------------------------------------------------------------
nuclear@0 172 // Returns true, if the loader can read this.
nuclear@0 173 bool Q3BSPFileImporter::CanRead( const std::string& rFile, IOSystem* /*pIOHandler*/, bool checkSig ) const
nuclear@0 174 {
nuclear@0 175 if(!checkSig) {
nuclear@0 176 return SimpleExtensionCheck( rFile, "pk3" );
nuclear@0 177 }
nuclear@0 178 // TODO perhaps add keyword based detection
nuclear@0 179 return false;
nuclear@0 180 }
nuclear@0 181
nuclear@0 182 // ------------------------------------------------------------------------------------------------
nuclear@0 183 // Adds extensions.
nuclear@0 184 const aiImporterDesc* Q3BSPFileImporter::GetInfo () const
nuclear@0 185 {
nuclear@0 186 return &desc;
nuclear@0 187 }
nuclear@0 188
nuclear@0 189 // ------------------------------------------------------------------------------------------------
nuclear@0 190 // Import method.
nuclear@0 191 void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* pScene, IOSystem* /*pIOHandler*/)
nuclear@0 192 {
nuclear@0 193 Q3BSPZipArchive Archive( rFile );
nuclear@0 194 if ( !Archive.isOpen() )
nuclear@0 195 {
nuclear@0 196 throw DeadlyImportError( "Failed to open file " + rFile + "." );
nuclear@0 197 }
nuclear@0 198
nuclear@0 199 std::string archiveName( "" ), mapName( "" );
nuclear@0 200 separateMapName( rFile, archiveName, mapName );
nuclear@0 201
nuclear@0 202 if ( mapName.empty() )
nuclear@0 203 {
nuclear@0 204 if ( !findFirstMapInArchive( Archive, mapName ) )
nuclear@0 205 {
nuclear@0 206 return;
nuclear@0 207 }
nuclear@0 208 }
nuclear@0 209
nuclear@0 210 Q3BSPFileParser fileParser( mapName, &Archive );
nuclear@0 211 Q3BSPModel *pBSPModel = fileParser.getModel();
nuclear@0 212 if ( NULL != pBSPModel )
nuclear@0 213 {
nuclear@0 214 CreateDataFromImport( pBSPModel, pScene, &Archive );
nuclear@0 215 }
nuclear@0 216 }
nuclear@0 217
nuclear@0 218 // ------------------------------------------------------------------------------------------------
nuclear@0 219 // Separates the map name from the import name.
nuclear@0 220 void Q3BSPFileImporter::separateMapName( const std::string &rImportName, std::string &rArchiveName,
nuclear@0 221 std::string &rMapName )
nuclear@0 222 {
nuclear@0 223 rArchiveName = "";
nuclear@0 224 rMapName = "";
nuclear@0 225 if ( rImportName.empty() )
nuclear@0 226 return;
nuclear@0 227
nuclear@0 228 std::string::size_type pos = rImportName.rfind( "," );
nuclear@0 229 if ( std::string::npos == pos )
nuclear@0 230 {
nuclear@0 231 rArchiveName = rImportName;
nuclear@0 232 return;
nuclear@0 233 }
nuclear@0 234
nuclear@0 235 rArchiveName = rImportName.substr( 0, pos );
nuclear@0 236 rMapName = rImportName.substr( pos, rImportName.size() - pos - 1 );
nuclear@0 237 }
nuclear@0 238
nuclear@0 239 // ------------------------------------------------------------------------------------------------
nuclear@0 240 // Returns the first map in the map archive.
nuclear@0 241 bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &rArchive, std::string &rMapName )
nuclear@0 242 {
nuclear@0 243 rMapName = "";
nuclear@0 244 std::vector<std::string> fileList;
nuclear@0 245 rArchive.getFileList( fileList );
nuclear@0 246 if ( fileList.empty() )
nuclear@0 247 return false;
nuclear@0 248
nuclear@0 249 for ( std::vector<std::string>::iterator it = fileList.begin(); it != fileList.end();
nuclear@0 250 ++it )
nuclear@0 251 {
nuclear@0 252 std::string::size_type pos = (*it).find( "maps/" );
nuclear@0 253 if ( std::string::npos != pos )
nuclear@0 254 {
nuclear@0 255 std::string::size_type extPos = (*it).find( ".bsp" );
nuclear@0 256 if ( std::string::npos != extPos )
nuclear@0 257 {
nuclear@0 258 rMapName = *it;
nuclear@0 259 return true;
nuclear@0 260 }
nuclear@0 261 }
nuclear@0 262 }
nuclear@0 263
nuclear@0 264 return false;
nuclear@0 265 }
nuclear@0 266
nuclear@0 267 // ------------------------------------------------------------------------------------------------
nuclear@0 268 // Creates the assimp specific data.
nuclear@0 269 void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
nuclear@0 270 Q3BSPZipArchive *pArchive )
nuclear@0 271 {
nuclear@0 272 if ( NULL == pModel || NULL == pScene )
nuclear@0 273 return;
nuclear@0 274
nuclear@0 275 pScene->mRootNode = new aiNode;
nuclear@0 276 if ( !pModel->m_ModelName.empty() )
nuclear@0 277 {
nuclear@0 278 pScene->mRootNode->mName.Set( pModel->m_ModelName );
nuclear@0 279 }
nuclear@0 280
nuclear@0 281 // Create the face to material relation map
nuclear@0 282 createMaterialMap( pModel );
nuclear@0 283
nuclear@0 284 // Create all nodes
nuclear@0 285 CreateNodes( pModel, pScene, pScene->mRootNode );
nuclear@0 286
nuclear@0 287 // Create the assigned materials
nuclear@0 288 createMaterials( pModel, pScene, pArchive );
nuclear@0 289 }
nuclear@0 290
nuclear@0 291 // ------------------------------------------------------------------------------------------------
nuclear@0 292 // Creates all assimp nodes.
nuclear@0 293 void Q3BSPFileImporter::CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
nuclear@0 294 aiNode *pParent )
nuclear@0 295 {
nuclear@0 296 ai_assert( NULL != pModel );
nuclear@0 297 if ( NULL == pModel )
nuclear@0 298 {
nuclear@0 299 return;
nuclear@0 300 }
nuclear@0 301
nuclear@0 302 unsigned int matIdx = 0;
nuclear@0 303 std::vector<aiMesh*> MeshArray;
nuclear@0 304 std::vector<aiNode*> NodeArray;
nuclear@0 305 for ( FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it )
nuclear@0 306 {
nuclear@0 307 std::vector<Q3BSP::sQ3BSPFace*> *pArray = (*it).second;
nuclear@0 308 size_t numVerts = countData( *pArray );
nuclear@0 309 if ( 0 != numVerts )
nuclear@0 310 {
nuclear@0 311 aiMesh* pMesh = new aiMesh;
nuclear@0 312 aiNode *pNode = CreateTopology( pModel, matIdx, *pArray, pMesh );
nuclear@0 313 if ( NULL != pNode )
nuclear@0 314 {
nuclear@0 315 NodeArray.push_back( pNode );
nuclear@0 316 MeshArray.push_back( pMesh );
nuclear@0 317 }
nuclear@0 318 else
nuclear@0 319 {
nuclear@0 320 delete pMesh;
nuclear@0 321 }
nuclear@0 322 }
nuclear@0 323 matIdx++;
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 pScene->mNumMeshes = MeshArray.size();
nuclear@0 327 if ( pScene->mNumMeshes > 0 )
nuclear@0 328 {
nuclear@0 329 pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
nuclear@0 330 for ( size_t i = 0; i < MeshArray.size(); i++ )
nuclear@0 331 {
nuclear@0 332 aiMesh *pMesh = MeshArray[ i ];
nuclear@0 333 if ( NULL != pMesh )
nuclear@0 334 {
nuclear@0 335 pScene->mMeshes[ i ] = pMesh;
nuclear@0 336 }
nuclear@0 337 }
nuclear@0 338 }
nuclear@0 339
nuclear@0 340 pParent->mNumChildren = MeshArray.size();
nuclear@0 341 pParent->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren ];
nuclear@0 342 for ( size_t i=0; i<NodeArray.size(); i++ )
nuclear@0 343 {
nuclear@0 344 aiNode *pNode = NodeArray[ i ];
nuclear@0 345 pNode->mParent = pParent;
nuclear@0 346 pParent->mChildren[ i ] = pNode;
nuclear@0 347 pParent->mChildren[ i ]->mMeshes[ 0 ] = i;
nuclear@0 348 }
nuclear@0 349 }
nuclear@0 350
nuclear@0 351 // ------------------------------------------------------------------------------------------------
nuclear@0 352 // Creates the topology.
nuclear@0 353 aiNode *Q3BSPFileImporter::CreateTopology( const Q3BSP::Q3BSPModel *pModel,
nuclear@0 354 unsigned int materialIdx,
nuclear@0 355 std::vector<sQ3BSPFace*> &rArray,
nuclear@0 356 aiMesh* pMesh )
nuclear@0 357 {
nuclear@0 358 size_t numVerts = countData( rArray );
nuclear@0 359 if ( 0 == numVerts )
nuclear@0 360 {
nuclear@0 361 return NULL;
nuclear@0 362 }
nuclear@0 363
nuclear@0 364 size_t numFaces = countFaces( rArray );
nuclear@0 365 if ( 0 == numFaces )
nuclear@0 366 {
nuclear@0 367 return NULL;
nuclear@0 368 }
nuclear@0 369
nuclear@0 370 size_t numTriangles = countTriangles( rArray );
nuclear@0 371 pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 372
nuclear@0 373 pMesh->mFaces = new aiFace[ numTriangles ];
nuclear@0 374 pMesh->mNumFaces = numTriangles;
nuclear@0 375
nuclear@0 376 pMesh->mNumVertices = numVerts;
nuclear@0 377 pMesh->mVertices = new aiVector3D[ numVerts ];
nuclear@0 378 pMesh->mNormals = new aiVector3D[ numVerts ];
nuclear@0 379 pMesh->mTextureCoords[ 0 ] = new aiVector3D[ numVerts ];
nuclear@0 380 pMesh->mTextureCoords[ 1 ] = new aiVector3D[ numVerts ];
nuclear@0 381 pMesh->mMaterialIndex = materialIdx;
nuclear@0 382
nuclear@0 383 unsigned int faceIdx = 0;
nuclear@0 384 unsigned int vertIdx = 0;
nuclear@0 385 pMesh->mNumUVComponents[ 0 ] = 2;
nuclear@0 386 pMesh->mNumUVComponents[ 1 ] = 2;
nuclear@0 387 for ( std::vector<sQ3BSPFace*>::const_iterator it = rArray.begin(); it != rArray.end(); ++it )
nuclear@0 388 {
nuclear@0 389 Q3BSP::sQ3BSPFace *pQ3BSPFace = *it;
nuclear@0 390 ai_assert( NULL != pQ3BSPFace );
nuclear@0 391 if ( NULL == pQ3BSPFace )
nuclear@0 392 {
nuclear@0 393 continue;
nuclear@0 394 }
nuclear@0 395
nuclear@0 396 if ( pQ3BSPFace->iNumOfFaceVerts > 0 )
nuclear@0 397 {
nuclear@0 398 if ( pQ3BSPFace->iType == Polygon || pQ3BSPFace->iType == TriangleMesh )
nuclear@0 399 {
nuclear@0 400 createTriangleTopology( pModel, pQ3BSPFace, pMesh, faceIdx, vertIdx );
nuclear@0 401 }
nuclear@0 402 }
nuclear@0 403 }
nuclear@0 404
nuclear@0 405 aiNode *pNode = new aiNode;
nuclear@0 406 pNode->mNumMeshes = 1;
nuclear@0 407 pNode->mMeshes = new unsigned int[ 1 ];
nuclear@0 408
nuclear@0 409 return pNode;
nuclear@0 410 }
nuclear@0 411
nuclear@0 412 // ------------------------------------------------------------------------------------------------
nuclear@0 413 // Creates the triangle topology from a face array.
nuclear@0 414 void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel,
nuclear@0 415 Q3BSP::sQ3BSPFace *pQ3BSPFace,
nuclear@0 416 aiMesh* pMesh,
nuclear@0 417 unsigned int &rFaceIdx,
nuclear@0 418 unsigned int &rVertIdx )
nuclear@0 419 {
nuclear@0 420 ai_assert( rFaceIdx < pMesh->mNumFaces );
nuclear@0 421
nuclear@0 422 m_pCurrentFace = getNextFace( pMesh, rFaceIdx );
nuclear@0 423 ai_assert( NULL != m_pCurrentFace );
nuclear@0 424 if ( NULL == m_pCurrentFace )
nuclear@0 425 {
nuclear@0 426 return;
nuclear@0 427 }
nuclear@0 428
nuclear@0 429 m_pCurrentFace->mNumIndices = 3;
nuclear@0 430 m_pCurrentFace->mIndices = new unsigned int[ m_pCurrentFace->mNumIndices ];
nuclear@0 431
nuclear@0 432 size_t idx = 0;
nuclear@0 433 for ( size_t i = 0; i < (size_t) pQ3BSPFace->iNumOfFaceVerts; i++ )
nuclear@0 434 {
nuclear@0 435 const size_t index = pQ3BSPFace->iVertexIndex + pModel->m_Indices[ pQ3BSPFace->iFaceVertexIndex + i ];
nuclear@0 436 ai_assert( index < pModel->m_Vertices.size() );
nuclear@0 437 if ( index >= pModel->m_Vertices.size() )
nuclear@0 438 {
nuclear@0 439 continue;
nuclear@0 440 }
nuclear@0 441
nuclear@0 442 sQ3BSPVertex *pVertex = pModel->m_Vertices[ index ];
nuclear@0 443 ai_assert( NULL != pVertex );
nuclear@0 444 if ( NULL == pVertex )
nuclear@0 445 {
nuclear@0 446 continue;
nuclear@0 447 }
nuclear@0 448
nuclear@0 449 pMesh->mVertices[ rVertIdx ].Set( pVertex->vPosition.x, pVertex->vPosition.y, pVertex->vPosition.z );
nuclear@0 450 pMesh->mNormals[ rVertIdx ].Set( pVertex->vNormal.x, pVertex->vNormal.y, pVertex->vNormal.z );
nuclear@0 451
nuclear@0 452 pMesh->mTextureCoords[ 0 ][ rVertIdx ].Set( pVertex->vTexCoord.x, pVertex->vTexCoord.y, 0.0f );
nuclear@0 453 pMesh->mTextureCoords[ 1 ][ rVertIdx ].Set( pVertex->vLightmap.x, pVertex->vLightmap.y, 0.0f );
nuclear@0 454
nuclear@0 455 m_pCurrentFace->mIndices[ idx ] = rVertIdx;
nuclear@0 456 rVertIdx++;
nuclear@0 457
nuclear@0 458 idx++;
nuclear@0 459 if ( idx > 2 )
nuclear@0 460 {
nuclear@0 461 idx = 0;
nuclear@0 462 m_pCurrentFace = getNextFace( pMesh, rFaceIdx );
nuclear@0 463 if ( NULL != m_pCurrentFace )
nuclear@0 464 {
nuclear@0 465 m_pCurrentFace->mNumIndices = 3;
nuclear@0 466 m_pCurrentFace->mIndices = new unsigned int[ 3 ];
nuclear@0 467 }
nuclear@0 468 }
nuclear@0 469 }
nuclear@0 470 rFaceIdx--;
nuclear@0 471 }
nuclear@0 472
nuclear@0 473 // ------------------------------------------------------------------------------------------------
nuclear@0 474 // Creates all referenced materials.
nuclear@0 475 void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
nuclear@0 476 Q3BSPZipArchive *pArchive )
nuclear@0 477 {
nuclear@0 478 if ( m_MaterialLookupMap.empty() )
nuclear@0 479 {
nuclear@0 480 return;
nuclear@0 481 }
nuclear@0 482
nuclear@0 483 pScene->mMaterials = new aiMaterial*[ m_MaterialLookupMap.size() ];
nuclear@0 484 aiString aiMatName;
nuclear@0 485 int textureId( -1 ), lightmapId( -1 );
nuclear@0 486 for ( FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end();
nuclear@0 487 ++it )
nuclear@0 488 {
nuclear@0 489 const std::string matName = (*it).first;
nuclear@0 490 if ( matName.empty() )
nuclear@0 491 {
nuclear@0 492 continue;
nuclear@0 493 }
nuclear@0 494
nuclear@0 495 aiMatName.Set( matName );
nuclear@0 496 aiMaterial *pMatHelper = new aiMaterial;
nuclear@0 497 pMatHelper->AddProperty( &aiMatName, AI_MATKEY_NAME );
nuclear@0 498
nuclear@0 499 extractIds( matName, textureId, lightmapId );
nuclear@0 500
nuclear@0 501 // Adding the texture
nuclear@0 502 if ( -1 != textureId )
nuclear@0 503 {
nuclear@0 504 sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ];
nuclear@0 505 if ( NULL != pTexture )
nuclear@0 506 {
nuclear@0 507 std::string tmp( "*" ), texName( "" );
nuclear@0 508 tmp += pTexture->strName;
nuclear@0 509 tmp += ".jpg";
nuclear@0 510 normalizePathName( tmp, texName );
nuclear@0 511
nuclear@0 512 if ( !importTextureFromArchive( pModel, pArchive, pScene, pMatHelper, textureId ) )
nuclear@0 513 {
nuclear@0 514 }
nuclear@0 515 }
nuclear@0 516
nuclear@0 517 }
nuclear@0 518 if ( -1 != lightmapId )
nuclear@0 519 {
nuclear@0 520 importLightmap( pModel, pScene, pMatHelper, lightmapId );
nuclear@0 521 }
nuclear@0 522 pScene->mMaterials[ pScene->mNumMaterials ] = pMatHelper;
nuclear@0 523 pScene->mNumMaterials++;
nuclear@0 524 }
nuclear@0 525 pScene->mNumTextures = mTextures.size();
nuclear@0 526 pScene->mTextures = new aiTexture*[ pScene->mNumTextures ];
nuclear@0 527 std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures );
nuclear@0 528 }
nuclear@0 529
nuclear@0 530 // ------------------------------------------------------------------------------------------------
nuclear@0 531 // Counts the number of referenced vertices.
nuclear@0 532 size_t Q3BSPFileImporter::countData( const std::vector<sQ3BSPFace*> &rArray ) const
nuclear@0 533 {
nuclear@0 534 size_t numVerts = 0;
nuclear@0 535 for ( std::vector<sQ3BSPFace*>::const_iterator it = rArray.begin(); it != rArray.end();
nuclear@0 536 ++it )
nuclear@0 537 {
nuclear@0 538 sQ3BSPFace *pQ3BSPFace = *it;
nuclear@0 539 if ( pQ3BSPFace->iType == Polygon || pQ3BSPFace->iType == TriangleMesh )
nuclear@0 540 {
nuclear@0 541 Q3BSP::sQ3BSPFace *pQ3BSPFace = *it;
nuclear@0 542 ai_assert( NULL != pQ3BSPFace );
nuclear@0 543 numVerts += pQ3BSPFace->iNumOfFaceVerts;
nuclear@0 544 }
nuclear@0 545 }
nuclear@0 546
nuclear@0 547 return numVerts;
nuclear@0 548 }
nuclear@0 549
nuclear@0 550 // ------------------------------------------------------------------------------------------------
nuclear@0 551 // Counts the faces with vertices.
nuclear@0 552 size_t Q3BSPFileImporter::countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const
nuclear@0 553 {
nuclear@0 554 size_t numFaces = 0;
nuclear@0 555 for ( std::vector<sQ3BSPFace*>::const_iterator it = rArray.begin(); it != rArray.end();
nuclear@0 556 ++it )
nuclear@0 557 {
nuclear@0 558 Q3BSP::sQ3BSPFace *pQ3BSPFace = *it;
nuclear@0 559 if ( pQ3BSPFace->iNumOfFaceVerts > 0 )
nuclear@0 560 {
nuclear@0 561 numFaces++;
nuclear@0 562 }
nuclear@0 563 }
nuclear@0 564
nuclear@0 565 return numFaces;
nuclear@0 566 }
nuclear@0 567
nuclear@0 568 // ------------------------------------------------------------------------------------------------
nuclear@0 569 // Counts the number of triangles in a Q3-facearray.
nuclear@0 570 size_t Q3BSPFileImporter::countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const
nuclear@0 571 {
nuclear@0 572 size_t numTriangles = 0;
nuclear@0 573 for ( std::vector<Q3BSP::sQ3BSPFace*>::const_iterator it = rArray.begin(); it != rArray.end();
nuclear@0 574 ++it )
nuclear@0 575 {
nuclear@0 576 const Q3BSP::sQ3BSPFace *pQ3BSPFace = *it;
nuclear@0 577 if ( NULL != pQ3BSPFace )
nuclear@0 578 {
nuclear@0 579 numTriangles += pQ3BSPFace->iNumOfFaceVerts / 3;
nuclear@0 580 }
nuclear@0 581 }
nuclear@0 582
nuclear@0 583 return numTriangles;
nuclear@0 584 }
nuclear@0 585
nuclear@0 586 // ------------------------------------------------------------------------------------------------
nuclear@0 587 // Creates the faces-to-material map.
nuclear@0 588 void Q3BSPFileImporter::createMaterialMap( const Q3BSP::Q3BSPModel *pModel )
nuclear@0 589 {
nuclear@0 590 std::string key( "" );
nuclear@0 591 std::vector<sQ3BSPFace*> *pCurFaceArray = NULL;
nuclear@0 592 for ( size_t idx = 0; idx < pModel->m_Faces.size(); idx++ )
nuclear@0 593 {
nuclear@0 594 Q3BSP::sQ3BSPFace *pQ3BSPFace = pModel->m_Faces[ idx ];
nuclear@0 595 const int texId = pQ3BSPFace->iTextureID;
nuclear@0 596 const int lightMapId = pQ3BSPFace->iLightmapID;
nuclear@0 597 createKey( texId, lightMapId, key );
nuclear@0 598 FaceMapIt it = m_MaterialLookupMap.find( key );
nuclear@0 599 if ( m_MaterialLookupMap.end() == it )
nuclear@0 600 {
nuclear@0 601 pCurFaceArray = new std::vector<Q3BSP::sQ3BSPFace*>;
nuclear@0 602 m_MaterialLookupMap[ key ] = pCurFaceArray;
nuclear@0 603 }
nuclear@0 604 else
nuclear@0 605 {
nuclear@0 606 pCurFaceArray = (*it).second;
nuclear@0 607 }
nuclear@0 608 ai_assert( NULL != pCurFaceArray );
nuclear@0 609 if ( NULL != pCurFaceArray )
nuclear@0 610 {
nuclear@0 611 pCurFaceArray->push_back( pQ3BSPFace );
nuclear@0 612 }
nuclear@0 613 }
nuclear@0 614 }
nuclear@0 615
nuclear@0 616 // ------------------------------------------------------------------------------------------------
nuclear@0 617 // Returns the next face.
nuclear@0 618 aiFace *Q3BSPFileImporter::getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx )
nuclear@0 619 {
nuclear@0 620 aiFace *pFace = NULL;
nuclear@0 621 if ( rFaceIdx < pMesh->mNumFaces )
nuclear@0 622 {
nuclear@0 623 pFace = &pMesh->mFaces[ rFaceIdx ];
nuclear@0 624 rFaceIdx++;
nuclear@0 625 }
nuclear@0 626 else
nuclear@0 627 {
nuclear@0 628 pFace = NULL;
nuclear@0 629 }
nuclear@0 630
nuclear@0 631 return pFace;
nuclear@0 632 }
nuclear@0 633
nuclear@0 634 // ------------------------------------------------------------------------------------------------
nuclear@0 635 // Imports a texture file.
nuclear@0 636 bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel,
nuclear@0 637 Q3BSP::Q3BSPZipArchive *pArchive, aiScene* /*pScene*/,
nuclear@0 638 aiMaterial *pMatHelper, int textureId )
nuclear@0 639 {
nuclear@0 640 std::vector<std::string> supportedExtensions;
nuclear@0 641 supportedExtensions.push_back( ".jpg" );
nuclear@0 642 supportedExtensions.push_back( ".png" );
nuclear@0 643 supportedExtensions.push_back( ".tga" );
nuclear@0 644 if ( NULL == pArchive || NULL == pArchive || NULL == pMatHelper )
nuclear@0 645 {
nuclear@0 646 return false;
nuclear@0 647 }
nuclear@0 648
nuclear@0 649 if ( textureId < 0 || textureId >= static_cast<int>( pModel->m_Textures.size() ) )
nuclear@0 650 {
nuclear@0 651 return false;
nuclear@0 652 }
nuclear@0 653
nuclear@0 654 bool res = true;
nuclear@0 655 sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ];
nuclear@0 656 if ( NULL == pTexture )
nuclear@0 657 return false;
nuclear@0 658
nuclear@0 659 std::string textureName, ext;
nuclear@0 660 if ( expandFile( pArchive, pTexture->strName, supportedExtensions, textureName, ext ) )
nuclear@0 661 {
nuclear@0 662 IOStream *pTextureStream = pArchive->Open( textureName.c_str() );
nuclear@0 663 if ( NULL != pTextureStream )
nuclear@0 664 {
nuclear@0 665 size_t texSize = pTextureStream->FileSize();
nuclear@0 666 aiTexture *pTexture = new aiTexture;
nuclear@0 667 pTexture->mHeight = 0;
nuclear@0 668 pTexture->mWidth = texSize;
nuclear@0 669 unsigned char *pData = new unsigned char[ pTexture->mWidth ];
nuclear@0 670 size_t readSize = pTextureStream->Read( pData, sizeof( unsigned char ), pTexture->mWidth );
nuclear@0 671 (void)readSize;
nuclear@0 672 ai_assert( readSize == pTexture->mWidth );
nuclear@0 673 pTexture->pcData = reinterpret_cast<aiTexel*>( pData );
nuclear@0 674 pTexture->achFormatHint[ 0 ] = ext[ 1 ];
nuclear@0 675 pTexture->achFormatHint[ 1 ] = ext[ 2 ];
nuclear@0 676 pTexture->achFormatHint[ 2 ] = ext[ 3 ];
nuclear@0 677 pTexture->achFormatHint[ 3 ] = '\0';
nuclear@0 678 res = true;
nuclear@0 679
nuclear@0 680 aiString name;
nuclear@0 681 name.data[ 0 ] = '*';
nuclear@0 682 name.length = 1 + ASSIMP_itoa10( name.data + 1, MAXLEN-1, mTextures.size() );
nuclear@0 683
nuclear@0 684 pArchive->Close( pTextureStream );
nuclear@0 685
nuclear@0 686 pMatHelper->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
nuclear@0 687 mTextures.push_back( pTexture );
nuclear@0 688 }
nuclear@0 689 else
nuclear@0 690 {
nuclear@0 691 // If it doesn't exist in the archive, it is probably just a reference to an external file.
nuclear@0 692 // We'll leave it up to the user to figure out which extension the file has.
nuclear@0 693 aiString name;
nuclear@0 694 strncpy( name.data, pTexture->strName, sizeof name.data );
nuclear@0 695 name.length = strlen( name.data );
nuclear@0 696 pMatHelper->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
nuclear@0 697 }
nuclear@0 698 }
nuclear@0 699
nuclear@0 700 return res;
nuclear@0 701 }
nuclear@0 702
nuclear@0 703 // ------------------------------------------------------------------------------------------------
nuclear@0 704 // Imports a light map file.
nuclear@0 705 bool Q3BSPFileImporter::importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
nuclear@0 706 aiMaterial *pMatHelper, int lightmapId )
nuclear@0 707 {
nuclear@0 708 if ( NULL == pModel || NULL == pScene || NULL == pMatHelper )
nuclear@0 709 {
nuclear@0 710 return false;
nuclear@0 711 }
nuclear@0 712
nuclear@0 713 if ( lightmapId < 0 || lightmapId >= static_cast<int>( pModel->m_Lightmaps.size() ) )
nuclear@0 714 {
nuclear@0 715 return false;
nuclear@0 716 }
nuclear@0 717
nuclear@0 718 sQ3BSPLightmap *pLightMap = pModel->m_Lightmaps[ lightmapId ];
nuclear@0 719 if ( NULL == pLightMap )
nuclear@0 720 {
nuclear@0 721 return false;
nuclear@0 722 }
nuclear@0 723
nuclear@0 724 aiTexture *pTexture = new aiTexture;
nuclear@0 725
nuclear@0 726 pTexture->mWidth = CE_BSP_LIGHTMAPWIDTH;
nuclear@0 727 pTexture->mHeight = CE_BSP_LIGHTMAPHEIGHT;
nuclear@0 728 pTexture->pcData = new aiTexel[CE_BSP_LIGHTMAPWIDTH * CE_BSP_LIGHTMAPHEIGHT];
nuclear@0 729
nuclear@0 730 ::memcpy( pTexture->pcData, pLightMap->bLMapData, pTexture->mWidth );
nuclear@0 731 size_t p = 0;
nuclear@0 732 for ( size_t i = 0; i < CE_BSP_LIGHTMAPWIDTH * CE_BSP_LIGHTMAPHEIGHT; ++i )
nuclear@0 733 {
nuclear@0 734 pTexture->pcData[ i ].r = pLightMap->bLMapData[ p++ ];
nuclear@0 735 pTexture->pcData[ i ].g = pLightMap->bLMapData[ p++ ];
nuclear@0 736 pTexture->pcData[ i ].b = pLightMap->bLMapData[ p++ ];
nuclear@0 737 pTexture->pcData[ i ].a = 0xFF;
nuclear@0 738 }
nuclear@0 739
nuclear@0 740 aiString name;
nuclear@0 741 name.data[ 0 ] = '*';
nuclear@0 742 name.length = 1 + ASSIMP_itoa10( name.data + 1, MAXLEN-1, mTextures.size() );
nuclear@0 743
nuclear@0 744 pMatHelper->AddProperty( &name,AI_MATKEY_TEXTURE_LIGHTMAP( 1 ) );
nuclear@0 745 mTextures.push_back( pTexture );
nuclear@0 746
nuclear@0 747 return true;
nuclear@0 748 }
nuclear@0 749
nuclear@0 750
nuclear@0 751 // ------------------------------------------------------------------------------------------------
nuclear@0 752 // Will search for a supported extension.
nuclear@0 753 bool Q3BSPFileImporter::expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename,
nuclear@0 754 const std::vector<std::string> &rExtList, std::string &rFile,
nuclear@0 755 std::string &rExt )
nuclear@0 756 {
nuclear@0 757 ai_assert( NULL != pArchive );
nuclear@0 758 ai_assert( !rFilename.empty() );
nuclear@0 759
nuclear@0 760 if ( rExtList.empty() )
nuclear@0 761 {
nuclear@0 762 rFile = rFilename;
nuclear@0 763 rExt = "";
nuclear@0 764 return true;
nuclear@0 765 }
nuclear@0 766
nuclear@0 767 bool found = false;
nuclear@0 768 for ( std::vector<std::string>::const_iterator it = rExtList.begin(); it != rExtList.end(); ++it )
nuclear@0 769 {
nuclear@0 770 const std::string textureName = rFilename + *it;
nuclear@0 771 if ( pArchive->Exists( textureName.c_str() ) )
nuclear@0 772 {
nuclear@0 773 rExt = *it;
nuclear@0 774 rFile = textureName;
nuclear@0 775 found = true;
nuclear@0 776 break;
nuclear@0 777 }
nuclear@0 778 }
nuclear@0 779
nuclear@0 780 return found;
nuclear@0 781 }
nuclear@0 782
nuclear@0 783 // ------------------------------------------------------------------------------------------------
nuclear@0 784
nuclear@0 785 } // Namespace Assimp
nuclear@0 786
nuclear@0 787 #endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER