rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 #include "AssimpPCH.h"
|
nuclear@0
|
43 #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
|
nuclear@0
|
44
|
nuclear@0
|
45 #include "DefaultIOSystem.h"
|
nuclear@0
|
46 #include "ObjFileImporter.h"
|
nuclear@0
|
47 #include "ObjFileParser.h"
|
nuclear@0
|
48 #include "ObjFileData.h"
|
nuclear@0
|
49
|
nuclear@0
|
50 static const aiImporterDesc desc = {
|
nuclear@0
|
51 "Wavefront Object Importer",
|
nuclear@0
|
52 "",
|
nuclear@0
|
53 "",
|
nuclear@0
|
54 "surfaces not supported",
|
nuclear@0
|
55 aiImporterFlags_SupportTextFlavour,
|
nuclear@0
|
56 0,
|
nuclear@0
|
57 0,
|
nuclear@0
|
58 0,
|
nuclear@0
|
59 0,
|
nuclear@0
|
60 "obj"
|
nuclear@0
|
61 };
|
nuclear@0
|
62
|
nuclear@0
|
63
|
nuclear@0
|
64 namespace Assimp {
|
nuclear@0
|
65
|
nuclear@0
|
66 using namespace std;
|
nuclear@0
|
67
|
nuclear@0
|
68 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
69 // Default constructor
|
nuclear@0
|
70 ObjFileImporter::ObjFileImporter() :
|
nuclear@0
|
71 m_Buffer(),
|
nuclear@0
|
72 m_pRootObject( NULL ),
|
nuclear@0
|
73 m_strAbsPath( "" )
|
nuclear@0
|
74 {
|
nuclear@0
|
75 DefaultIOSystem io;
|
nuclear@0
|
76 m_strAbsPath = io.getOsSeparator();
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
80 // Destructor.
|
nuclear@0
|
81 ObjFileImporter::~ObjFileImporter()
|
nuclear@0
|
82 {
|
nuclear@0
|
83 // Release root object instance
|
nuclear@0
|
84 if (NULL != m_pRootObject)
|
nuclear@0
|
85 {
|
nuclear@0
|
86 delete m_pRootObject;
|
nuclear@0
|
87 m_pRootObject = NULL;
|
nuclear@0
|
88 }
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
92 // Returns true, if file is an obj file.
|
nuclear@0
|
93 bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler , bool checkSig ) const
|
nuclear@0
|
94 {
|
nuclear@0
|
95 if(!checkSig) //Check File Extension
|
nuclear@0
|
96 {
|
nuclear@0
|
97 return SimpleExtensionCheck(pFile,"obj");
|
nuclear@0
|
98 }
|
nuclear@0
|
99 else //Check file Header
|
nuclear@0
|
100 {
|
nuclear@0
|
101 static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
|
nuclear@0
|
102 return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 );
|
nuclear@0
|
103 }
|
nuclear@0
|
104 }
|
nuclear@0
|
105
|
nuclear@0
|
106 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
107 const aiImporterDesc* ObjFileImporter::GetInfo () const
|
nuclear@0
|
108 {
|
nuclear@0
|
109 return &desc;
|
nuclear@0
|
110 }
|
nuclear@0
|
111
|
nuclear@0
|
112 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
113 // Obj-file import implementation
|
nuclear@0
|
114 void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
nuclear@0
|
115 {
|
nuclear@0
|
116 DefaultIOSystem io;
|
nuclear@0
|
117
|
nuclear@0
|
118 // Read file into memory
|
nuclear@0
|
119 const std::string mode = "rb";
|
nuclear@0
|
120 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
|
nuclear@0
|
121 if (NULL == file.get())
|
nuclear@0
|
122 throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
nuclear@0
|
123
|
nuclear@0
|
124 // Get the file-size and validate it, throwing an exception when fails
|
nuclear@0
|
125 size_t fileSize = file->FileSize();
|
nuclear@0
|
126 if( fileSize < 16)
|
nuclear@0
|
127 throw DeadlyImportError( "OBJ-file is too small.");
|
nuclear@0
|
128
|
nuclear@0
|
129 // Allocate buffer and read file into it
|
nuclear@0
|
130 TextFileToBuffer(file.get(),m_Buffer);
|
nuclear@0
|
131
|
nuclear@0
|
132 // Get the model name
|
nuclear@0
|
133 std::string strModelName;
|
nuclear@0
|
134 std::string::size_type pos = pFile.find_last_of( "\\/" );
|
nuclear@0
|
135 if ( pos != std::string::npos )
|
nuclear@0
|
136 {
|
nuclear@0
|
137 strModelName = pFile.substr(pos+1, pFile.size() - pos - 1);
|
nuclear@0
|
138 }
|
nuclear@0
|
139 else
|
nuclear@0
|
140 {
|
nuclear@0
|
141 strModelName = pFile;
|
nuclear@0
|
142 }
|
nuclear@0
|
143
|
nuclear@0
|
144 // parse the file into a temporary representation
|
nuclear@0
|
145 ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
|
nuclear@0
|
146
|
nuclear@0
|
147 // And create the proper return structures out of it
|
nuclear@0
|
148 CreateDataFromImport(parser.GetModel(), pScene);
|
nuclear@0
|
149
|
nuclear@0
|
150 // Clean up allocated storage for the next import
|
nuclear@0
|
151 m_Buffer.clear();
|
nuclear@0
|
152 }
|
nuclear@0
|
153
|
nuclear@0
|
154 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
155 // Create the data from parsed obj-file
|
nuclear@0
|
156 void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene)
|
nuclear@0
|
157 {
|
nuclear@0
|
158 if (0L == pModel)
|
nuclear@0
|
159 return;
|
nuclear@0
|
160
|
nuclear@0
|
161 // Create the root node of the scene
|
nuclear@0
|
162 pScene->mRootNode = new aiNode;
|
nuclear@0
|
163 if ( !pModel->m_ModelName.empty() )
|
nuclear@0
|
164 {
|
nuclear@0
|
165 // Set the name of the scene
|
nuclear@0
|
166 pScene->mRootNode->mName.Set(pModel->m_ModelName);
|
nuclear@0
|
167 }
|
nuclear@0
|
168 else
|
nuclear@0
|
169 {
|
nuclear@0
|
170 // This is an error, so break down the application
|
nuclear@0
|
171 ai_assert(false);
|
nuclear@0
|
172 }
|
nuclear@0
|
173
|
nuclear@0
|
174 // Create nodes for the whole scene
|
nuclear@0
|
175 std::vector<aiMesh*> MeshArray;
|
nuclear@0
|
176 for (size_t index = 0; index < pModel->m_Objects.size(); index++)
|
nuclear@0
|
177 {
|
nuclear@0
|
178 createNodes(pModel, pModel->m_Objects[ index ], index, pScene->mRootNode, pScene, MeshArray);
|
nuclear@0
|
179 }
|
nuclear@0
|
180
|
nuclear@0
|
181 // Create mesh pointer buffer for this scene
|
nuclear@0
|
182 if (pScene->mNumMeshes > 0)
|
nuclear@0
|
183 {
|
nuclear@0
|
184 pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
|
nuclear@0
|
185 for (size_t index =0; index < MeshArray.size(); index++)
|
nuclear@0
|
186 {
|
nuclear@0
|
187 pScene->mMeshes [ index ] = MeshArray[ index ];
|
nuclear@0
|
188 }
|
nuclear@0
|
189 }
|
nuclear@0
|
190
|
nuclear@0
|
191 // Create all materials
|
nuclear@0
|
192 createMaterials( pModel, pScene );
|
nuclear@0
|
193 }
|
nuclear@0
|
194
|
nuclear@0
|
195 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
196 // Creates all nodes of the model
|
nuclear@0
|
197 aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject,
|
nuclear@0
|
198 unsigned int /*uiMeshIndex*/,
|
nuclear@0
|
199 aiNode *pParent, aiScene* pScene,
|
nuclear@0
|
200 std::vector<aiMesh*> &MeshArray )
|
nuclear@0
|
201 {
|
nuclear@0
|
202 ai_assert( NULL != pModel );
|
nuclear@0
|
203 if ( NULL == pObject )
|
nuclear@0
|
204 return NULL;
|
nuclear@0
|
205
|
nuclear@0
|
206 // Store older mesh size to be able to computes mesh offsets for new mesh instances
|
nuclear@0
|
207 const size_t oldMeshSize = MeshArray.size();
|
nuclear@0
|
208 aiNode *pNode = new aiNode;
|
nuclear@0
|
209
|
nuclear@0
|
210 pNode->mName = pObject->m_strObjName;
|
nuclear@0
|
211
|
nuclear@0
|
212 // If we have a parent node, store it
|
nuclear@0
|
213 if (pParent != NULL)
|
nuclear@0
|
214 appendChildToParentNode(pParent, pNode);
|
nuclear@0
|
215
|
nuclear@0
|
216 for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
|
nuclear@0
|
217 {
|
nuclear@0
|
218 unsigned int meshId = pObject->m_Meshes[ i ];
|
nuclear@0
|
219 aiMesh *pMesh = new aiMesh;
|
nuclear@0
|
220 createTopology( pModel, pObject, meshId, pMesh );
|
nuclear@0
|
221 if ( pMesh->mNumVertices > 0 )
|
nuclear@0
|
222 {
|
nuclear@0
|
223 MeshArray.push_back( pMesh );
|
nuclear@0
|
224 }
|
nuclear@0
|
225 else
|
nuclear@0
|
226 {
|
nuclear@0
|
227 delete pMesh;
|
nuclear@0
|
228 }
|
nuclear@0
|
229 }
|
nuclear@0
|
230
|
nuclear@0
|
231 // Create all nodes from the sub-objects stored in the current object
|
nuclear@0
|
232 if ( !pObject->m_SubObjects.empty() )
|
nuclear@0
|
233 {
|
nuclear@0
|
234 size_t numChilds = pObject->m_SubObjects.size();
|
nuclear@0
|
235 pNode->mNumChildren = static_cast<unsigned int>( numChilds );
|
nuclear@0
|
236 pNode->mChildren = new aiNode*[ numChilds ];
|
nuclear@0
|
237 pNode->mNumMeshes = 1;
|
nuclear@0
|
238 pNode->mMeshes = new unsigned int[ 1 ];
|
nuclear@0
|
239 }
|
nuclear@0
|
240
|
nuclear@0
|
241 // Set mesh instances into scene- and node-instances
|
nuclear@0
|
242 const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
|
nuclear@0
|
243 if ( meshSizeDiff > 0 )
|
nuclear@0
|
244 {
|
nuclear@0
|
245 pNode->mMeshes = new unsigned int[ meshSizeDiff ];
|
nuclear@0
|
246 pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
|
nuclear@0
|
247 size_t index = 0;
|
nuclear@0
|
248 for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
|
nuclear@0
|
249 {
|
nuclear@0
|
250 pNode->mMeshes[ index ] = pScene->mNumMeshes;
|
nuclear@0
|
251 pScene->mNumMeshes++;
|
nuclear@0
|
252 index++;
|
nuclear@0
|
253 }
|
nuclear@0
|
254 }
|
nuclear@0
|
255
|
nuclear@0
|
256 return pNode;
|
nuclear@0
|
257 }
|
nuclear@0
|
258
|
nuclear@0
|
259 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
260 // Create topology data
|
nuclear@0
|
261 void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
|
nuclear@0
|
262 const ObjFile::Object* pData,
|
nuclear@0
|
263 unsigned int uiMeshIndex,
|
nuclear@0
|
264 aiMesh* pMesh )
|
nuclear@0
|
265 {
|
nuclear@0
|
266 // Checking preconditions
|
nuclear@0
|
267 ai_assert( NULL != pModel );
|
nuclear@0
|
268 if (NULL == pData)
|
nuclear@0
|
269 return;
|
nuclear@0
|
270
|
nuclear@0
|
271 // Create faces
|
nuclear@0
|
272 ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
|
nuclear@0
|
273 ai_assert( NULL != pObjMesh );
|
nuclear@0
|
274
|
nuclear@0
|
275 pMesh->mNumFaces = 0;
|
nuclear@0
|
276 for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
|
nuclear@0
|
277 {
|
nuclear@0
|
278 ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
|
nuclear@0
|
279 if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
|
nuclear@0
|
280 pMesh->mNumFaces += inp->m_pVertices->size() - 1;
|
nuclear@0
|
281 }
|
nuclear@0
|
282 else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
|
nuclear@0
|
283 pMesh->mNumFaces += inp->m_pVertices->size();
|
nuclear@0
|
284 }
|
nuclear@0
|
285 else {
|
nuclear@0
|
286 ++pMesh->mNumFaces;
|
nuclear@0
|
287 }
|
nuclear@0
|
288 }
|
nuclear@0
|
289
|
nuclear@0
|
290 unsigned int uiIdxCount = 0u;
|
nuclear@0
|
291 if ( pMesh->mNumFaces > 0 )
|
nuclear@0
|
292 {
|
nuclear@0
|
293 pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
|
nuclear@0
|
294 if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial )
|
nuclear@0
|
295 {
|
nuclear@0
|
296 pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
|
nuclear@0
|
297 }
|
nuclear@0
|
298
|
nuclear@0
|
299 unsigned int outIndex = 0;
|
nuclear@0
|
300
|
nuclear@0
|
301 // Copy all data from all stored meshes
|
nuclear@0
|
302 for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
|
nuclear@0
|
303 {
|
nuclear@0
|
304 ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
|
nuclear@0
|
305 if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
|
nuclear@0
|
306 for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) {
|
nuclear@0
|
307 aiFace& f = pMesh->mFaces[ outIndex++ ];
|
nuclear@0
|
308 uiIdxCount += f.mNumIndices = 2;
|
nuclear@0
|
309 f.mIndices = new unsigned int[2];
|
nuclear@0
|
310 }
|
nuclear@0
|
311 continue;
|
nuclear@0
|
312 }
|
nuclear@0
|
313 else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
|
nuclear@0
|
314 for(size_t i = 0; i < inp->m_pVertices->size(); ++i) {
|
nuclear@0
|
315 aiFace& f = pMesh->mFaces[ outIndex++ ];
|
nuclear@0
|
316 uiIdxCount += f.mNumIndices = 1;
|
nuclear@0
|
317 f.mIndices = new unsigned int[1];
|
nuclear@0
|
318 }
|
nuclear@0
|
319 continue;
|
nuclear@0
|
320 }
|
nuclear@0
|
321
|
nuclear@0
|
322 aiFace *pFace = &pMesh->mFaces[ outIndex++ ];
|
nuclear@0
|
323 const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size();
|
nuclear@0
|
324 uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices;
|
nuclear@0
|
325 if (pFace->mNumIndices > 0) {
|
nuclear@0
|
326 pFace->mIndices = new unsigned int[ uiNumIndices ];
|
nuclear@0
|
327 }
|
nuclear@0
|
328 }
|
nuclear@0
|
329 }
|
nuclear@0
|
330
|
nuclear@0
|
331 // Create mesh vertices
|
nuclear@0
|
332 createVertexArray(pModel, pData, uiMeshIndex, pMesh, uiIdxCount);
|
nuclear@0
|
333 }
|
nuclear@0
|
334
|
nuclear@0
|
335 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
336 // Creates a vertex array
|
nuclear@0
|
337 void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
|
nuclear@0
|
338 const ObjFile::Object* pCurrentObject,
|
nuclear@0
|
339 unsigned int uiMeshIndex,
|
nuclear@0
|
340 aiMesh* pMesh,
|
nuclear@0
|
341 unsigned int uiIdxCount)
|
nuclear@0
|
342 {
|
nuclear@0
|
343 // Checking preconditions
|
nuclear@0
|
344 ai_assert( NULL != pCurrentObject );
|
nuclear@0
|
345
|
nuclear@0
|
346 // Break, if no faces are stored in object
|
nuclear@0
|
347 if ( pCurrentObject->m_Meshes.empty() )
|
nuclear@0
|
348 return;
|
nuclear@0
|
349
|
nuclear@0
|
350 // Get current mesh
|
nuclear@0
|
351 ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
|
nuclear@0
|
352 if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1)
|
nuclear@0
|
353 return;
|
nuclear@0
|
354
|
nuclear@0
|
355 // Copy vertices of this mesh instance
|
nuclear@0
|
356 pMesh->mNumVertices = uiIdxCount;
|
nuclear@0
|
357 pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
|
nuclear@0
|
358
|
nuclear@0
|
359 // Allocate buffer for normal vectors
|
nuclear@0
|
360 if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals )
|
nuclear@0
|
361 pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ];
|
nuclear@0
|
362
|
nuclear@0
|
363 // Allocate buffer for texture coordinates
|
nuclear@0
|
364 if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] )
|
nuclear@0
|
365 {
|
nuclear@0
|
366 pMesh->mNumUVComponents[ 0 ] = 2;
|
nuclear@0
|
367 pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ];
|
nuclear@0
|
368 }
|
nuclear@0
|
369
|
nuclear@0
|
370 // Copy vertices, normals and textures into aiMesh instance
|
nuclear@0
|
371 unsigned int newIndex = 0, outIndex = 0;
|
nuclear@0
|
372 for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ )
|
nuclear@0
|
373 {
|
nuclear@0
|
374 // Get source face
|
nuclear@0
|
375 ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ];
|
nuclear@0
|
376
|
nuclear@0
|
377 // Copy all index arrays
|
nuclear@0
|
378 for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ )
|
nuclear@0
|
379 {
|
nuclear@0
|
380 const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex );
|
nuclear@0
|
381 if ( vertex >= pModel->m_Vertices.size() )
|
nuclear@0
|
382 throw DeadlyImportError( "OBJ: vertex index out of range" );
|
nuclear@0
|
383
|
nuclear@0
|
384 pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
|
nuclear@0
|
385
|
nuclear@0
|
386 // Copy all normals
|
nuclear@0
|
387 if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty())
|
nuclear@0
|
388 {
|
nuclear@0
|
389 const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex );
|
nuclear@0
|
390 if ( normal >= pModel->m_Normals.size() )
|
nuclear@0
|
391 throw DeadlyImportError("OBJ: vertex normal index out of range");
|
nuclear@0
|
392
|
nuclear@0
|
393 pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ];
|
nuclear@0
|
394 }
|
nuclear@0
|
395
|
nuclear@0
|
396 // Copy all texture coordinates
|
nuclear@0
|
397 if ( !pModel->m_TextureCoord.empty() )
|
nuclear@0
|
398 {
|
nuclear@0
|
399 if ( !pSourceFace->m_pTexturCoords->empty() )
|
nuclear@0
|
400 {
|
nuclear@0
|
401 const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex );
|
nuclear@0
|
402 ai_assert( tex < pModel->m_TextureCoord.size() );
|
nuclear@0
|
403 for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ )
|
nuclear@0
|
404 {
|
nuclear@0
|
405 if ( tex >= pModel->m_TextureCoord.size() )
|
nuclear@0
|
406 throw DeadlyImportError("OBJ: texture coord index out of range");
|
nuclear@0
|
407
|
nuclear@0
|
408 aiVector2D coord2d = pModel->m_TextureCoord[ tex ];
|
nuclear@0
|
409 pMesh->mTextureCoords[ i ][ newIndex ] = aiVector3D( coord2d.x, coord2d.y, 0.0 );
|
nuclear@0
|
410 }
|
nuclear@0
|
411 }
|
nuclear@0
|
412 }
|
nuclear@0
|
413
|
nuclear@0
|
414 ai_assert( pMesh->mNumVertices > newIndex );
|
nuclear@0
|
415
|
nuclear@0
|
416 // Get destination face
|
nuclear@0
|
417 aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
|
nuclear@0
|
418
|
nuclear@0
|
419 const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 );
|
nuclear@0
|
420 if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last)
|
nuclear@0
|
421 {
|
nuclear@0
|
422 pDestFace->mIndices[ outVertexIndex ] = newIndex;
|
nuclear@0
|
423 outVertexIndex++;
|
nuclear@0
|
424 }
|
nuclear@0
|
425
|
nuclear@0
|
426 if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT)
|
nuclear@0
|
427 {
|
nuclear@0
|
428 outIndex++;
|
nuclear@0
|
429 outVertexIndex = 0;
|
nuclear@0
|
430 }
|
nuclear@0
|
431 else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE)
|
nuclear@0
|
432 {
|
nuclear@0
|
433 outVertexIndex = 0;
|
nuclear@0
|
434
|
nuclear@0
|
435 if(!last)
|
nuclear@0
|
436 outIndex++;
|
nuclear@0
|
437
|
nuclear@0
|
438 if (vertexIndex) {
|
nuclear@0
|
439 if(!last) {
|
nuclear@0
|
440 pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ];
|
nuclear@0
|
441 if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) {
|
nuclear@0
|
442 pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ];
|
nuclear@0
|
443 }
|
nuclear@0
|
444 if ( !pModel->m_TextureCoord.empty() ) {
|
nuclear@0
|
445 for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) {
|
nuclear@0
|
446 pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ];
|
nuclear@0
|
447 }
|
nuclear@0
|
448 }
|
nuclear@0
|
449 ++newIndex;
|
nuclear@0
|
450 }
|
nuclear@0
|
451
|
nuclear@0
|
452 pDestFace[-1].mIndices[1] = newIndex;
|
nuclear@0
|
453 }
|
nuclear@0
|
454 }
|
nuclear@0
|
455 else if (last) {
|
nuclear@0
|
456 outIndex++;
|
nuclear@0
|
457 }
|
nuclear@0
|
458 ++newIndex;
|
nuclear@0
|
459 }
|
nuclear@0
|
460 }
|
nuclear@0
|
461 }
|
nuclear@0
|
462
|
nuclear@0
|
463 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
464 // Counts all stored meshes
|
nuclear@0
|
465 void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes)
|
nuclear@0
|
466 {
|
nuclear@0
|
467 iNumMeshes = 0;
|
nuclear@0
|
468 if ( rObjects.empty() )
|
nuclear@0
|
469 return;
|
nuclear@0
|
470
|
nuclear@0
|
471 iNumMeshes += static_cast<unsigned int>( rObjects.size() );
|
nuclear@0
|
472 for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
|
nuclear@0
|
473 it != rObjects.end();
|
nuclear@0
|
474 ++it)
|
nuclear@0
|
475 {
|
nuclear@0
|
476 if (!(*it)->m_SubObjects.empty())
|
nuclear@0
|
477 {
|
nuclear@0
|
478 countObjects((*it)->m_SubObjects, iNumMeshes);
|
nuclear@0
|
479 }
|
nuclear@0
|
480 }
|
nuclear@0
|
481 }
|
nuclear@0
|
482
|
nuclear@0
|
483 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
484 // Creates the material
|
nuclear@0
|
485 void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pScene )
|
nuclear@0
|
486 {
|
nuclear@0
|
487 ai_assert( NULL != pScene );
|
nuclear@0
|
488 if ( NULL == pScene )
|
nuclear@0
|
489 return;
|
nuclear@0
|
490
|
nuclear@0
|
491 const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size();
|
nuclear@0
|
492 pScene->mNumMaterials = 0;
|
nuclear@0
|
493 if ( pModel->m_MaterialLib.empty() ) {
|
nuclear@0
|
494 DefaultLogger::get()->debug("OBJ: no materials specified");
|
nuclear@0
|
495 return;
|
nuclear@0
|
496 }
|
nuclear@0
|
497
|
nuclear@0
|
498 pScene->mMaterials = new aiMaterial*[ numMaterials ];
|
nuclear@0
|
499 for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ )
|
nuclear@0
|
500 {
|
nuclear@0
|
501 // Store material name
|
nuclear@0
|
502 std::map<std::string, ObjFile::Material*>::const_iterator it;
|
nuclear@0
|
503 it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
|
nuclear@0
|
504
|
nuclear@0
|
505 // No material found, use the default material
|
nuclear@0
|
506 if ( pModel->m_MaterialMap.end() == it )
|
nuclear@0
|
507 continue;
|
nuclear@0
|
508
|
nuclear@0
|
509 aiMaterial* mat = new aiMaterial;
|
nuclear@0
|
510 ObjFile::Material *pCurrentMaterial = (*it).second;
|
nuclear@0
|
511 mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
|
nuclear@0
|
512
|
nuclear@0
|
513 // convert illumination model
|
nuclear@0
|
514 int sm = 0;
|
nuclear@0
|
515 switch (pCurrentMaterial->illumination_model)
|
nuclear@0
|
516 {
|
nuclear@0
|
517 case 0:
|
nuclear@0
|
518 sm = aiShadingMode_NoShading;
|
nuclear@0
|
519 break;
|
nuclear@0
|
520 case 1:
|
nuclear@0
|
521 sm = aiShadingMode_Gouraud;
|
nuclear@0
|
522 break;
|
nuclear@0
|
523 case 2:
|
nuclear@0
|
524 sm = aiShadingMode_Phong;
|
nuclear@0
|
525 break;
|
nuclear@0
|
526 default:
|
nuclear@0
|
527 sm = aiShadingMode_Gouraud;
|
nuclear@0
|
528 DefaultLogger::get()->error("OBJ: unexpected illumination model (0-2 recognized)");
|
nuclear@0
|
529 }
|
nuclear@0
|
530
|
nuclear@0
|
531 mat->AddProperty<int>( &sm, 1, AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
532
|
nuclear@0
|
533 // multiplying the specular exponent with 2 seems to yield better results
|
nuclear@0
|
534 pCurrentMaterial->shineness *= 4.f;
|
nuclear@0
|
535
|
nuclear@0
|
536 // Adding material colors
|
nuclear@0
|
537 mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
|
nuclear@0
|
538 mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
|
nuclear@0
|
539 mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
|
nuclear@0
|
540 mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
|
nuclear@0
|
541 mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
|
nuclear@0
|
542
|
nuclear@0
|
543 // Adding refraction index
|
nuclear@0
|
544 mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI );
|
nuclear@0
|
545
|
nuclear@0
|
546 // Adding textures
|
nuclear@0
|
547 if ( 0 != pCurrentMaterial->texture.length )
|
nuclear@0
|
548 mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
nuclear@0
|
549
|
nuclear@0
|
550 if ( 0 != pCurrentMaterial->textureAmbient.length )
|
nuclear@0
|
551 mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
|
nuclear@0
|
552
|
nuclear@0
|
553 if ( 0 != pCurrentMaterial->textureSpecular.length )
|
nuclear@0
|
554 mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
|
nuclear@0
|
555
|
nuclear@0
|
556 if ( 0 != pCurrentMaterial->textureBump.length )
|
nuclear@0
|
557 mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
|
nuclear@0
|
558
|
nuclear@0
|
559 if ( 0 != pCurrentMaterial->textureNormal.length )
|
nuclear@0
|
560 mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
|
nuclear@0
|
561
|
nuclear@0
|
562 if ( 0 != pCurrentMaterial->textureDisp.length )
|
nuclear@0
|
563 mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
|
nuclear@0
|
564
|
nuclear@0
|
565 if ( 0 != pCurrentMaterial->textureOpacity.length )
|
nuclear@0
|
566 mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
|
nuclear@0
|
567
|
nuclear@0
|
568 if ( 0 != pCurrentMaterial->textureSpecularity.length )
|
nuclear@0
|
569 mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
|
nuclear@0
|
570
|
nuclear@0
|
571 // Store material property info in material array in scene
|
nuclear@0
|
572 pScene->mMaterials[ pScene->mNumMaterials ] = mat;
|
nuclear@0
|
573 pScene->mNumMaterials++;
|
nuclear@0
|
574 }
|
nuclear@0
|
575
|
nuclear@0
|
576 // Test number of created materials.
|
nuclear@0
|
577 ai_assert( pScene->mNumMaterials == numMaterials );
|
nuclear@0
|
578 }
|
nuclear@0
|
579
|
nuclear@0
|
580 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
581 // Appends this node to the parent node
|
nuclear@0
|
582 void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
|
nuclear@0
|
583 {
|
nuclear@0
|
584 // Checking preconditions
|
nuclear@0
|
585 ai_assert( NULL != pParent );
|
nuclear@0
|
586 ai_assert( NULL != pChild );
|
nuclear@0
|
587
|
nuclear@0
|
588 // Assign parent to child
|
nuclear@0
|
589 pChild->mParent = pParent;
|
nuclear@0
|
590 size_t sNumChildren = 0;
|
nuclear@0
|
591 (void)sNumChildren; // remove warning on release build
|
nuclear@0
|
592
|
nuclear@0
|
593 // If already children was assigned to the parent node, store them in a
|
nuclear@0
|
594 std::vector<aiNode*> temp;
|
nuclear@0
|
595 if (pParent->mChildren != NULL)
|
nuclear@0
|
596 {
|
nuclear@0
|
597 sNumChildren = pParent->mNumChildren;
|
nuclear@0
|
598 ai_assert( 0 != sNumChildren );
|
nuclear@0
|
599 for (size_t index = 0; index < pParent->mNumChildren; index++)
|
nuclear@0
|
600 {
|
nuclear@0
|
601 temp.push_back(pParent->mChildren [ index ] );
|
nuclear@0
|
602 }
|
nuclear@0
|
603 delete [] pParent->mChildren;
|
nuclear@0
|
604 }
|
nuclear@0
|
605
|
nuclear@0
|
606 // Copy node instances into parent node
|
nuclear@0
|
607 pParent->mNumChildren++;
|
nuclear@0
|
608 pParent->mChildren = new aiNode*[ pParent->mNumChildren ];
|
nuclear@0
|
609 for (size_t index = 0; index < pParent->mNumChildren-1; index++)
|
nuclear@0
|
610 {
|
nuclear@0
|
611 pParent->mChildren[ index ] = temp [ index ];
|
nuclear@0
|
612 }
|
nuclear@0
|
613 pParent->mChildren[ pParent->mNumChildren-1 ] = pChild;
|
nuclear@0
|
614 }
|
nuclear@0
|
615
|
nuclear@0
|
616 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
617
|
nuclear@0
|
618 } // Namespace Assimp
|
nuclear@0
|
619
|
nuclear@0
|
620 #endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER
|