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
|