diff options
Diffstat (limited to 'src/3rdparty/assimp/code/3DSConverter.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/3DSConverter.cpp | 1518 |
1 files changed, 762 insertions, 756 deletions
diff --git a/src/3rdparty/assimp/code/3DSConverter.cpp b/src/3rdparty/assimp/code/3DSConverter.cpp index 3498a4b21..cb6fd9077 100644 --- a/src/3rdparty/assimp/code/3DSConverter.cpp +++ b/src/3rdparty/assimp/code/3DSConverter.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,28 +25,33 @@ 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. --------------------------------------------------------------------------- */ /** @file Implementation of the 3ds importer class */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers #include "3DSLoader.h" #include "TargetAnimation.h" +#include <assimp/scene.h> +#include <assimp/DefaultLogger.hpp> +#include "StringComparison.h" +#include <memory> +#include <cctype> using namespace Assimp; @@ -54,808 +59,809 @@ using namespace Assimp; // Setup final material indices, generae a default material if necessary void Discreet3DSImporter::ReplaceDefaultMaterial() { - - // Try to find an existing material that matches the - // typical default material setting: - // - no textures - // - diffuse color (in grey!) - // NOTE: This is here to workaround the fact that some - // exporters are writing a default material, too. - unsigned int idx = 0xcdcdcdcd; - for (unsigned int i = 0; i < mScene->mMaterials.size();++i) - { - std::string s = mScene->mMaterials[i].mName; - for (std::string::iterator it = s.begin(); it != s.end(); ++it) - *it = ::tolower(*it); - - if (std::string::npos == s.find("default"))continue; - - if (mScene->mMaterials[i].mDiffuse.r != - mScene->mMaterials[i].mDiffuse.g || - mScene->mMaterials[i].mDiffuse.r != - mScene->mMaterials[i].mDiffuse.b)continue; - - if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || - mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || - mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || - mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || - mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || - mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) - { - continue; - } - idx = i; - } - if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); - - // now iterate through all meshes and through all faces and - // find all faces that are using the default material - unsigned int cnt = 0; - for (std::vector<D3DS::Mesh>::iterator - i = mScene->mMeshes.begin(); - i != mScene->mMeshes.end();++i) - { - for (std::vector<unsigned int>::iterator - a = (*i).mFaceMaterials.begin(); - a != (*i).mFaceMaterials.end();++a) - { - // NOTE: The additional check seems to be necessary, - // some exporters seem to generate invalid data here - if (0xcdcdcdcd == (*a)) - { - (*a) = idx; - ++cnt; - } - else if ( (*a) >= mScene->mMaterials.size()) - { - (*a) = idx; - DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); - ++cnt; - } - } - } - if (cnt && idx == mScene->mMaterials.size()) - { - // We need to create our own default material - D3DS::Material sMat; - sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); - sMat.mName = "%%%DEFAULT"; - mScene->mMaterials.push_back(sMat); - - DefaultLogger::get()->info("3DS: Generating default material"); - } + + // Try to find an existing material that matches the + // typical default material setting: + // - no textures + // - diffuse color (in grey!) + // NOTE: This is here to workaround the fact that some + // exporters are writing a default material, too. + unsigned int idx = 0xcdcdcdcd; + for (unsigned int i = 0; i < mScene->mMaterials.size();++i) + { + std::string s = mScene->mMaterials[i].mName; + for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) { + *it = static_cast< char >( ::tolower( *it ) ); + } + + if (std::string::npos == s.find("default"))continue; + + if (mScene->mMaterials[i].mDiffuse.r != + mScene->mMaterials[i].mDiffuse.g || + mScene->mMaterials[i].mDiffuse.r != + mScene->mMaterials[i].mDiffuse.b)continue; + + if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || + mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || + mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || + mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || + mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || + mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) + { + continue; + } + idx = i; + } + if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); + + // now iterate through all meshes and through all faces and + // find all faces that are using the default material + unsigned int cnt = 0; + for (std::vector<D3DS::Mesh>::iterator + i = mScene->mMeshes.begin(); + i != mScene->mMeshes.end();++i) + { + for (std::vector<unsigned int>::iterator + a = (*i).mFaceMaterials.begin(); + a != (*i).mFaceMaterials.end();++a) + { + // NOTE: The additional check seems to be necessary, + // some exporters seem to generate invalid data here + if (0xcdcdcdcd == (*a)) + { + (*a) = idx; + ++cnt; + } + else if ( (*a) >= mScene->mMaterials.size()) + { + (*a) = idx; + DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); + ++cnt; + } + } + } + if (cnt && idx == mScene->mMaterials.size()) + { + // We need to create our own default material + D3DS::Material sMat; + sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); + sMat.mName = "%%%DEFAULT"; + mScene->mMaterials.push_back(sMat); + + DefaultLogger::get()->info("3DS: Generating default material"); + } } // ------------------------------------------------------------------------------------------------ // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) { - for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) - { - // check whether all indices are in range - for (unsigned int a = 0; a < 3;++a) - { - if ((*i).mIndices[a] >= sMesh.mPositions.size()) - { - DefaultLogger::get()->warn("3DS: Vertex index overflow)"); - (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; - } - if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) - { - DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); - (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; - } - } - } + for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) + { + // check whether all indices are in range + for (unsigned int a = 0; a < 3;++a) + { + if ((*i).mIndices[a] >= sMesh.mPositions.size()) + { + DefaultLogger::get()->warn("3DS: Vertex index overflow)"); + (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; + } + if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) + { + DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); + (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; + } + } + } } // ------------------------------------------------------------------------------------------------ // Generate out unique verbose format representation void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) { - // TODO: really necessary? I don't think. Just a waste of memory and time - // to do it now in a separate buffer. - - // Allocate output storage - std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3); - std::vector<aiVector3D> vNew2; - if (sMesh.mTexCoords.size()) - vNew2.resize(sMesh.mFaces.size() * 3); - - for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) - { - D3DS::Face& face = sMesh.mFaces[i]; - - // Positions - for (unsigned int a = 0; a < 3;++a,++base) - { - vNew[base] = sMesh.mPositions[face.mIndices[a]]; - if (sMesh.mTexCoords.size()) - vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; - - face.mIndices[a] = base; - } - } - sMesh.mPositions = vNew; - sMesh.mTexCoords = vNew2; + // TODO: really necessary? I don't think. Just a waste of memory and time + // to do it now in a separate buffer. + + // Allocate output storage + std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3); + std::vector<aiVector3D> vNew2; + if (sMesh.mTexCoords.size()) + vNew2.resize(sMesh.mFaces.size() * 3); + + for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) + { + D3DS::Face& face = sMesh.mFaces[i]; + + // Positions + for (unsigned int a = 0; a < 3;++a,++base) + { + vNew[base] = sMesh.mPositions[face.mIndices[a]]; + if (sMesh.mTexCoords.size()) + vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; + + face.mIndices[a] = base; + } + } + sMesh.mPositions = vNew; + sMesh.mTexCoords = vNew2; } // ------------------------------------------------------------------------------------------------ // Convert a 3DS texture to texture keys in an aiMaterial void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) { - // Setup the texture name - aiString tex; - tex.Set( texture.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); - - // Setup the texture blend factor - if (is_not_qnan(texture.mTextureBlend)) - mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); - - // Setup the texture mapping mode - mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); - mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); - - // Mirroring - double the scaling values - // FIXME: this is not really correct ... - if (texture.mMapMode == aiTextureMapMode_Mirror) - { - texture.mScaleU *= 2.f; - texture.mScaleV *= 2.f; - texture.mOffsetU /= 2.f; - texture.mOffsetV /= 2.f; - } - - // Setup texture UV transformations - mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); + // Setup the texture name + aiString tex; + tex.Set( texture.mMapName); + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + + // Setup the texture blend factor + if (is_not_qnan(texture.mTextureBlend)) + mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + + // Setup the texture mapping mode + mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); + mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); + + // Mirroring - double the scaling values + // FIXME: this is not really correct ... + if (texture.mMapMode == aiTextureMapMode_Mirror) + { + texture.mScaleU *= 2.f; + texture.mScaleV *= 2.f; + texture.mOffsetU /= 2.f; + texture.mOffsetV /= 2.f; + } + + // Setup texture UV transformations + mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); } // ------------------------------------------------------------------------------------------------ // Convert a 3DS material to an aiMaterial void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, - aiMaterial& mat) + aiMaterial& mat) { - // NOTE: Pass the background image to the viewer by bypassing the - // material system. This is an evil hack, never do it again! - if (0 != mBackgroundImage.length() && bHasBG) - { - aiString tex; - tex.Set( mBackgroundImage); - mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); - - // Be sure this is only done for the first material - mBackgroundImage = std::string(""); - } - - // At first add the base ambient color of the scene to the material - oldMat.mAmbient.r += mClrAmbient.r; - oldMat.mAmbient.g += mClrAmbient.g; - oldMat.mAmbient.b += mClrAmbient.b; - - aiString name; - name.Set( oldMat.mName); - mat.AddProperty( &name, AI_MATKEY_NAME); - - // Material colors - mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); - mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); - mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); - - // Phong shininess and shininess strength - if (D3DS::Discreet3DS::Phong == oldMat.mShading || - D3DS::Discreet3DS::Metal == oldMat.mShading) - { - if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) - { - oldMat.mShading = D3DS::Discreet3DS::Gouraud; - } - else - { - mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); - mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); - } - } - - // Opacity - mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); - - // Bump height scaling - mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); - - // Two sided rendering? - if (oldMat.mTwoSided) - { - int i = 1; - mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED); - } - - // Shading mode - aiShadingMode eShading = aiShadingMode_NoShading; - switch (oldMat.mShading) - { - case D3DS::Discreet3DS::Flat: - eShading = aiShadingMode_Flat; break; - - // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse shading - case D3DS::Discreet3DS::Wire: - { - // Set the wireframe flag - unsigned int iWire = 1; - mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } - - case D3DS::Discreet3DS::Gouraud: - eShading = aiShadingMode_Gouraud; break; - - // assume cook-torrance shading for metals. - case D3DS::Discreet3DS::Phong : - eShading = aiShadingMode_Phong; break; - - case D3DS::Discreet3DS::Metal : - eShading = aiShadingMode_CookTorrance; break; - - // FIX to workaround a warning with GCC 4 who complained - // about a missing case Blinn: here - Blinn isn't a valid - // value in the 3DS Loader, it is just needed for ASE - case D3DS::Discreet3DS::Blinn : - eShading = aiShadingMode_Blinn; break; - } - mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); - - // DIFFUSE texture - if( oldMat.sTexDiffuse.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); - - // SPECULAR texture - if( oldMat.sTexSpecular.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); - - // OPACITY texture - if( oldMat.sTexOpacity.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); - - // EMISSIVE texture - if( oldMat.sTexEmissive.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); - - // BUMP texture - if( oldMat.sTexBump.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); - - // SHININESS texture - if( oldMat.sTexShininess.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); - - // REFLECTION texture - if( oldMat.sTexReflective.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); - - // Store the name of the material itself, too - if( oldMat.mName.length()) { - aiString tex; - tex.Set( oldMat.mName); - mat.AddProperty( &tex, AI_MATKEY_NAME); - } + // NOTE: Pass the background image to the viewer by bypassing the + // material system. This is an evil hack, never do it again! + if (0 != mBackgroundImage.length() && bHasBG) + { + aiString tex; + tex.Set( mBackgroundImage); + mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); + + // Be sure this is only done for the first material + mBackgroundImage = std::string(""); + } + + // At first add the base ambient color of the scene to the material + oldMat.mAmbient.r += mClrAmbient.r; + oldMat.mAmbient.g += mClrAmbient.g; + oldMat.mAmbient.b += mClrAmbient.b; + + aiString name; + name.Set( oldMat.mName); + mat.AddProperty( &name, AI_MATKEY_NAME); + + // Material colors + mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); + + // Phong shininess and shininess strength + if (D3DS::Discreet3DS::Phong == oldMat.mShading || + D3DS::Discreet3DS::Metal == oldMat.mShading) + { + if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) + { + oldMat.mShading = D3DS::Discreet3DS::Gouraud; + } + else + { + mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); + mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); + } + } + + // Opacity + mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); + + // Bump height scaling + mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); + + // Two sided rendering? + if (oldMat.mTwoSided) + { + int i = 1; + mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED); + } + + // Shading mode + aiShadingMode eShading = aiShadingMode_NoShading; + switch (oldMat.mShading) + { + case D3DS::Discreet3DS::Flat: + eShading = aiShadingMode_Flat; break; + + // I don't know what "Wire" shading should be, + // assume it is simple lambertian diffuse shading + case D3DS::Discreet3DS::Wire: + { + // Set the wireframe flag + unsigned int iWire = 1; + mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); + } + + case D3DS::Discreet3DS::Gouraud: + eShading = aiShadingMode_Gouraud; break; + + // assume cook-torrance shading for metals. + case D3DS::Discreet3DS::Phong : + eShading = aiShadingMode_Phong; break; + + case D3DS::Discreet3DS::Metal : + eShading = aiShadingMode_CookTorrance; break; + + // FIX to workaround a warning with GCC 4 who complained + // about a missing case Blinn: here - Blinn isn't a valid + // value in the 3DS Loader, it is just needed for ASE + case D3DS::Discreet3DS::Blinn : + eShading = aiShadingMode_Blinn; break; + } + mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); + + // DIFFUSE texture + if( oldMat.sTexDiffuse.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); + + // SPECULAR texture + if( oldMat.sTexSpecular.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); + + // OPACITY texture + if( oldMat.sTexOpacity.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); + + // EMISSIVE texture + if( oldMat.sTexEmissive.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); + + // BUMP texture + if( oldMat.sTexBump.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); + + // SHININESS texture + if( oldMat.sTexShininess.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); + + // REFLECTION texture + if( oldMat.sTexReflective.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); + + // Store the name of the material itself, too + if( oldMat.mName.length()) { + aiString tex; + tex.Set( oldMat.mName); + mat.AddProperty( &tex, AI_MATKEY_NAME); + } } // ------------------------------------------------------------------------------------------------ // Split meshes by their materials and generate output aiMesh'es void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) { - std::vector<aiMesh*> avOutMeshes; - avOutMeshes.reserve(mScene->mMeshes.size() * 2); - - unsigned int iFaceCnt = 0,num = 0; - aiString name; - - // we need to split all meshes by their materials - for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { - boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]); - - name.length = ASSIMP_itoa10(name.data,num++); - - unsigned int iNum = 0; - for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin(); - a != (*i).mFaceMaterials.end();++a,++iNum) - { - aiSplit[*a].push_back(iNum); - } - // now generate submeshes - for (unsigned int p = 0; p < mScene->mMaterials.size();++p) - { - if (aiSplit[p].empty()) { - continue; - } - aiMesh* meshOut = new aiMesh(); - meshOut->mName = name; - meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - // be sure to setup the correct material index - meshOut->mMaterialIndex = p; - - // use the color data as temporary storage - meshOut->mColors[0] = (aiColor4D*)(&*i); - avOutMeshes.push_back(meshOut); - - // convert vertices - meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); - meshOut->mNumVertices = meshOut->mNumFaces*3; - - // allocate enough storage for faces - meshOut->mFaces = new aiFace[meshOut->mNumFaces]; - iFaceCnt += meshOut->mNumFaces; - - meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; - meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; - if ((*i).mTexCoords.size()) - { - meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; - } - for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) - { - unsigned int index = aiSplit[p][q]; - aiFace& face = meshOut->mFaces[q]; - - face.mIndices = new unsigned int[3]; - face.mNumIndices = 3; - - for (unsigned int a = 0; a < 3;++a,++base) - { - unsigned int idx = (*i).mFaces[index].mIndices[a]; - meshOut->mVertices[base] = (*i).mPositions[idx]; - meshOut->mNormals [base] = (*i).mNormals[idx]; - - if ((*i).mTexCoords.size()) - meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; - - face.mIndices[a] = base; - } - } - } - } - - // Copy them to the output array - pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); - pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); - for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { - pcOut->mMeshes[a] = avOutMeshes[a]; - } - - // We should have at least one face here - if (!iFaceCnt) { - throw DeadlyImportError("No faces loaded. The mesh is empty"); - } + std::vector<aiMesh*> avOutMeshes; + avOutMeshes.reserve(mScene->mMeshes.size() * 2); + + unsigned int iFaceCnt = 0,num = 0; + aiString name; + + // we need to split all meshes by their materials + for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { + std::unique_ptr< std::vector<unsigned int>[] > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]); + + name.length = ASSIMP_itoa10(name.data,num++); + + unsigned int iNum = 0; + for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin(); + a != (*i).mFaceMaterials.end();++a,++iNum) + { + aiSplit[*a].push_back(iNum); + } + // now generate submeshes + for (unsigned int p = 0; p < mScene->mMaterials.size();++p) + { + if (aiSplit[p].empty()) { + continue; + } + aiMesh* meshOut = new aiMesh(); + meshOut->mName = name; + meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + // be sure to setup the correct material index + meshOut->mMaterialIndex = p; + + // use the color data as temporary storage + meshOut->mColors[0] = (aiColor4D*)(&*i); + avOutMeshes.push_back(meshOut); + + // convert vertices + meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); + meshOut->mNumVertices = meshOut->mNumFaces*3; + + // allocate enough storage for faces + meshOut->mFaces = new aiFace[meshOut->mNumFaces]; + iFaceCnt += meshOut->mNumFaces; + + meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; + meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; + if ((*i).mTexCoords.size()) + { + meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; + } + for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) + { + unsigned int index = aiSplit[p][q]; + aiFace& face = meshOut->mFaces[q]; + + face.mIndices = new unsigned int[3]; + face.mNumIndices = 3; + + for (unsigned int a = 0; a < 3;++a,++base) + { + unsigned int idx = (*i).mFaces[index].mIndices[a]; + meshOut->mVertices[base] = (*i).mPositions[idx]; + meshOut->mNormals [base] = (*i).mNormals[idx]; + + if ((*i).mTexCoords.size()) + meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; + + face.mIndices[a] = base; + } + } + } + } + + // Copy them to the output array + pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); + pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); + for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { + pcOut->mMeshes[a] = avOutMeshes[a]; + } + + // We should have at least one face here + if (!iFaceCnt) { + throw DeadlyImportError("No faces loaded. The mesh is empty"); + } } // ------------------------------------------------------------------------------------------------ // Add a node to the scenegraph and setup its final transformation void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, - D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) + D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) { - std::vector<unsigned int> iArray; - iArray.reserve(3); - - aiMatrix4x4 abs; - - // Find all meshes with the same name as the node - for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) - { - const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; - ai_assert(NULL != pcMesh); - - if (pcIn->mName == pcMesh->mName) - iArray.push_back(a); - } - if (!iArray.empty()) - { - // The matrix should be identical for all meshes with the - // same name. It HAS to be identical for all meshes ..... - D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); - - // Compute the inverse of the transformation matrix to move the - // vertices back to their relative and local space - aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; - mInv.Inverse();mInvTransposed.Transpose(); - aiVector3D pivot = pcIn->vPivot; - - pcOut->mNumMeshes = (unsigned int)iArray.size(); - pcOut->mMeshes = new unsigned int[iArray.size()]; - for (unsigned int i = 0;i < iArray.size();++i) { - const unsigned int iIndex = iArray[i]; - aiMesh* const mesh = pcSOut->mMeshes[iIndex]; - - if (mesh->mColors[1] == NULL) - { - // Transform the vertices back into their local space - // fixme: consider computing normals after this, so we don't need to transform them - const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices; - aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; - - for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) { - *pvCurrent = mInv * (*pvCurrent); - *t2 = mInvTransposed * (*t2); - } - - // Handle negative transformation matrix determinant -> invert vertex x - if (imesh->mMat.Determinant() < 0.0f) - { - /* we *must* have normals */ - for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) { - pvCurrent->x *= -1.f; - t2->x *= -1.f; - } - DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); - } - - // Handle pivot point - if (pivot.x || pivot.y || pivot.z) - { - for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { - *pvCurrent -= pivot; - } - } - - mesh->mColors[1] = (aiColor4D*)1; - } - else - mesh->mColors[1] = (aiColor4D*)1; - - // Setup the mesh index - pcOut->mMeshes[i] = iIndex; - } - } - - // Setup the name of the node - // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number - if (pcIn->mInstanceNumber > 1) - { - char tmp[12]; - ASSIMP_itoa10(tmp, pcIn->mInstanceNumber); - std::string tempStr = pcIn->mName + "_inst_"; - tempStr += tmp; - pcOut->mName.Set(tempStr); - } - else - pcOut->mName.Set(pcIn->mName); - - // Now build the transformation matrix of the node - // ROTATION - if (pcIn->aRotationKeys.size()){ - - // FIX to get to Assimp's quaternion conventions - for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { - (*it).mValue.w *= -1.f; - } - - pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); - } - else if (pcIn->aCameraRollKeys.size()) - { - aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), - pcOut->mTransformation); - } - - // SCALING - aiMatrix4x4& m = pcOut->mTransformation; - if (pcIn->aScalingKeys.size()) - { - const aiVector3D& v = pcIn->aScalingKeys[0].mValue; - m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; - m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; - m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; - } - - // TRANSLATION - if (pcIn->aPositionKeys.size()) - { - const aiVector3D& v = pcIn->aPositionKeys[0].mValue; - m.a4 += v.x; - m.b4 += v.y; - m.c4 += v.z; - } - - // Generate animation channels for the node - if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || - pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || - pcIn->aTargetPositionKeys.size() > 1) - { - aiAnimation* anim = pcSOut->mAnimations[0]; - ai_assert(NULL != anim); - - if (pcIn->aCameraRollKeys.size() > 1) - { - DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); - - // Camera roll keys - in fact they're just rotations - // around the camera's z axis. The angles are given - // in degrees (and they're clockwise). - pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); - for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) - { - aiQuatKey& q = pcIn->aRotationKeys[i]; - aiFloatKey& f = pcIn->aCameraRollKeys[i]; - - q.mTime = f.mTime; - - // FIX to get to Assimp quaternion conventions - q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); - } - } + std::vector<unsigned int> iArray; + iArray.reserve(3); + + aiMatrix4x4 abs; + + // Find all meshes with the same name as the node + for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) + { + const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; + ai_assert(NULL != pcMesh); + + if (pcIn->mName == pcMesh->mName) + iArray.push_back(a); + } + if (!iArray.empty()) + { + // The matrix should be identical for all meshes with the + // same name. It HAS to be identical for all meshes ..... + D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); + + // Compute the inverse of the transformation matrix to move the + // vertices back to their relative and local space + aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; + mInv.Inverse();mInvTransposed.Transpose(); + aiVector3D pivot = pcIn->vPivot; + + pcOut->mNumMeshes = (unsigned int)iArray.size(); + pcOut->mMeshes = new unsigned int[iArray.size()]; + for (unsigned int i = 0;i < iArray.size();++i) { + const unsigned int iIndex = iArray[i]; + aiMesh* const mesh = pcSOut->mMeshes[iIndex]; + + if (mesh->mColors[1] == NULL) + { + // Transform the vertices back into their local space + // fixme: consider computing normals after this, so we don't need to transform them + const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices; + aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; + + for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) { + *pvCurrent = mInv * (*pvCurrent); + *t2 = mInvTransposed * (*t2); + } + + // Handle negative transformation matrix determinant -> invert vertex x + if (imesh->mMat.Determinant() < 0.0f) + { + /* we *must* have normals */ + for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) { + pvCurrent->x *= -1.f; + t2->x *= -1.f; + } + DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); + } + + // Handle pivot point + if (pivot.x || pivot.y || pivot.z) + { + for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { + *pvCurrent -= pivot; + } + } + + mesh->mColors[1] = (aiColor4D*)1; + } + else + mesh->mColors[1] = (aiColor4D*)1; + + // Setup the mesh index + pcOut->mMeshes[i] = iIndex; + } + } + + // Setup the name of the node + // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number + if (pcIn->mInstanceNumber > 1) + { + char tmp[12]; + ASSIMP_itoa10(tmp, pcIn->mInstanceNumber); + std::string tempStr = pcIn->mName + "_inst_"; + tempStr += tmp; + pcOut->mName.Set(tempStr); + } + else + pcOut->mName.Set(pcIn->mName); + + // Now build the transformation matrix of the node + // ROTATION + if (pcIn->aRotationKeys.size()){ + + // FIX to get to Assimp's quaternion conventions + for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { + (*it).mValue.w *= -1.f; + } + + pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); + } + else if (pcIn->aCameraRollKeys.size()) + { + aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), + pcOut->mTransformation); + } + + // SCALING + aiMatrix4x4& m = pcOut->mTransformation; + if (pcIn->aScalingKeys.size()) + { + const aiVector3D& v = pcIn->aScalingKeys[0].mValue; + m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; + m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; + m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; + } + + // TRANSLATION + if (pcIn->aPositionKeys.size()) + { + const aiVector3D& v = pcIn->aPositionKeys[0].mValue; + m.a4 += v.x; + m.b4 += v.y; + m.c4 += v.z; + } + + // Generate animation channels for the node + if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || + pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || + pcIn->aTargetPositionKeys.size() > 1) + { + aiAnimation* anim = pcSOut->mAnimations[0]; + ai_assert(NULL != anim); + + if (pcIn->aCameraRollKeys.size() > 1) + { + DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); + + // Camera roll keys - in fact they're just rotations + // around the camera's z axis. The angles are given + // in degrees (and they're clockwise). + pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); + for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) + { + aiQuatKey& q = pcIn->aRotationKeys[i]; + aiFloatKey& f = pcIn->aCameraRollKeys[i]; + + q.mTime = f.mTime; + + // FIX to get to Assimp quaternion conventions + q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); + } + } #if 0 - if (pcIn->aTargetPositionKeys.size() > 1) - { - DefaultLogger::get()->debug("3DS: Converting target track ..."); - - // Camera or spot light - need to convert the separate - // target position channel to our representation - TargetAnimationHelper helper; - - if (pcIn->aPositionKeys.empty()) - { - // We can just pass zero here ... - helper.SetFixedMainAnimationChannel(aiVector3D()); - } - else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); - helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); - - // Do the conversion - std::vector<aiVectorKey> distanceTrack; - helper.Process(&distanceTrack); - - // Now add a new node as child, name it <ourName>.Target - // and assign the distance track to it. This is that the - // information where the target is and how it moves is - // not lost - D3DS::Node* nd = new D3DS::Node(); - pcIn->push_back(nd); - - nd->mName = pcIn->mName + ".Target"; - - aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); - nda->mNodeName.Set(nd->mName); - - nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); - nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - ::memcpy(nda->mPositionKeys,&distanceTrack[0], - sizeof(aiVectorKey)*nda->mNumPositionKeys); - } + if (pcIn->aTargetPositionKeys.size() > 1) + { + DefaultLogger::get()->debug("3DS: Converting target track ..."); + + // Camera or spot light - need to convert the separate + // target position channel to our representation + TargetAnimationHelper helper; + + if (pcIn->aPositionKeys.empty()) + { + // We can just pass zero here ... + helper.SetFixedMainAnimationChannel(aiVector3D()); + } + else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); + helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); + + // Do the conversion + std::vector<aiVectorKey> distanceTrack; + helper.Process(&distanceTrack); + + // Now add a new node as child, name it <ourName>.Target + // and assign the distance track to it. This is that the + // information where the target is and how it moves is + // not lost + D3DS::Node* nd = new D3DS::Node(); + pcIn->push_back(nd); + + nd->mName = pcIn->mName + ".Target"; + + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + nda->mNodeName.Set(nd->mName); + + nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; + ::memcpy(nda->mPositionKeys,&distanceTrack[0], + sizeof(aiVectorKey)*nda->mNumPositionKeys); + } #endif - // 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. - for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { - if (pcSOut->mCameras[n]->mName == pcOut->mName) { - pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); - } - } - for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { - if (pcSOut->mLights[n]->mName == pcOut->mName) { - pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); - } - } - - // Allocate a new node anim and setup its name - aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); - nda->mNodeName.Set(pcIn->mName); - - // POSITION keys - if (pcIn->aPositionKeys.size() > 0) - { - nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); - nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], - sizeof(aiVectorKey)*nda->mNumPositionKeys); - } - - // ROTATION keys - if (pcIn->aRotationKeys.size() > 0) - { - nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); - nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; - - // Rotations are quaternion offsets - aiQuaternion abs; - for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) - { - const aiQuatKey& q = pcIn->aRotationKeys[n]; - - abs = (n ? abs * q.mValue : q.mValue); - nda->mRotationKeys[n].mTime = q.mTime; - nda->mRotationKeys[n].mValue = abs.Normalize(); - } - } - - // SCALING keys - if (pcIn->aScalingKeys.size() > 0) - { - nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); - nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; - ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], - sizeof(aiVectorKey)*nda->mNumScalingKeys); - } - } - - // Allocate storage for children - pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); - pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; - - // Recursively process all children - const unsigned int size = pcIn->mChildren.size(); - for (unsigned int i = 0; i < size;++i) - { - pcOut->mChildren[i] = new aiNode(); - pcOut->mChildren[i]->mParent = pcOut; - AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); - } + // 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. + for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { + if (pcSOut->mCameras[n]->mName == pcOut->mName) { + pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); + } + } + for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { + if (pcSOut->mLights[n]->mName == pcOut->mName) { + pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); + } + } + + // Allocate a new node anim and setup its name + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + nda->mNodeName.Set(pcIn->mName); + + // POSITION keys + if (pcIn->aPositionKeys.size() > 0) + { + nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; + ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], + sizeof(aiVectorKey)*nda->mNumPositionKeys); + } + + // ROTATION keys + if (pcIn->aRotationKeys.size() > 0) + { + nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); + nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; + + // Rotations are quaternion offsets + aiQuaternion abs1; + for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) + { + const aiQuatKey& q = pcIn->aRotationKeys[n]; + + abs1 = (n ? abs1 * q.mValue : q.mValue); + nda->mRotationKeys[n].mTime = q.mTime; + nda->mRotationKeys[n].mValue = abs1.Normalize(); + } + } + + // SCALING keys + if (pcIn->aScalingKeys.size() > 0) + { + nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); + nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; + ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], + sizeof(aiVectorKey)*nda->mNumScalingKeys); + } + } + + // Allocate storage for children + pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); + pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; + + // Recursively process all children + const unsigned int size = pcIn->mChildren.size(); + for (unsigned int i = 0; i < size;++i) + { + pcOut->mChildren[i] = new aiNode(); + pcOut->mChildren[i]->mParent = pcOut; + AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); + } } // ------------------------------------------------------------------------------------------------ // Find out how many node animation channels we'll have finally void CountTracks(D3DS::Node* node, unsigned int& cnt) { - ////////////////////////////////////////////////////////////////////////////// - // We will never generate more than one channel for a node, so - // this is rather easy here. - - if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || - node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || - node->aTargetPositionKeys.size() > 1) - { - ++cnt; - - // account for the additional channel for the camera/spotlight target position - if (node->aTargetPositionKeys.size() > 1)++cnt; - } - - // Recursively process all children - for (unsigned int i = 0; i < node->mChildren.size();++i) - CountTracks(node->mChildren[i],cnt); + ////////////////////////////////////////////////////////////////////////////// + // We will never generate more than one channel for a node, so + // this is rather easy here. + + if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || + node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || + node->aTargetPositionKeys.size() > 1) + { + ++cnt; + + // account for the additional channel for the camera/spotlight target position + if (node->aTargetPositionKeys.size() > 1)++cnt; + } + + // Recursively process all children + for (unsigned int i = 0; i < node->mChildren.size();++i) + CountTracks(node->mChildren[i],cnt); } // ------------------------------------------------------------------------------------------------ // Generate the output node graph void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) { - pcOut->mRootNode = new aiNode(); - if (0 == mRootNode->mChildren.size()) - { - ////////////////////////////////////////////////////////////////////////////// - // It seems the file is so messed up that it has not even a hierarchy. - // generate a flat hiearachy which looks like this: - // - // ROOT_NODE - // | - // ---------------------------------------- - // | | | | | - // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... - // - DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); - - pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + - mScene->mCameras.size() + mScene->mLights.size(); - - pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; - pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); - - // Build dummy nodes for all meshes - unsigned int a = 0; - for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); - pcNode->mParent = pcOut->mRootNode; - pcNode->mMeshes = new unsigned int[1]; - pcNode->mMeshes[0] = i; - pcNode->mNumMeshes = 1; - - // Build a name for the node - pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i); - } - - // Build dummy nodes for all cameras - for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); - pcNode->mParent = pcOut->mRootNode; - - // Build a name for the node - pcNode->mName = mScene->mCameras[i]->mName; - } - - // Build dummy nodes for all lights - for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); - pcNode->mParent = pcOut->mRootNode; - - // Build a name for the node - pcNode->mName = mScene->mLights[i]->mName; - } - } - else - { - // First of all: find out how many scaling, rotation and translation - // animation tracks we'll have afterwards - unsigned int numChannel = 0; - CountTracks(mRootNode,numChannel); - - if (numChannel) - { - // Allocate a primary animation channel - pcOut->mNumAnimations = 1; - pcOut->mAnimations = new aiAnimation*[1]; - aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); - - anim->mName.Set("3DSMasterAnim"); - - // Allocate enough storage for all node animation channels, - // but don't set the mNumChannels member - we'll use it to - // index into the array - anim->mChannels = new aiNodeAnim*[numChannel]; - } - - aiMatrix4x4 m; - AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); - } - - // We used the first and second vertex color set to store some temporary values so we need to cleanup here - for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) - { - pcOut->mMeshes[a]->mColors[0] = NULL; - pcOut->mMeshes[a]->mColors[1] = NULL; - } - - pcOut->mRootNode->mTransformation = aiMatrix4x4( - 1.f,0.f,0.f,0.f, - 0.f,0.f,1.f,0.f, - 0.f,-1.f,0.f,0.f, - 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; - - // If the root node is unnamed name it "<3DSRoot>" - if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || - (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) - { - pcOut->mRootNode->mName.Set("<3DSRoot>"); - } + pcOut->mRootNode = new aiNode(); + if (0 == mRootNode->mChildren.size()) + { + ////////////////////////////////////////////////////////////////////////////// + // It seems the file is so messed up that it has not even a hierarchy. + // generate a flat hiearachy which looks like this: + // + // ROOT_NODE + // | + // ---------------------------------------- + // | | | | | + // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... + // + DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); + + pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + + mScene->mCameras.size() + mScene->mLights.size(); + + pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; + pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); + + // Build dummy nodes for all meshes + unsigned int a = 0; + for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) + { + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + pcNode->mParent = pcOut->mRootNode; + pcNode->mMeshes = new unsigned int[1]; + pcNode->mMeshes[0] = i; + pcNode->mNumMeshes = 1; + + // Build a name for the node + pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u",i); + } + + // Build dummy nodes for all cameras + for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) + { + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + pcNode->mParent = pcOut->mRootNode; + + // Build a name for the node + pcNode->mName = mScene->mCameras[i]->mName; + } + + // Build dummy nodes for all lights + for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) + { + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + pcNode->mParent = pcOut->mRootNode; + + // Build a name for the node + pcNode->mName = mScene->mLights[i]->mName; + } + } + else + { + // First of all: find out how many scaling, rotation and translation + // animation tracks we'll have afterwards + unsigned int numChannel = 0; + CountTracks(mRootNode,numChannel); + + if (numChannel) + { + // Allocate a primary animation channel + pcOut->mNumAnimations = 1; + pcOut->mAnimations = new aiAnimation*[1]; + aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); + + anim->mName.Set("3DSMasterAnim"); + + // Allocate enough storage for all node animation channels, + // but don't set the mNumChannels member - we'll use it to + // index into the array + anim->mChannels = new aiNodeAnim*[numChannel]; + } + + aiMatrix4x4 m; + AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); + } + + // We used the first and second vertex color set to store some temporary values so we need to cleanup here + for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) + { + pcOut->mMeshes[a]->mColors[0] = NULL; + pcOut->mMeshes[a]->mColors[1] = NULL; + } + + pcOut->mRootNode->mTransformation = aiMatrix4x4( + 1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f, + 0.f,-1.f,0.f,0.f, + 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; + + // If the root node is unnamed name it "<3DSRoot>" + if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || + (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) + { + pcOut->mRootNode->mName.Set("<3DSRoot>"); + } } // ------------------------------------------------------------------------------------------------ // Convert all meshes in the scene and generate the final output scene. void Discreet3DSImporter::ConvertScene(aiScene* pcOut) { - // Allocate enough storage for all output materials - pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); - pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; - - // ... and convert the 3DS materials to aiMaterial's - for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) - { - aiMaterial* pcNew = new aiMaterial(); - ConvertMaterial(mScene->mMaterials[i],*pcNew); - pcOut->mMaterials[i] = pcNew; - } - - // Generate the output mesh list - ConvertMeshes(pcOut); - - // Now copy all light sources to the output scene - pcOut->mNumLights = (unsigned int)mScene->mLights.size(); - if (pcOut->mNumLights) - { - pcOut->mLights = new aiLight*[pcOut->mNumLights]; - ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); - } - - // Now copy all cameras to the output scene - pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); - if (pcOut->mNumCameras) - { - pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; - ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); - } + // Allocate enough storage for all output materials + pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); + pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; + + // ... and convert the 3DS materials to aiMaterial's + for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) + { + aiMaterial* pcNew = new aiMaterial(); + ConvertMaterial(mScene->mMaterials[i],*pcNew); + pcOut->mMaterials[i] = pcNew; + } + + // Generate the output mesh list + ConvertMeshes(pcOut); + + // Now copy all light sources to the output scene + pcOut->mNumLights = (unsigned int)mScene->mLights.size(); + if (pcOut->mNumLights) + { + pcOut->mLights = new aiLight*[pcOut->mNumLights]; + ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); + } + + // Now copy all cameras to the output scene + pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); + if (pcOut->mNumCameras) + { + pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; + ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); + } } #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER |