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 #ifndef INC_StdMeshLoaderChunks
17 #define INC_StdMeshLoaderChunks
18 
19 #include "lib/StdMesh.h"
20 #include "lib/StdMeshLoaderDataStream.h"
21 
22 // ==== Ogre file format ====
23 // The Ogre file format is a chunked format similar to PNG.
24 // Each chunk except for the file header (type 0x1000) has the following format:
25 //  uint32_t chunk_type, values dependent on file type (mesh or skeleton)
26 //  uint32_t chunk_length, in bytes; includes the size of the header
27 //  uint8_t data[]
28 // The file header omits the length field.
29 // Ogre files can be stored in either big-endian or little-endian byte order. The
30 // byte order is determined by the first two bytes in the file, which must always
31 // be the chunk type of the file header (0x1000). If the bytes are 0x00 0x10, the
32 // file is assumed to be little-endian, if they are 0x10 0x00, the file is big-
33 // endian. If any other bytes are encountered, the file is invalid.
34 // This implementation only reads files stored in the platform's native byte order.
35 //
36 // ==== Data types ====
37 // Most of the numeric data is stored directly in binary as a memory representation.
38 // Strings are stored without a leading length field, and terminated by a 0x0A byte.
39 // Boolean fields are stored as a single byte, which is 0x00 for false or anything
40 // else for true.
41 //
42 // ==== Mesh chunks ====
43 // Unless specified, this section will only describe the data part of each chunk.
44 // Any values that are in parentheses are not available in this implementation.
45 //
46 // Type 0x1000: File Header
47 //  string version
48 //    Depending on the version, different features are enabled or disabled while
49 //    loading the file.
50 //    This implementation does not support fallback to different versions of the
51 //    file format.
52 //  This chunk does not contain a length field; the type id is directly followed
53 //  by the version string.
54 //  The file header must be immediately followed by a 0x3000 Mesh Data chunk.
55 // ----------
56 // Type 0x3000: Mesh Data
57 //  bool skeletal_animation
58 //    This field is only used by Ogre to optimize rendering. Set if the mesh has
59 //    animation data associated with it.
60 //  Allowed subchunks:
61 //    0x4000 Submesh Data
62 //    0x5000 Geometry Data (may occur at most once)
63 //    0x6000 Skeleton Link (may occur at most once)
64 //    0x7000 Mesh Bone Assignments
65 //    (0x8000 Precomputed Level of Detail Data)
66 //    0x9000 Mesh Boundaries
67 //    (0xA000 Submesh Name Table)
68 //    (0xB000 Edge List)
69 //    (0xC000 Animation Poses)
70 //    (0xD000 Animation List)
71 //    (0xE000 Table of Extremes)
72 // ----------
73 // Type 0x4000: Submesh data
74 //  string material
75 //    The name of a material to be used for this submesh. Must be loaded externally.
76 //  bool vertices_shared
77 //    If set, the submesh uses the geometry data of its parent mesh. In this case, the
78 //    submesh may not contain its own 0x5000 Geometry Data chunk.
79 //  uint32_t index_count
80 //    The number of vertex indices used by this submesh.
81 //  bool indices_are_32_bit
82 //    If set, each vertex index is 32 bits wide. If unset, each vertex index is 16 bits
83 //    wide.
84 //  uint16_t/uint32_t indices[index_count]
85 //    A list of vertex indices used by this submesh.
86 //  Allowed subchunks:
87 //    0x5000 Geometry Data (only if vertices_shared == false)
88 //    0x4010 Submesh Operation
89 //    0x4100 Submesh Bone Assignments
90 //    (0x4200 Submesh Texture Replacement)
91 //  If no 0x4010 Submesh Operation chunk is present, the submesh uses SO_TriList.
92 // ----------
93 // Type 0x4010: Submesh Operation
94 //  uint16_t operation
95 //    This value specifies how the indices of a submesh are to be interpreted.
96 //    Acceptable values:
97 //      (0x01 SO_PointList)
98 //        Each index defines a single point.
99 //      (0x02 SO_LineList)
100 //        Each pair (2k, 2k+1) of indices defines a line.
101 //      (0x03 SO_LineStrip)
102 //        Each pair (k, k+1) of indices defines a line.
103 //      0x04 SO_TriList
104 //        Each triplet (3k, 3k+1, 3k+2) of indices defines a triangle.
105 //      (0x05 SO_TriStrip)
106 //        For odd k, (k, k+1, k+2) define a triangle. For even k, (k+1, k, k+2) define a triangle.
107 //      (0x06 SO_TriFan)
108 //        Indices (1, k+1, k+2) define a triangle.
109 // ----------
110 // Type 0x4100: Submesh Bone Assignments
111 // Type 0x7000: Mesh Bone Assignments
112 //  uint32_t vertex_index
113 //  uint32_t bone_index
114 //  float weight
115 //    This defines the strength of the influence a bone has on a vertex. The sum of
116 //    the weights on each vertex is not guaranteed to be 1.0.
117 //  These values repeat until the size of the chunk is exhausted.
118 // ----------
119 // Type 0x5000: Geometry Data
120 //  uint32_t vertex_count
121 //    The number of vertices stored in each contained 0x5020 Vertex Buffer chunk.
122 //  Allowed subchunks:
123 //    0x5100 Vertex Declaration (required; must occur exactly once)
124 //    0x5200 Vertex Buffer (required; must occur at least once)
125 // ----------
126 // Type 0x5100 Vertex Declaration
127 //  This chunk does not store any values itself. It only acts as a container for
128 //  0x5110 Vertex Declaration Element chunks.
129 //  Allowed subchunks:
130 //    0x5110 Vertex Declaration Element (required; repeats until the size of the chunk is exhausted)
131 // ----------
132 // Type 0x5110 Vertex Declaration Element
133 //  uint16_t source
134 //    The index of the stream where this element is found.
135 //  uint16_t type
136 //    The type of data this element contains.
137 //    Acceptable values:
138 //      0x00 VDET_Float1
139 //        A single 32-bit float, expanded to (a, 0, 0, 1)
140 //      0x01 VDET_Float2
141 //        Two 32-bit floats, expanded to (a, b, 0, 1)
142 //      0x02 VDET_Float3
143 //        Three 32-bit floats, expanded to (a, b, c, 1)
144 //      0x03 VDET_Float4
145 //        Four 32-bit floats
146 //      (0x04 VDET_Reserved)
147 //      (0x05 VDET_Short1)
148 //        A single 16-bit integer
149 //      (0x06 VDET_Short2)
150 //        Two 16-bit integers
151 //      (0x07 VDET_Short3)
152 //        Three 16-bit integers
153 //      (0x08 VDET_Short4)
154 //        Four 16-bit integers
155 //      (0x09 VDET_UByte4)
156 //        Four 8-bit integers
157 //      0x0A VDET_Color_ARGB
158 //        Four 8-bit integers, describing a color in the order Alpha, Red, Green, Blue.
159 //        Acceptable values range from 0 to 255.
160 //      0x0B VDET_Color_ABGR
161 //        Four 8-bit integers, describing a color in the order Alpha, Blue, Green, Red.
162 //        Acceptable values range from 0 to 255.
163 //  uint16_t semantic
164 //    The semantic of the data this element contains.
165 //    Acceptable values:
166 //      0x01 VDES_Position
167 //        The element contains the vertex's position in world space.
168 //      (0x02 VDES_Blend_Weights)
169 //      (0x03 VDES_Blend_Indices)
170 //      0x04 VDES_Normals
171 //        The element contains vertex normals.
172 //      (0x05 VDES_Diffuse)
173 //        The element contains the diffuse color of the vertex.
174 //      (0x06 VDES_Specular)
175 //        The element contains the specular color of the vertex.
176 //      0x07 VDES_Texcoords
177 //        The element contains the texture coordinates of the vertex.
178 //  uint16_t offset
179 //    The element's offset in bytes from the beginning of the stream.
180 //  uint16_t index
181 //    Index of the element semantic. Used with colors and texture coordinates.
182 // ----------
183 // 0x5200 Vertex Buffer
184 //  uint16_t index
185 //    The index of the stream this buffer will get bound to.
186 //  uint16_t stride
187 //    The distance in bytes between two elements inside the buffer.
188 //  Allowed subchunks:
189 //    0x5210 Vertex Buffer Data (required; must occur exactly once)
190 // ----------
191 // 0x5210 Vertex Buffer Data
192 //  uint8_t data[]
193 //    The buffered data. This field spans the whole extent of the chunk.
194 // ----------
195 // 0x6000 Skeleton Link
196 //  string file
197 //    The name of the file that contains the skeleton of this mesh.
198 // ----------
199 // 0x9000 Mesh Boundaries
200 //  float min[3]
201 //    The minimum extents of the axis-aligned bounding box of the mesh.
202 //  float max[3]
203 //    The maximum extents of the axis-aligned bounding box of the mesh.
204 //  float radius
205 //    The radius of the minimal enclosing sphere of the mesh.
206 //
207 // ==== Skeleton files ====
208 // Each skeleton file must begin with a 0x1000 File Header chunk. Afterwards,
209 // any combination of the following chunks may appear:
210 //  0x2000 Bone Data
211 //  0x3000 Bone Hierarchy
212 //  0x4000 Animation
213 //  (0x5000 Animation Link)
214 //
215 // Unless specified, this section will only describe the data part of each chunk.
216 // Any values that are in parentheses are not available in this implementation.
217 //
218 // Type 0x1000: File Header
219 //  string version
220 //    Depending on the version, different features are enabled or disabled while
221 //    loading the file.
222 //    This implementation does not support fallback to different versions of the
223 //    file format.
224 //  This chunk does not contain a length field; the type id is directly followed
225 //  by the version string.
226 // ----------
227 // Type 0x2000: Bone Data
228 //  string name
229 //    The name of the bone. This is only used to produce human-readable output.
230 //  uint16_t handle
231 //    The internal handle of the bone. All other chunks that refer to a bone reference
232 //    this.
233 //  float position[3]
234 //    The position of the bone, relative to its parent.
235 //  float orientation[4]
236 //    The orientation of the bone, as a quaternion (x,y,z,w). Relative to the parent.
237 //  float scale[3]
238 //    The scale of the bone, relative to its parent. This element only appears if the
239 //    chunk size is large enough; if it is omitted, it defaults to (1,1,1).
240 // ----------
241 // Type 0x3000 Bone Hierarchy
242 //  uint16_t child
243 //    The handle of the parent bone.
244 //  uint16_t parent
245 //    The handle of the parent bone.
246 // ----------
247 // Type 0x4000 Animation
248 //  string name
249 //    The name of this animation.
250 //  float duration
251 //    The length of this animation, in seconds.
252 //  Allowed subchunks:
253 //    0x4100 Animation Track
254 // ----------
255 // Type 0x4100 Animation Track
256 //  uint16_t bone
257 //    The handle of the bone this track belongs to.
258 //  Allowed subchunks:
259 //    0x4110 Animation Track Keyframe
260 // ----------
261 // Type 0x4110 Animation Track Keyframe
262 //  float time
263 //    The time this keyframe matches.
264 //  float rotation[4]
265 //    The rotation of the bone at the corresponding time, as a quaternion (x,y,z,w).
266 //  float translation[3]
267 //    The translation of the bone at the corresponding time.
268 //  float scale[3]
269 //    The scale of the bone at the time of the keyframe. This element only appears if the
270 //    chunk size is large enough; if it is omitted, it defaults to (1,1,1).
271 
272 // Most of the chunk classes below faithfully match the abovementioned file format.
273 namespace Ogre
274 {
275 	// used to have boost::ptr_vector. Behaves reasonably similar
276 	template<typename T>
277 	using unique_ptr_vector = std::vector<std::unique_ptr<T>>;
278 
279 	class DataStream;
280 	template<class _Type>
281 	class ChunkBase
282 	{
283 	protected:
ChunkBase()284 		ChunkBase() : type(static_cast<Type>(0)) {}
285 		virtual void ReadImpl(DataStream *stream) = 0;
286 		typedef _Type Type;
287 		Type type;
288 		size_t size;
289 	public:
290 		virtual ~ChunkBase() = default;
GetType()291 		Type GetType() const { return type; }
GetSize()292 		size_t GetSize() const { return size; }
293 
294 		static const size_t ChunkHeaderLength = sizeof(uint16_t) /* chunk type */ + sizeof(uint32_t) /* chunk length */;
Peek(const DataStream * stream)295 		static Type Peek(const DataStream *stream)
296 		{
297 			return static_cast<Type>(stream->Peek<uint16_t>());
298 		}
299 	};
300 
301 	namespace Mesh
302 	{
303 		enum ChunkID
304 		{
305 			CID_Invalid = 0,
306 			CID_Header = 0x1000,
307 			CID_Mesh = 0x3000,
308 			CID_Submesh = 0x4000,
309 			CID_Submesh_Op = 0x4010,
310 			CID_Submesh_Bone_Assignment = 0x4100,
311 			CID_Submesh_Texture_Alias = 0x4200,
312 			CID_Geometry = 0x5000,
313 			CID_Geometry_Vertex_Decl = 0x5100,
314 			CID_Geometry_Vertex_Decl_Element = 0x5110,
315 			CID_Geometry_Vertex_Buffer = 0x5200,
316 			CID_Geometry_Vertex_Data = 0x5210,
317 			CID_Mesh_Skeleton_Link = 0x6000,
318 			CID_Mesh_Bone_Assignment = 0x7000,
319 			CID_Mesh_LOD = 0x8000,
320 			CID_Mesh_LOD_Usage = 0x8100,
321 			CID_Mesh_LOD_Manual = 0x8110,
322 			CID_Mesh_LOD_Generated = 0x8120,
323 			CID_Mesh_Bounds = 0x9000,
324 			CID_Submesh_Name_Table = 0xA000,
325 			CID_Submesh_Name_Table_Entry = 0xA100,
326 			CID_Edge_List = 0xB000,
327 			CID_Edge_List_LOD = 0xB100,
328 			CID_Edge_Group = 0xB110,
329 			CID_Pose_List = 0xC000,
330 			CID_Pose = 0xC100,
331 			CID_Pose_Vertex = 0xC111,
332 			CID_Animation_List = 0xD000,
333 			CID_Animation = 0xD100,
334 			CID_Animation_Track = 0xD110,
335 			CID_Animation_Morph_Keyframe = 0xD111,
336 			CID_Animation_Pose_Keyframe = 0xD112,
337 			CID_Animation_Pose_Ref = 0xD113,
338 			CID_Table_Extremes = 0xE000
339 		};
340 
341 		struct BoneAssignment
342 		{
343 			uint32_t vertex;
344 			uint32_t bone;
345 			float weight;
346 		};
347 
348 		class Chunk : public ChunkBase<ChunkID>
349 		{
350 		public:
351 			static std::unique_ptr<Chunk> Read(DataStream *stream);
352 		};
353 
354 		class ChunkUnknown; class
355 		ChunkFileHeader;
356 		class ChunkMesh; class ChunkMeshSkeletonLink; class ChunkMeshBoneAssignments; class ChunkMeshBounds;
357 		class ChunkSubmesh; class ChunkSubmeshOp;
358 		class ChunkGeometry; class ChunkGeometryVertexDecl; class ChunkGeometryVertexDeclElement; class ChunkGeometryVertexBuffer; class ChunkGeometryVertexData;
359 		class ChunkPoseList; class ChunkPose; class ChunkPoseVertex;
360 		class ChunkAnimationList; class ChunkAnimation; class ChunkAnimationTrack;
361 		class ChunkAnimationMorphKF; class ChunkAnimationPoseKF; class ChunkAnimationPoseRef;
362 
363 		class ChunkUnknown : public Chunk
364 		{
365 		protected:
366 			void ReadImpl(DataStream *stream) override;
367 		};
368 
369 		class ChunkFileHeader : public Chunk
370 		{
371 			typedef std::map<std::string, uint32_t> VersionTable_t;
372 			static const VersionTable_t VersionTable;
373 			static const uint32_t CurrentVersion;
374 		public:
375 			std::string version;
376 
377 		protected:
378 			void ReadImpl(DataStream *stream) override;
379 		};
380 
381 		class ChunkMesh : public Chunk
382 		{
383 		public:
384 			ChunkMesh() = default;
385 			bool hasAnimatedSkeleton{false};
386 			std::string skeletonFile;
387 			std::unique_ptr<ChunkGeometry> geometry;
388 			unique_ptr_vector<ChunkSubmesh> submeshes;
389 			std::vector<BoneAssignment> boneAssignments;
390 			StdMeshBox bounds;
391 			float radius{0.0f};
392 
393 		protected:
394 			void ReadImpl(DataStream *stream) override;
395 		};
396 
397 		class ChunkMeshSkeletonLink : public Chunk
398 		{
399 		public:
400 			std::string skeleton;
401 		protected:
402 			void ReadImpl(DataStream *stream) override;
403 		};
404 
405 		class ChunkSubmesh : public Chunk
406 		{
407 		public:
408 			ChunkSubmesh() = default;
409 			std::string material;
410 			bool hasSharedVertices;
411 			std::vector<size_t> faceVertices;
412 			std::unique_ptr<ChunkGeometry> geometry;
413 			enum SubmeshOperation
414 			{
415 				SO_PointList = 1,
416 				SO_LineList = 2,
417 				SO_LineStrip = 3,
418 				SO_TriList = 4,
419 				SO_TriStrip = 5,
420 				SO_TriFan = 6,
421 				SO_MIN = SO_PointList,
422 				SO_MAX = SO_TriFan
423 			} operation{SO_TriList};
424 			std::vector<BoneAssignment> boneAssignments;
425 		protected:
426 			void ReadImpl(DataStream *stream) override;
427 		};
428 
429 		class ChunkSubmeshOp : public Chunk
430 		{
431 		public:
432 			ChunkSubmesh::SubmeshOperation operation;
433 		protected:
434 			void ReadImpl(DataStream *stream) override;
435 		};
436 
437 		class ChunkMeshBoneAssignments : public Chunk
438 		{
439 		public:
440 			std::vector<BoneAssignment> assignments;
441 		protected:
442 			void ReadImpl(DataStream *stream) override;
443 		};
444 
445 		class ChunkMeshBounds : public Chunk
446 		{
447 		public:
448 			StdMeshBox bounds;
449 			float radius;
450 		protected:
451 			void ReadImpl(DataStream *stream) override;
452 		};
453 
454 		class ChunkGeometry : public Chunk
455 		{
456 		public:
457 			size_t vertexCount;
458 			unique_ptr_vector<ChunkGeometryVertexDeclElement> vertexDeclaration;
459 			unique_ptr_vector<ChunkGeometryVertexBuffer> vertexBuffers;
460 		protected:
461 			void ReadImpl(DataStream *stream) override;
462 		};
463 
464 		class ChunkGeometryVertexDecl : public Chunk
465 		{
466 		public:
467 			unique_ptr_vector<ChunkGeometryVertexDeclElement> declaration;
468 		protected:
469 			void ReadImpl(DataStream *stream) override;
470 		};
471 
472 		class ChunkGeometryVertexDeclElement : public Chunk
473 		{
474 		public:
475 			uint16_t source;
476 			uint16_t offset;
477 			enum Type
478 			{
479 				VDET_Float1 = 0,
480 				VDET_Float2 = 1,
481 				VDET_Float3 = 2,
482 				VDET_Float4 = 3,
483 				/* 4 omitted intentionally */
484 				VDET_Short1 = 5,
485 				VDET_Short2 = 6,
486 				VDET_Short3 = 7,
487 				VDET_Short4 = 8,
488 				VDET_UByte4 = 9,
489 				VDET_Color_ARGB = 10,
490 				VDET_Color_ABGR = 11,
491 				VDET_MIN = VDET_Float1,
492 				VDET_MAX = VDET_Color_ABGR
493 			} type;
494 			enum Semantic
495 			{
496 				VDES_Position = 1,
497 				VDES_Blend_Weights = 2,
498 				VDES_Blend_Indices = 3,
499 				VDES_Normals = 4,
500 				VDES_Diffuse = 5,
501 				VDES_Specular = 6,
502 				VDES_Texcoords = 7,
503 				VDES_Binormal = 8,
504 				VDES_Tangent = 9,
505 				VDES_MIN = VDES_Position,
506 				VDES_MAX = VDES_Tangent
507 			} semantic;
508 			uint16_t index;
509 		protected:
510 			void ReadImpl(DataStream *stream) override;
511 		};
512 
513 		class ChunkGeometryVertexBuffer : public Chunk
514 		{
515 		public:
516 			uint16_t index;
517 			uint16_t vertexSize;
518 			std::unique_ptr<ChunkGeometryVertexData> data;
519 		protected:
520 			void ReadImpl(DataStream *stream) override;
521 		};
522 
523 		class ChunkGeometryVertexData : public Chunk
524 		{
525 		public:
526 			ChunkGeometryVertexData() = default;
~ChunkGeometryVertexData()527 			~ChunkGeometryVertexData() override { delete[] static_cast<char*>(data); }
528 			void *data{nullptr};
529 		protected:
530 			void ReadImpl(DataStream *stream) override;
531 		};
532 	}
533 
534 	namespace Skeleton
535 	{
536 		enum ChunkID
537 		{
538 			CID_Invalid = 0,
539 			CID_Header = 0x1000,
540 			CID_BlendMode=  0x1010,
541 			CID_Bone = 0x2000,
542 			CID_Bone_Parent = 0x3000,
543 			CID_Animation = 0x4000,
544 			CID_Animation_BaseInfo = 0x4010,
545 			CID_Animation_Track = 0x4100,
546 			CID_Animation_Track_KF = 0x4110,
547 			CID_Animation_Link = 0x5000
548 		};
549 
550 		class Chunk : public ChunkBase<ChunkID>
551 		{
552 		public:
553 			static std::unique_ptr<Chunk> Read(DataStream *stream);
554 		};
555 
556 		class ChunkUnknown; class ChunkFileHeader;
557 		class ChunkBone; class ChunkBoneParent;
558 		class ChunkAnimation; class ChunkAnimationTrack; class ChunkAnimationTrackKF; class ChunkAnimationLink;
559 
560 		class ChunkUnknown : public Chunk
561 		{
562 		protected:
563 			void ReadImpl(DataStream *stream) override;
564 		};
565 
566 		class ChunkFileHeader : public Chunk
567 		{
568 			typedef std::map<std::string, uint32_t> VersionTable_t;
569 			static const VersionTable_t VersionTable;
570 			static const uint32_t CurrentVersion;
571 		public:
572 			std::string version;
573 
574 		protected:
575 			void ReadImpl(DataStream *stream) override;
576 		};
577 
578 		class ChunkBlendMode : public Chunk
579 		{
580 		public:
581 			uint16_t blend_mode;
582 		protected:
583 			void ReadImpl(DataStream* stream) override;
584 		};
585 
586 		class ChunkBone : public Chunk
587 		{
588 		public:
589 			std::string name;
590 			uint16_t handle;
591 
592 			StdMeshVector position;
593 			StdMeshQuaternion orientation;
594 			StdMeshVector scale;
595 		protected:
596 			void ReadImpl(DataStream *stream) override;
597 		};
598 
599 		class ChunkBoneParent : public Chunk
600 		{
601 		public:
602 			uint16_t childHandle;
603 			uint16_t parentHandle;
604 		protected:
605 			void ReadImpl(DataStream *stream) override;
606 		};
607 
608 		class ChunkAnimation : public Chunk
609 		{
610 		public:
611 			std::string name;
612 			float duration;
613 			unique_ptr_vector<ChunkAnimationTrack> tracks;
614 		protected:
615 			void ReadImpl(DataStream *stream) override;
616 		};
617 
618 		class ChunkAnimationBaseInfo : public Chunk
619 		{
620 		public:
621 			std::string base_animation_name;
622 			float base_key_frame_time;
623 		protected:
624 			void ReadImpl(DataStream* stream) override;
625 		};
626 
627 		class ChunkAnimationTrack : public Chunk
628 		{
629 		public:
630 			uint16_t bone;
631 			unique_ptr_vector<ChunkAnimationTrackKF> keyframes;
632 		protected:
633 			void ReadImpl(DataStream *stream) override;
634 		};
635 
636 		class ChunkAnimationTrackKF : public Chunk
637 		{
638 		public:
639 			float time;
640 			StdMeshQuaternion rotation;
641 			StdMeshVector translation;
642 			StdMeshVector scale;
643 		protected:
644 			void ReadImpl(DataStream *stream) override;
645 		};
646 
647 		class ChunkAnimationLink : public Chunk
648 		{
649 		public:
650 			std::string file;
651 			StdMeshVector scale;
652 		protected:
653 			void ReadImpl(DataStream *stream) override;
654 		};
655 	}
656 }
657 
658 #endif
659