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

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