diff options
Diffstat (limited to 'src/3rdparty/assimp/code/3DSLoader.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/3DSLoader.cpp | 2397 |
1 files changed, 1208 insertions, 1189 deletions
diff --git a/src/3rdparty/assimp/code/3DSLoader.cpp b/src/3rdparty/assimp/code/3DSLoader.cpp index 137cceb1f..a2b73b2cb 100644 --- a/src/3rdparty/assimp/code/3DSLoader.cpp +++ b/src/3rdparty/assimp/code/3DSLoader.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ @@ -45,554 +45,570 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * http://www.the-labs.com/Blender/3DS-details.html */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers #include "3DSLoader.h" +#include "Macros.h" +#include <assimp/IOSystem.hpp> +#include <assimp/scene.h> +#include <assimp/DefaultLogger.hpp> +#include "StringComparison.h" using namespace Assimp; static const aiImporterDesc desc = { - "Discreet 3DS Importer", - "", - "", - "Limited animation support", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "3ds prj" + "Discreet 3DS Importer", + "", + "", + "Limited animation support", + aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, + "3ds prj" }; - + // ------------------------------------------------------------------------------------------------ // Begins a new parsing block // - Reads the current chunk and validates it // - computes its length #define ASSIMP_3DS_BEGIN_CHUNK() \ - while (true) { \ - if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \ - return; \ - } \ - Discreet3DS::Chunk chunk; \ - ReadChunk(&chunk); \ - int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ + while (true) { \ + if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \ + return; \ + } \ + Discreet3DS::Chunk chunk; \ + ReadChunk(&chunk); \ + int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ if(chunkSize <= 0) \ continue; \ - const int oldReadLimit = stream->GetReadLimit(); \ - stream->SetReadLimit(stream->GetCurrentPos() + chunkSize); \ - + const unsigned int oldReadLimit = stream->SetReadLimit( \ + stream->GetCurrentPos() + chunkSize); \ + // ------------------------------------------------------------------------------------------------ // End a parsing block // Must follow at the end of each parsing block, reset chunk end marker to previous value #define ASSIMP_3DS_END_CHUNK() \ - stream->SkipToReadLimit(); \ - stream->SetReadLimit(oldReadLimit); \ - if (stream->GetRemainingSizeToLimit() == 0) \ - return; \ - } + stream->SkipToReadLimit(); \ + stream->SetReadLimit(oldReadLimit); \ + if (stream->GetRemainingSizeToLimit() == 0) \ + return; \ + } // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer Discreet3DSImporter::Discreet3DSImporter() + : stream(), + mLastNodeIndex(), + mCurrentNode(), + mRootNode(), + mScene(), + mMasterScale(), + bHasBG(), + bIsPrj() {} // ------------------------------------------------------------------------------------------------ -// Destructor, private as well +// Destructor, private as well Discreet3DSImporter::~Discreet3DSImporter() {} // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - std::string extension = GetExtension(pFile); - if(extension == "3ds" || extension == "prj" ) { - return true; - } - if (!extension.length() || checkSig) { - uint16_t token[3]; - token[0] = 0x4d4d; - token[1] = 0x3dc2; - //token[2] = 0x3daa; - return CheckMagicToken(pIOHandler,pFile,token,2,0,2); - } - return false; + std::string extension = GetExtension(pFile); + if(extension == "3ds" || extension == "prj" ) { + return true; + } + if (!extension.length() || checkSig) { + uint16_t token[3]; + token[0] = 0x4d4d; + token[1] = 0x3dc2; + //token[2] = 0x3daa; + return CheckMagicToken(pIOHandler,pFile,token,2,0,2); + } + return false; } // ------------------------------------------------------------------------------------------------ // Loader registry entry const aiImporterDesc* Discreet3DSImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration properties void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/) { - // nothing to be done for the moment + // nothing to be done for the moment } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void Discreet3DSImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +// Imports the given file into the given scene structure. +void Discreet3DSImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - StreamReaderLE stream(pIOHandler->Open(pFile,"rb")); - this->stream = &stream; - - // We should have at least one chunk - if (stream.GetRemainingSize() < 16) { - throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); - } - - // Allocate our temporary 3DS representation - mScene = new D3DS::Scene(); - - // Initialize members - mLastNodeIndex = -1; - mCurrentNode = new D3DS::Node(); - mRootNode = mCurrentNode; - mRootNode->mHierarchyPos = -1; - mRootNode->mHierarchyIndex = -1; - mRootNode->mParent = NULL; - mMasterScale = 1.0f; - mBackgroundImage = ""; - bHasBG = false; - bIsPrj = false; - - // Parse the file - ParseMainChunk(); - - // Process all meshes in the file. First check whether all - // face indices haev valid values. The generate our - // internal verbose representation. Finally compute normal - // vectors from the smoothing groups we read from the - // file. - for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(), - end = mScene->mMeshes.end(); i != end;++i) { - CheckIndices(*i); - MakeUnique (*i); - ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i); - } - - // Replace all occurences of the default material with a - // valid material. Generate it if no material containing - // DEFAULT in its name has been found in the file - ReplaceDefaultMaterial(); - - // Convert the scene from our internal representation to an - // aiScene object. This involves copying all meshes, lights - // and cameras to the scene - ConvertScene(pScene); - - // Generate the node graph for the scene. This is a little bit - // tricky since we'll need to split some meshes into submeshes - GenerateNodeGraph(pScene); - - // Now apply the master scaling factor to the scene - ApplyMasterScale(pScene); - - // Delete our internal scene representation and the root - // node, so the whole hierarchy will follow - delete mRootNode; - delete mScene; - - AI_DEBUG_INVALIDATE_PTR(mRootNode); - AI_DEBUG_INVALIDATE_PTR(mScene); - AI_DEBUG_INVALIDATE_PTR(this->stream); + StreamReaderLE stream(pIOHandler->Open(pFile,"rb")); + this->stream = &stream; + + // We should have at least one chunk + if (stream.GetRemainingSize() < 16) { + throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); + } + + // Allocate our temporary 3DS representation + mScene = new D3DS::Scene(); + + // Initialize members + mLastNodeIndex = -1; + mCurrentNode = new D3DS::Node(); + mRootNode = mCurrentNode; + mRootNode->mHierarchyPos = -1; + mRootNode->mHierarchyIndex = -1; + mRootNode->mParent = NULL; + mMasterScale = 1.0f; + mBackgroundImage = ""; + bHasBG = false; + bIsPrj = false; + + // Parse the file + ParseMainChunk(); + + // Process all meshes in the file. First check whether all + // face indices haev valid values. The generate our + // internal verbose representation. Finally compute normal + // vectors from the smoothing groups we read from the + // file. + for (auto &mesh : mScene->mMeshes) { + if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { + delete mScene; + throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile); + } + CheckIndices(mesh); + MakeUnique (mesh); + ComputeNormalsWithSmoothingsGroups<D3DS::Face>(mesh); + } + + // Replace all occurrences of the default material with a + // valid material. Generate it if no material containing + // DEFAULT in its name has been found in the file + ReplaceDefaultMaterial(); + + // Convert the scene from our internal representation to an + // aiScene object. This involves copying all meshes, lights + // and cameras to the scene + ConvertScene(pScene); + + // Generate the node graph for the scene. This is a little bit + // tricky since we'll need to split some meshes into submeshes + GenerateNodeGraph(pScene); + + // Now apply the master scaling factor to the scene + ApplyMasterScale(pScene); + + // Delete our internal scene representation and the root + // node, so the whole hierarchy will follow + delete mRootNode; + delete mScene; + + AI_DEBUG_INVALIDATE_PTR(mRootNode); + AI_DEBUG_INVALIDATE_PTR(mScene); + AI_DEBUG_INVALIDATE_PTR(this->stream); } // ------------------------------------------------------------------------------------------------ // Applies a master-scaling factor to the imported scene void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene) { - // There are some 3DS files with a zero scaling factor - if (!mMasterScale)mMasterScale = 1.0f; - else mMasterScale = 1.0f / mMasterScale; - - // Construct an uniform scaling matrix and multiply with it - pScene->mRootNode->mTransformation *= aiMatrix4x4( - mMasterScale,0.0f, 0.0f, 0.0f, - 0.0f, mMasterScale,0.0f, 0.0f, - 0.0f, 0.0f, mMasterScale,0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - - // Check whether a scaling track is assigned to the root node. + // There are some 3DS files with a zero scaling factor + if (!mMasterScale)mMasterScale = 1.0f; + else mMasterScale = 1.0f / mMasterScale; + + // Construct an uniform scaling matrix and multiply with it + pScene->mRootNode->mTransformation *= aiMatrix4x4( + mMasterScale,0.0f, 0.0f, 0.0f, + 0.0f, mMasterScale,0.0f, 0.0f, + 0.0f, 0.0f, mMasterScale,0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + + // Check whether a scaling track is assigned to the root node. } // ------------------------------------------------------------------------------------------------ // Reads a new chunk from the file void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut) { - ai_assert(pcOut != NULL); + ai_assert(pcOut != NULL); - pcOut->Flag = stream->GetI2(); - pcOut->Size = stream->GetI4(); + pcOut->Flag = stream->GetI2(); + pcOut->Size = stream->GetI4(); - if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) - throw DeadlyImportError("Chunk is too large"); - - if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) - DefaultLogger::get()->error("3DS: Chunk overflow"); + if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) + throw DeadlyImportError("Chunk is too large"); + + if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) + DefaultLogger::get()->error("3DS: Chunk overflow"); } // ------------------------------------------------------------------------------------------------ // Skip a chunk void Discreet3DSImporter::SkipChunk() { - Discreet3DS::Chunk psChunk; - ReadChunk(&psChunk); - - stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk)); - return; + Discreet3DS::Chunk psChunk; + ReadChunk(&psChunk); + + stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk)); + return; } // ------------------------------------------------------------------------------------------------ // Process the primary chunk of the file void Discreet3DSImporter::ParseMainChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - - case Discreet3DS::CHUNK_PRJ: - bIsPrj = true; - case Discreet3DS::CHUNK_MAIN: - ParseEditorChunk(); - break; - }; - - ASSIMP_3DS_END_CHUNK(); - // recursively continue processing this hierarchy level - return ParseMainChunk(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + + case Discreet3DS::CHUNK_PRJ: + bIsPrj = true; + case Discreet3DS::CHUNK_MAIN: + ParseEditorChunk(); + break; + }; + + ASSIMP_3DS_END_CHUNK(); + // recursively continue processing this hierarchy level + return ParseMainChunk(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseEditorChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_OBJMESH: - - ParseObjectChunk(); - break; - - // NOTE: In several documentations in the internet this - // chunk appears at different locations - case Discreet3DS::CHUNK_KEYFRAMER: - - ParseKeyframeChunk(); - break; - - case Discreet3DS::CHUNK_VERSION: - { - // print the version number - char buff[10]; - ASSIMP_itoa10(buff,stream->GetI2()); - DefaultLogger::get()->info(std::string("3DS file format version: ") + buff); - } - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_OBJMESH: + + ParseObjectChunk(); + break; + + // NOTE: In several documentations in the internet this + // chunk appears at different locations + case Discreet3DS::CHUNK_KEYFRAMER: + + ParseKeyframeChunk(); + break; + + case Discreet3DS::CHUNK_VERSION: + { + // print the version number + char buff[10]; + ASSIMP_itoa10(buff,stream->GetI2()); + DefaultLogger::get()->info(std::string("3DS file format version: ") + buff); + } + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseObjectChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_OBJBLOCK: - { - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - - // Get the name of the geometry object - while (stream->GetI1())++cnt; - ParseChunk(sz,cnt); - } - break; - - case Discreet3DS::CHUNK_MAT_MATERIAL: - - // Add a new material to the list - mScene->mMaterials.push_back(D3DS::Material()); - ParseMaterialChunk(); - break; - - case Discreet3DS::CHUNK_AMBCOLOR: - - // This is the ambient base color of the scene. - // We add it to the ambient color of all materials - ParseColorChunk(&mClrAmbient,true); - if (is_qnan(mClrAmbient.r)) - { - // We failed to read the ambient base color. - DefaultLogger::get()->error("3DS: Failed to read ambient base color"); - mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f; - } - break; - - case Discreet3DS::CHUNK_BIT_MAP: - { - // Specifies the background image. The string should already be - // properly 0 terminated but we need to be sure - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - while (stream->GetI1())++cnt; - mBackgroundImage = std::string(sz,cnt); - } - break; - - case Discreet3DS::CHUNK_BIT_MAP_EXISTS: - bHasBG = true; - break; - - case Discreet3DS::CHUNK_MASTER_SCALE: - // Scene master scaling factor - mMasterScale = stream->GetF4(); - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_OBJBLOCK: + { + unsigned int cnt = 0; + const char* sz = (const char*)stream->GetPtr(); + + // Get the name of the geometry object + while (stream->GetI1())++cnt; + ParseChunk(sz,cnt); + } + break; + + case Discreet3DS::CHUNK_MAT_MATERIAL: + + // Add a new material to the list + mScene->mMaterials.push_back(D3DS::Material()); + ParseMaterialChunk(); + break; + + case Discreet3DS::CHUNK_AMBCOLOR: + + // This is the ambient base color of the scene. + // We add it to the ambient color of all materials + ParseColorChunk(&mClrAmbient,true); + if (is_qnan(mClrAmbient.r)) + { + // We failed to read the ambient base color. + DefaultLogger::get()->error("3DS: Failed to read ambient base color"); + mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f; + } + break; + + case Discreet3DS::CHUNK_BIT_MAP: + { + // Specifies the background image. The string should already be + // properly 0 terminated but we need to be sure + unsigned int cnt = 0; + const char* sz = (const char*)stream->GetPtr(); + while (stream->GetI1())++cnt; + mBackgroundImage = std::string(sz,cnt); + } + break; + + case Discreet3DS::CHUNK_BIT_MAP_EXISTS: + bHasBG = true; + break; + + case Discreet3DS::CHUNK_MASTER_SCALE: + // Scene master scaling factor + mMasterScale = stream->GetF4(); + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) { - ASSIMP_3DS_BEGIN_CHUNK(); - - // IMPLEMENTATION NOTE; - // Cameras or lights define their transformation in their parent node and in the - // corresponding light or camera chunks. However, we read and process the latter - // to to be able to return valid cameras/lights even if no scenegraph is given. - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRIMESH: - { - // this starts a new triangle mesh - mScene->mMeshes.push_back(D3DS::Mesh()); - D3DS::Mesh& m = mScene->mMeshes.back(); - - // Setup the name of the mesh - m.mName = std::string(name, num); - - // Read mesh chunks - ParseMeshChunk(); - } - break; - - case Discreet3DS::CHUNK_LIGHT: - { - // This starts a new light - aiLight* light = new aiLight(); - mScene->mLights.push_back(light); - - light->mName.Set(std::string(name, num)); - - // First read the position of the light - light->mPosition.x = stream->GetF4(); - light->mPosition.y = stream->GetF4(); - light->mPosition.z = stream->GetF4(); - - light->mColorDiffuse = aiColor3D(1.f,1.f,1.f); - - // Now check for further subchunks - if (!bIsPrj) /* fixme */ - ParseLightChunk(); - - // The specular light color is identical the the diffuse light color. The ambient light color - // is equal to the ambient base color of the whole scene. - light->mColorSpecular = light->mColorDiffuse; - light->mColorAmbient = mClrAmbient; - - if (light->mType == aiLightSource_UNDEFINED) - { - // It must be a point light - light->mType = aiLightSource_POINT; - }} - break; - - case Discreet3DS::CHUNK_CAMERA: - { - // This starts a new camera - aiCamera* camera = new aiCamera(); - mScene->mCameras.push_back(camera); - camera->mName.Set(std::string(name, num)); - - // First read the position of the camera - camera->mPosition.x = stream->GetF4(); - camera->mPosition.y = stream->GetF4(); - camera->mPosition.z = stream->GetF4(); - - // Then the camera target - camera->mLookAt.x = stream->GetF4() - camera->mPosition.x; - camera->mLookAt.y = stream->GetF4() - camera->mPosition.y; - camera->mLookAt.z = stream->GetF4() - camera->mPosition.z; - float len = camera->mLookAt.Length(); - if (len < 1e-5f) { - - // There are some files with lookat == position. Don't know why or whether it's ok or not. - DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector"); - camera->mLookAt = aiVector3D(0.f,1.f,0.f); - - } - else camera->mLookAt /= len; - - // And finally - the camera rotation angle, in counter clockwise direction - const float angle = AI_DEG_TO_RAD( stream->GetF4() ); - aiQuaternion quat(camera->mLookAt,angle); - camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f); - - // Read the lense angle - camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() ); - if (camera->mHorizontalFOV < 0.001f) { - camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f); - } - - // Now check for further subchunks - if (!bIsPrj) /* fixme */ { - ParseCameraChunk(); - }} - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // IMPLEMENTATION NOTE; + // Cameras or lights define their transformation in their parent node and in the + // corresponding light or camera chunks. However, we read and process the latter + // to to be able to return valid cameras/lights even if no scenegraph is given. + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_TRIMESH: + { + // this starts a new triangle mesh + mScene->mMeshes.push_back(D3DS::Mesh()); + D3DS::Mesh& m = mScene->mMeshes.back(); + + // Setup the name of the mesh + m.mName = std::string(name, num); + + // Read mesh chunks + ParseMeshChunk(); + } + break; + + case Discreet3DS::CHUNK_LIGHT: + { + // This starts a new light + aiLight* light = new aiLight(); + mScene->mLights.push_back(light); + + light->mName.Set(std::string(name, num)); + + // First read the position of the light + light->mPosition.x = stream->GetF4(); + light->mPosition.y = stream->GetF4(); + light->mPosition.z = stream->GetF4(); + + light->mColorDiffuse = aiColor3D(1.f,1.f,1.f); + + // Now check for further subchunks + if (!bIsPrj) /* fixme */ + ParseLightChunk(); + + // The specular light color is identical the the diffuse light color. The ambient light color + // is equal to the ambient base color of the whole scene. + light->mColorSpecular = light->mColorDiffuse; + light->mColorAmbient = mClrAmbient; + + if (light->mType == aiLightSource_UNDEFINED) + { + // It must be a point light + light->mType = aiLightSource_POINT; + }} + break; + + case Discreet3DS::CHUNK_CAMERA: + { + // This starts a new camera + aiCamera* camera = new aiCamera(); + mScene->mCameras.push_back(camera); + camera->mName.Set(std::string(name, num)); + + // First read the position of the camera + camera->mPosition.x = stream->GetF4(); + camera->mPosition.y = stream->GetF4(); + camera->mPosition.z = stream->GetF4(); + + // Then the camera target + camera->mLookAt.x = stream->GetF4() - camera->mPosition.x; + camera->mLookAt.y = stream->GetF4() - camera->mPosition.y; + camera->mLookAt.z = stream->GetF4() - camera->mPosition.z; + float len = camera->mLookAt.Length(); + if (len < 1e-5f) { + + // There are some files with lookat == position. Don't know why or whether it's ok or not. + DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector"); + camera->mLookAt = aiVector3D(0.f,1.f,0.f); + + } + else camera->mLookAt /= len; + + // And finally - the camera rotation angle, in counter clockwise direction + const float angle = AI_DEG_TO_RAD( stream->GetF4() ); + aiQuaternion quat(camera->mLookAt,angle); + camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f); + + // Read the lense angle + camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() ); + if (camera->mHorizontalFOV < 0.001f) { + camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f); + } + + // Now check for further subchunks + if (!bIsPrj) /* fixme */ { + ParseCameraChunk(); + }} + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseLightChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - aiLight* light = mScene->mLights.back(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_DL_SPOTLIGHT: - // Now we can be sure that the light is a spot light - light->mType = aiLightSource_SPOT; - - // We wouldn't need to normalize here, but we do it - light->mDirection.x = stream->GetF4() - light->mPosition.x; - light->mDirection.y = stream->GetF4() - light->mPosition.y; - light->mDirection.z = stream->GetF4() - light->mPosition.z; - light->mDirection.Normalize(); - - // Now the hotspot and falloff angles - in degrees - light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() ); - - // FIX: the falloff angle is just an offset - light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() ); - break; - - // intensity multiplier - case Discreet3DS::CHUNK_DL_MULTIPLIER: - light->mColorDiffuse = light->mColorDiffuse * stream->GetF4(); - break; - - // light color - case Discreet3DS::CHUNK_RGBF: - case Discreet3DS::CHUNK_LINRGBF: - light->mColorDiffuse.r *= stream->GetF4(); - light->mColorDiffuse.g *= stream->GetF4(); - light->mColorDiffuse.b *= stream->GetF4(); - break; - - // light attenuation - case Discreet3DS::CHUNK_DL_ATTENUATE: - light->mAttenuationLinear = stream->GetF4(); - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + aiLight* light = mScene->mLights.back(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_DL_SPOTLIGHT: + // Now we can be sure that the light is a spot light + light->mType = aiLightSource_SPOT; + + // We wouldn't need to normalize here, but we do it + light->mDirection.x = stream->GetF4() - light->mPosition.x; + light->mDirection.y = stream->GetF4() - light->mPosition.y; + light->mDirection.z = stream->GetF4() - light->mPosition.z; + light->mDirection.Normalize(); + + // Now the hotspot and falloff angles - in degrees + light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() ); + + // FIX: the falloff angle is just an offset + light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() ); + break; + + // intensity multiplier + case Discreet3DS::CHUNK_DL_MULTIPLIER: + light->mColorDiffuse = light->mColorDiffuse * stream->GetF4(); + break; + + // light color + case Discreet3DS::CHUNK_RGBF: + case Discreet3DS::CHUNK_LINRGBF: + light->mColorDiffuse.r *= stream->GetF4(); + light->mColorDiffuse.g *= stream->GetF4(); + light->mColorDiffuse.b *= stream->GetF4(); + break; + + // light attenuation + case Discreet3DS::CHUNK_DL_ATTENUATE: + light->mAttenuationLinear = stream->GetF4(); + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseCameraChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - aiCamera* camera = mScene->mCameras.back(); - - // get chunk type - switch (chunk.Flag) - { - // near and far clip plane - case Discreet3DS::CHUNK_CAM_RANGES: - camera->mClipPlaneNear = stream->GetF4(); - camera->mClipPlaneFar = stream->GetF4(); - break; - } - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + aiCamera* camera = mScene->mCameras.back(); + + // get chunk type + switch (chunk.Flag) + { + // near and far clip plane + case Discreet3DS::CHUNK_CAM_RANGES: + camera->mClipPlaneNear = stream->GetF4(); + camera->mClipPlaneFar = stream->GetF4(); + break; + } + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseKeyframeChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRACKCAMTGT: - case Discreet3DS::CHUNK_TRACKSPOTL: - case Discreet3DS::CHUNK_TRACKCAMERA: - case Discreet3DS::CHUNK_TRACKINFO: - case Discreet3DS::CHUNK_TRACKLIGHT: - case Discreet3DS::CHUNK_TRACKLIGTGT: - - // this starts a new mesh hierarchy chunk - ParseHierarchyChunk(chunk.Flag); - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_TRACKCAMTGT: + case Discreet3DS::CHUNK_TRACKSPOTL: + case Discreet3DS::CHUNK_TRACKCAMERA: + case Discreet3DS::CHUNK_TRACKINFO: + case Discreet3DS::CHUNK_TRACKLIGHT: + case Discreet3DS::CHUNK_TRACKLIGTGT: + + // this starts a new mesh hierarchy chunk + ParseHierarchyChunk(chunk.Flag); + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Little helper function for ParseHierarchyChunk void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent) { - if (!pcCurrent) { - mRootNode->push_back(pcNode); - return; - } - - if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) { - if(pcCurrent->mParent) { - pcCurrent->mParent->push_back(pcNode); - } - else pcCurrent->push_back(pcNode); - return; - } - return InverseNodeSearch(pcNode,pcCurrent->mParent); + if (!pcCurrent) { + mRootNode->push_back(pcNode); + return; + } + + if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) { + if(pcCurrent->mParent) { + pcCurrent->mParent->push_back(pcNode); + } + else pcCurrent->push_back(pcNode); + return; + } + return InverseNodeSearch(pcNode,pcCurrent->mParent); } // ------------------------------------------------------------------------------------------------ // Find a node with a specific name in the import hierarchy D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) { - if (root->mName == name) - return root; - for (std::vector<D3DS::Node*>::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { - D3DS::Node* nd; - if (( nd = FindNode(*it,name))) - return nd; - } - return NULL; + if (root->mName == name) + return root; + for (std::vector<D3DS::Node*>::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { + D3DS::Node* nd; + if (( nd = FindNode(*it,name))) + return nd; + } + return NULL; } // ------------------------------------------------------------------------------------------------ @@ -600,803 +616,806 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) template <class T> bool KeyUniqueCompare(const T& first, const T& second) { - return first.mTime == second.mTime; + return first.mTime == second.mTime; } // ------------------------------------------------------------------------------------------------ // Skip some additional import data. void Discreet3DSImporter::SkipTCBInfo() { - unsigned int flags = stream->GetI2(); - - if (!flags) { - // Currently we can't do anything with these values. They occur - // quite rare, so it wouldn't be worth the effort implementing - // them. 3DS ist not really suitable for complex animations, - // so full support is not required. - DefaultLogger::get()->warn("3DS: Skipping TCB animation info"); - } - - if (flags & Discreet3DS::KEY_USE_TENS) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_BIAS) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_CONT) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_EASE_FROM) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_EASE_TO) { - stream->IncPtr(4); - } + unsigned int flags = stream->GetI2(); + + if (!flags) { + // Currently we can't do anything with these values. They occur + // quite rare, so it wouldn't be worth the effort implementing + // them. 3DS ist not really suitable for complex animations, + // so full support is not required. + DefaultLogger::get()->warn("3DS: Skipping TCB animation info"); + } + + if (flags & Discreet3DS::KEY_USE_TENS) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_BIAS) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_CONT) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_EASE_FROM) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_EASE_TO) { + stream->IncPtr(4); + } } // ------------------------------------------------------------------------------------------------ // Read hierarchy and keyframe info void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRACKOBJNAME: - - // This is the name of the object to which the track applies. The chunk also - // defines the position of this object in the hierarchy. - { - - // First of all: get the name of the object - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - - while (stream->GetI1())++cnt; - std::string name = std::string(sz,cnt); - - // Now find out whether we have this node already (target animation channels - // are stored with a separate object ID) - D3DS::Node* pcNode = FindNode(mRootNode,name); - int instanceNumber = 1; - - if ( pcNode) - { - // if the source is not a CHUNK_TRACKINFO block it wont be an object instance - if (parent != Discreet3DS::CHUNK_TRACKINFO) - { - mCurrentNode = pcNode; - break; - } - pcNode->mInstanceCount++; - instanceNumber = pcNode->mInstanceCount; - } - pcNode = new D3DS::Node(); - pcNode->mName = name; - pcNode->mInstanceNumber = instanceNumber; - - // There are two unknown values which we can safely ignore - stream->IncPtr(4); - - // Now read the hierarchy position of the object - uint16_t hierarchy = stream->GetI2() + 1; - pcNode->mHierarchyPos = hierarchy; - pcNode->mHierarchyIndex = mLastNodeIndex; - - // And find a proper position in the graph for it - if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) { - - // add to the parent of the last touched node - mCurrentNode->mParent->push_back(pcNode); - mLastNodeIndex++; - } - else if(hierarchy >= mLastNodeIndex) { - - // place it at the current position in the hierarchy - mCurrentNode->push_back(pcNode); - mLastNodeIndex = hierarchy; - } - else { - // need to go back to the specified position in the hierarchy. - InverseNodeSearch(pcNode,mCurrentNode); - mLastNodeIndex++; - } - // Make this node the current node - mCurrentNode = pcNode; - } - break; - - case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME: - - // This is the "real" name of a $$$DUMMY object - { - const char* sz = (const char*) stream->GetPtr(); - while (stream->GetI1()); - - // If object name is DUMMY, take this one instead - if (mCurrentNode->mName == "$$$DUMMY") { - //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object"); - mCurrentNode->mName = std::string(sz); - break; - } - } - break; - - case Discreet3DS::CHUNK_TRACKPIVOT: - - if ( Discreet3DS::CHUNK_TRACKINFO != parent) - { - DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object"); - break; - } - - // Pivot = origin of rotation and scaling - mCurrentNode->vPivot.x = stream->GetF4(); - mCurrentNode->vPivot.y = stream->GetF4(); - mCurrentNode->vPivot.z = stream->GetF4(); - break; - - - // //////////////////////////////////////////////////////////////////// - // POSITION KEYFRAME - case Discreet3DS::CHUNK_TRACKPOS: - { - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI4(); - bool sortKeys = false; - - // This could also be meant as the target position for - // (targeted) lights and cameras - std::vector<aiVectorKey>* l; - if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) { - l = & mCurrentNode->aTargetPositionKeys; - } - else l = & mCurrentNode->aPositionKeys; - - l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - - // Setup a new position key - aiVectorKey v; - v.mTime = (double)fidx; - - SkipTCBInfo(); - v.mValue.x = stream->GetF4(); - v.mValue.y = stream->GetF4(); - v.mValue.z = stream->GetF4(); - - // check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // Add the new keyframe to the list - l->push_back(v); - } - - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() ); - }} - - break; - - // //////////////////////////////////////////////////////////////////// - // CAMERA ROLL KEYFRAME - case Discreet3DS::CHUNK_TRACKROLL: - { - // roll keys are accepted for cameras only - if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { - DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object"); - break; - } - bool sortKeys = false; - std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys; - - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI4(); - l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - - // Setup a new position key - aiFloatKey v; - v.mTime = (double)fidx; - - // This is just a single float - SkipTCBInfo(); - v.mValue = stream->GetF4(); - - // Check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // Add the new keyframe to the list - l->push_back(v); - } - - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiFloatKey>), l->end() ); - }} - break; - - - // //////////////////////////////////////////////////////////////////// - // CAMERA FOV KEYFRAME - case Discreet3DS::CHUNK_TRACKFOV: - { - DefaultLogger::get()->error("3DS: Skipping FOV animation track. " - "This is not supported"); - } - break; - - - // //////////////////////////////////////////////////////////////////// - // ROTATION KEYFRAME - case Discreet3DS::CHUNK_TRACKROTATE: - { - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI4(); - - bool sortKeys = false; - std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys; - l->reserve(numFrames); - - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - SkipTCBInfo(); - - aiQuatKey v; - v.mTime = (double)fidx; - - // The rotation keyframe is given as an axis-angle pair - const float rad = stream->GetF4(); - aiVector3D axis; - axis.x = stream->GetF4(); - axis.y = stream->GetF4(); - axis.z = stream->GetF4(); - - if (!axis.x && !axis.y && !axis.z) - axis.y = 1.f; - - // Construct a rotation quaternion from the axis-angle pair - v.mValue = aiQuaternion(axis,rad); - - // Check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // add the new keyframe to the list - l->push_back(v); - } - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiQuatKey>), l->end() ); - }} - break; - - // //////////////////////////////////////////////////////////////////// - // SCALING KEYFRAME - case Discreet3DS::CHUNK_TRACKSCALE: - { - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI2(); - stream->IncPtr(2); - - bool sortKeys = false; - std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys; - l->reserve(numFrames); - - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - SkipTCBInfo(); - - // Setup a new key - aiVectorKey v; - v.mTime = (double)fidx; - - // ... and read its value - v.mValue.x = stream->GetF4(); - v.mValue.y = stream->GetF4(); - v.mValue.z = stream->GetF4(); - - // check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files - if (!v.mValue.x) v.mValue.x = 1.f; - if (!v.mValue.y) v.mValue.y = 1.f; - if (!v.mValue.z) v.mValue.z = 1.f; - - l->push_back(v); - } - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() ); - }} - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_TRACKOBJNAME: + + // This is the name of the object to which the track applies. The chunk also + // defines the position of this object in the hierarchy. + { + + // First of all: get the name of the object + unsigned int cnt = 0; + const char* sz = (const char*)stream->GetPtr(); + + while (stream->GetI1())++cnt; + std::string name = std::string(sz,cnt); + + // Now find out whether we have this node already (target animation channels + // are stored with a separate object ID) + D3DS::Node* pcNode = FindNode(mRootNode,name); + int instanceNumber = 1; + + if ( pcNode) + { + // if the source is not a CHUNK_TRACKINFO block it wont be an object instance + if (parent != Discreet3DS::CHUNK_TRACKINFO) + { + mCurrentNode = pcNode; + break; + } + pcNode->mInstanceCount++; + instanceNumber = pcNode->mInstanceCount; + } + pcNode = new D3DS::Node(); + pcNode->mName = name; + pcNode->mInstanceNumber = instanceNumber; + + // There are two unknown values which we can safely ignore + stream->IncPtr(4); + + // Now read the hierarchy position of the object + uint16_t hierarchy = stream->GetI2() + 1; + pcNode->mHierarchyPos = hierarchy; + pcNode->mHierarchyIndex = mLastNodeIndex; + + // And find a proper position in the graph for it + if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) { + + // add to the parent of the last touched node + mCurrentNode->mParent->push_back(pcNode); + mLastNodeIndex++; + } + else if(hierarchy >= mLastNodeIndex) { + + // place it at the current position in the hierarchy + mCurrentNode->push_back(pcNode); + mLastNodeIndex = hierarchy; + } + else { + // need to go back to the specified position in the hierarchy. + InverseNodeSearch(pcNode,mCurrentNode); + mLastNodeIndex++; + } + // Make this node the current node + mCurrentNode = pcNode; + } + break; + + case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME: + + // This is the "real" name of a $$$DUMMY object + { + const char* sz = (const char*) stream->GetPtr(); + while (stream->GetI1()); + + // If object name is DUMMY, take this one instead + if (mCurrentNode->mName == "$$$DUMMY") { + //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object"); + mCurrentNode->mName = std::string(sz); + break; + } + } + break; + + case Discreet3DS::CHUNK_TRACKPIVOT: + + if ( Discreet3DS::CHUNK_TRACKINFO != parent) + { + DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object"); + break; + } + + // Pivot = origin of rotation and scaling + mCurrentNode->vPivot.x = stream->GetF4(); + mCurrentNode->vPivot.y = stream->GetF4(); + mCurrentNode->vPivot.z = stream->GetF4(); + break; + + + // //////////////////////////////////////////////////////////////////// + // POSITION KEYFRAME + case Discreet3DS::CHUNK_TRACKPOS: + { + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI4(); + bool sortKeys = false; + + // This could also be meant as the target position for + // (targeted) lights and cameras + std::vector<aiVectorKey>* l; + if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) { + l = & mCurrentNode->aTargetPositionKeys; + } + else l = & mCurrentNode->aPositionKeys; + + l->reserve(numFrames); + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + + // Setup a new position key + aiVectorKey v; + v.mTime = (double)fidx; + + SkipTCBInfo(); + v.mValue.x = stream->GetF4(); + v.mValue.y = stream->GetF4(); + v.mValue.z = stream->GetF4(); + + // check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // Add the new keyframe to the list + l->push_back(v); + } + + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() ); + }} + + break; + + // //////////////////////////////////////////////////////////////////// + // CAMERA ROLL KEYFRAME + case Discreet3DS::CHUNK_TRACKROLL: + { + // roll keys are accepted for cameras only + if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { + DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object"); + break; + } + bool sortKeys = false; + std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys; + + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI4(); + l->reserve(numFrames); + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + + // Setup a new position key + aiFloatKey v; + v.mTime = (double)fidx; + + // This is just a single float + SkipTCBInfo(); + v.mValue = stream->GetF4(); + + // Check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // Add the new keyframe to the list + l->push_back(v); + } + + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiFloatKey>), l->end() ); + }} + break; + + + // //////////////////////////////////////////////////////////////////// + // CAMERA FOV KEYFRAME + case Discreet3DS::CHUNK_TRACKFOV: + { + DefaultLogger::get()->error("3DS: Skipping FOV animation track. " + "This is not supported"); + } + break; + + + // //////////////////////////////////////////////////////////////////// + // ROTATION KEYFRAME + case Discreet3DS::CHUNK_TRACKROTATE: + { + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI4(); + + bool sortKeys = false; + std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys; + l->reserve(numFrames); + + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + SkipTCBInfo(); + + aiQuatKey v; + v.mTime = (double)fidx; + + // The rotation keyframe is given as an axis-angle pair + const float rad = stream->GetF4(); + aiVector3D axis; + axis.x = stream->GetF4(); + axis.y = stream->GetF4(); + axis.z = stream->GetF4(); + + if (!axis.x && !axis.y && !axis.z) + axis.y = 1.f; + + // Construct a rotation quaternion from the axis-angle pair + v.mValue = aiQuaternion(axis,rad); + + // Check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // add the new keyframe to the list + l->push_back(v); + } + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiQuatKey>), l->end() ); + }} + break; + + // //////////////////////////////////////////////////////////////////// + // SCALING KEYFRAME + case Discreet3DS::CHUNK_TRACKSCALE: + { + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI2(); + stream->IncPtr(2); + + bool sortKeys = false; + std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys; + l->reserve(numFrames); + + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + SkipTCBInfo(); + + // Setup a new key + aiVectorKey v; + v.mTime = (double)fidx; + + // ... and read its value + v.mValue.x = stream->GetF4(); + v.mValue.y = stream->GetF4(); + v.mValue.z = stream->GetF4(); + + // check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files + if (!v.mValue.x) v.mValue.x = 1.f; + if (!v.mValue.y) v.mValue.y = 1.f; + if (!v.mValue.z) v.mValue.z = 1.f; + + l->push_back(v); + } + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() ); + }} + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a face chunk - it contains smoothing groups and material assignments void Discreet3DSImporter::ParseFaceChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // Get the mesh we're currently working on - D3DS::Mesh& mMesh = mScene->mMeshes.back(); - - // Get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_SMOOLIST: - { - // This is the list of smoothing groups - a bitfield for every face. - // Up to 32 smoothing groups assigned to a single face. - unsigned int num = chunkSize/4, m = 0; - for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin(); m != num;++i, ++m) { - // nth bit is set for nth smoothing group - (*i).iSmoothGroup = stream->GetI4(); - }} - break; - - case Discreet3DS::CHUNK_FACEMAT: - { - // at fist an asciiz with the material name - const char* sz = (const char*)stream->GetPtr(); - while (stream->GetI1()); - - // find the index of the material - unsigned int idx = 0xcdcdcdcd, cnt = 0; - for (std::vector<D3DS::Material>::const_iterator i = mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt) { - // use case independent comparisons. hopefully it will work. - if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) { - idx = cnt; - break; - } - } - if (0xcdcdcdcd == idx) { - DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz); - } - - // Now continue and read all material indices - cnt = (uint16_t)stream->GetI2(); - for (unsigned int i = 0; i < cnt;++i) { - unsigned int fidx = (uint16_t)stream->GetI2(); - - // check range - if (fidx >= mMesh.mFaceMaterials.size()) { - DefaultLogger::get()->error("3DS: Invalid face index in face material list"); - } - else mMesh.mFaceMaterials[fidx] = idx; - }} - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // Get the mesh we're currently working on + D3DS::Mesh& mMesh = mScene->mMeshes.back(); + + // Get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_SMOOLIST: + { + // This is the list of smoothing groups - a bitfield for every face. + // Up to 32 smoothing groups assigned to a single face. + unsigned int num = chunkSize/4, m = 0; + if (num > mMesh.mFaces.size()) { + throw DeadlyImportError("3DS: More smoothing groups than faces"); + } + for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin(); m != num;++i, ++m) { + // nth bit is set for nth smoothing group + (*i).iSmoothGroup = stream->GetI4(); + }} + break; + + case Discreet3DS::CHUNK_FACEMAT: + { + // at fist an asciiz with the material name + const char* sz = (const char*)stream->GetPtr(); + while (stream->GetI1()); + + // find the index of the material + unsigned int idx = 0xcdcdcdcd, cnt = 0; + for (std::vector<D3DS::Material>::const_iterator i = mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt) { + // use case independent comparisons. hopefully it will work. + if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) { + idx = cnt; + break; + } + } + if (0xcdcdcdcd == idx) { + DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz); + } + + // Now continue and read all material indices + cnt = (uint16_t)stream->GetI2(); + for (unsigned int i = 0; i < cnt;++i) { + unsigned int fidx = (uint16_t)stream->GetI2(); + + // check range + if (fidx >= mMesh.mFaceMaterials.size()) { + DefaultLogger::get()->error("3DS: Invalid face index in face material list"); + } + else mMesh.mFaceMaterials[fidx] = idx; + }} + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a mesh chunk. Here's the actual mesh data void Discreet3DSImporter::ParseMeshChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // Get the mesh we're currently working on - D3DS::Mesh& mMesh = mScene->mMeshes.back(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_VERTLIST: - { - // This is the list of all vertices in the current mesh - int num = (int)(uint16_t)stream->GetI2(); - mMesh.mPositions.reserve(num); - while (num-- > 0) { - aiVector3D v; - v.x = stream->GetF4(); - v.y = stream->GetF4(); - v.z = stream->GetF4(); - mMesh.mPositions.push_back(v); - }} - break; - case Discreet3DS::CHUNK_TRMATRIX: - { - // This is the RLEATIVE transformation matrix of the current mesh. Vertices are - // pretransformed by this matrix wonder. - mMesh.mMat.a1 = stream->GetF4(); - mMesh.mMat.b1 = stream->GetF4(); - mMesh.mMat.c1 = stream->GetF4(); - mMesh.mMat.a2 = stream->GetF4(); - mMesh.mMat.b2 = stream->GetF4(); - mMesh.mMat.c2 = stream->GetF4(); - mMesh.mMat.a3 = stream->GetF4(); - mMesh.mMat.b3 = stream->GetF4(); - mMesh.mMat.c3 = stream->GetF4(); - mMesh.mMat.a4 = stream->GetF4(); - mMesh.mMat.b4 = stream->GetF4(); - mMesh.mMat.c4 = stream->GetF4(); - } - break; - - case Discreet3DS::CHUNK_MAPLIST: - { - // This is the list of all UV coords in the current mesh - int num = (int)(uint16_t)stream->GetI2(); - mMesh.mTexCoords.reserve(num); - while (num-- > 0) { - aiVector3D v; - v.x = stream->GetF4(); - v.y = stream->GetF4(); - mMesh.mTexCoords.push_back(v); - }} - break; - - case Discreet3DS::CHUNK_FACELIST: - { - // This is the list of all faces in the current mesh - int num = (int)(uint16_t)stream->GetI2(); - mMesh.mFaces.reserve(num); - while (num-- > 0) { - // 3DS faces are ALWAYS triangles - mMesh.mFaces.push_back(D3DS::Face()); - D3DS::Face& sFace = mMesh.mFaces.back(); - - sFace.mIndices[0] = (uint16_t)stream->GetI2(); - sFace.mIndices[1] = (uint16_t)stream->GetI2(); - sFace.mIndices[2] = (uint16_t)stream->GetI2(); - - stream->IncPtr(2); // skip edge visibility flag - } - - // Resize the material array (0xcdcdcdcd marks the default material; so if a face is - // not referenced by a material, $$DEFAULT will be assigned to it) - mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd); - - // Larger 3DS files could have multiple FACE chunks here - chunkSize = stream->GetRemainingSizeToLimit(); - if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) ) - ParseFaceChunk(); - } - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // Get the mesh we're currently working on + D3DS::Mesh& mMesh = mScene->mMeshes.back(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_VERTLIST: + { + // This is the list of all vertices in the current mesh + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mPositions.reserve(num); + while (num-- > 0) { + aiVector3D v; + v.x = stream->GetF4(); + v.y = stream->GetF4(); + v.z = stream->GetF4(); + mMesh.mPositions.push_back(v); + }} + break; + case Discreet3DS::CHUNK_TRMATRIX: + { + // This is the RLEATIVE transformation matrix of the current mesh. Vertices are + // pretransformed by this matrix wonder. + mMesh.mMat.a1 = stream->GetF4(); + mMesh.mMat.b1 = stream->GetF4(); + mMesh.mMat.c1 = stream->GetF4(); + mMesh.mMat.a2 = stream->GetF4(); + mMesh.mMat.b2 = stream->GetF4(); + mMesh.mMat.c2 = stream->GetF4(); + mMesh.mMat.a3 = stream->GetF4(); + mMesh.mMat.b3 = stream->GetF4(); + mMesh.mMat.c3 = stream->GetF4(); + mMesh.mMat.a4 = stream->GetF4(); + mMesh.mMat.b4 = stream->GetF4(); + mMesh.mMat.c4 = stream->GetF4(); + } + break; + + case Discreet3DS::CHUNK_MAPLIST: + { + // This is the list of all UV coords in the current mesh + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mTexCoords.reserve(num); + while (num-- > 0) { + aiVector3D v; + v.x = stream->GetF4(); + v.y = stream->GetF4(); + mMesh.mTexCoords.push_back(v); + }} + break; + + case Discreet3DS::CHUNK_FACELIST: + { + // This is the list of all faces in the current mesh + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mFaces.reserve(num); + while (num-- > 0) { + // 3DS faces are ALWAYS triangles + mMesh.mFaces.push_back(D3DS::Face()); + D3DS::Face& sFace = mMesh.mFaces.back(); + + sFace.mIndices[0] = (uint16_t)stream->GetI2(); + sFace.mIndices[1] = (uint16_t)stream->GetI2(); + sFace.mIndices[2] = (uint16_t)stream->GetI2(); + + stream->IncPtr(2); // skip edge visibility flag + } + + // Resize the material array (0xcdcdcdcd marks the default material; so if a face is + // not referenced by a material, $$DEFAULT will be assigned to it) + mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd); + + // Larger 3DS files could have multiple FACE chunks here + chunkSize = stream->GetRemainingSizeToLimit(); + if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) ) + ParseFaceChunk(); + } + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a 3DS material chunk void Discreet3DSImporter::ParseMaterialChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_MAT_MATNAME: - - { - // The material name string is already zero-terminated, but we need to be sure ... - const char* sz = (const char*)stream->GetPtr(); - unsigned int cnt = 0; - while (stream->GetI1()) - ++cnt; - - if (!cnt) { - // This may not be, we use the default name instead - DefaultLogger::get()->error("3DS: Empty material name"); - } - else mScene->mMaterials.back().mName = std::string(sz,cnt); - } - break; - - case Discreet3DS::CHUNK_MAT_DIFFUSE: - { - // This is the diffuse material color - aiColor3D* pc = &mScene->mMaterials.back().mDiffuse; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk"); - pc->r = pc->g = pc->b = 1.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_SPECULAR: - { - // This is the specular material color - aiColor3D* pc = &mScene->mMaterials.back().mSpecular; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk"); - pc->r = pc->g = pc->b = 1.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_AMBIENT: - { - // This is the ambient material color - aiColor3D* pc = &mScene->mMaterials.back().mAmbient; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk"); - pc->r = pc->g = pc->b = 0.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_SELF_ILLUM: - { - // This is the emissive material color - aiColor3D* pc = &mScene->mMaterials.back().mEmissive; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk"); - pc->r = pc->g = pc->b = 0.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_TRANSPARENCY: - { - // This is the material's transparency - float* pcf = &mScene->mMaterials.back().mTransparency; - *pcf = ParsePercentageChunk(); - - // NOTE: transparency, not opacity - if (is_qnan(*pcf)) - *pcf = 1.0f; - else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f; - } - break; - - case Discreet3DS::CHUNK_MAT_SHADING: - // This is the material shading mode - mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2(); - break; - - case Discreet3DS::CHUNK_MAT_TWO_SIDE: - // This is the two-sided flag - mScene->mMaterials.back().mTwoSided = true; - break; - - case Discreet3DS::CHUNK_MAT_SHININESS: - { // This is the shininess of the material - float* pcf = &mScene->mMaterials.back().mSpecularExponent; - *pcf = ParsePercentageChunk(); - if (is_qnan(*pcf)) - *pcf = 0.0f; - else *pcf *= (float)0xFFFF; - } - break; - - case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: - { // This is the shininess strength of the material - float* pcf = &mScene->mMaterials.back().mShininessStrength; - *pcf = ParsePercentageChunk(); - if (is_qnan(*pcf)) - *pcf = 0.0f; - else *pcf *= (float)0xffff / 100.0f; - } - break; - - case Discreet3DS::CHUNK_MAT_SELF_ILPCT: - { // This is the self illumination strength of the material - float f = ParsePercentageChunk(); - if (is_qnan(f)) - f = 0.0f; - else f *= (float)0xFFFF / 100.0f; - mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f); - } - break; - - // Parse texture chunks - case Discreet3DS::CHUNK_MAT_TEXTURE: - // Diffuse texture - ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse); - break; - case Discreet3DS::CHUNK_MAT_BUMPMAP: - // Height map - ParseTextureChunk(&mScene->mMaterials.back().sTexBump); - break; - case Discreet3DS::CHUNK_MAT_OPACMAP: - // Opacity texture - ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity); - break; - case Discreet3DS::CHUNK_MAT_MAT_SHINMAP: - // Shininess map - ParseTextureChunk(&mScene->mMaterials.back().sTexShininess); - break; - case Discreet3DS::CHUNK_MAT_SPECMAP: - // Specular map - ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular); - break; - case Discreet3DS::CHUNK_MAT_SELFIMAP: - // Self-illumination (emissive) map - ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive); - break; - case Discreet3DS::CHUNK_MAT_REFLMAP: - // Reflection map - ParseTextureChunk(&mScene->mMaterials.back().sTexReflective); - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_MAT_MATNAME: + + { + // The material name string is already zero-terminated, but we need to be sure ... + const char* sz = (const char*)stream->GetPtr(); + unsigned int cnt = 0; + while (stream->GetI1()) + ++cnt; + + if (!cnt) { + // This may not be, we use the default name instead + DefaultLogger::get()->error("3DS: Empty material name"); + } + else mScene->mMaterials.back().mName = std::string(sz,cnt); + } + break; + + case Discreet3DS::CHUNK_MAT_DIFFUSE: + { + // This is the diffuse material color + aiColor3D* pc = &mScene->mMaterials.back().mDiffuse; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk"); + pc->r = pc->g = pc->b = 1.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_SPECULAR: + { + // This is the specular material color + aiColor3D* pc = &mScene->mMaterials.back().mSpecular; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk"); + pc->r = pc->g = pc->b = 1.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_AMBIENT: + { + // This is the ambient material color + aiColor3D* pc = &mScene->mMaterials.back().mAmbient; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk"); + pc->r = pc->g = pc->b = 0.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_SELF_ILLUM: + { + // This is the emissive material color + aiColor3D* pc = &mScene->mMaterials.back().mEmissive; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk"); + pc->r = pc->g = pc->b = 0.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_TRANSPARENCY: + { + // This is the material's transparency + float* pcf = &mScene->mMaterials.back().mTransparency; + *pcf = ParsePercentageChunk(); + + // NOTE: transparency, not opacity + if (is_qnan(*pcf)) + *pcf = 1.0f; + else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f; + } + break; + + case Discreet3DS::CHUNK_MAT_SHADING: + // This is the material shading mode + mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2(); + break; + + case Discreet3DS::CHUNK_MAT_TWO_SIDE: + // This is the two-sided flag + mScene->mMaterials.back().mTwoSided = true; + break; + + case Discreet3DS::CHUNK_MAT_SHININESS: + { // This is the shininess of the material + float* pcf = &mScene->mMaterials.back().mSpecularExponent; + *pcf = ParsePercentageChunk(); + if (is_qnan(*pcf)) + *pcf = 0.0f; + else *pcf *= (float)0xFFFF; + } + break; + + case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: + { // This is the shininess strength of the material + float* pcf = &mScene->mMaterials.back().mShininessStrength; + *pcf = ParsePercentageChunk(); + if (is_qnan(*pcf)) + *pcf = 0.0f; + else *pcf *= (float)0xffff / 100.0f; + } + break; + + case Discreet3DS::CHUNK_MAT_SELF_ILPCT: + { // This is the self illumination strength of the material + float f = ParsePercentageChunk(); + if (is_qnan(f)) + f = 0.0f; + else f *= (float)0xFFFF / 100.0f; + mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f); + } + break; + + // Parse texture chunks + case Discreet3DS::CHUNK_MAT_TEXTURE: + // Diffuse texture + ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse); + break; + case Discreet3DS::CHUNK_MAT_BUMPMAP: + // Height map + ParseTextureChunk(&mScene->mMaterials.back().sTexBump); + break; + case Discreet3DS::CHUNK_MAT_OPACMAP: + // Opacity texture + ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity); + break; + case Discreet3DS::CHUNK_MAT_MAT_SHINMAP: + // Shininess map + ParseTextureChunk(&mScene->mMaterials.back().sTexShininess); + break; + case Discreet3DS::CHUNK_MAT_SPECMAP: + // Specular map + ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular); + break; + case Discreet3DS::CHUNK_MAT_SELFIMAP: + // Self-illumination (emissive) map + ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive); + break; + case Discreet3DS::CHUNK_MAT_REFLMAP: + // Reflection map + ParseTextureChunk(&mScene->mMaterials.back().sTexReflective); + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_MAPFILE: - { - // The material name string is already zero-terminated, but we need to be sure ... - const char* sz = (const char*)stream->GetPtr(); - unsigned int cnt = 0; - while (stream->GetI1()) - ++cnt; - pcOut->mMapName = std::string(sz,cnt); - } - break; - - - case Discreet3DS::CHUNK_PERCENTF: - // Manually parse the blend factor - pcOut->mTextureBlend = stream->GetF4(); - break; - - case Discreet3DS::CHUNK_PERCENTW: - // Manually parse the blend factor - pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f; - break; - - case Discreet3DS::CHUNK_MAT_MAP_USCALE: - // Texture coordinate scaling in the U direction - pcOut->mScaleU = stream->GetF4(); - if (0.0f == pcOut->mScaleU) - { - DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1."); - pcOut->mScaleU = 1.0f; - } - break; - case Discreet3DS::CHUNK_MAT_MAP_VSCALE: - // Texture coordinate scaling in the V direction - pcOut->mScaleV = stream->GetF4(); - if (0.0f == pcOut->mScaleV) - { - DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1."); - pcOut->mScaleV = 1.0f; - } - break; - - case Discreet3DS::CHUNK_MAT_MAP_UOFFSET: - // Texture coordinate offset in the U direction - pcOut->mOffsetU = -stream->GetF4(); - break; - - case Discreet3DS::CHUNK_MAT_MAP_VOFFSET: - // Texture coordinate offset in the V direction - pcOut->mOffsetV = stream->GetF4(); - break; - - case Discreet3DS::CHUNK_MAT_MAP_ANG: - // Texture coordinate rotation, CCW in DEGREES - pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() ); - break; - - case Discreet3DS::CHUNK_MAT_MAP_TILING: - { - const uint16_t iFlags = stream->GetI2(); - - // Get the mapping mode (for both axes) - if (iFlags & 0x2u) - pcOut->mMapMode = aiTextureMapMode_Mirror; - - else if (iFlags & 0x10u) - pcOut->mMapMode = aiTextureMapMode_Decal; - - // wrapping in all remaining cases - else pcOut->mMapMode = aiTextureMapMode_Wrap; - } - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_MAPFILE: + { + // The material name string is already zero-terminated, but we need to be sure ... + const char* sz = (const char*)stream->GetPtr(); + unsigned int cnt = 0; + while (stream->GetI1()) + ++cnt; + pcOut->mMapName = std::string(sz,cnt); + } + break; + + + case Discreet3DS::CHUNK_PERCENTF: + // Manually parse the blend factor + pcOut->mTextureBlend = stream->GetF4(); + break; + + case Discreet3DS::CHUNK_PERCENTW: + // Manually parse the blend factor + pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f; + break; + + case Discreet3DS::CHUNK_MAT_MAP_USCALE: + // Texture coordinate scaling in the U direction + pcOut->mScaleU = stream->GetF4(); + if (0.0f == pcOut->mScaleU) + { + DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1."); + pcOut->mScaleU = 1.0f; + } + break; + case Discreet3DS::CHUNK_MAT_MAP_VSCALE: + // Texture coordinate scaling in the V direction + pcOut->mScaleV = stream->GetF4(); + if (0.0f == pcOut->mScaleV) + { + DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1."); + pcOut->mScaleV = 1.0f; + } + break; + + case Discreet3DS::CHUNK_MAT_MAP_UOFFSET: + // Texture coordinate offset in the U direction + pcOut->mOffsetU = -stream->GetF4(); + break; + + case Discreet3DS::CHUNK_MAT_MAP_VOFFSET: + // Texture coordinate offset in the V direction + pcOut->mOffsetV = stream->GetF4(); + break; + + case Discreet3DS::CHUNK_MAT_MAP_ANG: + // Texture coordinate rotation, CCW in DEGREES + pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() ); + break; + + case Discreet3DS::CHUNK_MAT_MAP_TILING: + { + const uint16_t iFlags = stream->GetI2(); + + // Get the mapping mode (for both axes) + if (iFlags & 0x2u) + pcOut->mMapMode = aiTextureMapMode_Mirror; + + else if (iFlags & 0x10u) + pcOut->mMapMode = aiTextureMapMode_Decal; + + // wrapping in all remaining cases + else pcOut->mMapMode = aiTextureMapMode_Wrap; + } + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a percentage chunk float Discreet3DSImporter::ParsePercentageChunk() { - Discreet3DS::Chunk chunk; - ReadChunk(&chunk); - - if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) - return stream->GetF4(); - else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) - return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF; - return get_qnan(); + Discreet3DS::Chunk chunk; + ReadChunk(&chunk); + + if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) + return stream->GetF4(); + else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) + return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF; + return get_qnan(); } // ------------------------------------------------------------------------------------------------ // Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color void Discreet3DSImporter::ParseColorChunk(aiColor3D* out, - bool acceptPercent) + bool acceptPercent) { - ai_assert(out != NULL); - - // error return value - const float qnan = get_qnan(); - static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan); - - Discreet3DS::Chunk chunk; - ReadChunk(&chunk); - const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk); - - bool bGamma = false; - - // Get the type of the chunk - switch(chunk.Flag) - { - case Discreet3DS::CHUNK_LINRGBF: - bGamma = true; - - case Discreet3DS::CHUNK_RGBF: - if (sizeof(float) * 3 > diff) { - *out = clrError; - return; - } - out->r = stream->GetF4(); - out->g = stream->GetF4(); - out->b = stream->GetF4(); - break; - - case Discreet3DS::CHUNK_LINRGBB: - bGamma = true; - case Discreet3DS::CHUNK_RGBB: - if (sizeof(char) * 3 > diff) { - *out = clrError; - return; - } - out->r = (float)(uint8_t)stream->GetI1() / 255.0f; - out->g = (float)(uint8_t)stream->GetI1() / 255.0f; - out->b = (float)(uint8_t)stream->GetI1() / 255.0f; - break; - - // Percentage chunks are accepted, too. - case Discreet3DS::CHUNK_PERCENTF: - if (acceptPercent && 4 <= diff) { - out->g = out->b = out->r = stream->GetF4(); - break; - } - *out = clrError; - return; - - case Discreet3DS::CHUNK_PERCENTW: - if (acceptPercent && 1 <= diff) { - out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f; - break; - } - *out = clrError; - return; - - default: - stream->IncPtr(diff); - // Skip unknown chunks, hope this won't cause any problems. - return ParseColorChunk(out,acceptPercent); - }; - (void)bGamma; + ai_assert(out != NULL); + + // error return value + const float qnan = get_qnan(); + static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan); + + Discreet3DS::Chunk chunk; + ReadChunk(&chunk); + const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk); + + bool bGamma = false; + + // Get the type of the chunk + switch(chunk.Flag) + { + case Discreet3DS::CHUNK_LINRGBF: + bGamma = true; + + case Discreet3DS::CHUNK_RGBF: + if (sizeof(float) * 3 > diff) { + *out = clrError; + return; + } + out->r = stream->GetF4(); + out->g = stream->GetF4(); + out->b = stream->GetF4(); + break; + + case Discreet3DS::CHUNK_LINRGBB: + bGamma = true; + case Discreet3DS::CHUNK_RGBB: + if (sizeof(char) * 3 > diff) { + *out = clrError; + return; + } + out->r = (float)(uint8_t)stream->GetI1() / 255.0f; + out->g = (float)(uint8_t)stream->GetI1() / 255.0f; + out->b = (float)(uint8_t)stream->GetI1() / 255.0f; + break; + + // Percentage chunks are accepted, too. + case Discreet3DS::CHUNK_PERCENTF: + if (acceptPercent && 4 <= diff) { + out->g = out->b = out->r = stream->GetF4(); + break; + } + *out = clrError; + return; + + case Discreet3DS::CHUNK_PERCENTW: + if (acceptPercent && 1 <= diff) { + out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f; + break; + } + *out = clrError; + return; + + default: + stream->IncPtr(diff); + // Skip unknown chunks, hope this won't cause any problems. + return ParseColorChunk(out,acceptPercent); + }; + (void)bGamma; } #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER |