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