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#include "OgreBinarySerializer.h"
43#include "OgreXmlSerializer.h"
44#include "OgreParsingUtils.h"
45
46#include "TinyFormatter.h"
47#include <assimp/DefaultLogger.hpp>
48
49
50#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
51
52// Define as 1 to get verbose logging.
53#define OGRE_BINARY_SERIALIZER_DEBUG 0
54
55namespace Assimp
56{
57namespace Ogre
58{
59
60const std::string MESH_VERSION_1_8 = "[MeshSerializer_v1.8]";
61const std::string SKELETON_VERSION_1_8 = "[Serializer_v1.80]";
62const std::string SKELETON_VERSION_1_1 = "[Serializer_v1.10]";
63
64const unsigned short HEADER_CHUNK_ID = 0x1000;
65
66const long MSTREAM_OVERHEAD_SIZE = sizeof(uint16_t) + sizeof(uint32_t);
67const long MSTREAM_BONE_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + sizeof(unsigned short) + (sizeof(float) * 7);
68const long MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + (sizeof(float) * 8);
69
70template<>
71inline bool OgreBinarySerializer::Read<bool>()
72{
73 return (m_reader->GetU1() > 0);
74}
75
76template<>
77inline char OgreBinarySerializer::Read<char>()
78{
79 return static_cast<char>(m_reader->GetU1());
80}
81
82template<>
83inline uint8_t OgreBinarySerializer::Read<uint8_t>()
84{
85 return m_reader->GetU1();
86}
87
88template<>
89inline uint16_t OgreBinarySerializer::Read<uint16_t>()
90{
91 return m_reader->GetU2();
92}
93
94template<>
95inline uint32_t OgreBinarySerializer::Read<uint32_t>()
96{
97 return m_reader->GetU4();
98}
99
100template<>
101inline float OgreBinarySerializer::Read<float>()
102{
103 return m_reader->GetF4();
104}
105
106void OgreBinarySerializer::ReadBytes(char *dest, size_t numBytes)
107{
108 ReadBytes(static_cast<void*>(dest), numBytes);
109}
110
111void OgreBinarySerializer::ReadBytes(uint8_t *dest, size_t numBytes)
112{
113 ReadBytes(static_cast<void*>(dest), numBytes);
114}
115
116void OgreBinarySerializer::ReadBytes(void *dest, size_t numBytes)
117{
118 m_reader->CopyAndAdvance(dest, numBytes);
119}
120
121uint8_t *OgreBinarySerializer::ReadBytes(size_t numBytes)
122{
123 uint8_t *bytes = new uint8_t[numBytes];
124 ReadBytes(bytes, numBytes);
125 return bytes;
126}
127
128void OgreBinarySerializer::ReadVector(aiVector3D &vec)
129{
130 m_reader->CopyAndAdvance(&vec.x, sizeof(float)*3);
131}
132
133void OgreBinarySerializer::ReadQuaternion(aiQuaternion &quat)
134{
135 float temp[4];
136 m_reader->CopyAndAdvance(temp, sizeof(float)*4);
137 quat.x = temp[0];
138 quat.y = temp[1];
139 quat.z = temp[2];
140 quat.w = temp[3];
141}
142
143bool OgreBinarySerializer::AtEnd() const
144{
145 return (m_reader->GetRemainingSize() == 0);
146}
147
148std::string OgreBinarySerializer::ReadString(size_t len)
149{
150 std::string str;
151 str.resize(len);
152 ReadBytes(&str[0], len);
153 return str;
154}
155
156std::string OgreBinarySerializer::ReadLine()
157{
158 std::string str;
159 while(!AtEnd())
160 {
161 char c = Read<char>();
162 if (c == '\n')
163 break;
164 str += c;
165 }
166 return str;
167}
168
169uint16_t OgreBinarySerializer::ReadHeader(bool readLen)
170{
171 uint16_t id = Read<uint16_t>();
172 if (readLen)
173 m_currentLen = Read<uint32_t>();
174
175#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
176 if (id != HEADER_CHUNK_ID)
177 {
178 DefaultLogger::get()->debug(Formatter::format() << (assetMode == AM_Mesh
179 ? MeshHeaderToString(static_cast<MeshChunkId>(id)) : SkeletonHeaderToString(static_cast<SkeletonChunkId>(id))));
180 }
181#endif
182
183 return id;
184}
185
186void OgreBinarySerializer::RollbackHeader()
187{
188 m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE);
189}
190
191void OgreBinarySerializer::SkipBytes(size_t numBytes)
192{
193#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
194 DefaultLogger::get()->debug(Formatter::format() << "Skipping " << numBytes << " bytes");
195#endif
196
197 m_reader->IncPtr(numBytes);
198}
199
200// Mesh
201
202Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
203{
204 OgreBinarySerializer serializer(stream, OgreBinarySerializer::AM_Mesh);
205
206 uint16_t id = serializer.ReadHeader(false);
207 if (id != HEADER_CHUNK_ID) {
208 throw DeadlyExportError("Invalid Ogre Mesh file header.");
209 }
210
211 /// @todo Check what we can actually support.
212 std::string version = serializer.ReadLine();
213 if (version != MESH_VERSION_1_8)
214 {
215 throw DeadlyExportError(Formatter::format() << "Mesh version " << version << " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again."
216 << " Supported versions: " << MESH_VERSION_1_8);
217 }
218
219 Mesh *mesh = new Mesh();
220 while (!serializer.AtEnd())
221 {
222 id = serializer.ReadHeader();
223 switch(id)
224 {
225 case M_MESH:
226 {
227 serializer.ReadMesh(mesh);
228 break;
229 }
230 }
231 }
232 return mesh;
233}
234
235void OgreBinarySerializer::ReadMesh(Mesh *mesh)
236{
237 mesh->hasSkeletalAnimations = Read<bool>();
238
239 DefaultLogger::get()->debug("Reading Mesh");
240 DefaultLogger::get()->debug(Formatter::format() << " - Skeletal animations: " << (mesh->hasSkeletalAnimations ? "true" : "false"));
241
242 if (!AtEnd())
243 {
244 uint16_t id = ReadHeader();
245 while (!AtEnd() &&
246 (id == M_GEOMETRY ||
247 id == M_SUBMESH ||
248 id == M_MESH_SKELETON_LINK ||
249 id == M_MESH_BONE_ASSIGNMENT ||
250 id == M_MESH_LOD ||
251 id == M_MESH_BOUNDS ||
252 id == M_SUBMESH_NAME_TABLE ||
253 id == M_EDGE_LISTS ||
254 id == M_POSES ||
255 id == M_ANIMATIONS ||
256 id == M_TABLE_EXTREMES))
257 {
258 switch(id)
259 {
260 case M_GEOMETRY:
261 {
262 mesh->sharedVertexData = new VertexData();
263 ReadGeometry(mesh->sharedVertexData);
264 break;
265 }
266 case M_SUBMESH:
267 {
268 ReadSubMesh(mesh);
269 break;
270 }
271 case M_MESH_SKELETON_LINK:
272 {
273 ReadMeshSkeletonLink(mesh);
274 break;
275 }
276 case M_MESH_BONE_ASSIGNMENT:
277 {
278 ReadBoneAssignment(mesh->sharedVertexData);
279 break;
280 }
281 case M_MESH_LOD:
282 {
283 ReadMeshLodInfo(mesh);
284 break;
285 }
286 case M_MESH_BOUNDS:
287 {
288 ReadMeshBounds(mesh);
289 break;
290 }
291 case M_SUBMESH_NAME_TABLE:
292 {
293 ReadSubMeshNames(mesh);
294 break;
295 }
296 case M_EDGE_LISTS:
297 {
298 ReadEdgeList(mesh);
299 break;
300 }
301 case M_POSES:
302 {
303 ReadPoses(mesh);
304 break;
305 }
306 case M_ANIMATIONS:
307 {
308 ReadAnimations(mesh);
309 break;
310 }
311 case M_TABLE_EXTREMES:
312 {
313 ReadMeshExtremes(mesh);
314 break;
315 }
316 }
317
318 if (!AtEnd())
319 id = ReadHeader();
320 }
321 if (!AtEnd())
322 RollbackHeader();
323 }
324
325 NormalizeBoneWeights(mesh->sharedVertexData);
326}
327
328void OgreBinarySerializer::ReadMeshLodInfo(Mesh *mesh)
329{
330 // Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
331 // @todo Put this stuff to scene/mesh custom properties. If manual mesh the app can use the information.
332 ReadLine(); // strategy name
333 uint16_t numLods = Read<uint16_t>();
334 bool manual = Read<bool>();
335
336 /// @note Main mesh is considered as LOD 0, start from index 1.
337 for (size_t i=1; i<numLods; ++i)
338 {
339 uint16_t id = ReadHeader();
340 if (id != M_MESH_LOD_USAGE) {
341 throw DeadlyImportError("M_MESH_LOD does not contain a M_MESH_LOD_USAGE for each LOD level");
342 }
343
344 m_reader->IncPtr(sizeof(float)); // user value
345
346 if (manual)
347 {
348 id = ReadHeader();
349 if (id != M_MESH_LOD_MANUAL) {
350 throw DeadlyImportError("Manual M_MESH_LOD_USAGE does not contain M_MESH_LOD_MANUAL");
351 }
352
353 ReadLine(); // manual mesh name (ref to another mesh)
354 }
355 else
356 {
357 for(size_t si=0, silen=mesh->NumSubMeshes(); si<silen; ++si)
358 {
359 id = ReadHeader();
360 if (id != M_MESH_LOD_GENERATED) {
361 throw DeadlyImportError("Generated M_MESH_LOD_USAGE does not contain M_MESH_LOD_GENERATED");
362 }
363
364 uint32_t indexCount = Read<uint32_t>();
365 bool is32bit = Read<bool>();
366
367 if (indexCount > 0)
368 {
369 uint32_t len = indexCount * (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
370 m_reader->IncPtr(len);
371 }
372 }
373 }
374 }
375}
376
377void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh)
378{
379 mesh->skeletonRef = ReadLine();
380}
381
382void OgreBinarySerializer::ReadMeshBounds(Mesh * /*mesh*/)
383{
384 // Skip bounds, not compatible with Assimp.
385 // 2x float vec3 + 1x float sphere radius
386 SkipBytes(sizeof(float) * 7);
387}
388
389void OgreBinarySerializer::ReadMeshExtremes(Mesh * /*mesh*/)
390{
391 // Skip extremes, not compatible with Assimp.
392 size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE;
393 SkipBytes(numBytes);
394}
395
396void OgreBinarySerializer::ReadBoneAssignment(VertexData *dest)
397{
398 if (!dest) {
399 throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
400 }
401
402 VertexBoneAssignment ba;
403 ba.vertexIndex = Read<uint32_t>();
404 ba.boneIndex = Read<uint16_t>();
405 ba.weight = Read<float>();
406
407 dest->boneAssignments.push_back(ba);
408}
409
410void OgreBinarySerializer::ReadSubMesh(Mesh *mesh)
411{
412 uint16_t id = 0;
413
414 SubMesh *submesh = new SubMesh();
415 submesh->materialRef = ReadLine();
416 submesh->usesSharedVertexData = Read<bool>();
417
418 submesh->indexData->count = Read<uint32_t>();
419 submesh->indexData->faceCount = static_cast<uint32_t>(submesh->indexData->count / 3);
420 submesh->indexData->is32bit = Read<bool>();
421
422 DefaultLogger::get()->debug(Formatter::format() << "Reading SubMesh " << mesh->subMeshes.size());
423 DefaultLogger::get()->debug(Formatter::format() << " - Material: '" << submesh->materialRef << "'");
424 DefaultLogger::get()->debug(Formatter::format() << " - Uses shared geometry: " << (submesh->usesSharedVertexData ? "true" : "false"));
425
426 // Index buffer
427 if (submesh->indexData->count > 0)
428 {
429 uint32_t numBytes = submesh->indexData->count * (submesh->indexData->is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
430 uint8_t *indexBuffer = ReadBytes(numBytes);
431 submesh->indexData->buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(indexBuffer, numBytes, true));
432
433 DefaultLogger::get()->debug(Formatter::format() << " - " << submesh->indexData->faceCount
434 << " faces from " << submesh->indexData->count << (submesh->indexData->is32bit ? " 32bit" : " 16bit")
435 << " indexes of " << numBytes << " bytes");
436 }
437
438 // Vertex buffer if not referencing the shared geometry
439 if (!submesh->usesSharedVertexData)
440 {
441 id = ReadHeader();
442 if (id != M_GEOMETRY) {
443 throw DeadlyImportError("M_SUBMESH does not contain M_GEOMETRY, but shader geometry is set to false");
444 }
445
446 submesh->vertexData = new VertexData();
447 ReadGeometry(submesh->vertexData);
448 }
449
450 // Bone assignment, submesh operation and texture aliases
451 if (!AtEnd())
452 {
453 id = ReadHeader();
454 while (!AtEnd() &&
455 (id == M_SUBMESH_OPERATION ||
456 id == M_SUBMESH_BONE_ASSIGNMENT ||
457 id == M_SUBMESH_TEXTURE_ALIAS))
458 {
459 switch(id)
460 {
461 case M_SUBMESH_OPERATION:
462 {
463 ReadSubMeshOperation(submesh);
464 break;
465 }
466 case M_SUBMESH_BONE_ASSIGNMENT:
467 {
468 ReadBoneAssignment(submesh->vertexData);
469 break;
470 }
471 case M_SUBMESH_TEXTURE_ALIAS:
472 {
473 ReadSubMeshTextureAlias(submesh);
474 break;
475 }
476 }
477
478 if (!AtEnd())
479 id = ReadHeader();
480 }
481 if (!AtEnd())
482 RollbackHeader();
483 }
484
485 NormalizeBoneWeights(submesh->vertexData);
486
487 submesh->index = static_cast<unsigned int>(mesh->subMeshes.size());
488 mesh->subMeshes.push_back(submesh);
489}
490
491void OgreBinarySerializer::NormalizeBoneWeights(VertexData *vertexData) const
492{
493 if (!vertexData || vertexData->boneAssignments.empty())
494 return;
495
496 std::set<uint32_t> influencedVertices;
497 for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) {
498 influencedVertices.insert(baIter->vertexIndex);
499 }
500
501 /** Normalize bone weights.
502 Some exporters won't care if the sum of all bone weights
503 for a single vertex equals 1 or not, so validate here. */
504 const float epsilon = 0.05f;
505 for (const uint32_t vertexIndex : influencedVertices)
506 {
507 float sum = 0.0f;
508 for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter)
509 {
510 if (baIter->vertexIndex == vertexIndex)
511 sum += baIter->weight;
512 }
513 if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon)))
514 {
515 for (auto &boneAssign : vertexData->boneAssignments)
516 {
517 if (boneAssign.vertexIndex == vertexIndex)
518 boneAssign.weight /= sum;
519 }
520 }
521 }
522}
523
524void OgreBinarySerializer::ReadSubMeshOperation(SubMesh *submesh)
525{
526 submesh->operationType = static_cast<SubMesh::OperationType>(Read<uint16_t>());
527}
528
529void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh *submesh)
530{
531 submesh->textureAliasName = ReadLine();
532 submesh->textureAliasRef = ReadLine();
533}
534
535void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh)
536{
537 uint16_t id = 0;
538
539 if (!AtEnd())
540 {
541 id = ReadHeader();
542 while (!AtEnd() && id == M_SUBMESH_NAME_TABLE_ELEMENT)
543 {
544 uint16_t submeshIndex = Read<uint16_t>();
545 SubMesh *submesh = mesh->GetSubMesh(submeshIndex);
546 if (!submesh) {
547 throw DeadlyImportError(Formatter::format() << "Ogre Mesh does not include submesh " << submeshIndex << " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file.");
548 }
549
550 submesh->name = ReadLine();
551 DefaultLogger::get()->debug(Formatter::format() << " - SubMesh " << submesh->index << " name '" << submesh->name << "'");
552
553 if (!AtEnd())
554 id = ReadHeader();
555 }
556 if (!AtEnd())
557 RollbackHeader();
558 }
559}
560
561void OgreBinarySerializer::ReadGeometry(VertexData *dest)
562{
563 dest->count = Read<uint32_t>();
564
565 DefaultLogger::get()->debug(Formatter::format() << " - Reading geometry of " << dest->count << " vertices");
566
567 if (!AtEnd())
568 {
569 uint16_t id = ReadHeader();
570 while (!AtEnd() &&
571 (id == M_GEOMETRY_VERTEX_DECLARATION ||
572 id == M_GEOMETRY_VERTEX_BUFFER))
573 {
574 switch(id)
575 {
576 case M_GEOMETRY_VERTEX_DECLARATION:
577 {
578 ReadGeometryVertexDeclaration(dest);
579 break;
580 }
581 case M_GEOMETRY_VERTEX_BUFFER:
582 {
583 ReadGeometryVertexBuffer(dest);
584 break;
585 }
586 }
587
588 if (!AtEnd())
589 id = ReadHeader();
590 }
591 if (!AtEnd())
592 RollbackHeader();
593 }
594}
595
596void OgreBinarySerializer::ReadGeometryVertexDeclaration(VertexData *dest)
597{
598 if (!AtEnd())
599 {
600 uint16_t id = ReadHeader();
601 while (!AtEnd() && id == M_GEOMETRY_VERTEX_ELEMENT)
602 {
603 ReadGeometryVertexElement(dest);
604
605 if (!AtEnd())
606 id = ReadHeader();
607 }
608 if (!AtEnd())
609 RollbackHeader();
610 }
611}
612
613void OgreBinarySerializer::ReadGeometryVertexElement(VertexData *dest)
614{
615 VertexElement element;
616 element.source = Read<uint16_t>();
617 element.type = static_cast<VertexElement::Type>(Read<uint16_t>());
618 element.semantic = static_cast<VertexElement::Semantic>(Read<uint16_t>());
619 element.offset = Read<uint16_t>();
620 element.index = Read<uint16_t>();
621
622 DefaultLogger::get()->debug(Formatter::format() << " - Vertex element " << element.SemanticToString() << " of type "
623 << element.TypeToString() << " index=" << element.index << " source=" << element.source);
624
625 dest->vertexElements.push_back(element);
626}
627
628void OgreBinarySerializer::ReadGeometryVertexBuffer(VertexData *dest)
629{
630 uint16_t bindIndex = Read<uint16_t>();
631 uint16_t vertexSize = Read<uint16_t>();
632
633 uint16_t id = ReadHeader();
634 if (id != M_GEOMETRY_VERTEX_BUFFER_DATA)
635 throw DeadlyImportError("M_GEOMETRY_VERTEX_BUFFER_DATA not found in M_GEOMETRY_VERTEX_BUFFER");
636
637 if (dest->VertexSize(bindIndex) != vertexSize)
638 throw DeadlyImportError("Vertex buffer size does not agree with vertex declaration in M_GEOMETRY_VERTEX_BUFFER");
639
640 size_t numBytes = dest->count * vertexSize;
641 uint8_t *vertexBuffer = ReadBytes(numBytes);
642 dest->vertexBindings[bindIndex] = MemoryStreamPtr(new Assimp::MemoryIOStream(vertexBuffer, numBytes, true));
643
644 DefaultLogger::get()->debug(Formatter::format() << " - Read vertex buffer for source " << bindIndex << " of " << numBytes << " bytes");
645}
646
647void OgreBinarySerializer::ReadEdgeList(Mesh * /*mesh*/)
648{
649 // Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
650
651 if (!AtEnd())
652 {
653 uint16_t id = ReadHeader();
654 while (!AtEnd() && id == M_EDGE_LIST_LOD)
655 {
656 m_reader->IncPtr(sizeof(uint16_t)); // lod index
657 bool manual = Read<bool>();
658
659 if (!manual)
660 {
661 m_reader->IncPtr(sizeof(uint8_t));
662 uint32_t numTriangles = Read<uint32_t>();
663 uint32_t numEdgeGroups = Read<uint32_t>();
664
665 size_t skipBytes = (sizeof(uint32_t) * 8 + sizeof(float) * 4) * numTriangles;
666 m_reader->IncPtr(skipBytes);
667
668 for (size_t i=0; i<numEdgeGroups; ++i)
669 {
670 uint16_t id = ReadHeader();
671 if (id != M_EDGE_GROUP)
672 throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD");
673
674 m_reader->IncPtr(sizeof(uint32_t) * 3);
675 uint32_t numEdges = Read<uint32_t>();
676 for (size_t j=0; j<numEdges; ++j)
677 {
678 m_reader->IncPtr(sizeof(uint32_t) * 6 + sizeof(uint8_t));
679 }
680 }
681 }
682
683 if (!AtEnd())
684 id = ReadHeader();
685 }
686 if (!AtEnd())
687 RollbackHeader();
688 }
689}
690
691void OgreBinarySerializer::ReadPoses(Mesh *mesh)
692{
693 if (!AtEnd())
694 {
695 uint16_t id = ReadHeader();
696 while (!AtEnd() && id == M_POSE)
697 {
698 Pose *pose = new Pose();
699 pose->name = ReadLine();
700 pose->target = Read<uint16_t>();
701 pose->hasNormals = Read<bool>();
702
703 ReadPoseVertices(pose);
704
705 mesh->poses.push_back(pose);
706
707 if (!AtEnd())
708 id = ReadHeader();
709 }
710 if (!AtEnd())
711 RollbackHeader();
712 }
713}
714
715void OgreBinarySerializer::ReadPoseVertices(Pose *pose)
716{
717 if (!AtEnd())
718 {
719 uint16_t id = ReadHeader();
720 while (!AtEnd() && id == M_POSE_VERTEX)
721 {
722 Pose::Vertex v;
723 v.index = Read<uint32_t>();
724 ReadVector(v.offset);
725 if (pose->hasNormals)
726 ReadVector(v.normal);
727
728 pose->vertices[v.index] = v;
729
730 if (!AtEnd())
731 id = ReadHeader();
732 }
733 if (!AtEnd())
734 RollbackHeader();
735 }
736}
737
738void OgreBinarySerializer::ReadAnimations(Mesh *mesh)
739{
740 if (!AtEnd())
741 {
742 uint16_t id = ReadHeader();
743 while (!AtEnd() && id == M_ANIMATION)
744 {
745 Animation *anim = new Animation(mesh);
746 anim->name = ReadLine();
747 anim->length = Read<float>();
748
749 ReadAnimation(anim);
750
751 mesh->animations.push_back(anim);
752
753 if (!AtEnd())
754 id = ReadHeader();
755 }
756 if (!AtEnd())
757 RollbackHeader();
758 }
759}
760
761void OgreBinarySerializer::ReadAnimation(Animation *anim)
762{
763 if (!AtEnd())
764 {
765 uint16_t id = ReadHeader();
766 if (id == M_ANIMATION_BASEINFO)
767 {
768 anim->baseName = ReadLine();
769 anim->baseTime = Read<float>();
770
771 // Advance to first track
772 id = ReadHeader();
773 }
774
775 while (!AtEnd() && id == M_ANIMATION_TRACK)
776 {
777 VertexAnimationTrack track;
778 track.type = static_cast<VertexAnimationTrack::Type>(Read<uint16_t>());
779 track.target = Read<uint16_t>();
780
781 ReadAnimationKeyFrames(anim, &track);
782
783 anim->tracks.push_back(track);
784
785 if (!AtEnd())
786 id = ReadHeader();
787 }
788 if (!AtEnd())
789 RollbackHeader();
790 }
791}
792
793void OgreBinarySerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track)
794{
795 if (!AtEnd())
796 {
797 uint16_t id = ReadHeader();
798 while (!AtEnd() &&
799 (id == M_ANIMATION_MORPH_KEYFRAME ||
800 id == M_ANIMATION_POSE_KEYFRAME))
801 {
802 if (id == M_ANIMATION_MORPH_KEYFRAME)
803 {
804 MorphKeyFrame kf;
805 kf.timePos = Read<float>();
806 bool hasNormals = Read<bool>();
807
808 size_t vertexCount = anim->AssociatedVertexData(track)->count;
809 size_t vertexSize = sizeof(float) * (hasNormals ? 6 : 3);
810 size_t numBytes = vertexCount * vertexSize;
811
812 uint8_t *morphBuffer = ReadBytes(numBytes);
813 kf.buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(morphBuffer, numBytes, true));
814
815 track->morphKeyFrames.push_back(kf);
816 }
817 else if (id == M_ANIMATION_POSE_KEYFRAME)
818 {
819 PoseKeyFrame kf;
820 kf.timePos = Read<float>();
821
822 if (!AtEnd())
823 {
824 id = ReadHeader();
825 while (!AtEnd() && id == M_ANIMATION_POSE_REF)
826 {
827 PoseRef pr;
828 pr.index = Read<uint16_t>();
829 pr.influence = Read<float>();
830 kf.references.push_back(pr);
831
832 if (!AtEnd())
833 id = ReadHeader();
834 }
835 if (!AtEnd())
836 RollbackHeader();
837 }
838
839 track->poseKeyFrames.push_back(kf);
840 }
841
842 if (!AtEnd())
843 id = ReadHeader();
844 }
845 if (!AtEnd())
846 RollbackHeader();
847 }
848}
849
850// Skeleton
851
852bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
853{
854 if (!mesh || mesh->skeletonRef.empty())
855 return false;
856
857 // Highly unusual to see in read world cases but support
858 // binary mesh referencing a XML skeleton file.
859 if (EndsWith(mesh->skeletonRef, ".skeleton.xml", false))
860 {
861 OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh);
862 return false;
863 }
864
865 MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
866
867 Skeleton *skeleton = new Skeleton();
868 OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
869 serializer.ReadSkeleton(skeleton);
870 mesh->skeleton = skeleton;
871 return true;
872}
873
874bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
875{
876 if (!mesh || mesh->skeletonRef.empty())
877 return false;
878
879 MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
880 if (!reader.get())
881 return false;
882
883 Skeleton *skeleton = new Skeleton();
884 OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
885 serializer.ReadSkeleton(skeleton);
886 mesh->skeleton = skeleton;
887 return true;
888}
889
890MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
891{
892 if (!EndsWith(filename, ".skeleton", false))
893 {
894 DefaultLogger::get()->error("Imported Mesh is referencing to unsupported '" + filename + "' skeleton file.");
895 return MemoryStreamReaderPtr();
896 }
897
898 if (!pIOHandler->Exists(filename))
899 {
900 DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
901 return MemoryStreamReaderPtr();
902 }
903
904 IOStream *f = pIOHandler->Open(filename, "rb");
905 if (!f) {
906 throw DeadlyImportError("Failed to open skeleton file " + filename);
907 }
908
909 return MemoryStreamReaderPtr(new MemoryStreamReader(f));
910}
911
912void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton)
913{
914 uint16_t id = ReadHeader(false);
915 if (id != HEADER_CHUNK_ID) {
916 throw DeadlyExportError("Invalid Ogre Skeleton file header.");
917 }
918
919 // This deserialization supports both versions of the skeleton spec
920 std::string version = ReadLine();
921 if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1)
922 {
923 throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer."
924 << " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1);
925 }
926
927 DefaultLogger::get()->debug("Reading Skeleton");
928
929 bool firstBone = true;
930 bool firstAnim = true;
931
932 while (!AtEnd())
933 {
934 id = ReadHeader();
935 switch(id)
936 {
937 case SKELETON_BLENDMODE:
938 {
939 skeleton->blendMode = static_cast<Skeleton::BlendMode>(Read<uint16_t>());
940 break;
941 }
942 case SKELETON_BONE:
943 {
944 if (firstBone)
945 {
946 DefaultLogger::get()->debug(" - Bones");
947 firstBone = false;
948 }
949
950 ReadBone(skeleton);
951 break;
952 }
953 case SKELETON_BONE_PARENT:
954 {
955 ReadBoneParent(skeleton);
956 break;
957 }
958 case SKELETON_ANIMATION:
959 {
960 if (firstAnim)
961 {
962 DefaultLogger::get()->debug(" - Animations");
963 firstAnim = false;
964 }
965
966 ReadSkeletonAnimation(skeleton);
967 break;
968 }
969 case SKELETON_ANIMATION_LINK:
970 {
971 ReadSkeletonAnimationLink(skeleton);
972 break;
973 }
974 }
975 }
976
977 // Calculate bone matrices for root bones. Recursively calculates their children.
978 for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
979 {
980 Bone *bone = skeleton->bones[i];
981 if (!bone->IsParented())
982 bone->CalculateWorldMatrixAndDefaultPose(skeleton);
983 }
984}
985
986void OgreBinarySerializer::ReadBone(Skeleton *skeleton)
987{
988 Bone *bone = new Bone();
989 bone->name = ReadLine();
990 bone->id = Read<uint16_t>();
991
992 // Pos and rot
993 ReadVector(bone->position);
994 ReadQuaternion(bone->rotation);
995
996 // Scale (optional)
997 if (m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE)
998 ReadVector(bone->scale);
999
1000 // Bone indexes need to start from 0 and be contiguous
1001 if (bone->id != skeleton->bones.size()) {
1002 throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id);
1003 }
1004
1005 DefaultLogger::get()->debug(Formatter::format() << " " << bone->id << " " << bone->name);
1006
1007 skeleton->bones.push_back(bone);
1008}
1009
1010void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton)
1011{
1012 uint16_t childId = Read<uint16_t>();
1013 uint16_t parentId = Read<uint16_t>();
1014
1015 Bone *child = skeleton->BoneById(childId);
1016 Bone *parent = skeleton->BoneById(parentId);
1017
1018 if (child && parent)
1019 parent->AddChild(child);
1020 else
1021 throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId);
1022}
1023
1024void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton)
1025{
1026 Animation *anim = new Animation(skeleton);
1027 anim->name = ReadLine();
1028 anim->length = Read<float>();
1029
1030 if (!AtEnd())
1031 {
1032 uint16_t id = ReadHeader();
1033 if (id == SKELETON_ANIMATION_BASEINFO)
1034 {
1035 anim->baseName = ReadLine();
1036 anim->baseTime = Read<float>();
1037
1038 // Advance to first track
1039 id = ReadHeader();
1040 }
1041
1042 while (!AtEnd() && id == SKELETON_ANIMATION_TRACK)
1043 {
1044 ReadSkeletonAnimationTrack(skeleton, anim);
1045
1046 if (!AtEnd())
1047 id = ReadHeader();
1048 }
1049 if (!AtEnd())
1050 RollbackHeader();
1051 }
1052
1053 skeleton->animations.push_back(anim);
1054
1055 DefaultLogger::get()->debug(Formatter::format() << " " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");
1056}
1057
1058void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, Animation *dest)
1059{
1060 uint16_t boneId = Read<uint16_t>();
1061 Bone *bone = dest->parentSkeleton->BoneById(boneId);
1062 if (!bone) {
1063 throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton");
1064 }
1065
1066 VertexAnimationTrack track;
1067 track.type = VertexAnimationTrack::VAT_TRANSFORM;
1068 track.boneName = bone->name;
1069
1070 uint16_t id = ReadHeader();
1071 while (!AtEnd() && id == SKELETON_ANIMATION_TRACK_KEYFRAME)
1072 {
1073 ReadSkeletonAnimationKeyFrame(&track);
1074
1075 if (!AtEnd())
1076 id = ReadHeader();
1077 }
1078 if (!AtEnd())
1079 RollbackHeader();
1080
1081 dest->tracks.push_back(track);
1082}
1083
1084void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest)
1085{
1086 TransformKeyFrame keyframe;
1087 keyframe.timePos = Read<float>();
1088
1089 // Rot and pos
1090 ReadQuaternion(keyframe.rotation);
1091 ReadVector(keyframe.position);
1092
1093 // Scale (optional)
1094 if (m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE)
1095 ReadVector(keyframe.scale);
1096
1097 dest->transformKeyFrames.push_back(keyframe);
1098}
1099
1100void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton * /*skeleton*/)
1101{
1102 // Skip bounds, not compatible with Assimp.
1103 ReadLine(); // skeleton name
1104 SkipBytes(sizeof(float) * 3); // scale
1105}
1106
1107} // Ogre
1108} // Assimp
1109
1110#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
1111