Open Source Tomb Raider Engine
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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