1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2015, assimp team
6 All rights reserved.
7 
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
11 
12 * Redistributions of source code must retain the above
13   copyright notice, this list of conditions and the
14   following disclaimer.
15 
16 * Redistributions in binary form must reproduce the above
17   copyright notice, this list of conditions and the
18   following disclaimer in the documentation and/or other
19   materials provided with the distribution.
20 
21 * Neither the name of the assimp team, nor the names of its
22   contributors may be used to endorse or promote products
23   derived from this software without specific prior
24   written permission of the assimp team.
25 
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 
38 ----------------------------------------------------------------------
39 */
40 
41 #include "OgreBinarySerializer.h"
42 #include "OgreXmlSerializer.h"
43 #include "OgreParsingUtils.h"
44 
45 #include "TinyFormatter.h"
46 #include "../include/assimp/DefaultLogger.hpp"
47 
48 
49 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
50 
51 // Define as 1 to get verbose logging.
52 #define OGRE_BINARY_SERIALIZER_DEBUG 0
53 
54 namespace Assimp
55 {
56 namespace Ogre
57 {
58 
59 const std::string       MESH_VERSION_1_8        = "[MeshSerializer_v1.8]";
60 const std::string       SKELETON_VERSION_1_8    = "[Serializer_v1.80]";
61 const std::string       SKELETON_VERSION_1_1    = "[Serializer_v1.10]";
62 
63 const unsigned short    HEADER_CHUNK_ID         = 0x1000;
64 
65 const long              MSTREAM_OVERHEAD_SIZE               = sizeof(uint16_t) + sizeof(uint32_t);
66 const long              MSTREAM_BONE_SIZE_WITHOUT_SCALE     = MSTREAM_OVERHEAD_SIZE + sizeof(unsigned short) + (sizeof(float) * 7);
67 const long              MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + (sizeof(float) * 8);
68 
69 template<>
Read()70 inline bool OgreBinarySerializer::Read<bool>()
71 {
72     return (m_reader->GetU1() > 0);
73 }
74 
75 template<>
Read()76 inline char OgreBinarySerializer::Read<char>()
77 {
78     return static_cast<char>(m_reader->GetU1());
79 }
80 
81 template<>
Read()82 inline uint8_t OgreBinarySerializer::Read<uint8_t>()
83 {
84     return m_reader->GetU1();
85 }
86 
87 template<>
Read()88 inline uint16_t OgreBinarySerializer::Read<uint16_t>()
89 {
90     return m_reader->GetU2();
91 }
92 
93 template<>
Read()94 inline uint32_t OgreBinarySerializer::Read<uint32_t>()
95 {
96     return m_reader->GetU4();
97 }
98 
99 template<>
Read()100 inline float OgreBinarySerializer::Read<float>()
101 {
102     return m_reader->GetF4();
103 }
104 
ReadBytes(char * dest,size_t numBytes)105 void OgreBinarySerializer::ReadBytes(char *dest, size_t numBytes)
106 {
107     ReadBytes(static_cast<void*>(dest), numBytes);
108 }
109 
ReadBytes(uint8_t * dest,size_t numBytes)110 void OgreBinarySerializer::ReadBytes(uint8_t *dest, size_t numBytes)
111 {
112     ReadBytes(static_cast<void*>(dest), numBytes);
113 }
114 
ReadBytes(void * dest,size_t numBytes)115 void OgreBinarySerializer::ReadBytes(void *dest, size_t numBytes)
116 {
117     m_reader->CopyAndAdvance(dest, numBytes);
118 }
119 
ReadBytes(size_t numBytes)120 uint8_t *OgreBinarySerializer::ReadBytes(size_t numBytes)
121 {
122     uint8_t *bytes = new uint8_t[numBytes];
123     ReadBytes(bytes, numBytes);
124     return bytes;
125 }
126 
ReadVector(aiVector3D & vec)127 void OgreBinarySerializer::ReadVector(aiVector3D &vec)
128 {
129     m_reader->CopyAndAdvance(&vec.x, sizeof(float)*3);
130 }
131 
ReadQuaternion(aiQuaternion & quat)132 void OgreBinarySerializer::ReadQuaternion(aiQuaternion &quat)
133 {
134     float temp[4];
135     m_reader->CopyAndAdvance(temp, sizeof(float)*4);
136     quat.x = temp[0];
137     quat.y = temp[1];
138     quat.z = temp[2];
139     quat.w = temp[3];
140 }
141 
AtEnd() const142 bool OgreBinarySerializer::AtEnd() const
143 {
144     return (m_reader->GetRemainingSize() == 0);
145 }
146 
ReadString(size_t len)147 std::string OgreBinarySerializer::ReadString(size_t len)
148 {
149     std::string str;
150     str.resize(len);
151     ReadBytes(&str[0], len);
152     return str;
153 }
154 
ReadLine()155 std::string OgreBinarySerializer::ReadLine()
156 {
157     std::string str;
158     while(!AtEnd())
159     {
160         char c = Read<char>();
161         if (c == '\n')
162             break;
163         str += c;
164     }
165     return str;
166 }
167 
ReadHeader(bool readLen)168 uint16_t OgreBinarySerializer::ReadHeader(bool readLen)
169 {
170     uint16_t id = Read<uint16_t>();
171     if (readLen)
172         m_currentLen = Read<uint32_t>();
173 
174 #if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
175     if (id != HEADER_CHUNK_ID)
176     {
177         DefaultLogger::get()->debug(Formatter::format() << (assetMode == AM_Mesh
178             ? MeshHeaderToString(static_cast<MeshChunkId>(id)) : SkeletonHeaderToString(static_cast<SkeletonChunkId>(id))));
179     }
180 #endif
181 
182     return id;
183 }
184 
RollbackHeader()185 void OgreBinarySerializer::RollbackHeader()
186 {
187     m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE);
188 }
189 
SkipBytes(size_t numBytes)190 void OgreBinarySerializer::SkipBytes(size_t numBytes)
191 {
192 #if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
193     DefaultLogger::get()->debug(Formatter::format() << "Skipping " << numBytes << " bytes");
194 #endif
195 
196     m_reader->IncPtr(numBytes);
197 }
198 
199 // Mesh
200 
ImportMesh(MemoryStreamReader * stream)201 Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
202 {
203     OgreBinarySerializer serializer(stream, OgreBinarySerializer::AM_Mesh);
204 
205     uint16_t id = serializer.ReadHeader(false);
206     if (id != HEADER_CHUNK_ID) {
207         throw DeadlyExportError("Invalid Ogre Mesh file header.");
208     }
209 
210     /// @todo Check what we can actually support.
211     std::string version = serializer.ReadLine();
212     if (version != MESH_VERSION_1_8)
213     {
214         throw DeadlyExportError(Formatter::format() << "Mesh version " << version << " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again."
215             << " Supported versions: " << MESH_VERSION_1_8);
216     }
217 
218     Mesh *mesh = new Mesh();
219     while (!serializer.AtEnd())
220     {
221         id = serializer.ReadHeader();
222         switch(id)
223         {
224             case M_MESH:
225             {
226                 serializer.ReadMesh(mesh);
227                 break;
228             }
229         }
230     }
231     return mesh;
232 }
233 
ReadMesh(Mesh * mesh)234 void OgreBinarySerializer::ReadMesh(Mesh *mesh)
235 {
236     mesh->hasSkeletalAnimations = Read<bool>();
237 
238     DefaultLogger::get()->debug("Reading Mesh");
239     DefaultLogger::get()->debug(Formatter::format() << "  - Skeletal animations: " << (mesh->hasSkeletalAnimations ? "true" : "false"));
240 
241     if (!AtEnd())
242     {
243         uint16_t id = ReadHeader();
244         while (!AtEnd() &&
245             (id == M_GEOMETRY ||
246              id == M_SUBMESH ||
247              id == M_MESH_SKELETON_LINK ||
248              id == M_MESH_BONE_ASSIGNMENT ||
249              id == M_MESH_LOD ||
250              id == M_MESH_BOUNDS ||
251              id == M_SUBMESH_NAME_TABLE ||
252              id == M_EDGE_LISTS ||
253              id == M_POSES ||
254              id == M_ANIMATIONS ||
255              id == M_TABLE_EXTREMES))
256         {
257             switch(id)
258             {
259                 case M_GEOMETRY:
260                 {
261                     mesh->sharedVertexData = new VertexData();
262                     ReadGeometry(mesh->sharedVertexData);
263                     break;
264                 }
265                 case M_SUBMESH:
266                 {
267                     ReadSubMesh(mesh);
268                     break;
269                 }
270                 case M_MESH_SKELETON_LINK:
271                 {
272                     ReadMeshSkeletonLink(mesh);
273                     break;
274                 }
275                 case M_MESH_BONE_ASSIGNMENT:
276                 {
277                     ReadBoneAssignment(mesh->sharedVertexData);
278                     break;
279                 }
280                 case M_MESH_LOD:
281                 {
282                     ReadMeshLodInfo(mesh);
283                     break;
284                 }
285                 case M_MESH_BOUNDS:
286                 {
287                     ReadMeshBounds(mesh);
288                     break;
289                 }
290                 case M_SUBMESH_NAME_TABLE:
291                 {
292                     ReadSubMeshNames(mesh);
293                     break;
294                 }
295                 case M_EDGE_LISTS:
296                 {
297                     ReadEdgeList(mesh);
298                     break;
299                 }
300                 case M_POSES:
301                 {
302                     ReadPoses(mesh);
303                     break;
304                 }
305                 case M_ANIMATIONS:
306                 {
307                     ReadAnimations(mesh);
308                     break;
309                 }
310                 case M_TABLE_EXTREMES:
311                 {
312                     ReadMeshExtremes(mesh);
313                     break;
314                 }
315             }
316 
317             if (!AtEnd())
318                 id = ReadHeader();
319         }
320         if (!AtEnd())
321             RollbackHeader();
322     }
323 
324     NormalizeBoneWeights(mesh->sharedVertexData);
325 }
326 
ReadMeshLodInfo(Mesh * mesh)327 void OgreBinarySerializer::ReadMeshLodInfo(Mesh *mesh)
328 {
329     // Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
330     // @todo Put this stuff to scene/mesh custom properties. If manual mesh the app can use the information.
331     ReadLine(); // strategy name
332     uint16_t numLods = Read<uint16_t>();
333     bool manual = Read<bool>();
334 
335     /// @note Main mesh is considered as LOD 0, start from index 1.
336     for (size_t i=1; i<numLods; ++i)
337     {
338         uint16_t id = ReadHeader();
339         if (id != M_MESH_LOD_USAGE) {
340             throw DeadlyImportError("M_MESH_LOD does not contain a M_MESH_LOD_USAGE for each LOD level");
341         }
342 
343         m_reader->IncPtr(sizeof(float)); // user value
344 
345         if (manual)
346         {
347             id = ReadHeader();
348             if (id != M_MESH_LOD_MANUAL) {
349                 throw DeadlyImportError("Manual M_MESH_LOD_USAGE does not contain M_MESH_LOD_MANUAL");
350             }
351 
352             ReadLine(); // manual mesh name (ref to another mesh)
353         }
354         else
355         {
356             for(size_t si=0, silen=mesh->NumSubMeshes(); si<silen; ++si)
357             {
358                 id = ReadHeader();
359                 if (id != M_MESH_LOD_GENERATED) {
360                     throw DeadlyImportError("Generated M_MESH_LOD_USAGE does not contain M_MESH_LOD_GENERATED");
361                 }
362 
363                 uint32_t indexCount = Read<uint32_t>();
364                 bool is32bit = Read<bool>();
365 
366                 if (indexCount > 0)
367                 {
368                     uint32_t len = indexCount * (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
369                     m_reader->IncPtr(len);
370                 }
371             }
372         }
373     }
374 }
375 
ReadMeshSkeletonLink(Mesh * mesh)376 void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh)
377 {
378     mesh->skeletonRef = ReadLine();
379 }
380 
ReadMeshBounds(Mesh *)381 void OgreBinarySerializer::ReadMeshBounds(Mesh * /*mesh*/)
382 {
383     // Skip bounds, not compatible with Assimp.
384     // 2x float vec3 + 1x float sphere radius
385     SkipBytes(sizeof(float) * 7);
386 }
387 
ReadMeshExtremes(Mesh *)388 void OgreBinarySerializer::ReadMeshExtremes(Mesh * /*mesh*/)
389 {
390     // Skip extremes, not compatible with Assimp.
391     size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE;
392     SkipBytes(numBytes);
393 }
394 
ReadBoneAssignment(VertexData * dest)395 void OgreBinarySerializer::ReadBoneAssignment(VertexData *dest)
396 {
397     if (!dest) {
398         throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
399     }
400 
401     VertexBoneAssignment ba;
402     ba.vertexIndex = Read<uint32_t>();
403     ba.boneIndex = Read<uint16_t>();
404     ba.weight = Read<float>();
405 
406     dest->boneAssignments.push_back(ba);
407 }
408 
ReadSubMesh(Mesh * mesh)409 void OgreBinarySerializer::ReadSubMesh(Mesh *mesh)
410 {
411     uint16_t id = 0;
412 
413     SubMesh *submesh = new SubMesh();
414     submesh->materialRef = ReadLine();
415     submesh->usesSharedVertexData = Read<bool>();
416 
417     submesh->indexData->count = Read<uint32_t>();
418     submesh->indexData->faceCount = static_cast<uint32_t>(submesh->indexData->count / 3);
419     submesh->indexData->is32bit = Read<bool>();
420 
421     DefaultLogger::get()->debug(Formatter::format() << "Reading SubMesh " << mesh->subMeshes.size());
422     DefaultLogger::get()->debug(Formatter::format() << "  - Material: '" << submesh->materialRef << "'");
423     DefaultLogger::get()->debug(Formatter::format() << "  - Uses shared geometry: " << (submesh->usesSharedVertexData ? "true" : "false"));
424 
425     // Index buffer
426     if (submesh->indexData->count > 0)
427     {
428         uint32_t numBytes = submesh->indexData->count * (submesh->indexData->is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
429         uint8_t *indexBuffer = ReadBytes(numBytes);
430         submesh->indexData->buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(indexBuffer, numBytes, true));
431 
432         DefaultLogger::get()->debug(Formatter::format() << "  - " << submesh->indexData->faceCount
433             << " faces from " << submesh->indexData->count << (submesh->indexData->is32bit ? " 32bit" : " 16bit")
434             << " indexes of " << numBytes << " bytes");
435     }
436 
437     // Vertex buffer if not referencing the shared geometry
438     if (!submesh->usesSharedVertexData)
439     {
440         id = ReadHeader();
441         if (id != M_GEOMETRY) {
442             throw DeadlyImportError("M_SUBMESH does not contain M_GEOMETRY, but shader geometry is set to false");
443         }
444 
445         submesh->vertexData = new VertexData();
446         ReadGeometry(submesh->vertexData);
447     }
448 
449     // Bone assignment, submesh operation and texture aliases
450     if (!AtEnd())
451     {
452         id = ReadHeader();
453         while (!AtEnd() &&
454             (id == M_SUBMESH_OPERATION ||
455              id == M_SUBMESH_BONE_ASSIGNMENT ||
456              id == M_SUBMESH_TEXTURE_ALIAS))
457         {
458             switch(id)
459             {
460                 case M_SUBMESH_OPERATION:
461                 {
462                     ReadSubMeshOperation(submesh);
463                     break;
464                 }
465                 case M_SUBMESH_BONE_ASSIGNMENT:
466                 {
467                     ReadBoneAssignment(submesh->vertexData);
468                     break;
469                 }
470                 case M_SUBMESH_TEXTURE_ALIAS:
471                 {
472                     ReadSubMeshTextureAlias(submesh);
473                     break;
474                 }
475             }
476 
477             if (!AtEnd())
478                 id = ReadHeader();
479         }
480         if (!AtEnd())
481             RollbackHeader();
482     }
483 
484     NormalizeBoneWeights(submesh->vertexData);
485 
486     submesh->index = mesh->subMeshes.size();
487     mesh->subMeshes.push_back(submesh);
488 }
489 
NormalizeBoneWeights(VertexData * vertexData) const490 void OgreBinarySerializer::NormalizeBoneWeights(VertexData *vertexData) const
491 {
492     if (!vertexData || vertexData->boneAssignments.empty())
493         return;
494 
495     std::set<uint32_t> influencedVertices;
496     for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) {
497         influencedVertices.insert(baIter->vertexIndex);
498     }
499 
500     /** Normalize bone weights.
501         Some exporters wont care if the sum of all bone weights
502         for a single vertex equals 1 or not, so validate here. */
503     const float epsilon = 0.05f;
504     for(std::set<uint32_t>::const_iterator iter=influencedVertices.begin(), end=influencedVertices.end(); iter != end; ++iter)
505     {
506         const uint32_t vertexIndex = (*iter);
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 (VertexBoneAssignmentList::iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter)
517             {
518                 if (baIter->vertexIndex == vertexIndex)
519                     baIter->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             DefaultLogger::get()->debug(Formatter::format() << "  - 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     DefaultLogger::get()->debug(Formatter::format() << "  - 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     DefaultLogger::get()->debug(Formatter::format() << "    - 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     DefaultLogger::get()->debug(Formatter::format() << "    - 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 
868     Skeleton *skeleton = new Skeleton();
869     OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
870     serializer.ReadSkeleton(skeleton);
871     mesh->skeleton = skeleton;
872     return true;
873 }
874 
ImportSkeleton(Assimp::IOSystem * pIOHandler,MeshXml * mesh)875 bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
876 {
877     if (!mesh || mesh->skeletonRef.empty())
878         return false;
879 
880     MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
881     if (!reader.get())
882         return false;
883 
884     Skeleton *skeleton = new Skeleton();
885     OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
886     serializer.ReadSkeleton(skeleton);
887     mesh->skeleton = skeleton;
888     return true;
889 }
890 
OpenReader(Assimp::IOSystem * pIOHandler,const std::string & filename)891 MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
892 {
893     if (!EndsWith(filename, ".skeleton", false))
894     {
895         DefaultLogger::get()->error("Imported Mesh is referencing to unsupported '" + filename + "' skeleton file.");
896         return MemoryStreamReaderPtr();
897     }
898 
899     if (!pIOHandler->Exists(filename))
900     {
901         DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
902         return MemoryStreamReaderPtr();
903     }
904 
905     IOStream *f = pIOHandler->Open(filename, "rb");
906     if (!f) {
907         throw DeadlyImportError("Failed to open skeleton file " + filename);
908     }
909 
910     return MemoryStreamReaderPtr(new MemoryStreamReader(f));
911 }
912 
ReadSkeleton(Skeleton * skeleton)913 void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton)
914 {
915     uint16_t id = ReadHeader(false);
916     if (id != HEADER_CHUNK_ID) {
917         throw DeadlyExportError("Invalid Ogre Skeleton file header.");
918     }
919 
920     // This deserialization supports both versions of the skeleton spec
921     std::string version = ReadLine();
922     if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1)
923     {
924         throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer."
925             << " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1);
926     }
927 
928     DefaultLogger::get()->debug("Reading Skeleton");
929 
930     bool firstBone = true;
931     bool firstAnim = true;
932 
933     while (!AtEnd())
934     {
935         id = ReadHeader();
936         switch(id)
937         {
938             case SKELETON_BLENDMODE:
939             {
940                 skeleton->blendMode = static_cast<Skeleton::BlendMode>(Read<uint16_t>());
941                 break;
942             }
943             case SKELETON_BONE:
944             {
945                 if (firstBone)
946                 {
947                     DefaultLogger::get()->debug("  - Bones");
948                     firstBone = false;
949                 }
950 
951                 ReadBone(skeleton);
952                 break;
953             }
954             case SKELETON_BONE_PARENT:
955             {
956                 ReadBoneParent(skeleton);
957                 break;
958             }
959             case SKELETON_ANIMATION:
960             {
961                 if (firstAnim)
962                 {
963                     DefaultLogger::get()->debug("  - Animations");
964                     firstAnim = false;
965                 }
966 
967                 ReadSkeletonAnimation(skeleton);
968                 break;
969             }
970             case SKELETON_ANIMATION_LINK:
971             {
972                 ReadSkeletonAnimationLink(skeleton);
973                 break;
974             }
975         }
976     }
977 
978     // Calculate bone matrices for root bones. Recursively calculates their children.
979     for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
980     {
981         Bone *bone = skeleton->bones[i];
982         if (!bone->IsParented())
983             bone->CalculateWorldMatrixAndDefaultPose(skeleton);
984     }
985 }
986 
ReadBone(Skeleton * skeleton)987 void OgreBinarySerializer::ReadBone(Skeleton *skeleton)
988 {
989     Bone *bone = new Bone();
990     bone->name = ReadLine();
991     bone->id = Read<uint16_t>();
992 
993     // Pos and rot
994     ReadVector(bone->position);
995     ReadQuaternion(bone->rotation);
996 
997     // Scale (optional)
998     if (m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE)
999         ReadVector(bone->scale);
1000 
1001     // Bone indexes need to start from 0 and be contiguous
1002     if (bone->id != skeleton->bones.size()) {
1003         throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id);
1004     }
1005 
1006     DefaultLogger::get()->debug(Formatter::format() << "    " << bone->id << " " << bone->name);
1007 
1008     skeleton->bones.push_back(bone);
1009 }
1010 
ReadBoneParent(Skeleton * skeleton)1011 void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton)
1012 {
1013     uint16_t childId = Read<uint16_t>();
1014     uint16_t parentId = Read<uint16_t>();
1015 
1016     Bone *child = skeleton->BoneById(childId);
1017     Bone *parent = skeleton->BoneById(parentId);
1018 
1019     if (child && parent)
1020         parent->AddChild(child);
1021     else
1022         throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId);
1023 }
1024 
ReadSkeletonAnimation(Skeleton * skeleton)1025 void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton)
1026 {
1027     Animation *anim = new Animation(skeleton);
1028     anim->name = ReadLine();
1029     anim->length = Read<float>();
1030 
1031     if (!AtEnd())
1032     {
1033         uint16_t id = ReadHeader();
1034         if (id == SKELETON_ANIMATION_BASEINFO)
1035         {
1036             anim->baseName = ReadLine();
1037             anim->baseTime = Read<float>();
1038 
1039             // Advance to first track
1040             id = ReadHeader();
1041         }
1042 
1043         while (!AtEnd() && id == SKELETON_ANIMATION_TRACK)
1044         {
1045             ReadSkeletonAnimationTrack(skeleton, anim);
1046 
1047             if (!AtEnd())
1048                 id = ReadHeader();
1049         }
1050         if (!AtEnd())
1051             RollbackHeader();
1052     }
1053 
1054     skeleton->animations.push_back(anim);
1055 
1056     DefaultLogger::get()->debug(Formatter::format() << "    " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");
1057 }
1058 
ReadSkeletonAnimationTrack(Skeleton *,Animation * dest)1059 void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, Animation *dest)
1060 {
1061     uint16_t boneId = Read<uint16_t>();
1062     Bone *bone = dest->parentSkeleton->BoneById(boneId);
1063     if (!bone) {
1064         throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton");
1065     }
1066 
1067     VertexAnimationTrack track;
1068     track.type = VertexAnimationTrack::VAT_TRANSFORM;
1069     track.boneName = bone->name;
1070 
1071     uint16_t id = ReadHeader();
1072     while (!AtEnd() && id == SKELETON_ANIMATION_TRACK_KEYFRAME)
1073     {
1074         ReadSkeletonAnimationKeyFrame(&track);
1075 
1076         if (!AtEnd())
1077             id = ReadHeader();
1078     }
1079     if (!AtEnd())
1080         RollbackHeader();
1081 
1082     dest->tracks.push_back(track);
1083 }
1084 
ReadSkeletonAnimationKeyFrame(VertexAnimationTrack * dest)1085 void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest)
1086 {
1087     TransformKeyFrame keyframe;
1088     keyframe.timePos = Read<float>();
1089 
1090     // Rot and pos
1091     ReadQuaternion(keyframe.rotation);
1092     ReadVector(keyframe.position);
1093 
1094     // Scale (optional)
1095     if (m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE)
1096         ReadVector(keyframe.scale);
1097 
1098     dest->transformKeyFrames.push_back(keyframe);
1099 }
1100 
ReadSkeletonAnimationLink(Skeleton *)1101 void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton * /*skeleton*/)
1102 {
1103     // Skip bounds, not compatible with Assimp.
1104     ReadLine(); // skeleton name
1105     SkipBytes(sizeof(float) * 3); // scale
1106 }
1107 
1108 } // Ogre
1109 } // Assimp
1110 
1111 #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
1112