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

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