Cafu Engine
Loader_mdl_hl2_anim.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_HL2_MDL_ANIM_DATA_HPP_INCLUDED
8 #define CAFU_HL2_MDL_ANIM_DATA_HPP_INCLUDED
9 
10 #include "Math3D/Vector3.hpp"
11 #include "Templates/Array.hpp"
12 
13 #if defined(_WIN32) && _MSC_VER<1600
14 #include "pstdint.h" // Paul Hsieh's portable implementation of the stdint.h header.
15 #else
16 #include <stdint.h>
17 #endif
18 
19 
20 namespace HL2mdl
21 {
22  // animation frames
24  {
25  struct
26  {
27  uint8_t valid;
28  uint8_t total;
29  } num;
30 
31  short value;
32  };
33 
34 
36  {
37  short offset[3];
38 
39  StudioAnim_ValueT* pAnimvalue(uint32_t i) const { if (offset[i] > 0) return (StudioAnim_ValueT *)(((uint8_t*)this) + offset[i]); else return NULL; }
40  };
41 
42 
43  // possible combinations, all components optional:
44  // ANIMROT, ANIMPOS
45  // RAWROT, RAWPOS
46  // RAWROT2, RAWPOS
47  #define STUDIO_ANIM_RAWPOS 0x01 // Vector48
48  #define STUDIO_ANIM_RAWROT 0x02 // Quaternion48
49  #define STUDIO_ANIM_ANIMPOS 0x04 // StudioAnim_ValuePointerT
50  #define STUDIO_ANIM_ANIMROT 0x08 // StudioAnim_ValuePointerT
51  #define STUDIO_ANIM_DELTA 0x10
52  #define STUDIO_ANIM_RAWROT2 0x20 // Quaternion64
53 
54 
56  {
57  public:
58 
59  Quaternion64();
60 
61  operator Quaternion() const
62  {
63  Quaternion tmp;
64 
65  // shift to -1048576, + 1048575, then round down slightly to -1.0 < x < 1.0
66  tmp.x = ((int)x - 1048576) * (1 / 1048576.5f);
67  tmp.y = ((int)y - 1048576) * (1 / 1048576.5f);
68  tmp.z = ((int)z - 1048576) * (1 / 1048576.5f);
69  tmp.w = sqrt( 1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z );
70 
71  if (wneg)
72  tmp.w = -tmp.w;
73 
74  return tmp;
75  }
76 
77 
78  private:
79 
80  uint64 x:21;
81  uint64 y:21;
82  uint64 z:21;
83  uint64 wneg:1;
84  };
85 
86 
87  // per bone per animation DOF and weight pointers
88  struct StudioAnimT
89  {
90  uint8_t Bone; ///< 255 means "no animation data".
91  uint8_t Flags; // weighing options
92  uint16_t NextOffset; ///< see GetNext()
93 
94 
95  public:
96 
97  // valid for animating data only
98  const StudioAnim_ValuePointerT* GetPosValues() const { assert(Flags & STUDIO_ANIM_ANIMPOS); return (const StudioAnim_ValuePointerT*)(GetData()) + ((Flags & STUDIO_ANIM_ANIMROT) != 0); }
99  const StudioAnim_ValuePointerT* GetRotValues() const { assert(Flags & STUDIO_ANIM_ANIMROT); return (const StudioAnim_ValuePointerT*)(GetData()); }
100 
101  uint8_t *pData() const { return (((uint8_t*)this) + sizeof(StudioAnimT)); }
102  StudioAnim_ValuePointerT* pRotV() const { return (StudioAnim_ValuePointerT*)(pData()); }
103  StudioAnim_ValuePointerT* pPosV() const { return (StudioAnim_ValuePointerT*)(pData()) + ((Flags & STUDIO_ANIM_ANIMROT) != 0); }
104 
105  // valid if animation unvaring over timeline
106 // const Quaternion48* GetQuat48() const { return (Quaternion48*)(GetData()); };
107  const Quaternion64* GetQuat64() const { return (Quaternion64*)(GetData()); };
108 // const Vector48* GetPos48() const
109 // {
110 // return (Vector48*)( GetData() + ((Flags & STUDIO_ANIM_RAWROT) != 0) * sizeof(*pQuat48()) + ((Flags & STUDIO_ANIM_RAWROT2) != 0) * sizeof(*pQuat64()) );
111 // };
112 #if 0
113  Quaternion48 *pQuat48() const { return (Quaternion48 *)(pData()); };
114  Quaternion64 *pQuat64() const { return (Quaternion64 *)(pData()); };
115  Vector48 *pPos() const { return (Vector48 *)(pData() + ((flags & STUDIO_ANIM_RAWROT) != 0) * sizeof( *pQuat48() ) + ((flags & STUDIO_ANIM_RAWROT2) != 0) * sizeof( *pQuat64() ) ); };
116 #endif
117 
118  const StudioAnimT* GetNext() const { if (NextOffset != 0) return (StudioAnimT*)(((uint8_t*)this) + NextOffset); else return NULL; }
119 
120  std::ostream& print(std::ostream& os, const char* indent) const;
121 
122 
123  private:
124 
125  const uint8_t* GetData() const { return ((uint8_t*)this) + sizeof(StudioAnimT); }
126  };
127 
128 
130  {
131  uint32_t AnimBlock;
132  uint32_t AnimOffset;
133  };
134 
135 
137  {
138  int32_t HeaderOffset; ///< A negative number that is the offset back to the StudioHeaderT.
139  uint32_t NameOffset;
140  float FPS; // frames per second
141  uint32_t Flags; // looping/non-looping flags
142  uint32_t NumFrames;
143 
144  uint32_t NumMovements; // piecewise movement
145  uint32_t MovementOffset;
146 
147  uint32_t Unused[6]; // remove as appropriate (and zero if loading older versions)
148 
149  uint32_t AnimBlock; ///< AnimBlocks are used for piecewise loading of animation data.
150  uint32_t AnimIndex; ///< If zero, then anim data is kept in sections, see below.
151 
152  uint32_t NumIkRules;
153  uint32_t IkRuleIndex; // non-zero when IK data is stored in the mdl
154  uint32_t AnimBlockIkRuleIndex; // non-zero when IK data is stored in animblock file
155 
156  uint32_t NumLocalHierarchy;
157  uint32_t LocalHierarchyIndex;
158 
159  uint32_t SectionIndex; ///< If zero, then anim data is kept directly at AnimIndex, see above.
160  uint32_t SectionFrames; ///< Number of frames used in each fast lookup section.
161 
162  uint16_t ZeroFrameSpan; // frames per span
163  uint16_t ZeroFrameCount; // Number of spans
164  uint32_t ZeroFrameIndex;
165  float ZeroFrameStallTime; // mutable, saved during read stalls
166 
167 
168  public:
169 
170  const StudioHeaderT* GetStudioHeader() const { return (StudioHeaderT*)(((uint8_t*)this) + HeaderOffset); }
171  const char* GetName() const { return ((char*)this) + NameOffset; }
172 
173 // const mstudiomovement_t* pMovement( int i ) const { return (mstudiomovement_t *)(((uint8_t*)this) + MovementOffset) + i; };
174 
175  // Should probably be just named "GetAnim()".
176  const StudioAnimT* GetAnimBlock() const ///< A custom, minimal variant of pAnimBlock(int block, int Index) below.
177  {
178  assert(AnimBlock == 0);
179  return (StudioAnimT*)(((uint8_t*)this) + AnimIndex);
180  }
181 
182  StudioAnimT* pAnimBlock(int block, int Index) const; // returns pointer to a specific anim block (local or external)
183  StudioAnimT* pAnim( int *piFrame, float &flStall ) const; // returns pointer to data and new frame index
184  StudioAnimT* pAnim( int *piFrame ) const; // returns pointer to data and new frame index
185 
186  const StudioAnimSectionsT* GetSections() const { return (StudioAnimSectionsT*)(((uint8_t*)this) + SectionIndex); }
187 
188 #if 0
189  mstudioikrule_t *pIKRule( int i ) const;
190  mstudiolocalhierarchy_t *pHierarchy( int i ) const;
191  uint8_t* pZeroFrameData() const { if (ZeroFrameIndex) return (((uint8_t*)this) + ZeroFrameIndex); else return NULL; }
192 #endif
193 
194  std::ostream& print(std::ostream& os, const char* indent) const;
195  };
196 
197 
199  {
200  float cycle;
201  uint32_t event;
202  uint32_t type;
203  const char * pszOptions() const { return options; }
204  char options[64];
205 
206  uint32_t szeventindex;
207  char * const pszEventName() const { return ((char *)this) + szeventindex; }
208  };
209 
210 
212  {
213  uint16_t Sequence;
214  uint16_t Pose;
215 
216  uint32_t Flags;
217  float Start; // Beginning of influence.
218  float Peak; // Start of full influence.
219  float Tail; // End of full influence.
220  float End; // End of all influence.
221  };
222 
223 
224  /**
225  * Sequences seem to be groups of animations that are supposed to be used together.
226  *
227  * For example, a sequence labelled "head_rot_x" might refer to animations
228  * "a_head_rot_left", "a_head_rot", "a_head_rot_right". Other sequences "head_rot_y"
229  * and "head_rot_z" might use different begin and end animations but share the animation
230  * in the middle, for example: "a_head_rot_up", "a_head_rot", "a_head_rot_down".
231  */
233  {
234  int HeaderOffset; ///< A negative number that is the offset back to the StudioHeaderT.
235  uint32_t LabelOffset;
236  uint32_t ActivityNameOffset;
237  uint32_t Flags; // looping/non-looping flags
238 
239  int32_t Activity; // initialized at loadtime to game DLL values
240  uint32_t ActWeight;
241 
242  uint32_t NumEvents; ///< see pEvent()
243  uint32_t EventOffset;
244 
245  Vector3fT BBMin; // per sequence bounding box
246  Vector3fT BBMax;
247 
248  /// Afaics, we always have `NumBlends == GroupSize[0] * GroupSize[1]` (with `GroupSize[1] == 1`).
249  /// A "blend" seems to address an animation (StudioAnimDescT) that is supposed to be (randomly?
250  /// sequentially?) blended with other animations in the same group.
251  uint32_t NumBlends; ///< See GetAnim() for further details.
252  uint32_t AnimIndexOffset; ///< See `NumBlends` and GetAnim() for details.
253 
254  uint32_t MovementOffset; // [blend] float array for blended movement
255  uint32_t GroupSize[2]; ///< Among other code, GetAnim() refers to these values.
256  int32_t ParamIndex[2]; // X, Y, Z, XR, YR, ZR
257  float ParamStart[2]; // local (0..1) starting value
258  float ParamEnd[2]; // local (0..1) ending value
259  uint32_t ParamParent;
260 
261  float FadeInTime; // ideal cross fate in time (0.2 default)
262  float FadeOutTime; // ideal cross fade out time (0.2 default)
263 
264  uint32_t LocalEntryNode; // transition node at entry
265  uint32_t LocalExitNode; // transition node at exit
266  uint32_t NodeFlags; // transition rules
267 
268  float EntryPhase; // used to match entry gait
269  float ExitPhase; // used to match exit gait
270 
271  float LastFrame; // frame that should generation EndOfSequence
272  uint32_t NextSequ; // auto advancing sequences
273  uint32_t Pose; // Index of delta animation between end and nextseq
274  uint32_t NumIKRules;
275 
276  uint32_t NumAutoLayers;
277  uint32_t AutoLayerOffset; ///< see pAutoLayer()
278 
279  uint32_t WeightListOffset; ///< see GetWeight()
280  uint32_t PoseKeyOffset; ///< see GetPoseKey()
281 
282  uint32_t NumIKLocks; ///< see pIKLock()
283  uint32_t IKLockOffset;
284 
285  uint32_t KeyValueOffset; ///< see KeyValueText()
286  uint32_t KeyValueSize;
287 
288  uint32_t CyclePoseIndex; // Index of pose parameter to use as cycle index
289  uint32_t Unused[7];
290 
291 
292  public:
293 
294  const StudioHeaderT* GetStudioHeader() const { return (StudioHeaderT*)(((uint8_t*)this) + HeaderOffset); }
295  const char* GetLabel() const { return ((char *)this) + LabelOffset; }
296  const char* GetActivityName() const { return ((char *)this) + ActivityNameOffset; }
297 
298  const StudioEventT* pEvent(uint32_t i) const { assert(i < NumEvents); return (StudioEventT*)(((uint8_t*)this) + EventOffset) + i; }
299 
300  /// Afaics, we always have `GroupSize[0] * GroupSize[1]` (with `GroupSize[1] == 1`)
301  /// animations (StudioAnimDescT) that are supposed to be (randomly? sequentially?)
302  /// blended with other animations in the same group.
303  /// For example, a StudioSequDescT labelled "shiftweight_x" may refer to StudioAnimDescT%s
304  /// "23: shiftweight_left", "25: @shiftweight_x" and "24: shiftweight_right".
305  ///
306  /// @return The returned value is supposed to be used with StudioHeaderT::GetAnimDesc(), e.g.
307  /// const StudioAnimDescT* AnimDesc = StudioHeader->GetAnimDesc(GetAnim(x, y));
308  uint16_t GetAnim(uint32_t x, uint32_t y) const
309  {
310  if (x >= GroupSize[0]) x = GroupSize[0] - 1;
311  if (y >= GroupSize[1]) y = GroupSize[1] - 1;
312 
313  // AnimIndexOffset is an index into an array of uint16_t which is GroupSize[0] * GroupSize[1] in size.
314  const uint16_t* blends = (uint16_t*)(((uint8_t*)this) + AnimIndexOffset);
315 
316  return blends[y*GroupSize[0] + x];
317  }
318 
319  const StudioAutoLayerT* pAutoLayer(uint32_t i) const { assert(i < NumAutoLayers); return (StudioAutoLayerT*)(((uint8_t*)this) + AutoLayerOffset) + i; }
320 
321  const float* pBoneweight(uint32_t i) const { return ((float*)(((uint8_t*)this) + WeightListOffset) + i); }
322  const float GetWeight(uint32_t i) const { return *(pBoneweight(i)); }
323 
324  const float* pPoseKey(uint32_t iParam, int iAnim ) const { return (float *)(((uint8_t*)this) + PoseKeyOffset) + iParam * GroupSize[0] + iAnim; }
325  const float GetPoseKey(uint32_t iParam, int iAnim ) const { return *(pPoseKey( iParam, iAnim )); }
326 
327 #if 0
328  const mstudioiklock_t* pIKLock(uint32_t i) const { assert(i >= 0 && i < NumIKLocks); return (mstudioiklock_t*)(((uint8_t*)this) + IKLockOffset) + i; }
329 #endif
330  const char* KeyValueText() const { return KeyValueSize != 0 ? ((char*)this) + KeyValueOffset : NULL; }
331 
332  std::ostream& print(std::ostream& os, const char* indent) const;
333  };
334 }
335 
336 #endif
int HeaderOffset
A negative number that is the offset back to the StudioHeaderT.
Definition: Loader_mdl_hl2_anim.hpp:234
This is the header of an MDL model file.
Definition: Loader_mdl_hl2_mdl.hpp:231
uint16_t NextOffset
see GetNext()
Definition: Loader_mdl_hl2_anim.hpp:92
uint32_t WeightListOffset
see GetWeight()
Definition: Loader_mdl_hl2_anim.hpp:279
uint32_t KeyValueOffset
see KeyValueText()
Definition: Loader_mdl_hl2_anim.hpp:285
uint16_t GetAnim(uint32_t x, uint32_t y) const
Afaics, we always have GroupSize[0] * GroupSize[1] (with GroupSize[1] == 1) animations (StudioAnimDes...
Definition: Loader_mdl_hl2_anim.hpp:308
Definition: Loader_mdl_hl2_anim.hpp:198
uint32_t NumBlends
Afaics, we always have NumBlends == GroupSize[0] * GroupSize[1] (with GroupSize[1] == 1)...
Definition: Loader_mdl_hl2_anim.hpp:251
Definition: Loader_mdl_hl2_anim.hpp:35
uint32_t AnimIndex
If zero, then anim data is kept in sections, see below.
Definition: Loader_mdl_hl2_anim.hpp:150
Definition: Loader_mdl_hl2_anim.hpp:55
int32_t HeaderOffset
A negative number that is the offset back to the StudioHeaderT.
Definition: Loader_mdl_hl2_anim.hpp:138
Sequences seem to be groups of animations that are supposed to be used together.
Definition: Loader_mdl_hl2_anim.hpp:232
Definition: Loader_mdl_hl2_anim.hpp:136
uint32_t GroupSize[2]
Among other code, GetAnim() refers to these values.
Definition: Loader_mdl_hl2_anim.hpp:255
uint32_t AnimIndexOffset
See NumBlends and GetAnim() for details.
Definition: Loader_mdl_hl2_anim.hpp:252
const StudioAnimT * GetAnimBlock() const
< A custom, minimal variant of pAnimBlock(int block, int Index) below.
Definition: Loader_mdl_hl2_anim.hpp:176
uint32_t NumIKLocks
see pIKLock()
Definition: Loader_mdl_hl2_anim.hpp:282
uint32_t SectionIndex
If zero, then anim data is kept directly at AnimIndex, see above.
Definition: Loader_mdl_hl2_anim.hpp:159
uint32_t AutoLayerOffset
see pAutoLayer()
Definition: Loader_mdl_hl2_anim.hpp:277
Definition: Loader_mdl_hl2_anim.hpp:88
uint32_t NumEvents
see pEvent()
Definition: Loader_mdl_hl2_anim.hpp:242
uint32_t AnimBlock
AnimBlocks are used for piecewise loading of animation data.
Definition: Loader_mdl_hl2_anim.hpp:149
uint32_t PoseKeyOffset
see GetPoseKey()
Definition: Loader_mdl_hl2_anim.hpp:280
uint8_t Bone
255 means "no animation data".
Definition: Loader_mdl_hl2_anim.hpp:90
Definition: Loader_mdl_hl2_anim.hpp:211
Definition: Loader_mdl_hl2_anim.hpp:129
Definition: Loader_mdl_hl1.h:215
Definition: Loader_mdl_hl2_anim.hpp:23
uint32_t SectionFrames
Number of frames used in each fast lookup section.
Definition: Loader_mdl_hl2_anim.hpp:160