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.

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. }