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

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