Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SkeletalModel.cpp 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*!
  2. * \file src/SkeletalModel.cpp
  3. * \brief This is the factored out skeletal model class
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include <assert.h>
  9. #include "main.h"
  10. #include "SkeletalModel.h"
  11. BoneTag::BoneTag(TombRaider &tr, unsigned int index, int j, unsigned int *l) {
  12. tr2_moveable_t *moveable = mTombRaider.Moveable();
  13. tr2_meshtree_t *meshtree = mTombRaider.MeshTree();
  14. off[0] = 0.0;
  15. off[1] = 0.0;
  16. off[2] = 0.0;
  17. flag = 0x00;
  18. rot[0] = 0.0;
  19. rot[1] = 0.0;
  20. rot[2] = 0.0;
  21. mesh = moveable[index].starting_mesh + j;
  22. // Setup offsets to produce skeleton
  23. if (j == 0) {
  24. // Always push tag[0], this isn't really used either
  25. tag->flag = 0x02;
  26. } else { // Nonprimary tag - position relative to first tag
  27. // Hack: moveable[index].mesh_tree is a byte offset
  28. // into mesh_tree[], so we have to convert to index
  29. int *tree = (int *)(void *)meshtree;
  30. tr2_meshtree_t *mesh_tree = (tr2_meshtree_t *)(tree
  31. + moveable[index].mesh_tree + ((j - 1) * 4));
  32. off[0] = mesh_tree->x;
  33. off[1] = mesh_tree->y;
  34. off[2] = mesh_tree->z;
  35. flag = (char)mesh_tree->flags;
  36. }
  37. // Setup tag rotations
  38. tr.computeRotationAngles(&frame, &frame_offset, l, rot, rot+1, rot+2);
  39. }
  40. BoneFrame::BoneFrame(TombRaider &tr, unsigned int index, unsigned int i, unsigned int frame_offset) {
  41. tr2_moveable_t *moveable = mTombRaider.Moveable();
  42. unsigned short *frame = mTombRaider.Frame();
  43. pos[0] = (short)frame[frame_offset + 6];
  44. pos[1] = (short)frame[frame_offset + 7];
  45. pos[2] = (short)frame[frame_offset + 8];
  46. yaw = ((item[i].angle >> 14) & 0x03);
  47. yaw *= 90;
  48. unsigned int l = 9; // First angle offset in this Frame
  49. // Run through the tag and calculate the rotation and offset
  50. for (int j = 0; j < (int)moveable[index].num_meshes; ++j)
  51. tag.push_back(*new BoneTag(tr, index, j, &l));
  52. }
  53. BoneFrame::~BoneFrame() {
  54. for (unsigned int i = 0; i < tag.size(); i++)
  55. delete tag[i];
  56. }
  57. unsigned int BoneFrame::size() {
  58. return tag.size();
  59. }
  60. BoneTag &BoneFrame::get(unsigned int i) {
  61. assert(i < tag.size());
  62. return *tag.at(i);
  63. }
  64. void BoneFrame::add(BoneTag &b) {
  65. tag.push_back(&b);
  66. }
  67. AnimationFrame::AnimationFrame(TombRaider &tr, unsigned int index, unsigned int i, int a) {
  68. tr2_moveable_t *moveable = mTombRaider.Moveable();
  69. tr2_animation_t *animation = mTombRaider.Animation();
  70. unsigned int frame_offset = animation[a].frame_offset / 2;
  71. int frame_step = animation[a].frame_size;
  72. unsigned int frame_count = (animation[a].frame_end - animation[a].frame_start) + 1;
  73. rate = animation[a].frame_rate;
  74. for (unsigned int f = 0; f < frame_count; f++, frame_offset += frame_step) {
  75. // HACK: Lara's ObjectID is 315, but her meshes start at 0, so make a
  76. // quick substitution (so she doesn't appear as a bunch of thighs)
  77. if ((index == 0) && (tr.Engine() == TR_VERSION_3)) {
  78. for (int j = 0; (j < (int)tr.NumMoveables()) && (index == 0); j++) {
  79. if (moveable[j].object_id == 315)
  80. index = j;
  81. }
  82. }
  83. // Fix Lara in TR4
  84. // Body is ItemID 8, joints are ItemID 9
  85. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  86. if ((index == 0) && (tr.Engine() == TR_VERSION_4)) {
  87. for (int j = 0; (j < (int)tr.NumMoveables()) && (index == 0); j++) {
  88. if (moveable[j].object_id == 8)
  89. index = j;
  90. }
  91. } else if ((moveable[index].object_id == 8) && (tr.Engine() == TR_VERSION_4)) {
  92. // KLUDGE to do "skinning"
  93. index = 0;
  94. for (int j = 0; (j < (int)tr.NumMoveables()) && (index == 0); j++) {
  95. if (moveable[j].object_id == 9)
  96. index = j;
  97. }
  98. }
  99. if (frame_offset > tr.NumFrames()) {
  100. getConsole().print("WARNING: Bad animation frame %i > %i",
  101. frame_offset, tr.NumFrames());
  102. return;
  103. }
  104. frame.push_back(*new BoneFrame(tr, index, i, frame_offset));
  105. }
  106. }
  107. AnimationFrame::~AnimationFrame() {
  108. for (unsigned int i = 0; i < frame.size(); i++)
  109. delete frame[i];
  110. }
  111. unsigned int AnimationFrame::size() {
  112. return frame.size();
  113. }
  114. BoneFrame &AnimationFrame::get(unsigned int i) {
  115. assert(i < frame.size());
  116. return *frame.at(i);
  117. }
  118. void AnimationFrame::add(BoneFrame &b) {
  119. frame.push_back(&b);
  120. }
  121. SkeletalModel::SkeletalModel(TombRaider &tr, unsigned int index, unsigned int i, int objectId) {
  122. tr2_moveable_t *moveable = mTombRaider.Moveable();
  123. tr2_animation_t *anim = mTombRaider.Animation();
  124. id = objectId;
  125. // Gather more info if this is lara
  126. if (id == 0) {
  127. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  128. tr4Overlay = (mTombRaider.Engine() == TR_VERSION_4);
  129. ponytailId = 0;
  130. } else {
  131. tr4Overlay = false;
  132. ponytailId = -1;
  133. }
  134. switch (mTombRaider.Engine()) {
  135. case TR_VERSION_4:
  136. if (moveable[index].object_id == 30) {
  137. ponytailId = getWorld().sizeSkeletalModel(); //! \fixme Why is this even needed?
  138. ponytailMeshId = moveable[index].starting_mesh;
  139. ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  140. moveable[index].num_meshes : 0);
  141. ponytailAngle = -90.0f;
  142. ponytail[0] = -3;
  143. ponytail[1] = -22;
  144. ponytail[2] = -20;
  145. ponyOff = 40;
  146. ponyOff2 = 32;
  147. pigtails = false;
  148. // Try to guess pigtails by looking for certian num verts in head
  149. if (mesh[moveable[0].starting_mesh].num_vertices > 80) {
  150. pigtails = true;
  151. ponyOff -= 20;
  152. ponytail[1] -= 32;
  153. }
  154. getRender().setFlags(Render::fRenderPonytail);
  155. getConsole().print("Found known ponytail");
  156. }
  157. break;
  158. case TR_VERSION_1:
  159. case TR_VERSION_2:
  160. case TR_VERSION_3:
  161. case TR_VERSION_5:
  162. case TR_VERSION_UNKNOWN:
  163. if (moveable[index].object_id == 2) {
  164. ponytailId = k;
  165. ponytailMeshId = moveable[index].starting_mesh;
  166. ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  167. moveable[index].num_meshes : 0);
  168. ponytailAngle = -90.0f;
  169. ponytail[0] = 0;
  170. ponytail[1] = -20;
  171. ponytail[2] = -20;
  172. ponyOff = 40;
  173. ponyOff2 = 0;
  174. getRender().setFlags(Render::fRenderPonytail);
  175. getConsole().print("Found ponytail?");
  176. }
  177. break;
  178. }
  179. // Animations
  180. int a = moveable[index].animation;
  181. unsigned int frame_offset = anim[a].frame_offset / 2;
  182. int frame_step = anim[a].frame_size;
  183. if (a >= (int)tr.NumAnimations())
  184. a = tr.NumFrames() - frame_offset; //! \fixme Couldn't a be already used out of range?!
  185. else
  186. a = (anim[a].frame_offset / 2) - frame_offset;
  187. if (frame_step != 0) // prevent divide-by-zero errors
  188. a /= frame_step;
  189. if (a < 0) {
  190. getConsole().print("Invalid animation data for model %d. Skip!", index);
  191. return;
  192. } else {
  193. for (; a < tr.getNumAnimsForMoveable(index); a++) {
  194. animation.push_back(new AnimationFrame(tr, index, i, a))
  195. }
  196. }
  197. }
  198. SkeletalModel::~SkeletalModel() {
  199. for (unsigned int i = 0; i < animation.size(); i++)
  200. delete animation[i];
  201. }
  202. int SkeletalModel::getId() {
  203. return id;
  204. }
  205. void SkeletalModel::setPigTail(bool b) {
  206. pigtails = b;
  207. if (b) {
  208. ponyOff -= 20;
  209. ponytail[1] -= 32;
  210. } else {
  211. ponyOff += 20;
  212. ponytail[1] += 32;
  213. }
  214. }
  215. unsigned int SkeletalModel::size() {
  216. return animation.size();
  217. }
  218. AnimationFrame &SkeletalModel::get(unsigned int i) {
  219. assert(i < animation.size());
  220. return *animation.at(i);
  221. }