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.

World.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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 < (int)mRooms.size());
  231. Room &room = *mRooms.at(index);
  232. if (room.getBoundingBox().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)->getBoundingBox().inBoxPlane(x, z)) {
  241. if (mRooms.at(i)->getBoundingBox().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 < (int)mRooms.size());
  254. Room &room = *mRooms.at(index);
  255. vec3_t intersect, p1, p2;
  256. vec3_t vertices[4];
  257. p1[0] = x; p1[1] = y; p1[2] = z;
  258. p2[0] = x2; p2[1] = y2; p2[2] = z2;
  259. for (unsigned int i = 0; i < room.sizePortals(); i++) {
  260. room.getPortal(i).getVertices(vertices);
  261. if (intersectionLinePolygon(intersect, p1, p2, //4,
  262. vertices))
  263. return room.getPortal(i).getAdjoiningRoom();
  264. }
  265. return -1;
  266. }
  267. int World::getSector(int room, float x, float z, float *floor, float *ceiling) {
  268. assert(room >= 0);
  269. assert(room < (int)mRooms.size());
  270. assert(floor != NULL);
  271. assert(ceiling != NULL);
  272. int sector = getSector(room, x, z);
  273. if ((sector >= 0) && (sector < (int)mRooms.at(room)->sizeSectors())) {
  274. *floor = mRooms.at(room)->getSector(sector).getFloor();
  275. *ceiling = mRooms.at(room)->getSector(sector).getCeiling();
  276. }
  277. return sector;
  278. }
  279. int World::getSector(int room, float x, float z) {
  280. assert(room >= 0);
  281. assert(room < (int)mRooms.size());
  282. vec3_t pos;
  283. mRooms.at(room)->getPos(pos);
  284. int sector = (((((int)x - (int)pos[0]) / 1024) *
  285. mRooms.at(room)->getNumZSectors()) + (((int)z - (int)pos[2]) / 1024));
  286. if (sector < 0)
  287. return -1;
  288. return sector;
  289. }
  290. unsigned int World::getRoomInfo(int room) {
  291. assert(room >= 0);
  292. assert(room < (int)mRooms.size());
  293. return mRooms.at(room)->getFlags();
  294. }
  295. bool World::isWall(int room, int sector) {
  296. assert(room >= 0);
  297. assert(room < (int)mRooms.size());
  298. assert(sector >= 0);
  299. assert(sector < (int)mRooms.at(room)->sizeSectors());
  300. //! \fixme is (sector > 0) correct??
  301. return ((sector > 0) && mRooms.at(room)->getSector(sector).isWall());
  302. }
  303. void World::getHeightAtPosition(int index, float x, float *y, float z) {
  304. assert(index >= 0);
  305. assert(index < (int)mRooms.size());
  306. int sector = getSector(index, x, z);
  307. if ((sector >= 0) && (sector < (int)mRooms.at(index)->sizeSectors()))
  308. *y = mRooms.at(index)->getSector(sector).getFloor();
  309. }
  310. void World::destroy()
  311. {
  312. for (unsigned int i = 0; i != mRooms.size(); i++)
  313. delete mRooms[i];
  314. for (unsigned int i = 0; i != mSprites.size(); i++)
  315. delete mSprites[i];
  316. model_mesh_t *mesh;
  317. skeletal_model_t *model;
  318. bone_frame_t *boneframe;
  319. bone_tag_t *tag;
  320. animation_frame_t *animation;
  321. std::list<skeletal_model_t *> cache;
  322. for (std::vector<int>::size_type i = 0; i != mEntities.size(); i++)
  323. delete mEntities[i];
  324. for (std::vector<int>::size_type i = 0; i != mMeshes.size(); i++) {
  325. mesh = mMeshes[i];
  326. if (!mesh)
  327. continue;
  328. for (std::vector<int>::size_type j = 0; j != mesh->texturedTriangles.size(); j++) {
  329. if (mesh->texturedTriangles[j])
  330. delete mesh->texturedTriangles[j];
  331. }
  332. for (std::vector<int>::size_type j = 0; j != mesh->coloredTriangles.size(); j++) {
  333. if (mesh->coloredTriangles[j])
  334. delete mesh->coloredTriangles[j];
  335. }
  336. for (std::vector<int>::size_type j = 0; j != mesh->texturedRectangles.size(); j++) {
  337. if (mesh->texturedRectangles[j])
  338. delete mesh->texturedRectangles[j];
  339. }
  340. for (std::vector<int>::size_type j = 0; j != mesh->coloredRectangles.size(); j++) {
  341. if (mesh->coloredRectangles[j])
  342. delete mesh->coloredRectangles[j];
  343. }
  344. if (mesh->vertices)
  345. delete [] mesh->vertices;
  346. if (mesh->colors)
  347. delete [] mesh->colors;
  348. if (mesh->normals)
  349. delete [] mesh->normals;
  350. delete mesh;
  351. }
  352. mMeshes.clear();
  353. for (std::vector<int>::size_type i = 0; i != mModels.size(); i++) {
  354. model = mModels[i];
  355. if (!model)
  356. continue;
  357. // No smart pointers, so skip if deleted once =)
  358. bool found = false;
  359. for (std::list<skeletal_model_t *>::const_iterator iterator = cache.begin(), end = cache.end(); iterator != end; ++iterator) {
  360. if (model == *iterator) {
  361. found = true;
  362. break;
  363. }
  364. }
  365. if (!found)
  366. cache.push_back(model);
  367. else
  368. continue;
  369. for (std::vector<int>::size_type j = 0; j != model->animation.size(); j++) {
  370. animation = model->animation[j];
  371. if (!animation)
  372. continue;
  373. for (std::vector<int>::size_type k = 0; k != animation->frame.size(); k++) {
  374. boneframe = animation->frame[k];
  375. if (!boneframe)
  376. continue;
  377. for (std::vector<int>::size_type l = 0; l != boneframe->tag.size(); l++) {
  378. tag = boneframe->tag[l];
  379. if (!tag)
  380. continue;
  381. delete tag;
  382. }
  383. delete boneframe;
  384. }
  385. delete animation;
  386. }
  387. delete model;
  388. }
  389. mModels.clear();
  390. }