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.

Room.cpp 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /*!
  2. * \file src/Room.cpp
  3. * \brief World Room Mesh
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include "global.h"
  9. #include "Console.h"
  10. #include "Game.h"
  11. #include "Render.h"
  12. #include "Room.h"
  13. #ifdef MULTITEXTURE
  14. #include <map>
  15. extern std::map<int, int> gMapTex2Bump;
  16. #endif
  17. Room::Room(TombRaider &tr, unsigned int index) {
  18. vec3_t box[2];
  19. Matrix transform;
  20. if (!tr.isRoomValid(index)) {
  21. getConsole().print("WARNING: Handling invalid vertex array in room");
  22. //printf("x");
  23. //fflush(stdout);
  24. return;
  25. }
  26. flags = 0;
  27. unsigned int trFlags = 0;
  28. tr.getRoomInfo(index, &trFlags, pos, box[0], box[1]);
  29. if (trFlags & tombraiderRoom_underWater)
  30. flags |= RoomFlagUnderWater;
  31. // Adjust positioning for OR world coordinate translation
  32. box[0][0] += pos[0];
  33. box[1][0] += pos[0];
  34. box[0][2] += pos[2];
  35. box[1][2] += pos[2];
  36. bbox.setBoundingBox(box[0], box[1]);
  37. // Mongoose 2002.04.03, Setup 3D transform
  38. transform.setIdentity();
  39. transform.translate(pos);
  40. // Current room is always first
  41. adjacentRooms.push_back(index);
  42. // Setup portals
  43. unsigned int count = tr.getRoomPortalCount(index);
  44. for (unsigned int i = 0; i < count; i++) {
  45. portals.push_back(new Portal(tr, index, i, transform));
  46. adjacentRooms.push_back(portals.back()->getAdjoiningRoom());
  47. }
  48. //! \fixme Use more of sector structure, boxes, and floordata
  49. // List of sectors in this room
  50. count = tr.getRoomSectorCount(index, &numZSectors, &numXSectors);
  51. for (unsigned int i = 0; i < count; i++)
  52. sectors.push_back(new Sector(tr, index, i));
  53. // Setup collision boxes
  54. //! fixme Should use sectors, but this is a test
  55. count = tr.getRoomBoxCount(index);
  56. for (unsigned int i = 0; i < count; i++)
  57. boxes.push_back(new Box(tr, index, i));
  58. // Setup room lights
  59. count = tr.getRoomLightCount(index);
  60. for (unsigned int i = 0; i < count; i++)
  61. lights.push_back(new Light(tr, index, i));
  62. // Room models
  63. count = tr.getRoomModelCount(index);
  64. for (unsigned int i = 0; i < count; i++)
  65. models.push_back(new StaticModel(tr, index, i));
  66. // Room sprites
  67. count = tr.getRoomSpriteCount(index);
  68. for (unsigned int i = 0; i < count; i++)
  69. sprites.push_back(new Sprite(tr, index, i));
  70. //#define EXPERIMENTAL_UNIFIED_ROOM_GEOMETERY
  71. #ifdef EXPERIMENTAL_UNIFIED_ROOM_GEOMETERY
  72. unsigned int vertexCount, normalCount, colorCount, triCount;
  73. vec_t *vertexArray;
  74. vec_t *normalArray;
  75. vec_t *colorArray;
  76. unsigned int *indices, *fflags;
  77. float *texCoords;
  78. int *textures;
  79. tr.getRoomVertexArrays(index,
  80. &vertexCount, &vertexArray,
  81. &normalCount, &normalArray,
  82. &colorCount, &colorArray);
  83. mesh.bufferVertexArray(vertexCount, vertexArray);
  84. mesh.bufferNormalArray(normalCount, normalArray);
  85. mesh.bufferColorArray(vertexCount, colorArray);
  86. tr.getRoomTriangles(index, getGame().getTextureStart(),
  87. &triCount, &indices, &texCoords, &textures,
  88. &fflags);
  89. mesh.bufferTriangles(triCount, indices, texCoords, textures, fflags);
  90. #else
  91. const unsigned int TextureLimit = 24;
  92. float rgba[4];
  93. float xyz[3];
  94. count = tr.getRoomVertexCount(index);
  95. mesh.allocateVertices(count);
  96. mesh.allocateNormals(0); // count
  97. mesh.allocateColors(count);
  98. for (unsigned int i = 0; i < count; ++i)
  99. {
  100. tr.getRoomVertex(index, i, xyz, rgba);
  101. mesh.setVertex(i, xyz[0], xyz[1], xyz[2]);
  102. mesh.setColor(i, rgba);
  103. }
  104. // Mongoose 2002.06.09, Setup allocation of meshes and polygons
  105. // Counters ( Textured polygon lists are allocated per texture)
  106. // ( Textures are mapped to these meshes )
  107. int triangle_counter[TextureLimit];
  108. int triangle_counter_alpha[TextureLimit];
  109. int rectangle_counter[TextureLimit];
  110. int rectangle_counter_alpha[TextureLimit];
  111. int tris_mesh_map[TextureLimit];
  112. int rect_mesh_map[TextureLimit];
  113. for (unsigned int i = 0; i < TextureLimit; ++i)
  114. {
  115. triangle_counter[i] = 0;
  116. triangle_counter_alpha[i] = 0;
  117. rectangle_counter[i] = 0;
  118. rectangle_counter_alpha[i] = 0;
  119. tris_mesh_map[i] = -1;
  120. rect_mesh_map[i] = -1;
  121. }
  122. unsigned int numTris = 0;
  123. unsigned int numQuads = 0;
  124. int texture;
  125. unsigned int r, t, q, v;
  126. unsigned int indices[4];
  127. float texCoords[8];
  128. count = tr.getRoomTriangleCount(index);
  129. // Mongoose 2002.08.15, Presort by alpha and texture and setup mapping
  130. for (t = 0; t < count; ++t)
  131. {
  132. tr.getRoomTriangle(index, t,
  133. indices, texCoords, &texture, &flags);
  134. texture += getGame().getTextureStart();
  135. if (texture > (int)TextureLimit)
  136. {
  137. getConsole().print("Handling bad room[%i].tris[%i].texture = %i",
  138. index, t, texture);
  139. texture = TextureLimit - 1;
  140. }
  141. // Counters set up polygon allocation
  142. if (flags & tombraiderFace_Alpha ||
  143. flags & tombraiderFace_PartialAlpha)
  144. {
  145. triangle_counter_alpha[texture] += 1;
  146. }
  147. else
  148. {
  149. triangle_counter[texture] += 1;
  150. }
  151. // Counter sets up texture id to mesh id mapping
  152. if (tris_mesh_map[texture] == -1)
  153. {
  154. tris_mesh_map[texture] = ++numTris;
  155. }
  156. }
  157. count = tr.getRoomRectangleCount(index);
  158. for (r = 0; r < count; ++r)
  159. {
  160. tr.getRoomRectangle(index, r,
  161. indices, texCoords, &texture, &flags);
  162. texture += getGame().getTextureStart();
  163. if (texture > (int)TextureLimit)
  164. {
  165. getConsole().print("Handling bad room[%i].quad[%i].texture = %i",
  166. index, r, texture);
  167. texture = TextureLimit - 1;
  168. }
  169. if (flags & tombraiderFace_Alpha ||
  170. flags & tombraiderFace_PartialAlpha)
  171. {
  172. rectangle_counter_alpha[texture] += 1;
  173. }
  174. else
  175. {
  176. rectangle_counter[texture] += 1;
  177. }
  178. if (rect_mesh_map[texture] == -1)
  179. {
  180. rect_mesh_map[texture] = ++numQuads;
  181. }
  182. }
  183. // Allocate indexed polygon meshes
  184. mesh.allocateTriangles(numTris);
  185. mesh.allocateRectangles(numQuads);
  186. for (unsigned int i = 0, j = 0; i < TextureLimit; ++i)
  187. {
  188. if (tris_mesh_map[i] > 0)
  189. {
  190. j = tris_mesh_map[i] - 1;
  191. t = triangle_counter[i];
  192. mesh.mTris[j].texture = i;
  193. #ifdef MULTITEXTURE
  194. mesh.mTris[j].bumpmap = gMapTex2Bump[i];
  195. #endif
  196. mesh.mTris[j].cnum_triangles = 0;
  197. mesh.mTris[j].num_triangles = 0;
  198. mesh.mTris[j].cnum_alpha_triangles = 0;
  199. mesh.mTris[j].num_alpha_triangles = 0;
  200. mesh.mTris[j].triangles = 0x0;
  201. mesh.mTris[j].alpha_triangles = 0x0;
  202. mesh.mTris[j].texcoors = 0x0;
  203. mesh.mTris[j].texcoors2 = 0x0;
  204. if (t > 0)
  205. {
  206. mesh.mTris[j].num_triangles = t;
  207. mesh.mTris[j].triangles = new unsigned int[t*3];
  208. mesh.mTris[j].num_texcoors = t * 3;
  209. mesh.mTris[j].texcoors = new vec2_t[t * 3];
  210. }
  211. t = triangle_counter_alpha[i];
  212. if (t > 0)
  213. {
  214. mesh.mTris[j].num_alpha_triangles = t;
  215. mesh.mTris[j].alpha_triangles = new unsigned int[t*3];
  216. mesh.mTris[j].num_texcoors2 = t * 3;
  217. mesh.mTris[j].texcoors2 = new vec2_t[t * 3];
  218. }
  219. }
  220. ///////////////////////////////////////////
  221. if (rect_mesh_map[i] > 0)
  222. {
  223. j = rect_mesh_map[i] - 1;
  224. r = rectangle_counter[i];
  225. mesh.mQuads[j].texture = i;
  226. #ifdef MULTITEXTURE
  227. mesh.mQuads[j].bumpmap = gMapTex2Bump[i];
  228. #endif
  229. mesh.mQuads[j].cnum_quads = 0;
  230. mesh.mQuads[j].num_quads = 0;
  231. mesh.mQuads[j].cnum_alpha_quads = 0;
  232. mesh.mQuads[j].num_alpha_quads = 0;
  233. mesh.mQuads[j].quads = 0x0;
  234. mesh.mQuads[j].alpha_quads = 0x0;
  235. mesh.mQuads[j].texcoors = 0x0;
  236. mesh.mQuads[j].texcoors2 = 0x0;
  237. if (r > 0)
  238. {
  239. mesh.mQuads[j].num_quads = r;
  240. mesh.mQuads[j].quads = new unsigned int[r*4];
  241. mesh.mQuads[j].num_texcoors = r * 4;
  242. mesh.mQuads[j].texcoors = new vec2_t[r * 4];
  243. }
  244. r = rectangle_counter_alpha[i];
  245. if (r > 0)
  246. {
  247. mesh.mQuads[j].num_alpha_quads = r;
  248. mesh.mQuads[j].alpha_quads = new unsigned int[r*4];
  249. mesh.mQuads[j].num_texcoors2 = r * 4;
  250. mesh.mQuads[j].texcoors2 = new vec2_t[r * 4];
  251. }
  252. }
  253. }
  254. // Generate textured triangles
  255. count = tr.getRoomTriangleCount(index);
  256. for (t = 0; t < count; ++t)
  257. {
  258. tr.getRoomTriangle(index, t,
  259. indices, texCoords, &texture, &flags);
  260. // Adjust texture id using getGame().getTextureStart() to map into
  261. // correct textures
  262. texture += getGame().getTextureStart();
  263. unsigned int j = tris_mesh_map[texture] - 1;
  264. // Setup per vertex
  265. for (unsigned int i = 0; i < 3; ++i)
  266. {
  267. // Get vertex index {(0, a), (1, b), (2, c)}
  268. v = indices[i];
  269. if ((flags & tombraiderFace_Alpha ||
  270. flags & tombraiderFace_PartialAlpha) &&
  271. mesh.mTris[j].num_alpha_triangles > 0)
  272. {
  273. q = mesh.mTris[j].cnum_alpha_triangles*3+i;
  274. mesh.mTris[j].alpha_triangles[q] = v;
  275. mesh.mTris[j].texcoors2[q][0] = texCoords[i*2];
  276. mesh.mTris[j].texcoors2[q][1] = texCoords[i*2+1];
  277. }
  278. else if (mesh.mTris[j].num_triangles > 0)
  279. {
  280. q = mesh.mTris[j].cnum_triangles*3+i;
  281. mesh.mTris[j].triangles[q] = v;
  282. mesh.mTris[j].texcoors[q][0] = texCoords[i*2];
  283. mesh.mTris[j].texcoors[q][1] = texCoords[i*2+1];
  284. }
  285. // Partial alpha hack
  286. if (flags & tombraiderFace_PartialAlpha)
  287. {
  288. //mesh.colors[v].rgba[3] = 0.45;
  289. }
  290. }
  291. if (flags & tombraiderFace_Alpha ||
  292. flags & tombraiderFace_PartialAlpha)
  293. {
  294. mesh.mTris[j].cnum_alpha_triangles++;
  295. }
  296. else
  297. {
  298. mesh.mTris[j].cnum_triangles++;
  299. }
  300. }
  301. // Generate textured quads
  302. count = tr.getRoomRectangleCount(index);
  303. for (r = 0; r < count; ++r)
  304. {
  305. tr.getRoomRectangle(index, r,
  306. indices, texCoords, &texture, &flags);
  307. // Adjust texture id using getGame().getTextureStart() to map into
  308. // correct textures
  309. texture += getGame().getTextureStart();
  310. if (texture > (int)TextureLimit)
  311. {
  312. texture = TextureLimit - 1;
  313. }
  314. unsigned int j = rect_mesh_map[texture] - 1;
  315. if (mesh.mQuads[j].num_quads <= 0 &&
  316. mesh.mQuads[j].num_alpha_quads <= 0)
  317. continue;
  318. // Setup per vertex
  319. for (unsigned int i = 0; i < 4; ++i)
  320. {
  321. // Get vertex index {(0, a), (1, b), (2, c), (3, d)}
  322. v = indices[i];
  323. if ((flags & tombraiderFace_Alpha ||
  324. flags & tombraiderFace_PartialAlpha) &&
  325. mesh.mQuads[j].num_alpha_quads > 0)
  326. {
  327. q = mesh.mQuads[j].cnum_alpha_quads*4+i;
  328. mesh.mQuads[j].alpha_quads[q] = v;
  329. mesh.mQuads[j].texcoors2[q][0] = texCoords[i*2];
  330. mesh.mQuads[j].texcoors2[q][1] = texCoords[i*2+1];
  331. }
  332. else if (mesh.mQuads[j].num_quads > 0)
  333. {
  334. q = mesh.mQuads[j].cnum_quads*4+i;
  335. mesh.mQuads[j].quads[q] = v;
  336. mesh.mQuads[j].texcoors[q][0] = texCoords[i*2];
  337. mesh.mQuads[j].texcoors[q][1] = texCoords[i*2+1];
  338. }
  339. // Partial alpha hack
  340. if (flags & tombraiderFace_PartialAlpha)
  341. {
  342. //rRoom->mesh.colors[v].rgba[3] = 0.45;
  343. }
  344. }
  345. if (flags & tombraiderFace_Alpha ||
  346. flags & tombraiderFace_PartialAlpha)
  347. {
  348. mesh.mQuads[j].cnum_alpha_quads++;
  349. }
  350. else
  351. {
  352. mesh.mQuads[j].cnum_quads++;
  353. }
  354. }
  355. #endif
  356. }
  357. #define EMPTY_VECTOR(x) \
  358. while (!x.empty()) { \
  359. delete x[x.size() - 1]; \
  360. x.pop_back(); \
  361. }
  362. Room::~Room() {
  363. EMPTY_VECTOR(sprites);
  364. EMPTY_VECTOR(models);
  365. EMPTY_VECTOR(portals);
  366. EMPTY_VECTOR(boxes);
  367. EMPTY_VECTOR(sectors);
  368. EMPTY_VECTOR(lights);
  369. }
  370. void Room::display(bool alpha) {
  371. glPushMatrix();
  372. //LightingSetup();
  373. getRender().mTexture.bindTextureId(0); // WHITE texture
  374. if ((!alpha) && getRender().getMode() == Render::modeWireframe) {
  375. glLineWidth(2.0);
  376. glColor3fv(RED);
  377. for (unsigned int i = 0; i < sizePortals(); i++) {
  378. Portal &portal = getPortal(i);
  379. vec3_t vertices[4];
  380. portal.getVertices(vertices);
  381. glBegin(GL_LINE_LOOP);
  382. glVertex3fv(vertices[0]);
  383. glVertex3fv(vertices[1]);
  384. glVertex3fv(vertices[2]);
  385. glVertex3fv(vertices[3]);
  386. glEnd();
  387. }
  388. glLineWidth(1.0);
  389. }
  390. if (getRender().getMode() == Render::modeWireframe && (!alpha)) {
  391. bbox.display(true, RED, GREEN);
  392. }
  393. glTranslated(pos[0], pos[1], pos[2]);
  394. // Reset since GL_MODULATE used, reset to WHITE
  395. glColor3fv(WHITE);
  396. switch (getRender().getMode())
  397. {
  398. case Render::modeWireframe:
  399. getMesh().mMode = Mesh::MeshModeWireframe;
  400. break;
  401. case Render::modeSolid:
  402. getMesh().mMode = Mesh::MeshModeSolid;
  403. break;
  404. default:
  405. getMesh().mMode = Mesh::MeshModeTexture;
  406. break;
  407. }
  408. if (alpha)
  409. getMesh().drawAlpha();
  410. else
  411. getMesh().drawSolid();
  412. glPopMatrix();
  413. //getRender().mTexture.bindTextureId(0);
  414. // Draw other room meshes and sprites
  415. if (alpha || (getRender().getMode() == Render::modeWireframe)
  416. || (getRender().getMode() == Render::modeSolid)) {
  417. sortModels();
  418. for (unsigned int i = 0; i < sizeModels(); i++)
  419. getModel(i).display();
  420. for (unsigned int i = 0; i < sizeSprites(); i++)
  421. getSprite(i).display();
  422. }
  423. }
  424. bool Room::isWall(unsigned int sector) {
  425. assert(sector >= 0);
  426. assert(sector < sectors.size());
  427. //! \fixme is (sector > 0) correct??
  428. return ((sector > 0) && sectors.at(sector)->isWall());
  429. }
  430. int Room::getSector(float x, float z, float *floor, float *ceiling) {
  431. assert(floor != NULL);
  432. assert(ceiling != NULL);
  433. int sector = getSector(x, z);
  434. if ((sector >= 0) && (sector < (int)sectors.size())) {
  435. *floor = sectors.at(sector)->getFloor();
  436. *ceiling = sectors.at(sector)->getCeiling();
  437. }
  438. return sector;
  439. }
  440. int Room::getSector(float x, float z) {
  441. int sector = (((((int)x - (int)pos[0]) / 1024) *
  442. numZSectors) + (((int)z - (int)pos[2]) / 1024));
  443. if (sector < 0)
  444. return -1;
  445. return sector;
  446. }
  447. void Room::getHeightAtPosition(float x, float *y, float z) {
  448. int sector = getSector(x, z);
  449. if ((sector >= 0) && (sector < (int)sectors.size()))
  450. *y = sectors.at(sector)->getFloor();
  451. }
  452. int Room::getAdjoiningRoom(float x, float y, float z,
  453. float x2, float y2, float z2) {
  454. vec3_t intersect, p1, p2;
  455. vec3_t vertices[4];
  456. p1[0] = x; p1[1] = y; p1[2] = z;
  457. p2[0] = x2; p2[1] = y2; p2[2] = z2;
  458. for (unsigned int i = 0; i < portals.size(); i++) {
  459. portals.at(i)->getVertices(vertices);
  460. if (intersectionLinePolygon(intersect, p1, p2, //4,
  461. vertices))
  462. return portals.at(i)->getAdjoiningRoom();
  463. }
  464. return -1;
  465. }
  466. unsigned int Room::getFlags() {
  467. return flags;
  468. }
  469. unsigned int Room::getNumXSectors() {
  470. return numXSectors;
  471. }
  472. unsigned int Room::getNumZSectors() {
  473. return numZSectors;
  474. }
  475. void Room::getPos(vec3_t p) {
  476. for (unsigned int i = 0; i < 3; i++)
  477. p[i] = pos[i];
  478. }
  479. unsigned int Room::sizeAdjacentRooms() {
  480. return adjacentRooms.size();
  481. }
  482. int Room::getAdjacentRoom(unsigned int index) {
  483. assert(index < adjacentRooms.size());
  484. return adjacentRooms.at(index);
  485. }
  486. unsigned int Room::sizePortals() {
  487. return portals.size();
  488. }
  489. Portal &Room::getPortal(unsigned int index) {
  490. assert(index < portals.size());
  491. return *portals.at(index);
  492. }
  493. unsigned int Room::sizeSectors() {
  494. return sectors.size();
  495. }
  496. Sector &Room::getSector(unsigned int index) {
  497. assert(index < sectors.size());
  498. return *sectors.at(index);
  499. }
  500. unsigned int Room::sizeBox() {
  501. return boxes.size();
  502. }
  503. Box &Room::getBox(unsigned int index) {
  504. assert(index < boxes.size());
  505. return *boxes.at(index);
  506. }
  507. unsigned int Room::sizeModels() {
  508. return models.size();
  509. }
  510. StaticModel &Room::getModel(unsigned int index) {
  511. assert(index < models.size());
  512. return *models.at(index);
  513. }
  514. void Room::sortModels() {
  515. std::sort(models.begin(), models.end());
  516. }
  517. unsigned int Room::sizeLights() {
  518. return lights.size();
  519. }
  520. Light &Room::getLight(unsigned int index) {
  521. assert(index < lights.size());
  522. return *lights.at(index);
  523. }
  524. unsigned int Room::sizeSprites() {
  525. return sprites.size();
  526. }
  527. Sprite &Room::getSprite(unsigned int index) {
  528. assert(index < sprites.size());
  529. return *sprites.at(index);
  530. }
  531. BoundingBox &Room::getBoundingBox() {
  532. return bbox;
  533. }
  534. Mesh &Room::getMesh() {
  535. return mesh;
  536. }