vrshoot

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