Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Game.cpp 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  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 = 0;
  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. Entity &Game::getLara() {
  146. assert(mLara < getWorld().sizeEntity());
  147. return getWorld().getEntity(mLara);
  148. }
  149. void Game::processSprites() {
  150. printf("Processing sprites: ");
  151. for (int i = 0; i < (mTombRaider.NumItems() - 1); i++) {
  152. if ((mTombRaider.Engine() == TR_VERSION_1) && (mTombRaider.Item()[i].intensity1 == -1))
  153. continue;
  154. for (int j = 0; j < mTombRaider.NumSpriteSequences(); j++) {
  155. if (mTombRaider.SpriteSequence()[j].object_id == mTombRaider.Item()[i].object_id)
  156. getWorld().addSprite(*new SpriteSequence(mTombRaider, i, j));
  157. }
  158. }
  159. printf("Done! Found %d sprites.\n", mTombRaider.NumSpriteSequences());
  160. }
  161. void Game::processRooms() {
  162. printf("Processing rooms: ");
  163. for (int index = 0; index < mTombRaider.NumRooms(); index++)
  164. getWorld().addRoom(*new Room(mTombRaider, index));
  165. printf("Done! Found %d rooms.\n", mTombRaider.NumRooms());
  166. }
  167. void Game::processPakSounds()
  168. {
  169. unsigned char *riff;
  170. unsigned int riffSz;
  171. //tr2_sound_source_t *sound;
  172. //tr2_sound_details_t *detail;
  173. //float pos[3];
  174. unsigned int i;
  175. int id;
  176. /* detail
  177. short sample;
  178. short volume;
  179. short sound_range;
  180. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  181. // in this group, bits 0-1: channel number
  182. */
  183. printf("Processing pak sound files: ");
  184. for (i = 0; i < mTombRaider.getSoundSamplesCount(); ++i)
  185. {
  186. mTombRaider.getSoundSample(i, &riffSz, &riff);
  187. getSound().addWave(riff, riffSz, &id, Sound::SoundFlagsNone);
  188. //if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  189. //{
  190. //m_testSFX = id;
  191. //}
  192. delete [] riff;
  193. // sound[i].sound_id; // internal sound index
  194. // sound[i].flags; // 0x40, 0x80, or 0xc0
  195. //pos[0] = sound[i].x;
  196. //pos[1] = sound[i].y;
  197. //pos[2] = sound[i].z;
  198. //getSound().SourceAt(id, pos);
  199. //printf(".");
  200. //fflush(stdout);
  201. }
  202. printf("Done! Found %u files.\n", mTombRaider.getSoundSamplesCount());
  203. }
  204. void Game::processTextures()
  205. {
  206. unsigned char *image;
  207. unsigned char *bumpmap;
  208. int i;
  209. printf("Processing TR textures: ");
  210. //if ( mTombRaider.getNumBumpMaps())
  211. // gBumpMapStart = mTombRaider.NumTextures();
  212. for (i = 0; i < mTombRaider.NumTextures(); ++i)
  213. {
  214. mTombRaider.Texture(i, &image, &bumpmap);
  215. // Overwrite any previous level textures on load
  216. getRender().loadTexture(image, 256, 256, (mTextureStart - 1) + i);
  217. #ifdef MULTITEXTURE
  218. gMapTex2Bump[(mTextureStart - 1) + i] = -1;
  219. #endif
  220. if (bumpmap)
  221. {
  222. #ifdef MULTITEXTURE
  223. gMapTex2Bump[(mTextureStart - 1) + i] = (mTextureStart - 1) + i +
  224. mTombRaider.NumTextures();
  225. #endif
  226. getRender().loadTexture(bumpmap, 256, 256, (mTextureStart - 1) + i +
  227. mTombRaider.NumTextures());
  228. }
  229. if (image)
  230. delete [] image;
  231. if (bumpmap)
  232. delete [] bumpmap;
  233. //printf(".");
  234. //fflush(stdout);
  235. }
  236. mTextureOffset = (mTextureStart - 1) + mTombRaider.NumTextures();
  237. printf("Done! Found %d textures.\n", mTombRaider.NumTextures());
  238. }
  239. void Game::processMoveables()
  240. {
  241. unsigned int statCount = 0;
  242. tr2_moveable_t *moveable = mTombRaider.Moveable();
  243. tr2_item_t *item = mTombRaider.Item();
  244. tr2_sprite_sequence_t *sprite_sequence = mTombRaider.SpriteSequence();
  245. printf("Processing skeletal models: ");
  246. for (int i = 0; i < mTombRaider.NumItems(); ++i)
  247. {
  248. int j;
  249. int object_id = item[i].object_id;
  250. // It may not be a moveable, test for sprite
  251. if (!(mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1)) {
  252. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j) {
  253. if (sprite_sequence[j].object_id == object_id)
  254. break;
  255. }
  256. // It's not a moveable, skip sprite
  257. if (j < (int)mTombRaider.NumSpriteSequences())
  258. continue;
  259. }
  260. for (j = 0; j < (int)mTombRaider.NumMoveables(); ++j) {
  261. if ((int)moveable[j].object_id == object_id)
  262. break;
  263. }
  264. // It's not a moveable or even a sprite? Skip unknown
  265. if (j == (int)mTombRaider.NumMoveables())
  266. continue;
  267. processMoveable(j, i, object_id);
  268. statCount++;
  269. }
  270. /*
  271. // Get models that aren't items
  272. for (int i = 0; i < mTombRaider.NumMoveables(); ++i)
  273. {
  274. switch ((int)moveable[i].object_id)
  275. {
  276. case 30:
  277. case 2: // Which tr needs this as model again?
  278. processMoveable(i, i, (int)moveable[i].object_id);
  279. break;
  280. default:
  281. switch (mTombRaider.Engine())
  282. {
  283. case TR_VERSION_1:
  284. switch ((int)moveable[i].object_id)
  285. {
  286. case TombRaider1::LaraMutant:
  287. processMoveable(i, i, (int)moveable[i].object_id);
  288. break;
  289. }
  290. break;
  291. case TR_VERSION_4:
  292. switch ((int)moveable[i].object_id)
  293. {
  294. case TR4_PISTOLS_ANIM:
  295. case TR4_UZI_ANIM:
  296. case TR4_SHOTGUN_ANIM:
  297. case TR4_CROSSBOW_ANIM:
  298. case TR4_GRENADE_GUN_ANIM:
  299. case TR4_SIXSHOOTER_ANIM:
  300. processMoveable(i, i, (int)moveable[i].object_id);
  301. break;
  302. }
  303. break;
  304. case TR_VERSION_2:
  305. case TR_VERSION_3:
  306. case TR_VERSION_5:
  307. case TR_VERSION_UNKNOWN:
  308. break;
  309. }
  310. }
  311. }
  312. */
  313. printf("Done! Found %d models.\n", mTombRaider.NumMoveables() + statCount);
  314. }
  315. // index moveable, i item, sometimes both moveable
  316. // object_id of item or moveable
  317. void Game::processMoveable(int index, int i, int object_id)
  318. {
  319. //std::vector<skeletal_model_t *> &cache2
  320. //std::vector<unsigned int> &cache
  321. bool cached = false;
  322. for (unsigned int mod = 0; mod < getWorld().sizeSkeletalModel(); mod++) {
  323. if (getWorld().getSkeletalModel(mod).getId() == moveable[index].object_id) {
  324. cached = true;
  325. break;
  326. }
  327. }
  328. if (!cached) {
  329. getWorld().addSkeletalModel(*new SkeletalModel(mTombRaider /* ... */));
  330. }
  331. getWorld().addEntity(*new Entity(mTombRaider, /* ... */ mod));
  332. // This creates both Entity and SkeletalModel
  333. // Basic Idea:
  334. // - Move animation state from SkeletalModel into Entity
  335. // - Check if skeletal model is already stored
  336. // - If so tell new Entity to reuse
  337. // - Else store new skeletal model, tell new entity to use this one
  338. int j, k, a, frame_step;
  339. unsigned int l, frame_offset, frame_count, f;
  340. unsigned short *frame = mTombRaider.Frame();
  341. tr2_moveable_t *moveable = mTombRaider.Moveable();
  342. tr2_meshtree_t *meshtree = mTombRaider.MeshTree();
  343. tr2_mesh_t *mesh = mTombRaider.Mesh();
  344. tr2_item_t *item = mTombRaider.Item();
  345. tr2_animation_t *animation = mTombRaider.Animation();
  346. float yaw = ((item[i].angle >> 14) & 0x03);
  347. yaw *= 90;
  348. entity_t *thing = new entity_t;
  349. thing->pos[0] = item[i].x;
  350. thing->pos[1] = item[i].y;
  351. thing->pos[2] = item[i].z;
  352. thing->angles[1] = yaw;
  353. thing->objectId = moveable[index].object_id;
  354. SkeletalModel *sModel = new SkeletalModel();
  355. getRender().addSkeletalModel(sModel);
  356. thing->tmpHook = sModel; // temp hack to keep a running version during refactoring
  357. if (mTombRaider.Engine() == TR_VERSION_1)
  358. {
  359. switch (thing->objectId)
  360. {
  361. case TombRaider1::Wolf:
  362. thing->state = TombRaider1::WolfState_Lying;
  363. sModel->setAnimation(3);
  364. sModel->setFrame(0);
  365. break;
  366. }
  367. }
  368. //! \fixme Check here and see if we already have one for object_id later
  369. // if (getWorld().isCachedSkeletalModel(moveable[index].object_id))
  370. // {
  371. // thing->modelId = getRender().add(sModel);
  372. // return;
  373. // }
  374. skeletal_model_t *r_model = new skeletal_model_t;
  375. r_model->id = moveable[index].object_id;
  376. // Gather more info if this is lara
  377. if (moveable[index].object_id == 0)
  378. {
  379. mLara = thing; // Mongoose 2002.03.22, Cheap hack for now
  380. sModel->setAnimation(TR_ANIAMTION_RUN);
  381. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  382. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  383. r_model->tr4Overlay = (mTombRaider.Engine() == TR_VERSION_4);
  384. r_model->ponytailId = 0;
  385. }
  386. else
  387. {
  388. r_model->ponytailId = -1;
  389. }
  390. // Animation
  391. a = moveable[index].animation;
  392. frame_offset = animation[a].frame_offset / 2;
  393. frame_step = animation[a].frame_size;
  394. if (a >= (int)mTombRaider.NumAnimations())
  395. {
  396. a = mTombRaider.NumFrames() - frame_offset;
  397. }
  398. else
  399. {
  400. a = (animation[a].frame_offset / 2) - frame_offset;
  401. }
  402. if (frame_step != 0) // prevent divide-by-zero errors
  403. a /= frame_step;
  404. if (a < 0)
  405. {
  406. //continue;
  407. getConsole().print("Invalid animation data for model %d", index);
  408. delete r_model;
  409. return; // leaking thing here!
  410. }
  411. //! \fixme Might be better UID for each model, but this seems to work well
  412. j = object_id;
  413. // We only want one copy of the skeletal model in memory
  414. unsigned int foundIndex;
  415. bool found = false;
  416. for (foundIndex = 0; foundIndex < cache.size(); foundIndex++) {
  417. if ((int)cache[foundIndex] == j) {
  418. found = true;
  419. break;
  420. }
  421. }
  422. if (!found)
  423. {
  424. sModel->model = r_model;
  425. getWorld().addEntity(thing);
  426. k = getWorld().addModel(r_model);
  427. cache.push_back(j);
  428. cache2.push_back(r_model);
  429. switch (mTombRaider.Engine())
  430. {
  431. case TR_VERSION_4:
  432. if (mLara && moveable[index].object_id == 30)
  433. {
  434. r_model->ponytailId = k;
  435. r_model->ponytailMeshId = moveable[index].starting_mesh;
  436. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  437. moveable[index].num_meshes : 0);
  438. r_model->ponytailAngle = -90.0f;
  439. r_model->ponytail[0] = -3;
  440. r_model->ponytail[1] = -22;
  441. r_model->ponytail[2] = -20;
  442. r_model->ponyOff = 40;
  443. r_model->ponyOff2 = 32;
  444. r_model->pigtails = false;
  445. // Try to guess pigtails by looking for certian num verts in head
  446. if (mesh[moveable[0].starting_mesh].num_vertices > 80)
  447. {
  448. r_model->pigtails = true;
  449. r_model->ponyOff -= 20;
  450. r_model->ponytail[1] -= 32;
  451. }
  452. getRender().setFlags(Render::fRenderPonytail);
  453. getConsole().print("Found known ponytail");
  454. }
  455. break; // ?
  456. case TR_VERSION_1:
  457. case TR_VERSION_2:
  458. case TR_VERSION_3:
  459. case TR_VERSION_5:
  460. case TR_VERSION_UNKNOWN:
  461. if (mLara && moveable[index].object_id == 2)
  462. {
  463. r_model->ponytailId = k;
  464. r_model->ponytailMeshId = moveable[index].starting_mesh;
  465. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  466. moveable[index].num_meshes : 0);
  467. r_model->ponytailAngle = -90.0f;
  468. r_model->ponytail[0] = 0;
  469. r_model->ponytail[1] = -20;
  470. r_model->ponytail[2] = -20;
  471. r_model->ponyOff = 40;
  472. r_model->ponyOff2 = 0;
  473. getRender().setFlags(Render::fRenderPonytail);
  474. getConsole().print("Found ponytail?");
  475. }
  476. break;
  477. }
  478. }
  479. else
  480. {
  481. // Already cached
  482. delete r_model;
  483. r_model = cache2[foundIndex];
  484. sModel->model = r_model;
  485. getWorld().addEntity(thing);
  486. getWorld().addModel(r_model);
  487. printf("c");
  488. return;
  489. }
  490. int aloop = mTombRaider.getNumAnimsForMoveable(index);
  491. //a = moveable[index].animation;
  492. //frame_offset = animation[a].frame_offset / 2;
  493. //frame_step = animation[a].frame_size;
  494. for (; a < aloop; ++a,
  495. frame_offset = animation[a].frame_offset / 2,
  496. frame_step = animation[a].frame_size)
  497. {
  498. animation_frame_t *animation_frame = new animation_frame_t;
  499. r_model->animation.push_back(animation_frame);
  500. frame_count = (animation[a].frame_end - animation[a].frame_start) + 1;
  501. animation_frame->rate = animation[a].frame_rate;
  502. // Get all the frames for aniamtion
  503. for (f = 0; f < frame_count; ++f, frame_offset += frame_step)
  504. {
  505. // HACK: Lara's ObjectID is 315, but her meshes start at 0, so make a
  506. // quick substitution (so she doesn't appear as a bunch of thighs)
  507. if (index == 0 && mTombRaider.Engine() == TR_VERSION_3)
  508. {
  509. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  510. {
  511. if (moveable[j].object_id == 315)
  512. index = j;
  513. }
  514. }
  515. // Fix Lara in TR4
  516. if (index == 0 && mTombRaider.Engine() == TR_VERSION_4)
  517. {
  518. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  519. {
  520. // Body is ItemID 8, joints are ItemID 9
  521. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  522. if (moveable[j].object_id == 8)
  523. index = j;
  524. }
  525. }
  526. else if (moveable[index].object_id == 8 &&
  527. mTombRaider.Engine() == TR_VERSION_4)
  528. {
  529. // KLUDGE to do "skinning"
  530. index = 0;
  531. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  532. {
  533. // Body is ItemID 8, joints are ItemID 9
  534. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  535. if (moveable[j].object_id == 9)
  536. index = j;
  537. }
  538. }
  539. // Mongoose 2002.08.15, Was
  540. // if (frame_offset + 8 > _tombraider.NumFrames())
  541. if (frame_offset > mTombRaider.NumFrames())
  542. {
  543. getConsole().print("WARNING: Bad animation frame %i > %i",
  544. frame_offset, mTombRaider.NumFrames());
  545. return; //continue;
  546. }
  547. // Generate bone frames and tags per frame ////////////
  548. bone_frame_t *bone = new bone_frame_t;
  549. animation_frame->frame.push_back(bone);
  550. // Init translate for bone frame
  551. bone->pos[0] = (short)frame[frame_offset + 6];
  552. bone->pos[1] = (short)frame[frame_offset + 7];
  553. bone->pos[2] = (short)frame[frame_offset + 8];
  554. bone->yaw = yaw;
  555. //printf("%f %f %f\n", bone->pos[0], bone->pos[1], bone->pos[2]);
  556. l = 9; // First angle offset in this Frame
  557. // Run through the tag and calculate the rotation and offset
  558. for (j = 0; j < (int)moveable[index].num_meshes; ++j)
  559. {
  560. bone_tag_t *tag = new bone_tag_t;
  561. bone->tag.push_back(tag);
  562. tag->off[0] = 0.0;
  563. tag->off[1] = 0.0;
  564. tag->off[2] = 0.0;
  565. tag->flag = 0x00;
  566. tag->rot[0] = 0.0;
  567. tag->rot[1] = 0.0;
  568. tag->rot[2] = 0.0;
  569. tag->mesh = moveable[index].starting_mesh + j;
  570. // Setup offsets to produce skeletion
  571. if (j == 0)
  572. {
  573. // Always push tag[0], this isn't really used either
  574. tag->flag = 0x02;
  575. }
  576. else // Nonprimary tag - position relative to first tag
  577. {
  578. int *tree;
  579. // Hack: moveable[index].mesh_tree is a byte offset
  580. // into mesh_tree[], so we have to convert to index
  581. tree = (int *)(void *)meshtree;
  582. tr2_meshtree_t *mesh_tree = (tr2_meshtree_t *)&tree[moveable[index].mesh_tree
  583. + ((j - 1) * 4)];
  584. tag->off[0] = mesh_tree->x;
  585. tag->off[1] = mesh_tree->y;
  586. tag->off[2] = mesh_tree->z;
  587. tag->flag = (char)mesh_tree->flags;
  588. }
  589. // Setup tag rotations
  590. mTombRaider.computeRotationAngles(&frame, &frame_offset, &l,
  591. tag->rot, tag->rot+1, tag->rot+2);
  592. }
  593. }
  594. }
  595. if (i == mTombRaider.getSkyModelId())
  596. getRender().setSkyMesh(i, //moveable[i].starting_mesh,
  597. (mTombRaider.Engine() == TR_VERSION_2));
  598. }
  599. bool compareFaceTextureId(const void *voidA, const void *voidB)
  600. {
  601. texture_tri_t *a = (texture_tri_t *)voidA, *b = (texture_tri_t *)voidB;
  602. if (!a || !b)
  603. return false; // error really
  604. return (a->texture < b->texture);
  605. }
  606. #ifdef EXPERIMENTAL
  607. void Game::setupTextureColor(texture_tri_t *r_tri, float *colorf)
  608. {
  609. unsigned char color[4];
  610. unsigned int colorI;
  611. color[0] = (unsigned char)(colorf[0]*255.0f);
  612. color[1] = (unsigned char)(colorf[1]*255.0f);
  613. color[2] = (unsigned char)(colorf[2]*255.0f);
  614. color[3] = (unsigned char)(colorf[3]*255.0f);
  615. ((unsigned char *)(&colorI))[3] = color[0];
  616. ((unsigned char *)(&colorI))[2] = color[1];
  617. ((unsigned char *)(&colorI))[1] = color[2];
  618. ((unsigned char *)(&colorI))[0] = color[3];
  619. bool found = false;
  620. unsigned int foundIndex = 0;
  621. for (foundIndex = 0; foundIndex < gColorTextureHACK.size(); foundIndex++) {
  622. if (gColorTextureHACK[foundIndex] == colorI) {
  623. found = true;
  624. break;
  625. }
  626. }
  627. if (!found)
  628. {
  629. gColorTextureHACK.push_back(colorI);
  630. r_tri->texture = mTextureOffset + gColorTextureHACK.size();
  631. getRender().loadTexture(Texture::generateColorTexture(color, 32, 32),
  632. 32, 32, r_tri->texture);
  633. }
  634. else
  635. {
  636. //printf("Color already loaded %i -> 0x%08x\n",
  637. // gColorTextureHACK.getCurrentIndex(),
  638. // gColorTextureHACK.current());
  639. r_tri->texture = mTextureOffset + foundIndex;
  640. }
  641. //r_tri->texture = white; // White texture
  642. }
  643. #endif
  644. void Game::processModels()
  645. {
  646. printf("Processing meshes: ");
  647. for (int index = 0; index < mTombRaider.getMeshCount(); index++) {
  648. int i, j, count, texture;
  649. int vertexIndices[6];
  650. float st[12];
  651. float color[4];
  652. unsigned short transparency;
  653. texture_tri_t *r_tri;
  654. // Assert common sense
  655. if (index < 0 || !mTombRaider.isMeshValid(index))
  656. {
  657. //! \fixme allow sparse lists with matching ids instead?
  658. getWorld().addMesh(NULL); // Filler, to make meshes array ids align
  659. //printf("x");
  660. //fflush(stdout);
  661. return;
  662. }
  663. #ifndef EXPERIMENTAL
  664. // WHITE texture id
  665. int white = 0;
  666. #endif
  667. model_mesh_t *mesh = new model_mesh_t;
  668. // Mongoose 2002.08.30, Testing support for 'shootable' models ( traceable )
  669. mTombRaider.getMeshCollisionInfo(index, mesh->center, &mesh->radius);
  670. //! \fixme Arrays don't work either =)
  671. // Mesh geometery, colors, etc
  672. mTombRaider.getMeshVertexArrays(index,
  673. &mesh->vertexCount, &mesh->vertices,
  674. &mesh->normalCount, &mesh->normals,
  675. &mesh->colorCount, &mesh->colors);
  676. // Textured Triangles
  677. count = mTombRaider.getMeshTexturedTriangleCount(index);
  678. mesh->texturedTriangles.reserve(count); // little faster
  679. for (i = 0; i < count; ++i)
  680. {
  681. r_tri = new texture_tri_t;
  682. mTombRaider.getMeshTexturedTriangle(index, i,
  683. r_tri->index,
  684. r_tri->st,
  685. &r_tri->texture,
  686. &r_tri->transparency);
  687. r_tri->texture += mTextureStart;
  688. // Add to face vector
  689. mesh->texturedTriangles.push_back(r_tri);
  690. }
  691. // Coloured Triangles
  692. count = mTombRaider.getMeshColoredTriangleCount(index);
  693. mesh->coloredTriangles.reserve(count); // little faster
  694. for (i = 0; i < count; i++)
  695. {
  696. r_tri = new texture_tri_t;
  697. mTombRaider.getMeshColoredTriangle(index, i,
  698. r_tri->index,
  699. color);
  700. r_tri->st[0] = color[0];
  701. r_tri->st[1] = color[1];
  702. r_tri->st[2] = color[2];
  703. r_tri->st[3] = color[3];
  704. r_tri->st[4] = 1.0;
  705. r_tri->st[5] = 1.0;
  706. #ifdef EXPERIMENTAL
  707. setupTextureColor(r_tri, color);
  708. #else
  709. r_tri->texture = white; // White texture
  710. #endif
  711. r_tri->transparency = 0;
  712. // Add to face vector
  713. mesh->coloredTriangles.push_back(r_tri);
  714. }
  715. // Textured Rectangles
  716. count = mTombRaider.getMeshTexturedRectangleCount(index);
  717. mesh->texturedRectangles.reserve(count*2); // little faster
  718. for (i = 0; i < count; ++i)
  719. {
  720. mTombRaider.getMeshTexturedRectangle(index, i,
  721. vertexIndices,
  722. st,
  723. &texture,
  724. &transparency);
  725. r_tri = new texture_tri_t;
  726. for (j = 0; j < 3; ++j)
  727. r_tri->index[j] = vertexIndices[j];
  728. for (j = 0; j < 6; ++j)
  729. r_tri->st[j] = st[j];
  730. r_tri->texture = texture + mTextureStart;
  731. r_tri->transparency = transparency;
  732. // Add to face vector
  733. mesh->texturedRectangles.push_back(r_tri);
  734. r_tri = new texture_tri_t;
  735. for (j = 3; j < 6; ++j)
  736. r_tri->index[j-3] = vertexIndices[j];
  737. for (j = 6; j < 12; ++j)
  738. r_tri->st[j-6] = st[j];
  739. r_tri->texture = texture + mTextureStart;
  740. r_tri->transparency = transparency;
  741. // Add to face vector
  742. mesh->texturedRectangles.push_back(r_tri);
  743. }
  744. // Coloured Rectangles
  745. count = mTombRaider.getMeshColoredRectangleCount(index);
  746. mesh->coloredRectangles.reserve(count*2); // little faster
  747. for (i = 0; i < count; ++i)
  748. {
  749. mTombRaider.getMeshColoredRectangle(index, i,
  750. vertexIndices,
  751. color);
  752. r_tri = new texture_tri_t;
  753. for (j = 0; j < 3; ++j)
  754. r_tri->index[j] = vertexIndices[j];
  755. //for (j = 0; j < 6; ++j)
  756. // r_tri->st[j] = st[j];
  757. r_tri->st[0] = color[0];
  758. r_tri->st[1] = color[1];
  759. r_tri->st[2] = color[2];
  760. r_tri->st[3] = color[3];
  761. r_tri->st[4] = 1.0;
  762. r_tri->st[5] = 1.0;
  763. #ifdef EXPERIMENTAL
  764. //for (j = 6; j < 12; ++j)
  765. // r_tri->st[j-6] = st[j];
  766. setupTextureColor(r_tri, color);
  767. #else
  768. r_tri->texture = white; // White texture
  769. #endif
  770. r_tri->transparency = 0;
  771. // Add to face vector
  772. mesh->coloredRectangles.push_back(r_tri);
  773. r_tri = new texture_tri_t;
  774. for (j = 3; j < 6; ++j)
  775. r_tri->index[j-3] = vertexIndices[j];
  776. //for (j = 6; j < 12; ++j)
  777. // r_tri->st[j-6] = st[j];
  778. r_tri->st[0] = color[0];
  779. r_tri->st[1] = color[1];
  780. r_tri->st[2] = color[2];
  781. r_tri->st[3] = color[3];
  782. r_tri->st[4] = 1.0;
  783. r_tri->st[5] = 1.0;
  784. #ifdef EXPERIMENTAL
  785. setupTextureColor(r_tri, color);
  786. #else
  787. r_tri->texture = white; // White texture
  788. #endif
  789. r_tri->transparency = 0;
  790. // Add to face vector
  791. mesh->coloredRectangles.push_back(r_tri);
  792. }
  793. // Sort faces by texture
  794. std::sort(mesh->texturedTriangles.begin(), mesh->texturedTriangles.end(), compareFaceTextureId);
  795. std::sort(mesh->coloredTriangles.begin(), mesh->coloredTriangles.end(), compareFaceTextureId);
  796. std::sort(mesh->texturedRectangles.begin(), mesh->texturedRectangles.end(), compareFaceTextureId);
  797. std::sort(mesh->coloredRectangles.begin(), mesh->coloredRectangles.end(), compareFaceTextureId);
  798. getWorld().addMesh(mesh);
  799. }
  800. printf("Done! Found %d meshes.\n", mTombRaider.getMeshCount());
  801. }