Open Source Tomb Raider Engine
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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