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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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 <cstring>
  11. #include "global.h"
  12. #include "Camera.h"
  13. #include "Console.h"
  14. #include "Game.h"
  15. #include "loader/Loader.h"
  16. #include "OpenRaider.h"
  17. #include "Render.h"
  18. #include "Sound.h"
  19. #include "StaticMesh.h"
  20. #include "TextureManager.h"
  21. #include "World.h"
  22. #include "utils/strings.h"
  23. #include "games/TombRaider1.h"
  24. #ifdef MULTITEXTURE
  25. std::map<int, int> gMapTex2Bump;
  26. #endif
  27. Game &getGame() {
  28. static Game gGame;
  29. return gGame;
  30. }
  31. Game::Game() {
  32. zPos = 0;
  33. mLoaded = false;
  34. mLara = -1;
  35. mTextureStart = 0;
  36. mTextureOffset = 0;
  37. UI::addWindow(this);
  38. }
  39. Game::~Game() {
  40. destroy();
  41. UI::removeWindow(this);
  42. }
  43. unsigned int Game::getTextureStart() {
  44. return mTextureStart;
  45. }
  46. unsigned int Game::getTextureOffset() {
  47. return mTextureOffset;
  48. }
  49. int Game::initialize() {
  50. // Enable Renderer
  51. getRender().setMode(Render::modeLoadScreen);
  52. mTextureStart = getTextureManager().getTextureCount();
  53. return 0;
  54. }
  55. void Game::display() {
  56. getRender().display();
  57. }
  58. void Game::destroy() {
  59. mLoaded = false;
  60. mLara = -1;
  61. getRender().setMode(Render::modeDisabled);
  62. getWorld().destroy();
  63. getRender().ClearWorld();
  64. getSound().clear(); // Remove all previously loaded sounds
  65. }
  66. bool Game::isLoaded() {
  67. return mLoaded;
  68. }
  69. int Game::loadLevel(const char *level) {
  70. if (mLoaded)
  71. destroy();
  72. levelName = level;
  73. getConsole() << "Loading " << levelName << Console::endl;
  74. int error = 0;
  75. auto loader = Loader::createLoader(level);
  76. if (loader) {
  77. // First Loader test
  78. error = loader->load(level);
  79. if (error != 0) {
  80. return error;
  81. }
  82. // And now...?
  83. getConsole() << "Tried Loader..." << Console::endl;
  84. }
  85. if ((!loader) || (error == 0)) {
  86. // Old TombRaider level loader
  87. error = mTombRaider.Load(levelName.c_str());
  88. if (error != 0)
  89. return error;
  90. // If required, load the external sound effect file MAIN.SFX into TombRaider
  91. if ((mTombRaider.getEngine() == TR_VERSION_2) || (mTombRaider.getEngine() == TR_VERSION_3)) {
  92. std::string tmp(levelName);
  93. size_t pos = tmp.rfind('/');
  94. tmp.erase(pos + 1);
  95. tmp += "MAIN.SFX";
  96. error = mTombRaider.loadSFX(tmp.c_str());
  97. if (error != 0)
  98. getConsole() << "Could not load " << tmp << Console::endl;
  99. }
  100. // Process data
  101. processTextures();
  102. processRooms();
  103. processModels();
  104. processSprites();
  105. processMoveables();
  106. processPakSounds();
  107. mTombRaider.reset();
  108. if (mLara == -1) {
  109. //! \todo Cutscene support
  110. getConsole() << "Can't find Lara entity in level pak!" << Console::endl;
  111. destroy();
  112. return -1;
  113. } else {
  114. mLoaded = true;
  115. getRender().setMode(Render::modeVertexLight);
  116. return 0;
  117. }
  118. }
  119. }
  120. void Game::handleAction(ActionEvents action, bool isFinished) {
  121. if (mLoaded && (!isFinished)) {
  122. if (action == forwardAction) {
  123. getLara().move('f');
  124. } else if (action == backwardAction) {
  125. getLara().move('b');
  126. } else if (action == leftAction) {
  127. getLara().move('l');
  128. } else if (action == rightAction) {
  129. getLara().move('r');
  130. } else if (action == jumpAction) {
  131. } else if (action == crouchAction) {
  132. } else if (action == useAction) {
  133. } else if (action == holsterAction) {
  134. } else if (action == walkAction) {
  135. }
  136. }
  137. }
  138. void Game::handleMouseMotion(int xrel, int yrel) {
  139. if (mLoaded) {
  140. // Move Camera on X Axis
  141. if (xrel > 0)
  142. while (xrel-- > 0)
  143. getCamera().command(CAMERA_ROTATE_RIGHT);
  144. else if (xrel < 0)
  145. while (xrel++ < 0)
  146. getCamera().command(CAMERA_ROTATE_LEFT);
  147. // Move Camera on Y Axis
  148. if (yrel > 0)
  149. while (yrel-- > 0)
  150. getCamera().command(CAMERA_ROTATE_UP);
  151. else if (yrel < 0)
  152. while (yrel++ < 0)
  153. getCamera().command(CAMERA_ROTATE_DOWN);
  154. // Fix Laras rotation
  155. float angles[3] = { 0.0f, getCamera().getRadianYaw(), getCamera().getRadianPitch() };
  156. getLara().setAngles(angles);
  157. }
  158. }
  159. Entity &Game::getLara() {
  160. assert(mLara >= 0);
  161. assert(mLara < (int)getWorld().sizeEntity());
  162. return getWorld().getEntity(mLara);
  163. }
  164. void Game::processSprites() {
  165. for (int i = 0; i < (mTombRaider.NumItems() - 1); i++) {
  166. if ((mTombRaider.Engine() == TR_VERSION_1) && (mTombRaider.Item()[i].intensity1 == -1))
  167. continue;
  168. for (int j = 0; j < mTombRaider.NumSpriteSequences(); j++) {
  169. if (mTombRaider.SpriteSequence()[j].object_id == mTombRaider.Item()[i].object_id)
  170. getWorld().addSprite(*new SpriteSequence(mTombRaider, i, j));
  171. }
  172. }
  173. getConsole() << "Found " << mTombRaider.NumSpriteSequences() << " sprites." << Console::endl;
  174. }
  175. void Game::processRooms() {
  176. for (int index = 0; index < mTombRaider.NumRooms(); index++)
  177. getWorld().addRoom(*new Room(mTombRaider, index));
  178. getConsole() << "Found " << mTombRaider.NumRooms() << " rooms." << Console::endl;
  179. }
  180. void Game::processModels() {
  181. for (int index = 0; index < mTombRaider.getMeshCount(); index++)
  182. getWorld().addStaticMesh(*new StaticMesh(mTombRaider, index));
  183. getConsole() << "Found " << mTombRaider.getMeshCount() << " meshes." << Console::endl;
  184. }
  185. void Game::processPakSounds()
  186. {
  187. unsigned char *riff;
  188. unsigned int riffSz;
  189. //tr2_sound_source_t *sound;
  190. //tr2_sound_details_t *detail;
  191. //float pos[3];
  192. unsigned int i;
  193. unsigned long id;
  194. /* detail
  195. short sample;
  196. short volume;
  197. short sound_range;
  198. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  199. // in this group, bits 0-1: channel number
  200. */
  201. for (i = 0; i < mTombRaider.getSoundSamplesCount(); ++i)
  202. {
  203. mTombRaider.getSoundSample(i, &riffSz, &riff);
  204. getSound().addWave(riff, riffSz, &id, Sound::SoundFlagsNone);
  205. //if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  206. //{
  207. //m_testSFX = id;
  208. //}
  209. delete [] riff;
  210. // sound[i].sound_id; // internal sound index
  211. // sound[i].flags; // 0x40, 0x80, or 0xc0
  212. //pos[0] = sound[i].x;
  213. //pos[1] = sound[i].y;
  214. //pos[2] = sound[i].z;
  215. //getSound().SourceAt(id, pos);
  216. }
  217. getConsole() << "Found " << mTombRaider.getSoundSamplesCount() << " sound samples." << Console::endl;
  218. }
  219. void Game::processTextures()
  220. {
  221. unsigned char *image;
  222. unsigned char *bumpmap;
  223. int i;
  224. //if ( mTombRaider.getNumBumpMaps())
  225. // gBumpMapStart = mTombRaider.NumTextures();
  226. for (i = 0; i < mTombRaider.NumTextures(); ++i)
  227. {
  228. mTombRaider.Texture(i, &image, &bumpmap);
  229. // Overwrite any previous level textures on load
  230. getTextureManager().loadBufferSlot(image, 256, 256,
  231. RGBA, 32, (mTextureStart - 1) + i);
  232. #ifdef MULTITEXTURE
  233. gMapTex2Bump[(mTextureStart - 1) + i] = -1;
  234. #endif
  235. if (bumpmap)
  236. {
  237. #ifdef MULTITEXTURE
  238. gMapTex2Bump[(mTextureStart - 1) + i] = (mTextureStart - 1) + i +
  239. mTombRaider.NumTextures();
  240. #endif
  241. getTextureManager().loadBufferSlot(bumpmap, 256, 256,
  242. RGBA, 32,
  243. (mTextureStart - 1) + i + mTombRaider.NumTextures());
  244. }
  245. if (image)
  246. delete [] image;
  247. if (bumpmap)
  248. delete [] bumpmap;
  249. }
  250. mTextureOffset = (mTextureStart - 1) + mTombRaider.NumTextures();
  251. getConsole() << "Found " << mTombRaider.NumTextures() << " textures." << Console::endl;
  252. }
  253. void Game::processMoveables()
  254. {
  255. unsigned int statCount = 0;
  256. tr2_moveable_t *moveable = mTombRaider.Moveable();
  257. tr2_item_t *item = mTombRaider.Item();
  258. tr2_sprite_sequence_t *sprite_sequence = mTombRaider.SpriteSequence();
  259. for (int i = 0; i < mTombRaider.NumItems(); ++i)
  260. {
  261. int j;
  262. int object_id = item[i].object_id;
  263. // It may not be a moveable, test for sprite
  264. if (!(mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1)) {
  265. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j) {
  266. if (sprite_sequence[j].object_id == object_id)
  267. break;
  268. }
  269. // It's not a moveable, skip sprite
  270. if (j < (int)mTombRaider.NumSpriteSequences())
  271. continue;
  272. }
  273. for (j = 0; j < (int)mTombRaider.NumMoveables(); ++j) {
  274. if ((int)moveable[j].object_id == object_id)
  275. break;
  276. }
  277. // It's not a moveable or even a sprite? Skip unknown
  278. if (j == (int)mTombRaider.NumMoveables())
  279. continue;
  280. processMoveable(j, i, object_id);
  281. statCount++;
  282. }
  283. /*
  284. // Get models that aren't items
  285. for (int i = 0; i < mTombRaider.NumMoveables(); ++i)
  286. {
  287. switch ((int)moveable[i].object_id)
  288. {
  289. case 30:
  290. case 2: // Which tr needs this as model again?
  291. processMoveable(i, i, (int)moveable[i].object_id);
  292. break;
  293. default:
  294. switch (mTombRaider.Engine())
  295. {
  296. case TR_VERSION_1:
  297. switch ((int)moveable[i].object_id)
  298. {
  299. case TombRaider1::LaraMutant:
  300. processMoveable(i, i, (int)moveable[i].object_id);
  301. break;
  302. }
  303. break;
  304. case TR_VERSION_4:
  305. switch ((int)moveable[i].object_id)
  306. {
  307. case TR4_PISTOLS_ANIM:
  308. case TR4_UZI_ANIM:
  309. case TR4_SHOTGUN_ANIM:
  310. case TR4_CROSSBOW_ANIM:
  311. case TR4_GRENADE_GUN_ANIM:
  312. case TR4_SIXSHOOTER_ANIM:
  313. processMoveable(i, i, (int)moveable[i].object_id);
  314. break;
  315. }
  316. break;
  317. case TR_VERSION_2:
  318. case TR_VERSION_3:
  319. case TR_VERSION_5:
  320. case TR_VERSION_UNKNOWN:
  321. break;
  322. }
  323. }
  324. }
  325. */
  326. getConsole() << "Found " << mTombRaider.NumMoveables() + statCount << " moveables." << Console::endl;
  327. }
  328. // index moveable, i item, sometimes both moveable
  329. // object_id of item or moveable
  330. void Game::processMoveable(int index, int i, int object_id) {
  331. // Check if the SkeletalModel is already cached
  332. bool cached = false;
  333. unsigned int model;
  334. for (model = 0; model < getWorld().sizeSkeletalModel(); model++) {
  335. if (getWorld().getSkeletalModel(model).getId() == object_id) {
  336. cached = true;
  337. break;
  338. }
  339. }
  340. // Create a new SkeletalModel, if needed
  341. if (!cached)
  342. getWorld().addSkeletalModel(*new SkeletalModel(mTombRaider, index, object_id));
  343. // Create a new Entity, using the cached or the new SkeletalModel
  344. Entity &entity = *new Entity(mTombRaider, index, i, model);
  345. getWorld().addEntity(entity);
  346. // Store reference to Lara
  347. if (entity.getObjectId() == 0)
  348. mLara = getWorld().sizeEntity() - 1;
  349. // Store reference to the SkyMesh
  350. if (i == mTombRaider.getSkyModelId())
  351. getRender().setSkyMesh(i, //moveable[i].starting_mesh,
  352. (mTombRaider.Engine() == TR_VERSION_2));
  353. }