vrshoot

view libs/assimp/Q3DLoader.cpp @ 0:b2f14e535253

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