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