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

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