Open Source Tomb Raider Engine
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

SkeletalModel.cpp 11KB

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