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.

World.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*!
  2. * \file src/World.cpp
  3. * \brief The game world (model)
  4. *
  5. * \author Mongoose
  6. */
  7. #include <cstdio>
  8. #include <math.h>
  9. #include <assert.h>
  10. #include "World.h"
  11. World::~World()
  12. {
  13. destroy();
  14. }
  15. // Temp methods for rendering use until more refactoring is done
  16. model_mesh_t *World::getMesh(int index)
  17. {
  18. return mMeshes[index];
  19. }
  20. skeletal_model_t *World::getModel(int index)
  21. {
  22. return mModels[index];
  23. }
  24. std::vector<entity_t *> *World::getEntities()
  25. {
  26. return &mEntities;
  27. }
  28. void World::addMesh(model_mesh_t *mesh)
  29. {
  30. if (mesh)
  31. mMeshes.push_back(mesh);
  32. }
  33. void World::addEntity(entity_t *e)
  34. {
  35. if (e)
  36. {
  37. e->master = 0x0;
  38. e->moveType = worldMoveType_walk; // Walk
  39. e->room = getRoomByLocation(e->pos[0], e->pos[1], e->pos[2]);
  40. mEntities.push_back(e);
  41. }
  42. }
  43. int World::addModel(skeletal_model_t *model)
  44. {
  45. if (model)
  46. {
  47. mModels.push_back(model);
  48. return mModels.size() - 1;
  49. }
  50. return -1;
  51. }
  52. void World::moveEntity(entity_t *e, char movement)
  53. {
  54. const float moved = 180.0f;
  55. const float testd = 220.0f;
  56. const float camHeight = 8.0f;
  57. float x, y, z, pitch, h, floor, ceiling;
  58. int room, sector;
  59. bool wall;
  60. unsigned int roomFlags;
  61. if (!e)
  62. {
  63. return;
  64. }
  65. switch (e->moveType)
  66. {
  67. case worldMoveType_walkNoSwim:
  68. case worldMoveType_walk:
  69. pitch = 0.0f; // in the future pitch could control jump up blocks here
  70. break;
  71. case worldMoveType_noClipping:
  72. case worldMoveType_fly:
  73. case worldMoveType_swim:
  74. pitch = e->angles[2];
  75. break;
  76. }
  77. switch (movement)
  78. {
  79. case 'f':
  80. x = e->pos[0] + (testd * sinf(e->angles[1]));
  81. y = e->pos[1] + (testd * sinf(pitch));
  82. z = e->pos[2] + (testd * cosf(e->angles[1]));
  83. break;
  84. case 'b':
  85. x = e->pos[0] - (testd * sinf(e->angles[1]));
  86. y = e->pos[1] - (testd * sinf(pitch));
  87. z = e->pos[2] - (testd * cosf(e->angles[1]));
  88. break;
  89. case 'l':
  90. x = e->pos[0] - (testd * sinf(e->angles[1] + 90.0f));
  91. y = e->pos[1];
  92. z = e->pos[2] - (testd * cosf(e->angles[1] + 90.0f));
  93. break;
  94. case 'r':
  95. x = e->pos[0] + (testd * sinf(e->angles[1] + 90.0f));
  96. y = e->pos[1];
  97. z = e->pos[2] + (testd * cosf(e->angles[1] + 90.0f));
  98. break;
  99. default:
  100. return;
  101. }
  102. //room = getRoomByLocation(x, y, z);
  103. room = getRoomByLocation(e->room, x, y, z);
  104. if (room == -1) // Will we hit a portal?
  105. {
  106. room = getAdjoiningRoom(e->room,
  107. e->pos[0], e->pos[1], e->pos[2],
  108. x, y, z);
  109. if (room > -1)
  110. {
  111. printf("Crossing from room %i to %i\n", e->room, room);
  112. } else {
  113. //! \fixme mRooms, sectors, ... are now std::vector, but often upper bound checks are missing
  114. return;
  115. }
  116. }
  117. roomFlags = getRoomInfo(room);
  118. sector = getSector(room, x, z, &floor, &ceiling);
  119. wall = isWall(room, sector);
  120. // If you're underwater you may want to swim =)
  121. // ...if you're worldMoveType_walkNoSwim, you better hope it's shallow
  122. if (roomFlags & roomFlag_underWater && e->moveType == worldMoveType_walk)
  123. {
  124. e->moveType = worldMoveType_swim;
  125. }
  126. // Don't swim on land
  127. if (!(roomFlags & roomFlag_underWater) && e->moveType == worldMoveType_swim)
  128. {
  129. e->moveType = worldMoveType_walk;
  130. }
  131. // Mongoose 2002.09.02, Add check for room -> room transition
  132. // ( Only allow by movement between rooms by using portals )
  133. if (((e->moveType == worldMoveType_noClipping) ||
  134. (e->moveType == worldMoveType_fly) ||
  135. (e->moveType == worldMoveType_swim)) ||
  136. ((room > -1) && (!wall)))
  137. {
  138. e->room = room;
  139. switch (movement)
  140. {
  141. case 'f':
  142. x = e->pos[0] + (moved * sinf(e->angles[1]));
  143. y = e->pos[1] + (moved * sinf(pitch));
  144. z = e->pos[2] + (moved * cosf(e->angles[1]));
  145. break;
  146. case 'b':
  147. x = e->pos[0] - (moved * sinf(e->angles[1]));
  148. y = e->pos[1] - (moved * sinf(pitch));
  149. z = e->pos[2] - (moved * cosf(e->angles[1]));
  150. break;
  151. case 'l':
  152. x = e->pos[0] - (moved * sinf(e->angles[1] + 90.0f));
  153. z = e->pos[2] - (moved * cosf(e->angles[1] + 90.0f));
  154. break;
  155. case 'r':
  156. x = e->pos[0] + (moved * sinf(e->angles[1] + 90.0f));
  157. z = e->pos[2] + (moved * cosf(e->angles[1] + 90.0f));
  158. break;
  159. }
  160. /*! \fixme Test for vector (move vector) / plane (portal) collision here
  161. * to see if we need to switch rooms... man...
  162. */
  163. h = y;
  164. getHeightAtPosition(room, x, &h, z);
  165. switch (e->moveType)
  166. {
  167. case worldMoveType_fly:
  168. case worldMoveType_swim:
  169. // Don't fall out of world, avoid a movement that does
  170. if (h > y - camHeight)
  171. {
  172. e->pos[0] = x;
  173. e->pos[1] = y;
  174. e->pos[2] = z;
  175. }
  176. break;
  177. case worldMoveType_walk:
  178. case worldMoveType_walkNoSwim:
  179. y = e->pos[1]; // Override vector movement walking ( er, not pretty )
  180. // Now fake gravity
  181. // Mongoose 2002.08.14, Remember TR is upside down ( you fall 'up' )
  182. //ddist = h - e->pos[1];
  183. // This is to force false gravity, by making camera stay on ground
  184. e->pos[1] = h; //roomFloor->bbox_min[1];
  185. // Check for camera below terrian and correct
  186. if (e->pos[1] < h - camHeight)
  187. {
  188. e->pos[1] = h - camHeight;
  189. }
  190. e->pos[0] = x;
  191. e->pos[2] = z;
  192. break;
  193. case worldMoveType_noClipping:
  194. e->pos[0] = x;
  195. e->pos[1] = y;
  196. e->pos[2] = z;
  197. }
  198. }
  199. else
  200. {
  201. e->moving = false;
  202. return;
  203. }
  204. e->room = room;
  205. e->moving = true;
  206. }
  207. void World::addRoom(Room &room) {
  208. mRooms.push_back(&room);
  209. }
  210. unsigned int World::sizeRoom() {
  211. return mRooms.size();
  212. }
  213. Room &World::getRoom(unsigned int index) {
  214. assert(index < mRooms.size());
  215. return *mRooms.at(index);
  216. }
  217. void World::addSprite(SpriteSequence &sprite) {
  218. mSprites.push_back(&sprite);
  219. }
  220. unsigned int World::sizeSprite() {
  221. return mSprites.size();
  222. }
  223. SpriteSequence &World::getSprite(unsigned int index) {
  224. assert(index < mSprites.size());
  225. return *mSprites.at(index);
  226. }
  227. int World::getRoomByLocation(int index, float x, float y, float z)
  228. {
  229. assert(index >= 0);
  230. assert(index < mRooms.size());
  231. Room &room = *mRooms.at(index);
  232. if (room.inBox(x, y, z))
  233. return index;
  234. else
  235. return getRoomByLocation(x, y, z);
  236. }
  237. int World::getRoomByLocation(float x, float y, float z) {
  238. int hop = -1;
  239. for (unsigned int i = 0; i < mRooms.size(); i++) {
  240. if (mRooms.at(i)->inBoxPlane(x, z)) {
  241. if (mRooms.at(i)->inBox(x, y, z))
  242. return i;
  243. else
  244. hop = i; // This room is above or below current position
  245. }
  246. }
  247. return hop;
  248. }
  249. int World::getAdjoiningRoom(int index,
  250. float x, float y, float z,
  251. float x2, float y2, float z2) {
  252. assert(index >= 0);
  253. assert(index < mRooms.size());
  254. Room &room = *mRooms.at(index);
  255. vec3_t intersect, p1, p2;
  256. p1[0] = x; p1[1] = y; p1[2] = z;
  257. p2[0] = x2; p2[1] = y2; p2[2] = z2;
  258. for (unsigned int i = 0; i < room.sizePortals(); i++) {
  259. if (intersectionLinePolygon(intersect, p1, p2, //4,
  260. room.getPortal(i).getVertices()))
  261. return room.getPortal(i).getAdjoiningRoom();
  262. }
  263. return -1;
  264. }
  265. int World::getSector(int room, float x, float z, float *floor, float *ceiling) {
  266. assert(room >= 0);
  267. assert(room < mRooms.size());
  268. assert(floor != NULL);
  269. assert(ceiling != NULL);
  270. int sector = getSector(room, x, z);
  271. if ((sector >= 0) && (sector < mRooms.at(room)->sizeSectors())) {
  272. *floor = mRooms.at(room)->getSector(sector).getFloor();
  273. *ceiling = mRooms.at(room)->getSector(sector).getCeiling();
  274. }
  275. return sector;
  276. }
  277. int World::getSector(int room, float x, float z) {
  278. assert(room >= 0);
  279. assert(room < mRooms.size());
  280. vec3_t pos;
  281. mRooms.at(room)->getPos(pos);
  282. int sector = (((((int)x - (int)pos[0]) / 1024) *
  283. mRooms.at(room)->getNumZSectors()) + (((int)z - (int)pos[2]) / 1024));
  284. if (sector < 0)
  285. return -1;
  286. return sector;
  287. }
  288. unsigned int World::getRoomInfo(int room) {
  289. assert(room >= 0);
  290. assert(room < mRooms.size());
  291. return mRooms.at(room)->getFlags();
  292. }
  293. bool World::isWall(int room, int sector) {
  294. assert(room >= 0);
  295. assert(room < mRooms.size());
  296. assert(sector >= 0);
  297. assert(sector < mRooms.at(room)->sizeSectors());
  298. //! \fixme is (sector > 0) correct??
  299. return ((sector > 0) && mRooms.at(room)->getSector(sector).isWall());
  300. }
  301. void World::getHeightAtPosition(int index, float x, float *y, float z) {
  302. assert(index >= 0);
  303. assert(index < mRooms.size());
  304. int sector = getSector(index, x, z);
  305. if ((sector >= 0) && (sector < mRooms.at(index)->sizeSectors()))
  306. *y = mRooms.at(index)->getSector(sector).getFloor();
  307. }
  308. void World::destroy()
  309. {
  310. for (unsigned int i = 0; i != mRooms.size(); i++)
  311. delete mRooms[i];
  312. for (unsigned int i = 0; i != mSprites.size(); i++)
  313. delete mSprites[i];
  314. model_mesh_t *mesh;
  315. skeletal_model_t *model;
  316. bone_frame_t *boneframe;
  317. bone_tag_t *tag;
  318. animation_frame_t *animation;
  319. std::list<skeletal_model_t *> cache;
  320. for (std::vector<int>::size_type i = 0; i != mEntities.size(); i++)
  321. delete mEntities[i];
  322. for (std::vector<int>::size_type i = 0; i != mMeshes.size(); i++) {
  323. mesh = mMeshes[i];
  324. if (!mesh)
  325. continue;
  326. for (std::vector<int>::size_type j = 0; j != mesh->texturedTriangles.size(); j++) {
  327. if (mesh->texturedTriangles[j])
  328. delete mesh->texturedTriangles[j];
  329. }
  330. for (std::vector<int>::size_type j = 0; j != mesh->coloredTriangles.size(); j++) {
  331. if (mesh->coloredTriangles[j])
  332. delete mesh->coloredTriangles[j];
  333. }
  334. for (std::vector<int>::size_type j = 0; j != mesh->texturedRectangles.size(); j++) {
  335. if (mesh->texturedRectangles[j])
  336. delete mesh->texturedRectangles[j];
  337. }
  338. for (std::vector<int>::size_type j = 0; j != mesh->coloredRectangles.size(); j++) {
  339. if (mesh->coloredRectangles[j])
  340. delete mesh->coloredRectangles[j];
  341. }
  342. if (mesh->vertices)
  343. delete [] mesh->vertices;
  344. if (mesh->colors)
  345. delete [] mesh->colors;
  346. if (mesh->normals)
  347. delete [] mesh->normals;
  348. delete mesh;
  349. }
  350. mMeshes.clear();
  351. for (std::vector<int>::size_type i = 0; i != mModels.size(); i++) {
  352. model = mModels[i];
  353. if (!model)
  354. continue;
  355. // No smart pointers, so skip if deleted once =)
  356. bool found = false;
  357. for (std::list<skeletal_model_t *>::const_iterator iterator = cache.begin(), end = cache.end(); iterator != end; ++iterator) {
  358. if (model == *iterator) {
  359. found = true;
  360. break;
  361. }
  362. }
  363. if (!found)
  364. cache.push_back(model);
  365. else
  366. continue;
  367. for (std::vector<int>::size_type j = 0; j != model->animation.size(); j++) {
  368. animation = model->animation[j];
  369. if (!animation)
  370. continue;
  371. for (std::vector<int>::size_type k = 0; k != animation->frame.size(); k++) {
  372. boneframe = animation->frame[k];
  373. if (!boneframe)
  374. continue;
  375. for (std::vector<int>::size_type l = 0; l != boneframe->tag.size(); l++) {
  376. tag = boneframe->tag[l];
  377. if (!tag)
  378. continue;
  379. delete tag;
  380. }
  381. delete boneframe;
  382. }
  383. delete animation;
  384. }
  385. delete model;
  386. }
  387. mModels.clear();
  388. }