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

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