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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /*!
  2. * \file src/Room.cpp
  3. * \brief World Room Mesh
  4. *
  5. * \author xythobuz
  6. */
  7. #ifdef __APPLE__
  8. #include <OpenGL/gl.h>
  9. #include <OpenGL/glu.h>
  10. #else
  11. #include <GL/gl.h>
  12. #include <GL/glu.h>
  13. #endif
  14. #include <algorithm>
  15. #include <assert.h>
  16. #include "main.h"
  17. #include "Room.h"
  18. #ifndef EXPERIMENTAL_UNIFIED_ROOM_GEOMETERY
  19. #define TextureLimit 24
  20. #endif
  21. Light::Light(TombRaider &tr, unsigned int room, unsigned int index) {
  22. unsigned int lightFlags, lightType;
  23. tr.getRoomLight(room, index, pos, color,
  24. dir, &att, &cutoff, &lightType, &lightFlags);
  25. switch (lightType) {
  26. case tombraiderLight_typeDirectional:
  27. type = Light::typeDirectional;
  28. break;
  29. case tombraiderLight_typeSpot:
  30. type = Light::typeSpot;
  31. break;
  32. case tombraiderLight_typePoint:
  33. default:
  34. type = Light::typePoint;
  35. }
  36. //! \todo Light flags?
  37. }
  38. void Light::getPos(vec4_t p) {
  39. p[0] = pos[0];
  40. p[1] = pos[1];
  41. p[2] = pos[2];
  42. p[3] = pos[3];
  43. }
  44. void Light::getDir(vec3_t d) {
  45. d[0] = dir[0];
  46. d[1] = dir[1];
  47. d[2] = dir[2];
  48. }
  49. vec_t Light::getAtt() {
  50. return att;
  51. }
  52. void Light::getColor(vec4_t c) {
  53. c[0] = color[0];
  54. c[1] = color[1];
  55. c[2] = color[2];
  56. c[3] = color[3];
  57. }
  58. vec_t Light::getCutoff() {
  59. return cutoff;
  60. }
  61. Light::LightType Light::getType() {
  62. return type;
  63. }
  64. StaticModel::StaticModel(TombRaider &tr, unsigned int room, unsigned int i) {
  65. tr.getRoomModel(room, i, &index, pos, &yaw);
  66. }
  67. void StaticModel::display() {
  68. model_mesh_t *mesh = getWorld().getMesh(index);
  69. if (!mesh)
  70. return;
  71. if (!getRender().isVisible(pos[0], pos[1], pos[2], mesh->radius))
  72. return;
  73. glPushMatrix();
  74. glTranslated(pos[0], pos[1], pos[2]);
  75. glRotated(yaw, 0, 1, 0);
  76. getRender().drawModelMesh(mesh, Render::roomMesh);
  77. glPopMatrix();
  78. }
  79. bool StaticModel::operator<(const StaticModel &other) {
  80. vec_t distA, distB;
  81. distA = getRender().mViewVolume.getDistToSphereFromNear(pos[0],
  82. pos[1], pos[2], 128.0f);
  83. distB = getRender().mViewVolume.getDistToSphereFromNear(other.pos[0],
  84. other.pos[1], other.pos[2], 128.0f);
  85. return (distA < distB);
  86. }
  87. Portal::Portal(TombRaider &tr, unsigned int room, unsigned int index, Matrix &transform) {
  88. float portalVertices[12];
  89. tr.getRoomPortal(room, index, &adjoiningRoom, normal, portalVertices);
  90. for (unsigned int j = 0; j < 4; ++j) {
  91. vertices[j][0] = portalVertices[j*3];
  92. vertices[j][1] = portalVertices[j*3+1];
  93. vertices[j][2] = portalVertices[j*3+2];
  94. // Relative coors in vis portals
  95. transform.multiply3v(vertices[j], vertices[j]);
  96. }
  97. }
  98. void Portal::getVertices(vec3_t vert[4]) {
  99. for (unsigned int i = 0; i < 4; i++) {
  100. for (unsigned int j = 0; j < 3; j++) {
  101. vert[i][j] = vertices[i][j];
  102. }
  103. }
  104. }
  105. int Portal::getAdjoiningRoom() {
  106. return adjoiningRoom;
  107. }
  108. Box::Box(TombRaider &tr, unsigned int room, unsigned int index) {
  109. tr.getRoomBox(room, index, a, b, c, d);
  110. }
  111. Sector::Sector(TombRaider &tr, unsigned int room, unsigned int index) {
  112. unsigned int sectorFlags;
  113. int floorDataIndex, boxIndex, roomBelow, roomAbove;
  114. tr.getRoomSector(room, index, &sectorFlags,
  115. &ceiling, &floor, &floorDataIndex, &boxIndex,
  116. &roomBelow, &roomAbove);
  117. wall = (sectorFlags & tombraiderSector_wall);
  118. }
  119. vec_t Sector::getFloor() {
  120. return floor;
  121. }
  122. vec_t Sector::getCeiling() {
  123. return ceiling;
  124. }
  125. bool Sector::isWall() {
  126. return wall;
  127. }
  128. Room::Room(TombRaider &tr, unsigned int index) {
  129. Matrix transform;
  130. if (!tr.isRoomValid(index)) {
  131. getConsole().print("WARNING: Handling invalid vertex array in room");
  132. //printf("x");
  133. //fflush(stdout);
  134. return;
  135. }
  136. tr.getRoomInfo(index, &flags, pos, bbox[0], bbox[1]);
  137. // Adjust positioning for OR world coordinate translation
  138. bbox[0][0] += pos[0];
  139. bbox[1][0] += pos[0];
  140. bbox[0][2] += pos[2];
  141. bbox[1][2] += pos[2];
  142. // Mongoose 2002.04.03, Setup 3D transform
  143. transform.setIdentity();
  144. transform.translate(pos);
  145. // Current room is always first
  146. adjacentRooms.push_back(index);
  147. // Setup portals
  148. unsigned int count = tr.getRoomPortalCount(index);
  149. for (unsigned int i = 0; i < count; i++) {
  150. portals.push_back(new Portal(tr, index, i, transform));
  151. adjacentRooms.push_back(portals.back()->getAdjoiningRoom());
  152. }
  153. //! \fixme Use more of sector structure, boxes, and floordata
  154. // List of sectors in this room
  155. count = tr.getRoomSectorCount(index, &numZSectors, &numXSectors);
  156. for (unsigned int i = 0; i < count; i++)
  157. sectors.push_back(new Sector(tr, index, i));
  158. // Setup collision boxes
  159. //! fixme Should use sectors, but this is a test
  160. count = tr.getRoomBoxCount(index);
  161. for (unsigned int i = 0; i < count; i++)
  162. boxes.push_back(new Box(tr, index, i));
  163. // Setup room lights
  164. count = tr.getRoomLightCount(index);
  165. for (unsigned int i = 0; i < count; i++)
  166. lights.push_back(new Light(tr, index, i));
  167. // Room models
  168. count = tr.getRoomModelCount(index);
  169. for (unsigned int i = 0; i < count; i++)
  170. models.push_back(new StaticModel(tr, index, i));
  171. // Room sprites
  172. count = tr.getRoomSpriteCount(index);
  173. for (unsigned int i = 0; i < count; i++)
  174. sprites.push_back(new Sprite(tr, index, i));
  175. //#define EXPERIMENTAL_UNIFIED_ROOM_GEOMETERY
  176. #ifdef EXPERIMENTAL_UNIFIED_ROOM_GEOMETERY
  177. unsigned int vertexCount, normalCount, colorCount, triCount;
  178. vec_t *vertexArray;
  179. vec_t *normalArray;
  180. vec_t *colorArray;
  181. unsigned int *indices, *flags;
  182. float *texCoords;
  183. int *textures;
  184. tr.getRoomVertexArrays(index,
  185. &vertexCount, &vertexArray,
  186. &normalCount, &normalArray,
  187. &colorCount, &colorArray);
  188. mesh.bufferVertexArray(vertexCount, (vec_t *)vertexArray);
  189. mesh.bufferNormalArray(normalCount, (vec_t *)normalArray);
  190. mesh.bufferColorArray(vertexCount, (vec_t *)colorArray);
  191. tr.getRoomTriangles(index, getGame().getTextureStart(),
  192. &triCount, &indices, &texCoords, &textures,
  193. &flags);
  194. mesh.bufferTriangles(triCount, indices, texCoords, textures, flags);
  195. #else
  196. float rgba[4];
  197. float xyz[3];
  198. count = tr.getRoomVertexCount(index);
  199. mesh.allocateVertices(count);
  200. mesh.allocateNormals(0); // count
  201. mesh.allocateColors(count);
  202. for (unsigned int i = 0; i < count; ++i)
  203. {
  204. tr.getRoomVertex(index, i, xyz, rgba);
  205. mesh.setVertex(i, xyz[0], xyz[1], xyz[2]);
  206. mesh.setColor(i, rgba);
  207. }
  208. // Mongoose 2002.06.09, Setup allocation of meshes and polygons
  209. // Counters ( Textured polygon lists are allocated per texture)
  210. // ( Textures are mapped to these meshes )
  211. int triangle_counter[TextureLimit];
  212. int triangle_counter_alpha[TextureLimit];
  213. int rectangle_counter[TextureLimit];
  214. int rectangle_counter_alpha[TextureLimit];
  215. int tris_mesh_map[TextureLimit];
  216. int rect_mesh_map[TextureLimit];
  217. for (unsigned int i = 0; i < TextureLimit; ++i)
  218. {
  219. triangle_counter[i] = 0;
  220. triangle_counter_alpha[i] = 0;
  221. rectangle_counter[i] = 0;
  222. rectangle_counter_alpha[i] = 0;
  223. tris_mesh_map[i] = -1;
  224. rect_mesh_map[i] = -1;
  225. }
  226. unsigned int numTris = 0;
  227. unsigned int numQuads = 0;
  228. int texture;
  229. unsigned int r, t, q, v;
  230. unsigned int indices[4];
  231. float texCoords[8];
  232. count = tr.getRoomTriangleCount(index);
  233. // Mongoose 2002.08.15, Presort by alpha and texture and setup mapping
  234. for (t = 0; t < count; ++t)
  235. {
  236. tr.getRoomTriangle(index, t,
  237. indices, texCoords, &texture, &flags);
  238. texture += getGame().getTextureStart();
  239. if (texture > (int)TextureLimit)
  240. {
  241. getConsole().print("Handling bad room[%i].tris[%i].texture = %i",
  242. index, t, texture);
  243. texture = TextureLimit - 1;
  244. }
  245. // Counters set up polygon allocation
  246. if (flags & tombraiderFace_Alpha ||
  247. flags & tombraiderFace_PartialAlpha)
  248. {
  249. triangle_counter_alpha[texture] += 1;
  250. }
  251. else
  252. {
  253. triangle_counter[texture] += 1;
  254. }
  255. // Counter sets up texture id to mesh id mapping
  256. if (tris_mesh_map[texture] == -1)
  257. {
  258. tris_mesh_map[texture] = ++numTris;
  259. }
  260. }
  261. count = tr.getRoomRectangleCount(index);
  262. for (r = 0; r < count; ++r)
  263. {
  264. tr.getRoomRectangle(index, r,
  265. indices, texCoords, &texture, &flags);
  266. texture += getGame().getTextureStart();
  267. if (texture > (int)TextureLimit)
  268. {
  269. getConsole().print("Handling bad room[%i].quad[%i].texture = %i",
  270. index, r, texture);
  271. texture = TextureLimit - 1;
  272. }
  273. if (flags & tombraiderFace_Alpha ||
  274. flags & tombraiderFace_PartialAlpha)
  275. {
  276. rectangle_counter_alpha[texture] += 1;
  277. }
  278. else
  279. {
  280. rectangle_counter[texture] += 1;
  281. }
  282. if (rect_mesh_map[texture] == -1)
  283. {
  284. rect_mesh_map[texture] = ++numQuads;
  285. }
  286. }
  287. // Allocate indexed polygon meshes
  288. mesh.allocateTriangles(numTris);
  289. mesh.allocateRectangles(numQuads);
  290. for (unsigned int i = 0, j = 0; i < TextureLimit; ++i)
  291. {
  292. if (tris_mesh_map[i] > 0)
  293. {
  294. j = tris_mesh_map[i] - 1;
  295. t = triangle_counter[i];
  296. mesh.mTris[j].texture = i;
  297. #ifdef MULTITEXTURE
  298. mesh.mTris[j].bumpmap = gMapTex2Bump[i];
  299. #endif
  300. mesh.mTris[j].cnum_triangles = 0;
  301. mesh.mTris[j].num_triangles = 0;
  302. mesh.mTris[j].cnum_alpha_triangles = 0;
  303. mesh.mTris[j].num_alpha_triangles = 0;
  304. mesh.mTris[j].triangles = 0x0;
  305. mesh.mTris[j].alpha_triangles = 0x0;
  306. mesh.mTris[j].texcoors = 0x0;
  307. mesh.mTris[j].texcoors2 = 0x0;
  308. if (t > 0)
  309. {
  310. mesh.mTris[j].num_triangles = t;
  311. mesh.mTris[j].triangles = new unsigned int[t*3];
  312. mesh.mTris[j].num_texcoors = t * 3;
  313. mesh.mTris[j].texcoors = new vec2_t[t * 3];
  314. }
  315. t = triangle_counter_alpha[i];
  316. if (t > 0)
  317. {
  318. mesh.mTris[j].num_alpha_triangles = t;
  319. mesh.mTris[j].alpha_triangles = new unsigned int[t*3];
  320. mesh.mTris[j].num_texcoors2 = t * 3;
  321. mesh.mTris[j].texcoors2 = new vec2_t[t * 3];
  322. }
  323. }
  324. ///////////////////////////////////////////
  325. if (rect_mesh_map[i] > 0)
  326. {
  327. j = rect_mesh_map[i] - 1;
  328. r = rectangle_counter[i];
  329. mesh.mQuads[j].texture = i;
  330. #ifdef MULTITEXTURE
  331. mesh.mQuads[j].bumpmap = gMapTex2Bump[i];
  332. #endif
  333. mesh.mQuads[j].cnum_quads = 0;
  334. mesh.mQuads[j].num_quads = 0;
  335. mesh.mQuads[j].cnum_alpha_quads = 0;
  336. mesh.mQuads[j].num_alpha_quads = 0;
  337. mesh.mQuads[j].quads = 0x0;
  338. mesh.mQuads[j].alpha_quads = 0x0;
  339. mesh.mQuads[j].texcoors = 0x0;
  340. mesh.mQuads[j].texcoors2 = 0x0;
  341. if (r > 0)
  342. {
  343. mesh.mQuads[j].num_quads = r;
  344. mesh.mQuads[j].quads = new unsigned int[r*4];
  345. mesh.mQuads[j].num_texcoors = r * 4;
  346. mesh.mQuads[j].texcoors = new vec2_t[r * 4];
  347. }
  348. r = rectangle_counter_alpha[i];
  349. if (r > 0)
  350. {
  351. mesh.mQuads[j].num_alpha_quads = r;
  352. mesh.mQuads[j].alpha_quads = new unsigned int[r*4];
  353. mesh.mQuads[j].num_texcoors2 = r * 4;
  354. mesh.mQuads[j].texcoors2 = new vec2_t[r * 4];
  355. }
  356. }
  357. }
  358. // Generate textured triangles
  359. count = tr.getRoomTriangleCount(index);
  360. for (t = 0; t < count; ++t)
  361. {
  362. tr.getRoomTriangle(index, t,
  363. indices, texCoords, &texture, &flags);
  364. // Adjust texture id using getGame().getTextureStart() to map into
  365. // correct textures
  366. texture += getGame().getTextureStart();
  367. unsigned int j = tris_mesh_map[texture] - 1;
  368. // Setup per vertex
  369. for (unsigned int i = 0; i < 3; ++i)
  370. {
  371. // Get vertex index {(0, a), (1, b), (2, c)}
  372. v = indices[i];
  373. if ((flags & tombraiderFace_Alpha ||
  374. flags & tombraiderFace_PartialAlpha) &&
  375. mesh.mTris[j].num_alpha_triangles > 0)
  376. {
  377. q = mesh.mTris[j].cnum_alpha_triangles*3+i;
  378. mesh.mTris[j].alpha_triangles[q] = v;
  379. mesh.mTris[j].texcoors2[q][0] = texCoords[i*2];
  380. mesh.mTris[j].texcoors2[q][1] = texCoords[i*2+1];
  381. }
  382. else if (mesh.mTris[j].num_triangles > 0)
  383. {
  384. q = mesh.mTris[j].cnum_triangles*3+i;
  385. mesh.mTris[j].triangles[q] = v;
  386. mesh.mTris[j].texcoors[q][0] = texCoords[i*2];
  387. mesh.mTris[j].texcoors[q][1] = texCoords[i*2+1];
  388. }
  389. // Partial alpha hack
  390. if (flags & tombraiderFace_PartialAlpha)
  391. {
  392. //mesh.colors[v].rgba[3] = 0.45;
  393. }
  394. }
  395. if (flags & tombraiderFace_Alpha ||
  396. flags & tombraiderFace_PartialAlpha)
  397. {
  398. mesh.mTris[j].cnum_alpha_triangles++;
  399. }
  400. else
  401. {
  402. mesh.mTris[j].cnum_triangles++;
  403. }
  404. }
  405. // Generate textured quads
  406. count = tr.getRoomRectangleCount(index);
  407. for (r = 0; r < count; ++r)
  408. {
  409. tr.getRoomRectangle(index, r,
  410. indices, texCoords, &texture, &flags);
  411. // Adjust texture id using getGame().getTextureStart() to map into
  412. // correct textures
  413. texture += getGame().getTextureStart();
  414. if (texture > (int)TextureLimit)
  415. {
  416. texture = TextureLimit - 1;
  417. }
  418. unsigned int j = rect_mesh_map[texture] - 1;
  419. if (mesh.mQuads[j].num_quads <= 0 &&
  420. mesh.mQuads[j].num_alpha_quads <= 0)
  421. continue;
  422. // Setup per vertex
  423. for (unsigned int i = 0; i < 4; ++i)
  424. {
  425. // Get vertex index {(0, a), (1, b), (2, c), (3, d)}
  426. v = indices[i];
  427. if ((flags & tombraiderFace_Alpha ||
  428. flags & tombraiderFace_PartialAlpha) &&
  429. mesh.mQuads[j].num_alpha_quads > 0)
  430. {
  431. q = mesh.mQuads[j].cnum_alpha_quads*4+i;
  432. mesh.mQuads[j].alpha_quads[q] = v;
  433. mesh.mQuads[j].texcoors2[q][0] = texCoords[i*2];
  434. mesh.mQuads[j].texcoors2[q][1] = texCoords[i*2+1];
  435. }
  436. else if (mesh.mQuads[j].num_quads > 0)
  437. {
  438. q = mesh.mQuads[j].cnum_quads*4+i;
  439. mesh.mQuads[j].quads[q] = v;
  440. mesh.mQuads[j].texcoors[q][0] = texCoords[i*2];
  441. mesh.mQuads[j].texcoors[q][1] = texCoords[i*2+1];
  442. }
  443. // Partial alpha hack
  444. if (flags & tombraiderFace_PartialAlpha)
  445. {
  446. //rRoom->mesh.colors[v].rgba[3] = 0.45;
  447. }
  448. }
  449. if (flags & tombraiderFace_Alpha ||
  450. flags & tombraiderFace_PartialAlpha)
  451. {
  452. mesh.mQuads[j].cnum_alpha_quads++;
  453. }
  454. else
  455. {
  456. mesh.mQuads[j].cnum_quads++;
  457. }
  458. }
  459. #endif
  460. }
  461. #define EMPTY_VECTOR(x) \
  462. while (!x.empty()) { \
  463. delete x[x.size() - 1]; \
  464. x.pop_back(); \
  465. }
  466. Room::~Room() {
  467. EMPTY_VECTOR(sprites);
  468. EMPTY_VECTOR(models);
  469. EMPTY_VECTOR(portals);
  470. EMPTY_VECTOR(boxes);
  471. EMPTY_VECTOR(sectors);
  472. EMPTY_VECTOR(lights);
  473. }
  474. unsigned int Room::getFlags() {
  475. return flags;
  476. }
  477. unsigned int Room::getNumXSectors() {
  478. return numXSectors;
  479. }
  480. unsigned int Room::getNumZSectors() {
  481. return numZSectors;
  482. }
  483. void Room::getPos(vec3_t p) {
  484. for (unsigned int i = 0; i < 3; i++)
  485. p[i] = pos[i];
  486. }
  487. void Room::getBoundingBox(vec3_t box[2]) {
  488. for (unsigned int i = 0; i < 2; i++)
  489. for (unsigned int j = 0; j < 3; j++)
  490. box[i][j] = bbox[i][j];
  491. }
  492. bool Room::inBox(vec_t x, vec_t y, vec_t z) {
  493. return ((y > bbox[0][1]) && (y < bbox[1][1]) && inBoxPlane(x, z));
  494. }
  495. bool Room::inBoxPlane(vec_t x, vec_t z) {
  496. return ((x > bbox[0][0]) && (x < bbox[1][0])
  497. && (z > bbox[0][2]) && (z < bbox[1][2]));
  498. }
  499. unsigned int Room::sizeAdjacentRooms() {
  500. return adjacentRooms.size();
  501. }
  502. int Room::getAdjacentRoom(unsigned int index) {
  503. assert(index < adjacentRooms.size());
  504. return adjacentRooms.at(index);
  505. }
  506. unsigned int Room::sizePortals() {
  507. return portals.size();
  508. }
  509. Portal &Room::getPortal(unsigned int index) {
  510. assert(index < portals.size());
  511. return *portals.at(index);
  512. }
  513. unsigned int Room::sizeSectors() {
  514. return sectors.size();
  515. }
  516. Sector &Room::getSector(unsigned int index) {
  517. assert(index < sectors.size());
  518. return *sectors.at(index);
  519. }
  520. unsigned int Room::sizeBox() {
  521. return boxes.size();
  522. }
  523. Box &Room::getBox(unsigned int index) {
  524. assert(index < boxes.size());
  525. return *boxes.at(index);
  526. }
  527. unsigned int Room::sizeModels() {
  528. return models.size();
  529. }
  530. StaticModel &Room::getModel(unsigned int index) {
  531. assert(index < models.size());
  532. return *models.at(index);
  533. }
  534. void Room::sortModels() {
  535. std::sort(models.begin(), models.end());
  536. }
  537. unsigned int Room::sizeLights() {
  538. return lights.size();
  539. }
  540. Light &Room::getLight(unsigned int index) {
  541. assert(index < lights.size());
  542. return *lights.at(index);
  543. }
  544. unsigned int Room::sizeSprites() {
  545. return sprites.size();
  546. }
  547. Sprite &Room::getSprite(unsigned int index) {
  548. assert(index < sprites.size());
  549. return *sprites.at(index);
  550. }
  551. Mesh &Room::getMesh() {
  552. return mesh;
  553. }