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.

Game.cpp 33KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. /*!
  2. * \file src/Game.cpp
  3. * \brief Game abstraction
  4. *
  5. * \author xythobuz
  6. */
  7. #ifdef __APPLE__
  8. #include <OpenGL/gl.h>
  9. #elif defined WIN32
  10. #include <gl/glew.h>
  11. #include <gl/wglew.h>
  12. #else
  13. #include <GL/gl.h>
  14. #endif
  15. #include <algorithm>
  16. #include <map>
  17. #include <cstdlib>
  18. #include "main.h"
  19. #include "Console.h"
  20. #include "Game.h"
  21. #include "utils/strings.h"
  22. #include "games/TombRaider1.h"
  23. #ifdef EXPERIMENTAL
  24. std::vector<unsigned int> gColorTextureHACK;
  25. #endif
  26. #ifdef MULTITEXTURE
  27. std::map<int, int> gMapTex2Bump;
  28. #endif
  29. Game::Game() {
  30. mLoaded = false;
  31. mName = NULL;
  32. mLara = NULL;
  33. mTextureStart = 0;
  34. mTextureOffset = 0;
  35. }
  36. Game::~Game() {
  37. destroy();
  38. }
  39. unsigned int Game::getTextureStart() {
  40. return mTextureStart;
  41. }
  42. unsigned int Game::getTextureOffset() {
  43. return mTextureOffset;
  44. }
  45. int Game::initialize() {
  46. // Enable Renderer
  47. mTextureStart = getRender().initTextures(getOpenRaider().mDataDir);
  48. getRender().setMode(Render::modeLoadScreen);
  49. return 0;
  50. }
  51. void Game::destroy() {
  52. if (mName)
  53. delete [] mName;
  54. mLoaded = false;
  55. mLara = NULL;
  56. getRender().setMode(Render::modeDisabled);
  57. getWorld().destroy();
  58. getRender().ClearWorld();
  59. getSound().clear(); // Remove all previously loaded sounds
  60. }
  61. bool Game::isLoaded() {
  62. return mLoaded;
  63. }
  64. int Game::loadLevel(const char *level) {
  65. if (mLoaded)
  66. destroy();
  67. mName = bufferString("%s", level);
  68. // Load the level pak into TombRaider
  69. getConsole().print("Loading %s", mName);
  70. int error = mTombRaider.Load(mName);
  71. if (error != 0) {
  72. return error;
  73. }
  74. // If required, load the external sound effect file MAIN.SFX into TombRaider
  75. if ((mTombRaider.getEngine() == TR_VERSION_2) || (mTombRaider.getEngine() == TR_VERSION_3)) {
  76. char *tmp = bufferString("%sMAIN.SFX", level); // Ensure theres enough space
  77. size_t length = strlen(tmp);
  78. size_t dir = 0;
  79. for (int i = length - 1; i >= 0; i--) {
  80. if ((tmp[i] == '/') || (tmp[i] == '\\')) {
  81. dir = i + 1; // Find where the filename (bla.tr2) starts
  82. break;
  83. }
  84. }
  85. strcpy(tmp + dir, "MAIN.SFX"); // overwrite the name itself with MAIN.SFX
  86. tmp[dir + 8] = '\0';
  87. error = mTombRaider.loadSFX(tmp);
  88. if (error != 0) {
  89. getConsole().print("Could not load %s", tmp);
  90. }
  91. delete [] tmp;
  92. }
  93. // Process data
  94. processTextures();
  95. processRooms();
  96. processModels();
  97. processSprites();
  98. processMoveables();
  99. processPakSounds();
  100. // Free pak file
  101. mTombRaider.reset();
  102. // Check if the level contains Lara
  103. if (mLara == NULL) {
  104. getConsole().print("Can't find Lara entity in level pak!");
  105. return -1;
  106. }
  107. mLoaded = true;
  108. getRender().setMode(Render::modeVertexLight);
  109. return 0;
  110. }
  111. void Game::handleAction(ActionEvents action, bool isFinished) {
  112. if (mLoaded) {
  113. if (action == forwardAction) {
  114. getWorld().moveEntity(mLara, 'f');
  115. } else if (action == backwardAction) {
  116. getWorld().moveEntity(mLara, 'b');
  117. } else if (action == leftAction) {
  118. getWorld().moveEntity(mLara, 'l');
  119. } else if (action == rightAction) {
  120. getWorld().moveEntity(mLara, 'r');
  121. }
  122. }
  123. }
  124. void Game::handleMouseMotion(int xrel, int yrel) {
  125. if (mLoaded) {
  126. // Move Camera on X Axis
  127. if (xrel > 0)
  128. while (xrel-- > 0)
  129. getCamera().command(CAMERA_ROTATE_RIGHT);
  130. else if (xrel < 0)
  131. while (xrel++ < 0)
  132. getCamera().command(CAMERA_ROTATE_LEFT);
  133. // Move Camera on Y Axis
  134. if (yrel > 0)
  135. while (yrel-- > 0)
  136. getCamera().command(CAMERA_ROTATE_UP);
  137. else if (yrel < 0)
  138. while (yrel++ < 0)
  139. getCamera().command(CAMERA_ROTATE_DOWN);
  140. // Fix Laras rotation
  141. mLara->angles[1] = getCamera().getRadianYaw();
  142. mLara->angles[2] = getCamera().getRadianPitch();
  143. }
  144. }
  145. void Game::processSprites() {
  146. printf("Processing sprites: ");
  147. for (int i = 0; i < (mTombRaider.NumItems() - 1); i++) {
  148. if ((mTombRaider.Engine() == TR_VERSION_1) && (mTombRaider.Item()[i].intensity1 == -1))
  149. continue;
  150. for (int j = 0; j < mTombRaider.NumSpriteSequences(); j++) {
  151. if (mTombRaider.SpriteSequence()[j].object_id == mTombRaider.Item()[i].object_id)
  152. getWorld().addSprite(*new SpriteSequence(mTombRaider, i, j));
  153. }
  154. }
  155. printf("Done! Found %d sprites.\n", mTombRaider.NumSpriteSequences());
  156. }
  157. void Game::processRooms() {
  158. printf("Processing rooms: ");
  159. for (int index = 0; index < mTombRaider.NumRooms(); index++) {
  160. Room &room = *new Room(mTombRaider, index);
  161. getWorld().addRoom(room);
  162. }
  163. printf("Done! Found %d rooms.\n", mTombRaider.NumRooms());
  164. }
  165. void Game::processPakSounds()
  166. {
  167. unsigned char *riff;
  168. unsigned int riffSz;
  169. //tr2_sound_source_t *sound;
  170. //tr2_sound_details_t *detail;
  171. //float pos[3];
  172. unsigned int i;
  173. int id;
  174. /* detail
  175. short sample;
  176. short volume;
  177. short sound_range;
  178. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  179. // in this group, bits 0-1: channel number
  180. */
  181. printf("Processing pak sound files: ");
  182. for (i = 0; i < mTombRaider.getSoundSamplesCount(); ++i)
  183. {
  184. mTombRaider.getSoundSample(i, &riffSz, &riff);
  185. getSound().addWave(riff, riffSz, &id, Sound::SoundFlagsNone);
  186. //if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  187. //{
  188. //m_testSFX = id;
  189. //}
  190. delete [] riff;
  191. // sound[i].sound_id; // internal sound index
  192. // sound[i].flags; // 0x40, 0x80, or 0xc0
  193. //pos[0] = sound[i].x;
  194. //pos[1] = sound[i].y;
  195. //pos[2] = sound[i].z;
  196. //getSound().SourceAt(id, pos);
  197. //printf(".");
  198. //fflush(stdout);
  199. }
  200. printf("Done! Found %u files.\n", mTombRaider.getSoundSamplesCount());
  201. }
  202. void Game::processTextures()
  203. {
  204. unsigned char *image;
  205. unsigned char *bumpmap;
  206. int i;
  207. printf("Processing TR textures: ");
  208. //if ( mTombRaider.getNumBumpMaps())
  209. // gBumpMapStart = mTombRaider.NumTextures();
  210. for (i = 0; i < mTombRaider.NumTextures(); ++i)
  211. {
  212. mTombRaider.Texture(i, &image, &bumpmap);
  213. // Overwrite any previous level textures on load
  214. getRender().loadTexture(image, 256, 256, (mTextureStart - 1) + i);
  215. #ifdef MULTITEXTURE
  216. gMapTex2Bump[(mTextureStart - 1) + i] = -1;
  217. #endif
  218. if (bumpmap)
  219. {
  220. #ifdef MULTITEXTURE
  221. gMapTex2Bump[(mTextureStart - 1) + i] = (mTextureStart - 1) + i +
  222. mTombRaider.NumTextures();
  223. #endif
  224. getRender().loadTexture(bumpmap, 256, 256, (mTextureStart - 1) + i +
  225. mTombRaider.NumTextures());
  226. }
  227. if (image)
  228. delete [] image;
  229. if (bumpmap)
  230. delete [] bumpmap;
  231. //printf(".");
  232. //fflush(stdout);
  233. }
  234. mTextureOffset = (mTextureStart - 1) + mTombRaider.NumTextures();
  235. printf("Done! Found %d textures.\n", mTombRaider.NumTextures());
  236. }
  237. void Game::processMoveables()
  238. {
  239. std::vector<unsigned int> cache;
  240. std::vector<skeletal_model_t *> cache2;
  241. tr2_mesh_t *mesh = NULL;
  242. tr2_moveable_t *moveable = NULL;
  243. tr2_meshtree_t *meshtree = NULL;
  244. tr2_item_t *item = NULL;
  245. tr2_animation_t *animation = NULL;
  246. unsigned short *frame = NULL;
  247. tr2_sprite_sequence_t *sprite_sequence = NULL;
  248. tr2_object_texture_t *object_texture = NULL;
  249. int i, j, object_id;
  250. int ent = 0;
  251. unsigned int statCount = 0;
  252. frame = mTombRaider.Frame();
  253. moveable = mTombRaider.Moveable();
  254. meshtree = mTombRaider.MeshTree();
  255. mesh = mTombRaider.Mesh();
  256. object_texture = mTombRaider.ObjectTextures();
  257. item = mTombRaider.Item();
  258. animation = mTombRaider.Animation();
  259. sprite_sequence = mTombRaider.SpriteSequence();
  260. printf("Processing skeletal models: ");
  261. for (i = 0; i < mTombRaider.NumItems(); ++i)
  262. {
  263. object_id = item[i].object_id;
  264. // It may not be a moveable, test for sprite
  265. if (!(mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1))
  266. {
  267. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j)
  268. {
  269. if (sprite_sequence[j].object_id == object_id)
  270. break;
  271. }
  272. // It's not a moveable, skip sprite
  273. if (j != (int)mTombRaider.NumSpriteSequences())
  274. {
  275. //printf("s");
  276. //fflush(stdout);
  277. continue;
  278. }
  279. }
  280. for (j = 0; j < (int)mTombRaider.NumMoveables(); ++j)
  281. {
  282. if ((int)moveable[j].object_id == object_id)
  283. break;
  284. }
  285. // It's not a moveable or even a sprite?, skip unknown
  286. if (j == (int)mTombRaider.NumMoveables())
  287. {
  288. //printf("?"); // what the wolf?
  289. //fflush(stdout);
  290. continue;
  291. }
  292. processMoveable(j, i, &ent, cache2, cache, object_id);
  293. statCount++;
  294. }
  295. // Get models that aren't items
  296. for (i = 0; i < mTombRaider.NumMoveables(); ++i)
  297. {
  298. switch ((int)moveable[i].object_id)
  299. {
  300. case 30:
  301. case 2: // Which tr needs this as model again?
  302. processMoveable(i, i, &ent, cache2, cache,
  303. (int)moveable[i].object_id);
  304. break;
  305. default:
  306. switch (mTombRaider.Engine())
  307. {
  308. case TR_VERSION_1:
  309. switch ((int)moveable[i].object_id)
  310. {
  311. case TombRaider1::LaraMutant:
  312. processMoveable(i, i, &ent, cache2, cache,
  313. (int)moveable[i].object_id);
  314. break;
  315. }
  316. break;
  317. case TR_VERSION_4:
  318. switch ((int)moveable[i].object_id)
  319. {
  320. case TR4_PISTOLS_ANIM:
  321. case TR4_UZI_ANIM:
  322. case TR4_SHOTGUN_ANIM:
  323. case TR4_CROSSBOW_ANIM:
  324. case TR4_GRENADE_GUN_ANIM:
  325. case TR4_SIXSHOOTER_ANIM:
  326. processMoveable(i, i, &ent, cache2, cache,
  327. (int)moveable[i].object_id);
  328. break;
  329. }
  330. break;
  331. case TR_VERSION_2:
  332. case TR_VERSION_3:
  333. case TR_VERSION_5:
  334. case TR_VERSION_UNKNOWN:
  335. break;
  336. }
  337. }
  338. }
  339. printf("Done! Found %d models.\n", mTombRaider.NumMoveables() + statCount);
  340. }
  341. void Game::processMoveable(int index, int i, int *ent,
  342. std::vector<skeletal_model_t *> &cache2,
  343. std::vector<unsigned int> &cache, int object_id)
  344. {
  345. skeletal_model_t *r_model = NULL;
  346. skeletal_model_t *c_model = NULL;
  347. animation_frame_t *animation_frame = NULL;
  348. tr2_mesh_t *mesh = NULL;
  349. tr2_moveable_t *moveable = NULL;
  350. tr2_meshtree_t *meshtree = NULL;
  351. tr2_item_t *item = NULL;
  352. tr2_animation_t *animation = NULL;
  353. tr2_meshtree_t *mesh_tree = NULL;
  354. bone_frame_t *bone = NULL;
  355. bone_tag_t *tag = NULL;
  356. entity_t *thing = NULL;
  357. SkeletalModel *sModel = 0x0;
  358. unsigned short *frame;
  359. int j, k, a, frame_step;
  360. unsigned int l, frame_offset, frame_count, f;
  361. float pos[3];
  362. float yaw;
  363. bool lara = false;
  364. int skyMesh;
  365. skyMesh = mTombRaider.getSkyModelId();
  366. frame = mTombRaider.Frame();
  367. moveable = mTombRaider.Moveable();
  368. meshtree = mTombRaider.MeshTree();
  369. mesh = mTombRaider.Mesh();
  370. item = mTombRaider.Item();
  371. animation = mTombRaider.Animation();
  372. pos[0] = item[i].x;
  373. pos[1] = item[i].y;
  374. pos[2] = item[i].z;
  375. yaw = ((item[i].angle >> 14) & 0x03);
  376. yaw *= 90;
  377. thing = new entity_t;
  378. thing->id = (*ent)++;
  379. thing->type = 0x00;
  380. thing->pos[0] = item[i].x;
  381. thing->pos[1] = item[i].y;
  382. thing->pos[2] = item[i].z;
  383. thing->angles[1] = yaw;
  384. thing->objectId = moveable[index].object_id;
  385. thing->moving = false;
  386. thing->animate = false;
  387. sModel = new SkeletalModel();
  388. getRender().addSkeletalModel(sModel);
  389. thing->tmpHook = sModel; // temp hack to keep a running version during refactoring
  390. if (mTombRaider.Engine() == TR_VERSION_1)
  391. {
  392. switch (thing->objectId)
  393. {
  394. case TombRaider1::Wolf:
  395. thing->state = TombRaider1::WolfState_Lying;
  396. //thing->animate = true;
  397. sModel->setAnimation(3);
  398. sModel->setFrame(0);
  399. break;
  400. }
  401. }
  402. //! \fixme Check here and see if we already have one for object_id later
  403. // if (getWorld().isCachedSkeletalModel(moveable[index].object_id))
  404. // {
  405. // thing->modelId = getRender().add(sModel);
  406. // return;
  407. // }
  408. r_model = new skeletal_model_t;
  409. r_model->id = moveable[index].object_id;
  410. // Gather more info if this is lara
  411. if (moveable[index].object_id == 0)
  412. {
  413. lara = true;
  414. thing->type = 0x02;
  415. mLara = thing; // Mongoose 2002.03.22, Cheap hack for now
  416. mLara->master = 0x0;
  417. switch (mTombRaider.Engine())
  418. {
  419. case TR_VERSION_3:
  420. mLara->modelId = i;
  421. sModel->setAnimation(TR_ANIAMTION_RUN);
  422. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  423. r_model->tr4Overlay = false;
  424. break;
  425. case TR_VERSION_4:
  426. mLara->modelId = i;
  427. sModel->setAnimation(TR_ANIAMTION_RUN);
  428. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  429. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  430. r_model->tr4Overlay = true;
  431. break;
  432. case TR_VERSION_1:
  433. case TR_VERSION_2:
  434. case TR_VERSION_5:
  435. case TR_VERSION_UNKNOWN:
  436. mLara->modelId = index;
  437. sModel->setAnimation(TR_ANIAMTION_RUN);
  438. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  439. r_model->tr4Overlay = false;
  440. break;
  441. }
  442. r_model->ponytailId = 0;
  443. }
  444. else
  445. {
  446. lara = false;
  447. r_model->ponytailId = -1;
  448. }
  449. // Animation
  450. a = moveable[index].animation;
  451. frame_offset = animation[a].frame_offset / 2;
  452. frame_step = animation[a].frame_size;
  453. int frame_cycle = 0;
  454. if (a >= (int)mTombRaider.NumAnimations())
  455. {
  456. a = mTombRaider.NumFrames() - frame_offset;
  457. }
  458. else
  459. {
  460. a = (animation[a].frame_offset / 2) - frame_offset;
  461. }
  462. if (frame_step != 0) // prevent divide-by-zero errors
  463. a /= frame_step;
  464. if (a != 0) // prevent divide-by-zero errors
  465. frame_offset += frame_step * (frame_cycle % a);
  466. if (a < 0)
  467. {
  468. //continue;
  469. getConsole().print("Invalid animation data for model %d", index);
  470. delete r_model;
  471. return;
  472. }
  473. //! \fixme Might be better UID for each model, but this seems to work well
  474. j = object_id;
  475. // We only want one copy of the skeletal model in memory
  476. unsigned int foundIndex;
  477. bool found = false;
  478. for (foundIndex = 0; foundIndex < cache.size(); foundIndex++) {
  479. if ((int)cache[foundIndex] == j) {
  480. found = true;
  481. break;
  482. }
  483. }
  484. if (!found)
  485. {
  486. sModel->model = r_model;
  487. getWorld().addEntity(thing);
  488. k = getWorld().addModel(r_model);
  489. cache.push_back(j);
  490. cache2.push_back(r_model);
  491. switch (mTombRaider.Engine())
  492. {
  493. case TR_VERSION_4:
  494. if (mLara && moveable[index].object_id == 30)
  495. {
  496. r_model->ponytailId = k;
  497. r_model->ponytailMeshId = moveable[index].starting_mesh;
  498. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  499. moveable[index].num_meshes : 0);
  500. r_model->ponytailAngle = -90.0f;
  501. r_model->ponytail[0] = -3;
  502. r_model->ponytail[1] = -22;
  503. r_model->ponytail[2] = -20;
  504. r_model->ponyOff = 40;
  505. r_model->ponyOff2 = 32;
  506. r_model->pigtails = false;
  507. // Try to guess pigtails by looking for certian num verts in head
  508. if (mesh[moveable[0].starting_mesh].num_vertices > 80)
  509. {
  510. r_model->pigtails = true;
  511. r_model->ponyOff -= 20;
  512. r_model->ponytail[1] -= 32;
  513. }
  514. getRender().setFlags(Render::fRenderPonytail);
  515. getConsole().print("Found known ponytail");
  516. }
  517. break; // ?
  518. case TR_VERSION_1:
  519. case TR_VERSION_2:
  520. case TR_VERSION_3:
  521. case TR_VERSION_5:
  522. case TR_VERSION_UNKNOWN:
  523. if (mLara && moveable[index].object_id == 2)
  524. {
  525. r_model->ponytailId = k;
  526. r_model->ponytailMeshId = moveable[index].starting_mesh;
  527. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  528. moveable[index].num_meshes : 0);
  529. r_model->ponytailAngle = -90.0f;
  530. r_model->ponytail[0] = 0;
  531. r_model->ponytail[1] = -20;
  532. r_model->ponytail[2] = -20;
  533. r_model->ponyOff = 40;
  534. r_model->ponyOff2 = 0;
  535. getRender().setFlags(Render::fRenderPonytail);
  536. getConsole().print("Found ponytail?");
  537. }
  538. break;
  539. }
  540. }
  541. else
  542. {
  543. // Already cached
  544. delete r_model;
  545. c_model = cache2[foundIndex];
  546. sModel->model = c_model;
  547. getWorld().addEntity(thing);
  548. getWorld().addModel(c_model);
  549. printf("c");
  550. return;
  551. }
  552. int aloop = mTombRaider.getNumAnimsForMoveable(index);
  553. #ifdef DEBUG_MOVEABLE
  554. printf("\nanimation = %i, num_animations = %i\n",
  555. moveable[index].animation, aloop);
  556. printf("\nitem[%i].flags = %i\nentity[%i]\n",
  557. i, item[i].flags, thing->id);
  558. #endif
  559. //a = moveable[index].animation;
  560. //frame_offset = animation[a].frame_offset / 2;
  561. //frame_step = animation[a].frame_size;
  562. for (; a < aloop; ++a,
  563. frame_offset = animation[a].frame_offset / 2,
  564. frame_step = animation[a].frame_size)
  565. {
  566. animation_frame = new animation_frame_t;
  567. r_model->animation.push_back(animation_frame);
  568. frame_count = (animation[a].frame_end - animation[a].frame_start) + 1;
  569. animation_frame->rate = animation[a].frame_rate;
  570. #ifdef DEBUG_MOVEABLE
  571. printf("animation[%i] state and unknowns = %i, %i, %i, %i, %i\n",
  572. a, animation[a].state_id, animation[a].unknown1,
  573. animation[a].unknown2, animation[a].unknown3,
  574. animation[a].unknown4);
  575. printf("animation[%i].frame_rate = %i\n",
  576. a, animation[a].frame_rate);
  577. printf("animation[%i].next_animation = %i\n",
  578. a, animation[a].next_animation);
  579. printf("animation[%i].frame_offset = %u\n",
  580. a, animation[a].frame_offset);
  581. printf("animation[%i].anim_command = %i\n",
  582. a, animation[a].anim_command);
  583. printf("animation[%i].num_anim_commands = %i\n",
  584. a, animation[a].num_anim_commands);
  585. printf("animation[%i].state_change_offset = %i\n",
  586. a, animation[a].state_change_offset);
  587. printf(" frame_offset = %u\n",
  588. frame_offset);
  589. #endif
  590. // Get all the frames for aniamtion
  591. for (f = 0; f < frame_count; ++f, frame_offset += frame_step)
  592. {
  593. // HACK: Lara's ObjectID is 315, but her meshes start at 0, so make a
  594. // quick substitution (so she doesn't appear as a bunch of thighs)
  595. if (index == 0 && mTombRaider.Engine() == TR_VERSION_3)
  596. {
  597. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  598. {
  599. if (moveable[j].object_id == 315)
  600. index = j;
  601. }
  602. }
  603. // Fix Lara in TR4
  604. if (index == 0 && mTombRaider.Engine() == TR_VERSION_4)
  605. {
  606. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  607. {
  608. // Body is ItemID 8, joints are ItemID 9
  609. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  610. if (moveable[j].object_id == 8)
  611. index = j;
  612. }
  613. }
  614. else if (moveable[index].object_id == 8 &&
  615. mTombRaider.Engine() == TR_VERSION_4)
  616. {
  617. // KLUDGE to do "skinning"
  618. index = 0;
  619. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  620. {
  621. // Body is ItemID 8, joints are ItemID 9
  622. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  623. if (moveable[j].object_id == 9)
  624. index = j;
  625. }
  626. }
  627. #ifdef DEBUG_MOVEABLE
  628. printf("animation[%i].boneframe[%u] = offset %u, step %i\n",
  629. a, f, frame_offset, frame_step);
  630. #endif
  631. // Mongoose 2002.08.15, Was
  632. // if (frame_offset + 8 > _tombraider.NumFrames())
  633. if (frame_offset > mTombRaider.NumFrames())
  634. {
  635. getConsole().print("WARNING: Bad animation frame %i > %i",
  636. frame_offset, mTombRaider.NumFrames());
  637. // Mongoose 2002.08.15, Attempt to skip more likely bad animation data
  638. getConsole().print("WARNING: Handling bad animation data...");
  639. return; //continue;
  640. }
  641. // Generate bone frames and tags per frame ////////////
  642. bone = new bone_frame_t;
  643. animation_frame->frame.push_back(bone);
  644. // Init translate for bone frame
  645. bone->pos[0] = (short)frame[frame_offset + 6];
  646. bone->pos[1] = (short)frame[frame_offset + 7];
  647. bone->pos[2] = (short)frame[frame_offset + 8];
  648. bone->yaw = yaw;
  649. //printf("%f %f %f\n", bone->pos[0], bone->pos[1], bone->pos[2]);
  650. l = 9; // First angle offset in this Frame
  651. // Run through the tag and calculate the rotation and offset
  652. for (j = 0; j < (int)moveable[index].num_meshes; ++j)
  653. {
  654. tag = new bone_tag_t;
  655. bone->tag.push_back(tag);
  656. tag->off[0] = 0.0;
  657. tag->off[1] = 0.0;
  658. tag->off[2] = 0.0;
  659. tag->flag = 0x00;
  660. tag->rot[0] = 0.0;
  661. tag->rot[1] = 0.0;
  662. tag->rot[2] = 0.0;
  663. tag->mesh = moveable[index].starting_mesh + j;
  664. // Setup offsets to produce skeletion
  665. if (j == 0)
  666. {
  667. // Since we use bone's offset, these aren't used
  668. tag->off[0] = 0.0;
  669. tag->off[1] = 0.0;
  670. tag->off[2] = 0.0;
  671. // Always push tag[0], this isn't really used either
  672. tag->flag = 0x02;
  673. }
  674. else // Nonprimary tag - position relative to first tag
  675. {
  676. int *tree;
  677. // Hack: moveable[index].mesh_tree is a byte offset
  678. // into mesh_tree[], so we have to convert to index
  679. tree = (int *)(void *)meshtree;
  680. mesh_tree = (tr2_meshtree_t *)&tree[moveable[index].mesh_tree
  681. + ((j - 1) * 4)];
  682. tag->off[0] = mesh_tree->x;
  683. tag->off[1] = mesh_tree->y;
  684. tag->off[2] = mesh_tree->z;
  685. tag->flag = (char)mesh_tree->flags;
  686. }
  687. // Setup tag rotations
  688. mTombRaider.computeRotationAngles(&frame, &frame_offset, &l,
  689. tag->rot, tag->rot+1, tag->rot+2);
  690. }
  691. }
  692. }
  693. if (i == skyMesh)
  694. {
  695. getRender().setSkyMesh(i, //moveable[i].starting_mesh,
  696. (mTombRaider.Engine() == TR_VERSION_2));
  697. }
  698. //printf(".");
  699. //fflush(stdout);
  700. }
  701. bool compareFaceTextureId(const void *voidA, const void *voidB)
  702. {
  703. texture_tri_t *a = (texture_tri_t *)voidA, *b = (texture_tri_t *)voidB;
  704. if (!a || !b)
  705. return false; // error really
  706. return (a->texture < b->texture);
  707. }
  708. #ifdef EXPERIMENTAL
  709. void Game::setupTextureColor(texture_tri_t *r_tri, float *colorf)
  710. {
  711. unsigned char color[4];
  712. unsigned int colorI;
  713. color[0] = (unsigned char)(colorf[0]*255.0f);
  714. color[1] = (unsigned char)(colorf[1]*255.0f);
  715. color[2] = (unsigned char)(colorf[2]*255.0f);
  716. color[3] = (unsigned char)(colorf[3]*255.0f);
  717. ((unsigned char *)(&colorI))[3] = color[0];
  718. ((unsigned char *)(&colorI))[2] = color[1];
  719. ((unsigned char *)(&colorI))[1] = color[2];
  720. ((unsigned char *)(&colorI))[0] = color[3];
  721. bool found = false;
  722. unsigned int foundIndex = 0;
  723. for (foundIndex = 0; foundIndex < gColorTextureHACK.size(); foundIndex++) {
  724. if (gColorTextureHACK[foundIndex] == colorI) {
  725. found = true;
  726. break;
  727. }
  728. }
  729. if (!found)
  730. {
  731. gColorTextureHACK.push_back(colorI);
  732. r_tri->texture = mTextureOffset + gColorTextureHACK.size();
  733. getRender().loadTexture(Texture::generateColorTexture(color, 32, 32),
  734. 32, 32,
  735. r_tri->texture);
  736. #ifdef DEBUG_COLOR_TEXTURE_GEN
  737. printf("Color 0x%02x%02x%02x%02x | 0x%08xto texture[%u]?\n",
  738. color[0], color[1], color[2], color[3], colorI,
  739. gColorTextureHACK.size());
  740. #endif
  741. }
  742. else
  743. {
  744. //printf("Color already loaded %i -> 0x%08x\n",
  745. // gColorTextureHACK.getCurrentIndex(),
  746. // gColorTextureHACK.current());
  747. r_tri->texture = mTextureOffset + foundIndex;
  748. }
  749. //r_tri->texture = white; // White texture
  750. }
  751. #endif
  752. void Game::processModels()
  753. {
  754. printf("Processing meshes: ");
  755. for (int index = 0; index < mTombRaider.getMeshCount(); index++) {
  756. int i, j, count, texture;
  757. int vertexIndices[6];
  758. float st[12];
  759. float color[4];
  760. unsigned short transparency;
  761. texture_tri_t *r_tri;
  762. // Assert common sense
  763. if (index < 0 || !mTombRaider.isMeshValid(index))
  764. {
  765. //! \fixme allow sparse lists with matching ids instead?
  766. getWorld().addMesh(NULL); // Filler, to make meshes array ids align
  767. //printf("x");
  768. //fflush(stdout);
  769. return;
  770. }
  771. #ifndef EXPERIMENTAL
  772. // WHITE texture id
  773. int white = 0;
  774. #endif
  775. model_mesh_t *mesh = new model_mesh_t;
  776. // Mongoose 2002.08.30, Testing support for 'shootable' models ( traceable )
  777. mTombRaider.getMeshCollisionInfo(index, mesh->center, &mesh->radius);
  778. //! \fixme Arrays don't work either =)
  779. // Mesh geometery, colors, etc
  780. mTombRaider.getMeshVertexArrays(index,
  781. &mesh->vertexCount, &mesh->vertices,
  782. &mesh->normalCount, &mesh->normals,
  783. &mesh->colorCount, &mesh->colors);
  784. // Textured Triangles
  785. count = mTombRaider.getMeshTexturedTriangleCount(index);
  786. mesh->texturedTriangles.reserve(count); // little faster
  787. for (i = 0; i < count; ++i)
  788. {
  789. r_tri = new texture_tri_t;
  790. mTombRaider.getMeshTexturedTriangle(index, i,
  791. r_tri->index,
  792. r_tri->st,
  793. &r_tri->texture,
  794. &r_tri->transparency);
  795. r_tri->texture += mTextureStart;
  796. // Add to face vector
  797. mesh->texturedTriangles.push_back(r_tri);
  798. }
  799. // Coloured Triangles
  800. count = mTombRaider.getMeshColoredTriangleCount(index);
  801. mesh->coloredTriangles.reserve(count); // little faster
  802. for (i = 0; i < count; i++)
  803. {
  804. r_tri = new texture_tri_t;
  805. mTombRaider.getMeshColoredTriangle(index, i,
  806. r_tri->index,
  807. color);
  808. r_tri->st[0] = color[0];
  809. r_tri->st[1] = color[1];
  810. r_tri->st[2] = color[2];
  811. r_tri->st[3] = color[3];
  812. r_tri->st[4] = 1.0;
  813. r_tri->st[5] = 1.0;
  814. #ifdef EXPERIMENTAL
  815. setupTextureColor(r_tri, color);
  816. #else
  817. r_tri->texture = white; // White texture
  818. #endif
  819. r_tri->transparency = 0;
  820. // Add to face vector
  821. mesh->coloredTriangles.push_back(r_tri);
  822. }
  823. // Textured Rectangles
  824. count = mTombRaider.getMeshTexturedRectangleCount(index);
  825. mesh->texturedRectangles.reserve(count*2); // little faster
  826. for (i = 0; i < count; ++i)
  827. {
  828. mTombRaider.getMeshTexturedRectangle(index, i,
  829. vertexIndices,
  830. st,
  831. &texture,
  832. &transparency);
  833. r_tri = new texture_tri_t;
  834. for (j = 0; j < 3; ++j)
  835. r_tri->index[j] = vertexIndices[j];
  836. for (j = 0; j < 6; ++j)
  837. r_tri->st[j] = st[j];
  838. r_tri->texture = texture + mTextureStart;
  839. r_tri->transparency = transparency;
  840. // Add to face vector
  841. mesh->texturedRectangles.push_back(r_tri);
  842. r_tri = new texture_tri_t;
  843. for (j = 3; j < 6; ++j)
  844. r_tri->index[j-3] = vertexIndices[j];
  845. for (j = 6; j < 12; ++j)
  846. r_tri->st[j-6] = st[j];
  847. r_tri->texture = texture + mTextureStart;
  848. r_tri->transparency = transparency;
  849. // Add to face vector
  850. mesh->texturedRectangles.push_back(r_tri);
  851. }
  852. // Coloured Rectangles
  853. count = mTombRaider.getMeshColoredRectangleCount(index);
  854. mesh->coloredRectangles.reserve(count*2); // little faster
  855. for (i = 0; i < count; ++i)
  856. {
  857. mTombRaider.getMeshColoredRectangle(index, i,
  858. vertexIndices,
  859. color);
  860. r_tri = new texture_tri_t;
  861. for (j = 0; j < 3; ++j)
  862. r_tri->index[j] = vertexIndices[j];
  863. //for (j = 0; j < 6; ++j)
  864. // r_tri->st[j] = st[j];
  865. r_tri->st[0] = color[0];
  866. r_tri->st[1] = color[1];
  867. r_tri->st[2] = color[2];
  868. r_tri->st[3] = color[3];
  869. r_tri->st[4] = 1.0;
  870. r_tri->st[5] = 1.0;
  871. #ifdef EXPERIMENTAL
  872. //for (j = 6; j < 12; ++j)
  873. // r_tri->st[j-6] = st[j];
  874. setupTextureColor(r_tri, color);
  875. #else
  876. r_tri->texture = white; // White texture
  877. #endif
  878. r_tri->transparency = 0;
  879. // Add to face vector
  880. mesh->coloredRectangles.push_back(r_tri);
  881. r_tri = new texture_tri_t;
  882. for (j = 3; j < 6; ++j)
  883. r_tri->index[j-3] = vertexIndices[j];
  884. //for (j = 6; j < 12; ++j)
  885. // r_tri->st[j-6] = st[j];
  886. r_tri->st[0] = color[0];
  887. r_tri->st[1] = color[1];
  888. r_tri->st[2] = color[2];
  889. r_tri->st[3] = color[3];
  890. r_tri->st[4] = 1.0;
  891. r_tri->st[5] = 1.0;
  892. #ifdef EXPERIMENTAL
  893. setupTextureColor(r_tri, color);
  894. #else
  895. r_tri->texture = white; // White texture
  896. #endif
  897. r_tri->transparency = 0;
  898. // Add to face vector
  899. mesh->coloredRectangles.push_back(r_tri);
  900. }
  901. // Sort faces by texture
  902. std::sort(mesh->texturedTriangles.begin(), mesh->texturedTriangles.end(), compareFaceTextureId);
  903. std::sort(mesh->coloredTriangles.begin(), mesh->coloredTriangles.end(), compareFaceTextureId);
  904. std::sort(mesh->texturedRectangles.begin(), mesh->texturedRectangles.end(), compareFaceTextureId);
  905. std::sort(mesh->coloredRectangles.begin(), mesh->coloredRectangles.end(), compareFaceTextureId);
  906. getWorld().addMesh(mesh);
  907. //printf(".");
  908. //fflush(stdout);
  909. }
  910. printf("Done! Found %d meshes.\n", mTombRaider.getMeshCount());
  911. }