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 3DSLoader.cpp
|
nuclear@0
|
43 * @brief Implementation of the 3ds importer class
|
nuclear@0
|
44 *
|
nuclear@0
|
45 * http://www.the-labs.com/Blender/3DS-details.html
|
nuclear@0
|
46 */
|
nuclear@0
|
47
|
nuclear@0
|
48 #include "AssimpPCH.h"
|
nuclear@0
|
49 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
nuclear@0
|
50
|
nuclear@0
|
51 // internal headers
|
nuclear@0
|
52 #include "3DSLoader.h"
|
nuclear@0
|
53
|
nuclear@0
|
54 using namespace Assimp;
|
nuclear@0
|
55
|
nuclear@0
|
56 static const aiImporterDesc desc = {
|
nuclear@0
|
57 "Discreet 3DS Importer",
|
nuclear@0
|
58 "",
|
nuclear@0
|
59 "",
|
nuclear@0
|
60 "Limited animation support",
|
nuclear@0
|
61 aiImporterFlags_SupportBinaryFlavour,
|
nuclear@0
|
62 0,
|
nuclear@0
|
63 0,
|
nuclear@0
|
64 0,
|
nuclear@0
|
65 0,
|
nuclear@0
|
66 "3ds prj"
|
nuclear@0
|
67 };
|
nuclear@0
|
68
|
nuclear@0
|
69
|
nuclear@0
|
70 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
71 // Begins a new parsing block
|
nuclear@0
|
72 // - Reads the current chunk and validates it
|
nuclear@0
|
73 // - computes its length
|
nuclear@0
|
74 #define ASSIMP_3DS_BEGIN_CHUNK() \
|
nuclear@0
|
75 while (true) { \
|
nuclear@0
|
76 if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \
|
nuclear@0
|
77 return; \
|
nuclear@0
|
78 } \
|
nuclear@0
|
79 Discreet3DS::Chunk chunk; \
|
nuclear@0
|
80 ReadChunk(&chunk); \
|
nuclear@0
|
81 int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \
|
nuclear@0
|
82 const int oldReadLimit = stream->GetReadLimit(); \
|
nuclear@0
|
83 stream->SetReadLimit(stream->GetCurrentPos() + chunkSize); \
|
nuclear@0
|
84
|
nuclear@0
|
85
|
nuclear@0
|
86 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
87 // End a parsing block
|
nuclear@0
|
88 // Must follow at the end of each parsing block, reset chunk end marker to previous value
|
nuclear@0
|
89 #define ASSIMP_3DS_END_CHUNK() \
|
nuclear@0
|
90 stream->SkipToReadLimit(); \
|
nuclear@0
|
91 stream->SetReadLimit(oldReadLimit); \
|
nuclear@0
|
92 if (stream->GetRemainingSizeToLimit() == 0) \
|
nuclear@0
|
93 return; \
|
nuclear@0
|
94 }
|
nuclear@0
|
95
|
nuclear@0
|
96 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
97 // Constructor to be privately used by Importer
|
nuclear@0
|
98 Discreet3DSImporter::Discreet3DSImporter()
|
nuclear@0
|
99 {}
|
nuclear@0
|
100
|
nuclear@0
|
101 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
102 // Destructor, private as well
|
nuclear@0
|
103 Discreet3DSImporter::~Discreet3DSImporter()
|
nuclear@0
|
104 {}
|
nuclear@0
|
105
|
nuclear@0
|
106 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
107 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
108 bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
nuclear@0
|
109 {
|
nuclear@0
|
110 std::string extension = GetExtension(pFile);
|
nuclear@0
|
111 if(extension == "3ds" || extension == "prj" ) {
|
nuclear@0
|
112 return true;
|
nuclear@0
|
113 }
|
nuclear@0
|
114 if (!extension.length() || checkSig) {
|
nuclear@0
|
115 uint16_t token[3];
|
nuclear@0
|
116 token[0] = 0x4d4d;
|
nuclear@0
|
117 token[1] = 0x3dc2;
|
nuclear@0
|
118 //token[2] = 0x3daa;
|
nuclear@0
|
119 return CheckMagicToken(pIOHandler,pFile,token,2,0,2);
|
nuclear@0
|
120 }
|
nuclear@0
|
121 return false;
|
nuclear@0
|
122 }
|
nuclear@0
|
123
|
nuclear@0
|
124 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
125 // Loader registry entry
|
nuclear@0
|
126 const aiImporterDesc* Discreet3DSImporter::GetInfo () const
|
nuclear@0
|
127 {
|
nuclear@0
|
128 return &desc;
|
nuclear@0
|
129 }
|
nuclear@0
|
130
|
nuclear@0
|
131 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
132 // Setup configuration properties
|
nuclear@0
|
133 void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/)
|
nuclear@0
|
134 {
|
nuclear@0
|
135 // nothing to be done for the moment
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
139 // Imports the given file into the given scene structure.
|
nuclear@0
|
140 void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
nuclear@0
|
141 aiScene* pScene, IOSystem* pIOHandler)
|
nuclear@0
|
142 {
|
nuclear@0
|
143 StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
|
nuclear@0
|
144 this->stream = &stream;
|
nuclear@0
|
145
|
nuclear@0
|
146 // We should have at least one chunk
|
nuclear@0
|
147 if (stream.GetRemainingSize() < 16) {
|
nuclear@0
|
148 throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
|
nuclear@0
|
149 }
|
nuclear@0
|
150
|
nuclear@0
|
151 // Allocate our temporary 3DS representation
|
nuclear@0
|
152 mScene = new D3DS::Scene();
|
nuclear@0
|
153
|
nuclear@0
|
154 // Initialize members
|
nuclear@0
|
155 mLastNodeIndex = -1;
|
nuclear@0
|
156 mCurrentNode = new D3DS::Node();
|
nuclear@0
|
157 mRootNode = mCurrentNode;
|
nuclear@0
|
158 mRootNode->mHierarchyPos = -1;
|
nuclear@0
|
159 mRootNode->mHierarchyIndex = -1;
|
nuclear@0
|
160 mRootNode->mParent = NULL;
|
nuclear@0
|
161 mMasterScale = 1.0f;
|
nuclear@0
|
162 mBackgroundImage = "";
|
nuclear@0
|
163 bHasBG = false;
|
nuclear@0
|
164 bIsPrj = false;
|
nuclear@0
|
165
|
nuclear@0
|
166 // Parse the file
|
nuclear@0
|
167 ParseMainChunk();
|
nuclear@0
|
168
|
nuclear@0
|
169 // Process all meshes in the file. First check whether all
|
nuclear@0
|
170 // face indices haev valid values. The generate our
|
nuclear@0
|
171 // internal verbose representation. Finally compute normal
|
nuclear@0
|
172 // vectors from the smoothing groups we read from the
|
nuclear@0
|
173 // file.
|
nuclear@0
|
174 for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(),
|
nuclear@0
|
175 end = mScene->mMeshes.end(); i != end;++i) {
|
nuclear@0
|
176 CheckIndices(*i);
|
nuclear@0
|
177 MakeUnique (*i);
|
nuclear@0
|
178 ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i);
|
nuclear@0
|
179 }
|
nuclear@0
|
180
|
nuclear@0
|
181 // Replace all occurences of the default material with a
|
nuclear@0
|
182 // valid material. Generate it if no material containing
|
nuclear@0
|
183 // DEFAULT in its name has been found in the file
|
nuclear@0
|
184 ReplaceDefaultMaterial();
|
nuclear@0
|
185
|
nuclear@0
|
186 // Convert the scene from our internal representation to an
|
nuclear@0
|
187 // aiScene object. This involves copying all meshes, lights
|
nuclear@0
|
188 // and cameras to the scene
|
nuclear@0
|
189 ConvertScene(pScene);
|
nuclear@0
|
190
|
nuclear@0
|
191 // Generate the node graph for the scene. This is a little bit
|
nuclear@0
|
192 // tricky since we'll need to split some meshes into submeshes
|
nuclear@0
|
193 GenerateNodeGraph(pScene);
|
nuclear@0
|
194
|
nuclear@0
|
195 // Now apply the master scaling factor to the scene
|
nuclear@0
|
196 ApplyMasterScale(pScene);
|
nuclear@0
|
197
|
nuclear@0
|
198 // Delete our internal scene representation and the root
|
nuclear@0
|
199 // node, so the whole hierarchy will follow
|
nuclear@0
|
200 delete mRootNode;
|
nuclear@0
|
201 delete mScene;
|
nuclear@0
|
202
|
nuclear@0
|
203 AI_DEBUG_INVALIDATE_PTR(mRootNode);
|
nuclear@0
|
204 AI_DEBUG_INVALIDATE_PTR(mScene);
|
nuclear@0
|
205 AI_DEBUG_INVALIDATE_PTR(this->stream);
|
nuclear@0
|
206 }
|
nuclear@0
|
207
|
nuclear@0
|
208 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
209 // Applies a master-scaling factor to the imported scene
|
nuclear@0
|
210 void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
|
nuclear@0
|
211 {
|
nuclear@0
|
212 // There are some 3DS files with a zero scaling factor
|
nuclear@0
|
213 if (!mMasterScale)mMasterScale = 1.0f;
|
nuclear@0
|
214 else mMasterScale = 1.0f / mMasterScale;
|
nuclear@0
|
215
|
nuclear@0
|
216 // Construct an uniform scaling matrix and multiply with it
|
nuclear@0
|
217 pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
nuclear@0
|
218 mMasterScale,0.0f, 0.0f, 0.0f,
|
nuclear@0
|
219 0.0f, mMasterScale,0.0f, 0.0f,
|
nuclear@0
|
220 0.0f, 0.0f, mMasterScale,0.0f,
|
nuclear@0
|
221 0.0f, 0.0f, 0.0f, 1.0f);
|
nuclear@0
|
222
|
nuclear@0
|
223 // Check whether a scaling track is assigned to the root node.
|
nuclear@0
|
224 }
|
nuclear@0
|
225
|
nuclear@0
|
226 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
227 // Reads a new chunk from the file
|
nuclear@0
|
228 void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
|
nuclear@0
|
229 {
|
nuclear@0
|
230 ai_assert(pcOut != NULL);
|
nuclear@0
|
231
|
nuclear@0
|
232 pcOut->Flag = stream->GetI2();
|
nuclear@0
|
233 pcOut->Size = stream->GetI4();
|
nuclear@0
|
234
|
nuclear@0
|
235 if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize())
|
nuclear@0
|
236 throw DeadlyImportError("Chunk is too large");
|
nuclear@0
|
237
|
nuclear@0
|
238 if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit())
|
nuclear@0
|
239 DefaultLogger::get()->error("3DS: Chunk overflow");
|
nuclear@0
|
240 }
|
nuclear@0
|
241
|
nuclear@0
|
242 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
243 // Skip a chunk
|
nuclear@0
|
244 void Discreet3DSImporter::SkipChunk()
|
nuclear@0
|
245 {
|
nuclear@0
|
246 Discreet3DS::Chunk psChunk;
|
nuclear@0
|
247 ReadChunk(&psChunk);
|
nuclear@0
|
248
|
nuclear@0
|
249 stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk));
|
nuclear@0
|
250 return;
|
nuclear@0
|
251 }
|
nuclear@0
|
252
|
nuclear@0
|
253 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
254 // Process the primary chunk of the file
|
nuclear@0
|
255 void Discreet3DSImporter::ParseMainChunk()
|
nuclear@0
|
256 {
|
nuclear@0
|
257 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
258
|
nuclear@0
|
259 // get chunk type
|
nuclear@0
|
260 switch (chunk.Flag)
|
nuclear@0
|
261 {
|
nuclear@0
|
262
|
nuclear@0
|
263 case Discreet3DS::CHUNK_PRJ:
|
nuclear@0
|
264 bIsPrj = true;
|
nuclear@0
|
265 case Discreet3DS::CHUNK_MAIN:
|
nuclear@0
|
266 ParseEditorChunk();
|
nuclear@0
|
267 break;
|
nuclear@0
|
268 };
|
nuclear@0
|
269
|
nuclear@0
|
270 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
271 // recursively continue processing this hierarchy level
|
nuclear@0
|
272 return ParseMainChunk();
|
nuclear@0
|
273 }
|
nuclear@0
|
274
|
nuclear@0
|
275 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
276 void Discreet3DSImporter::ParseEditorChunk()
|
nuclear@0
|
277 {
|
nuclear@0
|
278 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
279
|
nuclear@0
|
280 // get chunk type
|
nuclear@0
|
281 switch (chunk.Flag)
|
nuclear@0
|
282 {
|
nuclear@0
|
283 case Discreet3DS::CHUNK_OBJMESH:
|
nuclear@0
|
284
|
nuclear@0
|
285 ParseObjectChunk();
|
nuclear@0
|
286 break;
|
nuclear@0
|
287
|
nuclear@0
|
288 // NOTE: In several documentations in the internet this
|
nuclear@0
|
289 // chunk appears at different locations
|
nuclear@0
|
290 case Discreet3DS::CHUNK_KEYFRAMER:
|
nuclear@0
|
291
|
nuclear@0
|
292 ParseKeyframeChunk();
|
nuclear@0
|
293 break;
|
nuclear@0
|
294
|
nuclear@0
|
295 case Discreet3DS::CHUNK_VERSION:
|
nuclear@0
|
296 {
|
nuclear@0
|
297 // print the version number
|
nuclear@0
|
298 char buff[10];
|
nuclear@0
|
299 ASSIMP_itoa10(buff,stream->GetI2());
|
nuclear@0
|
300 DefaultLogger::get()->info(std::string("3DS file format version: ") + buff);
|
nuclear@0
|
301 }
|
nuclear@0
|
302 break;
|
nuclear@0
|
303 };
|
nuclear@0
|
304 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
305 }
|
nuclear@0
|
306
|
nuclear@0
|
307 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
308 void Discreet3DSImporter::ParseObjectChunk()
|
nuclear@0
|
309 {
|
nuclear@0
|
310 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
311
|
nuclear@0
|
312 // get chunk type
|
nuclear@0
|
313 switch (chunk.Flag)
|
nuclear@0
|
314 {
|
nuclear@0
|
315 case Discreet3DS::CHUNK_OBJBLOCK:
|
nuclear@0
|
316 {
|
nuclear@0
|
317 unsigned int cnt = 0;
|
nuclear@0
|
318 const char* sz = (const char*)stream->GetPtr();
|
nuclear@0
|
319
|
nuclear@0
|
320 // Get the name of the geometry object
|
nuclear@0
|
321 while (stream->GetI1())++cnt;
|
nuclear@0
|
322 ParseChunk(sz,cnt);
|
nuclear@0
|
323 }
|
nuclear@0
|
324 break;
|
nuclear@0
|
325
|
nuclear@0
|
326 case Discreet3DS::CHUNK_MAT_MATERIAL:
|
nuclear@0
|
327
|
nuclear@0
|
328 // Add a new material to the list
|
nuclear@0
|
329 mScene->mMaterials.push_back(D3DS::Material());
|
nuclear@0
|
330 ParseMaterialChunk();
|
nuclear@0
|
331 break;
|
nuclear@0
|
332
|
nuclear@0
|
333 case Discreet3DS::CHUNK_AMBCOLOR:
|
nuclear@0
|
334
|
nuclear@0
|
335 // This is the ambient base color of the scene.
|
nuclear@0
|
336 // We add it to the ambient color of all materials
|
nuclear@0
|
337 ParseColorChunk(&mClrAmbient,true);
|
nuclear@0
|
338 if (is_qnan(mClrAmbient.r))
|
nuclear@0
|
339 {
|
nuclear@0
|
340 // We failed to read the ambient base color.
|
nuclear@0
|
341 DefaultLogger::get()->error("3DS: Failed to read ambient base color");
|
nuclear@0
|
342 mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
|
nuclear@0
|
343 }
|
nuclear@0
|
344 break;
|
nuclear@0
|
345
|
nuclear@0
|
346 case Discreet3DS::CHUNK_BIT_MAP:
|
nuclear@0
|
347 {
|
nuclear@0
|
348 // Specifies the background image. The string should already be
|
nuclear@0
|
349 // properly 0 terminated but we need to be sure
|
nuclear@0
|
350 unsigned int cnt = 0;
|
nuclear@0
|
351 const char* sz = (const char*)stream->GetPtr();
|
nuclear@0
|
352 while (stream->GetI1())++cnt;
|
nuclear@0
|
353 mBackgroundImage = std::string(sz,cnt);
|
nuclear@0
|
354 }
|
nuclear@0
|
355 break;
|
nuclear@0
|
356
|
nuclear@0
|
357 case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
|
nuclear@0
|
358 bHasBG = true;
|
nuclear@0
|
359 break;
|
nuclear@0
|
360
|
nuclear@0
|
361 case Discreet3DS::CHUNK_MASTER_SCALE:
|
nuclear@0
|
362 // Scene master scaling factor
|
nuclear@0
|
363 mMasterScale = stream->GetF4();
|
nuclear@0
|
364 break;
|
nuclear@0
|
365 };
|
nuclear@0
|
366 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
367 }
|
nuclear@0
|
368
|
nuclear@0
|
369 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
370 void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
nuclear@0
|
371 {
|
nuclear@0
|
372 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
373
|
nuclear@0
|
374 // IMPLEMENTATION NOTE;
|
nuclear@0
|
375 // Cameras or lights define their transformation in their parent node and in the
|
nuclear@0
|
376 // corresponding light or camera chunks. However, we read and process the latter
|
nuclear@0
|
377 // to to be able to return valid cameras/lights even if no scenegraph is given.
|
nuclear@0
|
378
|
nuclear@0
|
379 // get chunk type
|
nuclear@0
|
380 switch (chunk.Flag)
|
nuclear@0
|
381 {
|
nuclear@0
|
382 case Discreet3DS::CHUNK_TRIMESH:
|
nuclear@0
|
383 {
|
nuclear@0
|
384 // this starts a new triangle mesh
|
nuclear@0
|
385 mScene->mMeshes.push_back(D3DS::Mesh());
|
nuclear@0
|
386 D3DS::Mesh& m = mScene->mMeshes.back();
|
nuclear@0
|
387
|
nuclear@0
|
388 // Setup the name of the mesh
|
nuclear@0
|
389 m.mName = std::string(name, num);
|
nuclear@0
|
390
|
nuclear@0
|
391 // Read mesh chunks
|
nuclear@0
|
392 ParseMeshChunk();
|
nuclear@0
|
393 }
|
nuclear@0
|
394 break;
|
nuclear@0
|
395
|
nuclear@0
|
396 case Discreet3DS::CHUNK_LIGHT:
|
nuclear@0
|
397 {
|
nuclear@0
|
398 // This starts a new light
|
nuclear@0
|
399 aiLight* light = new aiLight();
|
nuclear@0
|
400 mScene->mLights.push_back(light);
|
nuclear@0
|
401
|
nuclear@0
|
402 light->mName.Set(std::string(name, num));
|
nuclear@0
|
403
|
nuclear@0
|
404 // First read the position of the light
|
nuclear@0
|
405 light->mPosition.x = stream->GetF4();
|
nuclear@0
|
406 light->mPosition.y = stream->GetF4();
|
nuclear@0
|
407 light->mPosition.z = stream->GetF4();
|
nuclear@0
|
408
|
nuclear@0
|
409 light->mColorDiffuse = aiColor3D(1.f,1.f,1.f);
|
nuclear@0
|
410
|
nuclear@0
|
411 // Now check for further subchunks
|
nuclear@0
|
412 if (!bIsPrj) /* fixme */
|
nuclear@0
|
413 ParseLightChunk();
|
nuclear@0
|
414
|
nuclear@0
|
415 // The specular light color is identical the the diffuse light color. The ambient light color
|
nuclear@0
|
416 // is equal to the ambient base color of the whole scene.
|
nuclear@0
|
417 light->mColorSpecular = light->mColorDiffuse;
|
nuclear@0
|
418 light->mColorAmbient = mClrAmbient;
|
nuclear@0
|
419
|
nuclear@0
|
420 if (light->mType == aiLightSource_UNDEFINED)
|
nuclear@0
|
421 {
|
nuclear@0
|
422 // It must be a point light
|
nuclear@0
|
423 light->mType = aiLightSource_POINT;
|
nuclear@0
|
424 }}
|
nuclear@0
|
425 break;
|
nuclear@0
|
426
|
nuclear@0
|
427 case Discreet3DS::CHUNK_CAMERA:
|
nuclear@0
|
428 {
|
nuclear@0
|
429 // This starts a new camera
|
nuclear@0
|
430 aiCamera* camera = new aiCamera();
|
nuclear@0
|
431 mScene->mCameras.push_back(camera);
|
nuclear@0
|
432 camera->mName.Set(std::string(name, num));
|
nuclear@0
|
433
|
nuclear@0
|
434 // First read the position of the camera
|
nuclear@0
|
435 camera->mPosition.x = stream->GetF4();
|
nuclear@0
|
436 camera->mPosition.y = stream->GetF4();
|
nuclear@0
|
437 camera->mPosition.z = stream->GetF4();
|
nuclear@0
|
438
|
nuclear@0
|
439 // Then the camera target
|
nuclear@0
|
440 camera->mLookAt.x = stream->GetF4() - camera->mPosition.x;
|
nuclear@0
|
441 camera->mLookAt.y = stream->GetF4() - camera->mPosition.y;
|
nuclear@0
|
442 camera->mLookAt.z = stream->GetF4() - camera->mPosition.z;
|
nuclear@0
|
443 float len = camera->mLookAt.Length();
|
nuclear@0
|
444 if (len < 1e-5f) {
|
nuclear@0
|
445
|
nuclear@0
|
446 // There are some files with lookat == position. Don't know why or whether it's ok or not.
|
nuclear@0
|
447 DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector");
|
nuclear@0
|
448 camera->mLookAt = aiVector3D(0.f,1.f,0.f);
|
nuclear@0
|
449
|
nuclear@0
|
450 }
|
nuclear@0
|
451 else camera->mLookAt /= len;
|
nuclear@0
|
452
|
nuclear@0
|
453 // And finally - the camera rotation angle, in counter clockwise direction
|
nuclear@0
|
454 const float angle = AI_DEG_TO_RAD( stream->GetF4() );
|
nuclear@0
|
455 aiQuaternion quat(camera->mLookAt,angle);
|
nuclear@0
|
456 camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f);
|
nuclear@0
|
457
|
nuclear@0
|
458 // Read the lense angle
|
nuclear@0
|
459 camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() );
|
nuclear@0
|
460 if (camera->mHorizontalFOV < 0.001f) {
|
nuclear@0
|
461 camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f);
|
nuclear@0
|
462 }
|
nuclear@0
|
463
|
nuclear@0
|
464 // Now check for further subchunks
|
nuclear@0
|
465 if (!bIsPrj) /* fixme */ {
|
nuclear@0
|
466 ParseCameraChunk();
|
nuclear@0
|
467 }}
|
nuclear@0
|
468 break;
|
nuclear@0
|
469 };
|
nuclear@0
|
470 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
471 }
|
nuclear@0
|
472
|
nuclear@0
|
473 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
474 void Discreet3DSImporter::ParseLightChunk()
|
nuclear@0
|
475 {
|
nuclear@0
|
476 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
477 aiLight* light = mScene->mLights.back();
|
nuclear@0
|
478
|
nuclear@0
|
479 // get chunk type
|
nuclear@0
|
480 switch (chunk.Flag)
|
nuclear@0
|
481 {
|
nuclear@0
|
482 case Discreet3DS::CHUNK_DL_SPOTLIGHT:
|
nuclear@0
|
483 // Now we can be sure that the light is a spot light
|
nuclear@0
|
484 light->mType = aiLightSource_SPOT;
|
nuclear@0
|
485
|
nuclear@0
|
486 // We wouldn't need to normalize here, but we do it
|
nuclear@0
|
487 light->mDirection.x = stream->GetF4() - light->mPosition.x;
|
nuclear@0
|
488 light->mDirection.y = stream->GetF4() - light->mPosition.y;
|
nuclear@0
|
489 light->mDirection.z = stream->GetF4() - light->mPosition.z;
|
nuclear@0
|
490 light->mDirection.Normalize();
|
nuclear@0
|
491
|
nuclear@0
|
492 // Now the hotspot and falloff angles - in degrees
|
nuclear@0
|
493 light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() );
|
nuclear@0
|
494
|
nuclear@0
|
495 // FIX: the falloff angle is just an offset
|
nuclear@0
|
496 light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() );
|
nuclear@0
|
497 break;
|
nuclear@0
|
498
|
nuclear@0
|
499 // intensity multiplier
|
nuclear@0
|
500 case Discreet3DS::CHUNK_DL_MULTIPLIER:
|
nuclear@0
|
501 light->mColorDiffuse = light->mColorDiffuse * stream->GetF4();
|
nuclear@0
|
502 break;
|
nuclear@0
|
503
|
nuclear@0
|
504 // light color
|
nuclear@0
|
505 case Discreet3DS::CHUNK_RGBF:
|
nuclear@0
|
506 case Discreet3DS::CHUNK_LINRGBF:
|
nuclear@0
|
507 light->mColorDiffuse.r *= stream->GetF4();
|
nuclear@0
|
508 light->mColorDiffuse.g *= stream->GetF4();
|
nuclear@0
|
509 light->mColorDiffuse.b *= stream->GetF4();
|
nuclear@0
|
510 break;
|
nuclear@0
|
511
|
nuclear@0
|
512 // light attenuation
|
nuclear@0
|
513 case Discreet3DS::CHUNK_DL_ATTENUATE:
|
nuclear@0
|
514 light->mAttenuationLinear = stream->GetF4();
|
nuclear@0
|
515 break;
|
nuclear@0
|
516 };
|
nuclear@0
|
517
|
nuclear@0
|
518 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
519 }
|
nuclear@0
|
520
|
nuclear@0
|
521 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
522 void Discreet3DSImporter::ParseCameraChunk()
|
nuclear@0
|
523 {
|
nuclear@0
|
524 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
525 aiCamera* camera = mScene->mCameras.back();
|
nuclear@0
|
526
|
nuclear@0
|
527 // get chunk type
|
nuclear@0
|
528 switch (chunk.Flag)
|
nuclear@0
|
529 {
|
nuclear@0
|
530 // near and far clip plane
|
nuclear@0
|
531 case Discreet3DS::CHUNK_CAM_RANGES:
|
nuclear@0
|
532 camera->mClipPlaneNear = stream->GetF4();
|
nuclear@0
|
533 camera->mClipPlaneFar = stream->GetF4();
|
nuclear@0
|
534 break;
|
nuclear@0
|
535 }
|
nuclear@0
|
536
|
nuclear@0
|
537 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
538 }
|
nuclear@0
|
539
|
nuclear@0
|
540 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
541 void Discreet3DSImporter::ParseKeyframeChunk()
|
nuclear@0
|
542 {
|
nuclear@0
|
543 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
544
|
nuclear@0
|
545 // get chunk type
|
nuclear@0
|
546 switch (chunk.Flag)
|
nuclear@0
|
547 {
|
nuclear@0
|
548 case Discreet3DS::CHUNK_TRACKCAMTGT:
|
nuclear@0
|
549 case Discreet3DS::CHUNK_TRACKSPOTL:
|
nuclear@0
|
550 case Discreet3DS::CHUNK_TRACKCAMERA:
|
nuclear@0
|
551 case Discreet3DS::CHUNK_TRACKINFO:
|
nuclear@0
|
552 case Discreet3DS::CHUNK_TRACKLIGHT:
|
nuclear@0
|
553 case Discreet3DS::CHUNK_TRACKLIGTGT:
|
nuclear@0
|
554
|
nuclear@0
|
555 // this starts a new mesh hierarchy chunk
|
nuclear@0
|
556 ParseHierarchyChunk(chunk.Flag);
|
nuclear@0
|
557 break;
|
nuclear@0
|
558 };
|
nuclear@0
|
559
|
nuclear@0
|
560 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
561 }
|
nuclear@0
|
562
|
nuclear@0
|
563 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
564 // Little helper function for ParseHierarchyChunk
|
nuclear@0
|
565 void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent)
|
nuclear@0
|
566 {
|
nuclear@0
|
567 if (!pcCurrent) {
|
nuclear@0
|
568 mRootNode->push_back(pcNode);
|
nuclear@0
|
569 return;
|
nuclear@0
|
570 }
|
nuclear@0
|
571
|
nuclear@0
|
572 if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) {
|
nuclear@0
|
573 if(pcCurrent->mParent) {
|
nuclear@0
|
574 pcCurrent->mParent->push_back(pcNode);
|
nuclear@0
|
575 }
|
nuclear@0
|
576 else pcCurrent->push_back(pcNode);
|
nuclear@0
|
577 return;
|
nuclear@0
|
578 }
|
nuclear@0
|
579 return InverseNodeSearch(pcNode,pcCurrent->mParent);
|
nuclear@0
|
580 }
|
nuclear@0
|
581
|
nuclear@0
|
582 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
583 // Find a node with a specific name in the import hierarchy
|
nuclear@0
|
584 D3DS::Node* FindNode(D3DS::Node* root, const std::string& name)
|
nuclear@0
|
585 {
|
nuclear@0
|
586 if (root->mName == name)
|
nuclear@0
|
587 return root;
|
nuclear@0
|
588 for (std::vector<D3DS::Node*>::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) {
|
nuclear@0
|
589 D3DS::Node* nd;
|
nuclear@0
|
590 if (( nd = FindNode(*it,name)))
|
nuclear@0
|
591 return nd;
|
nuclear@0
|
592 }
|
nuclear@0
|
593 return NULL;
|
nuclear@0
|
594 }
|
nuclear@0
|
595
|
nuclear@0
|
596 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
597 // Binary predicate for std::unique()
|
nuclear@0
|
598 template <class T>
|
nuclear@0
|
599 bool KeyUniqueCompare(const T& first, const T& second)
|
nuclear@0
|
600 {
|
nuclear@0
|
601 return first.mTime == second.mTime;
|
nuclear@0
|
602 }
|
nuclear@0
|
603
|
nuclear@0
|
604 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
605 // Skip some additional import data.
|
nuclear@0
|
606 void Discreet3DSImporter::SkipTCBInfo()
|
nuclear@0
|
607 {
|
nuclear@0
|
608 unsigned int flags = stream->GetI2();
|
nuclear@0
|
609
|
nuclear@0
|
610 if (!flags) {
|
nuclear@0
|
611 // Currently we can't do anything with these values. They occur
|
nuclear@0
|
612 // quite rare, so it wouldn't be worth the effort implementing
|
nuclear@0
|
613 // them. 3DS ist not really suitable for complex animations,
|
nuclear@0
|
614 // so full support is not required.
|
nuclear@0
|
615 DefaultLogger::get()->warn("3DS: Skipping TCB animation info");
|
nuclear@0
|
616 }
|
nuclear@0
|
617
|
nuclear@0
|
618 if (flags & Discreet3DS::KEY_USE_TENS) {
|
nuclear@0
|
619 stream->IncPtr(4);
|
nuclear@0
|
620 }
|
nuclear@0
|
621 if (flags & Discreet3DS::KEY_USE_BIAS) {
|
nuclear@0
|
622 stream->IncPtr(4);
|
nuclear@0
|
623 }
|
nuclear@0
|
624 if (flags & Discreet3DS::KEY_USE_CONT) {
|
nuclear@0
|
625 stream->IncPtr(4);
|
nuclear@0
|
626 }
|
nuclear@0
|
627 if (flags & Discreet3DS::KEY_USE_EASE_FROM) {
|
nuclear@0
|
628 stream->IncPtr(4);
|
nuclear@0
|
629 }
|
nuclear@0
|
630 if (flags & Discreet3DS::KEY_USE_EASE_TO) {
|
nuclear@0
|
631 stream->IncPtr(4);
|
nuclear@0
|
632 }
|
nuclear@0
|
633 }
|
nuclear@0
|
634
|
nuclear@0
|
635 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
636 // Read hierarchy and keyframe info
|
nuclear@0
|
637 void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
nuclear@0
|
638 {
|
nuclear@0
|
639 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
640
|
nuclear@0
|
641 // get chunk type
|
nuclear@0
|
642 switch (chunk.Flag)
|
nuclear@0
|
643 {
|
nuclear@0
|
644 case Discreet3DS::CHUNK_TRACKOBJNAME:
|
nuclear@0
|
645
|
nuclear@0
|
646 // This is the name of the object to which the track applies. The chunk also
|
nuclear@0
|
647 // defines the position of this object in the hierarchy.
|
nuclear@0
|
648 {
|
nuclear@0
|
649
|
nuclear@0
|
650 // First of all: get the name of the object
|
nuclear@0
|
651 unsigned int cnt = 0;
|
nuclear@0
|
652 const char* sz = (const char*)stream->GetPtr();
|
nuclear@0
|
653
|
nuclear@0
|
654 while (stream->GetI1())++cnt;
|
nuclear@0
|
655 std::string name = std::string(sz,cnt);
|
nuclear@0
|
656
|
nuclear@0
|
657 // Now find out whether we have this node already (target animation channels
|
nuclear@0
|
658 // are stored with a separate object ID)
|
nuclear@0
|
659 D3DS::Node* pcNode = FindNode(mRootNode,name);
|
nuclear@0
|
660 if (pcNode)
|
nuclear@0
|
661 {
|
nuclear@0
|
662 // Make this node the current node
|
nuclear@0
|
663 mCurrentNode = pcNode;
|
nuclear@0
|
664 break;
|
nuclear@0
|
665 }
|
nuclear@0
|
666 pcNode = new D3DS::Node();
|
nuclear@0
|
667 pcNode->mName = name;
|
nuclear@0
|
668
|
nuclear@0
|
669 // There are two unknown values which we can safely ignore
|
nuclear@0
|
670 stream->IncPtr(4);
|
nuclear@0
|
671
|
nuclear@0
|
672 // Now read the hierarchy position of the object
|
nuclear@0
|
673 uint16_t hierarchy = stream->GetI2() + 1;
|
nuclear@0
|
674 pcNode->mHierarchyPos = hierarchy;
|
nuclear@0
|
675 pcNode->mHierarchyIndex = mLastNodeIndex;
|
nuclear@0
|
676
|
nuclear@0
|
677 // And find a proper position in the graph for it
|
nuclear@0
|
678 if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) {
|
nuclear@0
|
679
|
nuclear@0
|
680 // add to the parent of the last touched node
|
nuclear@0
|
681 mCurrentNode->mParent->push_back(pcNode);
|
nuclear@0
|
682 mLastNodeIndex++;
|
nuclear@0
|
683 }
|
nuclear@0
|
684 else if(hierarchy >= mLastNodeIndex) {
|
nuclear@0
|
685
|
nuclear@0
|
686 // place it at the current position in the hierarchy
|
nuclear@0
|
687 mCurrentNode->push_back(pcNode);
|
nuclear@0
|
688 mLastNodeIndex = hierarchy;
|
nuclear@0
|
689 }
|
nuclear@0
|
690 else {
|
nuclear@0
|
691 // need to go back to the specified position in the hierarchy.
|
nuclear@0
|
692 InverseNodeSearch(pcNode,mCurrentNode);
|
nuclear@0
|
693 mLastNodeIndex++;
|
nuclear@0
|
694 }
|
nuclear@0
|
695 // Make this node the current node
|
nuclear@0
|
696 mCurrentNode = pcNode;
|
nuclear@0
|
697 }
|
nuclear@0
|
698 break;
|
nuclear@0
|
699
|
nuclear@0
|
700 case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME:
|
nuclear@0
|
701
|
nuclear@0
|
702 // This is the "real" name of a $$$DUMMY object
|
nuclear@0
|
703 {
|
nuclear@0
|
704 const char* sz = (const char*) stream->GetPtr();
|
nuclear@0
|
705 while (stream->GetI1());
|
nuclear@0
|
706
|
nuclear@0
|
707 // If object name is DUMMY, take this one instead
|
nuclear@0
|
708 if (mCurrentNode->mName == "$$$DUMMY") {
|
nuclear@0
|
709 //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object");
|
nuclear@0
|
710 mCurrentNode->mName = std::string(sz);
|
nuclear@0
|
711 break;
|
nuclear@0
|
712 }
|
nuclear@0
|
713 }
|
nuclear@0
|
714 break;
|
nuclear@0
|
715
|
nuclear@0
|
716 case Discreet3DS::CHUNK_TRACKPIVOT:
|
nuclear@0
|
717
|
nuclear@0
|
718 if ( Discreet3DS::CHUNK_TRACKINFO != parent)
|
nuclear@0
|
719 {
|
nuclear@0
|
720 DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object");
|
nuclear@0
|
721 break;
|
nuclear@0
|
722 }
|
nuclear@0
|
723
|
nuclear@0
|
724 // Pivot = origin of rotation and scaling
|
nuclear@0
|
725 mCurrentNode->vPivot.x = stream->GetF4();
|
nuclear@0
|
726 mCurrentNode->vPivot.y = stream->GetF4();
|
nuclear@0
|
727 mCurrentNode->vPivot.z = stream->GetF4();
|
nuclear@0
|
728 break;
|
nuclear@0
|
729
|
nuclear@0
|
730
|
nuclear@0
|
731 // ////////////////////////////////////////////////////////////////////
|
nuclear@0
|
732 // POSITION KEYFRAME
|
nuclear@0
|
733 case Discreet3DS::CHUNK_TRACKPOS:
|
nuclear@0
|
734 {
|
nuclear@0
|
735 stream->IncPtr(10);
|
nuclear@0
|
736 const unsigned int numFrames = stream->GetI4();
|
nuclear@0
|
737 bool sortKeys = false;
|
nuclear@0
|
738
|
nuclear@0
|
739 // This could also be meant as the target position for
|
nuclear@0
|
740 // (targeted) lights and cameras
|
nuclear@0
|
741 std::vector<aiVectorKey>* l;
|
nuclear@0
|
742 if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) {
|
nuclear@0
|
743 l = & mCurrentNode->aTargetPositionKeys;
|
nuclear@0
|
744 }
|
nuclear@0
|
745 else l = & mCurrentNode->aPositionKeys;
|
nuclear@0
|
746
|
nuclear@0
|
747 l->reserve(numFrames);
|
nuclear@0
|
748 for (unsigned int i = 0; i < numFrames;++i) {
|
nuclear@0
|
749 const unsigned int fidx = stream->GetI4();
|
nuclear@0
|
750
|
nuclear@0
|
751 // Setup a new position key
|
nuclear@0
|
752 aiVectorKey v;
|
nuclear@0
|
753 v.mTime = (double)fidx;
|
nuclear@0
|
754
|
nuclear@0
|
755 SkipTCBInfo();
|
nuclear@0
|
756 v.mValue.x = stream->GetF4();
|
nuclear@0
|
757 v.mValue.y = stream->GetF4();
|
nuclear@0
|
758 v.mValue.z = stream->GetF4();
|
nuclear@0
|
759
|
nuclear@0
|
760 // check whether we'll need to sort the keys
|
nuclear@0
|
761 if (!l->empty() && v.mTime <= l->back().mTime)
|
nuclear@0
|
762 sortKeys = true;
|
nuclear@0
|
763
|
nuclear@0
|
764 // Add the new keyframe to the list
|
nuclear@0
|
765 l->push_back(v);
|
nuclear@0
|
766 }
|
nuclear@0
|
767
|
nuclear@0
|
768 // Sort all keys with ascending time values and remove duplicates?
|
nuclear@0
|
769 if (sortKeys) {
|
nuclear@0
|
770 std::stable_sort(l->begin(),l->end());
|
nuclear@0
|
771 l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
|
nuclear@0
|
772 }}
|
nuclear@0
|
773
|
nuclear@0
|
774 break;
|
nuclear@0
|
775
|
nuclear@0
|
776 // ////////////////////////////////////////////////////////////////////
|
nuclear@0
|
777 // CAMERA ROLL KEYFRAME
|
nuclear@0
|
778 case Discreet3DS::CHUNK_TRACKROLL:
|
nuclear@0
|
779 {
|
nuclear@0
|
780 // roll keys are accepted for cameras only
|
nuclear@0
|
781 if (parent != Discreet3DS::CHUNK_TRACKCAMERA) {
|
nuclear@0
|
782 DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object");
|
nuclear@0
|
783 break;
|
nuclear@0
|
784 }
|
nuclear@0
|
785 bool sortKeys = false;
|
nuclear@0
|
786 std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys;
|
nuclear@0
|
787
|
nuclear@0
|
788 stream->IncPtr(10);
|
nuclear@0
|
789 const unsigned int numFrames = stream->GetI4();
|
nuclear@0
|
790 l->reserve(numFrames);
|
nuclear@0
|
791 for (unsigned int i = 0; i < numFrames;++i) {
|
nuclear@0
|
792 const unsigned int fidx = stream->GetI4();
|
nuclear@0
|
793
|
nuclear@0
|
794 // Setup a new position key
|
nuclear@0
|
795 aiFloatKey v;
|
nuclear@0
|
796 v.mTime = (double)fidx;
|
nuclear@0
|
797
|
nuclear@0
|
798 // This is just a single float
|
nuclear@0
|
799 SkipTCBInfo();
|
nuclear@0
|
800 v.mValue = stream->GetF4();
|
nuclear@0
|
801
|
nuclear@0
|
802 // Check whether we'll need to sort the keys
|
nuclear@0
|
803 if (!l->empty() && v.mTime <= l->back().mTime)
|
nuclear@0
|
804 sortKeys = true;
|
nuclear@0
|
805
|
nuclear@0
|
806 // Add the new keyframe to the list
|
nuclear@0
|
807 l->push_back(v);
|
nuclear@0
|
808 }
|
nuclear@0
|
809
|
nuclear@0
|
810 // Sort all keys with ascending time values and remove duplicates?
|
nuclear@0
|
811 if (sortKeys) {
|
nuclear@0
|
812 std::stable_sort(l->begin(),l->end());
|
nuclear@0
|
813 l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiFloatKey>), l->end() );
|
nuclear@0
|
814 }}
|
nuclear@0
|
815 break;
|
nuclear@0
|
816
|
nuclear@0
|
817
|
nuclear@0
|
818 // ////////////////////////////////////////////////////////////////////
|
nuclear@0
|
819 // CAMERA FOV KEYFRAME
|
nuclear@0
|
820 case Discreet3DS::CHUNK_TRACKFOV:
|
nuclear@0
|
821 {
|
nuclear@0
|
822 DefaultLogger::get()->error("3DS: Skipping FOV animation track. "
|
nuclear@0
|
823 "This is not supported");
|
nuclear@0
|
824 }
|
nuclear@0
|
825 break;
|
nuclear@0
|
826
|
nuclear@0
|
827
|
nuclear@0
|
828 // ////////////////////////////////////////////////////////////////////
|
nuclear@0
|
829 // ROTATION KEYFRAME
|
nuclear@0
|
830 case Discreet3DS::CHUNK_TRACKROTATE:
|
nuclear@0
|
831 {
|
nuclear@0
|
832 stream->IncPtr(10);
|
nuclear@0
|
833 const unsigned int numFrames = stream->GetI4();
|
nuclear@0
|
834
|
nuclear@0
|
835 bool sortKeys = false;
|
nuclear@0
|
836 std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
|
nuclear@0
|
837 l->reserve(numFrames);
|
nuclear@0
|
838
|
nuclear@0
|
839 for (unsigned int i = 0; i < numFrames;++i) {
|
nuclear@0
|
840 const unsigned int fidx = stream->GetI4();
|
nuclear@0
|
841 SkipTCBInfo();
|
nuclear@0
|
842
|
nuclear@0
|
843 aiQuatKey v;
|
nuclear@0
|
844 v.mTime = (double)fidx;
|
nuclear@0
|
845
|
nuclear@0
|
846 // The rotation keyframe is given as an axis-angle pair
|
nuclear@0
|
847 const float rad = stream->GetF4();
|
nuclear@0
|
848 aiVector3D axis;
|
nuclear@0
|
849 axis.x = stream->GetF4();
|
nuclear@0
|
850 axis.y = stream->GetF4();
|
nuclear@0
|
851 axis.z = stream->GetF4();
|
nuclear@0
|
852
|
nuclear@0
|
853 if (!axis.x && !axis.y && !axis.z)
|
nuclear@0
|
854 axis.y = 1.f;
|
nuclear@0
|
855
|
nuclear@0
|
856 // Construct a rotation quaternion from the axis-angle pair
|
nuclear@0
|
857 v.mValue = aiQuaternion(axis,rad);
|
nuclear@0
|
858
|
nuclear@0
|
859 // Check whether we'll need to sort the keys
|
nuclear@0
|
860 if (!l->empty() && v.mTime <= l->back().mTime)
|
nuclear@0
|
861 sortKeys = true;
|
nuclear@0
|
862
|
nuclear@0
|
863 // add the new keyframe to the list
|
nuclear@0
|
864 l->push_back(v);
|
nuclear@0
|
865 }
|
nuclear@0
|
866 // Sort all keys with ascending time values and remove duplicates?
|
nuclear@0
|
867 if (sortKeys) {
|
nuclear@0
|
868 std::stable_sort(l->begin(),l->end());
|
nuclear@0
|
869 l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiQuatKey>), l->end() );
|
nuclear@0
|
870 }}
|
nuclear@0
|
871 break;
|
nuclear@0
|
872
|
nuclear@0
|
873 // ////////////////////////////////////////////////////////////////////
|
nuclear@0
|
874 // SCALING KEYFRAME
|
nuclear@0
|
875 case Discreet3DS::CHUNK_TRACKSCALE:
|
nuclear@0
|
876 {
|
nuclear@0
|
877 stream->IncPtr(10);
|
nuclear@0
|
878 const unsigned int numFrames = stream->GetI2();
|
nuclear@0
|
879 stream->IncPtr(2);
|
nuclear@0
|
880
|
nuclear@0
|
881 bool sortKeys = false;
|
nuclear@0
|
882 std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
|
nuclear@0
|
883 l->reserve(numFrames);
|
nuclear@0
|
884
|
nuclear@0
|
885 for (unsigned int i = 0; i < numFrames;++i) {
|
nuclear@0
|
886 const unsigned int fidx = stream->GetI4();
|
nuclear@0
|
887 SkipTCBInfo();
|
nuclear@0
|
888
|
nuclear@0
|
889 // Setup a new key
|
nuclear@0
|
890 aiVectorKey v;
|
nuclear@0
|
891 v.mTime = (double)fidx;
|
nuclear@0
|
892
|
nuclear@0
|
893 // ... and read its value
|
nuclear@0
|
894 v.mValue.x = stream->GetF4();
|
nuclear@0
|
895 v.mValue.y = stream->GetF4();
|
nuclear@0
|
896 v.mValue.z = stream->GetF4();
|
nuclear@0
|
897
|
nuclear@0
|
898 // check whether we'll need to sort the keys
|
nuclear@0
|
899 if (!l->empty() && v.mTime <= l->back().mTime)
|
nuclear@0
|
900 sortKeys = true;
|
nuclear@0
|
901
|
nuclear@0
|
902 // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files
|
nuclear@0
|
903 if (!v.mValue.x) v.mValue.x = 1.f;
|
nuclear@0
|
904 if (!v.mValue.y) v.mValue.y = 1.f;
|
nuclear@0
|
905 if (!v.mValue.z) v.mValue.z = 1.f;
|
nuclear@0
|
906
|
nuclear@0
|
907 l->push_back(v);
|
nuclear@0
|
908 }
|
nuclear@0
|
909 // Sort all keys with ascending time values and remove duplicates?
|
nuclear@0
|
910 if (sortKeys) {
|
nuclear@0
|
911 std::stable_sort(l->begin(),l->end());
|
nuclear@0
|
912 l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
|
nuclear@0
|
913 }}
|
nuclear@0
|
914 break;
|
nuclear@0
|
915 };
|
nuclear@0
|
916
|
nuclear@0
|
917 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
918 }
|
nuclear@0
|
919
|
nuclear@0
|
920 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
921 // Read a face chunk - it contains smoothing groups and material assignments
|
nuclear@0
|
922 void Discreet3DSImporter::ParseFaceChunk()
|
nuclear@0
|
923 {
|
nuclear@0
|
924 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
925
|
nuclear@0
|
926 // Get the mesh we're currently working on
|
nuclear@0
|
927 D3DS::Mesh& mMesh = mScene->mMeshes.back();
|
nuclear@0
|
928
|
nuclear@0
|
929 // Get chunk type
|
nuclear@0
|
930 switch (chunk.Flag)
|
nuclear@0
|
931 {
|
nuclear@0
|
932 case Discreet3DS::CHUNK_SMOOLIST:
|
nuclear@0
|
933 {
|
nuclear@0
|
934 // This is the list of smoothing groups - a bitfield for every face.
|
nuclear@0
|
935 // Up to 32 smoothing groups assigned to a single face.
|
nuclear@0
|
936 unsigned int num = chunkSize/4, m = 0;
|
nuclear@0
|
937 for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin(); m != num;++i, ++m) {
|
nuclear@0
|
938 // nth bit is set for nth smoothing group
|
nuclear@0
|
939 (*i).iSmoothGroup = stream->GetI4();
|
nuclear@0
|
940 }}
|
nuclear@0
|
941 break;
|
nuclear@0
|
942
|
nuclear@0
|
943 case Discreet3DS::CHUNK_FACEMAT:
|
nuclear@0
|
944 {
|
nuclear@0
|
945 // at fist an asciiz with the material name
|
nuclear@0
|
946 const char* sz = (const char*)stream->GetPtr();
|
nuclear@0
|
947 while (stream->GetI1());
|
nuclear@0
|
948
|
nuclear@0
|
949 // find the index of the material
|
nuclear@0
|
950 unsigned int idx = 0xcdcdcdcd, cnt = 0;
|
nuclear@0
|
951 for (std::vector<D3DS::Material>::const_iterator i = mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt) {
|
nuclear@0
|
952 // use case independent comparisons. hopefully it will work.
|
nuclear@0
|
953 if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) {
|
nuclear@0
|
954 idx = cnt;
|
nuclear@0
|
955 break;
|
nuclear@0
|
956 }
|
nuclear@0
|
957 }
|
nuclear@0
|
958 if (0xcdcdcdcd == idx) {
|
nuclear@0
|
959 DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz);
|
nuclear@0
|
960 }
|
nuclear@0
|
961
|
nuclear@0
|
962 // Now continue and read all material indices
|
nuclear@0
|
963 cnt = (uint16_t)stream->GetI2();
|
nuclear@0
|
964 for (unsigned int i = 0; i < cnt;++i) {
|
nuclear@0
|
965 unsigned int fidx = (uint16_t)stream->GetI2();
|
nuclear@0
|
966
|
nuclear@0
|
967 // check range
|
nuclear@0
|
968 if (fidx >= mMesh.mFaceMaterials.size()) {
|
nuclear@0
|
969 DefaultLogger::get()->error("3DS: Invalid face index in face material list");
|
nuclear@0
|
970 }
|
nuclear@0
|
971 else mMesh.mFaceMaterials[fidx] = idx;
|
nuclear@0
|
972 }}
|
nuclear@0
|
973 break;
|
nuclear@0
|
974 };
|
nuclear@0
|
975 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
976 }
|
nuclear@0
|
977
|
nuclear@0
|
978 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
979 // Read a mesh chunk. Here's the actual mesh data
|
nuclear@0
|
980 void Discreet3DSImporter::ParseMeshChunk()
|
nuclear@0
|
981 {
|
nuclear@0
|
982 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
983
|
nuclear@0
|
984 // Get the mesh we're currently working on
|
nuclear@0
|
985 D3DS::Mesh& mMesh = mScene->mMeshes.back();
|
nuclear@0
|
986
|
nuclear@0
|
987 // get chunk type
|
nuclear@0
|
988 switch (chunk.Flag)
|
nuclear@0
|
989 {
|
nuclear@0
|
990 case Discreet3DS::CHUNK_VERTLIST:
|
nuclear@0
|
991 {
|
nuclear@0
|
992 // This is the list of all vertices in the current mesh
|
nuclear@0
|
993 int num = (int)(uint16_t)stream->GetI2();
|
nuclear@0
|
994 mMesh.mPositions.reserve(num);
|
nuclear@0
|
995 while (num-- > 0) {
|
nuclear@0
|
996 aiVector3D v;
|
nuclear@0
|
997 v.x = stream->GetF4();
|
nuclear@0
|
998 v.y = stream->GetF4();
|
nuclear@0
|
999 v.z = stream->GetF4();
|
nuclear@0
|
1000 mMesh.mPositions.push_back(v);
|
nuclear@0
|
1001 }}
|
nuclear@0
|
1002 break;
|
nuclear@0
|
1003 case Discreet3DS::CHUNK_TRMATRIX:
|
nuclear@0
|
1004 {
|
nuclear@0
|
1005 // This is the RLEATIVE transformation matrix of the current mesh. Vertices are
|
nuclear@0
|
1006 // pretransformed by this matrix wonder.
|
nuclear@0
|
1007 mMesh.mMat.a1 = stream->GetF4();
|
nuclear@0
|
1008 mMesh.mMat.b1 = stream->GetF4();
|
nuclear@0
|
1009 mMesh.mMat.c1 = stream->GetF4();
|
nuclear@0
|
1010 mMesh.mMat.a2 = stream->GetF4();
|
nuclear@0
|
1011 mMesh.mMat.b2 = stream->GetF4();
|
nuclear@0
|
1012 mMesh.mMat.c2 = stream->GetF4();
|
nuclear@0
|
1013 mMesh.mMat.a3 = stream->GetF4();
|
nuclear@0
|
1014 mMesh.mMat.b3 = stream->GetF4();
|
nuclear@0
|
1015 mMesh.mMat.c3 = stream->GetF4();
|
nuclear@0
|
1016 mMesh.mMat.a4 = stream->GetF4();
|
nuclear@0
|
1017 mMesh.mMat.b4 = stream->GetF4();
|
nuclear@0
|
1018 mMesh.mMat.c4 = stream->GetF4();
|
nuclear@0
|
1019 }
|
nuclear@0
|
1020 break;
|
nuclear@0
|
1021
|
nuclear@0
|
1022 case Discreet3DS::CHUNK_MAPLIST:
|
nuclear@0
|
1023 {
|
nuclear@0
|
1024 // This is the list of all UV coords in the current mesh
|
nuclear@0
|
1025 int num = (int)(uint16_t)stream->GetI2();
|
nuclear@0
|
1026 mMesh.mTexCoords.reserve(num);
|
nuclear@0
|
1027 while (num-- > 0) {
|
nuclear@0
|
1028 aiVector3D v;
|
nuclear@0
|
1029 v.x = stream->GetF4();
|
nuclear@0
|
1030 v.y = stream->GetF4();
|
nuclear@0
|
1031 mMesh.mTexCoords.push_back(v);
|
nuclear@0
|
1032 }}
|
nuclear@0
|
1033 break;
|
nuclear@0
|
1034
|
nuclear@0
|
1035 case Discreet3DS::CHUNK_FACELIST:
|
nuclear@0
|
1036 {
|
nuclear@0
|
1037 // This is the list of all faces in the current mesh
|
nuclear@0
|
1038 int num = (int)(uint16_t)stream->GetI2();
|
nuclear@0
|
1039 mMesh.mFaces.reserve(num);
|
nuclear@0
|
1040 while (num-- > 0) {
|
nuclear@0
|
1041 // 3DS faces are ALWAYS triangles
|
nuclear@0
|
1042 mMesh.mFaces.push_back(D3DS::Face());
|
nuclear@0
|
1043 D3DS::Face& sFace = mMesh.mFaces.back();
|
nuclear@0
|
1044
|
nuclear@0
|
1045 sFace.mIndices[0] = (uint16_t)stream->GetI2();
|
nuclear@0
|
1046 sFace.mIndices[1] = (uint16_t)stream->GetI2();
|
nuclear@0
|
1047 sFace.mIndices[2] = (uint16_t)stream->GetI2();
|
nuclear@0
|
1048
|
nuclear@0
|
1049 stream->IncPtr(2); // skip edge visibility flag
|
nuclear@0
|
1050 }
|
nuclear@0
|
1051
|
nuclear@0
|
1052 // Resize the material array (0xcdcdcdcd marks the default material; so if a face is
|
nuclear@0
|
1053 // not referenced by a material, $$DEFAULT will be assigned to it)
|
nuclear@0
|
1054 mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd);
|
nuclear@0
|
1055
|
nuclear@0
|
1056 // Larger 3DS files could have multiple FACE chunks here
|
nuclear@0
|
1057 chunkSize = stream->GetRemainingSizeToLimit();
|
nuclear@0
|
1058 if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) )
|
nuclear@0
|
1059 ParseFaceChunk();
|
nuclear@0
|
1060 }
|
nuclear@0
|
1061 break;
|
nuclear@0
|
1062 };
|
nuclear@0
|
1063 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
1064 }
|
nuclear@0
|
1065
|
nuclear@0
|
1066 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1067 // Read a 3DS material chunk
|
nuclear@0
|
1068 void Discreet3DSImporter::ParseMaterialChunk()
|
nuclear@0
|
1069 {
|
nuclear@0
|
1070 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
1071 switch (chunk.Flag)
|
nuclear@0
|
1072 {
|
nuclear@0
|
1073 case Discreet3DS::CHUNK_MAT_MATNAME:
|
nuclear@0
|
1074
|
nuclear@0
|
1075 {
|
nuclear@0
|
1076 // The material name string is already zero-terminated, but we need to be sure ...
|
nuclear@0
|
1077 const char* sz = (const char*)stream->GetPtr();
|
nuclear@0
|
1078 unsigned int cnt = 0;
|
nuclear@0
|
1079 while (stream->GetI1())
|
nuclear@0
|
1080 ++cnt;
|
nuclear@0
|
1081
|
nuclear@0
|
1082 if (!cnt) {
|
nuclear@0
|
1083 // This may not be, we use the default name instead
|
nuclear@0
|
1084 DefaultLogger::get()->error("3DS: Empty material name");
|
nuclear@0
|
1085 }
|
nuclear@0
|
1086 else mScene->mMaterials.back().mName = std::string(sz,cnt);
|
nuclear@0
|
1087 }
|
nuclear@0
|
1088 break;
|
nuclear@0
|
1089
|
nuclear@0
|
1090 case Discreet3DS::CHUNK_MAT_DIFFUSE:
|
nuclear@0
|
1091 {
|
nuclear@0
|
1092 // This is the diffuse material color
|
nuclear@0
|
1093 aiColor3D* pc = &mScene->mMaterials.back().mDiffuse;
|
nuclear@0
|
1094 ParseColorChunk(pc);
|
nuclear@0
|
1095 if (is_qnan(pc->r)) {
|
nuclear@0
|
1096 // color chunk is invalid. Simply ignore it
|
nuclear@0
|
1097 DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk");
|
nuclear@0
|
1098 pc->r = pc->g = pc->b = 1.0f;
|
nuclear@0
|
1099 }}
|
nuclear@0
|
1100 break;
|
nuclear@0
|
1101
|
nuclear@0
|
1102 case Discreet3DS::CHUNK_MAT_SPECULAR:
|
nuclear@0
|
1103 {
|
nuclear@0
|
1104 // This is the specular material color
|
nuclear@0
|
1105 aiColor3D* pc = &mScene->mMaterials.back().mSpecular;
|
nuclear@0
|
1106 ParseColorChunk(pc);
|
nuclear@0
|
1107 if (is_qnan(pc->r)) {
|
nuclear@0
|
1108 // color chunk is invalid. Simply ignore it
|
nuclear@0
|
1109 DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk");
|
nuclear@0
|
1110 pc->r = pc->g = pc->b = 1.0f;
|
nuclear@0
|
1111 }}
|
nuclear@0
|
1112 break;
|
nuclear@0
|
1113
|
nuclear@0
|
1114 case Discreet3DS::CHUNK_MAT_AMBIENT:
|
nuclear@0
|
1115 {
|
nuclear@0
|
1116 // This is the ambient material color
|
nuclear@0
|
1117 aiColor3D* pc = &mScene->mMaterials.back().mAmbient;
|
nuclear@0
|
1118 ParseColorChunk(pc);
|
nuclear@0
|
1119 if (is_qnan(pc->r)) {
|
nuclear@0
|
1120 // color chunk is invalid. Simply ignore it
|
nuclear@0
|
1121 DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk");
|
nuclear@0
|
1122 pc->r = pc->g = pc->b = 0.0f;
|
nuclear@0
|
1123 }}
|
nuclear@0
|
1124 break;
|
nuclear@0
|
1125
|
nuclear@0
|
1126 case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
|
nuclear@0
|
1127 {
|
nuclear@0
|
1128 // This is the emissive material color
|
nuclear@0
|
1129 aiColor3D* pc = &mScene->mMaterials.back().mEmissive;
|
nuclear@0
|
1130 ParseColorChunk(pc);
|
nuclear@0
|
1131 if (is_qnan(pc->r)) {
|
nuclear@0
|
1132 // color chunk is invalid. Simply ignore it
|
nuclear@0
|
1133 DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk");
|
nuclear@0
|
1134 pc->r = pc->g = pc->b = 0.0f;
|
nuclear@0
|
1135 }}
|
nuclear@0
|
1136 break;
|
nuclear@0
|
1137
|
nuclear@0
|
1138 case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
|
nuclear@0
|
1139 {
|
nuclear@0
|
1140 // This is the material's transparency
|
nuclear@0
|
1141 float* pcf = &mScene->mMaterials.back().mTransparency;
|
nuclear@0
|
1142 *pcf = ParsePercentageChunk();
|
nuclear@0
|
1143
|
nuclear@0
|
1144 // NOTE: transparency, not opacity
|
nuclear@0
|
1145 if (is_qnan(*pcf))
|
nuclear@0
|
1146 *pcf = 1.0f;
|
nuclear@0
|
1147 else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
|
nuclear@0
|
1148 }
|
nuclear@0
|
1149 break;
|
nuclear@0
|
1150
|
nuclear@0
|
1151 case Discreet3DS::CHUNK_MAT_SHADING:
|
nuclear@0
|
1152 // This is the material shading mode
|
nuclear@0
|
1153 mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2();
|
nuclear@0
|
1154 break;
|
nuclear@0
|
1155
|
nuclear@0
|
1156 case Discreet3DS::CHUNK_MAT_TWO_SIDE:
|
nuclear@0
|
1157 // This is the two-sided flag
|
nuclear@0
|
1158 mScene->mMaterials.back().mTwoSided = true;
|
nuclear@0
|
1159 break;
|
nuclear@0
|
1160
|
nuclear@0
|
1161 case Discreet3DS::CHUNK_MAT_SHININESS:
|
nuclear@0
|
1162 { // This is the shininess of the material
|
nuclear@0
|
1163 float* pcf = &mScene->mMaterials.back().mSpecularExponent;
|
nuclear@0
|
1164 *pcf = ParsePercentageChunk();
|
nuclear@0
|
1165 if (is_qnan(*pcf))
|
nuclear@0
|
1166 *pcf = 0.0f;
|
nuclear@0
|
1167 else *pcf *= (float)0xFFFF;
|
nuclear@0
|
1168 }
|
nuclear@0
|
1169 break;
|
nuclear@0
|
1170
|
nuclear@0
|
1171 case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
|
nuclear@0
|
1172 { // This is the shininess strength of the material
|
nuclear@0
|
1173 float* pcf = &mScene->mMaterials.back().mShininessStrength;
|
nuclear@0
|
1174 *pcf = ParsePercentageChunk();
|
nuclear@0
|
1175 if (is_qnan(*pcf))
|
nuclear@0
|
1176 *pcf = 0.0f;
|
nuclear@0
|
1177 else *pcf *= (float)0xffff / 100.0f;
|
nuclear@0
|
1178 }
|
nuclear@0
|
1179 break;
|
nuclear@0
|
1180
|
nuclear@0
|
1181 case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
|
nuclear@0
|
1182 { // This is the self illumination strength of the material
|
nuclear@0
|
1183 float f = ParsePercentageChunk();
|
nuclear@0
|
1184 if (is_qnan(f))
|
nuclear@0
|
1185 f = 0.0f;
|
nuclear@0
|
1186 else f *= (float)0xFFFF / 100.0f;
|
nuclear@0
|
1187 mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f);
|
nuclear@0
|
1188 }
|
nuclear@0
|
1189 break;
|
nuclear@0
|
1190
|
nuclear@0
|
1191 // Parse texture chunks
|
nuclear@0
|
1192 case Discreet3DS::CHUNK_MAT_TEXTURE:
|
nuclear@0
|
1193 // Diffuse texture
|
nuclear@0
|
1194 ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse);
|
nuclear@0
|
1195 break;
|
nuclear@0
|
1196 case Discreet3DS::CHUNK_MAT_BUMPMAP:
|
nuclear@0
|
1197 // Height map
|
nuclear@0
|
1198 ParseTextureChunk(&mScene->mMaterials.back().sTexBump);
|
nuclear@0
|
1199 break;
|
nuclear@0
|
1200 case Discreet3DS::CHUNK_MAT_OPACMAP:
|
nuclear@0
|
1201 // Opacity texture
|
nuclear@0
|
1202 ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity);
|
nuclear@0
|
1203 break;
|
nuclear@0
|
1204 case Discreet3DS::CHUNK_MAT_MAT_SHINMAP:
|
nuclear@0
|
1205 // Shininess map
|
nuclear@0
|
1206 ParseTextureChunk(&mScene->mMaterials.back().sTexShininess);
|
nuclear@0
|
1207 break;
|
nuclear@0
|
1208 case Discreet3DS::CHUNK_MAT_SPECMAP:
|
nuclear@0
|
1209 // Specular map
|
nuclear@0
|
1210 ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular);
|
nuclear@0
|
1211 break;
|
nuclear@0
|
1212 case Discreet3DS::CHUNK_MAT_SELFIMAP:
|
nuclear@0
|
1213 // Self-illumination (emissive) map
|
nuclear@0
|
1214 ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive);
|
nuclear@0
|
1215 break;
|
nuclear@0
|
1216 case Discreet3DS::CHUNK_MAT_REFLMAP:
|
nuclear@0
|
1217 // Reflection map
|
nuclear@0
|
1218 ParseTextureChunk(&mScene->mMaterials.back().sTexReflective);
|
nuclear@0
|
1219 break;
|
nuclear@0
|
1220 };
|
nuclear@0
|
1221 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
1222 }
|
nuclear@0
|
1223
|
nuclear@0
|
1224 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1225 void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
nuclear@0
|
1226 {
|
nuclear@0
|
1227 ASSIMP_3DS_BEGIN_CHUNK();
|
nuclear@0
|
1228
|
nuclear@0
|
1229 // get chunk type
|
nuclear@0
|
1230 switch (chunk.Flag)
|
nuclear@0
|
1231 {
|
nuclear@0
|
1232 case Discreet3DS::CHUNK_MAPFILE:
|
nuclear@0
|
1233 {
|
nuclear@0
|
1234 // The material name string is already zero-terminated, but we need to be sure ...
|
nuclear@0
|
1235 const char* sz = (const char*)stream->GetPtr();
|
nuclear@0
|
1236 unsigned int cnt = 0;
|
nuclear@0
|
1237 while (stream->GetI1())
|
nuclear@0
|
1238 ++cnt;
|
nuclear@0
|
1239 pcOut->mMapName = std::string(sz,cnt);
|
nuclear@0
|
1240 }
|
nuclear@0
|
1241 break;
|
nuclear@0
|
1242
|
nuclear@0
|
1243
|
nuclear@0
|
1244 case Discreet3DS::CHUNK_PERCENTF:
|
nuclear@0
|
1245 // Manually parse the blend factor
|
nuclear@0
|
1246 pcOut->mTextureBlend = stream->GetF4();
|
nuclear@0
|
1247 break;
|
nuclear@0
|
1248
|
nuclear@0
|
1249 case Discreet3DS::CHUNK_PERCENTW:
|
nuclear@0
|
1250 // Manually parse the blend factor
|
nuclear@0
|
1251 pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f;
|
nuclear@0
|
1252 break;
|
nuclear@0
|
1253
|
nuclear@0
|
1254 case Discreet3DS::CHUNK_MAT_MAP_USCALE:
|
nuclear@0
|
1255 // Texture coordinate scaling in the U direction
|
nuclear@0
|
1256 pcOut->mScaleU = stream->GetF4();
|
nuclear@0
|
1257 if (0.0f == pcOut->mScaleU)
|
nuclear@0
|
1258 {
|
nuclear@0
|
1259 DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1.");
|
nuclear@0
|
1260 pcOut->mScaleU = 1.0f;
|
nuclear@0
|
1261 }
|
nuclear@0
|
1262 break;
|
nuclear@0
|
1263 case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
|
nuclear@0
|
1264 // Texture coordinate scaling in the V direction
|
nuclear@0
|
1265 pcOut->mScaleV = stream->GetF4();
|
nuclear@0
|
1266 if (0.0f == pcOut->mScaleV)
|
nuclear@0
|
1267 {
|
nuclear@0
|
1268 DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1.");
|
nuclear@0
|
1269 pcOut->mScaleV = 1.0f;
|
nuclear@0
|
1270 }
|
nuclear@0
|
1271 break;
|
nuclear@0
|
1272
|
nuclear@0
|
1273 case Discreet3DS::CHUNK_MAT_MAP_UOFFSET:
|
nuclear@0
|
1274 // Texture coordinate offset in the U direction
|
nuclear@0
|
1275 pcOut->mOffsetU = -stream->GetF4();
|
nuclear@0
|
1276 break;
|
nuclear@0
|
1277
|
nuclear@0
|
1278 case Discreet3DS::CHUNK_MAT_MAP_VOFFSET:
|
nuclear@0
|
1279 // Texture coordinate offset in the V direction
|
nuclear@0
|
1280 pcOut->mOffsetV = stream->GetF4();
|
nuclear@0
|
1281 break;
|
nuclear@0
|
1282
|
nuclear@0
|
1283 case Discreet3DS::CHUNK_MAT_MAP_ANG:
|
nuclear@0
|
1284 // Texture coordinate rotation, CCW in DEGREES
|
nuclear@0
|
1285 pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() );
|
nuclear@0
|
1286 break;
|
nuclear@0
|
1287
|
nuclear@0
|
1288 case Discreet3DS::CHUNK_MAT_MAP_TILING:
|
nuclear@0
|
1289 {
|
nuclear@0
|
1290 const uint16_t iFlags = stream->GetI2();
|
nuclear@0
|
1291
|
nuclear@0
|
1292 // Get the mapping mode (for both axes)
|
nuclear@0
|
1293 if (iFlags & 0x2u)
|
nuclear@0
|
1294 pcOut->mMapMode = aiTextureMapMode_Mirror;
|
nuclear@0
|
1295
|
nuclear@0
|
1296 else if (iFlags & 0x10u)
|
nuclear@0
|
1297 pcOut->mMapMode = aiTextureMapMode_Decal;
|
nuclear@0
|
1298
|
nuclear@0
|
1299 // wrapping in all remaining cases
|
nuclear@0
|
1300 else pcOut->mMapMode = aiTextureMapMode_Wrap;
|
nuclear@0
|
1301 }
|
nuclear@0
|
1302 break;
|
nuclear@0
|
1303 };
|
nuclear@0
|
1304
|
nuclear@0
|
1305 ASSIMP_3DS_END_CHUNK();
|
nuclear@0
|
1306 }
|
nuclear@0
|
1307
|
nuclear@0
|
1308 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1309 // Read a percentage chunk
|
nuclear@0
|
1310 float Discreet3DSImporter::ParsePercentageChunk()
|
nuclear@0
|
1311 {
|
nuclear@0
|
1312 Discreet3DS::Chunk chunk;
|
nuclear@0
|
1313 ReadChunk(&chunk);
|
nuclear@0
|
1314
|
nuclear@0
|
1315 if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag)
|
nuclear@0
|
1316 return stream->GetF4();
|
nuclear@0
|
1317 else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag)
|
nuclear@0
|
1318 return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF;
|
nuclear@0
|
1319 return get_qnan();
|
nuclear@0
|
1320 }
|
nuclear@0
|
1321
|
nuclear@0
|
1322 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1323 // Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color
|
nuclear@0
|
1324 void Discreet3DSImporter::ParseColorChunk(aiColor3D* out,
|
nuclear@0
|
1325 bool acceptPercent)
|
nuclear@0
|
1326 {
|
nuclear@0
|
1327 ai_assert(out != NULL);
|
nuclear@0
|
1328
|
nuclear@0
|
1329 // error return value
|
nuclear@0
|
1330 const float qnan = get_qnan();
|
nuclear@0
|
1331 static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan);
|
nuclear@0
|
1332
|
nuclear@0
|
1333 Discreet3DS::Chunk chunk;
|
nuclear@0
|
1334 ReadChunk(&chunk);
|
nuclear@0
|
1335 const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk);
|
nuclear@0
|
1336
|
nuclear@0
|
1337 bool bGamma = false;
|
nuclear@0
|
1338
|
nuclear@0
|
1339 // Get the type of the chunk
|
nuclear@0
|
1340 switch(chunk.Flag)
|
nuclear@0
|
1341 {
|
nuclear@0
|
1342 case Discreet3DS::CHUNK_LINRGBF:
|
nuclear@0
|
1343 bGamma = true;
|
nuclear@0
|
1344
|
nuclear@0
|
1345 case Discreet3DS::CHUNK_RGBF:
|
nuclear@0
|
1346 if (sizeof(float) * 3 > diff) {
|
nuclear@0
|
1347 *out = clrError;
|
nuclear@0
|
1348 return;
|
nuclear@0
|
1349 }
|
nuclear@0
|
1350 out->r = stream->GetF4();
|
nuclear@0
|
1351 out->g = stream->GetF4();
|
nuclear@0
|
1352 out->b = stream->GetF4();
|
nuclear@0
|
1353 break;
|
nuclear@0
|
1354
|
nuclear@0
|
1355 case Discreet3DS::CHUNK_LINRGBB:
|
nuclear@0
|
1356 bGamma = true;
|
nuclear@0
|
1357 case Discreet3DS::CHUNK_RGBB:
|
nuclear@0
|
1358 if (sizeof(char) * 3 > diff) {
|
nuclear@0
|
1359 *out = clrError;
|
nuclear@0
|
1360 return;
|
nuclear@0
|
1361 }
|
nuclear@0
|
1362 out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
|
nuclear@0
|
1363 out->g = (float)(uint8_t)stream->GetI1() / 255.0f;
|
nuclear@0
|
1364 out->b = (float)(uint8_t)stream->GetI1() / 255.0f;
|
nuclear@0
|
1365 break;
|
nuclear@0
|
1366
|
nuclear@0
|
1367 // Percentage chunks are accepted, too.
|
nuclear@0
|
1368 case Discreet3DS::CHUNK_PERCENTF:
|
nuclear@0
|
1369 if (acceptPercent && 4 <= diff) {
|
nuclear@0
|
1370 out->g = out->b = out->r = stream->GetF4();
|
nuclear@0
|
1371 break;
|
nuclear@0
|
1372 }
|
nuclear@0
|
1373 *out = clrError;
|
nuclear@0
|
1374 return;
|
nuclear@0
|
1375
|
nuclear@0
|
1376 case Discreet3DS::CHUNK_PERCENTW:
|
nuclear@0
|
1377 if (acceptPercent && 1 <= diff) {
|
nuclear@0
|
1378 out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
|
nuclear@0
|
1379 break;
|
nuclear@0
|
1380 }
|
nuclear@0
|
1381 *out = clrError;
|
nuclear@0
|
1382 return;
|
nuclear@0
|
1383
|
nuclear@0
|
1384 default:
|
nuclear@0
|
1385 stream->IncPtr(diff);
|
nuclear@0
|
1386 // Skip unknown chunks, hope this won't cause any problems.
|
nuclear@0
|
1387 return ParseColorChunk(out,acceptPercent);
|
nuclear@0
|
1388 };
|
nuclear@0
|
1389 (void)bGamma;
|
nuclear@0
|
1390 }
|
nuclear@0
|
1391
|
nuclear@0
|
1392 #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER
|