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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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 "Log.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. getLog() << "WARNING: Bad animation frame " << *frame_offset
  117. << " > " << tr.NumFrames() << " (" << index << "." << a << ")"
  118. << Log::endl;
  119. return;
  120. }
  121. frame.push_back(new BoneFrame(tr, index, *frame_offset));
  122. }
  123. }
  124. AnimationFrame::~AnimationFrame() {
  125. for (unsigned long i = 0; i < frame.size(); i++)
  126. delete frame[i];
  127. }
  128. unsigned long AnimationFrame::size() {
  129. return frame.size();
  130. }
  131. BoneFrame &AnimationFrame::get(unsigned long i) {
  132. assert(i < frame.size());
  133. return *frame.at(i);
  134. }
  135. SkeletalModel::SkeletalModel(TombRaider &tr, unsigned int index, int objectId) {
  136. tr2_moveable_t *moveable = tr.Moveable();
  137. tr2_animation_t *anim = tr.Animation();
  138. tr2_mesh_t *mesh = tr.Mesh();
  139. id = objectId;
  140. // Gather more info if this is lara
  141. if (id == 0) {
  142. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  143. tr4Overlay = (tr.Engine() == TR_VERSION_4);
  144. ponytailId = 0;
  145. } else {
  146. tr4Overlay = false;
  147. ponytailId = -1;
  148. }
  149. switch (tr.Engine()) {
  150. case TR_VERSION_4:
  151. if (moveable[index].object_id == 30) {
  152. ponytailId = getWorld().sizeSkeletalModel(); //! \fixme Why is this even needed?
  153. ponytailMeshId = moveable[index].starting_mesh;
  154. ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  155. moveable[index].num_meshes : 0);
  156. ponytailAngle = -90.0f;
  157. ponytail[0] = -3;
  158. ponytail[1] = -22;
  159. ponytail[2] = -20;
  160. ponyOff = 40;
  161. ponyOff2 = 32;
  162. pigtails = false;
  163. // Try to guess pigtails by looking for certian num verts in head
  164. if (mesh[moveable[0].starting_mesh].num_vertices > 80) {
  165. pigtails = true;
  166. ponyOff -= 20;
  167. ponytail[1] -= 32;
  168. }
  169. getRender().setFlags(Render::fRenderPonytail);
  170. getLog() << "Found known ponytail" << Log::endl;
  171. }
  172. break;
  173. case TR_VERSION_1:
  174. case TR_VERSION_2:
  175. case TR_VERSION_3:
  176. case TR_VERSION_5:
  177. case TR_VERSION_UNKNOWN:
  178. if (moveable[index].object_id == 2) {
  179. ponytailId = getWorld().sizeSkeletalModel(); //! \fixme Why is this even needed?
  180. ponytailMeshId = moveable[index].starting_mesh;
  181. ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  182. moveable[index].num_meshes : 0);
  183. ponytailAngle = -90.0f;
  184. ponytail[0] = 0;
  185. ponytail[1] = -20;
  186. ponytail[2] = -20;
  187. ponyOff = 40;
  188. ponyOff2 = 0;
  189. getRender().setFlags(Render::fRenderPonytail);
  190. getLog() << "Found ponytail?" << Log::endl;
  191. }
  192. break;
  193. }
  194. // Animations
  195. int a = moveable[index].animation;
  196. unsigned int frame_offset = anim[a].frame_offset / 2;
  197. int frame_step = anim[a].frame_size;
  198. int frame_cycle = 0;
  199. if (a >= (int)tr.NumAnimations())
  200. a = tr.NumFrames() - frame_offset; //! \fixme Couldn't a be already used out of range?!
  201. else
  202. a = (anim[a].frame_offset / 2) - frame_offset; //! \fixme Same as a = 0; ??
  203. if (frame_step != 0) // prevent divide-by-zero errors
  204. a /= frame_step;
  205. if (a != 0)
  206. frame_offset += frame_step * (frame_cycle % a);
  207. if (a < 0) {
  208. getLog() << "Invalid animation data for model " << index << ". Skip!" << Log::endl;
  209. return;
  210. } else {
  211. for (; a < tr.getNumAnimsForMoveable(index); a++) {
  212. animation.push_back(new AnimationFrame(tr, index, a, &frame_offset, frame_step));
  213. if (frame_offset > tr.NumFrames())
  214. return;
  215. frame_offset = anim[a].frame_offset / 2;
  216. frame_step = anim[a].frame_size;
  217. }
  218. }
  219. }
  220. SkeletalModel::~SkeletalModel() {
  221. for (unsigned long i = 0; i < animation.size(); i++)
  222. delete animation[i];
  223. }
  224. void SkeletalModel::display(unsigned long aframe, unsigned long bframe) {
  225. assert(aframe < size());
  226. assert(bframe < get(aframe).size());
  227. AnimationFrame &anim = get(aframe);
  228. BoneFrame &boneframe = anim.get(bframe);
  229. float pos[3];
  230. boneframe.getPosition(pos);
  231. glTranslatef(pos[0], pos[1], pos[2]);
  232. for (unsigned int a = 0; a < boneframe.size(); a++) {
  233. BoneTag &tag = boneframe.get(a);
  234. float rot[3], off[3];
  235. tag.getRotation(rot);
  236. tag.getOffset(off);
  237. if (a == 0) {
  238. glRotatef(rot[1], 0, 1, 0);
  239. glRotatef(rot[0], 1, 0, 0);
  240. glRotatef(rot[2], 0, 0, 1);
  241. } else {
  242. if (tag.getFlag() & 0x01)
  243. glPopMatrix();
  244. if (tag.getFlag() & 0x02)
  245. glPushMatrix();
  246. glTranslatef(off[0], off[1], off[2]);
  247. glRotatef(rot[1], 0, 1, 0);
  248. glRotatef(rot[0], 1, 0, 0);
  249. glRotatef(rot[2], 0, 0, 1);
  250. }
  251. // Draw layered lara in TR4 (2 meshes per tag)
  252. if (tr4Overlay) {
  253. BoneFrame &boneframe2 = get(0).get(0); //! \fixme Woot?
  254. if (a < boneframe2.size())
  255. boneframe2.get(a).display();
  256. }
  257. if (getRender().getFlags() & Render::fRenderPonytail) {
  258. if ((ponytailId > 0) && (a == 14)) {
  259. glPushMatrix();
  260. // Mongoose 2002.08.30, TEST to align offset
  261. glTranslatef(ponytail[0], ponytail[1], ponytail[2]);
  262. glRotatef(ponytailAngle, 1, 0, 0);
  263. // HACK: To fill TR4 void between ponytail/head
  264. // since no vertex welds are implemented yet
  265. if (tr4Overlay)
  266. glScalef(1.20f, 1.20f, 1.20f);
  267. #ifdef EXPERIMENTAL_NON_ITEM_RENDER
  268. getWorld().getSkeletalModel(ponytail).display(0, 0);
  269. #else
  270. for (unsigned int i = 0; i < ponytailNumMeshes; i++) {
  271. glPushMatrix();
  272. if (i > 0) {
  273. glRotatef(randomNum(-8.0f, -10.0f), 1, 0, 0);
  274. glRotatef(randomNum(-5.0f, 5.0f), 0, 1, 0);
  275. glRotatef(randomNum(-5.0f, 5.0f), 0, 0, 1);
  276. glTranslatef(0.0, 0.0, ponyOff);
  277. }
  278. if (pigtails) {
  279. glPushMatrix();
  280. glTranslatef(ponyOff2, 0.0, 0.0);
  281. getWorld().getStaticMesh(ponytailMeshId + i).display();
  282. glPopMatrix();
  283. glPushMatrix();
  284. glTranslatef(-ponyOff2, 0.0, 0.0);
  285. getWorld().getStaticMesh(ponytailMeshId + i).display();
  286. glPopMatrix();
  287. } else {
  288. getWorld().getStaticMesh(ponytailMeshId + i).display();
  289. }
  290. }
  291. for (unsigned int i = 0; i < ponytailNumMeshes; i++)
  292. glPopMatrix();
  293. #endif
  294. glPopMatrix();
  295. }
  296. }
  297. tag.display();
  298. }
  299. }
  300. int SkeletalModel::getId() {
  301. return id;
  302. }
  303. void SkeletalModel::setPigTail(bool b) {
  304. pigtails = b;
  305. if (b) {
  306. ponyOff -= 20;
  307. ponytail[1] -= 32;
  308. } else {
  309. ponyOff += 20;
  310. ponytail[1] += 32;
  311. }
  312. }
  313. void SkeletalModel::setPonyPos(float x, float y, float z, float angle) {
  314. ponytail[0] = x;
  315. ponytail[1] = y;
  316. ponytail[2] = z;
  317. ponytailAngle = angle;
  318. }
  319. unsigned long SkeletalModel::size() {
  320. return animation.size();
  321. }
  322. AnimationFrame &SkeletalModel::get(unsigned long i) {
  323. assert(i < animation.size());
  324. return *animation.at(i);
  325. }