vrshoot

view libs/assimp/MS3DLoader.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 MS3DLoader.cpp
43 * @brief Implementation of the Ms3D importer class.
44 * Written against http://chumbalum.swissquake.ch/ms3d/ms3dspec.txt
45 */
47 #include "AssimpPCH.h"
48 #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
50 // internal headers
51 #include "MS3DLoader.h"
52 #include "StreamReader.h"
53 using namespace Assimp;
55 static const aiImporterDesc desc = {
56 "Milkshape 3D Importer",
57 "",
58 "",
59 "http://chumbalum.swissquake.ch/",
60 aiImporterFlags_SupportBinaryFlavour,
61 0,
62 0,
63 0,
64 0,
65 "ms3d"
66 };
68 // ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
69 // (enable old code path, which generates extra nodes per mesh while
70 // the newer code uses aiMesh::mName to express the name of the
71 // meshes (a.k.a. groups in MS3D))
73 // ------------------------------------------------------------------------------------------------
74 // Constructor to be privately used by Importer
75 MS3DImporter::MS3DImporter()
76 {}
78 // ------------------------------------------------------------------------------------------------
79 // Destructor, private as well
80 MS3DImporter::~MS3DImporter()
81 {}
83 // ------------------------------------------------------------------------------------------------
84 // Returns whether the class can handle the format of the given file.
85 bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
86 {
87 // first call - simple extension check
88 const std::string extension = GetExtension(pFile);
89 if (extension == "ms3d") {
90 return true;
91 }
93 // second call - check for magic identifiers
94 else if (!extension.length() || checkSig) {
95 if (!pIOHandler) {
96 return true;
97 }
98 const char* tokens[] = {"MS3D000000"};
99 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
100 }
101 return false;
102 }
104 // ------------------------------------------------------------------------------------------------
105 const aiImporterDesc* MS3DImporter::GetInfo () const
106 {
107 return &desc;
108 }
110 // ------------------------------------------------------------------------------------------------
111 void ReadColor(StreamReaderLE& stream, aiColor4D& ambient)
112 {
113 // aiColor4D is packed on gcc, implicit binding to float& fails therefore.
114 stream >> (float&)ambient.r >> (float&)ambient.g >> (float&)ambient.b >> (float&)ambient.a;
115 }
117 // ------------------------------------------------------------------------------------------------
118 void ReadVector(StreamReaderLE& stream, aiVector3D& pos)
119 {
120 // See note in ReadColor()
121 stream >> (float&)pos.x >> (float&)pos.y >> (float&)pos.z;
122 }
124 // ------------------------------------------------------------------------------------------------
125 template<typename T>
126 void MS3DImporter :: ReadComments(StreamReaderLE& stream, std::vector<T>& outp)
127 {
128 uint16_t cnt;
129 stream >> cnt;
131 for(unsigned int i = 0; i < cnt; ++i) {
132 uint32_t index, clength;
133 stream >> index >> clength;
135 if(index >= outp.size()) {
136 DefaultLogger::get()->warn("MS3D: Invalid index in comment section");
137 }
138 else if (clength > stream.GetRemainingSize()) {
139 throw DeadlyImportError("MS3D: Failure reading comment, length field is out of range");
140 }
141 else {
142 outp[index].comment = std::string(reinterpret_cast<char*>(stream.GetPtr()),clength);
143 }
144 stream.IncPtr(clength);
145 }
146 }
148 // ------------------------------------------------------------------------------------------------
149 template <typename T, typename T2, typename T3> bool inrange(const T& in, const T2& lower, const T3& higher)
150 {
151 return in > lower && in <= higher;
152 }
154 // ------------------------------------------------------------------------------------------------
155 void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints,
156 std::vector<bool>& hadit,
157 aiNode* nd,
158 const aiMatrix4x4& absTrafo)
159 {
160 unsigned int cnt = 0;
161 for(size_t i = 0; i < joints.size(); ++i) {
162 if (!hadit[i] && !strcmp(joints[i].parentName,nd->mName.data)) {
163 ++cnt;
164 }
165 }
167 nd->mChildren = new aiNode*[nd->mNumChildren = cnt];
168 cnt = 0;
169 for(size_t i = 0; i < joints.size(); ++i) {
170 if (!hadit[i] && !strcmp(joints[i].parentName,nd->mName.data)) {
171 aiNode* ch = nd->mChildren[cnt++] = new aiNode(joints[i].name);
172 ch->mParent = nd;
174 ch->mTransformation = aiMatrix4x4::Translation(joints[i].position,aiMatrix4x4()=aiMatrix4x4())*
175 // XXX actually, I don't *know* why we need the inverse here. Probably column vs. row order?
176 aiMatrix4x4().FromEulerAnglesXYZ(joints[i].rotation).Transpose();
178 const aiMatrix4x4 abs = absTrafo*ch->mTransformation;
179 for(unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
180 aiMesh* const msh = mScene->mMeshes[a];
181 for(unsigned int n = 0; n < msh->mNumBones; ++n) {
182 aiBone* const bone = msh->mBones[n];
184 if(bone->mName == ch->mName) {
185 bone->mOffsetMatrix = aiMatrix4x4(abs).Inverse();
186 }
187 }
188 }
190 hadit[i] = true;
191 CollectChildJoints(joints,hadit,ch,abs);
192 }
193 }
194 }
196 // ------------------------------------------------------------------------------------------------
197 void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints, aiNode* nd)
198 {
199 std::vector<bool> hadit(joints.size(),false);
200 aiMatrix4x4 trafo;
202 CollectChildJoints(joints,hadit,nd,trafo);
203 }
205 // ------------------------------------------------------------------------------------------------
206 // Imports the given file into the given scene structure.
207 void MS3DImporter::InternReadFile( const std::string& pFile,
208 aiScene* pScene, IOSystem* pIOHandler)
209 {
210 StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
212 // CanRead() should have done this already
213 char head[10];
214 int32_t version;
216 mScene = pScene;
219 // 1 ------------ read into temporary data structures mirroring the original file
221 stream.CopyAndAdvance(head,10);
222 stream >> version;
223 if (strncmp(head,"MS3D000000",10)) {
224 throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: "+pFile);
225 }
227 if (version != 4) {
228 throw DeadlyImportError("MS3D: Unsupported file format version, 4 was expected");
229 }
231 uint16_t verts;
232 stream >> verts;
234 std::vector<TempVertex> vertices(verts);
235 for (unsigned int i = 0; i < verts; ++i) {
236 TempVertex& v = vertices[i];
238 stream.IncPtr(1);
239 ReadVector(stream,v.pos);
240 v.bone_id[0] = stream.GetI1();
241 v.ref_cnt = stream.GetI1();
243 v.bone_id[1] = v.bone_id[2] = v.bone_id[3] = UINT_MAX;
244 v.weights[1] = v.weights[2] = v.weights[3] = 0.f;
245 v.weights[0] = 1.f;
246 }
248 uint16_t tris;
249 stream >> tris;
251 std::vector<TempTriangle> triangles(tris);
252 for (unsigned int i = 0;i < tris; ++i) {
253 TempTriangle& t = triangles[i];
255 stream.IncPtr(2);
256 for (unsigned int i = 0; i < 3; ++i) {
257 t.indices[i] = stream.GetI2();
258 }
260 for (unsigned int i = 0; i < 3; ++i) {
261 ReadVector(stream,t.normals[i]);
262 }
264 for (unsigned int i = 0; i < 3; ++i) {
265 stream >> (float&)(t.uv[i].x); // see note in ReadColor()
266 }
267 for (unsigned int i = 0; i < 3; ++i) {
268 stream >> (float&)(t.uv[i].y);
269 }
271 t.sg = stream.GetI1();
272 t.group = stream.GetI1();
273 }
275 uint16_t grp;
276 stream >> grp;
278 bool need_default = false;
279 std::vector<TempGroup> groups(grp);
280 for (unsigned int i = 0;i < grp; ++i) {
281 TempGroup& t = groups[i];
283 stream.IncPtr(1);
284 stream.CopyAndAdvance(t.name,32);
286 t.name[32] = '\0';
287 uint16_t num;
288 stream >> num;
290 t.triangles.resize(num);
291 for (unsigned int i = 0; i < num; ++i) {
292 t.triangles[i] = stream.GetI2();
293 }
294 t.mat = stream.GetI1();
295 if (t.mat == UINT_MAX) {
296 need_default = true;
297 }
298 }
300 uint16_t mat;
301 stream >> mat;
303 std::vector<TempMaterial> materials(mat);
304 for (unsigned int i = 0;i < mat; ++i) {
305 TempMaterial& t = materials[i];
307 stream.CopyAndAdvance(t.name,32);
308 t.name[32] = '\0';
310 ReadColor(stream,t.ambient);
311 ReadColor(stream,t.diffuse);
312 ReadColor(stream,t.specular);
313 ReadColor(stream,t.emissive);
314 stream >> t.shininess >> t.transparency;
316 stream.IncPtr(1);
318 stream.CopyAndAdvance(t.texture,128);
319 t.texture[128] = '\0';
321 stream.CopyAndAdvance(t.alphamap,128);
322 t.alphamap[128] = '\0';
323 }
325 float animfps, currenttime;
326 uint32_t totalframes;
327 stream >> animfps >> currenttime >> totalframes;
329 uint16_t joint;
330 stream >> joint;
332 std::vector<TempJoint> joints(joint);
333 for(unsigned int i = 0; i < joint; ++i) {
334 TempJoint& j = joints[i];
336 stream.IncPtr(1);
337 stream.CopyAndAdvance(j.name,32);
338 j.name[32] = '\0';
340 stream.CopyAndAdvance(j.parentName,32);
341 j.parentName[32] = '\0';
343 // DefaultLogger::get()->debug(j.name);
344 // DefaultLogger::get()->debug(j.parentName);
346 ReadVector(stream,j.rotation);
347 ReadVector(stream,j.position);
349 j.rotFrames.resize(stream.GetI2());
350 j.posFrames.resize(stream.GetI2());
352 for(unsigned int a = 0; a < j.rotFrames.size(); ++a) {
353 TempKeyFrame& kf = j.rotFrames[a];
354 stream >> kf.time;
355 ReadVector(stream,kf.value);
356 }
357 for(unsigned int a = 0; a < j.posFrames.size(); ++a) {
358 TempKeyFrame& kf = j.posFrames[a];
359 stream >> kf.time;
360 ReadVector(stream,kf.value);
361 }
362 }
364 if(stream.GetRemainingSize() > 4) {
365 uint32_t subversion;
366 stream >> subversion;
367 if (subversion == 1) {
368 ReadComments<TempGroup>(stream,groups);
369 ReadComments<TempMaterial>(stream,materials);
370 ReadComments<TempJoint>(stream,joints);
372 // model comment - print it for we have such a nice log.
373 if (stream.GetI4()) {
374 const size_t len = static_cast<size_t>(stream.GetI4());
375 if (len > stream.GetRemainingSize()) {
376 throw DeadlyImportError("MS3D: Model comment is too long");
377 }
379 const std::string& s = std::string(reinterpret_cast<char*>(stream.GetPtr()),len);
380 DefaultLogger::get()->debug("MS3D: Model comment: " + s);
381 }
383 if(stream.GetRemainingSize() > 4 && inrange((stream >> subversion,subversion),1u,3u)) {
384 for(unsigned int i = 0; i < verts; ++i) {
385 TempVertex& v = vertices[i];
386 v.weights[3]=1.f;
387 for(unsigned int n = 0; n < 3; v.weights[3]-=v.weights[n++]) {
388 v.bone_id[n+1] = stream.GetI1();
389 v.weights[n] = static_cast<float>(static_cast<unsigned int>(stream.GetI1()))/255.f;
390 }
391 stream.IncPtr((subversion-1)<<2u);
392 }
394 // even further extra data is not of interest for us, at least now now.
395 }
396 }
397 }
399 // 2 ------------ convert to proper aiXX data structures -----------------------------------
401 if (need_default && materials.size()) {
402 DefaultLogger::get()->warn("MS3D: Found group with no material assigned, spawning default material");
403 // if one of the groups has no material assigned, but there are other
404 // groups with materials, a default material needs to be added (
405 // scenepreprocessor adds a default material only if nummat==0).
406 materials.push_back(TempMaterial());
407 TempMaterial& m = materials.back();
409 strcpy(m.name,"<MS3D_DefaultMat>");
410 m.diffuse = aiColor4D(0.6f,0.6f,0.6f,1.0);
411 m.transparency = 1.f;
412 m.shininess = 0.f;
414 // this is because these TempXXX struct's have no c'tors.
415 m.texture[0] = m.alphamap[0] = '\0';
417 for (unsigned int i = 0; i < groups.size(); ++i) {
418 TempGroup& g = groups[i];
419 if (g.mat == UINT_MAX) {
420 g.mat = materials.size()-1;
421 }
422 }
423 }
425 // convert materials to our generic key-value dict-alike
426 if (materials.size()) {
427 pScene->mMaterials = new aiMaterial*[materials.size()];
428 for (size_t i = 0; i < materials.size(); ++i) {
430 aiMaterial* mo = new aiMaterial();
431 pScene->mMaterials[pScene->mNumMaterials++] = mo;
433 const TempMaterial& mi = materials[i];
435 aiString tmp;
436 if (0[mi.alphamap]) {
437 tmp = aiString(mi.alphamap);
438 mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_OPACITY(0));
439 }
440 if (0[mi.texture]) {
441 tmp = aiString(mi.texture);
442 mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_DIFFUSE(0));
443 }
444 if (0[mi.name]) {
445 tmp = aiString(mi.name);
446 mo->AddProperty(&tmp,AI_MATKEY_NAME);
447 }
449 mo->AddProperty(&mi.ambient,1,AI_MATKEY_COLOR_AMBIENT);
450 mo->AddProperty(&mi.diffuse,1,AI_MATKEY_COLOR_DIFFUSE);
451 mo->AddProperty(&mi.specular,1,AI_MATKEY_COLOR_SPECULAR);
452 mo->AddProperty(&mi.emissive,1,AI_MATKEY_COLOR_EMISSIVE);
454 mo->AddProperty(&mi.shininess,1,AI_MATKEY_SHININESS);
455 mo->AddProperty(&mi.transparency,1,AI_MATKEY_OPACITY);
457 const int sm = mi.shininess>0.f?aiShadingMode_Phong:aiShadingMode_Gouraud;
458 mo->AddProperty(&sm,1,AI_MATKEY_SHADING_MODEL);
459 }
460 }
462 // convert groups to meshes
463 if (groups.empty()) {
464 throw DeadlyImportError("MS3D: Didn't get any group records, file is malformed");
465 }
467 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes=static_cast<unsigned int>(groups.size())]();
468 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
470 aiMesh* m = pScene->mMeshes[i] = new aiMesh();
471 const TempGroup& g = groups[i];
473 if (pScene->mNumMaterials && g.mat > pScene->mNumMaterials) {
474 throw DeadlyImportError("MS3D: Encountered invalid material index, file is malformed");
475 } // no error if no materials at all - scenepreprocessor adds one then
477 m->mMaterialIndex = g.mat;
478 m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
480 m->mFaces = new aiFace[m->mNumFaces = g.triangles.size()];
481 m->mNumVertices = m->mNumFaces*3;
483 // storage for vertices - verbose format, as requested by the postprocessing pipeline
484 m->mVertices = new aiVector3D[m->mNumVertices];
485 m->mNormals = new aiVector3D[m->mNumVertices];
486 m->mTextureCoords[0] = new aiVector3D[m->mNumVertices];
487 m->mNumUVComponents[0] = 2;
489 typedef std::map<unsigned int,unsigned int> BoneSet;
490 BoneSet mybones;
492 for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
493 aiFace& f = m->mFaces[i];
494 if (g.triangles[i]>triangles.size()) {
495 throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
496 }
498 TempTriangle& t = triangles[g.triangles[i]];
499 f.mIndices = new unsigned int[f.mNumIndices=3];
501 for (unsigned int i = 0; i < 3; ++i,++n) {
502 if (t.indices[i]>vertices.size()) {
503 throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
504 }
506 const TempVertex& v = vertices[t.indices[i]];
507 for(unsigned int a = 0; a < 4; ++a) {
508 if (v.bone_id[a] != UINT_MAX) {
509 if (v.bone_id[a] >= joints.size()) {
510 throw DeadlyImportError("MS3D: Encountered invalid bone index, file is malformed");
511 }
512 if (mybones.find(v.bone_id[a]) == mybones.end()) {
513 mybones[v.bone_id[a]] = 1;
514 }
515 else ++mybones[v.bone_id[a]];
516 }
517 }
519 // collect vertex components
520 m->mVertices[n] = v.pos;
522 m->mNormals[n] = t.normals[i];
523 m->mTextureCoords[0][n] = aiVector3D(t.uv[i].x,1.f-t.uv[i].y,0.0);
524 f.mIndices[i] = n;
525 }
526 }
528 // allocate storage for bones
529 if(mybones.size()) {
530 std::vector<unsigned int> bmap(joints.size());
531 m->mBones = new aiBone*[mybones.size()]();
532 for(BoneSet::const_iterator it = mybones.begin(); it != mybones.end(); ++it) {
533 aiBone* const bn = m->mBones[m->mNumBones] = new aiBone();
534 const TempJoint& jnt = joints[(*it).first];
536 bn->mName.Set(jnt.name);
537 bn->mWeights = new aiVertexWeight[(*it).second];
539 bmap[(*it).first] = m->mNumBones++;
540 }
542 // .. and collect bone weights
543 for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
544 TempTriangle& t = triangles[g.triangles[i]];
546 for (unsigned int i = 0; i < 3; ++i,++n) {
547 const TempVertex& v = vertices[t.indices[i]];
548 for(unsigned int a = 0; a < 4; ++a) {
549 const unsigned int bone = v.bone_id[a];
550 if(bone==UINT_MAX){
551 continue;
552 }
554 aiBone* const outbone = m->mBones[bmap[bone]];
555 aiVertexWeight& outwght = outbone->mWeights[outbone->mNumWeights++];
557 outwght.mVertexId = n;
558 outwght.mWeight = v.weights[a];
559 }
560 }
561 }
562 }
563 }
565 // ... add dummy nodes under a single root, each holding a reference to one
566 // mesh. If we didn't do this, we'd loose the group name.
567 aiNode* rt = pScene->mRootNode = new aiNode("<MS3DRoot>");
569 #ifdef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
570 rt->mChildren = new aiNode*[rt->mNumChildren=pScene->mNumMeshes+(joints.size()?1:0)]();
572 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
573 aiNode* nd = rt->mChildren[i] = new aiNode();
575 const TempGroup& g = groups[i];
577 // we need to generate an unique name for all mesh nodes.
578 // since we want to keep the group name, a prefix is
579 // prepended.
580 nd->mName = aiString("<MS3DMesh>_");
581 nd->mName.Append(g.name);
582 nd->mParent = rt;
584 nd->mMeshes = new unsigned int[nd->mNumMeshes = 1];
585 nd->mMeshes[0] = i;
586 }
587 #else
588 rt->mMeshes = new unsigned int[pScene->mNumMeshes];
589 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
590 rt->mMeshes[rt->mNumMeshes++] = i;
591 }
592 #endif
594 // convert animations as well
595 if(joints.size()) {
596 #ifndef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
597 rt->mChildren = new aiNode*[1]();
598 rt->mNumChildren = 1;
600 aiNode* jt = rt->mChildren[0] = new aiNode();
601 #else
602 aiNode* jt = rt->mChildren[pScene->mNumMeshes] = new aiNode();
603 #endif
604 jt->mParent = rt;
605 CollectChildJoints(joints,jt);
606 jt->mName.Set("<MS3DJointRoot>");
608 pScene->mAnimations = new aiAnimation*[ pScene->mNumAnimations = 1 ];
609 aiAnimation* const anim = pScene->mAnimations[0] = new aiAnimation();
611 anim->mName.Set("<MS3DMasterAnim>");
613 // carry the fps info to the user by scaling all times with it
614 anim->mTicksPerSecond = animfps;
616 // leave duration at its default, so ScenePreprocessor will fill an appropriate
617 // value (the values taken from some MS3D files seem to be too unreliable
618 // to pass the validation)
619 // anim->mDuration = totalframes/animfps;
621 anim->mChannels = new aiNodeAnim*[joints.size()]();
622 for(std::vector<TempJoint>::const_iterator it = joints.begin(); it != joints.end(); ++it) {
623 if ((*it).rotFrames.empty() && (*it).posFrames.empty()) {
624 continue;
625 }
627 aiNodeAnim* nd = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
628 nd->mNodeName.Set((*it).name);
630 if ((*it).rotFrames.size()) {
631 nd->mRotationKeys = new aiQuatKey[(*it).rotFrames.size()];
632 for(std::vector<TempKeyFrame>::const_iterator rot = (*it).rotFrames.begin(); rot != (*it).rotFrames.end(); ++rot) {
633 aiQuatKey& q = nd->mRotationKeys[nd->mNumRotationKeys++];
635 q.mTime = (*rot).time*animfps;
637 // XXX it seems our matrix&quaternion code has faults in its conversion routines --
638 // aiQuaternion(x,y,z) seems to besomething different as quat(matrix.fromeuler(x,y,z)).
639 q.mValue = aiQuaternion(aiMatrix3x3(aiMatrix4x4().FromEulerAnglesXYZ((*rot).value)*
640 aiMatrix4x4().FromEulerAnglesXYZ((*it).rotation)).Transpose());
641 }
642 }
644 if ((*it).posFrames.size()) {
645 nd->mPositionKeys = new aiVectorKey[(*it).posFrames.size()];
647 aiQuatKey* qu = nd->mRotationKeys;
648 for(std::vector<TempKeyFrame>::const_iterator pos = (*it).posFrames.begin(); pos != (*it).posFrames.end(); ++pos,++qu) {
649 aiVectorKey& v = nd->mPositionKeys[nd->mNumPositionKeys++];
651 v.mTime = (*pos).time*animfps;
652 v.mValue = (*it).position + (*pos).value;
653 }
654 }
655 }
656 // fixup to pass the validation if not a single animation channel is non-trivial
657 if (!anim->mNumChannels) {
658 anim->mChannels = NULL;
659 }
660 }
661 }
663 #endif