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