vrshoot

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

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file Implementation of the 3ds importer class */
nuclear@0 43
nuclear@0 44 #include "AssimpPCH.h"
nuclear@0 45 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
nuclear@0 46
nuclear@0 47 // internal headers
nuclear@0 48 #include "3DSLoader.h"
nuclear@0 49 #include "TargetAnimation.h"
nuclear@0 50
nuclear@0 51 using namespace Assimp;
nuclear@0 52
nuclear@0 53 // ------------------------------------------------------------------------------------------------
nuclear@0 54 // Setup final material indices, generae a default material if necessary
nuclear@0 55 void Discreet3DSImporter::ReplaceDefaultMaterial()
nuclear@0 56 {
nuclear@0 57
nuclear@0 58 // Try to find an existing material that matches the
nuclear@0 59 // typical default material setting:
nuclear@0 60 // - no textures
nuclear@0 61 // - diffuse color (in grey!)
nuclear@0 62 // NOTE: This is here to workaround the fact that some
nuclear@0 63 // exporters are writing a default material, too.
nuclear@0 64 unsigned int idx = 0xcdcdcdcd;
nuclear@0 65 for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
nuclear@0 66 {
nuclear@0 67 std::string s = mScene->mMaterials[i].mName;
nuclear@0 68 for (std::string::iterator it = s.begin(); it != s.end(); ++it)
nuclear@0 69 *it = ::tolower(*it);
nuclear@0 70
nuclear@0 71 if (std::string::npos == s.find("default"))continue;
nuclear@0 72
nuclear@0 73 if (mScene->mMaterials[i].mDiffuse.r !=
nuclear@0 74 mScene->mMaterials[i].mDiffuse.g ||
nuclear@0 75 mScene->mMaterials[i].mDiffuse.r !=
nuclear@0 76 mScene->mMaterials[i].mDiffuse.b)continue;
nuclear@0 77
nuclear@0 78 if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 ||
nuclear@0 79 mScene->mMaterials[i].sTexBump.mMapName.length() != 0 ||
nuclear@0 80 mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
nuclear@0 81 mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
nuclear@0 82 mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
nuclear@0 83 mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
nuclear@0 84 {
nuclear@0 85 continue;
nuclear@0 86 }
nuclear@0 87 idx = i;
nuclear@0 88 }
nuclear@0 89 if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
nuclear@0 90
nuclear@0 91 // now iterate through all meshes and through all faces and
nuclear@0 92 // find all faces that are using the default material
nuclear@0 93 unsigned int cnt = 0;
nuclear@0 94 for (std::vector<D3DS::Mesh>::iterator
nuclear@0 95 i = mScene->mMeshes.begin();
nuclear@0 96 i != mScene->mMeshes.end();++i)
nuclear@0 97 {
nuclear@0 98 for (std::vector<unsigned int>::iterator
nuclear@0 99 a = (*i).mFaceMaterials.begin();
nuclear@0 100 a != (*i).mFaceMaterials.end();++a)
nuclear@0 101 {
nuclear@0 102 // NOTE: The additional check seems to be necessary,
nuclear@0 103 // some exporters seem to generate invalid data here
nuclear@0 104 if (0xcdcdcdcd == (*a))
nuclear@0 105 {
nuclear@0 106 (*a) = idx;
nuclear@0 107 ++cnt;
nuclear@0 108 }
nuclear@0 109 else if ( (*a) >= mScene->mMaterials.size())
nuclear@0 110 {
nuclear@0 111 (*a) = idx;
nuclear@0 112 DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
nuclear@0 113 ++cnt;
nuclear@0 114 }
nuclear@0 115 }
nuclear@0 116 }
nuclear@0 117 if (cnt && idx == mScene->mMaterials.size())
nuclear@0 118 {
nuclear@0 119 // We need to create our own default material
nuclear@0 120 D3DS::Material sMat;
nuclear@0 121 sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
nuclear@0 122 sMat.mName = "%%%DEFAULT";
nuclear@0 123 mScene->mMaterials.push_back(sMat);
nuclear@0 124
nuclear@0 125 DefaultLogger::get()->info("3DS: Generating default material");
nuclear@0 126 }
nuclear@0 127 }
nuclear@0 128
nuclear@0 129 // ------------------------------------------------------------------------------------------------
nuclear@0 130 // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
nuclear@0 131 void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
nuclear@0 132 {
nuclear@0 133 for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
nuclear@0 134 {
nuclear@0 135 // check whether all indices are in range
nuclear@0 136 for (unsigned int a = 0; a < 3;++a)
nuclear@0 137 {
nuclear@0 138 if ((*i).mIndices[a] >= sMesh.mPositions.size())
nuclear@0 139 {
nuclear@0 140 DefaultLogger::get()->warn("3DS: Vertex index overflow)");
nuclear@0 141 (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
nuclear@0 142 }
nuclear@0 143 if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
nuclear@0 144 {
nuclear@0 145 DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
nuclear@0 146 (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
nuclear@0 147 }
nuclear@0 148 }
nuclear@0 149 }
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 // ------------------------------------------------------------------------------------------------
nuclear@0 153 // Generate out unique verbose format representation
nuclear@0 154 void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
nuclear@0 155 {
nuclear@0 156 // TODO: really necessary? I don't think. Just a waste of memory and time
nuclear@0 157 // to do it now in a separate buffer.
nuclear@0 158
nuclear@0 159 // Allocate output storage
nuclear@0 160 std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3);
nuclear@0 161 std::vector<aiVector3D> vNew2;
nuclear@0 162 if (sMesh.mTexCoords.size())
nuclear@0 163 vNew2.resize(sMesh.mFaces.size() * 3);
nuclear@0 164
nuclear@0 165 for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
nuclear@0 166 {
nuclear@0 167 D3DS::Face& face = sMesh.mFaces[i];
nuclear@0 168
nuclear@0 169 // Positions
nuclear@0 170 for (unsigned int a = 0; a < 3;++a,++base)
nuclear@0 171 {
nuclear@0 172 vNew[base] = sMesh.mPositions[face.mIndices[a]];
nuclear@0 173 if (sMesh.mTexCoords.size())
nuclear@0 174 vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
nuclear@0 175
nuclear@0 176 face.mIndices[a] = base;
nuclear@0 177 }
nuclear@0 178 }
nuclear@0 179 sMesh.mPositions = vNew;
nuclear@0 180 sMesh.mTexCoords = vNew2;
nuclear@0 181 }
nuclear@0 182
nuclear@0 183 // ------------------------------------------------------------------------------------------------
nuclear@0 184 // Convert a 3DS texture to texture keys in an aiMaterial
nuclear@0 185 void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
nuclear@0 186 {
nuclear@0 187 // Setup the texture name
nuclear@0 188 aiString tex;
nuclear@0 189 tex.Set( texture.mMapName);
nuclear@0 190 mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
nuclear@0 191
nuclear@0 192 // Setup the texture blend factor
nuclear@0 193 if (is_not_qnan(texture.mTextureBlend))
nuclear@0 194 mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
nuclear@0 195
nuclear@0 196 // Setup the texture mapping mode
nuclear@0 197 mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
nuclear@0 198 mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
nuclear@0 199
nuclear@0 200 // Mirroring - double the scaling values
nuclear@0 201 // FIXME: this is not really correct ...
nuclear@0 202 if (texture.mMapMode == aiTextureMapMode_Mirror)
nuclear@0 203 {
nuclear@0 204 texture.mScaleU *= 2.f;
nuclear@0 205 texture.mScaleV *= 2.f;
nuclear@0 206 texture.mOffsetU /= 2.f;
nuclear@0 207 texture.mOffsetV /= 2.f;
nuclear@0 208 }
nuclear@0 209
nuclear@0 210 // Setup texture UV transformations
nuclear@0 211 mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
nuclear@0 212 }
nuclear@0 213
nuclear@0 214 // ------------------------------------------------------------------------------------------------
nuclear@0 215 // Convert a 3DS material to an aiMaterial
nuclear@0 216 void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
nuclear@0 217 aiMaterial& mat)
nuclear@0 218 {
nuclear@0 219 // NOTE: Pass the background image to the viewer by bypassing the
nuclear@0 220 // material system. This is an evil hack, never do it again!
nuclear@0 221 if (0 != mBackgroundImage.length() && bHasBG)
nuclear@0 222 {
nuclear@0 223 aiString tex;
nuclear@0 224 tex.Set( mBackgroundImage);
nuclear@0 225 mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
nuclear@0 226
nuclear@0 227 // Be sure this is only done for the first material
nuclear@0 228 mBackgroundImage = std::string("");
nuclear@0 229 }
nuclear@0 230
nuclear@0 231 // At first add the base ambient color of the scene to the material
nuclear@0 232 oldMat.mAmbient.r += mClrAmbient.r;
nuclear@0 233 oldMat.mAmbient.g += mClrAmbient.g;
nuclear@0 234 oldMat.mAmbient.b += mClrAmbient.b;
nuclear@0 235
nuclear@0 236 aiString name;
nuclear@0 237 name.Set( oldMat.mName);
nuclear@0 238 mat.AddProperty( &name, AI_MATKEY_NAME);
nuclear@0 239
nuclear@0 240 // Material colors
nuclear@0 241 mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
nuclear@0 242 mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 243 mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
nuclear@0 244 mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
nuclear@0 245
nuclear@0 246 // Phong shininess and shininess strength
nuclear@0 247 if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
nuclear@0 248 D3DS::Discreet3DS::Metal == oldMat.mShading)
nuclear@0 249 {
nuclear@0 250 if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
nuclear@0 251 {
nuclear@0 252 oldMat.mShading = D3DS::Discreet3DS::Gouraud;
nuclear@0 253 }
nuclear@0 254 else
nuclear@0 255 {
nuclear@0 256 mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
nuclear@0 257 mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
nuclear@0 258 }
nuclear@0 259 }
nuclear@0 260
nuclear@0 261 // Opacity
nuclear@0 262 mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
nuclear@0 263
nuclear@0 264 // Bump height scaling
nuclear@0 265 mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
nuclear@0 266
nuclear@0 267 // Two sided rendering?
nuclear@0 268 if (oldMat.mTwoSided)
nuclear@0 269 {
nuclear@0 270 int i = 1;
nuclear@0 271 mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
nuclear@0 272 }
nuclear@0 273
nuclear@0 274 // Shading mode
nuclear@0 275 aiShadingMode eShading = aiShadingMode_NoShading;
nuclear@0 276 switch (oldMat.mShading)
nuclear@0 277 {
nuclear@0 278 case D3DS::Discreet3DS::Flat:
nuclear@0 279 eShading = aiShadingMode_Flat; break;
nuclear@0 280
nuclear@0 281 // I don't know what "Wire" shading should be,
nuclear@0 282 // assume it is simple lambertian diffuse shading
nuclear@0 283 case D3DS::Discreet3DS::Wire:
nuclear@0 284 {
nuclear@0 285 // Set the wireframe flag
nuclear@0 286 unsigned int iWire = 1;
nuclear@0 287 mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
nuclear@0 288 }
nuclear@0 289
nuclear@0 290 case D3DS::Discreet3DS::Gouraud:
nuclear@0 291 eShading = aiShadingMode_Gouraud; break;
nuclear@0 292
nuclear@0 293 // assume cook-torrance shading for metals.
nuclear@0 294 case D3DS::Discreet3DS::Phong :
nuclear@0 295 eShading = aiShadingMode_Phong; break;
nuclear@0 296
nuclear@0 297 case D3DS::Discreet3DS::Metal :
nuclear@0 298 eShading = aiShadingMode_CookTorrance; break;
nuclear@0 299
nuclear@0 300 // FIX to workaround a warning with GCC 4 who complained
nuclear@0 301 // about a missing case Blinn: here - Blinn isn't a valid
nuclear@0 302 // value in the 3DS Loader, it is just needed for ASE
nuclear@0 303 case D3DS::Discreet3DS::Blinn :
nuclear@0 304 eShading = aiShadingMode_Blinn; break;
nuclear@0 305 }
nuclear@0 306 mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
nuclear@0 307
nuclear@0 308 // DIFFUSE texture
nuclear@0 309 if( oldMat.sTexDiffuse.mMapName.length() > 0)
nuclear@0 310 CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
nuclear@0 311
nuclear@0 312 // SPECULAR texture
nuclear@0 313 if( oldMat.sTexSpecular.mMapName.length() > 0)
nuclear@0 314 CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
nuclear@0 315
nuclear@0 316 // OPACITY texture
nuclear@0 317 if( oldMat.sTexOpacity.mMapName.length() > 0)
nuclear@0 318 CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
nuclear@0 319
nuclear@0 320 // EMISSIVE texture
nuclear@0 321 if( oldMat.sTexEmissive.mMapName.length() > 0)
nuclear@0 322 CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
nuclear@0 323
nuclear@0 324 // BUMP texture
nuclear@0 325 if( oldMat.sTexBump.mMapName.length() > 0)
nuclear@0 326 CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
nuclear@0 327
nuclear@0 328 // SHININESS texture
nuclear@0 329 if( oldMat.sTexShininess.mMapName.length() > 0)
nuclear@0 330 CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
nuclear@0 331
nuclear@0 332 // REFLECTION texture
nuclear@0 333 if( oldMat.sTexReflective.mMapName.length() > 0)
nuclear@0 334 CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
nuclear@0 335
nuclear@0 336 // Store the name of the material itself, too
nuclear@0 337 if( oldMat.mName.length()) {
nuclear@0 338 aiString tex;
nuclear@0 339 tex.Set( oldMat.mName);
nuclear@0 340 mat.AddProperty( &tex, AI_MATKEY_NAME);
nuclear@0 341 }
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 // ------------------------------------------------------------------------------------------------
nuclear@0 345 // Split meshes by their materials and generate output aiMesh'es
nuclear@0 346 void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
nuclear@0 347 {
nuclear@0 348 std::vector<aiMesh*> avOutMeshes;
nuclear@0 349 avOutMeshes.reserve(mScene->mMeshes.size() * 2);
nuclear@0 350
nuclear@0 351 unsigned int iFaceCnt = 0,num = 0;
nuclear@0 352 aiString name;
nuclear@0 353
nuclear@0 354 // we need to split all meshes by their materials
nuclear@0 355 for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) {
nuclear@0 356 boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
nuclear@0 357
nuclear@0 358 name.length = ASSIMP_itoa10(name.data,num++);
nuclear@0 359
nuclear@0 360 unsigned int iNum = 0;
nuclear@0 361 for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
nuclear@0 362 a != (*i).mFaceMaterials.end();++a,++iNum)
nuclear@0 363 {
nuclear@0 364 aiSplit[*a].push_back(iNum);
nuclear@0 365 }
nuclear@0 366 // now generate submeshes
nuclear@0 367 for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
nuclear@0 368 {
nuclear@0 369 if (aiSplit[p].empty()) {
nuclear@0 370 continue;
nuclear@0 371 }
nuclear@0 372 aiMesh* meshOut = new aiMesh();
nuclear@0 373 meshOut->mName = name;
nuclear@0 374 meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 375
nuclear@0 376 // be sure to setup the correct material index
nuclear@0 377 meshOut->mMaterialIndex = p;
nuclear@0 378
nuclear@0 379 // use the color data as temporary storage
nuclear@0 380 meshOut->mColors[0] = (aiColor4D*)(&*i);
nuclear@0 381 avOutMeshes.push_back(meshOut);
nuclear@0 382
nuclear@0 383 // convert vertices
nuclear@0 384 meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
nuclear@0 385 meshOut->mNumVertices = meshOut->mNumFaces*3;
nuclear@0 386
nuclear@0 387 // allocate enough storage for faces
nuclear@0 388 meshOut->mFaces = new aiFace[meshOut->mNumFaces];
nuclear@0 389 iFaceCnt += meshOut->mNumFaces;
nuclear@0 390
nuclear@0 391 meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
nuclear@0 392 meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
nuclear@0 393 if ((*i).mTexCoords.size())
nuclear@0 394 {
nuclear@0 395 meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
nuclear@0 396 }
nuclear@0 397 for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
nuclear@0 398 {
nuclear@0 399 register unsigned int index = aiSplit[p][q];
nuclear@0 400 aiFace& face = meshOut->mFaces[q];
nuclear@0 401
nuclear@0 402 face.mIndices = new unsigned int[3];
nuclear@0 403 face.mNumIndices = 3;
nuclear@0 404
nuclear@0 405 for (unsigned int a = 0; a < 3;++a,++base)
nuclear@0 406 {
nuclear@0 407 unsigned int idx = (*i).mFaces[index].mIndices[a];
nuclear@0 408 meshOut->mVertices[base] = (*i).mPositions[idx];
nuclear@0 409 meshOut->mNormals [base] = (*i).mNormals[idx];
nuclear@0 410
nuclear@0 411 if ((*i).mTexCoords.size())
nuclear@0 412 meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
nuclear@0 413
nuclear@0 414 face.mIndices[a] = base;
nuclear@0 415 }
nuclear@0 416 }
nuclear@0 417 }
nuclear@0 418 }
nuclear@0 419
nuclear@0 420 // Copy them to the output array
nuclear@0 421 pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
nuclear@0 422 pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
nuclear@0 423 for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
nuclear@0 424 pcOut->mMeshes[a] = avOutMeshes[a];
nuclear@0 425 }
nuclear@0 426
nuclear@0 427 // We should have at least one face here
nuclear@0 428 if (!iFaceCnt) {
nuclear@0 429 throw DeadlyImportError("No faces loaded. The mesh is empty");
nuclear@0 430 }
nuclear@0 431 }
nuclear@0 432
nuclear@0 433 // ------------------------------------------------------------------------------------------------
nuclear@0 434 // Add a node to the scenegraph and setup its final transformation
nuclear@0 435 void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
nuclear@0 436 D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
nuclear@0 437 {
nuclear@0 438 std::vector<unsigned int> iArray;
nuclear@0 439 iArray.reserve(3);
nuclear@0 440
nuclear@0 441 aiMatrix4x4 abs;
nuclear@0 442
nuclear@0 443 // Find all meshes with the same name as the node
nuclear@0 444 for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
nuclear@0 445 {
nuclear@0 446 const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
nuclear@0 447 ai_assert(NULL != pcMesh);
nuclear@0 448
nuclear@0 449 if (pcIn->mName == pcMesh->mName)
nuclear@0 450 iArray.push_back(a);
nuclear@0 451 }
nuclear@0 452 if (!iArray.empty())
nuclear@0 453 {
nuclear@0 454 // The matrix should be identical for all meshes with the
nuclear@0 455 // same name. It HAS to be identical for all meshes .....
nuclear@0 456 D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
nuclear@0 457
nuclear@0 458 // Compute the inverse of the transformation matrix to move the
nuclear@0 459 // vertices back to their relative and local space
nuclear@0 460 aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
nuclear@0 461 mInv.Inverse();mInvTransposed.Transpose();
nuclear@0 462 aiVector3D pivot = pcIn->vPivot;
nuclear@0 463
nuclear@0 464 pcOut->mNumMeshes = (unsigned int)iArray.size();
nuclear@0 465 pcOut->mMeshes = new unsigned int[iArray.size()];
nuclear@0 466 for (unsigned int i = 0;i < iArray.size();++i) {
nuclear@0 467 const unsigned int iIndex = iArray[i];
nuclear@0 468 aiMesh* const mesh = pcSOut->mMeshes[iIndex];
nuclear@0 469
nuclear@0 470 // Transform the vertices back into their local space
nuclear@0 471 // fixme: consider computing normals after this, so we don't need to transform them
nuclear@0 472 const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
nuclear@0 473 aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
nuclear@0 474
nuclear@0 475 for (;pvCurrent != pvEnd;++pvCurrent,++t2) {
nuclear@0 476 *pvCurrent = mInv * (*pvCurrent);
nuclear@0 477 *t2 = mInvTransposed * (*t2);
nuclear@0 478 }
nuclear@0 479
nuclear@0 480 // Handle negative transformation matrix determinant -> invert vertex x
nuclear@0 481 if (imesh->mMat.Determinant() < 0.0f)
nuclear@0 482 {
nuclear@0 483 /* we *must* have normals */
nuclear@0 484 for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) {
nuclear@0 485 pvCurrent->x *= -1.f;
nuclear@0 486 t2->x *= -1.f;
nuclear@0 487 }
nuclear@0 488 DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
nuclear@0 489 }
nuclear@0 490
nuclear@0 491 // Handle pivot point
nuclear@0 492 if(pivot.x || pivot.y || pivot.z)
nuclear@0 493 {
nuclear@0 494 for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent) {
nuclear@0 495 *pvCurrent -= pivot;
nuclear@0 496 }
nuclear@0 497 }
nuclear@0 498
nuclear@0 499 // Setup the mesh index
nuclear@0 500 pcOut->mMeshes[i] = iIndex;
nuclear@0 501 }
nuclear@0 502 }
nuclear@0 503
nuclear@0 504 // Setup the name of the node
nuclear@0 505 pcOut->mName.Set(pcIn->mName);
nuclear@0 506
nuclear@0 507 // Now build the transformation matrix of the node
nuclear@0 508 // ROTATION
nuclear@0 509 if (pcIn->aRotationKeys.size()){
nuclear@0 510
nuclear@0 511 // FIX to get to Assimp's quaternion conventions
nuclear@0 512 for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
nuclear@0 513 (*it).mValue.w *= -1.f;
nuclear@0 514 }
nuclear@0 515
nuclear@0 516 pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
nuclear@0 517 }
nuclear@0 518 else if (pcIn->aCameraRollKeys.size())
nuclear@0 519 {
nuclear@0 520 aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
nuclear@0 521 pcOut->mTransformation);
nuclear@0 522 }
nuclear@0 523
nuclear@0 524 // SCALING
nuclear@0 525 aiMatrix4x4& m = pcOut->mTransformation;
nuclear@0 526 if (pcIn->aScalingKeys.size())
nuclear@0 527 {
nuclear@0 528 const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
nuclear@0 529 m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
nuclear@0 530 m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
nuclear@0 531 m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
nuclear@0 532 }
nuclear@0 533
nuclear@0 534 // TRANSLATION
nuclear@0 535 if (pcIn->aPositionKeys.size())
nuclear@0 536 {
nuclear@0 537 const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
nuclear@0 538 m.a4 += v.x;
nuclear@0 539 m.b4 += v.y;
nuclear@0 540 m.c4 += v.z;
nuclear@0 541 }
nuclear@0 542
nuclear@0 543 // Generate animation channels for the node
nuclear@0 544 if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
nuclear@0 545 pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
nuclear@0 546 pcIn->aTargetPositionKeys.size() > 1)
nuclear@0 547 {
nuclear@0 548 aiAnimation* anim = pcSOut->mAnimations[0];
nuclear@0 549 ai_assert(NULL != anim);
nuclear@0 550
nuclear@0 551 if (pcIn->aCameraRollKeys.size() > 1)
nuclear@0 552 {
nuclear@0 553 DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
nuclear@0 554
nuclear@0 555 // Camera roll keys - in fact they're just rotations
nuclear@0 556 // around the camera's z axis. The angles are given
nuclear@0 557 // in degrees (and they're clockwise).
nuclear@0 558 pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
nuclear@0 559 for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
nuclear@0 560 {
nuclear@0 561 aiQuatKey& q = pcIn->aRotationKeys[i];
nuclear@0 562 aiFloatKey& f = pcIn->aCameraRollKeys[i];
nuclear@0 563
nuclear@0 564 q.mTime = f.mTime;
nuclear@0 565
nuclear@0 566 // FIX to get to Assimp quaternion conventions
nuclear@0 567 q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
nuclear@0 568 }
nuclear@0 569 }
nuclear@0 570 #if 0
nuclear@0 571 if (pcIn->aTargetPositionKeys.size() > 1)
nuclear@0 572 {
nuclear@0 573 DefaultLogger::get()->debug("3DS: Converting target track ...");
nuclear@0 574
nuclear@0 575 // Camera or spot light - need to convert the separate
nuclear@0 576 // target position channel to our representation
nuclear@0 577 TargetAnimationHelper helper;
nuclear@0 578
nuclear@0 579 if (pcIn->aPositionKeys.empty())
nuclear@0 580 {
nuclear@0 581 // We can just pass zero here ...
nuclear@0 582 helper.SetFixedMainAnimationChannel(aiVector3D());
nuclear@0 583 }
nuclear@0 584 else helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
nuclear@0 585 helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
nuclear@0 586
nuclear@0 587 // Do the conversion
nuclear@0 588 std::vector<aiVectorKey> distanceTrack;
nuclear@0 589 helper.Process(&distanceTrack);
nuclear@0 590
nuclear@0 591 // Now add a new node as child, name it <ourName>.Target
nuclear@0 592 // and assign the distance track to it. This is that the
nuclear@0 593 // information where the target is and how it moves is
nuclear@0 594 // not lost
nuclear@0 595 D3DS::Node* nd = new D3DS::Node();
nuclear@0 596 pcIn->push_back(nd);
nuclear@0 597
nuclear@0 598 nd->mName = pcIn->mName + ".Target";
nuclear@0 599
nuclear@0 600 aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
nuclear@0 601 nda->mNodeName.Set(nd->mName);
nuclear@0 602
nuclear@0 603 nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
nuclear@0 604 nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
nuclear@0 605 ::memcpy(nda->mPositionKeys,&distanceTrack[0],
nuclear@0 606 sizeof(aiVectorKey)*nda->mNumPositionKeys);
nuclear@0 607 }
nuclear@0 608 #endif
nuclear@0 609
nuclear@0 610 // Cameras or lights define their transformation in their parent node and in the
nuclear@0 611 // corresponding light or camera chunks. However, we read and process the latter
nuclear@0 612 // to to be able to return valid cameras/lights even if no scenegraph is given.
nuclear@0 613 for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) {
nuclear@0 614 if (pcSOut->mCameras[n]->mName == pcOut->mName) {
nuclear@0 615 pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
nuclear@0 616 }
nuclear@0 617 }
nuclear@0 618 for (unsigned int n = 0; n < pcSOut->mNumLights;++n) {
nuclear@0 619 if (pcSOut->mLights[n]->mName == pcOut->mName) {
nuclear@0 620 pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
nuclear@0 621 }
nuclear@0 622 }
nuclear@0 623
nuclear@0 624 // Allocate a new node anim and setup its name
nuclear@0 625 aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
nuclear@0 626 nda->mNodeName.Set(pcIn->mName);
nuclear@0 627
nuclear@0 628 // POSITION keys
nuclear@0 629 if (pcIn->aPositionKeys.size() > 0)
nuclear@0 630 {
nuclear@0 631 nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
nuclear@0 632 nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
nuclear@0 633 ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
nuclear@0 634 sizeof(aiVectorKey)*nda->mNumPositionKeys);
nuclear@0 635 }
nuclear@0 636
nuclear@0 637 // ROTATION keys
nuclear@0 638 if (pcIn->aRotationKeys.size() > 0)
nuclear@0 639 {
nuclear@0 640 nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
nuclear@0 641 nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
nuclear@0 642
nuclear@0 643 // Rotations are quaternion offsets
nuclear@0 644 aiQuaternion abs;
nuclear@0 645 for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
nuclear@0 646 {
nuclear@0 647 const aiQuatKey& q = pcIn->aRotationKeys[n];
nuclear@0 648
nuclear@0 649 abs = (n ? abs * q.mValue : q.mValue);
nuclear@0 650 nda->mRotationKeys[n].mTime = q.mTime;
nuclear@0 651 nda->mRotationKeys[n].mValue = abs.Normalize();
nuclear@0 652 }
nuclear@0 653 }
nuclear@0 654
nuclear@0 655 // SCALING keys
nuclear@0 656 if (pcIn->aScalingKeys.size() > 0)
nuclear@0 657 {
nuclear@0 658 nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
nuclear@0 659 nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
nuclear@0 660 ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
nuclear@0 661 sizeof(aiVectorKey)*nda->mNumScalingKeys);
nuclear@0 662 }
nuclear@0 663 }
nuclear@0 664
nuclear@0 665 // Allocate storage for children
nuclear@0 666 pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
nuclear@0 667 pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
nuclear@0 668
nuclear@0 669 // Recursively process all children
nuclear@0 670 const unsigned int size = pcIn->mChildren.size();
nuclear@0 671 for (unsigned int i = 0; i < size;++i)
nuclear@0 672 {
nuclear@0 673 pcOut->mChildren[i] = new aiNode();
nuclear@0 674 pcOut->mChildren[i]->mParent = pcOut;
nuclear@0 675 AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
nuclear@0 676 }
nuclear@0 677 }
nuclear@0 678
nuclear@0 679 // ------------------------------------------------------------------------------------------------
nuclear@0 680 // Find out how many node animation channels we'll have finally
nuclear@0 681 void CountTracks(D3DS::Node* node, unsigned int& cnt)
nuclear@0 682 {
nuclear@0 683 //////////////////////////////////////////////////////////////////////////////
nuclear@0 684 // We will never generate more than one channel for a node, so
nuclear@0 685 // this is rather easy here.
nuclear@0 686
nuclear@0 687 if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
nuclear@0 688 node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
nuclear@0 689 node->aTargetPositionKeys.size() > 1)
nuclear@0 690 {
nuclear@0 691 ++cnt;
nuclear@0 692
nuclear@0 693 // account for the additional channel for the camera/spotlight target position
nuclear@0 694 if (node->aTargetPositionKeys.size() > 1)++cnt;
nuclear@0 695 }
nuclear@0 696
nuclear@0 697 // Recursively process all children
nuclear@0 698 for (unsigned int i = 0; i < node->mChildren.size();++i)
nuclear@0 699 CountTracks(node->mChildren[i],cnt);
nuclear@0 700 }
nuclear@0 701
nuclear@0 702 // ------------------------------------------------------------------------------------------------
nuclear@0 703 // Generate the output node graph
nuclear@0 704 void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
nuclear@0 705 {
nuclear@0 706 pcOut->mRootNode = new aiNode();
nuclear@0 707 if (0 == mRootNode->mChildren.size())
nuclear@0 708 {
nuclear@0 709 //////////////////////////////////////////////////////////////////////////////
nuclear@0 710 // It seems the file is so messed up that it has not even a hierarchy.
nuclear@0 711 // generate a flat hiearachy which looks like this:
nuclear@0 712 //
nuclear@0 713 // ROOT_NODE
nuclear@0 714 // |
nuclear@0 715 // ----------------------------------------
nuclear@0 716 // | | | | |
nuclear@0 717 // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 ....
nuclear@0 718 //
nuclear@0 719 DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
nuclear@0 720
nuclear@0 721 pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
nuclear@0 722 mScene->mCameras.size() + mScene->mLights.size();
nuclear@0 723
nuclear@0 724 pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
nuclear@0 725 pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
nuclear@0 726
nuclear@0 727 // Build dummy nodes for all meshes
nuclear@0 728 unsigned int a = 0;
nuclear@0 729 for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
nuclear@0 730 {
nuclear@0 731 aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
nuclear@0 732 pcNode->mParent = pcOut->mRootNode;
nuclear@0 733 pcNode->mMeshes = new unsigned int[1];
nuclear@0 734 pcNode->mMeshes[0] = i;
nuclear@0 735 pcNode->mNumMeshes = 1;
nuclear@0 736
nuclear@0 737 // Build a name for the node
nuclear@0 738 pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i);
nuclear@0 739 }
nuclear@0 740
nuclear@0 741 // Build dummy nodes for all cameras
nuclear@0 742 for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
nuclear@0 743 {
nuclear@0 744 aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
nuclear@0 745 pcNode->mParent = pcOut->mRootNode;
nuclear@0 746
nuclear@0 747 // Build a name for the node
nuclear@0 748 pcNode->mName = mScene->mCameras[i]->mName;
nuclear@0 749 }
nuclear@0 750
nuclear@0 751 // Build dummy nodes for all lights
nuclear@0 752 for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
nuclear@0 753 {
nuclear@0 754 aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
nuclear@0 755 pcNode->mParent = pcOut->mRootNode;
nuclear@0 756
nuclear@0 757 // Build a name for the node
nuclear@0 758 pcNode->mName = mScene->mLights[i]->mName;
nuclear@0 759 }
nuclear@0 760 }
nuclear@0 761 else
nuclear@0 762 {
nuclear@0 763 // First of all: find out how many scaling, rotation and translation
nuclear@0 764 // animation tracks we'll have afterwards
nuclear@0 765 unsigned int numChannel = 0;
nuclear@0 766 CountTracks(mRootNode,numChannel);
nuclear@0 767
nuclear@0 768 if (numChannel)
nuclear@0 769 {
nuclear@0 770 // Allocate a primary animation channel
nuclear@0 771 pcOut->mNumAnimations = 1;
nuclear@0 772 pcOut->mAnimations = new aiAnimation*[1];
nuclear@0 773 aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation();
nuclear@0 774
nuclear@0 775 anim->mName.Set("3DSMasterAnim");
nuclear@0 776
nuclear@0 777 // Allocate enough storage for all node animation channels,
nuclear@0 778 // but don't set the mNumChannels member - we'll use it to
nuclear@0 779 // index into the array
nuclear@0 780 anim->mChannels = new aiNodeAnim*[numChannel];
nuclear@0 781 }
nuclear@0 782
nuclear@0 783 aiMatrix4x4 m;
nuclear@0 784 AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m);
nuclear@0 785 }
nuclear@0 786
nuclear@0 787 // We used the first vertex color set to store some emporary values so we need to cleanup here
nuclear@0 788 for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
nuclear@0 789 pcOut->mMeshes[a]->mColors[0] = NULL;
nuclear@0 790
nuclear@0 791 pcOut->mRootNode->mTransformation = aiMatrix4x4(
nuclear@0 792 1.f,0.f,0.f,0.f,
nuclear@0 793 0.f,0.f,1.f,0.f,
nuclear@0 794 0.f,-1.f,0.f,0.f,
nuclear@0 795 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
nuclear@0 796
nuclear@0 797 // If the root node is unnamed name it "<3DSRoot>"
nuclear@0 798 if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
nuclear@0 799 (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
nuclear@0 800 {
nuclear@0 801 pcOut->mRootNode->mName.Set("<3DSRoot>");
nuclear@0 802 }
nuclear@0 803 }
nuclear@0 804
nuclear@0 805 // ------------------------------------------------------------------------------------------------
nuclear@0 806 // Convert all meshes in the scene and generate the final output scene.
nuclear@0 807 void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
nuclear@0 808 {
nuclear@0 809 // Allocate enough storage for all output materials
nuclear@0 810 pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
nuclear@0 811 pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials];
nuclear@0 812
nuclear@0 813 // ... and convert the 3DS materials to aiMaterial's
nuclear@0 814 for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
nuclear@0 815 {
nuclear@0 816 aiMaterial* pcNew = new aiMaterial();
nuclear@0 817 ConvertMaterial(mScene->mMaterials[i],*pcNew);
nuclear@0 818 pcOut->mMaterials[i] = pcNew;
nuclear@0 819 }
nuclear@0 820
nuclear@0 821 // Generate the output mesh list
nuclear@0 822 ConvertMeshes(pcOut);
nuclear@0 823
nuclear@0 824 // Now copy all light sources to the output scene
nuclear@0 825 pcOut->mNumLights = (unsigned int)mScene->mLights.size();
nuclear@0 826 if (pcOut->mNumLights)
nuclear@0 827 {
nuclear@0 828 pcOut->mLights = new aiLight*[pcOut->mNumLights];
nuclear@0 829 ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
nuclear@0 830 }
nuclear@0 831
nuclear@0 832 // Now copy all cameras to the output scene
nuclear@0 833 pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
nuclear@0 834 if (pcOut->mNumCameras)
nuclear@0 835 {
nuclear@0 836 pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
nuclear@0 837 ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
nuclear@0 838 }
nuclear@0 839 }
nuclear@0 840
nuclear@0 841 #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER