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.

Render.cpp 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*!
  2. * \file src/Render.cpp
  3. * \brief OpenRaider Renderer class
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include <algorithm>
  9. #include <stdlib.h>
  10. #include <math.h>
  11. #include <string.h>
  12. #include "global.h"
  13. #include "Game.h"
  14. #include "OpenRaider.h"
  15. #include "Render.h"
  16. #include "utils/strings.h"
  17. #include "utils/tga.h"
  18. #include "Window.h"
  19. Render::Render() {
  20. mSkyMesh = -1;
  21. mSkyMeshRotation = false;
  22. mMode = Render::modeDisabled;
  23. mLock = 0;
  24. mFlags = (fRoomAlpha | fViewModel |
  25. fEntityModels | fRenderPonytail |
  26. fUsePortals | fUpdateRoomListPerFrame);
  27. }
  28. Render::~Render() {
  29. ClearWorld();
  30. }
  31. void Render::screenShot(char *filenameBase)
  32. {
  33. int sz = getWindow().getWidth() * getWindow().getHeight();
  34. unsigned char *image = new unsigned char[sz * 3];
  35. char *filename = NULL;
  36. static int count = 0;
  37. bool done = false;
  38. assert(filenameBase != NULL);
  39. // Don't overwrite files
  40. while (!done) {
  41. filename = bufferString("%s-%04i.tga", filenameBase, count++);
  42. FILE *f = fopen(filename, "rb");
  43. if (f)
  44. fclose(f);
  45. else
  46. done = true;
  47. }
  48. // Capture frame buffer
  49. glReadPixels(0, 0, getWindow().getWidth(), getWindow().getHeight(), GL_BGR_EXT, GL_UNSIGNED_BYTE, image);
  50. tgaSaveFilename(image, getWindow().getWidth(), getWindow().getHeight(), 0, "%s", filename);
  51. printf("Took screenshot '%s'.\n", filename);
  52. delete [] filename;
  53. delete [] image;
  54. }
  55. unsigned int Render::getFlags() {
  56. return mFlags;
  57. }
  58. void Render::loadTexture(unsigned char *image,
  59. unsigned int width, unsigned int height,
  60. unsigned int id)
  61. {
  62. glColor3fv(WHITE);
  63. mTexture.loadBufferSlot(image, width, height, Texture::RGBA, 32, id);
  64. }
  65. int Render::initTextures(char *textureDir) {
  66. char *filename;
  67. unsigned int numTextures = 0;
  68. unsigned char color[4];
  69. mTexture.reset();
  70. mTexture.setMaxTextureCount(128); /* TR never needs more than 32 iirc
  71. However, color texturegen is a lot */
  72. mTexture.setFlag(Texture::fUseMipmaps);
  73. color[0] = 0xff;
  74. color[1] = 0xff;
  75. color[2] = 0xff;
  76. color[3] = 0xff;
  77. if (mTexture.loadColorTexture(color, 32, 32) > -1)
  78. numTextures++;
  79. // Temporary
  80. filename = bufferString("%s/tr2/TITLE.PCX", getOpenRaider().mPakDir);
  81. if (mTexture.loadPCX(filename) > -1) {
  82. numTextures++;
  83. delete [] filename;
  84. } else {
  85. delete [] filename;
  86. //! \fixme Error Checking. Return negative error code, check in calling place too
  87. filename = bufferString("%s/%s", textureDir, "splash.tga");
  88. if (mTexture.loadTGA(filename) > -1)
  89. numTextures++;
  90. delete [] filename;
  91. }
  92. return numTextures;
  93. }
  94. void Render::ClearWorld() {
  95. mRoomRenderList.clear();
  96. }
  97. // Texture must be set to WHITE solid color texture
  98. void renderTrace(int color, vec3_t start, vec3_t end)
  99. {
  100. const float widthStart = 10.0f; //5.0f;
  101. const float widthEnd = 10.0f;
  102. float delta = randomNum(0.01f, 0.16f); // for flicker fx
  103. // Draw two long quads that skrink and fade the they go further out
  104. glBegin(GL_QUADS);
  105. switch (color)
  106. {
  107. case 0:
  108. glColor3f(0.9f - delta, 0.2f, 0.2f);
  109. break;
  110. case 1:
  111. glColor3f(0.2f, 0.9f - delta, 0.2f);
  112. break;
  113. case 2:
  114. default:
  115. glColor3f(0.2f, 0.2f, 0.9f - delta);
  116. }
  117. glVertex3f(start[0], start[1], start[2]);
  118. glVertex3f(start[0], start[1] + widthStart, start[2] + widthStart);
  119. glVertex3f(end[0], end[1] + widthEnd, end[2] + widthEnd);
  120. glVertex3f(end[0], end[1], end[2]);
  121. glVertex3f(start[0], start[1], start[2]);
  122. glVertex3f(start[0], start[1] + widthStart, start[2] - widthStart);
  123. glVertex3f(end[0], end[1] + widthEnd, end[2] - widthEnd);
  124. glVertex3f(end[0], end[1], end[2]);
  125. glVertex3f(start[0], start[1] + widthStart, start[2] + widthStart);
  126. glVertex3f(start[0], start[1] + widthStart, start[2] - widthStart);
  127. glVertex3f(end[0], end[1] + widthEnd, end[2] - widthEnd);
  128. glVertex3f(end[0], end[1] + widthEnd, end[2] + widthEnd);
  129. glEnd();
  130. }
  131. void setLighting(bool on)
  132. {
  133. if (on)
  134. {
  135. glEnable(GL_LIGHTING);
  136. glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
  137. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, WHITE);
  138. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, WHITE);
  139. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, DIM_WHITE);
  140. }
  141. else
  142. {
  143. glDisable(GL_LIGHTING);
  144. }
  145. }
  146. void lightRoom(Room &room)
  147. {
  148. for (unsigned int i = 0; i < room.sizeLights(); ++i)
  149. {
  150. Light &light = room.getLight(i);
  151. vec4_t pos, color;
  152. vec3_t dir;
  153. light.getPos(pos);
  154. light.getColor(color);
  155. light.getDir(dir);
  156. glEnable(GL_LIGHT0 + i);
  157. switch (light.getType())
  158. {
  159. case Light::typeSpot:
  160. glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, light.getCutoff());
  161. glLightfv(GL_LIGHT0 + i, GL_POSITION, pos);
  162. glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, dir);
  163. glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, color);
  164. break;
  165. case Light::typePoint:
  166. case Light::typeDirectional:
  167. glLightf(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, 1.0); // 1.0
  168. // GL_QUADRATIC_ATTENUATION
  169. // GL_LINEAR_ATTENUATION
  170. glLightf(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, light.getAtt());
  171. glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, color); // GL_DIFFUSE
  172. glLightfv(GL_LIGHT0 + i, GL_POSITION, pos);
  173. break;
  174. }
  175. }
  176. }
  177. void Render::clearFlags(unsigned int flags)
  178. {
  179. mFlags &= ~flags;
  180. if (flags & Render::fFog)
  181. {
  182. if (glIsEnabled(GL_FOG))
  183. {
  184. glDisable(GL_FOG);
  185. }
  186. }
  187. if (flags & Render::fGL_Lights)
  188. {
  189. setLighting(false);
  190. }
  191. }
  192. void Render::setFlags(unsigned int flags)
  193. {
  194. mFlags |= flags;
  195. if (flags & Render::fFog)
  196. {
  197. glEnable(GL_FOG);
  198. glFogf(GL_FOG_MODE, GL_EXP2);
  199. glFogf(GL_FOG_DENSITY, 0.00008f);
  200. glFogf(GL_FOG_START, 30000.0f);
  201. glFogf(GL_FOG_END, 50000.0f);
  202. glFogfv(GL_FOG_COLOR, BLACK);
  203. }
  204. if (flags & Render::fGL_Lights)
  205. {
  206. setLighting(true);
  207. }
  208. }
  209. int Render::getMode()
  210. {
  211. return mMode;
  212. }
  213. void Render::setMode(int n)
  214. {
  215. mMode = n;
  216. switch (mMode)
  217. {
  218. case Render::modeDisabled:
  219. break;
  220. case Render::modeSolid:
  221. case Render::modeWireframe:
  222. glClearColor(NEXT_PURPLE[0], NEXT_PURPLE[1],
  223. NEXT_PURPLE[2], NEXT_PURPLE[3]);
  224. glDisable(GL_TEXTURE_2D);
  225. break;
  226. default:
  227. if (mMode == Render::modeLoadScreen)
  228. {
  229. glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  230. }
  231. else
  232. {
  233. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  234. }
  235. glClearColor(BLACK[0], BLACK[1], BLACK[2], BLACK[3]);
  236. glEnable(GL_TEXTURE_2D);
  237. }
  238. }
  239. // Replaced the deprecated gluLookAt with slightly modified code from here:
  240. // http://www.khronos.org/message_boards/showthread.php/4991
  241. void gluLookAt(float eyeX, float eyeY, float eyeZ,
  242. float lookAtX, float lookAtY, float lookAtZ,
  243. float upX, float upY, float upZ) {
  244. float f[3];
  245. // calculating the viewing vector
  246. f[0] = lookAtX - eyeX;
  247. f[1] = lookAtY - eyeY;
  248. f[2] = lookAtZ - eyeZ;
  249. float fMag = sqrtf(f[0] * f[0] + f[1] * f[1] + f[2] * f[2]);
  250. //float upMag = sqrtf(upX * upX + upY * upY + upZ * upZ);
  251. // normalizing the viewing vector
  252. f[0] = f[0] / fMag;
  253. f[1] = f[1] / fMag;
  254. f[2] = f[2] / fMag;
  255. float s[3] = {
  256. f[1] * upZ - upY * f[2],
  257. upX * f[2] - f[0] * upZ,
  258. f[0] * upY - upX * f[1]
  259. };
  260. float u[3] = {
  261. s[1] * f[2] - f[1] * s[2],
  262. f[0] * s[2] - s[0] * f[2],
  263. s[0] * f[1] - f[0] * s[1]
  264. };
  265. float m[16] = {
  266. s[0], u[0], -f[0], 0,
  267. s[1], u[1], -f[1], 0,
  268. s[2], u[2], -f[2], 0,
  269. 0, 0, 0, 1
  270. };
  271. glMultMatrixf(m);
  272. glTranslatef(-eyeX, -eyeY, -eyeZ);
  273. }
  274. void Render::display()
  275. {
  276. switch (mMode)
  277. {
  278. case Render::modeDisabled:
  279. return;
  280. case Render::modeLoadScreen:
  281. //! \fixme entry for seperate main drawing method -- Mongoose 2002.01.01
  282. drawLoadScreen();
  283. return;
  284. default:
  285. break;
  286. }
  287. if (mMode == Render::modeWireframe)
  288. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  289. else
  290. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  291. float camOffsetH = 0.0f;
  292. switch (getGame().getLara().getMoveType())
  293. {
  294. case Entity::MoveTypeFly:
  295. case Entity::MoveTypeNoClipping:
  296. case Entity::MoveTypeSwim:
  297. //camOffsetH = 64.0f;
  298. camOffsetH = 512.0f;
  299. break;
  300. case Entity::MoveTypeWalk:
  301. case Entity::MoveTypeWalkNoSwim:
  302. camOffsetH = 512.0f;
  303. break;
  304. }
  305. vec3_t curPos;
  306. vec3_t camPos;
  307. vec3_t atPos;
  308. curPos[0] = getGame().getLara().getPos(0);
  309. curPos[1] = getGame().getLara().getPos(1);
  310. curPos[2] = getGame().getLara().getPos(2);
  311. vec_t yaw = getGame().getLara().getAngle(1);
  312. // Mongoose 2002.08.24, New 3rd person camera hack
  313. camPos[0] = curPos[0] - (1024.0f * sinf(yaw));
  314. camPos[1] = curPos[1] - camOffsetH; // UP is lower val
  315. camPos[2] = curPos[2] - (1024.0f * cosf(yaw));
  316. int index = getGame().getLara().getRoom();
  317. int sector = getWorld().getSector(index, camPos[0], camPos[2]);
  318. // Handle camera out of world
  319. if ((sector < 0) ||
  320. ((unsigned int)sector >= getWorld().getRoom(index).sizeSectors()) ||
  321. getWorld().isWall(index, sector)) {
  322. camPos[0] = curPos[0] + (64.0f * sinf(yaw));
  323. camPos[1] -= 64.0f;
  324. camPos[2] = curPos[2] + (64.0f * cosf(yaw));
  325. }
  326. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  327. glLoadIdentity();
  328. // Setup view in OpenGL with camera
  329. getCamera().setPosition(camPos);
  330. getCamera().update();
  331. getCamera().getTarget(atPos);
  332. // Mongoose 2002.08.13, Quick fix to render OpenRaider upside down
  333. gluLookAt(camPos[0], camPos[1], camPos[2], atPos[0], atPos[1], atPos[2], 0.0f, -1.0f, 0.0f);
  334. // Update view volume for vising
  335. updateViewVolume();
  336. // Render world
  337. glColor3fv(DIM_WHITE); // was WHITE
  338. drawSkyMesh(96.0);
  339. // Figure out how much of the map to render
  340. newRoomRenderList(index);
  341. // Room solid pass, need to do depth sorting to avoid 2 pass render
  342. for (unsigned int i = 0; i < mRoomRenderList.size(); i++) {
  343. Room &room = *mRoomRenderList[i];
  344. if (mFlags & Render::fGL_Lights)
  345. lightRoom(room);
  346. room.display(false);
  347. }
  348. // Draw all visible enities
  349. if (mFlags & Render::fEntityModels) {
  350. std::vector<Entity *> entityRenderList;
  351. for (unsigned int i = 0; i < getWorld().sizeEntity(); i++) {
  352. Entity &e = getWorld().getEntity(i);
  353. // Don't show Lara to the player
  354. if (&e == &getGame().getLara())
  355. continue;
  356. // Mongoose 2002.08.15, Nothing to draw, skip
  357. // Mongoose 2002.12.24, Some entities have no animation =p
  358. if (e.getModel().size() == 0)
  359. continue;
  360. // Is it in view volume? ( Hack to use sphere )
  361. if (!isVisible(e.getPos(0), e.getPos(1), e.getPos(2), 512.0f))
  362. continue;
  363. //! \fixme Is it in a room we're rendering?
  364. //if (mRoomRenderList[e->room] == 0x0)
  365. //{
  366. // continue;
  367. //}
  368. entityRenderList.push_back(&e);
  369. }
  370. // Draw objects not tied to rooms
  371. glPushMatrix();
  372. drawObjects();
  373. glPopMatrix();
  374. // Depth sort entityRenderList with qsort
  375. std::sort(entityRenderList.begin(), entityRenderList.end());
  376. for (unsigned int i = 0; i < entityRenderList.size(); i++) {
  377. entityRenderList[i]->display();
  378. }
  379. }
  380. // Room alpha pass
  381. // Skip room alpha pass for modes w/o texture
  382. if (!(mMode == Render::modeSolid || mMode == Render::modeWireframe)) {
  383. for (unsigned int i = 0; i < mRoomRenderList.size(); i++)
  384. mRoomRenderList[i]->display(true);
  385. }
  386. if (mMode == Render::modeWireframe)
  387. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  388. glFlush();
  389. }
  390. void Render::drawLoadScreen()
  391. {
  392. float x = 0.0f, y = 0.0f, z = -160.0f;
  393. float w, h;
  394. if (getWindow().getWidth() < getWindow().getHeight())
  395. w = h = (float)getWindow().getWidth();
  396. else
  397. w = h = (float)getWindow().getHeight();
  398. if (mTexture.getTextureCount() <= 0)
  399. return;
  400. // Mongoose 2002.01.01, Rendered while game is loading...
  401. //! \fixme seperate logo/particle coor later
  402. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  403. glLoadIdentity();
  404. glColor3fv(WHITE);
  405. if (mFlags & Render::fGL_Lights)
  406. glDisable(GL_LIGHTING);
  407. // Mongoose 2002.01.01, Draw logo/load screen
  408. glTranslatef(0.0f, 0.0f, -2000.0f);
  409. glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
  410. mTexture.bindTextureId(1); //! \fixme store texture id somewhere
  411. glBegin(GL_TRIANGLE_STRIP);
  412. glTexCoord2f(1.0, 1.0);
  413. glVertex3f(x + w, y + h, z);
  414. glTexCoord2f(0.0, 1.0);
  415. glVertex3f(x - w, y + h, z);
  416. glTexCoord2f(1.0, 0.0);
  417. glVertex3f(x + w, y - h, z);
  418. glTexCoord2f(0.0, 0.0);
  419. glVertex3f(x - w, y - h, z);
  420. glEnd();
  421. if (mFlags & Render::fGL_Lights)
  422. glEnable(GL_LIGHTING);
  423. glFlush();
  424. }
  425. void Render::newRoomRenderList(int index)
  426. {
  427. static int currentRoomId = -1;
  428. if (mFlags & Render::fUsePortals)
  429. {
  430. if (index == -1) // -1 is error, so draw room 0, for the hell of it
  431. {
  432. mRoomRenderList.clear();
  433. mRoomRenderList.push_back(&getWorld().getRoom(0));
  434. }
  435. else
  436. {
  437. // Update room render list if needed
  438. if (mFlags & Render::fUpdateRoomListPerFrame ||
  439. currentRoomId != index)
  440. {
  441. buildRoomRenderList(getWorld().getRoom(index));
  442. }
  443. }
  444. }
  445. else // Render all rooms pretty much
  446. {
  447. if (currentRoomId != index || index == -1)
  448. {
  449. printf("*** Room render list -> %i\n", index);
  450. mRoomRenderList.clear();
  451. for (unsigned int i = 0; i < getWorld().sizeRoom(); i++)
  452. {
  453. if (!isVisible(getWorld().getRoom(i).getBoundingBox()))
  454. continue;
  455. mRoomRenderList.push_back(&getWorld().getRoom(i));
  456. }
  457. }
  458. }
  459. currentRoomId = index;
  460. }
  461. void Render::buildRoomRenderList(Room &room)
  462. {
  463. // Must be visible
  464. //! \fixme Add depth sorting here - remove multipass
  465. if (!isVisible(room.getBoundingBox()))
  466. return;
  467. // Must not already be cached
  468. for (unsigned int i = 0; i < mRoomRenderList.size(); i++)
  469. {
  470. Room &room2 = *mRoomRenderList[i];
  471. if (&room2 == &room)
  472. return;
  473. }
  474. /* Add current room to list */
  475. mRoomRenderList.push_back(&room);
  476. if (mFlags & Render::fOneRoom)
  477. {
  478. return;
  479. }
  480. else if (mFlags & Render::fAllRooms) /* Are you serious? */
  481. {
  482. for (unsigned int i = 0; i < getWorld().sizeRoom(); i++)
  483. {
  484. Room &room2 = getWorld().getRoom(i);
  485. if (&room2 != &room)
  486. {
  487. buildRoomRenderList(room2);
  488. }
  489. }
  490. return;
  491. }
  492. // Try to add adj rooms and their adj rooms, skip this room
  493. for (unsigned int i = 1; i < room.sizeAdjacentRooms(); i++)
  494. {
  495. if (room.getAdjacentRoom(i) < 0)
  496. continue;
  497. Room &room2 = getWorld().getRoom(room.getAdjacentRoom(i));
  498. // Mongoose 2002.03.22, Add portal visibility check here
  499. if (&room2 != &room)
  500. {
  501. buildRoomRenderList(room2);
  502. }
  503. }
  504. }
  505. void Render::drawSkyMesh(float scale)
  506. {
  507. //skeletal_model_t *model = getWorld().getModel(mSkyMesh);
  508. //if (!model)
  509. // return;
  510. glDisable(GL_DEPTH_TEST);
  511. glPushMatrix();
  512. if (mSkyMeshRotation)
  513. {
  514. glRotated(90.0, 1, 0, 0);
  515. }
  516. glTranslated(0.0, 1000.0, 0.0);
  517. glScaled(scale, scale, scale);
  518. //drawModel(model);
  519. //drawModelMesh(getWorld().getMesh(mSkyMesh), );
  520. glPopMatrix();
  521. glEnable(GL_DEPTH_TEST);
  522. }
  523. void Render::drawObjects() {
  524. // Draw lara or other player model ( move to entity rendering method )
  525. if (mFlags & Render::fViewModel)
  526. getGame().getLara().display();
  527. // Draw sprites after player to handle alpha
  528. for (unsigned int i = 0; i < getWorld().sizeSprite(); i++) {
  529. SpriteSequence &sprite = getWorld().getSprite(i);
  530. for (unsigned int j = 0; j < sprite.size(); j++)
  531. sprite.get(j).display();
  532. }
  533. }
  534. void Render::tmpRenderModelMesh(model_mesh_t *r_mesh, texture_tri_t *ttri)
  535. {
  536. glBegin(GL_TRIANGLES);
  537. switch (mMode)
  538. {
  539. case modeSolid:
  540. case modeVertexLight:
  541. if (r_mesh->colors)
  542. {
  543. glColor3fv(r_mesh->colors+ttri->index[0]);
  544. glTexCoord2fv(ttri->st);
  545. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  546. glColor3fv(r_mesh->colors+ttri->index[1]);
  547. glTexCoord2fv(ttri->st+2);
  548. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  549. glColor3fv(r_mesh->colors+ttri->index[2]);
  550. glTexCoord2fv(ttri->st+4);
  551. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  552. }
  553. else if (r_mesh->normals)
  554. {
  555. glNormal3fv(r_mesh->normals+ttri->index[0]*3);
  556. glTexCoord2fv(ttri->st);
  557. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  558. glNormal3fv(r_mesh->normals+ttri->index[1]*3);
  559. glTexCoord2fv(ttri->st+2);
  560. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  561. glNormal3fv(r_mesh->normals+ttri->index[2]*3);
  562. glTexCoord2fv(ttri->st+4);
  563. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  564. }
  565. else
  566. {
  567. glTexCoord2fv(ttri->st);
  568. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  569. glTexCoord2fv(ttri->st+2);
  570. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  571. glTexCoord2fv(ttri->st+4);
  572. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  573. }
  574. break;
  575. case modeWireframe:
  576. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  577. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  578. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  579. break;
  580. default:
  581. glTexCoord2fv(ttri->st);
  582. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  583. glTexCoord2fv(ttri->st+2);
  584. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  585. glTexCoord2fv(ttri->st+4);
  586. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  587. }
  588. glEnd();
  589. }
  590. void Render::drawModelMesh(model_mesh_t *r_mesh)
  591. {
  592. texture_tri_t *ttri;
  593. int lastTexture = -1;
  594. // If they pass NULL structs let it hang up - this is tmp
  595. //! \fixme Duh, vis tests need to be put back
  596. //if (!isVisible(r_mesh->center, r_mesh->radius, r_mesh->bbox))
  597. //{
  598. // return;
  599. //}
  600. //! \fixme 'AMBIENT' -- Mongoose 2002.01.08
  601. glColor3fv(WHITE);
  602. if (mMode == modeWireframe)
  603. glColor3fv(WHITE);
  604. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  605. glBindTexture(GL_TEXTURE_2D, 1); // White texture for colors
  606. // Colored Triagles
  607. for (unsigned int i = 0; i < r_mesh->coloredTriangles.size(); i++)
  608. {
  609. ttri = r_mesh->coloredTriangles[i];
  610. if (!ttri)
  611. continue;
  612. if (mMode != modeWireframe && mMode != modeSolid &&
  613. ttri->texture != lastTexture)
  614. {
  615. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  616. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  617. lastTexture = ttri->texture;
  618. }
  619. tmpRenderModelMesh(r_mesh, ttri);
  620. }
  621. // Colored Rectagles
  622. for (unsigned int i = 0; i < r_mesh->coloredRectangles.size(); i++)
  623. {
  624. ttri = r_mesh->coloredRectangles[i];
  625. if (!ttri)
  626. continue;
  627. if (mMode != modeWireframe && mMode != modeSolid &&
  628. ttri->texture != lastTexture)
  629. {
  630. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  631. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  632. lastTexture = ttri->texture;
  633. }
  634. tmpRenderModelMesh(r_mesh, ttri);
  635. }
  636. // Textured Tris
  637. for (unsigned int i = 0; i < r_mesh->texturedTriangles.size(); i++)
  638. {
  639. ttri = r_mesh->texturedTriangles[i];
  640. if (!ttri)
  641. continue;
  642. if (mMode != modeWireframe && mMode != modeSolid &&
  643. ttri->texture != lastTexture)
  644. {
  645. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  646. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  647. lastTexture = ttri->texture;
  648. }
  649. tmpRenderModelMesh(r_mesh, ttri);
  650. }
  651. // Textured Quads
  652. for (unsigned int i = 0; i < r_mesh->texturedRectangles.size(); i++)
  653. {
  654. ttri = r_mesh->texturedRectangles[i];
  655. if (!ttri)
  656. continue;
  657. if (mMode != modeWireframe && mMode != modeSolid &&
  658. ttri->texture != lastTexture)
  659. {
  660. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  661. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  662. lastTexture = ttri->texture;
  663. }
  664. tmpRenderModelMesh(r_mesh, ttri);
  665. }
  666. }
  667. void Render::setSkyMesh(int index, bool rot)
  668. {
  669. mSkyMesh = index;
  670. mSkyMeshRotation = rot;
  671. }
  672. void Render::updateViewVolume()
  673. {
  674. matrix_t proj;
  675. matrix_t mdl;
  676. glGetFloatv(GL_PROJECTION_MATRIX, proj);
  677. glGetFloatv(GL_MODELVIEW_MATRIX, mdl);
  678. mViewVolume.updateFrame(proj, mdl);
  679. }
  680. bool Render::isVisible(BoundingBox &box) {
  681. vec3_t bbox[2];
  682. box.getBoundingBox(bbox);
  683. // For debugging purposes
  684. if (mMode == Render::modeWireframe)
  685. box.display(true, PINK, RED);
  686. return mViewVolume.isBboxInFrustum(bbox[0], bbox[1]);
  687. }
  688. bool Render::isVisible(float x, float y, float z)
  689. {
  690. // For debugging purposes
  691. if (mMode == Render::modeWireframe)
  692. {
  693. glPointSize(5.0);
  694. glColor3fv(PINK);
  695. glBegin(GL_POINTS);
  696. glVertex3f(x, y, z);
  697. glEnd();
  698. }
  699. return (mViewVolume.isPointInFrustum(x, y, z));
  700. }
  701. bool Render::isVisible(float x, float y, float z, float radius)
  702. {
  703. // For debugging purposes
  704. if (mMode == Render::modeWireframe)
  705. {
  706. glPointSize(5.0);
  707. glColor3fv(PINK);
  708. glBegin(GL_POINTS);
  709. glVertex3f(x, y, z);
  710. glEnd();
  711. }
  712. return (mViewVolume.isSphereInFrustum(x, y, z, radius));
  713. }