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

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