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

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