vrshoot
diff libs/assimp/3DSConverter.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/3DSConverter.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,841 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file Implementation of the 3ds importer class */ 1.46 + 1.47 +#include "AssimpPCH.h" 1.48 +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER 1.49 + 1.50 +// internal headers 1.51 +#include "3DSLoader.h" 1.52 +#include "TargetAnimation.h" 1.53 + 1.54 +using namespace Assimp; 1.55 + 1.56 +// ------------------------------------------------------------------------------------------------ 1.57 +// Setup final material indices, generae a default material if necessary 1.58 +void Discreet3DSImporter::ReplaceDefaultMaterial() 1.59 +{ 1.60 + 1.61 + // Try to find an existing material that matches the 1.62 + // typical default material setting: 1.63 + // - no textures 1.64 + // - diffuse color (in grey!) 1.65 + // NOTE: This is here to workaround the fact that some 1.66 + // exporters are writing a default material, too. 1.67 + unsigned int idx = 0xcdcdcdcd; 1.68 + for (unsigned int i = 0; i < mScene->mMaterials.size();++i) 1.69 + { 1.70 + std::string s = mScene->mMaterials[i].mName; 1.71 + for (std::string::iterator it = s.begin(); it != s.end(); ++it) 1.72 + *it = ::tolower(*it); 1.73 + 1.74 + if (std::string::npos == s.find("default"))continue; 1.75 + 1.76 + if (mScene->mMaterials[i].mDiffuse.r != 1.77 + mScene->mMaterials[i].mDiffuse.g || 1.78 + mScene->mMaterials[i].mDiffuse.r != 1.79 + mScene->mMaterials[i].mDiffuse.b)continue; 1.80 + 1.81 + if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || 1.82 + mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || 1.83 + mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || 1.84 + mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || 1.85 + mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || 1.86 + mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) 1.87 + { 1.88 + continue; 1.89 + } 1.90 + idx = i; 1.91 + } 1.92 + if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); 1.93 + 1.94 + // now iterate through all meshes and through all faces and 1.95 + // find all faces that are using the default material 1.96 + unsigned int cnt = 0; 1.97 + for (std::vector<D3DS::Mesh>::iterator 1.98 + i = mScene->mMeshes.begin(); 1.99 + i != mScene->mMeshes.end();++i) 1.100 + { 1.101 + for (std::vector<unsigned int>::iterator 1.102 + a = (*i).mFaceMaterials.begin(); 1.103 + a != (*i).mFaceMaterials.end();++a) 1.104 + { 1.105 + // NOTE: The additional check seems to be necessary, 1.106 + // some exporters seem to generate invalid data here 1.107 + if (0xcdcdcdcd == (*a)) 1.108 + { 1.109 + (*a) = idx; 1.110 + ++cnt; 1.111 + } 1.112 + else if ( (*a) >= mScene->mMaterials.size()) 1.113 + { 1.114 + (*a) = idx; 1.115 + DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); 1.116 + ++cnt; 1.117 + } 1.118 + } 1.119 + } 1.120 + if (cnt && idx == mScene->mMaterials.size()) 1.121 + { 1.122 + // We need to create our own default material 1.123 + D3DS::Material sMat; 1.124 + sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); 1.125 + sMat.mName = "%%%DEFAULT"; 1.126 + mScene->mMaterials.push_back(sMat); 1.127 + 1.128 + DefaultLogger::get()->info("3DS: Generating default material"); 1.129 + } 1.130 +} 1.131 + 1.132 +// ------------------------------------------------------------------------------------------------ 1.133 +// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached 1.134 +void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) 1.135 +{ 1.136 + for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) 1.137 + { 1.138 + // check whether all indices are in range 1.139 + for (unsigned int a = 0; a < 3;++a) 1.140 + { 1.141 + if ((*i).mIndices[a] >= sMesh.mPositions.size()) 1.142 + { 1.143 + DefaultLogger::get()->warn("3DS: Vertex index overflow)"); 1.144 + (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; 1.145 + } 1.146 + if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) 1.147 + { 1.148 + DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); 1.149 + (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; 1.150 + } 1.151 + } 1.152 + } 1.153 +} 1.154 + 1.155 +// ------------------------------------------------------------------------------------------------ 1.156 +// Generate out unique verbose format representation 1.157 +void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) 1.158 +{ 1.159 + // TODO: really necessary? I don't think. Just a waste of memory and time 1.160 + // to do it now in a separate buffer. 1.161 + 1.162 + // Allocate output storage 1.163 + std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3); 1.164 + std::vector<aiVector3D> vNew2; 1.165 + if (sMesh.mTexCoords.size()) 1.166 + vNew2.resize(sMesh.mFaces.size() * 3); 1.167 + 1.168 + for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) 1.169 + { 1.170 + D3DS::Face& face = sMesh.mFaces[i]; 1.171 + 1.172 + // Positions 1.173 + for (unsigned int a = 0; a < 3;++a,++base) 1.174 + { 1.175 + vNew[base] = sMesh.mPositions[face.mIndices[a]]; 1.176 + if (sMesh.mTexCoords.size()) 1.177 + vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; 1.178 + 1.179 + face.mIndices[a] = base; 1.180 + } 1.181 + } 1.182 + sMesh.mPositions = vNew; 1.183 + sMesh.mTexCoords = vNew2; 1.184 +} 1.185 + 1.186 +// ------------------------------------------------------------------------------------------------ 1.187 +// Convert a 3DS texture to texture keys in an aiMaterial 1.188 +void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) 1.189 +{ 1.190 + // Setup the texture name 1.191 + aiString tex; 1.192 + tex.Set( texture.mMapName); 1.193 + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); 1.194 + 1.195 + // Setup the texture blend factor 1.196 + if (is_not_qnan(texture.mTextureBlend)) 1.197 + mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); 1.198 + 1.199 + // Setup the texture mapping mode 1.200 + mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); 1.201 + mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); 1.202 + 1.203 + // Mirroring - double the scaling values 1.204 + // FIXME: this is not really correct ... 1.205 + if (texture.mMapMode == aiTextureMapMode_Mirror) 1.206 + { 1.207 + texture.mScaleU *= 2.f; 1.208 + texture.mScaleV *= 2.f; 1.209 + texture.mOffsetU /= 2.f; 1.210 + texture.mOffsetV /= 2.f; 1.211 + } 1.212 + 1.213 + // Setup texture UV transformations 1.214 + mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); 1.215 +} 1.216 + 1.217 +// ------------------------------------------------------------------------------------------------ 1.218 +// Convert a 3DS material to an aiMaterial 1.219 +void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, 1.220 + aiMaterial& mat) 1.221 +{ 1.222 + // NOTE: Pass the background image to the viewer by bypassing the 1.223 + // material system. This is an evil hack, never do it again! 1.224 + if (0 != mBackgroundImage.length() && bHasBG) 1.225 + { 1.226 + aiString tex; 1.227 + tex.Set( mBackgroundImage); 1.228 + mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); 1.229 + 1.230 + // Be sure this is only done for the first material 1.231 + mBackgroundImage = std::string(""); 1.232 + } 1.233 + 1.234 + // At first add the base ambient color of the scene to the material 1.235 + oldMat.mAmbient.r += mClrAmbient.r; 1.236 + oldMat.mAmbient.g += mClrAmbient.g; 1.237 + oldMat.mAmbient.b += mClrAmbient.b; 1.238 + 1.239 + aiString name; 1.240 + name.Set( oldMat.mName); 1.241 + mat.AddProperty( &name, AI_MATKEY_NAME); 1.242 + 1.243 + // Material colors 1.244 + mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); 1.245 + mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); 1.246 + mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); 1.247 + mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); 1.248 + 1.249 + // Phong shininess and shininess strength 1.250 + if (D3DS::Discreet3DS::Phong == oldMat.mShading || 1.251 + D3DS::Discreet3DS::Metal == oldMat.mShading) 1.252 + { 1.253 + if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) 1.254 + { 1.255 + oldMat.mShading = D3DS::Discreet3DS::Gouraud; 1.256 + } 1.257 + else 1.258 + { 1.259 + mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); 1.260 + mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); 1.261 + } 1.262 + } 1.263 + 1.264 + // Opacity 1.265 + mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); 1.266 + 1.267 + // Bump height scaling 1.268 + mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); 1.269 + 1.270 + // Two sided rendering? 1.271 + if (oldMat.mTwoSided) 1.272 + { 1.273 + int i = 1; 1.274 + mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED); 1.275 + } 1.276 + 1.277 + // Shading mode 1.278 + aiShadingMode eShading = aiShadingMode_NoShading; 1.279 + switch (oldMat.mShading) 1.280 + { 1.281 + case D3DS::Discreet3DS::Flat: 1.282 + eShading = aiShadingMode_Flat; break; 1.283 + 1.284 + // I don't know what "Wire" shading should be, 1.285 + // assume it is simple lambertian diffuse shading 1.286 + case D3DS::Discreet3DS::Wire: 1.287 + { 1.288 + // Set the wireframe flag 1.289 + unsigned int iWire = 1; 1.290 + mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); 1.291 + } 1.292 + 1.293 + case D3DS::Discreet3DS::Gouraud: 1.294 + eShading = aiShadingMode_Gouraud; break; 1.295 + 1.296 + // assume cook-torrance shading for metals. 1.297 + case D3DS::Discreet3DS::Phong : 1.298 + eShading = aiShadingMode_Phong; break; 1.299 + 1.300 + case D3DS::Discreet3DS::Metal : 1.301 + eShading = aiShadingMode_CookTorrance; break; 1.302 + 1.303 + // FIX to workaround a warning with GCC 4 who complained 1.304 + // about a missing case Blinn: here - Blinn isn't a valid 1.305 + // value in the 3DS Loader, it is just needed for ASE 1.306 + case D3DS::Discreet3DS::Blinn : 1.307 + eShading = aiShadingMode_Blinn; break; 1.308 + } 1.309 + mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); 1.310 + 1.311 + // DIFFUSE texture 1.312 + if( oldMat.sTexDiffuse.mMapName.length() > 0) 1.313 + CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); 1.314 + 1.315 + // SPECULAR texture 1.316 + if( oldMat.sTexSpecular.mMapName.length() > 0) 1.317 + CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); 1.318 + 1.319 + // OPACITY texture 1.320 + if( oldMat.sTexOpacity.mMapName.length() > 0) 1.321 + CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); 1.322 + 1.323 + // EMISSIVE texture 1.324 + if( oldMat.sTexEmissive.mMapName.length() > 0) 1.325 + CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); 1.326 + 1.327 + // BUMP texture 1.328 + if( oldMat.sTexBump.mMapName.length() > 0) 1.329 + CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); 1.330 + 1.331 + // SHININESS texture 1.332 + if( oldMat.sTexShininess.mMapName.length() > 0) 1.333 + CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); 1.334 + 1.335 + // REFLECTION texture 1.336 + if( oldMat.sTexReflective.mMapName.length() > 0) 1.337 + CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); 1.338 + 1.339 + // Store the name of the material itself, too 1.340 + if( oldMat.mName.length()) { 1.341 + aiString tex; 1.342 + tex.Set( oldMat.mName); 1.343 + mat.AddProperty( &tex, AI_MATKEY_NAME); 1.344 + } 1.345 +} 1.346 + 1.347 +// ------------------------------------------------------------------------------------------------ 1.348 +// Split meshes by their materials and generate output aiMesh'es 1.349 +void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) 1.350 +{ 1.351 + std::vector<aiMesh*> avOutMeshes; 1.352 + avOutMeshes.reserve(mScene->mMeshes.size() * 2); 1.353 + 1.354 + unsigned int iFaceCnt = 0,num = 0; 1.355 + aiString name; 1.356 + 1.357 + // we need to split all meshes by their materials 1.358 + for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { 1.359 + boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]); 1.360 + 1.361 + name.length = ASSIMP_itoa10(name.data,num++); 1.362 + 1.363 + unsigned int iNum = 0; 1.364 + for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin(); 1.365 + a != (*i).mFaceMaterials.end();++a,++iNum) 1.366 + { 1.367 + aiSplit[*a].push_back(iNum); 1.368 + } 1.369 + // now generate submeshes 1.370 + for (unsigned int p = 0; p < mScene->mMaterials.size();++p) 1.371 + { 1.372 + if (aiSplit[p].empty()) { 1.373 + continue; 1.374 + } 1.375 + aiMesh* meshOut = new aiMesh(); 1.376 + meshOut->mName = name; 1.377 + meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.378 + 1.379 + // be sure to setup the correct material index 1.380 + meshOut->mMaterialIndex = p; 1.381 + 1.382 + // use the color data as temporary storage 1.383 + meshOut->mColors[0] = (aiColor4D*)(&*i); 1.384 + avOutMeshes.push_back(meshOut); 1.385 + 1.386 + // convert vertices 1.387 + meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); 1.388 + meshOut->mNumVertices = meshOut->mNumFaces*3; 1.389 + 1.390 + // allocate enough storage for faces 1.391 + meshOut->mFaces = new aiFace[meshOut->mNumFaces]; 1.392 + iFaceCnt += meshOut->mNumFaces; 1.393 + 1.394 + meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; 1.395 + meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; 1.396 + if ((*i).mTexCoords.size()) 1.397 + { 1.398 + meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; 1.399 + } 1.400 + for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) 1.401 + { 1.402 + register unsigned int index = aiSplit[p][q]; 1.403 + aiFace& face = meshOut->mFaces[q]; 1.404 + 1.405 + face.mIndices = new unsigned int[3]; 1.406 + face.mNumIndices = 3; 1.407 + 1.408 + for (unsigned int a = 0; a < 3;++a,++base) 1.409 + { 1.410 + unsigned int idx = (*i).mFaces[index].mIndices[a]; 1.411 + meshOut->mVertices[base] = (*i).mPositions[idx]; 1.412 + meshOut->mNormals [base] = (*i).mNormals[idx]; 1.413 + 1.414 + if ((*i).mTexCoords.size()) 1.415 + meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; 1.416 + 1.417 + face.mIndices[a] = base; 1.418 + } 1.419 + } 1.420 + } 1.421 + } 1.422 + 1.423 + // Copy them to the output array 1.424 + pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); 1.425 + pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); 1.426 + for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { 1.427 + pcOut->mMeshes[a] = avOutMeshes[a]; 1.428 + } 1.429 + 1.430 + // We should have at least one face here 1.431 + if (!iFaceCnt) { 1.432 + throw DeadlyImportError("No faces loaded. The mesh is empty"); 1.433 + } 1.434 +} 1.435 + 1.436 +// ------------------------------------------------------------------------------------------------ 1.437 +// Add a node to the scenegraph and setup its final transformation 1.438 +void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, 1.439 + D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) 1.440 +{ 1.441 + std::vector<unsigned int> iArray; 1.442 + iArray.reserve(3); 1.443 + 1.444 + aiMatrix4x4 abs; 1.445 + 1.446 + // Find all meshes with the same name as the node 1.447 + for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) 1.448 + { 1.449 + const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; 1.450 + ai_assert(NULL != pcMesh); 1.451 + 1.452 + if (pcIn->mName == pcMesh->mName) 1.453 + iArray.push_back(a); 1.454 + } 1.455 + if (!iArray.empty()) 1.456 + { 1.457 + // The matrix should be identical for all meshes with the 1.458 + // same name. It HAS to be identical for all meshes ..... 1.459 + D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); 1.460 + 1.461 + // Compute the inverse of the transformation matrix to move the 1.462 + // vertices back to their relative and local space 1.463 + aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; 1.464 + mInv.Inverse();mInvTransposed.Transpose(); 1.465 + aiVector3D pivot = pcIn->vPivot; 1.466 + 1.467 + pcOut->mNumMeshes = (unsigned int)iArray.size(); 1.468 + pcOut->mMeshes = new unsigned int[iArray.size()]; 1.469 + for (unsigned int i = 0;i < iArray.size();++i) { 1.470 + const unsigned int iIndex = iArray[i]; 1.471 + aiMesh* const mesh = pcSOut->mMeshes[iIndex]; 1.472 + 1.473 + // Transform the vertices back into their local space 1.474 + // fixme: consider computing normals after this, so we don't need to transform them 1.475 + const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; 1.476 + aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; 1.477 + 1.478 + for (;pvCurrent != pvEnd;++pvCurrent,++t2) { 1.479 + *pvCurrent = mInv * (*pvCurrent); 1.480 + *t2 = mInvTransposed * (*t2); 1.481 + } 1.482 + 1.483 + // Handle negative transformation matrix determinant -> invert vertex x 1.484 + if (imesh->mMat.Determinant() < 0.0f) 1.485 + { 1.486 + /* we *must* have normals */ 1.487 + for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) { 1.488 + pvCurrent->x *= -1.f; 1.489 + t2->x *= -1.f; 1.490 + } 1.491 + DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); 1.492 + } 1.493 + 1.494 + // Handle pivot point 1.495 + if(pivot.x || pivot.y || pivot.z) 1.496 + { 1.497 + for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent) { 1.498 + *pvCurrent -= pivot; 1.499 + } 1.500 + } 1.501 + 1.502 + // Setup the mesh index 1.503 + pcOut->mMeshes[i] = iIndex; 1.504 + } 1.505 + } 1.506 + 1.507 + // Setup the name of the node 1.508 + pcOut->mName.Set(pcIn->mName); 1.509 + 1.510 + // Now build the transformation matrix of the node 1.511 + // ROTATION 1.512 + if (pcIn->aRotationKeys.size()){ 1.513 + 1.514 + // FIX to get to Assimp's quaternion conventions 1.515 + for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { 1.516 + (*it).mValue.w *= -1.f; 1.517 + } 1.518 + 1.519 + pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); 1.520 + } 1.521 + else if (pcIn->aCameraRollKeys.size()) 1.522 + { 1.523 + aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), 1.524 + pcOut->mTransformation); 1.525 + } 1.526 + 1.527 + // SCALING 1.528 + aiMatrix4x4& m = pcOut->mTransformation; 1.529 + if (pcIn->aScalingKeys.size()) 1.530 + { 1.531 + const aiVector3D& v = pcIn->aScalingKeys[0].mValue; 1.532 + m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; 1.533 + m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; 1.534 + m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; 1.535 + } 1.536 + 1.537 + // TRANSLATION 1.538 + if (pcIn->aPositionKeys.size()) 1.539 + { 1.540 + const aiVector3D& v = pcIn->aPositionKeys[0].mValue; 1.541 + m.a4 += v.x; 1.542 + m.b4 += v.y; 1.543 + m.c4 += v.z; 1.544 + } 1.545 + 1.546 + // Generate animation channels for the node 1.547 + if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || 1.548 + pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || 1.549 + pcIn->aTargetPositionKeys.size() > 1) 1.550 + { 1.551 + aiAnimation* anim = pcSOut->mAnimations[0]; 1.552 + ai_assert(NULL != anim); 1.553 + 1.554 + if (pcIn->aCameraRollKeys.size() > 1) 1.555 + { 1.556 + DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); 1.557 + 1.558 + // Camera roll keys - in fact they're just rotations 1.559 + // around the camera's z axis. The angles are given 1.560 + // in degrees (and they're clockwise). 1.561 + pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); 1.562 + for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) 1.563 + { 1.564 + aiQuatKey& q = pcIn->aRotationKeys[i]; 1.565 + aiFloatKey& f = pcIn->aCameraRollKeys[i]; 1.566 + 1.567 + q.mTime = f.mTime; 1.568 + 1.569 + // FIX to get to Assimp quaternion conventions 1.570 + q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); 1.571 + } 1.572 + } 1.573 +#if 0 1.574 + if (pcIn->aTargetPositionKeys.size() > 1) 1.575 + { 1.576 + DefaultLogger::get()->debug("3DS: Converting target track ..."); 1.577 + 1.578 + // Camera or spot light - need to convert the separate 1.579 + // target position channel to our representation 1.580 + TargetAnimationHelper helper; 1.581 + 1.582 + if (pcIn->aPositionKeys.empty()) 1.583 + { 1.584 + // We can just pass zero here ... 1.585 + helper.SetFixedMainAnimationChannel(aiVector3D()); 1.586 + } 1.587 + else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); 1.588 + helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); 1.589 + 1.590 + // Do the conversion 1.591 + std::vector<aiVectorKey> distanceTrack; 1.592 + helper.Process(&distanceTrack); 1.593 + 1.594 + // Now add a new node as child, name it <ourName>.Target 1.595 + // and assign the distance track to it. This is that the 1.596 + // information where the target is and how it moves is 1.597 + // not lost 1.598 + D3DS::Node* nd = new D3DS::Node(); 1.599 + pcIn->push_back(nd); 1.600 + 1.601 + nd->mName = pcIn->mName + ".Target"; 1.602 + 1.603 + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); 1.604 + nda->mNodeName.Set(nd->mName); 1.605 + 1.606 + nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); 1.607 + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; 1.608 + ::memcpy(nda->mPositionKeys,&distanceTrack[0], 1.609 + sizeof(aiVectorKey)*nda->mNumPositionKeys); 1.610 + } 1.611 +#endif 1.612 + 1.613 + // Cameras or lights define their transformation in their parent node and in the 1.614 + // corresponding light or camera chunks. However, we read and process the latter 1.615 + // to to be able to return valid cameras/lights even if no scenegraph is given. 1.616 + for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { 1.617 + if (pcSOut->mCameras[n]->mName == pcOut->mName) { 1.618 + pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); 1.619 + } 1.620 + } 1.621 + for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { 1.622 + if (pcSOut->mLights[n]->mName == pcOut->mName) { 1.623 + pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); 1.624 + } 1.625 + } 1.626 + 1.627 + // Allocate a new node anim and setup its name 1.628 + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); 1.629 + nda->mNodeName.Set(pcIn->mName); 1.630 + 1.631 + // POSITION keys 1.632 + if (pcIn->aPositionKeys.size() > 0) 1.633 + { 1.634 + nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); 1.635 + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; 1.636 + ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], 1.637 + sizeof(aiVectorKey)*nda->mNumPositionKeys); 1.638 + } 1.639 + 1.640 + // ROTATION keys 1.641 + if (pcIn->aRotationKeys.size() > 0) 1.642 + { 1.643 + nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); 1.644 + nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; 1.645 + 1.646 + // Rotations are quaternion offsets 1.647 + aiQuaternion abs; 1.648 + for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) 1.649 + { 1.650 + const aiQuatKey& q = pcIn->aRotationKeys[n]; 1.651 + 1.652 + abs = (n ? abs * q.mValue : q.mValue); 1.653 + nda->mRotationKeys[n].mTime = q.mTime; 1.654 + nda->mRotationKeys[n].mValue = abs.Normalize(); 1.655 + } 1.656 + } 1.657 + 1.658 + // SCALING keys 1.659 + if (pcIn->aScalingKeys.size() > 0) 1.660 + { 1.661 + nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); 1.662 + nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; 1.663 + ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], 1.664 + sizeof(aiVectorKey)*nda->mNumScalingKeys); 1.665 + } 1.666 + } 1.667 + 1.668 + // Allocate storage for children 1.669 + pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); 1.670 + pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; 1.671 + 1.672 + // Recursively process all children 1.673 + const unsigned int size = pcIn->mChildren.size(); 1.674 + for (unsigned int i = 0; i < size;++i) 1.675 + { 1.676 + pcOut->mChildren[i] = new aiNode(); 1.677 + pcOut->mChildren[i]->mParent = pcOut; 1.678 + AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); 1.679 + } 1.680 +} 1.681 + 1.682 +// ------------------------------------------------------------------------------------------------ 1.683 +// Find out how many node animation channels we'll have finally 1.684 +void CountTracks(D3DS::Node* node, unsigned int& cnt) 1.685 +{ 1.686 + ////////////////////////////////////////////////////////////////////////////// 1.687 + // We will never generate more than one channel for a node, so 1.688 + // this is rather easy here. 1.689 + 1.690 + if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || 1.691 + node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || 1.692 + node->aTargetPositionKeys.size() > 1) 1.693 + { 1.694 + ++cnt; 1.695 + 1.696 + // account for the additional channel for the camera/spotlight target position 1.697 + if (node->aTargetPositionKeys.size() > 1)++cnt; 1.698 + } 1.699 + 1.700 + // Recursively process all children 1.701 + for (unsigned int i = 0; i < node->mChildren.size();++i) 1.702 + CountTracks(node->mChildren[i],cnt); 1.703 +} 1.704 + 1.705 +// ------------------------------------------------------------------------------------------------ 1.706 +// Generate the output node graph 1.707 +void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) 1.708 +{ 1.709 + pcOut->mRootNode = new aiNode(); 1.710 + if (0 == mRootNode->mChildren.size()) 1.711 + { 1.712 + ////////////////////////////////////////////////////////////////////////////// 1.713 + // It seems the file is so messed up that it has not even a hierarchy. 1.714 + // generate a flat hiearachy which looks like this: 1.715 + // 1.716 + // ROOT_NODE 1.717 + // | 1.718 + // ---------------------------------------- 1.719 + // | | | | | 1.720 + // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... 1.721 + // 1.722 + DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); 1.723 + 1.724 + pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + 1.725 + mScene->mCameras.size() + mScene->mLights.size(); 1.726 + 1.727 + pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; 1.728 + pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); 1.729 + 1.730 + // Build dummy nodes for all meshes 1.731 + unsigned int a = 0; 1.732 + for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) 1.733 + { 1.734 + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); 1.735 + pcNode->mParent = pcOut->mRootNode; 1.736 + pcNode->mMeshes = new unsigned int[1]; 1.737 + pcNode->mMeshes[0] = i; 1.738 + pcNode->mNumMeshes = 1; 1.739 + 1.740 + // Build a name for the node 1.741 + pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i); 1.742 + } 1.743 + 1.744 + // Build dummy nodes for all cameras 1.745 + for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) 1.746 + { 1.747 + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); 1.748 + pcNode->mParent = pcOut->mRootNode; 1.749 + 1.750 + // Build a name for the node 1.751 + pcNode->mName = mScene->mCameras[i]->mName; 1.752 + } 1.753 + 1.754 + // Build dummy nodes for all lights 1.755 + for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) 1.756 + { 1.757 + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); 1.758 + pcNode->mParent = pcOut->mRootNode; 1.759 + 1.760 + // Build a name for the node 1.761 + pcNode->mName = mScene->mLights[i]->mName; 1.762 + } 1.763 + } 1.764 + else 1.765 + { 1.766 + // First of all: find out how many scaling, rotation and translation 1.767 + // animation tracks we'll have afterwards 1.768 + unsigned int numChannel = 0; 1.769 + CountTracks(mRootNode,numChannel); 1.770 + 1.771 + if (numChannel) 1.772 + { 1.773 + // Allocate a primary animation channel 1.774 + pcOut->mNumAnimations = 1; 1.775 + pcOut->mAnimations = new aiAnimation*[1]; 1.776 + aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); 1.777 + 1.778 + anim->mName.Set("3DSMasterAnim"); 1.779 + 1.780 + // Allocate enough storage for all node animation channels, 1.781 + // but don't set the mNumChannels member - we'll use it to 1.782 + // index into the array 1.783 + anim->mChannels = new aiNodeAnim*[numChannel]; 1.784 + } 1.785 + 1.786 + aiMatrix4x4 m; 1.787 + AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); 1.788 + } 1.789 + 1.790 + // We used the first vertex color set to store some emporary values so we need to cleanup here 1.791 + for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) 1.792 + pcOut->mMeshes[a]->mColors[0] = NULL; 1.793 + 1.794 + pcOut->mRootNode->mTransformation = aiMatrix4x4( 1.795 + 1.f,0.f,0.f,0.f, 1.796 + 0.f,0.f,1.f,0.f, 1.797 + 0.f,-1.f,0.f,0.f, 1.798 + 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; 1.799 + 1.800 + // If the root node is unnamed name it "<3DSRoot>" 1.801 + if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || 1.802 + (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) 1.803 + { 1.804 + pcOut->mRootNode->mName.Set("<3DSRoot>"); 1.805 + } 1.806 +} 1.807 + 1.808 +// ------------------------------------------------------------------------------------------------ 1.809 +// Convert all meshes in the scene and generate the final output scene. 1.810 +void Discreet3DSImporter::ConvertScene(aiScene* pcOut) 1.811 +{ 1.812 + // Allocate enough storage for all output materials 1.813 + pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); 1.814 + pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; 1.815 + 1.816 + // ... and convert the 3DS materials to aiMaterial's 1.817 + for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) 1.818 + { 1.819 + aiMaterial* pcNew = new aiMaterial(); 1.820 + ConvertMaterial(mScene->mMaterials[i],*pcNew); 1.821 + pcOut->mMaterials[i] = pcNew; 1.822 + } 1.823 + 1.824 + // Generate the output mesh list 1.825 + ConvertMeshes(pcOut); 1.826 + 1.827 + // Now copy all light sources to the output scene 1.828 + pcOut->mNumLights = (unsigned int)mScene->mLights.size(); 1.829 + if (pcOut->mNumLights) 1.830 + { 1.831 + pcOut->mLights = new aiLight*[pcOut->mNumLights]; 1.832 + ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); 1.833 + } 1.834 + 1.835 + // Now copy all cameras to the output scene 1.836 + pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); 1.837 + if (pcOut->mNumCameras) 1.838 + { 1.839 + pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; 1.840 + ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); 1.841 + } 1.842 +} 1.843 + 1.844 +#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER