vrshoot

annotate libs/assimp/ASELoader.cpp @ 3:c179c72369be

rename candy->vr
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 03 Feb 2014 08:52:13 +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 ASELoader.cpp
nuclear@0 43 * @brief Implementation of the ASE importer class
nuclear@0 44 */
nuclear@0 45
nuclear@0 46 #include "AssimpPCH.h"
nuclear@0 47 #include "assimp/config.h"
nuclear@0 48 #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
nuclear@0 49
nuclear@0 50 // internal headers
nuclear@0 51 #include "ASELoader.h"
nuclear@0 52 #include "StringComparison.h"
nuclear@0 53 #include "SkeletonMeshBuilder.h"
nuclear@0 54 #include "TargetAnimation.h"
nuclear@0 55
nuclear@0 56 // utilities
nuclear@0 57 #include "fast_atof.h"
nuclear@0 58
nuclear@0 59 using namespace Assimp;
nuclear@0 60 using namespace Assimp::ASE;
nuclear@0 61
nuclear@0 62 static const aiImporterDesc desc = {
nuclear@0 63 "ASE Importer",
nuclear@0 64 "",
nuclear@0 65 "",
nuclear@0 66 "Similar to 3DS but text-encoded",
nuclear@0 67 aiImporterFlags_SupportTextFlavour,
nuclear@0 68 0,
nuclear@0 69 0,
nuclear@0 70 0,
nuclear@0 71 0,
nuclear@0 72 "ase ask"
nuclear@0 73 };
nuclear@0 74
nuclear@0 75 // ------------------------------------------------------------------------------------------------
nuclear@0 76 // Constructor to be privately used by Importer
nuclear@0 77 ASEImporter::ASEImporter()
nuclear@0 78 : noSkeletonMesh()
nuclear@0 79 {}
nuclear@0 80
nuclear@0 81 // ------------------------------------------------------------------------------------------------
nuclear@0 82 // Destructor, private as well
nuclear@0 83 ASEImporter::~ASEImporter()
nuclear@0 84 {}
nuclear@0 85
nuclear@0 86 // ------------------------------------------------------------------------------------------------
nuclear@0 87 // Returns whether the class can handle the format of the given file.
nuclear@0 88 bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
nuclear@0 89 {
nuclear@0 90 // check file extension
nuclear@0 91 const std::string extension = GetExtension(pFile);
nuclear@0 92
nuclear@0 93 if( extension == "ase" || extension == "ask")
nuclear@0 94 return true;
nuclear@0 95
nuclear@0 96 if ((!extension.length() || cs) && pIOHandler) {
nuclear@0 97 const char* tokens[] = {"*3dsmax_asciiexport"};
nuclear@0 98 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
nuclear@0 99 }
nuclear@0 100 return false;
nuclear@0 101 }
nuclear@0 102
nuclear@0 103 // ------------------------------------------------------------------------------------------------
nuclear@0 104 // Loader meta information
nuclear@0 105 const aiImporterDesc* ASEImporter::GetInfo () const
nuclear@0 106 {
nuclear@0 107 return &desc;
nuclear@0 108 }
nuclear@0 109
nuclear@0 110 // ------------------------------------------------------------------------------------------------
nuclear@0 111 // Setup configuration options
nuclear@0 112 void ASEImporter::SetupProperties(const Importer* pImp)
nuclear@0 113 {
nuclear@0 114 configRecomputeNormals = (pImp->GetPropertyInteger(
nuclear@0 115 AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
nuclear@0 116
nuclear@0 117 noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
nuclear@0 118 }
nuclear@0 119
nuclear@0 120 // ------------------------------------------------------------------------------------------------
nuclear@0 121 // Imports the given file into the given scene structure.
nuclear@0 122 void ASEImporter::InternReadFile( const std::string& pFile,
nuclear@0 123 aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 124 {
nuclear@0 125 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
nuclear@0 126
nuclear@0 127 // Check whether we can read from the file
nuclear@0 128 if( file.get() == NULL) {
nuclear@0 129 throw DeadlyImportError( "Failed to open ASE file " + pFile + ".");
nuclear@0 130 }
nuclear@0 131
nuclear@0 132 // Allocate storage and copy the contents of the file to a memory buffer
nuclear@0 133 std::vector<char> mBuffer2;
nuclear@0 134 TextFileToBuffer(file.get(),mBuffer2);
nuclear@0 135
nuclear@0 136 this->mBuffer = &mBuffer2[0];
nuclear@0 137 this->pcScene = pScene;
nuclear@0 138
nuclear@0 139 // ------------------------------------------------------------------
nuclear@0 140 // Guess the file format by looking at the extension
nuclear@0 141 // ASC is considered to be the older format 110,
nuclear@0 142 // ASE is the actual version 200 (that is currently written by max)
nuclear@0 143 // ------------------------------------------------------------------
nuclear@0 144 unsigned int defaultFormat;
nuclear@0 145 std::string::size_type s = pFile.length()-1;
nuclear@0 146 switch (pFile.c_str()[s]) {
nuclear@0 147
nuclear@0 148 case 'C':
nuclear@0 149 case 'c':
nuclear@0 150 defaultFormat = AI_ASE_OLD_FILE_FORMAT;
nuclear@0 151 break;
nuclear@0 152 default:
nuclear@0 153 defaultFormat = AI_ASE_NEW_FILE_FORMAT;
nuclear@0 154 };
nuclear@0 155
nuclear@0 156 // Construct an ASE parser and parse the file
nuclear@0 157 ASE::Parser parser(mBuffer,defaultFormat);
nuclear@0 158 mParser = &parser;
nuclear@0 159 mParser->Parse();
nuclear@0 160
nuclear@0 161 //------------------------------------------------------------------
nuclear@0 162 // Check whether we god at least one mesh. If we did - generate
nuclear@0 163 // materials and copy meshes.
nuclear@0 164 // ------------------------------------------------------------------
nuclear@0 165 if ( !mParser->m_vMeshes.empty()) {
nuclear@0 166
nuclear@0 167 // If absolutely no material has been loaded from the file
nuclear@0 168 // we need to generate a default material
nuclear@0 169 GenerateDefaultMaterial();
nuclear@0 170
nuclear@0 171 // process all meshes
nuclear@0 172 bool tookNormals = false;
nuclear@0 173 std::vector<aiMesh*> avOutMeshes;
nuclear@0 174 avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
nuclear@0 175 for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) {
nuclear@0 176 if ((*i).bSkip) {
nuclear@0 177 continue;
nuclear@0 178 }
nuclear@0 179 BuildUniqueRepresentation(*i);
nuclear@0 180
nuclear@0 181 // Need to generate proper vertex normals if necessary
nuclear@0 182 if(GenerateNormals(*i)) {
nuclear@0 183 tookNormals = true;
nuclear@0 184 }
nuclear@0 185
nuclear@0 186 // Convert all meshes to aiMesh objects
nuclear@0 187 ConvertMeshes(*i,avOutMeshes);
nuclear@0 188 }
nuclear@0 189 if (tookNormals) {
nuclear@0 190 DefaultLogger::get()->debug("ASE: Taking normals from the file. Use "
nuclear@0 191 "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
nuclear@0 192 "experience problems");
nuclear@0 193 }
nuclear@0 194
nuclear@0 195 // Now build the output mesh list. Remove dummies
nuclear@0 196 pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
nuclear@0 197 aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
nuclear@0 198 for (std::vector<aiMesh*>::const_iterator i = avOutMeshes.begin();i != avOutMeshes.end();++i) {
nuclear@0 199 if (!(*i)->mNumFaces) {
nuclear@0 200 continue;
nuclear@0 201 }
nuclear@0 202 *pp++ = *i;
nuclear@0 203 }
nuclear@0 204 pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
nuclear@0 205
nuclear@0 206 // Build final material indices (remove submaterials and setup
nuclear@0 207 // the final list)
nuclear@0 208 BuildMaterialIndices();
nuclear@0 209 }
nuclear@0 210
nuclear@0 211 // ------------------------------------------------------------------
nuclear@0 212 // Copy all scene graph nodes - lights, cameras, dummies and meshes
nuclear@0 213 // into one huge list.
nuclear@0 214 //------------------------------------------------------------------
nuclear@0 215 std::vector<BaseNode*> nodes;
nuclear@0 216 nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
nuclear@0 217 + mParser->m_vCameras.size() + mParser->m_vDummies.size());
nuclear@0 218
nuclear@0 219 // Lights
nuclear@0 220 for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(),
nuclear@0 221 end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it));
nuclear@0 222 // Cameras
nuclear@0 223 for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(),
nuclear@0 224 end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it));
nuclear@0 225 // Meshes
nuclear@0 226 for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(),
nuclear@0 227 end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it));
nuclear@0 228 // Dummies
nuclear@0 229 for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(),
nuclear@0 230 end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it));
nuclear@0 231
nuclear@0 232 // build the final node graph
nuclear@0 233 BuildNodes(nodes);
nuclear@0 234
nuclear@0 235 // build output animations
nuclear@0 236 BuildAnimations(nodes);
nuclear@0 237
nuclear@0 238 // build output cameras
nuclear@0 239 BuildCameras();
nuclear@0 240
nuclear@0 241 // build output lights
nuclear@0 242 BuildLights();
nuclear@0 243
nuclear@0 244 // ------------------------------------------------------------------
nuclear@0 245 // If we have no meshes use the SkeletonMeshBuilder helper class
nuclear@0 246 // to build a mesh for the animation skeleton
nuclear@0 247 // FIXME: very strange results
nuclear@0 248 // ------------------------------------------------------------------
nuclear@0 249 if (!pScene->mNumMeshes) {
nuclear@0 250 pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
nuclear@0 251 if (!noSkeletonMesh) {
nuclear@0 252 SkeletonMeshBuilder skeleton(pScene);
nuclear@0 253 }
nuclear@0 254 }
nuclear@0 255 }
nuclear@0 256 // ------------------------------------------------------------------------------------------------
nuclear@0 257 void ASEImporter::GenerateDefaultMaterial()
nuclear@0 258 {
nuclear@0 259 ai_assert(NULL != mParser);
nuclear@0 260
nuclear@0 261 bool bHas = false;
nuclear@0 262 for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) {
nuclear@0 263 if ((*i).bSkip)continue;
nuclear@0 264 if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) {
nuclear@0 265 (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size();
nuclear@0 266 bHas = true;
nuclear@0 267 }
nuclear@0 268 }
nuclear@0 269 if (bHas || mParser->m_vMaterials.empty()) {
nuclear@0 270 // add a simple material without submaterials to the parser's list
nuclear@0 271 mParser->m_vMaterials.push_back ( ASE::Material() );
nuclear@0 272 ASE::Material& mat = mParser->m_vMaterials.back();
nuclear@0 273
nuclear@0 274 mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f);
nuclear@0 275 mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f);
nuclear@0 276 mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f);
nuclear@0 277 mat.mShading = Discreet3DS::Gouraud;
nuclear@0 278 mat.mName = AI_DEFAULT_MATERIAL_NAME;
nuclear@0 279 }
nuclear@0 280 }
nuclear@0 281
nuclear@0 282 // ------------------------------------------------------------------------------------------------
nuclear@0 283 void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
nuclear@0 284 {
nuclear@0 285 // check whether we have at least one mesh which has animations
nuclear@0 286 std::vector<ASE::BaseNode*>::const_iterator i = nodes.begin();
nuclear@0 287 unsigned int iNum = 0;
nuclear@0 288 for (;i != nodes.end();++i) {
nuclear@0 289
nuclear@0 290 // TODO: Implement Bezier & TCB support
nuclear@0 291 if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) {
nuclear@0 292 DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
nuclear@0 293 "This is not supported.");
nuclear@0 294 }
nuclear@0 295 if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) {
nuclear@0 296 DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. "
nuclear@0 297 "This is not supported.");
nuclear@0 298 }
nuclear@0 299 if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) {
nuclear@0 300 DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
nuclear@0 301 "This is not supported.");
nuclear@0 302 }
nuclear@0 303
nuclear@0 304 // We compare against 1 here - firstly one key is not
nuclear@0 305 // really an animation and secondly MAX writes dummies
nuclear@0 306 // that represent the node transformation.
nuclear@0 307 if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){
nuclear@0 308 ++iNum;
nuclear@0 309 }
nuclear@0 310 if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) {
nuclear@0 311 ++iNum;
nuclear@0 312 }
nuclear@0 313 }
nuclear@0 314 if (iNum) {
nuclear@0 315 // Generate a new animation channel and setup everything for it
nuclear@0 316 pcScene->mNumAnimations = 1;
nuclear@0 317 pcScene->mAnimations = new aiAnimation*[1];
nuclear@0 318 aiAnimation* pcAnim = pcScene->mAnimations[0] = new aiAnimation();
nuclear@0 319 pcAnim->mNumChannels = iNum;
nuclear@0 320 pcAnim->mChannels = new aiNodeAnim*[iNum];
nuclear@0 321 pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame;
nuclear@0 322
nuclear@0 323 iNum = 0;
nuclear@0 324
nuclear@0 325 // Now iterate through all meshes and collect all data we can find
nuclear@0 326 for (i = nodes.begin();i != nodes.end();++i) {
nuclear@0 327
nuclear@0 328 ASE::BaseNode* me = *i;
nuclear@0 329 if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x )) {
nuclear@0 330 // Generate an extra channel for the camera/light target.
nuclear@0 331 // BuildNodes() does also generate an extra node, named
nuclear@0 332 // <baseName>.Target.
nuclear@0 333 aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
nuclear@0 334 nd->mNodeName.Set(me->mName + ".Target");
nuclear@0 335
nuclear@0 336 // If there is no input position channel we will need
nuclear@0 337 // to supply the default position from the node's
nuclear@0 338 // local transformation matrix.
nuclear@0 339 /*TargetAnimationHelper helper;
nuclear@0 340 if (me->mAnim.akeyPositions.empty())
nuclear@0 341 {
nuclear@0 342 aiMatrix4x4& mat = (*i)->mTransform;
nuclear@0 343 helper.SetFixedMainAnimationChannel(aiVector3D(
nuclear@0 344 mat.a4, mat.b4, mat.c4));
nuclear@0 345 }
nuclear@0 346 else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
nuclear@0 347 helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
nuclear@0 348
nuclear@0 349 helper.Process(&me->mTargetAnim.akeyPositions);*/
nuclear@0 350
nuclear@0 351 // Allocate the key array and fill it
nuclear@0 352 nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
nuclear@0 353 nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
nuclear@0 354
nuclear@0 355 ::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0],
nuclear@0 356 nd->mNumPositionKeys * sizeof(aiVectorKey));
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) {
nuclear@0 360 // Begin a new node animation channel for this node
nuclear@0 361 aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
nuclear@0 362 nd->mNodeName.Set(me->mName);
nuclear@0 363
nuclear@0 364 // copy position keys
nuclear@0 365 if (me->mAnim.akeyPositions.size() > 1 )
nuclear@0 366 {
nuclear@0 367 // Allocate the key array and fill it
nuclear@0 368 nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size();
nuclear@0 369 nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
nuclear@0 370
nuclear@0 371 ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0],
nuclear@0 372 nd->mNumPositionKeys * sizeof(aiVectorKey));
nuclear@0 373 }
nuclear@0 374 // copy rotation keys
nuclear@0 375 if (me->mAnim.akeyRotations.size() > 1 ) {
nuclear@0 376 // Allocate the key array and fill it
nuclear@0 377 nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size();
nuclear@0 378 nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
nuclear@0 379
nuclear@0 380 // --------------------------------------------------------------------
nuclear@0 381 // Rotation keys are offsets to the previous keys.
nuclear@0 382 // We have the quaternion representations of all
nuclear@0 383 // of them, so we just need to concatenate all
nuclear@0 384 // (unit-length) quaternions to get the absolute
nuclear@0 385 // rotations.
nuclear@0 386 // Rotation keys are ABSOLUTE for older files
nuclear@0 387 // --------------------------------------------------------------------
nuclear@0 388
nuclear@0 389 aiQuaternion cur;
nuclear@0 390 for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) {
nuclear@0 391 aiQuatKey q = me->mAnim.akeyRotations[a];
nuclear@0 392
nuclear@0 393 if (mParser->iFileFormat > 110) {
nuclear@0 394 cur = (a ? cur*q.mValue : q.mValue);
nuclear@0 395 q.mValue = cur.Normalize();
nuclear@0 396 }
nuclear@0 397 nd->mRotationKeys[a] = q;
nuclear@0 398
nuclear@0 399 // need this to get to Assimp quaternion conventions
nuclear@0 400 nd->mRotationKeys[a].mValue.w *= -1.f;
nuclear@0 401 }
nuclear@0 402 }
nuclear@0 403 // copy scaling keys
nuclear@0 404 if (me->mAnim.akeyScaling.size() > 1 ) {
nuclear@0 405 // Allocate the key array and fill it
nuclear@0 406 nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size();
nuclear@0 407 nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
nuclear@0 408
nuclear@0 409 ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0],
nuclear@0 410 nd->mNumScalingKeys * sizeof(aiVectorKey));
nuclear@0 411 }
nuclear@0 412 }
nuclear@0 413 }
nuclear@0 414 }
nuclear@0 415 }
nuclear@0 416
nuclear@0 417 // ------------------------------------------------------------------------------------------------
nuclear@0 418 // Build output cameras
nuclear@0 419 void ASEImporter::BuildCameras()
nuclear@0 420 {
nuclear@0 421 if (!mParser->m_vCameras.empty()) {
nuclear@0 422 pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
nuclear@0 423 pcScene->mCameras = new aiCamera*[pcScene->mNumCameras];
nuclear@0 424
nuclear@0 425 for (unsigned int i = 0; i < pcScene->mNumCameras;++i) {
nuclear@0 426 aiCamera* out = pcScene->mCameras[i] = new aiCamera();
nuclear@0 427 ASE::Camera& in = mParser->m_vCameras[i];
nuclear@0 428
nuclear@0 429 // copy members
nuclear@0 430 out->mClipPlaneFar = in.mFar;
nuclear@0 431 out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f);
nuclear@0 432 out->mHorizontalFOV = in.mFOV;
nuclear@0 433
nuclear@0 434 out->mName.Set(in.mName);
nuclear@0 435 }
nuclear@0 436 }
nuclear@0 437 }
nuclear@0 438
nuclear@0 439 // ------------------------------------------------------------------------------------------------
nuclear@0 440 // Build output lights
nuclear@0 441 void ASEImporter::BuildLights()
nuclear@0 442 {
nuclear@0 443 if (!mParser->m_vLights.empty()) {
nuclear@0 444 pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
nuclear@0 445 pcScene->mLights = new aiLight*[pcScene->mNumLights];
nuclear@0 446
nuclear@0 447 for (unsigned int i = 0; i < pcScene->mNumLights;++i) {
nuclear@0 448 aiLight* out = pcScene->mLights[i] = new aiLight();
nuclear@0 449 ASE::Light& in = mParser->m_vLights[i];
nuclear@0 450
nuclear@0 451 // The direction is encoded in the transformation matrix of the node.
nuclear@0 452 // In 3DS MAX the light source points into negative Z direction if
nuclear@0 453 // the node transformation is the identity.
nuclear@0 454 out->mDirection = aiVector3D(0.f,0.f,-1.f);
nuclear@0 455
nuclear@0 456 out->mName.Set(in.mName);
nuclear@0 457 switch (in.mLightType)
nuclear@0 458 {
nuclear@0 459 case ASE::Light::TARGET:
nuclear@0 460 out->mType = aiLightSource_SPOT;
nuclear@0 461 out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
nuclear@0 462 out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone);
nuclear@0 463 break;
nuclear@0 464
nuclear@0 465 case ASE::Light::DIRECTIONAL:
nuclear@0 466 out->mType = aiLightSource_DIRECTIONAL;
nuclear@0 467 break;
nuclear@0 468
nuclear@0 469 default:
nuclear@0 470 //case ASE::Light::OMNI:
nuclear@0 471 out->mType = aiLightSource_POINT;
nuclear@0 472 break;
nuclear@0 473 };
nuclear@0 474 out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity;
nuclear@0 475 }
nuclear@0 476 }
nuclear@0 477 }
nuclear@0 478
nuclear@0 479 // ------------------------------------------------------------------------------------------------
nuclear@0 480 void ASEImporter::AddNodes(const std::vector<BaseNode*>& nodes,
nuclear@0 481 aiNode* pcParent,const char* szName)
nuclear@0 482 {
nuclear@0 483 aiMatrix4x4 m;
nuclear@0 484 AddNodes(nodes,pcParent,szName,m);
nuclear@0 485 }
nuclear@0 486
nuclear@0 487 // ------------------------------------------------------------------------------------------------
nuclear@0 488 // Add meshes to a given node
nuclear@0 489 void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
nuclear@0 490 {
nuclear@0 491 for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) {
nuclear@0 492 // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
nuclear@0 493 const aiMesh* pcMesh = pcScene->mMeshes[i];
nuclear@0 494 const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
nuclear@0 495
nuclear@0 496 if (mesh == snode) {
nuclear@0 497 ++node->mNumMeshes;
nuclear@0 498 }
nuclear@0 499 }
nuclear@0 500
nuclear@0 501 if(node->mNumMeshes) {
nuclear@0 502 node->mMeshes = new unsigned int[node->mNumMeshes];
nuclear@0 503 for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) {
nuclear@0 504
nuclear@0 505 const aiMesh* pcMesh = pcScene->mMeshes[i];
nuclear@0 506 const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
nuclear@0 507 if (mesh == snode) {
nuclear@0 508 node->mMeshes[p++] = i;
nuclear@0 509
nuclear@0 510 // Transform all vertices of the mesh back into their local space ->
nuclear@0 511 // at the moment they are pretransformed
nuclear@0 512 aiMatrix4x4 m = mesh->mTransform;
nuclear@0 513 m.Inverse();
nuclear@0 514
nuclear@0 515 aiVector3D* pvCurPtr = pcMesh->mVertices;
nuclear@0 516 const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
nuclear@0 517 while (pvCurPtr != pvEndPtr) {
nuclear@0 518 *pvCurPtr = m * (*pvCurPtr);
nuclear@0 519 pvCurPtr++;
nuclear@0 520 }
nuclear@0 521
nuclear@0 522 // Do the same for the normal vectors, if we have them.
nuclear@0 523 // As always, inverse transpose.
nuclear@0 524 if (pcMesh->mNormals) {
nuclear@0 525 aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform );
nuclear@0 526 m3.Transpose();
nuclear@0 527
nuclear@0 528 pvCurPtr = pcMesh->mNormals;
nuclear@0 529 pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
nuclear@0 530 while (pvCurPtr != pvEndPtr) {
nuclear@0 531 *pvCurPtr = m3 * (*pvCurPtr);
nuclear@0 532 pvCurPtr++;
nuclear@0 533 }
nuclear@0 534 }
nuclear@0 535 }
nuclear@0 536 }
nuclear@0 537 }
nuclear@0 538 }
nuclear@0 539
nuclear@0 540 // ------------------------------------------------------------------------------------------------
nuclear@0 541 // Add child nodes to a given parent node
nuclear@0 542 void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
nuclear@0 543 aiNode* pcParent, const char* szName,
nuclear@0 544 const aiMatrix4x4& mat)
nuclear@0 545 {
nuclear@0 546 const size_t len = szName ? ::strlen(szName) : 0;
nuclear@0 547 ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
nuclear@0 548
nuclear@0 549 // Receives child nodes for the pcParent node
nuclear@0 550 std::vector<aiNode*> apcNodes;
nuclear@0 551
nuclear@0 552 // Now iterate through all nodes in the scene and search for one
nuclear@0 553 // which has *us* as parent.
nuclear@0 554 for (std::vector<BaseNode*>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
nuclear@0 555 const BaseNode* snode = *it;
nuclear@0 556 if (szName) {
nuclear@0 557 if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str()))
nuclear@0 558 continue;
nuclear@0 559 }
nuclear@0 560 else if (snode->mParent.length())
nuclear@0 561 continue;
nuclear@0 562
nuclear@0 563 (*it)->mProcessed = true;
nuclear@0 564
nuclear@0 565 // Allocate a new node and add it to the output data structure
nuclear@0 566 apcNodes.push_back(new aiNode());
nuclear@0 567 aiNode* node = apcNodes.back();
nuclear@0 568
nuclear@0 569 node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
nuclear@0 570 node->mParent = pcParent;
nuclear@0 571
nuclear@0 572 // Setup the transformation matrix of the node
nuclear@0 573 aiMatrix4x4 mParentAdjust = mat;
nuclear@0 574 mParentAdjust.Inverse();
nuclear@0 575 node->mTransformation = mParentAdjust*snode->mTransform;
nuclear@0 576
nuclear@0 577 // Add sub nodes - prevent stack overflow due to recursive parenting
nuclear@0 578 if (node->mName != node->mParent->mName) {
nuclear@0 579 AddNodes(nodes,node,node->mName.data,snode->mTransform);
nuclear@0 580 }
nuclear@0 581
nuclear@0 582 // Further processing depends on the type of the node
nuclear@0 583 if (snode->mType == ASE::BaseNode::Mesh) {
nuclear@0 584 // If the type of this node is "Mesh" we need to search
nuclear@0 585 // the list of output meshes in the data structure for
nuclear@0 586 // all those that belonged to this node once. This is
nuclear@0 587 // slightly inconvinient here and a better solution should
nuclear@0 588 // be used when this code is refactored next.
nuclear@0 589 AddMeshes(snode,node);
nuclear@0 590 }
nuclear@0 591 else if (is_not_qnan( snode->mTargetPosition.x )) {
nuclear@0 592 // If this is a target camera or light we generate a small
nuclear@0 593 // child node which marks the position of the camera
nuclear@0 594 // target (the direction information is contained in *this*
nuclear@0 595 // node's animation track but the exact target position
nuclear@0 596 // would be lost otherwise)
nuclear@0 597 if (!node->mNumChildren) {
nuclear@0 598 node->mChildren = new aiNode*[1];
nuclear@0 599 }
nuclear@0 600
nuclear@0 601 aiNode* nd = new aiNode();
nuclear@0 602
nuclear@0 603 nd->mName.Set ( snode->mName + ".Target" );
nuclear@0 604
nuclear@0 605 nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4;
nuclear@0 606 nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4;
nuclear@0 607 nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4;
nuclear@0 608
nuclear@0 609 nd->mParent = node;
nuclear@0 610
nuclear@0 611 // The .Target node is always the first child node
nuclear@0 612 for (unsigned int m = 0; m < node->mNumChildren;++m)
nuclear@0 613 node->mChildren[m+1] = node->mChildren[m];
nuclear@0 614
nuclear@0 615 node->mChildren[0] = nd;
nuclear@0 616 node->mNumChildren++;
nuclear@0 617
nuclear@0 618 // What we did is so great, it is at least worth a debug message
nuclear@0 619 DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")");
nuclear@0 620 }
nuclear@0 621 }
nuclear@0 622
nuclear@0 623 // Allocate enough space for the child nodes
nuclear@0 624 // We allocate one slot more in case this is a target camera/light
nuclear@0 625 pcParent->mNumChildren = (unsigned int)apcNodes.size();
nuclear@0 626 if (pcParent->mNumChildren) {
nuclear@0 627 pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */];
nuclear@0 628
nuclear@0 629 // now build all nodes for our nice new children
nuclear@0 630 for (unsigned int p = 0; p < apcNodes.size();++p)
nuclear@0 631 pcParent->mChildren[p] = apcNodes[p];
nuclear@0 632 }
nuclear@0 633 return;
nuclear@0 634 }
nuclear@0 635
nuclear@0 636 // ------------------------------------------------------------------------------------------------
nuclear@0 637 // Build the output node graph
nuclear@0 638 void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
nuclear@0 639 ai_assert(NULL != pcScene);
nuclear@0 640
nuclear@0 641 // allocate the one and only root node
nuclear@0 642 aiNode* root = pcScene->mRootNode = new aiNode();
nuclear@0 643 root->mName.Set("<ASERoot>");
nuclear@0 644
nuclear@0 645 // Setup the coordinate system transformation
nuclear@0 646 pcScene->mRootNode->mNumChildren = 1;
nuclear@0 647 pcScene->mRootNode->mChildren = new aiNode*[1];
nuclear@0 648 aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode();
nuclear@0 649 ch->mParent = root;
nuclear@0 650
nuclear@0 651 // Change the transformation matrix of all nodes
nuclear@0 652 for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) {
nuclear@0 653 aiMatrix4x4& m = (*it)->mTransform;
nuclear@0 654 m.Transpose(); // row-order vs column-order
nuclear@0 655 }
nuclear@0 656
nuclear@0 657 // add all nodes
nuclear@0 658 AddNodes(nodes,ch,NULL);
nuclear@0 659
nuclear@0 660 // now iterate through al nodes and find those that have not yet
nuclear@0 661 // been added to the nodegraph (= their parent could not be recognized)
nuclear@0 662 std::vector<const BaseNode*> aiList;
nuclear@0 663 for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) {
nuclear@0 664 if ((*it)->mProcessed) {
nuclear@0 665 continue;
nuclear@0 666 }
nuclear@0 667
nuclear@0 668 // check whether our parent is known
nuclear@0 669 bool bKnowParent = false;
nuclear@0 670
nuclear@0 671 // search the list another time, starting *here* and try to find out whether
nuclear@0 672 // there is a node that references *us* as a parent
nuclear@0 673 for (std::vector<BaseNode*>::const_iterator it2 = nodes.begin();it2 != end; ++it2) {
nuclear@0 674 if (it2 == it) {
nuclear@0 675 continue;
nuclear@0 676 }
nuclear@0 677
nuclear@0 678 if ((*it2)->mName == (*it)->mParent) {
nuclear@0 679 bKnowParent = true;
nuclear@0 680 break;
nuclear@0 681 }
nuclear@0 682 }
nuclear@0 683 if (!bKnowParent) {
nuclear@0 684 aiList.push_back(*it);
nuclear@0 685 }
nuclear@0 686 }
nuclear@0 687
nuclear@0 688 // Are there ane orphaned nodes?
nuclear@0 689 if (!aiList.empty()) {
nuclear@0 690 std::vector<aiNode*> apcNodes;
nuclear@0 691 apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren);
nuclear@0 692
nuclear@0 693 for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i)
nuclear@0 694 apcNodes.push_back(pcScene->mRootNode->mChildren[i]);
nuclear@0 695
nuclear@0 696 delete[] pcScene->mRootNode->mChildren;
nuclear@0 697 for (std::vector<const BaseNode*>::/*const_*/iterator i = aiList.begin();i != aiList.end();++i) {
nuclear@0 698 const ASE::BaseNode* src = *i;
nuclear@0 699
nuclear@0 700 // The parent is not known, so we can assume that we must add
nuclear@0 701 // this node to the root node of the whole scene
nuclear@0 702 aiNode* pcNode = new aiNode();
nuclear@0 703 pcNode->mParent = pcScene->mRootNode;
nuclear@0 704 pcNode->mName.Set(src->mName);
nuclear@0 705 AddMeshes(src,pcNode);
nuclear@0 706 AddNodes(nodes,pcNode,pcNode->mName.data);
nuclear@0 707 apcNodes.push_back(pcNode);
nuclear@0 708 }
nuclear@0 709
nuclear@0 710 // Regenerate our output array
nuclear@0 711 pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()];
nuclear@0 712 for (unsigned int i = 0; i < apcNodes.size();++i)
nuclear@0 713 pcScene->mRootNode->mChildren[i] = apcNodes[i];
nuclear@0 714
nuclear@0 715 pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
nuclear@0 716 }
nuclear@0 717
nuclear@0 718 // Reset the third color set to NULL - we used this field to store a temporary pointer
nuclear@0 719 for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
nuclear@0 720 pcScene->mMeshes[i]->mColors[2] = NULL;
nuclear@0 721
nuclear@0 722 // The root node should not have at least one child or the file is valid
nuclear@0 723 if (!pcScene->mRootNode->mNumChildren) {
nuclear@0 724 throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt");
nuclear@0 725 }
nuclear@0 726
nuclear@0 727 // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
nuclear@0 728 pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
nuclear@0 729 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
nuclear@0 730 }
nuclear@0 731
nuclear@0 732 // ------------------------------------------------------------------------------------------------
nuclear@0 733 // Convert the imported data to the internal verbose representation
nuclear@0 734 void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
nuclear@0 735 // allocate output storage
nuclear@0 736 std::vector<aiVector3D> mPositions;
nuclear@0 737 std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
nuclear@0 738 std::vector<aiColor4D> mVertexColors;
nuclear@0 739 std::vector<aiVector3D> mNormals;
nuclear@0 740 std::vector<BoneVertex> mBoneVertices;
nuclear@0 741
nuclear@0 742 unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3;
nuclear@0 743 mPositions.resize(iSize);
nuclear@0 744
nuclear@0 745 // optional texture coordinates
nuclear@0 746 for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) {
nuclear@0 747 if (!mesh.amTexCoords[i].empty()) {
nuclear@0 748 amTexCoords[i].resize(iSize);
nuclear@0 749 }
nuclear@0 750 }
nuclear@0 751 // optional vertex colors
nuclear@0 752 if (!mesh.mVertexColors.empty()) {
nuclear@0 753 mVertexColors.resize(iSize);
nuclear@0 754 }
nuclear@0 755
nuclear@0 756 // optional vertex normals (vertex normals can simply be copied)
nuclear@0 757 if (!mesh.mNormals.empty()) {
nuclear@0 758 mNormals.resize(iSize);
nuclear@0 759 }
nuclear@0 760 // bone vertices. There is no need to change the bone list
nuclear@0 761 if (!mesh.mBoneVertices.empty()) {
nuclear@0 762 mBoneVertices.resize(iSize);
nuclear@0 763 }
nuclear@0 764
nuclear@0 765 // iterate through all faces in the mesh
nuclear@0 766 unsigned int iCurrent = 0, fi = 0;
nuclear@0 767 for (std::vector<ASE::Face>::iterator i = mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) {
nuclear@0 768 for (unsigned int n = 0; n < 3;++n,++iCurrent)
nuclear@0 769 {
nuclear@0 770 mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
nuclear@0 771
nuclear@0 772 // add texture coordinates
nuclear@0 773 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
nuclear@0 774 if (mesh.amTexCoords[c].empty())break;
nuclear@0 775 amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
nuclear@0 776 }
nuclear@0 777 // add vertex colors
nuclear@0 778 if (!mesh.mVertexColors.empty()) {
nuclear@0 779 mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]];
nuclear@0 780 }
nuclear@0 781 // add normal vectors
nuclear@0 782 if (!mesh.mNormals.empty()) {
nuclear@0 783 mNormals[iCurrent] = mesh.mNormals[fi*3+n];
nuclear@0 784 mNormals[iCurrent].Normalize();
nuclear@0 785 }
nuclear@0 786
nuclear@0 787 // handle bone vertices
nuclear@0 788 if ((*i).mIndices[n] < mesh.mBoneVertices.size()) {
nuclear@0 789 // (sometimes this will cause bone verts to be duplicated
nuclear@0 790 // however, I' quite sure Schrompf' JoinVerticesStep
nuclear@0 791 // will fix that again ...)
nuclear@0 792 mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]];
nuclear@0 793 }
nuclear@0 794 (*i).mIndices[n] = iCurrent;
nuclear@0 795 }
nuclear@0 796 }
nuclear@0 797
nuclear@0 798 // replace the old arrays
nuclear@0 799 mesh.mNormals = mNormals;
nuclear@0 800 mesh.mPositions = mPositions;
nuclear@0 801 mesh.mVertexColors = mVertexColors;
nuclear@0 802
nuclear@0 803 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
nuclear@0 804 mesh.amTexCoords[c] = amTexCoords[c];
nuclear@0 805 }
nuclear@0 806
nuclear@0 807 // ------------------------------------------------------------------------------------------------
nuclear@0 808 // Copy a texture from the ASE structs to the output material
nuclear@0 809 void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
nuclear@0 810 {
nuclear@0 811 // Setup the texture name
nuclear@0 812 aiString tex;
nuclear@0 813 tex.Set( texture.mMapName);
nuclear@0 814 mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
nuclear@0 815
nuclear@0 816 // Setup the texture blend factor
nuclear@0 817 if (is_not_qnan(texture.mTextureBlend))
nuclear@0 818 mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
nuclear@0 819
nuclear@0 820 // Setup texture UV transformations
nuclear@0 821 mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
nuclear@0 822 }
nuclear@0 823
nuclear@0 824 // ------------------------------------------------------------------------------------------------
nuclear@0 825 // Convert from ASE material to output material
nuclear@0 826 void ASEImporter::ConvertMaterial(ASE::Material& mat)
nuclear@0 827 {
nuclear@0 828 // LARGE TODO: Much code her is copied from 3DS ... join them maybe?
nuclear@0 829
nuclear@0 830 // Allocate the output material
nuclear@0 831 mat.pcInstance = new aiMaterial();
nuclear@0 832
nuclear@0 833 // At first add the base ambient color of the
nuclear@0 834 // scene to the material
nuclear@0 835 mat.mAmbient.r += mParser->m_clrAmbient.r;
nuclear@0 836 mat.mAmbient.g += mParser->m_clrAmbient.g;
nuclear@0 837 mat.mAmbient.b += mParser->m_clrAmbient.b;
nuclear@0 838
nuclear@0 839 aiString name;
nuclear@0 840 name.Set( mat.mName);
nuclear@0 841 mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME);
nuclear@0 842
nuclear@0 843 // material colors
nuclear@0 844 mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
nuclear@0 845 mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 846 mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
nuclear@0 847 mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
nuclear@0 848
nuclear@0 849 // shininess
nuclear@0 850 if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
nuclear@0 851 {
nuclear@0 852 mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
nuclear@0 853 mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
nuclear@0 854 }
nuclear@0 855 // If there is no shininess, we can disable phong lighting
nuclear@0 856 else if (D3DS::Discreet3DS::Metal == mat.mShading ||
nuclear@0 857 D3DS::Discreet3DS::Phong == mat.mShading ||
nuclear@0 858 D3DS::Discreet3DS::Blinn == mat.mShading)
nuclear@0 859 {
nuclear@0 860 mat.mShading = D3DS::Discreet3DS::Gouraud;
nuclear@0 861 }
nuclear@0 862
nuclear@0 863 // opacity
nuclear@0 864 mat.pcInstance->AddProperty<float>( &mat.mTransparency,1,AI_MATKEY_OPACITY);
nuclear@0 865
nuclear@0 866 // Two sided rendering?
nuclear@0 867 if (mat.mTwoSided)
nuclear@0 868 {
nuclear@0 869 int i = 1;
nuclear@0 870 mat.pcInstance->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
nuclear@0 871 }
nuclear@0 872
nuclear@0 873 // shading mode
nuclear@0 874 aiShadingMode eShading = aiShadingMode_NoShading;
nuclear@0 875 switch (mat.mShading)
nuclear@0 876 {
nuclear@0 877 case D3DS::Discreet3DS::Flat:
nuclear@0 878 eShading = aiShadingMode_Flat; break;
nuclear@0 879 case D3DS::Discreet3DS::Phong :
nuclear@0 880 eShading = aiShadingMode_Phong; break;
nuclear@0 881 case D3DS::Discreet3DS::Blinn :
nuclear@0 882 eShading = aiShadingMode_Blinn; break;
nuclear@0 883
nuclear@0 884 // I don't know what "Wire" shading should be,
nuclear@0 885 // assume it is simple lambertian diffuse (L dot N) shading
nuclear@0 886 case D3DS::Discreet3DS::Wire:
nuclear@0 887 {
nuclear@0 888 // set the wireframe flag
nuclear@0 889 unsigned int iWire = 1;
nuclear@0 890 mat.pcInstance->AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
nuclear@0 891 }
nuclear@0 892 case D3DS::Discreet3DS::Gouraud:
nuclear@0 893 eShading = aiShadingMode_Gouraud; break;
nuclear@0 894 case D3DS::Discreet3DS::Metal :
nuclear@0 895 eShading = aiShadingMode_CookTorrance; break;
nuclear@0 896 }
nuclear@0 897 mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
nuclear@0 898
nuclear@0 899 // DIFFUSE texture
nuclear@0 900 if( mat.sTexDiffuse.mMapName.length() > 0)
nuclear@0 901 CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE);
nuclear@0 902
nuclear@0 903 // SPECULAR texture
nuclear@0 904 if( mat.sTexSpecular.mMapName.length() > 0)
nuclear@0 905 CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR);
nuclear@0 906
nuclear@0 907 // AMBIENT texture
nuclear@0 908 if( mat.sTexAmbient.mMapName.length() > 0)
nuclear@0 909 CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT);
nuclear@0 910
nuclear@0 911 // OPACITY texture
nuclear@0 912 if( mat.sTexOpacity.mMapName.length() > 0)
nuclear@0 913 CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY);
nuclear@0 914
nuclear@0 915 // EMISSIVE texture
nuclear@0 916 if( mat.sTexEmissive.mMapName.length() > 0)
nuclear@0 917 CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE);
nuclear@0 918
nuclear@0 919 // BUMP texture
nuclear@0 920 if( mat.sTexBump.mMapName.length() > 0)
nuclear@0 921 CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT);
nuclear@0 922
nuclear@0 923 // SHININESS texture
nuclear@0 924 if( mat.sTexShininess.mMapName.length() > 0)
nuclear@0 925 CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS);
nuclear@0 926
nuclear@0 927 // store the name of the material itself, too
nuclear@0 928 if( mat.mName.length() > 0) {
nuclear@0 929 aiString tex;tex.Set( mat.mName);
nuclear@0 930 mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME);
nuclear@0 931 }
nuclear@0 932 return;
nuclear@0 933 }
nuclear@0 934
nuclear@0 935 // ------------------------------------------------------------------------------------------------
nuclear@0 936 // Build output meshes
nuclear@0 937 void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
nuclear@0 938 {
nuclear@0 939 // validate the material index of the mesh
nuclear@0 940 if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
nuclear@0 941 mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
nuclear@0 942 DefaultLogger::get()->warn("Material index is out of range");
nuclear@0 943 }
nuclear@0 944
nuclear@0 945 // If the material the mesh is assigned to is consisting of submeshes, split it
nuclear@0 946 if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
nuclear@0 947 std::vector<ASE::Material> vSubMaterials = mParser->
nuclear@0 948 m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
nuclear@0 949
nuclear@0 950 std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
nuclear@0 951
nuclear@0 952 // build a list of all faces per submaterial
nuclear@0 953 for (unsigned int i = 0; i < mesh.mFaces.size();++i) {
nuclear@0 954 // check range
nuclear@0 955 if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
nuclear@0 956 DefaultLogger::get()->warn("Submaterial index is out of range");
nuclear@0 957
nuclear@0 958 // use the last material instead
nuclear@0 959 aiSplit[vSubMaterials.size()-1].push_back(i);
nuclear@0 960 }
nuclear@0 961 else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
nuclear@0 962 }
nuclear@0 963
nuclear@0 964 // now generate submeshes
nuclear@0 965 for (unsigned int p = 0; p < vSubMaterials.size();++p) {
nuclear@0 966 if (!aiSplit[p].empty()) {
nuclear@0 967
nuclear@0 968 aiMesh* p_pcOut = new aiMesh();
nuclear@0 969 p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 970
nuclear@0 971 // let the sub material index
nuclear@0 972 p_pcOut->mMaterialIndex = p;
nuclear@0 973
nuclear@0 974 // we will need this material
nuclear@0 975 mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true;
nuclear@0 976
nuclear@0 977 // store the real index here ... color channel 3
nuclear@0 978 p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
nuclear@0 979
nuclear@0 980 // store a pointer to the mesh in color channel 2
nuclear@0 981 p_pcOut->mColors[2] = (aiColor4D*) &mesh;
nuclear@0 982 avOutMeshes.push_back(p_pcOut);
nuclear@0 983
nuclear@0 984 // convert vertices
nuclear@0 985 p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3;
nuclear@0 986 p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
nuclear@0 987
nuclear@0 988 // receive output vertex weights
nuclear@0 989 std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
nuclear@0 990 if (!mesh.mBones.empty()) {
nuclear@0 991 avOutputBones = new std::vector<std::pair<unsigned int, float> >[mesh.mBones.size()];
nuclear@0 992 }
nuclear@0 993
nuclear@0 994 // allocate enough storage for faces
nuclear@0 995 p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
nuclear@0 996
nuclear@0 997 unsigned int iBase = 0,iIndex;
nuclear@0 998 if (p_pcOut->mNumVertices) {
nuclear@0 999 p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
nuclear@0 1000 p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices];
nuclear@0 1001 for (unsigned int q = 0; q < aiSplit[p].size();++q) {
nuclear@0 1002
nuclear@0 1003 iIndex = aiSplit[p][q];
nuclear@0 1004
nuclear@0 1005 p_pcOut->mFaces[q].mIndices = new unsigned int[3];
nuclear@0 1006 p_pcOut->mFaces[q].mNumIndices = 3;
nuclear@0 1007
nuclear@0 1008 for (unsigned int t = 0; t < 3;++t, ++iBase) {
nuclear@0 1009 const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
nuclear@0 1010
nuclear@0 1011 p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2];
nuclear@0 1012 p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2];
nuclear@0 1013
nuclear@0 1014 // convert bones, if existing
nuclear@0 1015 if (!mesh.mBones.empty()) {
nuclear@0 1016 // check whether there is a vertex weight for this vertex index
nuclear@0 1017 if (iIndex2 < mesh.mBoneVertices.size()) {
nuclear@0 1018
nuclear@0 1019 for (std::vector<std::pair<int,float> >::const_iterator
nuclear@0 1020 blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin();
nuclear@0 1021 blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) {
nuclear@0 1022
nuclear@0 1023 // NOTE: illegal cases have already been filtered out
nuclear@0 1024 avOutputBones[(*blubb).first].push_back(std::pair<unsigned int, float>(
nuclear@0 1025 iBase,(*blubb).second));
nuclear@0 1026 }
nuclear@0 1027 }
nuclear@0 1028 }
nuclear@0 1029 p_pcOut->mFaces[q].mIndices[t] = iBase;
nuclear@0 1030 }
nuclear@0 1031 }
nuclear@0 1032 }
nuclear@0 1033 // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
nuclear@0 1034 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
nuclear@0 1035 if (!mesh.amTexCoords[c].empty())
nuclear@0 1036 {
nuclear@0 1037 p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
nuclear@0 1038 iBase = 0;
nuclear@0 1039 for (unsigned int q = 0; q < aiSplit[p].size();++q) {
nuclear@0 1040 iIndex = aiSplit[p][q];
nuclear@0 1041 for (unsigned int t = 0; t < 3;++t) {
nuclear@0 1042 p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
nuclear@0 1043 }
nuclear@0 1044 }
nuclear@0 1045 // Setup the number of valid vertex components
nuclear@0 1046 p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
nuclear@0 1047 }
nuclear@0 1048 }
nuclear@0 1049
nuclear@0 1050 // Convert vertex colors (only one set supported)
nuclear@0 1051 if (!mesh.mVertexColors.empty()){
nuclear@0 1052 p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
nuclear@0 1053 iBase = 0;
nuclear@0 1054 for (unsigned int q = 0; q < aiSplit[p].size();++q) {
nuclear@0 1055 iIndex = aiSplit[p][q];
nuclear@0 1056 for (unsigned int t = 0; t < 3;++t) {
nuclear@0 1057 p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]];
nuclear@0 1058 }
nuclear@0 1059 }
nuclear@0 1060 }
nuclear@0 1061 // Copy bones
nuclear@0 1062 if (!mesh.mBones.empty()) {
nuclear@0 1063 p_pcOut->mNumBones = 0;
nuclear@0 1064 for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
nuclear@0 1065 if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++;
nuclear@0 1066
nuclear@0 1067 p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ];
nuclear@0 1068 aiBone** pcBone = p_pcOut->mBones;
nuclear@0 1069 for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
nuclear@0 1070 {
nuclear@0 1071 if (!avOutputBones[mrspock].empty()) {
nuclear@0 1072 // we will need this bone. add it to the output mesh and
nuclear@0 1073 // add all per-vertex weights
nuclear@0 1074 aiBone* pc = *pcBone = new aiBone();
nuclear@0 1075 pc->mName.Set(mesh.mBones[mrspock].mName);
nuclear@0 1076
nuclear@0 1077 pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
nuclear@0 1078 pc->mWeights = new aiVertexWeight[pc->mNumWeights];
nuclear@0 1079
nuclear@0 1080 for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
nuclear@0 1081 {
nuclear@0 1082 const std::pair<unsigned int,float>& ref = avOutputBones[mrspock][captainkirk];
nuclear@0 1083 pc->mWeights[captainkirk].mVertexId = ref.first;
nuclear@0 1084 pc->mWeights[captainkirk].mWeight = ref.second;
nuclear@0 1085 }
nuclear@0 1086 ++pcBone;
nuclear@0 1087 }
nuclear@0 1088 }
nuclear@0 1089 // delete allocated storage
nuclear@0 1090 delete[] avOutputBones;
nuclear@0 1091 }
nuclear@0 1092 }
nuclear@0 1093 }
nuclear@0 1094 // delete storage
nuclear@0 1095 delete[] aiSplit;
nuclear@0 1096 }
nuclear@0 1097 else
nuclear@0 1098 {
nuclear@0 1099 // Otherwise we can simply copy the data to one output mesh
nuclear@0 1100 // This codepath needs less memory and uses fast memcpy()s
nuclear@0 1101 // to do the actual copying. So I think it is worth the
nuclear@0 1102 // effort here.
nuclear@0 1103
nuclear@0 1104 aiMesh* p_pcOut = new aiMesh();
nuclear@0 1105 p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 1106
nuclear@0 1107 // set an empty sub material index
nuclear@0 1108 p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX;
nuclear@0 1109 mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true;
nuclear@0 1110
nuclear@0 1111 // store the real index here ... in color channel 3
nuclear@0 1112 p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
nuclear@0 1113
nuclear@0 1114 // store a pointer to the mesh in color channel 2
nuclear@0 1115 p_pcOut->mColors[2] = (aiColor4D*) &mesh;
nuclear@0 1116 avOutMeshes.push_back(p_pcOut);
nuclear@0 1117
nuclear@0 1118 // If the mesh hasn't faces or vertices, there are two cases
nuclear@0 1119 // possible: 1. the model is invalid. 2. This is a dummy
nuclear@0 1120 // helper object which we are going to remove later ...
nuclear@0 1121 if (mesh.mFaces.empty() || mesh.mPositions.empty()) {
nuclear@0 1122 return;
nuclear@0 1123 }
nuclear@0 1124
nuclear@0 1125 // convert vertices
nuclear@0 1126 p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size();
nuclear@0 1127 p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size();
nuclear@0 1128
nuclear@0 1129 // allocate enough storage for faces
nuclear@0 1130 p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
nuclear@0 1131
nuclear@0 1132 // copy vertices
nuclear@0 1133 p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()];
nuclear@0 1134 memcpy(p_pcOut->mVertices,&mesh.mPositions[0],
nuclear@0 1135 mesh.mPositions.size() * sizeof(aiVector3D));
nuclear@0 1136
nuclear@0 1137 // copy normals
nuclear@0 1138 p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()];
nuclear@0 1139 memcpy(p_pcOut->mNormals,&mesh.mNormals[0],
nuclear@0 1140 mesh.mNormals.size() * sizeof(aiVector3D));
nuclear@0 1141
nuclear@0 1142 // copy texture coordinates
nuclear@0 1143 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
nuclear@0 1144 if (!mesh.amTexCoords[c].empty()) {
nuclear@0 1145 p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()];
nuclear@0 1146 memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0],
nuclear@0 1147 mesh.amTexCoords[c].size() * sizeof(aiVector3D));
nuclear@0 1148
nuclear@0 1149 // setup the number of valid vertex components
nuclear@0 1150 p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
nuclear@0 1151 }
nuclear@0 1152 }
nuclear@0 1153
nuclear@0 1154 // copy vertex colors
nuclear@0 1155 if (!mesh.mVertexColors.empty()) {
nuclear@0 1156 p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()];
nuclear@0 1157 memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0],
nuclear@0 1158 mesh.mVertexColors.size() * sizeof(aiColor4D));
nuclear@0 1159 }
nuclear@0 1160
nuclear@0 1161 // copy faces
nuclear@0 1162 for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) {
nuclear@0 1163 p_pcOut->mFaces[iFace].mNumIndices = 3;
nuclear@0 1164 p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
nuclear@0 1165
nuclear@0 1166 // copy indices
nuclear@0 1167 p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0];
nuclear@0 1168 p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1];
nuclear@0 1169 p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2];
nuclear@0 1170 }
nuclear@0 1171
nuclear@0 1172 // copy vertex bones
nuclear@0 1173 if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) {
nuclear@0 1174 std::vector<std::vector<aiVertexWeight> > avBonesOut( mesh.mBones.size() );
nuclear@0 1175
nuclear@0 1176 // find all vertex weights for this bone
nuclear@0 1177 unsigned int quak = 0;
nuclear@0 1178 for (std::vector<BoneVertex>::const_iterator harrypotter = mesh.mBoneVertices.begin();
nuclear@0 1179 harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) {
nuclear@0 1180
nuclear@0 1181 for (std::vector<std::pair<int,float> >::const_iterator
nuclear@0 1182 ronaldweasley = (*harrypotter).mBoneWeights.begin();
nuclear@0 1183 ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
nuclear@0 1184 {
nuclear@0 1185 aiVertexWeight weight;
nuclear@0 1186 weight.mVertexId = quak;
nuclear@0 1187 weight.mWeight = (*ronaldweasley).second;
nuclear@0 1188 avBonesOut[(*ronaldweasley).first].push_back(weight);
nuclear@0 1189 }
nuclear@0 1190 }
nuclear@0 1191
nuclear@0 1192 // now build a final bone list
nuclear@0 1193 p_pcOut->mNumBones = 0;
nuclear@0 1194 for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)
nuclear@0 1195 if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++;
nuclear@0 1196
nuclear@0 1197 p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones];
nuclear@0 1198 aiBone** pcBone = p_pcOut->mBones;
nuclear@0 1199 for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) {
nuclear@0 1200 if (!avBonesOut[jfkennedy].empty()) {
nuclear@0 1201 aiBone* pc = *pcBone = new aiBone();
nuclear@0 1202 pc->mName.Set(mesh.mBones[jfkennedy].mName);
nuclear@0 1203 pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size();
nuclear@0 1204 pc->mWeights = new aiVertexWeight[pc->mNumWeights];
nuclear@0 1205 ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0],
nuclear@0 1206 sizeof(aiVertexWeight) * pc->mNumWeights);
nuclear@0 1207 ++pcBone;
nuclear@0 1208 }
nuclear@0 1209 }
nuclear@0 1210 }
nuclear@0 1211 }
nuclear@0 1212 }
nuclear@0 1213
nuclear@0 1214 // ------------------------------------------------------------------------------------------------
nuclear@0 1215 // Setup proper material indices and build output materials
nuclear@0 1216 void ASEImporter::BuildMaterialIndices()
nuclear@0 1217 {
nuclear@0 1218 ai_assert(NULL != pcScene);
nuclear@0 1219
nuclear@0 1220 // iterate through all materials and check whether we need them
nuclear@0 1221 for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
nuclear@0 1222 {
nuclear@0 1223 ASE::Material& mat = mParser->m_vMaterials[iMat];
nuclear@0 1224 if (mat.bNeed) {
nuclear@0 1225 // Convert it to the aiMaterial layout
nuclear@0 1226 ConvertMaterial(mat);
nuclear@0 1227 ++pcScene->mNumMaterials;
nuclear@0 1228 }
nuclear@0 1229 for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
nuclear@0 1230 {
nuclear@0 1231 ASE::Material& submat = mat.avSubMaterials[iSubMat];
nuclear@0 1232 if (submat.bNeed) {
nuclear@0 1233 // Convert it to the aiMaterial layout
nuclear@0 1234 ConvertMaterial(submat);
nuclear@0 1235 ++pcScene->mNumMaterials;
nuclear@0 1236 }
nuclear@0 1237 }
nuclear@0 1238 }
nuclear@0 1239
nuclear@0 1240 // allocate the output material array
nuclear@0 1241 pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials];
nuclear@0 1242 D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials];
nuclear@0 1243
nuclear@0 1244 unsigned int iNum = 0;
nuclear@0 1245 for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) {
nuclear@0 1246 ASE::Material& mat = mParser->m_vMaterials[iMat];
nuclear@0 1247 if (mat.bNeed)
nuclear@0 1248 {
nuclear@0 1249 ai_assert(NULL != mat.pcInstance);
nuclear@0 1250 pcScene->mMaterials[iNum] = mat.pcInstance;
nuclear@0 1251
nuclear@0 1252 // Store the internal material, too
nuclear@0 1253 pcIntMaterials[iNum] = &mat;
nuclear@0 1254
nuclear@0 1255 // Iterate through all meshes and search for one which is using
nuclear@0 1256 // this top-level material index
nuclear@0 1257 for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
nuclear@0 1258 {
nuclear@0 1259 aiMesh* mesh = pcScene->mMeshes[iMesh];
nuclear@0 1260 if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
nuclear@0 1261 iMat == (uintptr_t)mesh->mColors[3])
nuclear@0 1262 {
nuclear@0 1263 mesh->mMaterialIndex = iNum;
nuclear@0 1264 mesh->mColors[3] = NULL;
nuclear@0 1265 }
nuclear@0 1266 }
nuclear@0 1267 iNum++;
nuclear@0 1268 }
nuclear@0 1269 for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) {
nuclear@0 1270 ASE::Material& submat = mat.avSubMaterials[iSubMat];
nuclear@0 1271 if (submat.bNeed) {
nuclear@0 1272 ai_assert(NULL != submat.pcInstance);
nuclear@0 1273 pcScene->mMaterials[iNum] = submat.pcInstance;
nuclear@0 1274
nuclear@0 1275 // Store the internal material, too
nuclear@0 1276 pcIntMaterials[iNum] = &submat;
nuclear@0 1277
nuclear@0 1278 // Iterate through all meshes and search for one which is using
nuclear@0 1279 // this sub-level material index
nuclear@0 1280 for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) {
nuclear@0 1281 aiMesh* mesh = pcScene->mMeshes[iMesh];
nuclear@0 1282
nuclear@0 1283 if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) {
nuclear@0 1284 mesh->mMaterialIndex = iNum;
nuclear@0 1285 mesh->mColors[3] = NULL;
nuclear@0 1286 }
nuclear@0 1287 }
nuclear@0 1288 iNum++;
nuclear@0 1289 }
nuclear@0 1290 }
nuclear@0 1291 }
nuclear@0 1292
nuclear@0 1293 // Dekete our temporary array
nuclear@0 1294 delete[] pcIntMaterials;
nuclear@0 1295 }
nuclear@0 1296
nuclear@0 1297 // ------------------------------------------------------------------------------------------------
nuclear@0 1298 // Generate normal vectors basing on smoothing groups
nuclear@0 1299 bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) {
nuclear@0 1300
nuclear@0 1301 if (!mesh.mNormals.empty() && !configRecomputeNormals)
nuclear@0 1302 {
nuclear@0 1303 // Check whether there are only uninitialized normals. If there are
nuclear@0 1304 // some, skip all normals from the file and compute them on our own
nuclear@0 1305 for (std::vector<aiVector3D>::const_iterator qq = mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) {
nuclear@0 1306 if ((*qq).x || (*qq).y || (*qq).z)
nuclear@0 1307 {
nuclear@0 1308 return true;
nuclear@0 1309 }
nuclear@0 1310 }
nuclear@0 1311 }
nuclear@0 1312 // The array is reused.
nuclear@0 1313 ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
nuclear@0 1314 return false;
nuclear@0 1315 }
nuclear@0 1316
nuclear@0 1317 #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER