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