Open Source Tomb Raider Engine
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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