vrshoot
diff libs/assimp/ASELoader.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/ASELoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,1317 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file ASELoader.cpp 1.46 + * @brief Implementation of the ASE importer class 1.47 + */ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 +#include "assimp/config.h" 1.51 +#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER 1.52 + 1.53 +// internal headers 1.54 +#include "ASELoader.h" 1.55 +#include "StringComparison.h" 1.56 +#include "SkeletonMeshBuilder.h" 1.57 +#include "TargetAnimation.h" 1.58 + 1.59 +// utilities 1.60 +#include "fast_atof.h" 1.61 + 1.62 +using namespace Assimp; 1.63 +using namespace Assimp::ASE; 1.64 + 1.65 +static const aiImporterDesc desc = { 1.66 + "ASE Importer", 1.67 + "", 1.68 + "", 1.69 + "Similar to 3DS but text-encoded", 1.70 + aiImporterFlags_SupportTextFlavour, 1.71 + 0, 1.72 + 0, 1.73 + 0, 1.74 + 0, 1.75 + "ase ask" 1.76 +}; 1.77 + 1.78 +// ------------------------------------------------------------------------------------------------ 1.79 +// Constructor to be privately used by Importer 1.80 +ASEImporter::ASEImporter() 1.81 +: noSkeletonMesh() 1.82 +{} 1.83 + 1.84 +// ------------------------------------------------------------------------------------------------ 1.85 +// Destructor, private as well 1.86 +ASEImporter::~ASEImporter() 1.87 +{} 1.88 + 1.89 +// ------------------------------------------------------------------------------------------------ 1.90 +// Returns whether the class can handle the format of the given file. 1.91 +bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const 1.92 +{ 1.93 + // check file extension 1.94 + const std::string extension = GetExtension(pFile); 1.95 + 1.96 + if( extension == "ase" || extension == "ask") 1.97 + return true; 1.98 + 1.99 + if ((!extension.length() || cs) && pIOHandler) { 1.100 + const char* tokens[] = {"*3dsmax_asciiexport"}; 1.101 + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); 1.102 + } 1.103 + return false; 1.104 +} 1.105 + 1.106 +// ------------------------------------------------------------------------------------------------ 1.107 +// Loader meta information 1.108 +const aiImporterDesc* ASEImporter::GetInfo () const 1.109 +{ 1.110 + return &desc; 1.111 +} 1.112 + 1.113 +// ------------------------------------------------------------------------------------------------ 1.114 +// Setup configuration options 1.115 +void ASEImporter::SetupProperties(const Importer* pImp) 1.116 +{ 1.117 + configRecomputeNormals = (pImp->GetPropertyInteger( 1.118 + AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false); 1.119 + 1.120 + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; 1.121 +} 1.122 + 1.123 +// ------------------------------------------------------------------------------------------------ 1.124 +// Imports the given file into the given scene structure. 1.125 +void ASEImporter::InternReadFile( const std::string& pFile, 1.126 + aiScene* pScene, IOSystem* pIOHandler) 1.127 +{ 1.128 + boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); 1.129 + 1.130 + // Check whether we can read from the file 1.131 + if( file.get() == NULL) { 1.132 + throw DeadlyImportError( "Failed to open ASE file " + pFile + "."); 1.133 + } 1.134 + 1.135 + // Allocate storage and copy the contents of the file to a memory buffer 1.136 + std::vector<char> mBuffer2; 1.137 + TextFileToBuffer(file.get(),mBuffer2); 1.138 + 1.139 + this->mBuffer = &mBuffer2[0]; 1.140 + this->pcScene = pScene; 1.141 + 1.142 + // ------------------------------------------------------------------ 1.143 + // Guess the file format by looking at the extension 1.144 + // ASC is considered to be the older format 110, 1.145 + // ASE is the actual version 200 (that is currently written by max) 1.146 + // ------------------------------------------------------------------ 1.147 + unsigned int defaultFormat; 1.148 + std::string::size_type s = pFile.length()-1; 1.149 + switch (pFile.c_str()[s]) { 1.150 + 1.151 + case 'C': 1.152 + case 'c': 1.153 + defaultFormat = AI_ASE_OLD_FILE_FORMAT; 1.154 + break; 1.155 + default: 1.156 + defaultFormat = AI_ASE_NEW_FILE_FORMAT; 1.157 + }; 1.158 + 1.159 + // Construct an ASE parser and parse the file 1.160 + ASE::Parser parser(mBuffer,defaultFormat); 1.161 + mParser = &parser; 1.162 + mParser->Parse(); 1.163 + 1.164 + //------------------------------------------------------------------ 1.165 + // Check whether we god at least one mesh. If we did - generate 1.166 + // materials and copy meshes. 1.167 + // ------------------------------------------------------------------ 1.168 + if ( !mParser->m_vMeshes.empty()) { 1.169 + 1.170 + // If absolutely no material has been loaded from the file 1.171 + // we need to generate a default material 1.172 + GenerateDefaultMaterial(); 1.173 + 1.174 + // process all meshes 1.175 + bool tookNormals = false; 1.176 + std::vector<aiMesh*> avOutMeshes; 1.177 + avOutMeshes.reserve(mParser->m_vMeshes.size()*2); 1.178 + for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { 1.179 + if ((*i).bSkip) { 1.180 + continue; 1.181 + } 1.182 + BuildUniqueRepresentation(*i); 1.183 + 1.184 + // Need to generate proper vertex normals if necessary 1.185 + if(GenerateNormals(*i)) { 1.186 + tookNormals = true; 1.187 + } 1.188 + 1.189 + // Convert all meshes to aiMesh objects 1.190 + ConvertMeshes(*i,avOutMeshes); 1.191 + } 1.192 + if (tookNormals) { 1.193 + DefaultLogger::get()->debug("ASE: Taking normals from the file. Use " 1.194 + "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " 1.195 + "experience problems"); 1.196 + } 1.197 + 1.198 + // Now build the output mesh list. Remove dummies 1.199 + pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); 1.200 + aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; 1.201 + for (std::vector<aiMesh*>::const_iterator i = avOutMeshes.begin();i != avOutMeshes.end();++i) { 1.202 + if (!(*i)->mNumFaces) { 1.203 + continue; 1.204 + } 1.205 + *pp++ = *i; 1.206 + } 1.207 + pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); 1.208 + 1.209 + // Build final material indices (remove submaterials and setup 1.210 + // the final list) 1.211 + BuildMaterialIndices(); 1.212 + } 1.213 + 1.214 + // ------------------------------------------------------------------ 1.215 + // Copy all scene graph nodes - lights, cameras, dummies and meshes 1.216 + // into one huge list. 1.217 + //------------------------------------------------------------------ 1.218 + std::vector<BaseNode*> nodes; 1.219 + nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size() 1.220 + + mParser->m_vCameras.size() + mParser->m_vDummies.size()); 1.221 + 1.222 + // Lights 1.223 + for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(), 1.224 + end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it)); 1.225 + // Cameras 1.226 + for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(), 1.227 + end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it)); 1.228 + // Meshes 1.229 + for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(), 1.230 + end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it)); 1.231 + // Dummies 1.232 + for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(), 1.233 + end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it)); 1.234 + 1.235 + // build the final node graph 1.236 + BuildNodes(nodes); 1.237 + 1.238 + // build output animations 1.239 + BuildAnimations(nodes); 1.240 + 1.241 + // build output cameras 1.242 + BuildCameras(); 1.243 + 1.244 + // build output lights 1.245 + BuildLights(); 1.246 + 1.247 + // ------------------------------------------------------------------ 1.248 + // If we have no meshes use the SkeletonMeshBuilder helper class 1.249 + // to build a mesh for the animation skeleton 1.250 + // FIXME: very strange results 1.251 + // ------------------------------------------------------------------ 1.252 + if (!pScene->mNumMeshes) { 1.253 + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; 1.254 + if (!noSkeletonMesh) { 1.255 + SkeletonMeshBuilder skeleton(pScene); 1.256 + } 1.257 + } 1.258 +} 1.259 +// ------------------------------------------------------------------------------------------------ 1.260 +void ASEImporter::GenerateDefaultMaterial() 1.261 +{ 1.262 + ai_assert(NULL != mParser); 1.263 + 1.264 + bool bHas = false; 1.265 + for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { 1.266 + if ((*i).bSkip)continue; 1.267 + if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) { 1.268 + (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size(); 1.269 + bHas = true; 1.270 + } 1.271 + } 1.272 + if (bHas || mParser->m_vMaterials.empty()) { 1.273 + // add a simple material without submaterials to the parser's list 1.274 + mParser->m_vMaterials.push_back ( ASE::Material() ); 1.275 + ASE::Material& mat = mParser->m_vMaterials.back(); 1.276 + 1.277 + mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); 1.278 + mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f); 1.279 + mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f); 1.280 + mat.mShading = Discreet3DS::Gouraud; 1.281 + mat.mName = AI_DEFAULT_MATERIAL_NAME; 1.282 + } 1.283 +} 1.284 + 1.285 +// ------------------------------------------------------------------------------------------------ 1.286 +void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes) 1.287 +{ 1.288 + // check whether we have at least one mesh which has animations 1.289 + std::vector<ASE::BaseNode*>::const_iterator i = nodes.begin(); 1.290 + unsigned int iNum = 0; 1.291 + for (;i != nodes.end();++i) { 1.292 + 1.293 + // TODO: Implement Bezier & TCB support 1.294 + if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) { 1.295 + DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " 1.296 + "This is not supported."); 1.297 + } 1.298 + if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) { 1.299 + DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. " 1.300 + "This is not supported."); 1.301 + } 1.302 + if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { 1.303 + DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " 1.304 + "This is not supported."); 1.305 + } 1.306 + 1.307 + // We compare against 1 here - firstly one key is not 1.308 + // really an animation and secondly MAX writes dummies 1.309 + // that represent the node transformation. 1.310 + if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){ 1.311 + ++iNum; 1.312 + } 1.313 + if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) { 1.314 + ++iNum; 1.315 + } 1.316 + } 1.317 + if (iNum) { 1.318 + // Generate a new animation channel and setup everything for it 1.319 + pcScene->mNumAnimations = 1; 1.320 + pcScene->mAnimations = new aiAnimation*[1]; 1.321 + aiAnimation* pcAnim = pcScene->mAnimations[0] = new aiAnimation(); 1.322 + pcAnim->mNumChannels = iNum; 1.323 + pcAnim->mChannels = new aiNodeAnim*[iNum]; 1.324 + pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame; 1.325 + 1.326 + iNum = 0; 1.327 + 1.328 + // Now iterate through all meshes and collect all data we can find 1.329 + for (i = nodes.begin();i != nodes.end();++i) { 1.330 + 1.331 + ASE::BaseNode* me = *i; 1.332 + if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x )) { 1.333 + // Generate an extra channel for the camera/light target. 1.334 + // BuildNodes() does also generate an extra node, named 1.335 + // <baseName>.Target. 1.336 + aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); 1.337 + nd->mNodeName.Set(me->mName + ".Target"); 1.338 + 1.339 + // If there is no input position channel we will need 1.340 + // to supply the default position from the node's 1.341 + // local transformation matrix. 1.342 + /*TargetAnimationHelper helper; 1.343 + if (me->mAnim.akeyPositions.empty()) 1.344 + { 1.345 + aiMatrix4x4& mat = (*i)->mTransform; 1.346 + helper.SetFixedMainAnimationChannel(aiVector3D( 1.347 + mat.a4, mat.b4, mat.c4)); 1.348 + } 1.349 + else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions); 1.350 + helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions); 1.351 + 1.352 + helper.Process(&me->mTargetAnim.akeyPositions);*/ 1.353 + 1.354 + // Allocate the key array and fill it 1.355 + nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size(); 1.356 + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; 1.357 + 1.358 + ::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0], 1.359 + nd->mNumPositionKeys * sizeof(aiVectorKey)); 1.360 + } 1.361 + 1.362 + if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) { 1.363 + // Begin a new node animation channel for this node 1.364 + aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); 1.365 + nd->mNodeName.Set(me->mName); 1.366 + 1.367 + // copy position keys 1.368 + if (me->mAnim.akeyPositions.size() > 1 ) 1.369 + { 1.370 + // Allocate the key array and fill it 1.371 + nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size(); 1.372 + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; 1.373 + 1.374 + ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0], 1.375 + nd->mNumPositionKeys * sizeof(aiVectorKey)); 1.376 + } 1.377 + // copy rotation keys 1.378 + if (me->mAnim.akeyRotations.size() > 1 ) { 1.379 + // Allocate the key array and fill it 1.380 + nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size(); 1.381 + nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; 1.382 + 1.383 + // -------------------------------------------------------------------- 1.384 + // Rotation keys are offsets to the previous keys. 1.385 + // We have the quaternion representations of all 1.386 + // of them, so we just need to concatenate all 1.387 + // (unit-length) quaternions to get the absolute 1.388 + // rotations. 1.389 + // Rotation keys are ABSOLUTE for older files 1.390 + // -------------------------------------------------------------------- 1.391 + 1.392 + aiQuaternion cur; 1.393 + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { 1.394 + aiQuatKey q = me->mAnim.akeyRotations[a]; 1.395 + 1.396 + if (mParser->iFileFormat > 110) { 1.397 + cur = (a ? cur*q.mValue : q.mValue); 1.398 + q.mValue = cur.Normalize(); 1.399 + } 1.400 + nd->mRotationKeys[a] = q; 1.401 + 1.402 + // need this to get to Assimp quaternion conventions 1.403 + nd->mRotationKeys[a].mValue.w *= -1.f; 1.404 + } 1.405 + } 1.406 + // copy scaling keys 1.407 + if (me->mAnim.akeyScaling.size() > 1 ) { 1.408 + // Allocate the key array and fill it 1.409 + nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size(); 1.410 + nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; 1.411 + 1.412 + ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0], 1.413 + nd->mNumScalingKeys * sizeof(aiVectorKey)); 1.414 + } 1.415 + } 1.416 + } 1.417 + } 1.418 +} 1.419 + 1.420 +// ------------------------------------------------------------------------------------------------ 1.421 +// Build output cameras 1.422 +void ASEImporter::BuildCameras() 1.423 +{ 1.424 + if (!mParser->m_vCameras.empty()) { 1.425 + pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size(); 1.426 + pcScene->mCameras = new aiCamera*[pcScene->mNumCameras]; 1.427 + 1.428 + for (unsigned int i = 0; i < pcScene->mNumCameras;++i) { 1.429 + aiCamera* out = pcScene->mCameras[i] = new aiCamera(); 1.430 + ASE::Camera& in = mParser->m_vCameras[i]; 1.431 + 1.432 + // copy members 1.433 + out->mClipPlaneFar = in.mFar; 1.434 + out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); 1.435 + out->mHorizontalFOV = in.mFOV; 1.436 + 1.437 + out->mName.Set(in.mName); 1.438 + } 1.439 + } 1.440 +} 1.441 + 1.442 +// ------------------------------------------------------------------------------------------------ 1.443 +// Build output lights 1.444 +void ASEImporter::BuildLights() 1.445 +{ 1.446 + if (!mParser->m_vLights.empty()) { 1.447 + pcScene->mNumLights = (unsigned int)mParser->m_vLights.size(); 1.448 + pcScene->mLights = new aiLight*[pcScene->mNumLights]; 1.449 + 1.450 + for (unsigned int i = 0; i < pcScene->mNumLights;++i) { 1.451 + aiLight* out = pcScene->mLights[i] = new aiLight(); 1.452 + ASE::Light& in = mParser->m_vLights[i]; 1.453 + 1.454 + // The direction is encoded in the transformation matrix of the node. 1.455 + // In 3DS MAX the light source points into negative Z direction if 1.456 + // the node transformation is the identity. 1.457 + out->mDirection = aiVector3D(0.f,0.f,-1.f); 1.458 + 1.459 + out->mName.Set(in.mName); 1.460 + switch (in.mLightType) 1.461 + { 1.462 + case ASE::Light::TARGET: 1.463 + out->mType = aiLightSource_SPOT; 1.464 + out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle); 1.465 + out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone); 1.466 + break; 1.467 + 1.468 + case ASE::Light::DIRECTIONAL: 1.469 + out->mType = aiLightSource_DIRECTIONAL; 1.470 + break; 1.471 + 1.472 + default: 1.473 + //case ASE::Light::OMNI: 1.474 + out->mType = aiLightSource_POINT; 1.475 + break; 1.476 + }; 1.477 + out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity; 1.478 + } 1.479 + } 1.480 +} 1.481 + 1.482 +// ------------------------------------------------------------------------------------------------ 1.483 +void ASEImporter::AddNodes(const std::vector<BaseNode*>& nodes, 1.484 + aiNode* pcParent,const char* szName) 1.485 +{ 1.486 + aiMatrix4x4 m; 1.487 + AddNodes(nodes,pcParent,szName,m); 1.488 +} 1.489 + 1.490 +// ------------------------------------------------------------------------------------------------ 1.491 +// Add meshes to a given node 1.492 +void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) 1.493 +{ 1.494 + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { 1.495 + // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color) 1.496 + const aiMesh* pcMesh = pcScene->mMeshes[i]; 1.497 + const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; 1.498 + 1.499 + if (mesh == snode) { 1.500 + ++node->mNumMeshes; 1.501 + } 1.502 + } 1.503 + 1.504 + if(node->mNumMeshes) { 1.505 + node->mMeshes = new unsigned int[node->mNumMeshes]; 1.506 + for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) { 1.507 + 1.508 + const aiMesh* pcMesh = pcScene->mMeshes[i]; 1.509 + const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; 1.510 + if (mesh == snode) { 1.511 + node->mMeshes[p++] = i; 1.512 + 1.513 + // Transform all vertices of the mesh back into their local space -> 1.514 + // at the moment they are pretransformed 1.515 + aiMatrix4x4 m = mesh->mTransform; 1.516 + m.Inverse(); 1.517 + 1.518 + aiVector3D* pvCurPtr = pcMesh->mVertices; 1.519 + const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices; 1.520 + while (pvCurPtr != pvEndPtr) { 1.521 + *pvCurPtr = m * (*pvCurPtr); 1.522 + pvCurPtr++; 1.523 + } 1.524 + 1.525 + // Do the same for the normal vectors, if we have them. 1.526 + // As always, inverse transpose. 1.527 + if (pcMesh->mNormals) { 1.528 + aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform ); 1.529 + m3.Transpose(); 1.530 + 1.531 + pvCurPtr = pcMesh->mNormals; 1.532 + pvEndPtr = pvCurPtr + pcMesh->mNumVertices; 1.533 + while (pvCurPtr != pvEndPtr) { 1.534 + *pvCurPtr = m3 * (*pvCurPtr); 1.535 + pvCurPtr++; 1.536 + } 1.537 + } 1.538 + } 1.539 + } 1.540 + } 1.541 +} 1.542 + 1.543 +// ------------------------------------------------------------------------------------------------ 1.544 +// Add child nodes to a given parent node 1.545 +void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes, 1.546 + aiNode* pcParent, const char* szName, 1.547 + const aiMatrix4x4& mat) 1.548 +{ 1.549 + const size_t len = szName ? ::strlen(szName) : 0; 1.550 + ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); 1.551 + 1.552 + // Receives child nodes for the pcParent node 1.553 + std::vector<aiNode*> apcNodes; 1.554 + 1.555 + // Now iterate through all nodes in the scene and search for one 1.556 + // which has *us* as parent. 1.557 + for (std::vector<BaseNode*>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { 1.558 + const BaseNode* snode = *it; 1.559 + if (szName) { 1.560 + if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str())) 1.561 + continue; 1.562 + } 1.563 + else if (snode->mParent.length()) 1.564 + continue; 1.565 + 1.566 + (*it)->mProcessed = true; 1.567 + 1.568 + // Allocate a new node and add it to the output data structure 1.569 + apcNodes.push_back(new aiNode()); 1.570 + aiNode* node = apcNodes.back(); 1.571 + 1.572 + node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node")); 1.573 + node->mParent = pcParent; 1.574 + 1.575 + // Setup the transformation matrix of the node 1.576 + aiMatrix4x4 mParentAdjust = mat; 1.577 + mParentAdjust.Inverse(); 1.578 + node->mTransformation = mParentAdjust*snode->mTransform; 1.579 + 1.580 + // Add sub nodes - prevent stack overflow due to recursive parenting 1.581 + if (node->mName != node->mParent->mName) { 1.582 + AddNodes(nodes,node,node->mName.data,snode->mTransform); 1.583 + } 1.584 + 1.585 + // Further processing depends on the type of the node 1.586 + if (snode->mType == ASE::BaseNode::Mesh) { 1.587 + // If the type of this node is "Mesh" we need to search 1.588 + // the list of output meshes in the data structure for 1.589 + // all those that belonged to this node once. This is 1.590 + // slightly inconvinient here and a better solution should 1.591 + // be used when this code is refactored next. 1.592 + AddMeshes(snode,node); 1.593 + } 1.594 + else if (is_not_qnan( snode->mTargetPosition.x )) { 1.595 + // If this is a target camera or light we generate a small 1.596 + // child node which marks the position of the camera 1.597 + // target (the direction information is contained in *this* 1.598 + // node's animation track but the exact target position 1.599 + // would be lost otherwise) 1.600 + if (!node->mNumChildren) { 1.601 + node->mChildren = new aiNode*[1]; 1.602 + } 1.603 + 1.604 + aiNode* nd = new aiNode(); 1.605 + 1.606 + nd->mName.Set ( snode->mName + ".Target" ); 1.607 + 1.608 + nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4; 1.609 + nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4; 1.610 + nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4; 1.611 + 1.612 + nd->mParent = node; 1.613 + 1.614 + // The .Target node is always the first child node 1.615 + for (unsigned int m = 0; m < node->mNumChildren;++m) 1.616 + node->mChildren[m+1] = node->mChildren[m]; 1.617 + 1.618 + node->mChildren[0] = nd; 1.619 + node->mNumChildren++; 1.620 + 1.621 + // What we did is so great, it is at least worth a debug message 1.622 + DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")"); 1.623 + } 1.624 + } 1.625 + 1.626 + // Allocate enough space for the child nodes 1.627 + // We allocate one slot more in case this is a target camera/light 1.628 + pcParent->mNumChildren = (unsigned int)apcNodes.size(); 1.629 + if (pcParent->mNumChildren) { 1.630 + pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */]; 1.631 + 1.632 + // now build all nodes for our nice new children 1.633 + for (unsigned int p = 0; p < apcNodes.size();++p) 1.634 + pcParent->mChildren[p] = apcNodes[p]; 1.635 + } 1.636 + return; 1.637 +} 1.638 + 1.639 +// ------------------------------------------------------------------------------------------------ 1.640 +// Build the output node graph 1.641 +void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) { 1.642 + ai_assert(NULL != pcScene); 1.643 + 1.644 + // allocate the one and only root node 1.645 + aiNode* root = pcScene->mRootNode = new aiNode(); 1.646 + root->mName.Set("<ASERoot>"); 1.647 + 1.648 + // Setup the coordinate system transformation 1.649 + pcScene->mRootNode->mNumChildren = 1; 1.650 + pcScene->mRootNode->mChildren = new aiNode*[1]; 1.651 + aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode(); 1.652 + ch->mParent = root; 1.653 + 1.654 + // Change the transformation matrix of all nodes 1.655 + for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { 1.656 + aiMatrix4x4& m = (*it)->mTransform; 1.657 + m.Transpose(); // row-order vs column-order 1.658 + } 1.659 + 1.660 + // add all nodes 1.661 + AddNodes(nodes,ch,NULL); 1.662 + 1.663 + // now iterate through al nodes and find those that have not yet 1.664 + // been added to the nodegraph (= their parent could not be recognized) 1.665 + std::vector<const BaseNode*> aiList; 1.666 + for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { 1.667 + if ((*it)->mProcessed) { 1.668 + continue; 1.669 + } 1.670 + 1.671 + // check whether our parent is known 1.672 + bool bKnowParent = false; 1.673 + 1.674 + // search the list another time, starting *here* and try to find out whether 1.675 + // there is a node that references *us* as a parent 1.676 + for (std::vector<BaseNode*>::const_iterator it2 = nodes.begin();it2 != end; ++it2) { 1.677 + if (it2 == it) { 1.678 + continue; 1.679 + } 1.680 + 1.681 + if ((*it2)->mName == (*it)->mParent) { 1.682 + bKnowParent = true; 1.683 + break; 1.684 + } 1.685 + } 1.686 + if (!bKnowParent) { 1.687 + aiList.push_back(*it); 1.688 + } 1.689 + } 1.690 + 1.691 + // Are there ane orphaned nodes? 1.692 + if (!aiList.empty()) { 1.693 + std::vector<aiNode*> apcNodes; 1.694 + apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren); 1.695 + 1.696 + for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i) 1.697 + apcNodes.push_back(pcScene->mRootNode->mChildren[i]); 1.698 + 1.699 + delete[] pcScene->mRootNode->mChildren; 1.700 + for (std::vector<const BaseNode*>::/*const_*/iterator i = aiList.begin();i != aiList.end();++i) { 1.701 + const ASE::BaseNode* src = *i; 1.702 + 1.703 + // The parent is not known, so we can assume that we must add 1.704 + // this node to the root node of the whole scene 1.705 + aiNode* pcNode = new aiNode(); 1.706 + pcNode->mParent = pcScene->mRootNode; 1.707 + pcNode->mName.Set(src->mName); 1.708 + AddMeshes(src,pcNode); 1.709 + AddNodes(nodes,pcNode,pcNode->mName.data); 1.710 + apcNodes.push_back(pcNode); 1.711 + } 1.712 + 1.713 + // Regenerate our output array 1.714 + pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()]; 1.715 + for (unsigned int i = 0; i < apcNodes.size();++i) 1.716 + pcScene->mRootNode->mChildren[i] = apcNodes[i]; 1.717 + 1.718 + pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size(); 1.719 + } 1.720 + 1.721 + // Reset the third color set to NULL - we used this field to store a temporary pointer 1.722 + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) 1.723 + pcScene->mMeshes[i]->mColors[2] = NULL; 1.724 + 1.725 + // The root node should not have at least one child or the file is valid 1.726 + if (!pcScene->mRootNode->mNumChildren) { 1.727 + throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt"); 1.728 + } 1.729 + 1.730 + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system 1.731 + pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, 1.732 + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); 1.733 +} 1.734 + 1.735 +// ------------------------------------------------------------------------------------------------ 1.736 +// Convert the imported data to the internal verbose representation 1.737 +void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { 1.738 + // allocate output storage 1.739 + std::vector<aiVector3D> mPositions; 1.740 + std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; 1.741 + std::vector<aiColor4D> mVertexColors; 1.742 + std::vector<aiVector3D> mNormals; 1.743 + std::vector<BoneVertex> mBoneVertices; 1.744 + 1.745 + unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3; 1.746 + mPositions.resize(iSize); 1.747 + 1.748 + // optional texture coordinates 1.749 + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) { 1.750 + if (!mesh.amTexCoords[i].empty()) { 1.751 + amTexCoords[i].resize(iSize); 1.752 + } 1.753 + } 1.754 + // optional vertex colors 1.755 + if (!mesh.mVertexColors.empty()) { 1.756 + mVertexColors.resize(iSize); 1.757 + } 1.758 + 1.759 + // optional vertex normals (vertex normals can simply be copied) 1.760 + if (!mesh.mNormals.empty()) { 1.761 + mNormals.resize(iSize); 1.762 + } 1.763 + // bone vertices. There is no need to change the bone list 1.764 + if (!mesh.mBoneVertices.empty()) { 1.765 + mBoneVertices.resize(iSize); 1.766 + } 1.767 + 1.768 + // iterate through all faces in the mesh 1.769 + unsigned int iCurrent = 0, fi = 0; 1.770 + for (std::vector<ASE::Face>::iterator i = mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) { 1.771 + for (unsigned int n = 0; n < 3;++n,++iCurrent) 1.772 + { 1.773 + mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]]; 1.774 + 1.775 + // add texture coordinates 1.776 + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { 1.777 + if (mesh.amTexCoords[c].empty())break; 1.778 + amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; 1.779 + } 1.780 + // add vertex colors 1.781 + if (!mesh.mVertexColors.empty()) { 1.782 + mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]]; 1.783 + } 1.784 + // add normal vectors 1.785 + if (!mesh.mNormals.empty()) { 1.786 + mNormals[iCurrent] = mesh.mNormals[fi*3+n]; 1.787 + mNormals[iCurrent].Normalize(); 1.788 + } 1.789 + 1.790 + // handle bone vertices 1.791 + if ((*i).mIndices[n] < mesh.mBoneVertices.size()) { 1.792 + // (sometimes this will cause bone verts to be duplicated 1.793 + // however, I' quite sure Schrompf' JoinVerticesStep 1.794 + // will fix that again ...) 1.795 + mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; 1.796 + } 1.797 + (*i).mIndices[n] = iCurrent; 1.798 + } 1.799 + } 1.800 + 1.801 + // replace the old arrays 1.802 + mesh.mNormals = mNormals; 1.803 + mesh.mPositions = mPositions; 1.804 + mesh.mVertexColors = mVertexColors; 1.805 + 1.806 + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) 1.807 + mesh.amTexCoords[c] = amTexCoords[c]; 1.808 +} 1.809 + 1.810 +// ------------------------------------------------------------------------------------------------ 1.811 +// Copy a texture from the ASE structs to the output material 1.812 +void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type) 1.813 +{ 1.814 + // Setup the texture name 1.815 + aiString tex; 1.816 + tex.Set( texture.mMapName); 1.817 + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); 1.818 + 1.819 + // Setup the texture blend factor 1.820 + if (is_not_qnan(texture.mTextureBlend)) 1.821 + mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); 1.822 + 1.823 + // Setup texture UV transformations 1.824 + mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); 1.825 +} 1.826 + 1.827 +// ------------------------------------------------------------------------------------------------ 1.828 +// Convert from ASE material to output material 1.829 +void ASEImporter::ConvertMaterial(ASE::Material& mat) 1.830 +{ 1.831 + // LARGE TODO: Much code her is copied from 3DS ... join them maybe? 1.832 + 1.833 + // Allocate the output material 1.834 + mat.pcInstance = new aiMaterial(); 1.835 + 1.836 + // At first add the base ambient color of the 1.837 + // scene to the material 1.838 + mat.mAmbient.r += mParser->m_clrAmbient.r; 1.839 + mat.mAmbient.g += mParser->m_clrAmbient.g; 1.840 + mat.mAmbient.b += mParser->m_clrAmbient.b; 1.841 + 1.842 + aiString name; 1.843 + name.Set( mat.mName); 1.844 + mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME); 1.845 + 1.846 + // material colors 1.847 + mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); 1.848 + mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); 1.849 + mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); 1.850 + mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); 1.851 + 1.852 + // shininess 1.853 + if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) 1.854 + { 1.855 + mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS); 1.856 + mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); 1.857 + } 1.858 + // If there is no shininess, we can disable phong lighting 1.859 + else if (D3DS::Discreet3DS::Metal == mat.mShading || 1.860 + D3DS::Discreet3DS::Phong == mat.mShading || 1.861 + D3DS::Discreet3DS::Blinn == mat.mShading) 1.862 + { 1.863 + mat.mShading = D3DS::Discreet3DS::Gouraud; 1.864 + } 1.865 + 1.866 + // opacity 1.867 + mat.pcInstance->AddProperty<float>( &mat.mTransparency,1,AI_MATKEY_OPACITY); 1.868 + 1.869 + // Two sided rendering? 1.870 + if (mat.mTwoSided) 1.871 + { 1.872 + int i = 1; 1.873 + mat.pcInstance->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED); 1.874 + } 1.875 + 1.876 + // shading mode 1.877 + aiShadingMode eShading = aiShadingMode_NoShading; 1.878 + switch (mat.mShading) 1.879 + { 1.880 + case D3DS::Discreet3DS::Flat: 1.881 + eShading = aiShadingMode_Flat; break; 1.882 + case D3DS::Discreet3DS::Phong : 1.883 + eShading = aiShadingMode_Phong; break; 1.884 + case D3DS::Discreet3DS::Blinn : 1.885 + eShading = aiShadingMode_Blinn; break; 1.886 + 1.887 + // I don't know what "Wire" shading should be, 1.888 + // assume it is simple lambertian diffuse (L dot N) shading 1.889 + case D3DS::Discreet3DS::Wire: 1.890 + { 1.891 + // set the wireframe flag 1.892 + unsigned int iWire = 1; 1.893 + mat.pcInstance->AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); 1.894 + } 1.895 + case D3DS::Discreet3DS::Gouraud: 1.896 + eShading = aiShadingMode_Gouraud; break; 1.897 + case D3DS::Discreet3DS::Metal : 1.898 + eShading = aiShadingMode_CookTorrance; break; 1.899 + } 1.900 + mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); 1.901 + 1.902 + // DIFFUSE texture 1.903 + if( mat.sTexDiffuse.mMapName.length() > 0) 1.904 + CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE); 1.905 + 1.906 + // SPECULAR texture 1.907 + if( mat.sTexSpecular.mMapName.length() > 0) 1.908 + CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR); 1.909 + 1.910 + // AMBIENT texture 1.911 + if( mat.sTexAmbient.mMapName.length() > 0) 1.912 + CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT); 1.913 + 1.914 + // OPACITY texture 1.915 + if( mat.sTexOpacity.mMapName.length() > 0) 1.916 + CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY); 1.917 + 1.918 + // EMISSIVE texture 1.919 + if( mat.sTexEmissive.mMapName.length() > 0) 1.920 + CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE); 1.921 + 1.922 + // BUMP texture 1.923 + if( mat.sTexBump.mMapName.length() > 0) 1.924 + CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT); 1.925 + 1.926 + // SHININESS texture 1.927 + if( mat.sTexShininess.mMapName.length() > 0) 1.928 + CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS); 1.929 + 1.930 + // store the name of the material itself, too 1.931 + if( mat.mName.length() > 0) { 1.932 + aiString tex;tex.Set( mat.mName); 1.933 + mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME); 1.934 + } 1.935 + return; 1.936 +} 1.937 + 1.938 +// ------------------------------------------------------------------------------------------------ 1.939 +// Build output meshes 1.940 +void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes) 1.941 +{ 1.942 + // validate the material index of the mesh 1.943 + if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { 1.944 + mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1; 1.945 + DefaultLogger::get()->warn("Material index is out of range"); 1.946 + } 1.947 + 1.948 + // If the material the mesh is assigned to is consisting of submeshes, split it 1.949 + if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) { 1.950 + std::vector<ASE::Material> vSubMaterials = mParser-> 1.951 + m_vMaterials[mesh.iMaterialIndex].avSubMaterials; 1.952 + 1.953 + std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()]; 1.954 + 1.955 + // build a list of all faces per submaterial 1.956 + for (unsigned int i = 0; i < mesh.mFaces.size();++i) { 1.957 + // check range 1.958 + if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) { 1.959 + DefaultLogger::get()->warn("Submaterial index is out of range"); 1.960 + 1.961 + // use the last material instead 1.962 + aiSplit[vSubMaterials.size()-1].push_back(i); 1.963 + } 1.964 + else aiSplit[mesh.mFaces[i].iMaterial].push_back(i); 1.965 + } 1.966 + 1.967 + // now generate submeshes 1.968 + for (unsigned int p = 0; p < vSubMaterials.size();++p) { 1.969 + if (!aiSplit[p].empty()) { 1.970 + 1.971 + aiMesh* p_pcOut = new aiMesh(); 1.972 + p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.973 + 1.974 + // let the sub material index 1.975 + p_pcOut->mMaterialIndex = p; 1.976 + 1.977 + // we will need this material 1.978 + mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true; 1.979 + 1.980 + // store the real index here ... color channel 3 1.981 + p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; 1.982 + 1.983 + // store a pointer to the mesh in color channel 2 1.984 + p_pcOut->mColors[2] = (aiColor4D*) &mesh; 1.985 + avOutMeshes.push_back(p_pcOut); 1.986 + 1.987 + // convert vertices 1.988 + p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3; 1.989 + p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); 1.990 + 1.991 + // receive output vertex weights 1.992 + std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL; 1.993 + if (!mesh.mBones.empty()) { 1.994 + avOutputBones = new std::vector<std::pair<unsigned int, float> >[mesh.mBones.size()]; 1.995 + } 1.996 + 1.997 + // allocate enough storage for faces 1.998 + p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; 1.999 + 1.1000 + unsigned int iBase = 0,iIndex; 1.1001 + if (p_pcOut->mNumVertices) { 1.1002 + p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; 1.1003 + p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; 1.1004 + for (unsigned int q = 0; q < aiSplit[p].size();++q) { 1.1005 + 1.1006 + iIndex = aiSplit[p][q]; 1.1007 + 1.1008 + p_pcOut->mFaces[q].mIndices = new unsigned int[3]; 1.1009 + p_pcOut->mFaces[q].mNumIndices = 3; 1.1010 + 1.1011 + for (unsigned int t = 0; t < 3;++t, ++iBase) { 1.1012 + const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; 1.1013 + 1.1014 + p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2]; 1.1015 + p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2]; 1.1016 + 1.1017 + // convert bones, if existing 1.1018 + if (!mesh.mBones.empty()) { 1.1019 + // check whether there is a vertex weight for this vertex index 1.1020 + if (iIndex2 < mesh.mBoneVertices.size()) { 1.1021 + 1.1022 + for (std::vector<std::pair<int,float> >::const_iterator 1.1023 + blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin(); 1.1024 + blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) { 1.1025 + 1.1026 + // NOTE: illegal cases have already been filtered out 1.1027 + avOutputBones[(*blubb).first].push_back(std::pair<unsigned int, float>( 1.1028 + iBase,(*blubb).second)); 1.1029 + } 1.1030 + } 1.1031 + } 1.1032 + p_pcOut->mFaces[q].mIndices[t] = iBase; 1.1033 + } 1.1034 + } 1.1035 + } 1.1036 + // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported) 1.1037 + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { 1.1038 + if (!mesh.amTexCoords[c].empty()) 1.1039 + { 1.1040 + p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices]; 1.1041 + iBase = 0; 1.1042 + for (unsigned int q = 0; q < aiSplit[p].size();++q) { 1.1043 + iIndex = aiSplit[p][q]; 1.1044 + for (unsigned int t = 0; t < 3;++t) { 1.1045 + p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; 1.1046 + } 1.1047 + } 1.1048 + // Setup the number of valid vertex components 1.1049 + p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; 1.1050 + } 1.1051 + } 1.1052 + 1.1053 + // Convert vertex colors (only one set supported) 1.1054 + if (!mesh.mVertexColors.empty()){ 1.1055 + p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; 1.1056 + iBase = 0; 1.1057 + for (unsigned int q = 0; q < aiSplit[p].size();++q) { 1.1058 + iIndex = aiSplit[p][q]; 1.1059 + for (unsigned int t = 0; t < 3;++t) { 1.1060 + p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]]; 1.1061 + } 1.1062 + } 1.1063 + } 1.1064 + // Copy bones 1.1065 + if (!mesh.mBones.empty()) { 1.1066 + p_pcOut->mNumBones = 0; 1.1067 + for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) 1.1068 + if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++; 1.1069 + 1.1070 + p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ]; 1.1071 + aiBone** pcBone = p_pcOut->mBones; 1.1072 + for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) 1.1073 + { 1.1074 + if (!avOutputBones[mrspock].empty()) { 1.1075 + // we will need this bone. add it to the output mesh and 1.1076 + // add all per-vertex weights 1.1077 + aiBone* pc = *pcBone = new aiBone(); 1.1078 + pc->mName.Set(mesh.mBones[mrspock].mName); 1.1079 + 1.1080 + pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size(); 1.1081 + pc->mWeights = new aiVertexWeight[pc->mNumWeights]; 1.1082 + 1.1083 + for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk) 1.1084 + { 1.1085 + const std::pair<unsigned int,float>& ref = avOutputBones[mrspock][captainkirk]; 1.1086 + pc->mWeights[captainkirk].mVertexId = ref.first; 1.1087 + pc->mWeights[captainkirk].mWeight = ref.second; 1.1088 + } 1.1089 + ++pcBone; 1.1090 + } 1.1091 + } 1.1092 + // delete allocated storage 1.1093 + delete[] avOutputBones; 1.1094 + } 1.1095 + } 1.1096 + } 1.1097 + // delete storage 1.1098 + delete[] aiSplit; 1.1099 + } 1.1100 + else 1.1101 + { 1.1102 + // Otherwise we can simply copy the data to one output mesh 1.1103 + // This codepath needs less memory and uses fast memcpy()s 1.1104 + // to do the actual copying. So I think it is worth the 1.1105 + // effort here. 1.1106 + 1.1107 + aiMesh* p_pcOut = new aiMesh(); 1.1108 + p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.1109 + 1.1110 + // set an empty sub material index 1.1111 + p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX; 1.1112 + mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true; 1.1113 + 1.1114 + // store the real index here ... in color channel 3 1.1115 + p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; 1.1116 + 1.1117 + // store a pointer to the mesh in color channel 2 1.1118 + p_pcOut->mColors[2] = (aiColor4D*) &mesh; 1.1119 + avOutMeshes.push_back(p_pcOut); 1.1120 + 1.1121 + // If the mesh hasn't faces or vertices, there are two cases 1.1122 + // possible: 1. the model is invalid. 2. This is a dummy 1.1123 + // helper object which we are going to remove later ... 1.1124 + if (mesh.mFaces.empty() || mesh.mPositions.empty()) { 1.1125 + return; 1.1126 + } 1.1127 + 1.1128 + // convert vertices 1.1129 + p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size(); 1.1130 + p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size(); 1.1131 + 1.1132 + // allocate enough storage for faces 1.1133 + p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; 1.1134 + 1.1135 + // copy vertices 1.1136 + p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()]; 1.1137 + memcpy(p_pcOut->mVertices,&mesh.mPositions[0], 1.1138 + mesh.mPositions.size() * sizeof(aiVector3D)); 1.1139 + 1.1140 + // copy normals 1.1141 + p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()]; 1.1142 + memcpy(p_pcOut->mNormals,&mesh.mNormals[0], 1.1143 + mesh.mNormals.size() * sizeof(aiVector3D)); 1.1144 + 1.1145 + // copy texture coordinates 1.1146 + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { 1.1147 + if (!mesh.amTexCoords[c].empty()) { 1.1148 + p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()]; 1.1149 + memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0], 1.1150 + mesh.amTexCoords[c].size() * sizeof(aiVector3D)); 1.1151 + 1.1152 + // setup the number of valid vertex components 1.1153 + p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; 1.1154 + } 1.1155 + } 1.1156 + 1.1157 + // copy vertex colors 1.1158 + if (!mesh.mVertexColors.empty()) { 1.1159 + p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()]; 1.1160 + memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0], 1.1161 + mesh.mVertexColors.size() * sizeof(aiColor4D)); 1.1162 + } 1.1163 + 1.1164 + // copy faces 1.1165 + for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) { 1.1166 + p_pcOut->mFaces[iFace].mNumIndices = 3; 1.1167 + p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; 1.1168 + 1.1169 + // copy indices 1.1170 + p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0]; 1.1171 + p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1]; 1.1172 + p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2]; 1.1173 + } 1.1174 + 1.1175 + // copy vertex bones 1.1176 + if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) { 1.1177 + std::vector<std::vector<aiVertexWeight> > avBonesOut( mesh.mBones.size() ); 1.1178 + 1.1179 + // find all vertex weights for this bone 1.1180 + unsigned int quak = 0; 1.1181 + for (std::vector<BoneVertex>::const_iterator harrypotter = mesh.mBoneVertices.begin(); 1.1182 + harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) { 1.1183 + 1.1184 + for (std::vector<std::pair<int,float> >::const_iterator 1.1185 + ronaldweasley = (*harrypotter).mBoneWeights.begin(); 1.1186 + ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley) 1.1187 + { 1.1188 + aiVertexWeight weight; 1.1189 + weight.mVertexId = quak; 1.1190 + weight.mWeight = (*ronaldweasley).second; 1.1191 + avBonesOut[(*ronaldweasley).first].push_back(weight); 1.1192 + } 1.1193 + } 1.1194 + 1.1195 + // now build a final bone list 1.1196 + p_pcOut->mNumBones = 0; 1.1197 + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) 1.1198 + if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++; 1.1199 + 1.1200 + p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones]; 1.1201 + aiBone** pcBone = p_pcOut->mBones; 1.1202 + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) { 1.1203 + if (!avBonesOut[jfkennedy].empty()) { 1.1204 + aiBone* pc = *pcBone = new aiBone(); 1.1205 + pc->mName.Set(mesh.mBones[jfkennedy].mName); 1.1206 + pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); 1.1207 + pc->mWeights = new aiVertexWeight[pc->mNumWeights]; 1.1208 + ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], 1.1209 + sizeof(aiVertexWeight) * pc->mNumWeights); 1.1210 + ++pcBone; 1.1211 + } 1.1212 + } 1.1213 + } 1.1214 + } 1.1215 +} 1.1216 + 1.1217 +// ------------------------------------------------------------------------------------------------ 1.1218 +// Setup proper material indices and build output materials 1.1219 +void ASEImporter::BuildMaterialIndices() 1.1220 +{ 1.1221 + ai_assert(NULL != pcScene); 1.1222 + 1.1223 + // iterate through all materials and check whether we need them 1.1224 + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) 1.1225 + { 1.1226 + ASE::Material& mat = mParser->m_vMaterials[iMat]; 1.1227 + if (mat.bNeed) { 1.1228 + // Convert it to the aiMaterial layout 1.1229 + ConvertMaterial(mat); 1.1230 + ++pcScene->mNumMaterials; 1.1231 + } 1.1232 + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) 1.1233 + { 1.1234 + ASE::Material& submat = mat.avSubMaterials[iSubMat]; 1.1235 + if (submat.bNeed) { 1.1236 + // Convert it to the aiMaterial layout 1.1237 + ConvertMaterial(submat); 1.1238 + ++pcScene->mNumMaterials; 1.1239 + } 1.1240 + } 1.1241 + } 1.1242 + 1.1243 + // allocate the output material array 1.1244 + pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials]; 1.1245 + D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials]; 1.1246 + 1.1247 + unsigned int iNum = 0; 1.1248 + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { 1.1249 + ASE::Material& mat = mParser->m_vMaterials[iMat]; 1.1250 + if (mat.bNeed) 1.1251 + { 1.1252 + ai_assert(NULL != mat.pcInstance); 1.1253 + pcScene->mMaterials[iNum] = mat.pcInstance; 1.1254 + 1.1255 + // Store the internal material, too 1.1256 + pcIntMaterials[iNum] = &mat; 1.1257 + 1.1258 + // Iterate through all meshes and search for one which is using 1.1259 + // this top-level material index 1.1260 + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) 1.1261 + { 1.1262 + aiMesh* mesh = pcScene->mMeshes[iMesh]; 1.1263 + if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex && 1.1264 + iMat == (uintptr_t)mesh->mColors[3]) 1.1265 + { 1.1266 + mesh->mMaterialIndex = iNum; 1.1267 + mesh->mColors[3] = NULL; 1.1268 + } 1.1269 + } 1.1270 + iNum++; 1.1271 + } 1.1272 + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { 1.1273 + ASE::Material& submat = mat.avSubMaterials[iSubMat]; 1.1274 + if (submat.bNeed) { 1.1275 + ai_assert(NULL != submat.pcInstance); 1.1276 + pcScene->mMaterials[iNum] = submat.pcInstance; 1.1277 + 1.1278 + // Store the internal material, too 1.1279 + pcIntMaterials[iNum] = &submat; 1.1280 + 1.1281 + // Iterate through all meshes and search for one which is using 1.1282 + // this sub-level material index 1.1283 + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { 1.1284 + aiMesh* mesh = pcScene->mMeshes[iMesh]; 1.1285 + 1.1286 + if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) { 1.1287 + mesh->mMaterialIndex = iNum; 1.1288 + mesh->mColors[3] = NULL; 1.1289 + } 1.1290 + } 1.1291 + iNum++; 1.1292 + } 1.1293 + } 1.1294 + } 1.1295 + 1.1296 + // Dekete our temporary array 1.1297 + delete[] pcIntMaterials; 1.1298 +} 1.1299 + 1.1300 +// ------------------------------------------------------------------------------------------------ 1.1301 +// Generate normal vectors basing on smoothing groups 1.1302 +bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) { 1.1303 + 1.1304 + if (!mesh.mNormals.empty() && !configRecomputeNormals) 1.1305 + { 1.1306 + // Check whether there are only uninitialized normals. If there are 1.1307 + // some, skip all normals from the file and compute them on our own 1.1308 + for (std::vector<aiVector3D>::const_iterator qq = mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) { 1.1309 + if ((*qq).x || (*qq).y || (*qq).z) 1.1310 + { 1.1311 + return true; 1.1312 + } 1.1313 + } 1.1314 + } 1.1315 + // The array is reused. 1.1316 + ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh); 1.1317 + return false; 1.1318 +} 1.1319 + 1.1320 +#endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER