OpenClonk
StdMeshLoaderBinaryChunks.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2010-2016, The OpenClonk Team and contributors
5  *
6  * Distributed under the terms of the ISC license; see accompanying file
7  * "COPYING" for details.
8  *
9  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10  * See accompanying file "TRADEMARK" for details.
11  *
12  * To redistribute this file separately, substitute the full license texts
13  * for the above references.
14  */
15 
16 #include "C4Include.h"
18 
19 // deleter-agnostic unique_ptr static caster
20 template<typename To, typename From>
21 std::unique_ptr<To> static_unique_cast(From&& p) {
22  return std::unique_ptr<To>(static_cast<To*>(p.release()));
23 }
24 
25 using std::move;
26 
27 namespace Ogre
28 {
29  namespace Mesh
30  {
31  const uint32_t ChunkFileHeader::CurrentVersion = 1080; // Major * 1000 + Minor
32  const std::map<std::string, uint32_t> ChunkFileHeader::VersionTable = {
33  // 1.8: Current version
34  std::make_pair("[MeshSerializer_v1.8]", CurrentVersion),
35  // 1.41: Changes to morph keyframes and poses. We don't use either, so no special handling needed
36  std::make_pair("[MeshSerializer_v1.41]", 1041),
37  // 1.40: Changes to CID_Mesh_LOD chunks, we ignore those, so no special handling needed
38  std::make_pair("[MeshSerializer_v1.40]", 1040)
39  };
40 
41  // Chunk factory
42  std::unique_ptr<Chunk> Chunk::Read(DataStream *stream)
43  {
44  assert(stream->GetRemainingBytes() >= ChunkHeaderLength);
45 
46  // Read metadata
47  ChunkID id = CID_Invalid;
48  id = static_cast<ChunkID>(stream->Read<uint16_t>());
49  size_t size = 0;
50  // Special case: CID_Header doesn't have any size info.
51  if (id != CID_Header)
52  {
53  // All others are proper chunks.
54  size = stream->Read<uint32_t>();
56  }
57 
58  // Create chunk
59  std::unique_ptr<Chunk> chunk;
60  switch (id)
61  {
62  case CID_Header: chunk = std::make_unique<Ogre::Mesh::ChunkFileHeader>(); break;
63  case CID_Mesh: chunk = std::make_unique<Ogre::Mesh::ChunkMesh>(); break;
66  chunk = std::make_unique<Ogre::Mesh::ChunkMeshBoneAssignments>(); break;
67  case CID_Mesh_Skeleton_Link: chunk = std::make_unique<Ogre::Mesh::ChunkMeshSkeletonLink>(); break;
68  case CID_Mesh_Bounds: chunk = std::make_unique<Ogre::Mesh::ChunkMeshBounds>(); break;
69  case CID_Submesh: chunk = std::make_unique<Ogre::Mesh::ChunkSubmesh>(); break;
70  case CID_Submesh_Op: chunk = std::make_unique<Ogre::Mesh::ChunkSubmeshOp>(); break;
71  case CID_Geometry: chunk = std::make_unique<Ogre::Mesh::ChunkGeometry>(); break;
72  case CID_Geometry_Vertex_Buffer: chunk = std::make_unique<Ogre::Mesh::ChunkGeometryVertexBuffer>(); break;
73  case CID_Geometry_Vertex_Data: chunk = std::make_unique<Ogre::Mesh::ChunkGeometryVertexData>(); break;
74  case CID_Geometry_Vertex_Decl: chunk = std::make_unique<Ogre::Mesh::ChunkGeometryVertexDecl>(); break;
75  case CID_Geometry_Vertex_Decl_Element: chunk = std::make_unique<Ogre::Mesh::ChunkGeometryVertexDeclElement>(); break;
76  default:
77  LogF("StdMeshLoader: I don't know what to do with a chunk of type 0x%xu", id);
78  // Fall through
80  // We don't care about these
81  chunk = std::make_unique<Ogre::Mesh::ChunkUnknown>(); break;
82  };
83  chunk->type = id;
84  chunk->size = size;
85  chunk->ReadImpl(stream);
86  return chunk;
87  }
88 
89  void ChunkUnknown::ReadImpl(DataStream *stream) { stream->Seek(GetSize()); }
90 
92  {
93  // Simple version check
94  VersionTable_t::const_iterator it = VersionTable.find(stream->Read<std::string>());
95  if (it == VersionTable.end())
96  throw InvalidVersion();
97  }
98 
100  {
101  hasAnimatedSkeleton = stream->Read<bool>();
102  for (ChunkID id = Chunk::Peek(stream);
104  id = Chunk::Peek(stream)
105  )
106  {
107  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
108  switch (chunk->GetType())
109  {
110  case CID_Geometry:
111  if (geometry)
112  throw MultipleSingletonChunks("There's only one CID_Geometry chunk allowed within a CID_Mesh chunk");
113  geometry = static_unique_cast<ChunkGeometry>(move(chunk));
114  break;
115  case CID_Submesh:
116  submeshes.push_back(static_unique_cast<ChunkSubmesh>(move(chunk)));
117  break;
119  if (!skeletonFile.empty())
120  throw MultipleSingletonChunks("There's only one CID_Mesh_Skeleton_Link chunk allowed within a CID_Mesh chunk");
121  skeletonFile = static_cast<ChunkMeshSkeletonLink*>(chunk.get())->skeleton;
122  break;
123  case CID_Mesh_Bounds:
124  bounds = static_cast<ChunkMeshBounds*>(chunk.get())->bounds;
125  radius = static_cast<ChunkMeshBounds*>(chunk.get())->radius;
126  break;
128  // Collect bone assignments
129  {
130  ChunkMeshBoneAssignments *assignments = static_cast<ChunkMeshBoneAssignments*>(chunk.get());
131  boneAssignments.insert(boneAssignments.end(), assignments->assignments.begin(), assignments->assignments.end());
132  break;
133  }
134  default:
135  LogF("StdMeshLoader: I don't know what to do with a chunk of type 0x%xu inside a CID_Mesh chunk", chunk->GetType());
136  // Fall through
138  case CID_Edge_List:
139  // Ignore those
140  break;
141  }
142  if (stream->AtEof()) break;
143  }
144  }
145 
147  {
148  skeleton = stream->Read<std::string>();
149  }
150 
152  {
153  operation = SO_TriList; // default if no CID_Submesh_Op chunk exists
154  material = stream->Read<std::string>();
155  hasSharedVertices = stream->Read<bool>();
156  size_t index_count = stream->Read<uint32_t>();
157  bool indexes_are_32bit = stream->Read<bool>();
158  faceVertices.reserve(index_count);
159  while (index_count--)
160  {
161  size_t index;
162  if (indexes_are_32bit)
163  index = stream->Read<uint32_t>();
164  else
165  index = stream->Read<uint16_t>();
166  faceVertices.push_back(index);
167  }
168  for (ChunkID id = Chunk::Peek(stream);
170  id = Chunk::Peek(stream)
171  )
172  {
173  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
174 
175  switch (chunk->GetType())
176  {
177  case CID_Geometry:
178  if (hasSharedVertices)
179  // Can't have own vertices and at the same time use those of the parent
180  throw SharedVertexGeometryForbidden();
181  if (geometry)
182  throw MultipleSingletonChunks("There's only one CID_Geometry chunk allowed within a CID_Submesh chunk");
183  geometry = static_unique_cast<ChunkGeometry>(move(chunk));
184  break;
185  case CID_Submesh_Op:
186  operation = static_cast<ChunkSubmeshOp*>(chunk.get())->operation;
187  break;
189  {
190  // Collect bone assignments
191  ChunkMeshBoneAssignments *assignments = static_cast<ChunkMeshBoneAssignments*>(chunk.get());
192  boneAssignments.insert(boneAssignments.end(), assignments->assignments.begin(), assignments->assignments.end());
193  }
194  break;
195  default:
196  LogF("StdMeshLoader: I don't know what to do with a chunk of type 0x%xu inside a CID_Submesh chunk", chunk->GetType());
197  break;
198  }
199  if (stream->AtEof()) break;
200  }
201  }
202 
204  {
205  uint32_t op = stream->Read<uint16_t>();
206  if (op < ChunkSubmesh::SO_MIN || op > ChunkSubmesh::SO_MAX)
207  throw InvalidSubmeshOp();
208  operation = static_cast<ChunkSubmesh::SubmeshOperation>(op);
209  }
210 
212  {
213  size_t bone_count = GetSize() / (sizeof(uint32_t)+sizeof(uint16_t)+sizeof(float));
214  BoneAssignment assignment;
215  while (bone_count-- > 0)
216  {
217  assignment.vertex = stream->Read<uint32_t>();
218  assignment.bone = stream->Read<uint16_t>();
219  assignment.weight = stream->Read<float>();
220  assignments.push_back(assignment);
221  }
222  }
223 
225  {
226  bounds.x1 = stream->Read<float>();
227  bounds.y1 = stream->Read<float>();
228  bounds.z1 = stream->Read<float>();
229  bounds.x2 = stream->Read<float>();
230  bounds.y2 = stream->Read<float>();
231  bounds.z2 = stream->Read<float>();
232  radius = stream->Read<float>();
233  }
234 
236  {
237  vertexCount = stream->Read<uint32_t>();
238  for (ChunkID id = Chunk::Peek(stream);
240  id = Chunk::Peek(stream)
241  )
242  {
243  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
244 
245  switch (chunk->GetType())
246  {
248  if (!vertexDeclaration.empty())
249  throw MultipleSingletonChunks("There's only one CID_Geometry_Vertex_Decl chunk allowed within a CID_Geometry chunk");
250  vertexDeclaration.swap(static_cast<ChunkGeometryVertexDecl*>(chunk.get())->declaration);
251  break;
253  vertexBuffers.push_back(static_unique_cast<ChunkGeometryVertexBuffer>(move(chunk)));
254  break;
255  default:
256  LogF("StdMeshLoader: I don't know what to do with a chunk of type 0x%xu inside a CID_Geometry chunk", chunk->GetType());
257  break;
258  }
259  if (stream->AtEof()) break;
260  }
261  }
262 
264  {
266  {
267  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
268  assert(chunk->GetType() == CID_Geometry_Vertex_Decl_Element);
269  declaration.push_back(static_unique_cast<ChunkGeometryVertexDeclElement>(chunk));
270  if (stream->AtEof()) break;
271  }
272  }
273 
275  {
276  source = stream->Read<uint16_t>();
277  int32_t t = stream->Read<uint16_t>();
278  if (t < VDET_MIN || t > VDET_MAX)
279  throw InvalidVertexType();
280  type = static_cast<Type>(t);
281  t = stream->Read<uint16_t>();
282  if (t < VDES_MIN || t > VDES_MAX)
283  throw InvalidVertexSemantic();
284  semantic = static_cast<Semantic>(t);
285  offset = stream->Read<uint16_t>();
286  index = stream->Read<uint16_t>();
287  }
288 
290  {
291  index = stream->Read<uint16_t>();
292  vertexSize = stream->Read<uint16_t>();
293 
294  while (Chunk::Peek(stream) == CID_Geometry_Vertex_Data)
295  {
296  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
297  assert(chunk->GetType() == CID_Geometry_Vertex_Data);
298  if (data)
299  throw MultipleSingletonChunks("There's only one CID_Geometry_Vertex_Data chunk allowed within a CID_Geometry_Vertex_Buffer chunk");
300  data = static_unique_cast<ChunkGeometryVertexData>(move(chunk));
301  if (stream->AtEof()) break;
302  }
303  }
304 
306  {
307  data = new char[GetSize()];
308  stream->Read(data, GetSize());
309  }
310  }
311 
312  namespace Skeleton
313  {
314  const uint32_t ChunkFileHeader::CurrentVersion = 1080; // Major * 1000 + Minor
315  const std::map<std::string, uint32_t> ChunkFileHeader::VersionTable = {
316  // 1.80: Current version
317  std::make_pair("[Serializer_v1.80]", CurrentVersion),
318  // 1.10: adds SKELETON_BLENDMODE and SKELETON_ANIMATION_BASEINFO chunks. The chunks have been added to the loader, but we ignore them for now.
319  std::make_pair("[Serializer_v1.10]", 1010)
320  };
321 
322  std::unique_ptr<Chunk> Chunk::Read(DataStream *stream)
323  {
324  assert(stream->GetRemainingBytes() >= ChunkHeaderLength);
325 
326  // Read metadata
327  ChunkID id = CID_Invalid;
328  id = static_cast<ChunkID>(stream->Read<uint16_t>());
329  size_t size = 0;
330  // Special case: CID_Header doesn't have any size info.
331  if (id != CID_Header)
332  {
333  // All others are proper chunks.
334  size = stream->Read<uint32_t>();
336  }
337 
338  // Create chunk
339  std::unique_ptr<Chunk> chunk;
340  switch (id)
341  {
342  case CID_Header: chunk = std::make_unique<Ogre::Skeleton::ChunkFileHeader>(); break;
343  case CID_BlendMode: chunk = std::make_unique<Ogre::Skeleton::ChunkBlendMode>(); break;
344  case CID_Bone: chunk = std::make_unique<Ogre::Skeleton::ChunkBone>(); break;
345  case CID_Bone_Parent: chunk = std::make_unique<Ogre::Skeleton::ChunkBoneParent>(); break;
346  case CID_Animation: chunk = std::make_unique<Ogre::Skeleton::ChunkAnimation>(); break;
347  case CID_Animation_BaseInfo: chunk = std::make_unique<Ogre::Skeleton::ChunkAnimationBaseInfo>(); break;
348  case CID_Animation_Track: chunk = std::make_unique<Ogre::Skeleton::ChunkAnimationTrack>(); break;
349  case CID_Animation_Track_KF: chunk = std::make_unique<Ogre::Skeleton::ChunkAnimationTrackKF>(); break;
350  case CID_Animation_Link: chunk = std::make_unique<Ogre::Skeleton::ChunkAnimationLink>(); break;
351  default:
352  LogF("StdMeshLoader: I don't know what to do with a chunk of type 0x%xu", id);
353  chunk = std::make_unique<Ogre::Skeleton::ChunkUnknown>(); break;
354  };
355  chunk->type = id;
356  chunk->size = size;
357  chunk->ReadImpl(stream);
358  return chunk;
359  }
360 
361  void ChunkUnknown::ReadImpl(DataStream *stream) { stream->Seek(GetSize()); }
362 
364  {
365  // Simple version check
366  VersionTable_t::const_iterator it = VersionTable.find(stream->Read<std::string>());
367  if (it == VersionTable.end())
368  throw InvalidVersion();
369  }
370 
372  {
373  blend_mode = stream->Read<uint16_t>();
374  }
375 
377  {
378  name = stream->Read<std::string>();
379  handle = stream->Read<uint16_t>();
380  position.x = stream->Read<float>();
381  position.y = stream->Read<float>();
382  position.z = stream->Read<float>();
383  orientation.x = stream->Read<float>();
384  orientation.y = stream->Read<float>();
385  orientation.z = stream->Read<float>();
386  orientation.w = stream->Read<float>();
387  // Guess whether we have a scale element
388  if (GetSize() > name.size() + 1 + sizeof(handle) + sizeof(float) * 7)
389  {
390  scale.x = stream->Read<float>();
391  scale.y = stream->Read<float>();
392  scale.z = stream->Read<float>();
393  }
394  else
395  {
397  }
398  }
399 
401  {
402  childHandle = stream->Read<uint16_t>();
403  parentHandle = stream->Read<uint16_t>();
404  }
405 
407  {
408  name = stream->Read<std::string>();
409  duration = stream->Read<float>();
410 
411  if(!stream->AtEof() && Chunk::Peek(stream) == CID_Animation_BaseInfo)
412  {
413  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
414  assert(chunk->GetType() == CID_Animation_BaseInfo);
415  // TODO: Handle it
416  LogF("StdMeshLoader: CID_Animation_BaseInfo not implemented. Skeleton might not be imported properly.");
417  }
418 
419  while (!stream->AtEof() && Chunk::Peek(stream) == CID_Animation_Track)
420  {
421  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
422  assert(chunk->GetType() == CID_Animation_Track);
423  tracks.push_back(static_unique_cast<ChunkAnimationTrack>(move(chunk)));
424  }
425  }
426 
428  {
429  base_animation_name = stream->Read<std::string>();
430  base_key_frame_time = stream->Read<float>();
431  }
432 
434  {
435  bone = stream->Read<uint16_t>();
436  while (Chunk::Peek(stream) == CID_Animation_Track_KF)
437  {
438  std::unique_ptr<Chunk> chunk = Chunk::Read(stream);
439  assert(chunk->GetType() == CID_Animation_Track_KF);
440  keyframes.push_back(static_unique_cast<ChunkAnimationTrackKF>(move(chunk)));
441  if (stream->AtEof()) break;
442  }
443  }
444 
446  {
447  time = stream->Read<float>();
448  rotation.x = stream->Read<float>();
449  rotation.y = stream->Read<float>();
450  rotation.z = stream->Read<float>();
451  rotation.w = stream->Read<float>();
452  translation.x = stream->Read<float>();
453  translation.y = stream->Read<float>();
454  translation.z = stream->Read<float>();
455  // Guess whether we have a scale element
456  if (GetSize() > sizeof(float) * 8)
457  {
458  scale.x = stream->Read<float>();
459  scale.y = stream->Read<float>();
460  scale.z = stream->Read<float>();
461  }
462  else
463  {
465  }
466  }
467 
469  {
470  file = stream->Read<std::string>();
471  scale.x = stream->Read<float>();
472  scale.y = stream->Read<float>();
473  scale.z = stream->Read<float>();
474  }
475  }
476 }
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
std::unique_ptr< To > static_unique_cast(From &&p)
static Type Peek(const DataStream *stream)
size_t GetRemainingBytes() const
void Seek(ptrdiff_t offset)
void ReadImpl(DataStream *stream) override
unique_ptr_vector< ChunkGeometryVertexDeclElement > vertexDeclaration
void ReadImpl(DataStream *stream) override
unique_ptr_vector< ChunkGeometryVertexBuffer > vertexBuffers
void ReadImpl(DataStream *stream) override
std::unique_ptr< ChunkGeometryVertexData > data
void ReadImpl(DataStream *stream) override
enum Ogre::Mesh::ChunkGeometryVertexDeclElement::Semantic semantic
enum Ogre::Mesh::ChunkGeometryVertexDeclElement::Type type
void ReadImpl(DataStream *stream) override
unique_ptr_vector< ChunkGeometryVertexDeclElement > declaration
static std::unique_ptr< Chunk > Read(DataStream *stream)
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
std::unique_ptr< ChunkGeometry > geometry
std::vector< BoneAssignment > boneAssignments
unique_ptr_vector< ChunkSubmesh > submeshes
std::vector< size_t > faceVertices
std::unique_ptr< ChunkGeometry > geometry
enum Ogre::Mesh::ChunkSubmesh::SubmeshOperation SO_TriList
std::vector< BoneAssignment > boneAssignments
void ReadImpl(DataStream *stream) override
ChunkSubmesh::SubmeshOperation operation
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
unique_ptr_vector< ChunkAnimationTrack > tracks
void ReadImpl(DataStream *stream) override
unique_ptr_vector< ChunkAnimationTrackKF > keyframes
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
void ReadImpl(DataStream *stream) override
static std::unique_ptr< Chunk > Read(DataStream *stream)
void ReadImpl(DataStream *stream) override
float y2
Definition: StdMesh.h:147
float z1
Definition: StdMesh.h:146
float z2
Definition: StdMesh.h:147
float x2
Definition: StdMesh.h:147
float y1
Definition: StdMesh.h:146
float x1
Definition: StdMesh.h:146
static StdMeshVector UnitScale()
Definition: StdMeshMath.cpp:29