1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
43
44#include "OgreStructs.h"
45#include "TinyFormatter.h"
46#include <assimp/scene.h>
47#include <assimp/DefaultLogger.hpp>
48#include "Exceptional.h"
49
50
51namespace Assimp
52{
53namespace Ogre
54{
55
56// VertexElement
57
58VertexElement::VertexElement() :
59 index(0),
60 source(0),
61 offset(0),
62 type(VET_FLOAT1),
63 semantic(VES_POSITION)
64{
65}
66
67size_t VertexElement::Size() const
68{
69 return TypeSize(type);
70}
71
72size_t VertexElement::ComponentCount() const
73{
74 return ComponentCount(type);
75}
76
77size_t VertexElement::ComponentCount(Type type)
78{
79 switch(type)
80 {
81 case VET_COLOUR:
82 case VET_COLOUR_ABGR:
83 case VET_COLOUR_ARGB:
84 case VET_FLOAT1:
85 case VET_DOUBLE1:
86 case VET_SHORT1:
87 case VET_USHORT1:
88 case VET_INT1:
89 case VET_UINT1:
90 return 1;
91 case VET_FLOAT2:
92 case VET_DOUBLE2:
93 case VET_SHORT2:
94 case VET_USHORT2:
95 case VET_INT2:
96 case VET_UINT2:
97 return 2;
98 case VET_FLOAT3:
99 case VET_DOUBLE3:
100 case VET_SHORT3:
101 case VET_USHORT3:
102 case VET_INT3:
103 case VET_UINT3:
104 return 3;
105 case VET_FLOAT4:
106 case VET_DOUBLE4:
107 case VET_SHORT4:
108 case VET_USHORT4:
109 case VET_INT4:
110 case VET_UINT4:
111 case VET_UBYTE4:
112 return 4;
113 }
114 return 0;
115}
116
117size_t VertexElement::TypeSize(Type type)
118{
119 switch(type)
120 {
121 case VET_COLOUR:
122 case VET_COLOUR_ABGR:
123 case VET_COLOUR_ARGB:
124 return sizeof(unsigned int);
125 case VET_FLOAT1:
126 return sizeof(float);
127 case VET_FLOAT2:
128 return sizeof(float)*2;
129 case VET_FLOAT3:
130 return sizeof(float)*3;
131 case VET_FLOAT4:
132 return sizeof(float)*4;
133 case VET_DOUBLE1:
134 return sizeof(double);
135 case VET_DOUBLE2:
136 return sizeof(double)*2;
137 case VET_DOUBLE3:
138 return sizeof(double)*3;
139 case VET_DOUBLE4:
140 return sizeof(double)*4;
141 case VET_SHORT1:
142 return sizeof(short);
143 case VET_SHORT2:
144 return sizeof(short)*2;
145 case VET_SHORT3:
146 return sizeof(short)*3;
147 case VET_SHORT4:
148 return sizeof(short)*4;
149 case VET_USHORT1:
150 return sizeof(unsigned short);
151 case VET_USHORT2:
152 return sizeof(unsigned short)*2;
153 case VET_USHORT3:
154 return sizeof(unsigned short)*3;
155 case VET_USHORT4:
156 return sizeof(unsigned short)*4;
157 case VET_INT1:
158 return sizeof(int);
159 case VET_INT2:
160 return sizeof(int)*2;
161 case VET_INT3:
162 return sizeof(int)*3;
163 case VET_INT4:
164 return sizeof(int)*4;
165 case VET_UINT1:
166 return sizeof(unsigned int);
167 case VET_UINT2:
168 return sizeof(unsigned int)*2;
169 case VET_UINT3:
170 return sizeof(unsigned int)*3;
171 case VET_UINT4:
172 return sizeof(unsigned int)*4;
173 case VET_UBYTE4:
174 return sizeof(unsigned char)*4;
175 }
176 return 0;
177}
178
179std::string VertexElement::TypeToString()
180{
181 return TypeToString(type);
182}
183
184std::string VertexElement::TypeToString(Type type)
185{
186 switch(type)
187 {
188 case VET_COLOUR: return "COLOUR";
189 case VET_COLOUR_ABGR: return "COLOUR_ABGR";
190 case VET_COLOUR_ARGB: return "COLOUR_ARGB";
191 case VET_FLOAT1: return "FLOAT1";
192 case VET_FLOAT2: return "FLOAT2";
193 case VET_FLOAT3: return "FLOAT3";
194 case VET_FLOAT4: return "FLOAT4";
195 case VET_DOUBLE1: return "DOUBLE1";
196 case VET_DOUBLE2: return "DOUBLE2";
197 case VET_DOUBLE3: return "DOUBLE3";
198 case VET_DOUBLE4: return "DOUBLE4";
199 case VET_SHORT1: return "SHORT1";
200 case VET_SHORT2: return "SHORT2";
201 case VET_SHORT3: return "SHORT3";
202 case VET_SHORT4: return "SHORT4";
203 case VET_USHORT1: return "USHORT1";
204 case VET_USHORT2: return "USHORT2";
205 case VET_USHORT3: return "USHORT3";
206 case VET_USHORT4: return "USHORT4";
207 case VET_INT1: return "INT1";
208 case VET_INT2: return "INT2";
209 case VET_INT3: return "INT3";
210 case VET_INT4: return "INT4";
211 case VET_UINT1: return "UINT1";
212 case VET_UINT2: return "UINT2";
213 case VET_UINT3: return "UINT3";
214 case VET_UINT4: return "UINT4";
215 case VET_UBYTE4: return "UBYTE4";
216 }
217 return "Uknown_VertexElement::Type";
218}
219
220std::string VertexElement::SemanticToString()
221{
222 return SemanticToString(semantic);
223}
224
225std::string VertexElement::SemanticToString(Semantic semantic)
226{
227 switch(semantic)
228 {
229 case VES_POSITION: return "POSITION";
230 case VES_BLEND_WEIGHTS: return "BLEND_WEIGHTS";
231 case VES_BLEND_INDICES: return "BLEND_INDICES";
232 case VES_NORMAL: return "NORMAL";
233 case VES_DIFFUSE: return "DIFFUSE";
234 case VES_SPECULAR: return "SPECULAR";
235 case VES_TEXTURE_COORDINATES: return "TEXTURE_COORDINATES";
236 case VES_BINORMAL: return "BINORMAL";
237 case VES_TANGENT: return "TANGENT";
238 }
239 return "Uknown_VertexElement::Semantic";
240}
241
242// IVertexData
243
244IVertexData::IVertexData() :
245 count(0)
246{
247}
248
249bool IVertexData::HasBoneAssignments() const
250{
251 return !boneAssignments.empty();
252}
253
254void IVertexData::AddVertexMapping(uint32_t oldIndex, uint32_t newIndex)
255{
256 BoneAssignmentsForVertex(oldIndex, newIndex, boneAssignmentsMap[newIndex]);
257 vertexIndexMapping[oldIndex].push_back(newIndex);
258}
259
260void IVertexData::BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const
261{
262 for (const auto &boneAssign : boneAssignments)
263 {
264 if (boneAssign.vertexIndex == currentIndex)
265 {
266 VertexBoneAssignment a = boneAssign;
267 a.vertexIndex = newIndex;
268 dest.push_back(a);
269 }
270 }
271}
272
273AssimpVertexBoneWeightList IVertexData::AssimpBoneWeights(size_t vertices)
274{
275 AssimpVertexBoneWeightList weights;
276 for(size_t vi=0; vi<vertices; ++vi)
277 {
278 VertexBoneAssignmentList &vertexWeights = boneAssignmentsMap[static_cast<unsigned int>(vi)];
279 for (VertexBoneAssignmentList::const_iterator iter=vertexWeights.begin(), end=vertexWeights.end();
280 iter!=end; ++iter)
281 {
282 std::vector<aiVertexWeight> &boneWeights = weights[iter->boneIndex];
283 boneWeights.push_back(aiVertexWeight(static_cast<unsigned int>(vi), iter->weight));
284 }
285 }
286 return weights;
287}
288
289std::set<uint16_t> IVertexData::ReferencedBonesByWeights() const
290{
291 std::set<uint16_t> referenced;
292 for (const auto &boneAssign : boneAssignments)
293 {
294 referenced.insert(boneAssign.boneIndex);
295 }
296 return referenced;
297}
298
299// VertexData
300
301VertexData::VertexData()
302{
303}
304
305VertexData::~VertexData()
306{
307 Reset();
308}
309
310void VertexData::Reset()
311{
312 // Releases shared ptr memory streams.
313 vertexBindings.clear();
314 vertexElements.clear();
315}
316
317uint32_t VertexData::VertexSize(uint16_t source) const
318{
319 uint32_t size = 0;
320 for(const auto &element : vertexElements)
321 {
322 if (element.source == source)
323 size += static_cast<uint32_t>(element.Size());
324 }
325 return size;
326}
327
328MemoryStream *VertexData::VertexBuffer(uint16_t source)
329{
330 if (vertexBindings.find(source) != vertexBindings.end())
331 return vertexBindings[source].get();
332 return 0;
333}
334
335VertexElement *VertexData::GetVertexElement(VertexElement::Semantic semantic, uint16_t index)
336{
337 for(auto & element : vertexElements)
338 {
339 if (element.semantic == semantic && element.index == index)
340 return &element;
341 }
342 return 0;
343}
344
345// VertexDataXml
346
347VertexDataXml::VertexDataXml()
348{
349}
350
351bool VertexDataXml::HasPositions() const
352{
353 return !positions.empty();
354}
355
356bool VertexDataXml::HasNormals() const
357{
358 return !normals.empty();
359}
360
361bool VertexDataXml::HasTangents() const
362{
363 return !tangents.empty();
364}
365
366bool VertexDataXml::HasUvs() const
367{
368 return !uvs.empty();
369}
370
371size_t VertexDataXml::NumUvs() const
372{
373 return uvs.size();
374}
375
376// IndexData
377
378IndexData::IndexData() :
379 count(0),
380 faceCount(0),
381 is32bit(false)
382{
383}
384
385IndexData::~IndexData()
386{
387 Reset();
388}
389
390void IndexData::Reset()
391{
392 // Release shared ptr memory stream.
393 buffer.reset();
394}
395
396size_t IndexData::IndexSize() const
397{
398 return (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
399}
400
401size_t IndexData::FaceSize() const
402{
403 return IndexSize() * 3;
404}
405
406// Mesh
407
408Mesh::Mesh()
409 : hasSkeletalAnimations(false)
410 , skeleton(NULL)
411 , sharedVertexData(NULL)
412 , subMeshes()
413 , animations()
414 , poses()
415{
416}
417
418Mesh::~Mesh()
419{
420 Reset();
421}
422
423void Mesh::Reset()
424{
425 OGRE_SAFE_DELETE(skeleton)
426 OGRE_SAFE_DELETE(sharedVertexData)
427
428 for(auto &mesh : subMeshes) {
429 OGRE_SAFE_DELETE(mesh)
430 }
431 subMeshes.clear();
432 for(auto &anim : animations) {
433 OGRE_SAFE_DELETE(anim)
434 }
435 animations.clear();
436 for(auto &pose : poses) {
437 OGRE_SAFE_DELETE(pose)
438 }
439 poses.clear();
440}
441
442size_t Mesh::NumSubMeshes() const
443{
444 return subMeshes.size();
445}
446
447SubMesh *Mesh::GetSubMesh( size_t index ) const
448{
449 for ( size_t i = 0; i < subMeshes.size(); ++i ) {
450 if ( subMeshes[ i ]->index == index ) {
451 return subMeshes[ i ];
452 }
453 }
454 return 0;
455}
456
457void Mesh::ConvertToAssimpScene(aiScene* dest)
458{
459 if ( nullptr == dest ) {
460 return;
461 }
462
463 // Setup
464 dest->mNumMeshes = static_cast<unsigned int>(NumSubMeshes());
465 dest->mMeshes = new aiMesh*[dest->mNumMeshes];
466
467 // Create root node
468 dest->mRootNode = new aiNode();
469 dest->mRootNode->mNumMeshes = dest->mNumMeshes;
470 dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
471
472 // Export meshes
473 for(size_t i=0; i<dest->mNumMeshes; ++i) {
474 dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
475 dest->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
476 }
477
478 // Export skeleton
479 if (skeleton)
480 {
481 // Bones
482 if (!skeleton->bones.empty())
483 {
484 BoneList rootBones = skeleton->RootBones();
485 dest->mRootNode->mNumChildren = static_cast<unsigned int>(rootBones.size());
486 dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren];
487
488 for(size_t i=0, len=rootBones.size(); i<len; ++i)
489 {
490 dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode);
491 }
492 }
493
494 // Animations
495 if (!skeleton->animations.empty())
496 {
497 dest->mNumAnimations = static_cast<unsigned int>(skeleton->animations.size());
498 dest->mAnimations = new aiAnimation*[dest->mNumAnimations];
499
500 for(size_t i=0, len=skeleton->animations.size(); i<len; ++i)
501 {
502 dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation();
503 }
504 }
505 }
506}
507
508// ISubMesh
509
510ISubMesh::ISubMesh() :
511 index(0),
512 materialIndex(-1),
513 usesSharedVertexData(false),
514 operationType(OT_POINT_LIST)
515{
516}
517
518// SubMesh
519
520SubMesh::SubMesh() :
521 vertexData(0),
522 indexData(new IndexData())
523{
524}
525
526SubMesh::~SubMesh()
527{
528 Reset();
529}
530
531void SubMesh::Reset()
532{
533 OGRE_SAFE_DELETE(vertexData)
534 OGRE_SAFE_DELETE(indexData)
535}
536
537aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent)
538{
539 if (operationType != OT_TRIANGLE_LIST) {
540 throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType);
541 }
542
543 aiMesh *dest = new aiMesh();
544 dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
545
546 if (!name.empty())
547 dest->mName = name;
548
549 // Material index
550 if (materialIndex != -1)
551 dest->mMaterialIndex = materialIndex;
552
553 // Pick source vertex data from shader geometry or from internal geometry.
554 VertexData *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData);
555
556 VertexElement *positionsElement = src->GetVertexElement(VertexElement::VES_POSITION);
557 VertexElement *normalsElement = src->GetVertexElement(VertexElement::VES_NORMAL);
558 VertexElement *uv1Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 0);
559 VertexElement *uv2Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 1);
560
561 // Sanity checks
562 if (!positionsElement) {
563 throw DeadlyImportError("Failed to import Ogre VertexElement::VES_POSITION. Mesh does not have vertex positions!");
564 } else if (positionsElement->type != VertexElement::VET_FLOAT3) {
565 throw DeadlyImportError("Ogre Mesh position vertex element type != VertexElement::VET_FLOAT3. This is not supported.");
566 } else if (normalsElement && normalsElement->type != VertexElement::VET_FLOAT3) {
567 throw DeadlyImportError("Ogre Mesh normal vertex element type != VertexElement::VET_FLOAT3. This is not supported.");
568 }
569
570 // Faces
571 dest->mNumFaces = indexData->faceCount;
572 dest->mFaces = new aiFace[dest->mNumFaces];
573
574 // Assimp required unique vertices, we need to convert from Ogres shared indexing.
575 size_t uniqueVertexCount = dest->mNumFaces * 3;
576 dest->mNumVertices = static_cast<unsigned int>(uniqueVertexCount);
577 dest->mVertices = new aiVector3D[dest->mNumVertices];
578
579 // Source streams
580 MemoryStream *positions = src->VertexBuffer(positionsElement->source);
581 MemoryStream *normals = (normalsElement ? src->VertexBuffer(normalsElement->source) : 0);
582 MemoryStream *uv1 = (uv1Element ? src->VertexBuffer(uv1Element->source) : 0);
583 MemoryStream *uv2 = (uv2Element ? src->VertexBuffer(uv2Element->source) : 0);
584
585 // Element size
586 const size_t sizePosition = positionsElement->Size();
587 const size_t sizeNormal = (normalsElement ? normalsElement->Size() : 0);
588 const size_t sizeUv1 = (uv1Element ? uv1Element->Size() : 0);
589 const size_t sizeUv2 = (uv2Element ? uv2Element->Size() : 0);
590
591 // Vertex width
592 const size_t vWidthPosition = src->VertexSize(positionsElement->source);
593 const size_t vWidthNormal = (normalsElement ? src->VertexSize(normalsElement->source) : 0);
594 const size_t vWidthUv1 = (uv1Element ? src->VertexSize(uv1Element->source) : 0);
595 const size_t vWidthUv2 = (uv2Element ? src->VertexSize(uv2Element->source) : 0);
596
597 bool boneAssignments = src->HasBoneAssignments();
598
599 // Prepare normals
600 if (normals)
601 dest->mNormals = new aiVector3D[dest->mNumVertices];
602
603 // Prepare UVs, ignoring incompatible UVs.
604 if (uv1)
605 {
606 if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3)
607 {
608 dest->mNumUVComponents[0] = static_cast<unsigned int>(uv1Element->ComponentCount());
609 dest->mTextureCoords[0] = new aiVector3D[dest->mNumVertices];
610 }
611 else
612 {
613 DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv1Element->TypeToString() << " is not compatible with Assimp. Ignoring UV.");
614 uv1 = 0;
615 }
616 }
617 if (uv2)
618 {
619 if (uv2Element->type == VertexElement::VET_FLOAT2 || uv2Element->type == VertexElement::VET_FLOAT3)
620 {
621 dest->mNumUVComponents[1] = static_cast<unsigned int>(uv2Element->ComponentCount());
622 dest->mTextureCoords[1] = new aiVector3D[dest->mNumVertices];
623 }
624 else
625 {
626 DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv2Element->TypeToString() << " is not compatible with Assimp. Ignoring UV.");
627 uv2 = 0;
628 }
629 }
630
631 aiVector3D *uv1Dest = (uv1 ? dest->mTextureCoords[0] : 0);
632 aiVector3D *uv2Dest = (uv2 ? dest->mTextureCoords[1] : 0);
633
634 MemoryStream *faces = indexData->buffer.get();
635 for (size_t fi=0, isize=indexData->IndexSize(), fsize=indexData->FaceSize();
636 fi<dest->mNumFaces; ++fi)
637 {
638 // Source Ogre face
639 aiFace ogreFace;
640 ogreFace.mNumIndices = 3;
641 ogreFace.mIndices = new unsigned int[3];
642
643 faces->Seek(fi * fsize, aiOrigin_SET);
644 if (indexData->is32bit)
645 {
646 faces->Read(&ogreFace.mIndices[0], isize, 3);
647 }
648 else
649 {
650 uint16_t iout = 0;
651 for (size_t ii=0; ii<3; ++ii)
652 {
653 faces->Read(&iout, isize, 1);
654 ogreFace.mIndices[ii] = static_cast<unsigned int>(iout);
655 }
656 }
657
658 // Destination Assimp face
659 aiFace &face = dest->mFaces[fi];
660 face.mNumIndices = 3;
661 face.mIndices = new unsigned int[3];
662
663 const size_t pos = fi * 3;
664 for (size_t v=0; v<3; ++v)
665 {
666 const size_t newIndex = pos + v;
667
668 // Write face index
669 face.mIndices[v] = static_cast<unsigned int>(newIndex);
670
671 // Ogres vertex index to ref into the source buffers.
672 const size_t ogreVertexIndex = ogreFace.mIndices[v];
673 src->AddVertexMapping(static_cast<uint32_t>(ogreVertexIndex), static_cast<uint32_t>(newIndex));
674
675 // Position
676 positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET);
677 positions->Read(&dest->mVertices[newIndex], sizePosition, 1);
678
679 // Normal
680 if (normals)
681 {
682 normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET);
683 normals->Read(&dest->mNormals[newIndex], sizeNormal, 1);
684 }
685 // UV0
686 if (uv1 && uv1Dest)
687 {
688 uv1->Seek((vWidthUv1 * ogreVertexIndex) + uv1Element->offset, aiOrigin_SET);
689 uv1->Read(&uv1Dest[newIndex], sizeUv1, 1);
690 uv1Dest[newIndex].y = (uv1Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form
691 }
692 // UV1
693 if (uv2 && uv2Dest)
694 {
695 uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET);
696 uv2->Read(&uv2Dest[newIndex], sizeUv2, 1);
697 uv2Dest[newIndex].y = (uv2Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form
698 }
699 }
700 }
701
702 // Bones and bone weights
703 if (parent->skeleton && boneAssignments)
704 {
705 AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
706 std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
707
708 dest->mNumBones = static_cast<unsigned int>(referencedBones.size());
709 dest->mBones = new aiBone*[dest->mNumBones];
710
711 size_t assimpBoneIndex = 0;
712 for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex)
713 {
714 Bone *bone = parent->skeleton->BoneById((*rbIter));
715 dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]);
716 }
717 }
718
719 return dest;
720}
721
722// MeshXml
723
724MeshXml::MeshXml() :
725 skeleton(0),
726 sharedVertexData(0)
727{
728}
729
730MeshXml::~MeshXml()
731{
732 Reset();
733}
734
735void MeshXml::Reset()
736{
737 OGRE_SAFE_DELETE(skeleton)
738 OGRE_SAFE_DELETE(sharedVertexData)
739
740 for(auto &mesh : subMeshes) {
741 OGRE_SAFE_DELETE(mesh)
742 }
743 subMeshes.clear();
744}
745
746size_t MeshXml::NumSubMeshes() const
747{
748 return subMeshes.size();
749}
750
751SubMeshXml *MeshXml::GetSubMesh(uint16_t index) const
752{
753 for(size_t i=0; i<subMeshes.size(); ++i)
754 if (subMeshes[i]->index == index)
755 return subMeshes[i];
756 return 0;
757}
758
759void MeshXml::ConvertToAssimpScene(aiScene* dest)
760{
761 // Setup
762 dest->mNumMeshes = static_cast<unsigned int>(NumSubMeshes());
763 dest->mMeshes = new aiMesh*[dest->mNumMeshes];
764
765 // Create root node
766 dest->mRootNode = new aiNode();
767 dest->mRootNode->mNumMeshes = dest->mNumMeshes;
768 dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
769
770 // Export meshes
771 for(size_t i=0; i<dest->mNumMeshes; ++i)
772 {
773 dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
774 dest->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
775 }
776
777 // Export skeleton
778 if (skeleton)
779 {
780 // Bones
781 if (!skeleton->bones.empty())
782 {
783 BoneList rootBones = skeleton->RootBones();
784 dest->mRootNode->mNumChildren = static_cast<unsigned int>(rootBones.size());
785 dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren];
786
787 for(size_t i=0, len=rootBones.size(); i<len; ++i)
788 {
789 dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode);
790 }
791 }
792
793 // Animations
794 if (!skeleton->animations.empty())
795 {
796 dest->mNumAnimations = static_cast<unsigned int>(skeleton->animations.size());
797 dest->mAnimations = new aiAnimation*[dest->mNumAnimations];
798
799 for(size_t i=0, len=skeleton->animations.size(); i<len; ++i)
800 {
801 dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation();
802 }
803 }
804 }
805}
806
807// SubMeshXml
808
809SubMeshXml::SubMeshXml() :
810 indexData(new IndexDataXml()),
811 vertexData(0)
812{
813}
814
815SubMeshXml::~SubMeshXml()
816{
817 Reset();
818}
819
820void SubMeshXml::Reset()
821{
822 OGRE_SAFE_DELETE(indexData)
823 OGRE_SAFE_DELETE(vertexData)
824}
825
826aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent)
827{
828 aiMesh *dest = new aiMesh();
829 dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
830
831 if (!name.empty())
832 dest->mName = name;
833
834 // Material index
835 if (materialIndex != -1)
836 dest->mMaterialIndex = materialIndex;
837
838 // Faces
839 dest->mNumFaces = indexData->faceCount;
840 dest->mFaces = new aiFace[dest->mNumFaces];
841
842 // Assimp required unique vertices, we need to convert from Ogres shared indexing.
843 size_t uniqueVertexCount = dest->mNumFaces * 3;
844 dest->mNumVertices = static_cast<unsigned int>(uniqueVertexCount);
845 dest->mVertices = new aiVector3D[dest->mNumVertices];
846
847 VertexDataXml *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData);
848 bool boneAssignments = src->HasBoneAssignments();
849 bool normals = src->HasNormals();
850 size_t uvs = src->NumUvs();
851
852 // Prepare normals
853 if (normals)
854 dest->mNormals = new aiVector3D[dest->mNumVertices];
855
856 // Prepare UVs
857 for(size_t uvi=0; uvi<uvs; ++uvi)
858 {
859 dest->mNumUVComponents[uvi] = 2;
860 dest->mTextureCoords[uvi] = new aiVector3D[dest->mNumVertices];
861 }
862
863 for (size_t fi=0; fi<dest->mNumFaces; ++fi)
864 {
865 // Source Ogre face
866 aiFace &ogreFace = indexData->faces[fi];
867
868 // Destination Assimp face
869 aiFace &face = dest->mFaces[fi];
870 face.mNumIndices = 3;
871 face.mIndices = new unsigned int[3];
872
873 const size_t pos = fi * 3;
874 for (size_t v=0; v<3; ++v)
875 {
876 const size_t newIndex = pos + v;
877
878 // Write face index
879 face.mIndices[v] = static_cast<unsigned int>(newIndex);
880
881 // Ogres vertex index to ref into the source buffers.
882 const size_t ogreVertexIndex = ogreFace.mIndices[v];
883 src->AddVertexMapping(static_cast<uint32_t>(ogreVertexIndex), static_cast<uint32_t>(newIndex));
884
885 // Position
886 dest->mVertices[newIndex] = src->positions[ogreVertexIndex];
887
888 // Normal
889 if (normals)
890 dest->mNormals[newIndex] = src->normals[ogreVertexIndex];
891
892 // UVs
893 for(size_t uvi=0; uvi<uvs; ++uvi)
894 {
895 aiVector3D *uvDest = dest->mTextureCoords[uvi];
896 std::vector<aiVector3D> &uvSrc = src->uvs[uvi];
897 uvDest[newIndex] = uvSrc[ogreVertexIndex];
898 }
899 }
900 }
901
902 // Bones and bone weights
903 if (parent->skeleton && boneAssignments)
904 {
905 AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
906 std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
907
908 dest->mNumBones = static_cast<unsigned int>(referencedBones.size());
909 dest->mBones = new aiBone*[dest->mNumBones];
910
911 size_t assimpBoneIndex = 0;
912 for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex)
913 {
914 Bone *bone = parent->skeleton->BoneById((*rbIter));
915 dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]);
916 }
917 }
918
919 return dest;
920}
921
922// Animation
923
924Animation::Animation(Skeleton *parent) :
925 parentMesh(NULL),
926 parentSkeleton(parent),
927 length(0.0f),
928 baseTime(-1.0f)
929{
930}
931
932Animation::Animation(Mesh *parent) :
933 parentMesh(parent),
934 parentSkeleton(0),
935 length(0.0f),
936 baseTime(-1.0f)
937{
938}
939
940VertexData *Animation::AssociatedVertexData(VertexAnimationTrack *track) const
941{
942 if (!parentMesh)
943 return 0;
944
945 bool sharedGeom = (track->target == 0);
946 if (sharedGeom)
947 return parentMesh->sharedVertexData;
948 else
949 return parentMesh->GetSubMesh(track->target-1)->vertexData;
950}
951
952aiAnimation *Animation::ConvertToAssimpAnimation()
953{
954 aiAnimation *anim = new aiAnimation();
955 anim->mName = name;
956 anim->mDuration = static_cast<double>(length);
957 anim->mTicksPerSecond = 1.0;
958
959 // Tracks
960 if (!tracks.empty())
961 {
962 anim->mNumChannels = static_cast<unsigned int>(tracks.size());
963 anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
964
965 for(size_t i=0, len=tracks.size(); i<len; ++i)
966 {
967 anim->mChannels[i] = tracks[i].ConvertToAssimpAnimationNode(parentSkeleton);
968 }
969 }
970 return anim;
971}
972
973// Skeleton
974
975Skeleton::Skeleton() :
976 bones(),
977 animations(),
978 blendMode(ANIMBLEND_AVERAGE)
979{
980}
981
982Skeleton::~Skeleton()
983{
984 Reset();
985}
986
987void Skeleton::Reset()
988{
989 for(auto &bone : bones) {
990 OGRE_SAFE_DELETE(bone)
991 }
992 bones.clear();
993 for(auto &anim : animations) {
994 OGRE_SAFE_DELETE(anim)
995 }
996 animations.clear();
997}
998
999BoneList Skeleton::RootBones() const
1000{
1001 BoneList rootBones;
1002 for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
1003 {
1004 if (!(*iter)->IsParented())
1005 rootBones.push_back((*iter));
1006 }
1007 return rootBones;
1008}
1009
1010size_t Skeleton::NumRootBones() const
1011{
1012 size_t num = 0;
1013 for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
1014 {
1015 if (!(*iter)->IsParented())
1016 num++;
1017 }
1018 return num;
1019}
1020
1021Bone *Skeleton::BoneByName(const std::string &name) const
1022{
1023 for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
1024 {
1025 if ((*iter)->name == name)
1026 return (*iter);
1027 }
1028 return 0;
1029}
1030
1031Bone *Skeleton::BoneById(uint16_t id) const
1032{
1033 for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
1034 {
1035 if ((*iter)->id == id)
1036 return (*iter);
1037 }
1038 return 0;
1039}
1040
1041// Bone
1042
1043Bone::Bone() :
1044 id(0),
1045 parent(0),
1046 parentId(-1),
1047 scale(1.0f, 1.0f, 1.0f)
1048{
1049}
1050
1051bool Bone::IsParented() const
1052{
1053 return (parentId != -1 && parent != 0);
1054}
1055
1056uint16_t Bone::ParentId() const
1057{
1058 return static_cast<uint16_t>(parentId);
1059}
1060
1061void Bone::AddChild(Bone *bone)
1062{
1063 if (!bone)
1064 return;
1065 if (bone->IsParented())
1066 throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name);
1067
1068 bone->parent = this;
1069 bone->parentId = id;
1070 children.push_back(bone->id);
1071}
1072
1073void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton)
1074{
1075 if (!IsParented())
1076 worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse();
1077 else
1078 worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix;
1079
1080 defaultPose = aiMatrix4x4(scale, rotation, position);
1081
1082 // Recursively for all children now that the parent matrix has been calculated.
1083 for (auto boneId : children)
1084 {
1085 Bone *child = skeleton->BoneById(boneId);
1086 if (!child) {
1087 throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << boneId << " for parent " << id << " " << name);
1088 }
1089 child->CalculateWorldMatrixAndDefaultPose(skeleton);
1090 }
1091}
1092
1093aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode)
1094{
1095 // Bone node
1096 aiNode* node = new aiNode(name);
1097 node->mParent = parentNode;
1098 node->mTransformation = defaultPose;
1099
1100 // Children
1101 if (!children.empty())
1102 {
1103 node->mNumChildren = static_cast<unsigned int>(children.size());
1104 node->mChildren = new aiNode*[node->mNumChildren];
1105
1106 for(size_t i=0, len=children.size(); i<len; ++i)
1107 {
1108 Bone *child = skeleton->BoneById(children[i]);
1109 if (!child) {
1110 throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name);
1111 }
1112 node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node);
1113 }
1114 }
1115 return node;
1116}
1117
1118aiBone *Bone::ConvertToAssimpBone(Skeleton * /*parent*/, const std::vector<aiVertexWeight> &boneWeights)
1119{
1120 aiBone *bone = new aiBone();
1121 bone->mName = name;
1122 bone->mOffsetMatrix = worldMatrix;
1123
1124 if (!boneWeights.empty())
1125 {
1126 bone->mNumWeights = static_cast<unsigned int>(boneWeights.size());
1127 bone->mWeights = new aiVertexWeight[boneWeights.size()];
1128 memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight));
1129 }
1130
1131 return bone;
1132}
1133
1134// VertexAnimationTrack
1135
1136VertexAnimationTrack::VertexAnimationTrack() :
1137 type(VAT_NONE),
1138 target(0)
1139{
1140}
1141
1142aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleton)
1143{
1144 if (boneName.empty() || type != VAT_TRANSFORM) {
1145 throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Cannot convert track that has no target bone name or is not type of VAT_TRANSFORM");
1146 }
1147
1148 aiNodeAnim *nodeAnim = new aiNodeAnim();
1149 nodeAnim->mNodeName = boneName;
1150
1151 Bone *bone = skeleton->BoneByName(boneName);
1152 if (!bone) {
1153 throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton");
1154 }
1155
1156 // Keyframes
1157 size_t numKeyframes = transformKeyFrames.size();
1158
1159 nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes];
1160 nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes];
1161 nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes];
1162 nodeAnim->mNumPositionKeys = static_cast<unsigned int>(numKeyframes);
1163 nodeAnim->mNumRotationKeys = static_cast<unsigned int>(numKeyframes);
1164 nodeAnim->mNumScalingKeys = static_cast<unsigned int>(numKeyframes);
1165
1166 for(size_t kfi=0; kfi<numKeyframes; ++kfi)
1167 {
1168 TransformKeyFrame &kfSource = transformKeyFrames[kfi];
1169
1170 // Calculate the complete transformation from world space to bone space
1171 aiVector3D pos; aiQuaternion rot; aiVector3D scale;
1172
1173 aiMatrix4x4 finalTransform = bone->defaultPose * kfSource.Transform();
1174 finalTransform.Decompose(scale, rot, pos);
1175
1176 double t = static_cast<double>(kfSource.timePos);
1177 nodeAnim->mPositionKeys[kfi].mTime = t;
1178 nodeAnim->mRotationKeys[kfi].mTime = t;
1179 nodeAnim->mScalingKeys[kfi].mTime = t;
1180
1181 nodeAnim->mPositionKeys[kfi].mValue = pos;
1182 nodeAnim->mRotationKeys[kfi].mValue = rot;
1183 nodeAnim->mScalingKeys[kfi].mValue = scale;
1184 }
1185
1186 return nodeAnim;
1187}
1188
1189// TransformKeyFrame
1190
1191TransformKeyFrame::TransformKeyFrame() :
1192 timePos(0.0f),
1193 scale(1.0f, 1.0f, 1.0f)
1194{
1195}
1196
1197aiMatrix4x4 TransformKeyFrame::Transform()
1198{
1199 return aiMatrix4x4(scale, rotation, position);
1200}
1201
1202} // Ogre
1203} // Assimp
1204
1205#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
1206