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