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 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /*!
  2. * \file src/Game.cpp
  3. * \brief Game abstraction
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include <map>
  9. #include <cstdlib>
  10. #include "global.h"
  11. #include "Console.h"
  12. #include "Game.h"
  13. #include "OpenRaider.h"
  14. #include "Sound.h"
  15. #include "utils/strings.h"
  16. #include "games/TombRaider1.h"
  17. #ifdef EXPERIMENTAL
  18. std::vector<unsigned int> gColorTextureHACK;
  19. #endif
  20. #ifdef MULTITEXTURE
  21. std::map<int, int> gMapTex2Bump;
  22. #endif
  23. Game::Game() {
  24. mLoaded = false;
  25. mName = NULL;
  26. mLara = -1;
  27. mTextureStart = 0;
  28. mTextureOffset = 0;
  29. }
  30. Game::~Game() {
  31. destroy();
  32. }
  33. unsigned int Game::getTextureStart() {
  34. return mTextureStart;
  35. }
  36. unsigned int Game::getTextureOffset() {
  37. return mTextureOffset;
  38. }
  39. int Game::initialize() {
  40. // Enable Renderer
  41. mTextureStart = getRender().initTextures(getOpenRaider().mDataDir);
  42. getRender().setMode(Render::modeLoadScreen);
  43. return 0;
  44. }
  45. void Game::destroy() {
  46. if (mName)
  47. delete [] mName;
  48. mName = NULL;
  49. mLoaded = false;
  50. mLara = -1;
  51. getRender().setMode(Render::modeDisabled);
  52. getWorld().destroy();
  53. getRender().ClearWorld();
  54. getSound().clear(); // Remove all previously loaded sounds
  55. }
  56. bool Game::isLoaded() {
  57. return mLoaded;
  58. }
  59. int Game::loadLevel(const char *level) {
  60. if (mLoaded)
  61. destroy();
  62. mName = bufferString("%s", level);
  63. // Load the level pak into TombRaider
  64. getConsole().print("Loading %s", mName);
  65. int error = mTombRaider.Load(mName);
  66. if (error != 0) {
  67. return error;
  68. }
  69. // If required, load the external sound effect file MAIN.SFX into TombRaider
  70. if ((mTombRaider.getEngine() == TR_VERSION_2) || (mTombRaider.getEngine() == TR_VERSION_3)) {
  71. char *tmp = bufferString("%sMAIN.SFX", level); // Ensure theres enough space
  72. size_t length = strlen(tmp);
  73. size_t dir = 0;
  74. for (int i = length - 1; i >= 0; i--) {
  75. if ((tmp[i] == '/') || (tmp[i] == '\\')) {
  76. dir = i + 1; // Find where the filename (bla.tr2) starts
  77. break;
  78. }
  79. }
  80. strcpy(tmp + dir, "MAIN.SFX"); // overwrite the name itself with MAIN.SFX
  81. tmp[dir + 8] = '\0';
  82. error = mTombRaider.loadSFX(tmp);
  83. if (error != 0) {
  84. getConsole().print("Could not load %s", tmp);
  85. }
  86. delete [] tmp;
  87. }
  88. // Process data
  89. processTextures();
  90. processRooms();
  91. processModels();
  92. processSprites();
  93. processMoveables();
  94. processPakSounds();
  95. // Free pak file
  96. mTombRaider.reset();
  97. // Check if the level contains Lara
  98. if (mLara == -1) {
  99. getConsole().print("Can't find Lara entity in level pak!");
  100. return -1;
  101. }
  102. mLoaded = true;
  103. getRender().setMode(Render::modeVertexLight);
  104. return 0;
  105. }
  106. void Game::handleAction(ActionEvents action, bool isFinished) {
  107. if (mLoaded) {
  108. if (action == forwardAction) {
  109. getLara().move('f');
  110. } else if (action == backwardAction) {
  111. getLara().move('b');
  112. } else if (action == leftAction) {
  113. getLara().move('l');
  114. } else if (action == rightAction) {
  115. getLara().move('r');
  116. }
  117. }
  118. }
  119. void Game::handleMouseMotion(int xrel, int yrel) {
  120. if (mLoaded) {
  121. // Move Camera on X Axis
  122. if (xrel > 0)
  123. while (xrel-- > 0)
  124. getCamera().command(CAMERA_ROTATE_RIGHT);
  125. else if (xrel < 0)
  126. while (xrel++ < 0)
  127. getCamera().command(CAMERA_ROTATE_LEFT);
  128. // Move Camera on Y Axis
  129. if (yrel > 0)
  130. while (yrel-- > 0)
  131. getCamera().command(CAMERA_ROTATE_UP);
  132. else if (yrel < 0)
  133. while (yrel++ < 0)
  134. getCamera().command(CAMERA_ROTATE_DOWN);
  135. // Fix Laras rotation
  136. getLara().setAngles(getCamera().getRadianYaw(), getCamera().getRadianPitch());
  137. }
  138. }
  139. Entity &Game::getLara() {
  140. assert(mLara >= 0);
  141. assert(mLara < (int)getWorld().sizeEntity());
  142. return getWorld().getEntity(mLara);
  143. }
  144. void Game::processSprites() {
  145. printf("Processing sprites: ");
  146. for (int i = 0; i < (mTombRaider.NumItems() - 1); i++) {
  147. if ((mTombRaider.Engine() == TR_VERSION_1) && (mTombRaider.Item()[i].intensity1 == -1))
  148. continue;
  149. for (int j = 0; j < mTombRaider.NumSpriteSequences(); j++) {
  150. if (mTombRaider.SpriteSequence()[j].object_id == mTombRaider.Item()[i].object_id)
  151. getWorld().addSprite(*new SpriteSequence(mTombRaider, i, j));
  152. }
  153. }
  154. printf("Done! Found %d sprites.\n", mTombRaider.NumSpriteSequences());
  155. }
  156. void Game::processRooms() {
  157. printf("Processing rooms: ");
  158. for (int index = 0; index < mTombRaider.NumRooms(); index++)
  159. getWorld().addRoom(*new Room(mTombRaider, index));
  160. printf("Done! Found %d rooms.\n", mTombRaider.NumRooms());
  161. }
  162. void Game::processPakSounds()
  163. {
  164. unsigned char *riff;
  165. unsigned int riffSz;
  166. //tr2_sound_source_t *sound;
  167. //tr2_sound_details_t *detail;
  168. //float pos[3];
  169. unsigned int i;
  170. int id;
  171. /* detail
  172. short sample;
  173. short volume;
  174. short sound_range;
  175. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  176. // in this group, bits 0-1: channel number
  177. */
  178. printf("Processing pak sound files: ");
  179. for (i = 0; i < mTombRaider.getSoundSamplesCount(); ++i)
  180. {
  181. mTombRaider.getSoundSample(i, &riffSz, &riff);
  182. getSound().addWave(riff, riffSz, &id, Sound::SoundFlagsNone);
  183. //if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  184. //{
  185. //m_testSFX = id;
  186. //}
  187. delete [] riff;
  188. // sound[i].sound_id; // internal sound index
  189. // sound[i].flags; // 0x40, 0x80, or 0xc0
  190. //pos[0] = sound[i].x;
  191. //pos[1] = sound[i].y;
  192. //pos[2] = sound[i].z;
  193. //getSound().SourceAt(id, pos);
  194. //printf(".");
  195. //fflush(stdout);
  196. }
  197. printf("Done! Found %u files.\n", mTombRaider.getSoundSamplesCount());
  198. }
  199. void Game::processTextures()
  200. {
  201. unsigned char *image;
  202. unsigned char *bumpmap;
  203. int i;
  204. printf("Processing TR textures: ");
  205. //if ( mTombRaider.getNumBumpMaps())
  206. // gBumpMapStart = mTombRaider.NumTextures();
  207. for (i = 0; i < mTombRaider.NumTextures(); ++i)
  208. {
  209. mTombRaider.Texture(i, &image, &bumpmap);
  210. // Overwrite any previous level textures on load
  211. getRender().loadTexture(image, 256, 256, (mTextureStart - 1) + i);
  212. #ifdef MULTITEXTURE
  213. gMapTex2Bump[(mTextureStart - 1) + i] = -1;
  214. #endif
  215. if (bumpmap)
  216. {
  217. #ifdef MULTITEXTURE
  218. gMapTex2Bump[(mTextureStart - 1) + i] = (mTextureStart - 1) + i +
  219. mTombRaider.NumTextures();
  220. #endif
  221. getRender().loadTexture(bumpmap, 256, 256, (mTextureStart - 1) + i +
  222. mTombRaider.NumTextures());
  223. }
  224. if (image)
  225. delete [] image;
  226. if (bumpmap)
  227. delete [] bumpmap;
  228. //printf(".");
  229. //fflush(stdout);
  230. }
  231. mTextureOffset = (mTextureStart - 1) + mTombRaider.NumTextures();
  232. printf("Done! Found %d textures.\n", mTombRaider.NumTextures());
  233. }
  234. void Game::processMoveables()
  235. {
  236. unsigned int statCount = 0;
  237. tr2_moveable_t *moveable = mTombRaider.Moveable();
  238. tr2_item_t *item = mTombRaider.Item();
  239. tr2_sprite_sequence_t *sprite_sequence = mTombRaider.SpriteSequence();
  240. printf("Processing skeletal models: ");
  241. for (int i = 0; i < mTombRaider.NumItems(); ++i)
  242. {
  243. int j;
  244. int object_id = item[i].object_id;
  245. // It may not be a moveable, test for sprite
  246. if (!(mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1)) {
  247. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j) {
  248. if (sprite_sequence[j].object_id == object_id)
  249. break;
  250. }
  251. // It's not a moveable, skip sprite
  252. if (j < (int)mTombRaider.NumSpriteSequences())
  253. continue;
  254. }
  255. for (j = 0; j < (int)mTombRaider.NumMoveables(); ++j) {
  256. if ((int)moveable[j].object_id == object_id)
  257. break;
  258. }
  259. // It's not a moveable or even a sprite? Skip unknown
  260. if (j == (int)mTombRaider.NumMoveables())
  261. continue;
  262. processMoveable(j, i, object_id);
  263. statCount++;
  264. }
  265. /*
  266. // Get models that aren't items
  267. for (int i = 0; i < mTombRaider.NumMoveables(); ++i)
  268. {
  269. switch ((int)moveable[i].object_id)
  270. {
  271. case 30:
  272. case 2: // Which tr needs this as model again?
  273. processMoveable(i, i, (int)moveable[i].object_id);
  274. break;
  275. default:
  276. switch (mTombRaider.Engine())
  277. {
  278. case TR_VERSION_1:
  279. switch ((int)moveable[i].object_id)
  280. {
  281. case TombRaider1::LaraMutant:
  282. processMoveable(i, i, (int)moveable[i].object_id);
  283. break;
  284. }
  285. break;
  286. case TR_VERSION_4:
  287. switch ((int)moveable[i].object_id)
  288. {
  289. case TR4_PISTOLS_ANIM:
  290. case TR4_UZI_ANIM:
  291. case TR4_SHOTGUN_ANIM:
  292. case TR4_CROSSBOW_ANIM:
  293. case TR4_GRENADE_GUN_ANIM:
  294. case TR4_SIXSHOOTER_ANIM:
  295. processMoveable(i, i, (int)moveable[i].object_id);
  296. break;
  297. }
  298. break;
  299. case TR_VERSION_2:
  300. case TR_VERSION_3:
  301. case TR_VERSION_5:
  302. case TR_VERSION_UNKNOWN:
  303. break;
  304. }
  305. }
  306. }
  307. */
  308. printf("Done! Found %d models.\n", mTombRaider.NumMoveables() + statCount);
  309. }
  310. // index moveable, i item, sometimes both moveable
  311. // object_id of item or moveable
  312. void Game::processMoveable(int index, int i, int object_id) {
  313. bool cached = false;
  314. unsigned int mod = 0;
  315. for (; mod < getWorld().sizeSkeletalModel(); mod++) {
  316. if (getWorld().getSkeletalModel(mod).getId() == object_id) {
  317. cached = true;
  318. break;
  319. }
  320. }
  321. if (!cached) {
  322. getWorld().addSkeletalModel(*new SkeletalModel(mTombRaider, index, i, object_id));
  323. }
  324. getWorld().addEntity(*new Entity(mTombRaider, index, i, mod));
  325. // Store reference to Lara
  326. if (getWorld().getEntity(getWorld().sizeEntity() - 1).getObjectId() == 0)
  327. mLara = getWorld().sizeEntity() - 1;
  328. if (i == mTombRaider.getSkyModelId())
  329. getRender().setSkyMesh(i, //moveable[i].starting_mesh,
  330. (mTombRaider.Engine() == TR_VERSION_2));
  331. }
  332. bool compareFaceTextureId(const void *voidA, const void *voidB)
  333. {
  334. texture_tri_t *a = (texture_tri_t *)voidA, *b = (texture_tri_t *)voidB;
  335. if (!a || !b)
  336. return false; // error really
  337. return (a->texture < b->texture);
  338. }
  339. #ifdef EXPERIMENTAL
  340. void Game::setupTextureColor(texture_tri_t *r_tri, float *colorf)
  341. {
  342. unsigned char color[4];
  343. unsigned int colorI;
  344. color[0] = (unsigned char)(colorf[0]*255.0f);
  345. color[1] = (unsigned char)(colorf[1]*255.0f);
  346. color[2] = (unsigned char)(colorf[2]*255.0f);
  347. color[3] = (unsigned char)(colorf[3]*255.0f);
  348. ((unsigned char *)(&colorI))[3] = color[0];
  349. ((unsigned char *)(&colorI))[2] = color[1];
  350. ((unsigned char *)(&colorI))[1] = color[2];
  351. ((unsigned char *)(&colorI))[0] = color[3];
  352. bool found = false;
  353. unsigned int foundIndex = 0;
  354. for (foundIndex = 0; foundIndex < gColorTextureHACK.size(); foundIndex++) {
  355. if (gColorTextureHACK[foundIndex] == colorI) {
  356. found = true;
  357. break;
  358. }
  359. }
  360. if (!found)
  361. {
  362. gColorTextureHACK.push_back(colorI);
  363. r_tri->texture = mTextureOffset + gColorTextureHACK.size();
  364. getRender().loadTexture(Texture::generateColorTexture(color, 32, 32),
  365. 32, 32, r_tri->texture);
  366. }
  367. else
  368. {
  369. //printf("Color already loaded %i -> 0x%08x\n",
  370. // gColorTextureHACK.getCurrentIndex(),
  371. // gColorTextureHACK.current());
  372. r_tri->texture = mTextureOffset + foundIndex;
  373. }
  374. //r_tri->texture = white; // White texture
  375. }
  376. #endif
  377. void Game::processModels()
  378. {
  379. printf("Processing meshes: ");
  380. for (int index = 0; index < mTombRaider.getMeshCount(); index++) {
  381. int i, j, count, texture;
  382. int vertexIndices[6];
  383. float st[12];
  384. float color[4];
  385. unsigned short transparency;
  386. texture_tri_t *r_tri;
  387. // Assert common sense
  388. if (index < 0 || !mTombRaider.isMeshValid(index))
  389. {
  390. //! \fixme allow sparse lists with matching ids instead?
  391. getWorld().addMesh(NULL); // Filler, to make meshes array ids align
  392. //printf("x");
  393. //fflush(stdout);
  394. return;
  395. }
  396. #ifndef EXPERIMENTAL
  397. // WHITE texture id
  398. int white = 0;
  399. #endif
  400. model_mesh_t *mesh = new model_mesh_t;
  401. // Mongoose 2002.08.30, Testing support for 'shootable' models ( traceable )
  402. mTombRaider.getMeshCollisionInfo(index, mesh->center, &mesh->radius);
  403. //! \fixme Arrays don't work either =)
  404. // Mesh geometery, colors, etc
  405. mTombRaider.getMeshVertexArrays(index,
  406. &mesh->vertexCount, &mesh->vertices,
  407. &mesh->normalCount, &mesh->normals,
  408. &mesh->colorCount, &mesh->colors);
  409. // Textured Triangles
  410. count = mTombRaider.getMeshTexturedTriangleCount(index);
  411. mesh->texturedTriangles.reserve(count); // little faster
  412. for (i = 0; i < count; ++i)
  413. {
  414. r_tri = new texture_tri_t;
  415. mTombRaider.getMeshTexturedTriangle(index, i,
  416. r_tri->index,
  417. r_tri->st,
  418. &r_tri->texture,
  419. &r_tri->transparency);
  420. r_tri->texture += mTextureStart;
  421. // Add to face vector
  422. mesh->texturedTriangles.push_back(r_tri);
  423. }
  424. // Coloured Triangles
  425. count = mTombRaider.getMeshColoredTriangleCount(index);
  426. mesh->coloredTriangles.reserve(count); // little faster
  427. for (i = 0; i < count; i++)
  428. {
  429. r_tri = new texture_tri_t;
  430. mTombRaider.getMeshColoredTriangle(index, i,
  431. r_tri->index,
  432. color);
  433. r_tri->st[0] = color[0];
  434. r_tri->st[1] = color[1];
  435. r_tri->st[2] = color[2];
  436. r_tri->st[3] = color[3];
  437. r_tri->st[4] = 1.0;
  438. r_tri->st[5] = 1.0;
  439. #ifdef EXPERIMENTAL
  440. setupTextureColor(r_tri, color);
  441. #else
  442. r_tri->texture = white; // White texture
  443. #endif
  444. r_tri->transparency = 0;
  445. // Add to face vector
  446. mesh->coloredTriangles.push_back(r_tri);
  447. }
  448. // Textured Rectangles
  449. count = mTombRaider.getMeshTexturedRectangleCount(index);
  450. mesh->texturedRectangles.reserve(count*2); // little faster
  451. for (i = 0; i < count; ++i)
  452. {
  453. mTombRaider.getMeshTexturedRectangle(index, i,
  454. vertexIndices,
  455. st,
  456. &texture,
  457. &transparency);
  458. r_tri = new texture_tri_t;
  459. for (j = 0; j < 3; ++j)
  460. r_tri->index[j] = vertexIndices[j];
  461. for (j = 0; j < 6; ++j)
  462. r_tri->st[j] = st[j];
  463. r_tri->texture = texture + mTextureStart;
  464. r_tri->transparency = transparency;
  465. // Add to face vector
  466. mesh->texturedRectangles.push_back(r_tri);
  467. r_tri = new texture_tri_t;
  468. for (j = 3; j < 6; ++j)
  469. r_tri->index[j-3] = vertexIndices[j];
  470. for (j = 6; j < 12; ++j)
  471. r_tri->st[j-6] = st[j];
  472. r_tri->texture = texture + mTextureStart;
  473. r_tri->transparency = transparency;
  474. // Add to face vector
  475. mesh->texturedRectangles.push_back(r_tri);
  476. }
  477. // Coloured Rectangles
  478. count = mTombRaider.getMeshColoredRectangleCount(index);
  479. mesh->coloredRectangles.reserve(count*2); // little faster
  480. for (i = 0; i < count; ++i)
  481. {
  482. mTombRaider.getMeshColoredRectangle(index, i,
  483. vertexIndices,
  484. color);
  485. r_tri = new texture_tri_t;
  486. for (j = 0; j < 3; ++j)
  487. r_tri->index[j] = vertexIndices[j];
  488. //for (j = 0; j < 6; ++j)
  489. // r_tri->st[j] = st[j];
  490. r_tri->st[0] = color[0];
  491. r_tri->st[1] = color[1];
  492. r_tri->st[2] = color[2];
  493. r_tri->st[3] = color[3];
  494. r_tri->st[4] = 1.0;
  495. r_tri->st[5] = 1.0;
  496. #ifdef EXPERIMENTAL
  497. //for (j = 6; j < 12; ++j)
  498. // r_tri->st[j-6] = st[j];
  499. setupTextureColor(r_tri, color);
  500. #else
  501. r_tri->texture = white; // White texture
  502. #endif
  503. r_tri->transparency = 0;
  504. // Add to face vector
  505. mesh->coloredRectangles.push_back(r_tri);
  506. r_tri = new texture_tri_t;
  507. for (j = 3; j < 6; ++j)
  508. r_tri->index[j-3] = vertexIndices[j];
  509. //for (j = 6; j < 12; ++j)
  510. // r_tri->st[j-6] = st[j];
  511. r_tri->st[0] = color[0];
  512. r_tri->st[1] = color[1];
  513. r_tri->st[2] = color[2];
  514. r_tri->st[3] = color[3];
  515. r_tri->st[4] = 1.0;
  516. r_tri->st[5] = 1.0;
  517. #ifdef EXPERIMENTAL
  518. setupTextureColor(r_tri, color);
  519. #else
  520. r_tri->texture = white; // White texture
  521. #endif
  522. r_tri->transparency = 0;
  523. // Add to face vector
  524. mesh->coloredRectangles.push_back(r_tri);
  525. }
  526. // Sort faces by texture
  527. std::sort(mesh->texturedTriangles.begin(), mesh->texturedTriangles.end(), compareFaceTextureId);
  528. std::sort(mesh->coloredTriangles.begin(), mesh->coloredTriangles.end(), compareFaceTextureId);
  529. std::sort(mesh->texturedRectangles.begin(), mesh->texturedRectangles.end(), compareFaceTextureId);
  530. std::sort(mesh->coloredRectangles.begin(), mesh->coloredRectangles.end(), compareFaceTextureId);
  531. getWorld().addMesh(mesh);
  532. }
  533. printf("Done! Found %d meshes.\n", mTombRaider.getMeshCount());
  534. }