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

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