vrshoot

annotate libs/assimp/3DSLoader.cpp @ 1:e7ca128b8713

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +0200
parents
children
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