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

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