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