Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

SkeletalModel.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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 "global.h"
  9. #include "Console.h"
  10. #include "Render.h"
  11. #include "SkeletalModel.h"
  12. #include "World.h"
  13. BoneTag::BoneTag(TombRaider &tr, unsigned int index, unsigned int i, unsigned int *l, unsigned int frame_offset) {
  14. tr2_moveable_t *moveable = tr.Moveable();
  15. tr2_meshtree_t *meshtree = tr.MeshTree();
  16. unsigned short *frame = tr.Frame();
  17. off[0] = 0.0f;
  18. off[1] = 0.0f;
  19. off[2] = 0.0f;
  20. flag = 0x00;
  21. rot[0] = 0.0f;
  22. rot[1] = 0.0f;
  23. rot[2] = 0.0f;
  24. mesh = moveable[index].starting_mesh + i;
  25. // Setup offsets to produce skeleton
  26. if (i == 0) {
  27. // Always push tag[0], this isn't really used either
  28. flag = 0x02;
  29. } else { // Nonprimary tag - position relative to first tag
  30. // Hack: moveable[index].mesh_tree is a byte offset
  31. // into mesh_tree[], so we have to convert to index
  32. int *tree = (int *)(void *)meshtree;
  33. tr2_meshtree_t *mesh_tree = (tr2_meshtree_t *)(tree
  34. + moveable[index].mesh_tree + ((i - 1) * 4));
  35. off[0] = mesh_tree->x;
  36. off[1] = mesh_tree->y;
  37. off[2] = mesh_tree->z;
  38. flag = (char)mesh_tree->flags;
  39. }
  40. // Setup tag rotations
  41. tr.computeRotationAngles(&frame, &frame_offset, l, rot, rot + 1, rot + 2);
  42. }
  43. void BoneTag::display() {
  44. getWorld().getStaticMesh(mesh).display();
  45. }
  46. void BoneTag::getOffset(float o[3]) {
  47. o[0] = off[0];
  48. o[1] = off[1];
  49. o[2] = off[2];
  50. }
  51. void BoneTag::getRotation(float r[3]) {
  52. r[0] = rot[0];
  53. r[1] = rot[1];
  54. r[2] = rot[2];
  55. }
  56. char BoneTag::getFlag() {
  57. return flag;
  58. }
  59. BoneFrame::BoneFrame(TombRaider &tr, unsigned int index, unsigned int frame_offset) {
  60. tr2_moveable_t *moveable = tr.Moveable();
  61. unsigned short *frame = tr.Frame();
  62. pos[0] = (short)frame[frame_offset + 6];
  63. pos[1] = (short)frame[frame_offset + 7];
  64. pos[2] = (short)frame[frame_offset + 8];
  65. unsigned int l = 9; // First angle offset in this Frame
  66. for (unsigned int i = 0; i < moveable[index].num_meshes; i++)
  67. tag.push_back(new BoneTag(tr, index, i, &l, frame_offset));
  68. }
  69. BoneFrame::~BoneFrame() {
  70. for (unsigned long i = 0; i < tag.size(); i++)
  71. delete tag[i];
  72. }
  73. unsigned long BoneFrame::size() {
  74. return tag.size();
  75. }
  76. BoneTag &BoneFrame::get(unsigned long i) {
  77. assert(i < tag.size());
  78. return *tag.at(i);
  79. }
  80. void BoneFrame::getPosition(float p[3]) {
  81. p[0] = pos[0];
  82. p[1] = pos[1];
  83. p[2] = pos[2];
  84. }
  85. AnimationFrame::AnimationFrame(TombRaider &tr, unsigned int index, int a, unsigned int *frame_offset, int frame_step) {
  86. tr2_moveable_t *moveable = tr.Moveable();
  87. tr2_animation_t *animation = tr.Animation();
  88. unsigned int frame_count = (animation[a].frame_end - animation[a].frame_start) + 1;
  89. rate = animation[a].frame_rate;
  90. for (unsigned int f = 0; f < frame_count; f++, *frame_offset += frame_step) {
  91. // HACK: Lara's ObjectID is 315, but her meshes start at 0, so make a
  92. // quick substitution (so she doesn't appear as a bunch of thighs)
  93. if ((index == 0) && (tr.Engine() == TR_VERSION_3)) {
  94. for (int j = 0; (j < (int)tr.NumMoveables()) && (index == 0); j++) {
  95. if (moveable[j].object_id == 315)
  96. index = j;
  97. }
  98. }
  99. // Fix Lara in TR4
  100. // Body is ItemID 8, joints are ItemID 9
  101. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  102. if ((index == 0) && (tr.Engine() == TR_VERSION_4)) {
  103. for (int j = 0; (j < (int)tr.NumMoveables()) && (index == 0); j++) {
  104. if (moveable[j].object_id == 8)
  105. index = j;
  106. }
  107. } else if ((moveable[index].object_id == 8) && (tr.Engine() == TR_VERSION_4)) {
  108. // KLUDGE to do "skinning"
  109. index = 0;
  110. for (int j = 0; (j < (int)tr.NumMoveables()) && (index == 0); j++) {
  111. if (moveable[j].object_id == 9)
  112. index = j;
  113. }
  114. }
  115. if (*frame_offset > tr.NumFrames()) {
  116. getConsole().print("WARNING: Bad animation frame %i > %i (%u.%d)",
  117. *frame_offset, tr.NumFrames(), index, a);
  118. return;
  119. }
  120. frame.push_back(new BoneFrame(tr, index, *frame_offset));
  121. }
  122. }
  123. AnimationFrame::~AnimationFrame() {
  124. for (unsigned long i = 0; i < frame.size(); i++)
  125. delete frame[i];
  126. }
  127. unsigned long AnimationFrame::size() {
  128. return frame.size();
  129. }
  130. BoneFrame &AnimationFrame::get(unsigned long i) {
  131. assert(i < frame.size());
  132. return *frame.at(i);
  133. }
  134. SkeletalModel::SkeletalModel(TombRaider &tr, unsigned int index, int objectId) {
  135. tr2_moveable_t *moveable = tr.Moveable();
  136. tr2_animation_t *anim = tr.Animation();
  137. tr2_mesh_t *mesh = tr.Mesh();
  138. id = objectId;
  139. // Gather more info if this is lara
  140. if (id == 0) {
  141. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  142. tr4Overlay = (tr.Engine() == TR_VERSION_4);
  143. ponytailId = 0;
  144. } else {
  145. tr4Overlay = false;
  146. ponytailId = -1;
  147. }
  148. switch (tr.Engine()) {
  149. case TR_VERSION_4:
  150. if (moveable[index].object_id == 30) {
  151. ponytailId = getWorld().sizeSkeletalModel(); //! \fixme Why is this even needed?
  152. ponytailMeshId = moveable[index].starting_mesh;
  153. ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  154. moveable[index].num_meshes : 0);
  155. ponytailAngle = -90.0f;
  156. ponytail[0] = -3;
  157. ponytail[1] = -22;
  158. ponytail[2] = -20;
  159. ponyOff = 40;
  160. ponyOff2 = 32;
  161. pigtails = false;
  162. // Try to guess pigtails by looking for certian num verts in head
  163. if (mesh[moveable[0].starting_mesh].num_vertices > 80) {
  164. pigtails = true;
  165. ponyOff -= 20;
  166. ponytail[1] -= 32;
  167. }
  168. getRender().setFlags(Render::fRenderPonytail);
  169. getConsole().print("Found known ponytail");
  170. }
  171. break;
  172. case TR_VERSION_1:
  173. case TR_VERSION_2:
  174. case TR_VERSION_3:
  175. case TR_VERSION_5:
  176. case TR_VERSION_UNKNOWN:
  177. if (moveable[index].object_id == 2) {
  178. ponytailId = getWorld().sizeSkeletalModel(); //! \fixme Why is this even needed?
  179. ponytailMeshId = moveable[index].starting_mesh;
  180. ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  181. moveable[index].num_meshes : 0);
  182. ponytailAngle = -90.0f;
  183. ponytail[0] = 0;
  184. ponytail[1] = -20;
  185. ponytail[2] = -20;
  186. ponyOff = 40;
  187. ponyOff2 = 0;
  188. getRender().setFlags(Render::fRenderPonytail);
  189. getConsole().print("Found ponytail?");
  190. }
  191. break;
  192. }
  193. // Animations
  194. int a = moveable[index].animation;
  195. unsigned int frame_offset = anim[a].frame_offset / 2;
  196. int frame_step = anim[a].frame_size;
  197. int frame_cycle = 0;
  198. if (a >= (int)tr.NumAnimations())
  199. a = tr.NumFrames() - frame_offset; //! \fixme Couldn't a be already used out of range?!
  200. else
  201. a = (anim[a].frame_offset / 2) - frame_offset; //! \fixme Same as a = 0; ??
  202. if (frame_step != 0) // prevent divide-by-zero errors
  203. a /= frame_step;
  204. if (a != 0)
  205. frame_offset += frame_step * (frame_cycle % a);
  206. if (a < 0) {
  207. getConsole().print("Invalid animation data for model %d. Skip!", index);
  208. return;
  209. } else {
  210. for (; a < tr.getNumAnimsForMoveable(index); a++) {
  211. animation.push_back(new AnimationFrame(tr, index, a, &frame_offset, frame_step));
  212. if (frame_offset > tr.NumFrames())
  213. return;
  214. frame_offset = anim[a].frame_offset / 2;
  215. frame_step = anim[a].frame_size;
  216. }
  217. }
  218. }
  219. SkeletalModel::~SkeletalModel() {
  220. for (unsigned long i = 0; i < animation.size(); i++)
  221. delete animation[i];
  222. }
  223. void SkeletalModel::display(unsigned long aframe, unsigned long bframe) {
  224. assert(aframe < size());
  225. assert(bframe < get(aframe).size());
  226. AnimationFrame &anim = get(aframe);
  227. BoneFrame &boneframe = anim.get(bframe);
  228. float pos[3];
  229. boneframe.getPosition(pos);
  230. glTranslatef(pos[0], pos[1], pos[2]);
  231. for (unsigned int a = 0; a < boneframe.size(); a++) {
  232. BoneTag &tag = boneframe.get(a);
  233. float rot[3], off[3];
  234. tag.getRotation(rot);
  235. tag.getOffset(off);
  236. if (a == 0) {
  237. glRotatef(rot[1], 0, 1, 0);
  238. glRotatef(rot[0], 1, 0, 0);
  239. glRotatef(rot[2], 0, 0, 1);
  240. } else {
  241. if (tag.getFlag() & 0x01)
  242. glPopMatrix();
  243. if (tag.getFlag() & 0x02)
  244. glPushMatrix();
  245. glTranslatef(off[0], off[1], off[2]);
  246. glRotatef(rot[1], 0, 1, 0);
  247. glRotatef(rot[0], 1, 0, 0);
  248. glRotatef(rot[2], 0, 0, 1);
  249. }
  250. // Draw layered lara in TR4 (2 meshes per tag)
  251. if (tr4Overlay) {
  252. BoneFrame &boneframe2 = get(0).get(0); //! \fixme Woot?
  253. if (a < boneframe2.size())
  254. boneframe2.get(a).display();
  255. }
  256. if (getRender().getFlags() & Render::fRenderPonytail) {
  257. if ((ponytailId > 0) && (a == 14)) {
  258. glPushMatrix();
  259. // Mongoose 2002.08.30, TEST to align offset
  260. glTranslatef(ponytail[0], ponytail[1], ponytail[2]);
  261. glRotatef(ponytailAngle, 1, 0, 0);
  262. // HACK: To fill TR4 void between ponytail/head
  263. // since no vertex welds are implemented yet
  264. if (tr4Overlay)
  265. glScalef(1.20f, 1.20f, 1.20f);
  266. #ifdef EXPERIMENTAL_NON_ITEM_RENDER
  267. getWorld().getSkeletalModel(ponytail).display(0, 0);
  268. #else
  269. for (unsigned int i = 0; i < ponytailNumMeshes; i++) {
  270. glPushMatrix();
  271. if (i > 0) {
  272. glRotatef(randomNum(-8.0f, -10.0f), 1, 0, 0);
  273. glRotatef(randomNum(-5.0f, 5.0f), 0, 1, 0);
  274. glRotatef(randomNum(-5.0f, 5.0f), 0, 0, 1);
  275. glTranslatef(0.0, 0.0, ponyOff);
  276. }
  277. if (pigtails) {
  278. glPushMatrix();
  279. glTranslatef(ponyOff2, 0.0, 0.0);
  280. getWorld().getStaticMesh(ponytailMeshId + i).display();
  281. glPopMatrix();
  282. glPushMatrix();
  283. glTranslatef(-ponyOff2, 0.0, 0.0);
  284. getWorld().getStaticMesh(ponytailMeshId + i).display();
  285. glPopMatrix();
  286. } else {
  287. getWorld().getStaticMesh(ponytailMeshId + i).display();
  288. }
  289. }
  290. for (unsigned int i = 0; i < ponytailNumMeshes; i++)
  291. glPopMatrix();
  292. #endif
  293. glPopMatrix();
  294. }
  295. }
  296. tag.display();
  297. }
  298. }
  299. int SkeletalModel::getId() {
  300. return id;
  301. }
  302. void SkeletalModel::setPigTail(bool b) {
  303. pigtails = b;
  304. if (b) {
  305. ponyOff -= 20;
  306. ponytail[1] -= 32;
  307. } else {
  308. ponyOff += 20;
  309. ponytail[1] += 32;
  310. }
  311. }
  312. void SkeletalModel::setPonyPos(float x, float y, float z, float angle) {
  313. ponytail[0] = x;
  314. ponytail[1] = y;
  315. ponytail[2] = z;
  316. ponytailAngle = angle;
  317. }
  318. unsigned long SkeletalModel::size() {
  319. return animation.size();
  320. }
  321. AnimationFrame &SkeletalModel::get(unsigned long i) {
  322. assert(i < animation.size());
  323. return *animation.at(i);
  324. }