1 | /* |
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2017, assimp team |
7 | |
8 | |
9 | All rights reserved. |
10 | |
11 | Redistribution and use of this software in source and binary forms, |
12 | with or without modification, are permitted provided that the following |
13 | conditions are met: |
14 | |
15 | * Redistributions of source code must retain the above |
16 | copyright notice, this list of conditions and the |
17 | following disclaimer. |
18 | |
19 | * Redistributions in binary form must reproduce the above |
20 | copyright notice, this list of conditions and the |
21 | following disclaimer in the documentation and/or other |
22 | materials provided with the distribution. |
23 | |
24 | * Neither the name of the assimp team, nor the names of its |
25 | contributors may be used to endorse or promote products |
26 | derived from this software without specific prior |
27 | written permission of the assimp team. |
28 | |
29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
40 | --------------------------------------------------------------------------- |
41 | */ |
42 | |
43 | /** @file Q3DLoader.cpp |
44 | * @brief Implementation of the Q3D importer class |
45 | */ |
46 | |
47 | |
48 | #ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER |
49 | |
50 | // internal headers |
51 | #include "Q3DLoader.h" |
52 | #include "StreamReader.h" |
53 | #include "fast_atof.h" |
54 | #include <assimp/IOSystem.hpp> |
55 | #include <assimp/DefaultLogger.hpp> |
56 | #include <assimp/scene.h> |
57 | #include <assimp/importerdesc.h> |
58 | |
59 | using namespace Assimp; |
60 | |
61 | static const aiImporterDesc desc = { |
62 | "Quick3D Importer" , |
63 | "" , |
64 | "" , |
65 | "http://www.quick3d.com/" , |
66 | aiImporterFlags_SupportBinaryFlavour, |
67 | 0, |
68 | 0, |
69 | 0, |
70 | 0, |
71 | "q3o q3s" |
72 | }; |
73 | |
74 | // ------------------------------------------------------------------------------------------------ |
75 | // Constructor to be privately used by Importer |
76 | Q3DImporter::Q3DImporter() |
77 | {} |
78 | |
79 | // ------------------------------------------------------------------------------------------------ |
80 | // Destructor, private as well |
81 | Q3DImporter::~Q3DImporter() |
82 | {} |
83 | |
84 | // ------------------------------------------------------------------------------------------------ |
85 | // Returns whether the class can handle the format of the given file. |
86 | bool Q3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const |
87 | { |
88 | const std::string extension = GetExtension(pFile); |
89 | |
90 | if (extension == "q3s" || extension == "q3o" ) |
91 | return true; |
92 | else if (!extension.length() || checkSig) { |
93 | if (!pIOHandler) |
94 | return true; |
95 | const char* tokens[] = {"quick3Do" ,"quick3Ds" }; |
96 | return SearchFileHeaderForToken(pIOHandler,pFile,tokens,2); |
97 | } |
98 | return false; |
99 | } |
100 | |
101 | // ------------------------------------------------------------------------------------------------ |
102 | const aiImporterDesc* Q3DImporter::GetInfo () const |
103 | { |
104 | return &desc; |
105 | } |
106 | |
107 | // ------------------------------------------------------------------------------------------------ |
108 | // Imports the given file into the given scene structure. |
109 | void Q3DImporter::InternReadFile( const std::string& pFile, |
110 | aiScene* pScene, IOSystem* pIOHandler) |
111 | { |
112 | StreamReaderLE stream(pIOHandler->Open(pFile,"rb" )); |
113 | |
114 | // The header is 22 bytes large |
115 | if (stream.GetRemainingSize() < 22) |
116 | throw DeadlyImportError("File is either empty or corrupt: " + pFile); |
117 | |
118 | // Check the file's signature |
119 | if (ASSIMP_strincmp( (const char*)stream.GetPtr(), "quick3Do" , 8 ) && |
120 | ASSIMP_strincmp( (const char*)stream.GetPtr(), "quick3Ds" , 8 )) |
121 | { |
122 | throw DeadlyImportError("Not a Quick3D file. Signature string is: " + |
123 | std::string((const char*)stream.GetPtr(),8)); |
124 | } |
125 | |
126 | // Print the file format version |
127 | DefaultLogger::get()->info("Quick3D File format version: " + |
128 | std::string(&((const char*)stream.GetPtr())[8],2)); |
129 | |
130 | // ... an store it |
131 | char major = ((const char*)stream.GetPtr())[8]; |
132 | char minor = ((const char*)stream.GetPtr())[9]; |
133 | |
134 | stream.IncPtr(10); |
135 | unsigned int numMeshes = (unsigned int)stream.GetI4(); |
136 | unsigned int numMats = (unsigned int)stream.GetI4(); |
137 | unsigned int numTextures = (unsigned int)stream.GetI4(); |
138 | |
139 | std::vector<Material> materials; |
140 | materials.reserve(numMats); |
141 | |
142 | std::vector<Mesh> meshes; |
143 | meshes.reserve(numMeshes); |
144 | |
145 | // Allocate the scene root node |
146 | pScene->mRootNode = new aiNode(); |
147 | |
148 | aiColor3D fgColor (0.6f,0.6f,0.6f); |
149 | |
150 | // Now read all file chunks |
151 | while (true) |
152 | { |
153 | if (stream.GetRemainingSize() < 1)break; |
154 | char c = stream.GetI1(); |
155 | switch (c) |
156 | { |
157 | // Meshes chunk |
158 | case 'm': |
159 | { |
160 | for (unsigned int quak = 0; quak < numMeshes; ++quak) |
161 | { |
162 | meshes.push_back(Mesh()); |
163 | Mesh& mesh = meshes.back(); |
164 | |
165 | // read all vertices |
166 | unsigned int numVerts = (unsigned int)stream.GetI4(); |
167 | if (!numVerts) |
168 | throw DeadlyImportError("Quick3D: Found mesh with zero vertices" ); |
169 | |
170 | std::vector<aiVector3D>& verts = mesh.verts; |
171 | verts.resize(numVerts); |
172 | |
173 | for (unsigned int i = 0; i < numVerts;++i) |
174 | { |
175 | verts[i].x = stream.GetF4(); |
176 | verts[i].y = stream.GetF4(); |
177 | verts[i].z = stream.GetF4(); |
178 | } |
179 | |
180 | // read all faces |
181 | numVerts = (unsigned int)stream.GetI4(); |
182 | if (!numVerts) |
183 | throw DeadlyImportError("Quick3D: Found mesh with zero faces" ); |
184 | |
185 | std::vector<Face >& faces = mesh.faces; |
186 | faces.reserve(numVerts); |
187 | |
188 | // number of indices |
189 | for (unsigned int i = 0; i < numVerts;++i) |
190 | { |
191 | faces.push_back(Face(stream.GetI2()) ); |
192 | if (faces.back().indices.empty()) |
193 | throw DeadlyImportError("Quick3D: Found face with zero indices" ); |
194 | } |
195 | |
196 | // indices |
197 | for (unsigned int i = 0; i < numVerts;++i) |
198 | { |
199 | Face& vec = faces[i]; |
200 | for (unsigned int a = 0; a < (unsigned int)vec.indices.size();++a) |
201 | vec.indices[a] = stream.GetI4(); |
202 | } |
203 | |
204 | // material indices |
205 | for (unsigned int i = 0; i < numVerts;++i) |
206 | { |
207 | faces[i].mat = (unsigned int)stream.GetI4(); |
208 | } |
209 | |
210 | // read all normals |
211 | numVerts = (unsigned int)stream.GetI4(); |
212 | std::vector<aiVector3D>& normals = mesh.normals; |
213 | normals.resize(numVerts); |
214 | |
215 | for (unsigned int i = 0; i < numVerts;++i) |
216 | { |
217 | normals[i].x = stream.GetF4(); |
218 | normals[i].y = stream.GetF4(); |
219 | normals[i].z = stream.GetF4(); |
220 | } |
221 | |
222 | numVerts = (unsigned int)stream.GetI4(); |
223 | if (numTextures && numVerts) |
224 | { |
225 | // read all texture coordinates |
226 | std::vector<aiVector3D>& uv = mesh.uv; |
227 | uv.resize(numVerts); |
228 | |
229 | for (unsigned int i = 0; i < numVerts;++i) |
230 | { |
231 | uv[i].x = stream.GetF4(); |
232 | uv[i].y = stream.GetF4(); |
233 | } |
234 | |
235 | // UV indices |
236 | for (unsigned int i = 0; i < (unsigned int)faces.size();++i) |
237 | { |
238 | Face& vec = faces[i]; |
239 | for (unsigned int a = 0; a < (unsigned int)vec.indices.size();++a) |
240 | { |
241 | vec.uvindices[a] = stream.GetI4(); |
242 | if (!i && !a) |
243 | mesh.prevUVIdx = vec.uvindices[a]; |
244 | else if (vec.uvindices[a] != mesh.prevUVIdx) |
245 | mesh.prevUVIdx = UINT_MAX; |
246 | } |
247 | } |
248 | } |
249 | |
250 | // we don't need the rest, but we need to get to the next chunk |
251 | stream.IncPtr(36); |
252 | if (minor > '0' && major == '3') |
253 | stream.IncPtr(mesh.faces.size()); |
254 | } |
255 | // stream.IncPtr(4); // unknown value here |
256 | } |
257 | break; |
258 | |
259 | // materials chunk |
260 | case 'c': |
261 | |
262 | for (unsigned int i = 0; i < numMats; ++i) |
263 | { |
264 | materials.push_back(Material()); |
265 | Material& mat = materials.back(); |
266 | |
267 | // read the material name |
268 | while (( c = stream.GetI1())) |
269 | mat.name.data[mat.name.length++] = c; |
270 | |
271 | // add the terminal character |
272 | mat.name.data[mat.name.length] = '\0'; |
273 | |
274 | // read the ambient color |
275 | mat.ambient.r = stream.GetF4(); |
276 | mat.ambient.g = stream.GetF4(); |
277 | mat.ambient.b = stream.GetF4(); |
278 | |
279 | // read the diffuse color |
280 | mat.diffuse.r = stream.GetF4(); |
281 | mat.diffuse.g = stream.GetF4(); |
282 | mat.diffuse.b = stream.GetF4(); |
283 | |
284 | // read the ambient color |
285 | mat.specular.r = stream.GetF4(); |
286 | mat.specular.g = stream.GetF4(); |
287 | mat.specular.b = stream.GetF4(); |
288 | |
289 | // read the transparency |
290 | mat.transparency = stream.GetF4(); |
291 | |
292 | // unknown value here |
293 | // stream.IncPtr(4); |
294 | // FIX: it could be the texture index ... |
295 | mat.texIdx = (unsigned int)stream.GetI4(); |
296 | } |
297 | |
298 | break; |
299 | |
300 | // texture chunk |
301 | case 't': |
302 | |
303 | pScene->mNumTextures = numTextures; |
304 | if (!numTextures)break; |
305 | pScene->mTextures = new aiTexture*[pScene->mNumTextures]; |
306 | // to make sure we won't crash if we leave through an exception |
307 | ::memset(pScene->mTextures,0,sizeof(void*)*pScene->mNumTextures); |
308 | for (unsigned int i = 0; i < pScene->mNumTextures; ++i) |
309 | { |
310 | aiTexture* tex = pScene->mTextures[i] = new aiTexture(); |
311 | |
312 | // skip the texture name |
313 | while (stream.GetI1()); |
314 | |
315 | // read texture width and height |
316 | tex->mWidth = (unsigned int)stream.GetI4(); |
317 | tex->mHeight = (unsigned int)stream.GetI4(); |
318 | |
319 | if (!tex->mWidth || !tex->mHeight) |
320 | throw DeadlyImportError("Quick3D: Invalid texture. Width or height is zero" ); |
321 | |
322 | unsigned int mul = tex->mWidth * tex->mHeight; |
323 | aiTexel* begin = tex->pcData = new aiTexel[mul]; |
324 | aiTexel* const end = & begin [mul]; |
325 | |
326 | for (;begin != end; ++begin) |
327 | { |
328 | begin->r = stream.GetI1(); |
329 | begin->g = stream.GetI1(); |
330 | begin->b = stream.GetI1(); |
331 | begin->a = 0xff; |
332 | } |
333 | } |
334 | |
335 | break; |
336 | |
337 | // scene chunk |
338 | case 's': |
339 | { |
340 | // skip position and rotation |
341 | stream.IncPtr(12); |
342 | |
343 | for (unsigned int i = 0; i < 4;++i) |
344 | for (unsigned int a = 0; a < 4;++a) |
345 | pScene->mRootNode->mTransformation[i][a] = stream.GetF4(); |
346 | |
347 | stream.IncPtr(16); |
348 | |
349 | // now setup a single camera |
350 | pScene->mNumCameras = 1; |
351 | pScene->mCameras = new aiCamera*[1]; |
352 | aiCamera* cam = pScene->mCameras[0] = new aiCamera(); |
353 | cam->mPosition.x = stream.GetF4(); |
354 | cam->mPosition.y = stream.GetF4(); |
355 | cam->mPosition.z = stream.GetF4(); |
356 | cam->mName.Set("Q3DCamera" ); |
357 | |
358 | // skip eye rotation for the moment |
359 | stream.IncPtr(12); |
360 | |
361 | // read the default material color |
362 | fgColor .r = stream.GetF4(); |
363 | fgColor .g = stream.GetF4(); |
364 | fgColor .b = stream.GetF4(); |
365 | |
366 | // skip some unimportant properties |
367 | stream.IncPtr(29); |
368 | |
369 | // setup a single point light with no attenuation |
370 | pScene->mNumLights = 1; |
371 | pScene->mLights = new aiLight*[1]; |
372 | aiLight* light = pScene->mLights[0] = new aiLight(); |
373 | light->mName.Set("Q3DLight" ); |
374 | light->mType = aiLightSource_POINT; |
375 | |
376 | light->mAttenuationConstant = 1; |
377 | light->mAttenuationLinear = 0; |
378 | light->mAttenuationQuadratic = 0; |
379 | |
380 | light->mColorDiffuse.r = stream.GetF4(); |
381 | light->mColorDiffuse.g = stream.GetF4(); |
382 | light->mColorDiffuse.b = stream.GetF4(); |
383 | |
384 | light->mColorSpecular = light->mColorDiffuse; |
385 | |
386 | |
387 | // We don't need the rest, but we need to know where this chunk ends. |
388 | unsigned int temp = (unsigned int)(stream.GetI4() * stream.GetI4()); |
389 | |
390 | // skip the background file name |
391 | while (stream.GetI1()); |
392 | |
393 | // skip background texture data + the remaining fields |
394 | stream.IncPtr(temp*3 + 20); // 4 bytes of unknown data here |
395 | |
396 | // TODO |
397 | goto outer; |
398 | } |
399 | break; |
400 | |
401 | default: |
402 | throw DeadlyImportError("Quick3D: Unknown chunk" ); |
403 | break; |
404 | }; |
405 | } |
406 | outer: |
407 | |
408 | // If we have no mesh loaded - break here |
409 | if (meshes.empty()) |
410 | throw DeadlyImportError("Quick3D: No meshes loaded" ); |
411 | |
412 | // If we have no materials loaded - generate a default mat |
413 | if (materials.empty()) |
414 | { |
415 | DefaultLogger::get()->info("Quick3D: No material found, generating one" ); |
416 | materials.push_back(Material()); |
417 | materials.back().diffuse = fgColor ; |
418 | } |
419 | |
420 | // find out which materials we'll need |
421 | typedef std::pair<unsigned int, unsigned int> FaceIdx; |
422 | typedef std::vector< FaceIdx > FaceIdxArray; |
423 | FaceIdxArray* fidx = new FaceIdxArray[materials.size()]; |
424 | |
425 | unsigned int p = 0; |
426 | for (std::vector<Mesh>::iterator it = meshes.begin(), end = meshes.end(); |
427 | it != end; ++it,++p) |
428 | { |
429 | unsigned int q = 0; |
430 | for (std::vector<Face>::iterator fit = (*it).faces.begin(), fend = (*it).faces.end(); |
431 | fit != fend; ++fit,++q) |
432 | { |
433 | if ((*fit).mat >= materials.size()) |
434 | { |
435 | DefaultLogger::get()->warn("Quick3D: Material index overflow" ); |
436 | (*fit).mat = 0; |
437 | } |
438 | if (fidx[(*fit).mat].empty())++pScene->mNumMeshes; |
439 | fidx[(*fit).mat].push_back( FaceIdx(p,q) ); |
440 | } |
441 | } |
442 | pScene->mNumMaterials = pScene->mNumMeshes; |
443 | pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; |
444 | pScene->mMeshes = new aiMesh*[pScene->mNumMaterials]; |
445 | |
446 | for (unsigned int i = 0, real = 0; i < (unsigned int)materials.size(); ++i) |
447 | { |
448 | if (fidx[i].empty())continue; |
449 | |
450 | // Allocate a mesh and a material |
451 | aiMesh* mesh = pScene->mMeshes[real] = new aiMesh(); |
452 | aiMaterial* mat = new aiMaterial(); |
453 | pScene->mMaterials[real] = mat; |
454 | |
455 | mesh->mMaterialIndex = real; |
456 | |
457 | // Build the output material |
458 | Material& srcMat = materials[i]; |
459 | mat->AddProperty(&srcMat.diffuse, 1,AI_MATKEY_COLOR_DIFFUSE); |
460 | mat->AddProperty(&srcMat.specular, 1,AI_MATKEY_COLOR_SPECULAR); |
461 | mat->AddProperty(&srcMat.ambient, 1,AI_MATKEY_COLOR_AMBIENT); |
462 | |
463 | // NOTE: Ignore transparency for the moment - it seems |
464 | // unclear how to interpret the data |
465 | #if 0 |
466 | if (!(minor > '0' && major == '3')) |
467 | srcMat.transparency = 1.0f - srcMat.transparency; |
468 | mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_OPACITY); |
469 | #endif |
470 | |
471 | // add shininess - Quick3D seems to use it ins its viewer |
472 | srcMat.transparency = 16.f; |
473 | mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_SHININESS); |
474 | |
475 | int m = (int)aiShadingMode_Phong; |
476 | mat->AddProperty(&m, 1, AI_MATKEY_SHADING_MODEL); |
477 | |
478 | if (srcMat.name.length) |
479 | mat->AddProperty(&srcMat.name,AI_MATKEY_NAME); |
480 | |
481 | // Add a texture |
482 | if (srcMat.texIdx < pScene->mNumTextures || real < pScene->mNumTextures) |
483 | { |
484 | srcMat.name.data[0] = '*'; |
485 | srcMat.name.length = ASSIMP_itoa10(&srcMat.name.data[1],1000, |
486 | (srcMat.texIdx < pScene->mNumTextures ? srcMat.texIdx : real)); |
487 | mat->AddProperty(&srcMat.name,AI_MATKEY_TEXTURE_DIFFUSE(0)); |
488 | } |
489 | |
490 | mesh->mNumFaces = (unsigned int)fidx[i].size(); |
491 | aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; |
492 | |
493 | // Now build the output mesh. First find out how many |
494 | // vertices we'll need |
495 | for (FaceIdxArray::const_iterator it = fidx[i].begin(),end = fidx[i].end(); |
496 | it != end; ++it) |
497 | { |
498 | mesh->mNumVertices += (unsigned int)meshes[(*it).first].faces[ |
499 | (*it).second].indices.size(); |
500 | } |
501 | |
502 | aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; |
503 | aiVector3D* norms = mesh->mNormals = new aiVector3D[mesh->mNumVertices]; |
504 | aiVector3D* uv; |
505 | if (real < pScene->mNumTextures) |
506 | { |
507 | uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; |
508 | mesh->mNumUVComponents[0] = 2; |
509 | } |
510 | else uv = NULL; |
511 | |
512 | // Build the final array |
513 | unsigned int cnt = 0; |
514 | for (FaceIdxArray::const_iterator it = fidx[i].begin(),end = fidx[i].end(); |
515 | it != end; ++it, ++faces) |
516 | { |
517 | Mesh& m = meshes[(*it).first]; |
518 | Face& face = m.faces[(*it).second]; |
519 | faces->mNumIndices = (unsigned int)face.indices.size(); |
520 | faces->mIndices = new unsigned int [faces->mNumIndices]; |
521 | |
522 | |
523 | aiVector3D faceNormal; |
524 | bool fnOK = false; |
525 | |
526 | for (unsigned int n = 0; n < faces->mNumIndices;++n, ++cnt, ++norms, ++verts) |
527 | { |
528 | if (face.indices[n] >= m.verts.size()) |
529 | { |
530 | DefaultLogger::get()->warn("Quick3D: Vertex index overflow" ); |
531 | face.indices[n] = 0; |
532 | } |
533 | |
534 | // copy vertices |
535 | *verts = m.verts[ face.indices[n] ]; |
536 | |
537 | if (face.indices[n] >= m.normals.size() && faces->mNumIndices >= 3) |
538 | { |
539 | // we have no normal here - assign the face normal |
540 | if (!fnOK) |
541 | { |
542 | const aiVector3D& pV1 = m.verts[ face.indices[0] ]; |
543 | const aiVector3D& pV2 = m.verts[ face.indices[1] ]; |
544 | const aiVector3D& pV3 = m.verts[ face.indices.size() - 1 ]; |
545 | faceNormal = (pV2 - pV1) ^ (pV3 - pV1).Normalize(); |
546 | fnOK = true; |
547 | } |
548 | *norms = faceNormal; |
549 | } |
550 | else *norms = m.normals[ face.indices[n] ]; |
551 | |
552 | // copy texture coordinates |
553 | if (uv && m.uv.size()) |
554 | { |
555 | if (m.prevUVIdx != 0xffffffff && m.uv.size() >= m.verts.size()) // workaround |
556 | { |
557 | *uv = m.uv[face.indices[n]]; |
558 | } |
559 | else |
560 | { |
561 | if (face.uvindices[n] >= m.uv.size()) |
562 | { |
563 | DefaultLogger::get()->warn("Quick3D: Texture coordinate index overflow" ); |
564 | face.uvindices[n] = 0; |
565 | } |
566 | *uv = m.uv[face.uvindices[n]]; |
567 | } |
568 | uv->y = 1.f - uv->y; |
569 | ++uv; |
570 | } |
571 | |
572 | // setup the new vertex index |
573 | faces->mIndices[n] = cnt; |
574 | } |
575 | |
576 | } |
577 | ++real; |
578 | } |
579 | |
580 | // Delete our nice helper array |
581 | delete[] fidx; |
582 | |
583 | // Now we need to attach the meshes to the root node of the scene |
584 | pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; |
585 | pScene->mRootNode->mMeshes = new unsigned int [pScene->mNumMeshes]; |
586 | for (unsigned int i = 0; i < pScene->mNumMeshes;++i) |
587 | pScene->mRootNode->mMeshes[i] = i; |
588 | |
589 | /*pScene->mRootNode->mTransformation *= aiMatrix4x4( |
590 | 1.f, 0.f, 0.f, 0.f, |
591 | 0.f, -1.f,0.f, 0.f, |
592 | 0.f, 0.f, 1.f, 0.f, |
593 | 0.f, 0.f, 0.f, 1.f);*/ |
594 | |
595 | // Add cameras and light sources to the scene root node |
596 | pScene->mRootNode->mNumChildren = pScene->mNumLights+pScene->mNumCameras; |
597 | if (pScene->mRootNode->mNumChildren) |
598 | { |
599 | pScene->mRootNode->mChildren = new aiNode* [ pScene->mRootNode->mNumChildren ]; |
600 | |
601 | // the light source |
602 | aiNode* nd = pScene->mRootNode->mChildren[0] = new aiNode(); |
603 | nd->mParent = pScene->mRootNode; |
604 | nd->mName.Set("Q3DLight" ); |
605 | nd->mTransformation = pScene->mRootNode->mTransformation; |
606 | nd->mTransformation.Inverse(); |
607 | |
608 | // camera |
609 | nd = pScene->mRootNode->mChildren[1] = new aiNode(); |
610 | nd->mParent = pScene->mRootNode; |
611 | nd->mName.Set("Q3DCamera" ); |
612 | nd->mTransformation = pScene->mRootNode->mChildren[0]->mTransformation; |
613 | } |
614 | } |
615 | |
616 | #endif // !! ASSIMP_BUILD_NO_Q3D_IMPORTER |
617 | |