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 50KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950
  1. /*!
  2. * \file src/Render.cpp
  3. * \brief OpenRaider Renderer class
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include <algorithm>
  9. #ifdef __APPLE__
  10. #include <OpenGL/gl.h>
  11. #include <OpenGL/glu.h>
  12. #else
  13. #include <GL/gl.h>
  14. #include <GL/glu.h>
  15. #endif
  16. #include <stdlib.h>
  17. #include <math.h>
  18. #include <string.h>
  19. #ifdef USING_EMITTER
  20. #include "Emitter.h"
  21. #endif
  22. #include "global.h"
  23. #include "main.h"
  24. #include "Game.h"
  25. #include "OpenRaider.h"
  26. #include "Render.h"
  27. bool compareEntites(const void *voidA, const void *voidB)
  28. {
  29. entity_t *a = (entity_t *)voidA, *b = (entity_t *)voidB;
  30. vec_t distA, distB;
  31. if (!a || !b)
  32. return false; // error really
  33. distA = gOpenRaider->mGame->mRender->mViewVolume.getDistToSphereFromNear(a->pos[0],
  34. a->pos[1],
  35. a->pos[2],
  36. 1.0f);
  37. distB = gOpenRaider->mGame->mRender->mViewVolume.getDistToSphereFromNear(b->pos[0],
  38. b->pos[1],
  39. b->pos[2],
  40. 1.0f);
  41. return (distA < distB);
  42. }
  43. bool compareStaticModels(const void *voidA, const void *voidB)
  44. {
  45. static_model_t *a = (static_model_t *)voidA, *b = (static_model_t *)voidB;
  46. vec_t distA, distB;
  47. if (!a || !b)
  48. return false; // error really
  49. distA = gOpenRaider->mGame->mRender->mViewVolume.getDistToSphereFromNear(a->pos[0],
  50. a->pos[1],
  51. a->pos[2],
  52. 128.0f);
  53. distB = gOpenRaider->mGame->mRender->mViewVolume.getDistToSphereFromNear(b->pos[0],
  54. b->pos[1],
  55. b->pos[2],
  56. 128.0f);
  57. return (distA < distB);
  58. }
  59. bool compareRoomDist(const void *voidA, const void *voidB)
  60. {
  61. const RenderRoom *a = static_cast<const RenderRoom *>(voidA);
  62. const RenderRoom *b = static_cast<const RenderRoom *>(voidB);
  63. if (!a || !b || !a->room || !b->room)
  64. return false; // error really
  65. return (a->dist < b->dist);
  66. }
  67. ////////////////////////////////////////////////////////////
  68. // Constructors
  69. ////////////////////////////////////////////////////////////
  70. Render::Render()
  71. {
  72. #ifdef USING_EMITTER
  73. mEmitter = 0x0;
  74. #endif
  75. mSkyMesh = -1;
  76. mSkyMeshRotation = false;
  77. mMode = Render::modeDisabled;
  78. mLock = 0;
  79. mFlags = (Render::fRoomAlpha | Render::fViewModel | Render::fSprites |
  80. Render::fRoomModels | Render::fEntityModels |
  81. Render::fUsePortals | fUpdateRoomListPerFrame);
  82. mNextTextureId = NULL;
  83. mNumTexturesLoaded = NULL;
  84. }
  85. Render::~Render()
  86. {
  87. ClearWorld();
  88. }
  89. ////////////////////////////////////////////////////////////
  90. // Public Accessors
  91. ////////////////////////////////////////////////////////////
  92. void Render::screenShot(char *filenameBase)
  93. {
  94. mTexture.glScreenShot(filenameBase, gOpenRaider->mWindow->mWidth, gOpenRaider->mWindow->mHeight);
  95. }
  96. ////////////////////////////////////////////////////////////
  97. // Public Mutators
  98. ////////////////////////////////////////////////////////////
  99. void Render::addRoom(RenderRoom *room)
  100. {
  101. mRooms.push_back(room);
  102. }
  103. void Render::loadTexture(unsigned char *image,
  104. unsigned int width, unsigned int height,
  105. unsigned int id)
  106. {
  107. glColor3fv(WHITE);
  108. mTexture.loadBufferSlot(image, width, height, Texture::RGBA, 32, id);
  109. }
  110. void Render::initTextures(char *textureDir, unsigned int *numLoaded,
  111. unsigned int *nextId)
  112. {
  113. char filename[128];
  114. int snow1_id;
  115. int snow2_id;
  116. int bg_id;
  117. unsigned int numTextures = 0;
  118. unsigned char color[4];
  119. // We want to update as needed later
  120. mNumTexturesLoaded = numLoaded;
  121. mNextTextureId = nextId;
  122. mTexture.reset();
  123. mTexture.setMaxTextureCount(128); /* TR never needs more than 32 iirc
  124. However, color texturegen is a lot */
  125. mTexture.setFlag(Texture::fUseMipmaps);
  126. printf("Processing Textures:\n");
  127. color[0] = 0xff;
  128. color[1] = 0xff;
  129. color[2] = 0xff;
  130. color[3] = 0xff;
  131. if (mTexture.loadColorTexture(color, 32, 32) > -1)
  132. {
  133. ++numTextures;
  134. }
  135. snprintf(filename, 126, "%s/%s", textureDir, "splash.tga");
  136. filename[127] = 0;
  137. if ((bg_id = mTexture.loadTGA(filename)) > -1)
  138. {
  139. ++numTextures;
  140. }
  141. snprintf(filename, 126, "%s/%s", textureDir, "snow.tga");
  142. filename[127] = 0;
  143. if ((snow1_id = mTexture.loadTGA(filename)) > -1)
  144. {
  145. ++numTextures;
  146. }
  147. snprintf(filename, 126, "%s/%s", textureDir, "snow2.tga");
  148. filename[127] = 0;
  149. if ((snow2_id = mTexture.loadTGA(filename)) > -1)
  150. {
  151. ++numTextures;
  152. }
  153. // Weird that it isn't linear, must be some storage deal in Texture
  154. // I forgot about Id allocation
  155. *nextId = snow2_id;
  156. // Setup particle system test
  157. initEmitter("Snow test", 650, snow1_id, snow2_id);
  158. *numLoaded = numTextures;
  159. }
  160. void Render::initEmitter(const char *name, unsigned int size,
  161. unsigned int snowTex1, unsigned int snowTex2)
  162. {
  163. #ifdef USING_EMITTER
  164. if (mEmitter)
  165. delete mEmitter; // Public, so avoid possible leak
  166. // Mongoose 2002.01.01, Screwing around with particle emitter test
  167. // note this is backwards b/c load screen is rendered upsidedown
  168. //mEmitter = new Emitter(/*name*/"snow", size);
  169. mEmitter = new Emitter(name, size);
  170. mEmitter->SetTextureId(snowTex1);
  171. mEmitter->TextureId(120, 280, snowTex2);
  172. mEmitter->TextureId(400, 450, snowTex2);
  173. mEmitter->TextureId(500, 550, snowTex2);
  174. // Mongoose 2002.01.01, Varing force and speed should look
  175. // like varing mass/SA in wind, maybe
  176. mEmitter->Speed(0, 150, 3500, 3000, 3500);
  177. mEmitter->Speed(150, 350, 3000, 4000, 3000);
  178. mEmitter->Speed(400, 500, 2000, 5000, 2000);
  179. mEmitter->Speed(400, 500, 2000, 5000, 2000);
  180. mEmitter->Force(100, 200, 0.0, 7.0, 0.0);
  181. mEmitter->Force(200, 300, 0.0, 5.0, 0.0);
  182. mEmitter->Force(300, 500, 0.0, 10.0, 0.0);
  183. mEmitter->Force(500, 650, 0.0, 9.0, 0.0);
  184. #endif
  185. }
  186. void Render::ClearWorld()
  187. {
  188. gOpenRaider->mGame->mLara = NULL;
  189. mRoomRenderList.clear();
  190. for (unsigned int i = 0; i < mRooms.size(); i++) {
  191. if (mRooms[i])
  192. delete mRooms[i];
  193. }
  194. mRooms.clear();
  195. for (unsigned int i = 0; i < mModels.size(); i++) {
  196. if (mModels[i])
  197. delete mModels[i];
  198. }
  199. mModels.clear();
  200. #ifdef USING_EMITTER
  201. if (mEmitter)
  202. {
  203. delete mEmitter;
  204. mEmitter = 0x0;
  205. }
  206. #endif
  207. }
  208. // Texture must be set to WHITE solid color texture
  209. void renderTrace(int color, vec3_t start, vec3_t end)
  210. {
  211. const float widthStart = 10.0f; //5.0f;
  212. const float widthEnd = 10.0f;
  213. float delta = randomNum(0.01f, 0.16f); // for flicker fx
  214. // Draw two long quads that skrink and fade the they go further out
  215. glBegin(GL_QUADS);
  216. switch (color)
  217. {
  218. case 0:
  219. glColor3f(0.9f - delta, 0.2f, 0.2f);
  220. break;
  221. case 1:
  222. glColor3f(0.2f, 0.9f - delta, 0.2f);
  223. break;
  224. case 2:
  225. default:
  226. glColor3f(0.2f, 0.2f, 0.9f - delta);
  227. }
  228. glVertex3f(start[0], start[1], start[2]);
  229. glVertex3f(start[0], start[1] + widthStart, start[2] + widthStart);
  230. glVertex3f(end[0], end[1] + widthEnd, end[2] + widthEnd);
  231. glVertex3f(end[0], end[1], end[2]);
  232. glVertex3f(start[0], start[1], start[2]);
  233. glVertex3f(start[0], start[1] + widthStart, start[2] - widthStart);
  234. glVertex3f(end[0], end[1] + widthEnd, end[2] - widthEnd);
  235. glVertex3f(end[0], end[1], end[2]);
  236. glVertex3f(start[0], start[1] + widthStart, start[2] + widthStart);
  237. glVertex3f(start[0], start[1] + widthStart, start[2] - widthStart);
  238. glVertex3f(end[0], end[1] + widthEnd, end[2] - widthEnd);
  239. glVertex3f(end[0], end[1] + widthEnd, end[2] + widthEnd);
  240. glEnd();
  241. }
  242. void setLighting(bool on)
  243. {
  244. if (on)
  245. {
  246. glEnable(GL_LIGHTING);
  247. glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
  248. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, WHITE);
  249. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, WHITE);
  250. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, DIM_WHITE);
  251. }
  252. else
  253. {
  254. glDisable(GL_LIGHTING);
  255. }
  256. }
  257. void lightRoom(RenderRoom *room)
  258. {
  259. unsigned int i;
  260. Light *light;
  261. for (i = 0; i < room->lights.size(); ++i)
  262. {
  263. light = room->lights[i];
  264. if (!light)
  265. continue;
  266. glEnable(GL_LIGHT0 + i);
  267. switch (light->mType)
  268. {
  269. case Light::typeSpot:
  270. glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, light->mCutoff);
  271. glLightfv(GL_LIGHT0 + i, GL_POSITION, light->mPos);
  272. glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, light->mDir);
  273. glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, light->mColor);
  274. break;
  275. case Light::typePoint:
  276. case Light::typeDirectional:
  277. glLightf(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, 1.0); // 1.0
  278. // GL_QUADRATIC_ATTENUATION
  279. // GL_LINEAR_ATTENUATION
  280. glLightf(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, light->mAtt);
  281. glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, light->mColor); // GL_DIFFUSE
  282. glLightfv(GL_LIGHT0 + i, GL_POSITION, light->mPos);
  283. break;
  284. }
  285. }
  286. }
  287. void Render::clearFlags(unsigned int flags)
  288. {
  289. // _defaults |= flags; // Force removal if it wasn't set
  290. mFlags ^= flags;
  291. if (flags & Render::fFog)
  292. {
  293. if (glIsEnabled(GL_FOG))
  294. {
  295. glDisable(GL_FOG);
  296. }
  297. }
  298. if (flags & Render::fGL_Lights)
  299. {
  300. setLighting(false);
  301. }
  302. }
  303. void Render::setFlags(unsigned int flags)
  304. {
  305. mFlags |= flags;
  306. if (flags & Render::fFog)
  307. {
  308. glEnable(GL_FOG);
  309. glFogf(GL_FOG_MODE, GL_EXP2);
  310. glFogf(GL_FOG_DENSITY, 0.00008f);
  311. glFogf(GL_FOG_START, 30000.0f);
  312. glFogf(GL_FOG_END, 50000.0f);
  313. glFogfv(GL_FOG_COLOR, BLACK);
  314. }
  315. if (flags & Render::fGL_Lights)
  316. {
  317. setLighting(true);
  318. }
  319. }
  320. int Render::getMode()
  321. {
  322. return mMode;
  323. }
  324. void Render::setMode(int n)
  325. {
  326. mMode = n;
  327. switch (mMode)
  328. {
  329. case Render::modeDisabled:
  330. break;
  331. case Render::modeSolid:
  332. case Render::modeWireframe:
  333. glClearColor(NEXT_PURPLE[0], NEXT_PURPLE[1],
  334. NEXT_PURPLE[2], NEXT_PURPLE[3]);
  335. glDisable(GL_TEXTURE_2D);
  336. break;
  337. default:
  338. if (mMode == Render::modeLoadScreen)
  339. {
  340. glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  341. }
  342. else
  343. {
  344. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  345. }
  346. glClearColor(BLACK[0], BLACK[1], BLACK[2], BLACK[3]);
  347. glEnable(GL_TEXTURE_2D);
  348. }
  349. }
  350. // Replaced the deprecated gluLookAt with slightly modified code from here:
  351. // http://www.khronos.org/message_boards/showthread.php/4991
  352. void CrossProd(float x1, float y1, float z1, float x2, float y2, float z2, float res[3])
  353. {
  354. res[0] = y1*z2 - y2*z1;
  355. res[1] = x2*z1 - x1*z2;
  356. res[2] = x1*y2 - x2*y1;
  357. }
  358. void deprecated_gluLookAt(float eyeX, float eyeY, float eyeZ, float lookAtX, float lookAtY, float lookAtZ, float upX, float upY, float upZ)
  359. {
  360. float f[3];
  361. // calculating the viewing vector
  362. f[0] = lookAtX - eyeX;
  363. f[1] = lookAtY - eyeY;
  364. f[2] = lookAtZ - eyeZ;
  365. float fMag, upMag;
  366. fMag = sqrtf(f[0]*f[0] + f[1]*f[1] + f[2]*f[2]);
  367. upMag = sqrtf(upX*upX + upY*upY + upZ*upZ);
  368. // normalizing the viewing vector
  369. f[0] = f[0]/fMag;
  370. f[1] = f[1]/fMag;
  371. f[2] = f[2]/fMag;
  372. // normalising the up vector. no need for this here if you have your
  373. // up vector already normalised, which is mostly the case.
  374. upX = upX/upMag;
  375. upY = upY/upMag;
  376. upZ = upZ/upMag;
  377. float s[3], u[3];
  378. CrossProd(f[0], f[1], f[2], upX, upY, upZ, s);
  379. CrossProd(s[0], s[1], s[2], f[0], f[1], f[2], u);
  380. float M[]=
  381. {
  382. s[0], u[0], -f[0], 0,
  383. s[1], u[1], -f[1], 0,
  384. s[2], u[2], -f[2], 0,
  385. 0, 0, 0, 1
  386. };
  387. glMultMatrixf(M);
  388. glTranslatef (-eyeX, -eyeY, -eyeZ);
  389. }
  390. void Render::Display()
  391. {
  392. vec3_t curPos;
  393. vec3_t camPos;
  394. vec3_t atPos;
  395. RenderRoom *room;
  396. int index;
  397. #ifdef DEBUG_MATRIX
  398. gl_test_reset();
  399. #endif
  400. switch (mMode)
  401. {
  402. case Render::modeDisabled:
  403. return;
  404. case Render::modeLoadScreen:
  405. //! \fixme entry for seperate main drawing method -- Mongoose 2002.01.01
  406. drawLoadScreen();
  407. return;
  408. default:
  409. ;
  410. }
  411. if (mMode == Render::modeWireframe)
  412. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  413. else
  414. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  415. index = -1;
  416. if (gOpenRaider->mGame->mLara)
  417. {
  418. float yaw;
  419. int sector;
  420. float camOffsetH = 0.0f;
  421. switch (gOpenRaider->mGame->mLara->moveType)
  422. {
  423. case worldMoveType_fly:
  424. case worldMoveType_noClipping:
  425. case worldMoveType_swim:
  426. camOffsetH = 64.0f;
  427. break;
  428. case worldMoveType_walk:
  429. case worldMoveType_walkNoSwim:
  430. camOffsetH = 512.0f;
  431. break;
  432. }
  433. curPos[0] = gOpenRaider->mGame->mLara->pos[0];
  434. curPos[1] = gOpenRaider->mGame->mLara->pos[1];
  435. curPos[2] = gOpenRaider->mGame->mLara->pos[2];
  436. yaw = gOpenRaider->mGame->mLara->angles[1];
  437. index = gOpenRaider->mGame->mLara->room;
  438. // Mongoose 2002.08.24, New 3rd person camera hack
  439. camPos[0] = curPos[0];
  440. camPos[1] = curPos[1] - camOffsetH; // UP is lower val
  441. camPos[2] = curPos[2];
  442. camPos[0] -= (1024.0f * sinf(yaw));
  443. camPos[2] -= (1024.0f * cosf(yaw));
  444. sector = gOpenRaider->mGame->mWorld.getSector(index, camPos[0], camPos[2]);
  445. // Handle camera out of world
  446. if (sector < 0 || gOpenRaider->mGame->mWorld.isWall(index, sector))
  447. {
  448. camPos[0] = curPos[0] + (64.0f * sinf(yaw));
  449. camPos[1] -= 64.0f;
  450. camPos[2] = curPos[2] + (64.0f * cosf(yaw));
  451. }
  452. gOpenRaider->mGame->mCamera->setPosition(camPos);
  453. }
  454. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  455. glLoadIdentity();
  456. // Setup view in OpenGL with camera
  457. gOpenRaider->mGame->mCamera->update();
  458. gOpenRaider->mGame->mCamera->getPosition(camPos);
  459. gOpenRaider->mGame->mCamera->getTarget(atPos);
  460. // Mongoose 2002.08.13, Quick fix to render OpenRaider upside down
  461. // gluLookAt(camPos[0], camPos[1], camPos[2], atPos[0], atPos[1], atPos[2], 0.0, -1.0, 0.0);
  462. deprecated_gluLookAt(camPos[0], camPos[1], camPos[2], atPos[0], atPos[1], atPos[2], 0.0f, -1.0f, 0.0f);
  463. // Update view volume for vising
  464. updateViewVolume();
  465. // Let's see the LoS -- should be event controled
  466. if (gOpenRaider->mGame->mLara)
  467. {
  468. // SkeletalModel *mdl = (SkeletalModel *)gOpenRaider->mGame->mLara->tmpHook;
  469. // Draw in solid colors
  470. glDisable(GL_TEXTURE_2D);
  471. glDisable(GL_CULL_FACE);
  472. if (gOpenRaider->mGame->mLara->state == 64) // eWeaponFire
  473. {
  474. vec3_t u, v; //, s, t;
  475. // Center of gOpenRaider->mGame->mLara
  476. u[0] = curPos[0];
  477. u[1] = curPos[1] - 512.0f;
  478. u[2] = curPos[2];
  479. // Location gOpenRaider->mGame->mLara is aiming at? ( Not finished yet )
  480. v[0] = u[0] + (9000.0f * sinf(gOpenRaider->mGame->mLara->angles[1]));
  481. v[1] = u[1] + (9000.0f * sinf(gOpenRaider->mGame->mLara->angles[2]));
  482. v[2] = u[2] + (9000.0f * cosf(gOpenRaider->mGame->mLara->angles[1]));
  483. // Test tracing of aim
  484. renderTrace(0, u, v); // v = target
  485. }
  486. entity_t *route = gOpenRaider->mGame->mLara->master;
  487. while (route)
  488. {
  489. if (route->master)
  490. {
  491. renderTrace(1, route->pos, route->master->pos);
  492. }
  493. route = route->master;
  494. }
  495. glEnable(GL_CULL_FACE);
  496. glEnable(GL_TEXTURE_2D);
  497. }
  498. // Render world
  499. glColor3fv(DIM_WHITE); // was WHITE
  500. drawSkyMesh(96.0);
  501. // Figure out how much of the map to render
  502. newRoomRenderList(index);
  503. // Room solid pass, need to do depth sorting to avoid 2 pass render
  504. for (unsigned int i = 0; i < mRoomRenderList.size(); i++)
  505. {
  506. room = mRoomRenderList[i];
  507. if (room)
  508. {
  509. if (mFlags & Render::fGL_Lights)
  510. {
  511. lightRoom(room);
  512. }
  513. drawRoom(room, false);
  514. }
  515. }
  516. // Draw all visible enities
  517. if (mFlags & Render::fEntityModels)
  518. {
  519. entity_t *e;
  520. std::vector<entity_t *> entityRenderList;
  521. std::vector<entity_t *> *entities = gOpenRaider->mGame->mWorld.getEntities();
  522. for (unsigned int i = 0; i < entities->size(); i++)
  523. {
  524. e = entities->at(i);
  525. // Mongoose 2002.03.26, Don't show lara to it's own player
  526. if (!e || e == gOpenRaider->mGame->mLara)
  527. {
  528. continue;
  529. }
  530. // Mongoose 2002.08.15, Nothing to draw, skip
  531. // Mongoose 2002.12.24, Some entities have no animation =p
  532. if (e->tmpHook)
  533. {
  534. SkeletalModel *mdl = static_cast<SkeletalModel *>(e->tmpHook);
  535. if (mdl->model->animation.empty())
  536. continue;
  537. }
  538. // Is it in view volume? ( Hack to use sphere )
  539. if (!isVisible(e->pos[0], e->pos[1], e->pos[2], 512.0f))
  540. continue;
  541. // Is it in a room we're rendering?
  542. //if (mRoomRenderList[e->room] == 0x0)
  543. //{
  544. // continue;
  545. //}
  546. entityRenderList.push_back(e);
  547. }
  548. // Draw objects not tied to rooms
  549. glPushMatrix();
  550. drawObjects();
  551. glPopMatrix();
  552. // Depth sort entityRenderList with qsort
  553. std::sort(entityRenderList.begin(), entityRenderList.end(), compareEntites);
  554. for (unsigned int i = 0; i < entityRenderList.size(); i++)
  555. {
  556. e = entityRenderList[i];
  557. glPushMatrix();
  558. glTranslatef(e->pos[0], e->pos[1], e->pos[2]);
  559. glRotatef(e->angles[1], 0, 1, 0);
  560. drawModel(static_cast<SkeletalModel *>(e->tmpHook));
  561. glPopMatrix();
  562. }
  563. }
  564. // Room alpha pass
  565. // Skip room alpha pass for modes w/o texture
  566. if (!(mMode == Render::modeSolid || mMode == Render::modeWireframe))
  567. {
  568. for (unsigned int i = 0; i < mRoomRenderList.size(); i++)
  569. {
  570. room = mRoomRenderList[i];
  571. if (room)
  572. {
  573. drawRoom(room, true);
  574. }
  575. }
  576. }
  577. #ifdef USING_EMITTER_IN_GAME
  578. // Mongoose 2002.01.01, Test particle prototype in game
  579. if (EMIT && mFlags & RENDER_F_PARTICLES)
  580. {
  581. glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  582. glPushMatrix();
  583. glLoadIdentity();
  584. glEnable(GL_BLEND);
  585. glRotatef(180.0, 1.0, 0.0, 0.0);
  586. glTranslatef(0.0, -820.0, 575.0);
  587. glScalef(80.0, 80.0, 80.0);
  588. EMIT->Draw();
  589. glPopMatrix();
  590. // Mongoose 2002.03.26, Account for particle system
  591. // not using new binds by setting WHITE texture here
  592. mTexture.bindTextureId(0);
  593. }
  594. #endif
  595. if (mMode == Render::modeWireframe)
  596. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  597. #ifdef USING_EMITTER
  598. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  599. #endif
  600. // Mongoose 2002.01.01, Test matrix ops
  601. #ifdef DEBUG_MATRIX
  602. if (gl_test_val())
  603. {
  604. printf("ERROR in matrix stack %i\n", gl_test_val());
  605. }
  606. #endif
  607. glFlush();
  608. }
  609. void Render::drawLoadScreen()
  610. {
  611. float x = 0.0f, y = 0.0f, z = -160.0f;
  612. float w, h;
  613. if (gOpenRaider->mWindow->mWidth < gOpenRaider->mWindow->mHeight)
  614. w = h = (float)gOpenRaider->mWindow->mWidth;
  615. else
  616. w = h = (float)gOpenRaider->mWindow->mHeight;
  617. if (mTexture.getTextureCount() <= 0)
  618. return;
  619. // Mongoose 2002.01.01, Rendered while game is loading...
  620. //! \fixme seperate logo/particle coor later
  621. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  622. glLoadIdentity();
  623. glColor3fv(WHITE);
  624. if (mFlags & Render::fGL_Lights)
  625. glDisable(GL_LIGHTING);
  626. // Mongoose 2002.01.01, Draw logo/load screen
  627. glTranslatef(0.0f, 0.0f, -2000.0f);
  628. glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
  629. glBindTexture(GL_TEXTURE_2D, 2); //! \fixme store texture id somewhere
  630. glBegin(GL_TRIANGLE_STRIP);
  631. glTexCoord2f(1.0, 1.0);
  632. glVertex3f(x + w, y + h, z);
  633. glTexCoord2f(0.0, 1.0);
  634. glVertex3f(x - w, y + h, z);
  635. glTexCoord2f(1.0, 0.0);
  636. glVertex3f(x + w, y - h, z);
  637. glTexCoord2f(0.0, 0.0);
  638. glVertex3f(x - w, y - h, z);
  639. glEnd();
  640. if (mFlags & Render::fGL_Lights)
  641. glEnable(GL_LIGHTING);
  642. #ifdef USING_EMITTER
  643. // Mongoose 2002.01.01, Test particle prototype on load screen
  644. if (mEmitter && mFlags & Render::fParticles)
  645. {
  646. glPushMatrix();
  647. glLoadIdentity();
  648. glEnable(GL_BLEND);
  649. glRotatef(180.0, 1.0, 0.0, 0.0);
  650. glTranslatef(0.0, -820.0, 575.0);
  651. glScalef(80.0, 80.0, 80.0);
  652. // Update view volume for vising
  653. updateViewVolume();
  654. mViewVolume.getFrustum(mEmitter->mFrustum);
  655. mEmitter->Flags(Emitter::fUseDepthSorting, true);
  656. mEmitter->Draw();
  657. glPopMatrix();
  658. }
  659. #endif
  660. glFlush();
  661. }
  662. void Render::newRoomRenderList(int index)
  663. {
  664. static int currentRoomId = -1;
  665. RenderRoom *room;
  666. if (mFlags & Render::fUsePortals)
  667. {
  668. if (index == -1) // -1 is error, so draw room 0, for the hell of it
  669. {
  670. room = mRooms[0];
  671. mRoomRenderList.clear();
  672. if (room)
  673. {
  674. mRoomRenderList.push_back(room);
  675. }
  676. }
  677. else
  678. {
  679. // Update room render list if needed
  680. if (mFlags & Render::fUpdateRoomListPerFrame ||
  681. currentRoomId != index)
  682. {
  683. mRoomRenderList.clear();
  684. room = mRooms[index];
  685. buildRoomRenderList(room);
  686. }
  687. }
  688. }
  689. else // Render all rooms pretty much
  690. {
  691. if (currentRoomId != index || index == -1)
  692. {
  693. printf("*** Room render list -> %i\n", index);
  694. mRoomRenderList.clear();
  695. for (unsigned int i = 0; i < mRooms.size(); i++)
  696. {
  697. room = mRooms[i];
  698. if (!room || !room->room)
  699. continue;
  700. if (!isVisible(room->room->bbox_min, room->room->bbox_max))
  701. continue;
  702. //room->dist =
  703. //mViewVolume.getDistToBboxFromNear(room->room->bbox_min,
  704. // room->room->bbox_max);
  705. mRoomRenderList.push_back(room);
  706. }
  707. }
  708. }
  709. // Depth Sort roomRenderList ( no use in that, work on portals first )
  710. std::sort(mRoomRenderList.begin(), mRoomRenderList.end(), compareRoomDist);
  711. currentRoomId = index;
  712. }
  713. void Render::buildRoomRenderList(RenderRoom *rRoom)
  714. {
  715. RenderRoom *rRoom2;
  716. // Must exist
  717. if (!rRoom || !rRoom->room)
  718. return;
  719. // Must be visible
  720. //! \fixme Add depth sorting here - remove multipass
  721. if (!isVisible(rRoom->room->bbox_min, rRoom->room->bbox_max))
  722. return;
  723. // Must not already be cached
  724. for (unsigned int i = 0; i < mRoomRenderList.size(); i++)
  725. {
  726. rRoom2 = mRoomRenderList[i];
  727. if (rRoom2 == rRoom)
  728. return;
  729. }
  730. //rRoom->dist =
  731. //mViewVolume.getDistToBboxFromNear(rRoom->room->bbox_min,
  732. // rRoom->room->bbox_max);
  733. /* Add current room to list */
  734. mRoomRenderList.push_back(rRoom);
  735. if (mFlags & Render::fOneRoom)
  736. {
  737. return;
  738. }
  739. else if (mFlags & Render::fAllRooms) /* Are you serious? */
  740. {
  741. for (unsigned int i = 0; i < mRooms.size(); i++)
  742. {
  743. rRoom2 = mRooms[i];
  744. if (rRoom2 && rRoom2 != rRoom)
  745. {
  746. buildRoomRenderList(rRoom2);
  747. }
  748. }
  749. return;
  750. }
  751. // Try to add adj rooms and their adj rooms, skip this room
  752. for (unsigned int i = 1; i < rRoom->room->adjacentRooms.size(); i++)
  753. {
  754. if (rRoom->room->adjacentRooms[i] < 0)
  755. continue;
  756. rRoom2 = mRooms[rRoom->room->adjacentRooms[i]];
  757. // Mongoose 2002.03.22, Add portal visibility check here
  758. if (rRoom2 && rRoom2 != rRoom)
  759. {
  760. buildRoomRenderList(rRoom2);
  761. }
  762. }
  763. }
  764. void Render::drawSkyMesh(float scale)
  765. {
  766. skeletal_model_t *model = gOpenRaider->mGame->mWorld.getModel(mSkyMesh);
  767. if (!model)
  768. return;
  769. glDisable(GL_DEPTH_TEST);
  770. glPushMatrix();
  771. if (mSkyMeshRotation)
  772. {
  773. glRotated(90.0, 1, 0, 0);
  774. }
  775. glTranslated(0.0, 1000.0, 0.0);
  776. glScaled(scale, scale, scale);
  777. //drawModel(model);
  778. //drawModelMesh(gOpenRaider->mGame->mWorld.getMesh(mSkyMesh), );
  779. glPopMatrix();
  780. glEnable(GL_DEPTH_TEST);
  781. }
  782. void Render::drawObjects()
  783. {
  784. #ifdef USING_FPS_CAMERA
  785. vec3_t curPos;
  786. #endif
  787. sprite_seq_t *sprite;
  788. int frame;
  789. // Draw lara or other player model ( move to entity rendering method )
  790. if (mFlags & Render::fViewModel && gOpenRaider->mGame->mLara && gOpenRaider->mGame->mLara->tmpHook)
  791. {
  792. SkeletalModel *mdl = static_cast<SkeletalModel *>(gOpenRaider->mGame->mLara->tmpHook);
  793. if (mdl)
  794. {
  795. // Mongoose 2002.03.22, Test 'idle' aniamtions
  796. if (!gOpenRaider->mGame->mLara->moving)
  797. {
  798. frame = mdl->getIdleAnimation();
  799. // Mongoose 2002.08.15, Stop flickering of idle lara here
  800. if (frame == 11)
  801. {
  802. mdl->setFrame(0);
  803. }
  804. }
  805. else
  806. {
  807. frame = mdl->getAnimation();
  808. }
  809. animation_frame_t *animation = mdl->model->animation[frame];
  810. if (animation && mdl->getFrame() > (int)animation->frame.size()-1)
  811. {
  812. mdl->setFrame(0);
  813. }
  814. }
  815. glPushMatrix();
  816. #ifdef USING_FPS_CAMERA
  817. gOpenRaider->mGame->mCamera->getPosition(curPos);
  818. glTranslated(curPos[0], curPos[1], curPos[2]);
  819. glRotated(gOpenRaider->mGame->mCamera->getYaw(), 0, 1, 0);
  820. glTranslated(0, 500, 1200);
  821. #else
  822. glTranslated(gOpenRaider->mGame->mLara->pos[0], gOpenRaider->mGame->mLara->pos[1], gOpenRaider->mGame->mLara->pos[2]);
  823. glRotated(gOpenRaider->mGame->mCamera->getYaw(), 0, 1, 0);
  824. #endif
  825. drawModel(static_cast<SkeletalModel *>(gOpenRaider->mGame->mLara->tmpHook));
  826. glPopMatrix();
  827. }
  828. // Mongoose 2002.03.22, Draw sprites after player to handle alpha
  829. if (mFlags & Render::fSprites)
  830. {
  831. std::vector<sprite_seq_t *> *sprites;
  832. sprites = gOpenRaider->mGame->mWorld.getSprites();
  833. for (unsigned int i = 0; i < sprites->size(); i++)
  834. {
  835. sprite = sprites->at(i);
  836. if (!sprite)
  837. continue;
  838. if (sprite->sprite && sprite->num_sprites)
  839. {
  840. for (int j = 0; j < sprite->num_sprites; j++)
  841. {
  842. drawSprite((sprite_t *)(sprite->sprite+j));
  843. }
  844. }
  845. }
  846. }
  847. }
  848. void Render::drawModel(SkeletalModel *model)
  849. {
  850. animation_frame_t *animation;
  851. bone_frame_t *boneframe;
  852. bone_frame_t *boneframe2 = 0x0;
  853. bone_tag_t *tag;
  854. bone_tag_t *tag2;
  855. int bframe, aframe;
  856. skeletal_model_t *mdl;
  857. if (!model || !model->model)
  858. return;
  859. mdl = model->model;
  860. aframe = model->getAnimation();
  861. bframe = model->getFrame();
  862. animation = mdl->animation[aframe];
  863. if (!animation)
  864. {
  865. #ifdef DEBUG
  866. printf("ERROR: No animation for model[%i].aframe[%i] %lu\n",
  867. mdl->id, aframe, mdl->animation.size());
  868. #endif
  869. return;
  870. }
  871. if (animation->frame.empty())
  872. {
  873. #ifdef DEBUG_RENDER
  874. printf("ERROR: No boneframes?!?! *** %i:%i ***\n",
  875. mdl->id, bframe);
  876. #endif
  877. return;
  878. }
  879. boneframe = animation->frame[bframe];
  880. if (!boneframe)
  881. return;
  882. if (boneframe->tag.empty())
  883. {
  884. printf("Empty bone frame?!?!\n");
  885. return;
  886. }
  887. glTranslatef(boneframe->pos[0], boneframe->pos[1], boneframe->pos[2]);
  888. for (unsigned int a = 0; a < boneframe->tag.size(); a++)
  889. {
  890. tag = boneframe->tag[a];
  891. if (!tag)
  892. continue;
  893. if (a == 0)
  894. {
  895. if (!equalEpsilon(tag->rot[1], 0.0f)) // was just if (tag->rot[1])
  896. glRotatef(tag->rot[1], 0, 1, 0);
  897. if (!equalEpsilon(tag->rot[0], 0.0f))
  898. glRotatef(tag->rot[0], 1, 0, 0);
  899. if (!equalEpsilon(tag->rot[2], 0.0f))
  900. glRotatef(tag->rot[2], 0, 0, 1);
  901. }
  902. else
  903. {
  904. if (tag->flag & 0x01)
  905. glPopMatrix();
  906. if (tag->flag & 0x02)
  907. glPushMatrix();
  908. glTranslatef(tag->off[0], tag->off[1], tag->off[2]);
  909. if (!equalEpsilon(tag->rot[1], 0.0f))
  910. glRotatef(tag->rot[1], 0, 1, 0);
  911. if (!equalEpsilon(tag->rot[0], 0.0f))
  912. glRotatef(tag->rot[0], 1, 0, 0);
  913. if (!equalEpsilon(tag->rot[2], 0.0f))
  914. glRotatef(tag->rot[2], 0, 0, 1);
  915. }
  916. // Draw layered lara in TR4 ( 2 meshes per tag )
  917. if (mdl->tr4Overlay == 1)
  918. {
  919. boneframe2 = (mdl->animation[0])->frame[0];
  920. if (boneframe2)
  921. {
  922. tag2 = boneframe2->tag[a];
  923. if (tag2)
  924. {
  925. drawModelMesh(gOpenRaider->mGame->mWorld.getMesh(tag2->mesh), Render::skeletalMesh);
  926. }
  927. }
  928. }
  929. if (mFlags & Render::fRenderPonytail)
  930. {
  931. if (mdl->ponytailId > 0 &&
  932. a == 14)
  933. {
  934. glPushMatrix();
  935. // Mongoose 2002.08.30, TEST to align offset
  936. glTranslatef(mdl->ponytail[0], mdl->ponytail[1], mdl->ponytail[2]);
  937. glRotatef(mdl->ponytailAngle, 1, 0, 0);
  938. // HACK: To fill TR4 void between ponytail/head
  939. // since no vertex welds are implemented yet
  940. if (mdl->tr4Overlay == 1)
  941. {
  942. glScalef(1.20f, 1.20f, 1.20f);
  943. }
  944. #ifdef EXPERIMENTAL_NON_ITEM_RENDER
  945. drawModel(mModels[mdl->ponytail], 0, 0);
  946. #else
  947. for (unsigned int i = 0; i < mdl->ponytailNumMeshes; ++i)
  948. {
  949. glPushMatrix();
  950. if (i > 0)
  951. {
  952. glRotatef(randomNum(-8.0f, -10.0f), 1, 0, 0);
  953. glRotatef(randomNum(-5.0f, 5.0f), 0, 1, 0);
  954. glRotatef(randomNum(-5.0f, 5.0f), 0, 0, 1);
  955. glTranslatef(0.0, 0.0, mdl->ponyOff);
  956. }
  957. if (mdl->pigtails)
  958. {
  959. glPushMatrix();
  960. glTranslatef(mdl->ponyOff2, 0.0, 0.0);
  961. drawModelMesh(gOpenRaider->mGame->mWorld.getMesh(mdl->ponytailMeshId + i),
  962. Render::skeletalMesh);
  963. glPopMatrix();
  964. glPushMatrix();
  965. glTranslatef(-mdl->ponyOff2, 0.0, 0.0);
  966. drawModelMesh(gOpenRaider->mGame->mWorld.getMesh(mdl->ponytailMeshId + i),
  967. Render::skeletalMesh);
  968. glPopMatrix();
  969. }
  970. else
  971. {
  972. drawModelMesh(gOpenRaider->mGame->mWorld.getMesh(mdl->ponytailMeshId + i),
  973. Render::skeletalMesh);
  974. }
  975. }
  976. for (unsigned int i = 0; i < mdl->ponytailNumMeshes; ++i)
  977. {
  978. glPopMatrix();
  979. }
  980. #endif
  981. glPopMatrix();
  982. }
  983. }
  984. drawModelMesh(gOpenRaider->mGame->mWorld.getMesh(tag->mesh), Render::skeletalMesh);
  985. }
  986. // Cycle frames ( cheap hack from old ent state based system )
  987. if (mFlags & fAnimateAllModels)
  988. {
  989. if (model->getFrame() + 1 > (int)animation->frame.size()-1)
  990. {
  991. model->setFrame(0);
  992. }
  993. else
  994. {
  995. model->setFrame(model->getFrame()+1);
  996. }
  997. }
  998. }
  999. void draw_bbox(vec3_t min, vec3_t max, bool draw_points)
  1000. {
  1001. // Bind before entering now
  1002. //glBindTexture(GL_TEXTURE_2D, 1);
  1003. glPointSize(4.0);
  1004. //glLineWidth(1.25);
  1005. //! \fixme Need to make custom color key for this
  1006. glColor3fv(RED);
  1007. glBegin(GL_POINTS);
  1008. glVertex3f(max[0], max[1], max[2]);
  1009. glVertex3f(min[0], min[1], min[2]);
  1010. if (draw_points)
  1011. {
  1012. glVertex3f(max[0], min[1], max[2]);
  1013. glVertex3f(min[0], max[1], max[2]);
  1014. glVertex3f(max[0], max[1], min[2]);
  1015. glVertex3f(min[0], min[1], max[2]);
  1016. glVertex3f(min[0], max[1], min[2]);
  1017. glVertex3f(max[0], min[1], min[2]);
  1018. }
  1019. glEnd();
  1020. glColor3fv(GREEN);
  1021. glBegin(GL_LINES);
  1022. // max, top quad
  1023. glVertex3f(max[0], max[1], max[2]);
  1024. glVertex3f(max[0], min[1], max[2]);
  1025. glVertex3f(max[0], max[1], max[2]);
  1026. glVertex3f(min[0], max[1], max[2]);
  1027. glVertex3f(max[0], max[1], max[2]);
  1028. glVertex3f(max[0], max[1], min[2]);
  1029. // max-min, vertical quads
  1030. glVertex3f(min[0], max[1], max[2]);
  1031. glVertex3f(min[0], max[1], min[2]);
  1032. glVertex3f(max[0], min[1], max[2]);
  1033. glVertex3f(max[0], min[1], min[2]);
  1034. glVertex3f(max[0], min[1], max[2]);
  1035. glVertex3f(min[0], min[1], max[2]);
  1036. // min-max, vertical quads
  1037. glVertex3f(max[0], max[1], min[2]);
  1038. glVertex3f(max[0], min[1], min[2]);
  1039. glVertex3f(max[0], max[1], min[2]);
  1040. glVertex3f(min[0], max[1], min[2]);
  1041. glVertex3f(min[0], max[1], max[2]);
  1042. glVertex3f(min[0], min[1], max[2]);
  1043. // min, bottom quad
  1044. glVertex3f(min[0], min[1], min[2]);
  1045. glVertex3f(min[0], max[1], min[2]);
  1046. glVertex3f(min[0], min[1], min[2]);
  1047. glVertex3f(max[0], min[1], min[2]);
  1048. glVertex3f(min[0], min[1], min[2]);
  1049. glVertex3f(min[0], min[1], max[2]);
  1050. glEnd();
  1051. glPointSize(1.0);
  1052. //glLineWidth(1.0);
  1053. }
  1054. void draw_bbox_color(vec3_t min, vec3_t max, bool draw_points,
  1055. const vec4_t c1, const vec4_t c2)
  1056. {
  1057. // Bind before entering now
  1058. //glBindTexture(GL_TEXTURE_2D, 1);
  1059. glPointSize(4.0);
  1060. //glLineWidth(1.25);
  1061. //! \fixme Need to make custom color key for this
  1062. glColor3fv(c1);
  1063. glBegin(GL_POINTS);
  1064. glVertex3f(max[0], max[1], max[2]);
  1065. glVertex3f(min[0], min[1], min[2]);
  1066. if (draw_points)
  1067. {
  1068. glVertex3f(max[0], min[1], max[2]);
  1069. glVertex3f(min[0], max[1], max[2]);
  1070. glVertex3f(max[0], max[1], min[2]);
  1071. glVertex3f(min[0], min[1], max[2]);
  1072. glVertex3f(min[0], max[1], min[2]);
  1073. glVertex3f(max[0], min[1], min[2]);
  1074. }
  1075. glEnd();
  1076. glColor3fv(c2);
  1077. glBegin(GL_LINES);
  1078. // max, top quad
  1079. glVertex3f(max[0], max[1], max[2]);
  1080. glVertex3f(max[0], min[1], max[2]);
  1081. glVertex3f(max[0], max[1], max[2]);
  1082. glVertex3f(min[0], max[1], max[2]);
  1083. glVertex3f(max[0], max[1], max[2]);
  1084. glVertex3f(max[0], max[1], min[2]);
  1085. // max-min, vertical quads
  1086. glVertex3f(min[0], max[1], max[2]);
  1087. glVertex3f(min[0], max[1], min[2]);
  1088. glVertex3f(max[0], min[1], max[2]);
  1089. glVertex3f(max[0], min[1], min[2]);
  1090. glVertex3f(max[0], min[1], max[2]);
  1091. glVertex3f(min[0], min[1], max[2]);
  1092. // min-max, vertical quads
  1093. glVertex3f(max[0], max[1], min[2]);
  1094. glVertex3f(max[0], min[1], min[2]);
  1095. glVertex3f(max[0], max[1], min[2]);
  1096. glVertex3f(min[0], max[1], min[2]);
  1097. glVertex3f(min[0], max[1], max[2]);
  1098. glVertex3f(min[0], min[1], max[2]);
  1099. // min, bottom quad
  1100. glVertex3f(min[0], min[1], min[2]);
  1101. glVertex3f(min[0], max[1], min[2]);
  1102. glVertex3f(min[0], min[1], min[2]);
  1103. glVertex3f(max[0], min[1], min[2]);
  1104. glVertex3f(min[0], min[1], min[2]);
  1105. glVertex3f(min[0], min[1], max[2]);
  1106. glEnd();
  1107. glPointSize(1.0);
  1108. //glLineWidth(1.0);
  1109. }
  1110. void Render::drawRoom(RenderRoom *rRoom, bool draw_alpha)
  1111. {
  1112. room_mesh_t *room;
  1113. if (!rRoom || !rRoom->room)
  1114. return;
  1115. room = rRoom->room;
  1116. if (!(mFlags & Render::fRoomAlpha) && draw_alpha)
  1117. return;
  1118. glPushMatrix();
  1119. //LightingSetup();
  1120. glBindTexture(GL_TEXTURE_2D, 1); // WHITE texture
  1121. if (!draw_alpha &&
  1122. (mFlags & Render::fPortals || mMode == Render::modeWireframe))
  1123. {
  1124. portal_t *portal;
  1125. glLineWidth(2.0);
  1126. glColor3fv(RED);
  1127. for (unsigned int i = 0; i < room->portals.size(); i++)
  1128. {
  1129. portal = room->portals[i];
  1130. if (!portal)
  1131. continue;
  1132. glBegin(GL_LINE_LOOP);
  1133. glVertex3fv(portal->vertices[0]);
  1134. glVertex3fv(portal->vertices[1]);
  1135. glVertex3fv(portal->vertices[2]);
  1136. glVertex3fv(portal->vertices[3]);
  1137. glEnd();
  1138. }
  1139. glLineWidth(1.0);
  1140. #ifdef OBSOLETE
  1141. glColor3fv(RED);
  1142. for (i = 0; i < (int)room->num_boxes; ++i)
  1143. {
  1144. // Mongoose 2002.08.14, This is a simple test -
  1145. // these like portals are really planes
  1146. glBegin(GL_QUADS);
  1147. glVertex3fv(room->boxes[i].a.pos);
  1148. glVertex3fv(room->boxes[i].b.pos);
  1149. glVertex3fv(room->boxes[i].c.pos);
  1150. glVertex3fv(room->boxes[i].d.pos);
  1151. glEnd();
  1152. }
  1153. #endif
  1154. }
  1155. if (mMode == Render::modeWireframe && !draw_alpha)
  1156. {
  1157. draw_bbox(room->bbox_min, room->bbox_max, true);
  1158. }
  1159. glTranslated(room->pos[0], room->pos[1], room->pos[2]);
  1160. // Reset since GL_MODULATE used, reset to WHITE
  1161. glColor3fv(WHITE);
  1162. switch (mMode)
  1163. {
  1164. case modeWireframe:
  1165. rRoom->mesh.mMode = Mesh::MeshModeWireframe;
  1166. break;
  1167. case modeSolid:
  1168. rRoom->mesh.mMode = Mesh::MeshModeSolid;
  1169. break;
  1170. default:
  1171. rRoom->mesh.mMode = Mesh::MeshModeTexture;
  1172. break;
  1173. }
  1174. if (draw_alpha)
  1175. {
  1176. rRoom->mesh.drawAlpha();
  1177. }
  1178. else
  1179. {
  1180. rRoom->mesh.drawSolid();
  1181. }
  1182. glPopMatrix();
  1183. //mTexture.bindTextureId(0);
  1184. // Draw other room meshes and sprites
  1185. if (draw_alpha || mMode == modeWireframe || mMode == modeSolid)
  1186. {
  1187. if (mFlags & Render::fRoomModels)
  1188. {
  1189. static_model_t *mdl;
  1190. for (unsigned int i = 0; i < room->models.size(); i++)
  1191. {
  1192. mdl = room->models[i];
  1193. if (!mdl)
  1194. continue;
  1195. mdl->pos[0] += room->pos[0];
  1196. mdl->pos[1] += room->pos[1];
  1197. mdl->pos[2] += room->pos[2];
  1198. // Depth sort room model render list with qsort
  1199. std::sort(room->models.begin(), room->models.end(), compareStaticModels);
  1200. mdl->pos[0] -= room->pos[0];
  1201. mdl->pos[1] -= room->pos[1];
  1202. mdl->pos[2] -= room->pos[2];
  1203. }
  1204. for (unsigned int i = 0; i < room->models.size(); i++)
  1205. {
  1206. drawRoomModel(room->models[i]);
  1207. }
  1208. }
  1209. // Draw other room alpha polygon objects
  1210. if (mFlags & Render::fSprites)
  1211. {
  1212. for (unsigned int i = 0; i < room->sprites.size(); i++)
  1213. {
  1214. drawSprite(room->sprites[i]);
  1215. }
  1216. }
  1217. }
  1218. }
  1219. void Render::drawSprite(sprite_t *sprite)
  1220. {
  1221. if (!sprite)
  1222. return;
  1223. if (!isVisible(sprite->pos[0], sprite->pos[1], sprite->pos[2],
  1224. sprite->radius))
  1225. return;
  1226. glPushMatrix();
  1227. glTranslated(sprite->pos[0], sprite->pos[1], sprite->pos[2]);
  1228. // Sprites must always face camera, because they have no depth =)
  1229. glRotated(gOpenRaider->mGame->mCamera->getYaw(), 0, 1, 0);
  1230. switch (mMode)
  1231. {
  1232. // No vertex lighting on sprites, as far as I see in specs
  1233. // So just draw normal texture, no case 2
  1234. case Render::modeSolid:
  1235. glBegin(GL_TRIANGLE_STRIP);
  1236. glColor3f(sprite->texel[0].st[0], sprite->texel[0].st[1], 0.5);
  1237. glVertex3fv(sprite->vertex[0].pos);
  1238. glColor3f(sprite->texel[1].st[0], sprite->texel[1].st[1], 0.5);
  1239. glVertex3fv(sprite->vertex[1].pos);
  1240. glColor3f(sprite->texel[3].st[0], sprite->texel[3].st[1], 0.5);
  1241. glVertex3fv(sprite->vertex[3].pos);
  1242. glColor3f(sprite->texel[2].st[0], sprite->texel[2].st[1], 0.5);
  1243. glVertex3fv(sprite->vertex[2].pos);
  1244. glEnd();
  1245. break;
  1246. case Render::modeWireframe:
  1247. glColor3fv(CYAN);
  1248. glBegin(GL_LINE_LOOP);
  1249. glVertex3fv(sprite->vertex[0].pos);
  1250. glVertex3fv(sprite->vertex[1].pos);
  1251. glVertex3fv(sprite->vertex[2].pos);
  1252. glVertex3fv(sprite->vertex[3].pos);
  1253. glEnd();
  1254. glColor3fv(WHITE);
  1255. break;
  1256. default:
  1257. glBindTexture(GL_TEXTURE_2D, sprite->texture+1);
  1258. glBegin(GL_TRIANGLE_STRIP);
  1259. glTexCoord2fv(sprite->texel[0].st);
  1260. glVertex3fv(sprite->vertex[0].pos);
  1261. glTexCoord2fv(sprite->texel[1].st);
  1262. glVertex3fv(sprite->vertex[1].pos);
  1263. glTexCoord2fv(sprite->texel[3].st);
  1264. glVertex3fv(sprite->vertex[3].pos);
  1265. glTexCoord2fv(sprite->texel[2].st);
  1266. glVertex3fv(sprite->vertex[2].pos);
  1267. glEnd();
  1268. }
  1269. glPopMatrix();
  1270. }
  1271. void Render::drawRoomModel(static_model_t *mesh)
  1272. {
  1273. model_mesh_t *r_mesh;
  1274. if (!mesh)
  1275. return;
  1276. r_mesh = gOpenRaider->mGame->mWorld.getMesh(mesh->index);
  1277. if (!r_mesh)
  1278. return;
  1279. if (!isVisible(mesh->pos[0], mesh->pos[1], mesh->pos[2], r_mesh->radius))
  1280. return;
  1281. glPushMatrix();
  1282. glTranslated(mesh->pos[0], mesh->pos[1], mesh->pos[2]);
  1283. glRotated(mesh->yaw, 0, 1, 0);
  1284. drawModelMesh(r_mesh, roomMesh);
  1285. glPopMatrix();
  1286. }
  1287. void Render::tmpRenderModelMesh(model_mesh_t *r_mesh, texture_tri_t *ttri)
  1288. {
  1289. glBegin(GL_TRIANGLES);
  1290. switch (mMode)
  1291. {
  1292. case modeSolid:
  1293. case modeVertexLight:
  1294. if (r_mesh->colors)
  1295. {
  1296. glColor3fv(r_mesh->colors+ttri->index[0]);
  1297. glTexCoord2fv(ttri->st);
  1298. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  1299. glColor3fv(r_mesh->colors+ttri->index[1]);
  1300. glTexCoord2fv(ttri->st+2);
  1301. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  1302. glColor3fv(r_mesh->colors+ttri->index[2]);
  1303. glTexCoord2fv(ttri->st+4);
  1304. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  1305. }
  1306. else if (r_mesh->normals)
  1307. {
  1308. glNormal3fv(r_mesh->normals+ttri->index[0]*3);
  1309. glTexCoord2fv(ttri->st);
  1310. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  1311. glNormal3fv(r_mesh->normals+ttri->index[1]*3);
  1312. glTexCoord2fv(ttri->st+2);
  1313. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  1314. glNormal3fv(r_mesh->normals+ttri->index[2]*3);
  1315. glTexCoord2fv(ttri->st+4);
  1316. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  1317. }
  1318. else
  1319. {
  1320. glTexCoord2fv(ttri->st);
  1321. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  1322. glTexCoord2fv(ttri->st+2);
  1323. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  1324. glTexCoord2fv(ttri->st+4);
  1325. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  1326. }
  1327. break;
  1328. case modeWireframe:
  1329. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  1330. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  1331. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  1332. break;
  1333. default:
  1334. glTexCoord2fv(ttri->st);
  1335. glVertex3fv(r_mesh->vertices+ttri->index[0]*3);
  1336. glTexCoord2fv(ttri->st+2);
  1337. glVertex3fv(r_mesh->vertices+ttri->index[1]*3);
  1338. glTexCoord2fv(ttri->st+4);
  1339. glVertex3fv(r_mesh->vertices+ttri->index[2]*3);
  1340. }
  1341. glEnd();
  1342. }
  1343. void Render::drawModelMesh(model_mesh_t *r_mesh, RenderMeshType type)
  1344. {
  1345. texture_tri_t *ttri;
  1346. int lastTexture = -1;
  1347. // If they pass NULL structs let it hang up - this is tmp
  1348. //! \fixme Duh, vis tests need to be put back
  1349. //if (!isVisible(r_mesh->center, r_mesh->radius, r_mesh->bbox))
  1350. //{
  1351. // return;
  1352. //}
  1353. #ifdef USE_GL_ARRAYS
  1354. // Setup Arrays ( move these to another method depends on mMode )
  1355. glEnableClientState(GL_VERTEX_ARRAY);
  1356. glVertexPointer(3, GL_FLOAT, 0, r_mesh->vertices);
  1357. if (r_mesh->normals)
  1358. {
  1359. glEnableClientState(GL_NORMAL_ARRAY);
  1360. glNormalPointer(3, GL_FLOAT, 0, r_mesh->normals);
  1361. }
  1362. if (r_mesh->colors)
  1363. {
  1364. glEnableClientState(GL_COLOR_ARRAY);
  1365. glColorPointer(4, GL_FLOAT, 0, r_mesh->colors);
  1366. }
  1367. //glTexCoordPointer(2, GL_FLOAT, 0, ttri->st);
  1368. //glDrawArrays(GL_TRIANGLES, i * 3, 3 * j);
  1369. glBegin(GL_TRIANGLES);
  1370. for (unsigned int i = 0; i < r_mesh->texturedTriangles.size(); i++)
  1371. {
  1372. ttri = r_mesh->texturedTriangles[i];
  1373. if (!ttri)
  1374. continue;
  1375. for (k = 0; k < 4; ++k)
  1376. {
  1377. index = mQuads[i].quads[j*4+k];
  1378. glTexCoord2fv(mQuads[i].texcoors[j*4+k]);
  1379. glArrayElement(mVertices[index]);
  1380. }
  1381. }
  1382. glEnd();
  1383. #endif
  1384. //! \fixme 'AMBIENT' -- Mongoose 2002.01.08
  1385. glColor3fv(WHITE);
  1386. if (mMode == modeWireframe)
  1387. {
  1388. switch (type)
  1389. {
  1390. case roomMesh:
  1391. glColor3fv(YELLOW);
  1392. break;
  1393. case skeletalMesh:
  1394. glColor3fv(WHITE);
  1395. break;
  1396. }
  1397. }
  1398. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1399. glBindTexture(GL_TEXTURE_2D, 1); // White texture for colors
  1400. // Colored Triagles
  1401. for (unsigned int i = 0; i < r_mesh->coloredTriangles.size(); i++)
  1402. {
  1403. ttri = r_mesh->coloredTriangles[i];
  1404. if (!ttri)
  1405. continue;
  1406. if (mMode != modeWireframe && mMode != modeSolid &&
  1407. ttri->texture != lastTexture)
  1408. {
  1409. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1410. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  1411. lastTexture = ttri->texture;
  1412. }
  1413. tmpRenderModelMesh(r_mesh, ttri);
  1414. }
  1415. // Colored Rectagles
  1416. for (unsigned int i = 0; i < r_mesh->coloredRectangles.size(); i++)
  1417. {
  1418. ttri = r_mesh->coloredRectangles[i];
  1419. if (!ttri)
  1420. continue;
  1421. if (mMode != modeWireframe && mMode != modeSolid &&
  1422. ttri->texture != lastTexture)
  1423. {
  1424. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1425. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  1426. lastTexture = ttri->texture;
  1427. }
  1428. tmpRenderModelMesh(r_mesh, ttri);
  1429. }
  1430. // Textured Tris
  1431. for (unsigned int i = 0; i < r_mesh->texturedTriangles.size(); i++)
  1432. {
  1433. ttri = r_mesh->texturedTriangles[i];
  1434. if (!ttri)
  1435. continue;
  1436. if (mMode != modeWireframe && mMode != modeSolid &&
  1437. ttri->texture != lastTexture)
  1438. {
  1439. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1440. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  1441. lastTexture = ttri->texture;
  1442. }
  1443. tmpRenderModelMesh(r_mesh, ttri);
  1444. }
  1445. // Textured Quads
  1446. for (unsigned int i = 0; i < r_mesh->texturedRectangles.size(); i++)
  1447. {
  1448. ttri = r_mesh->texturedRectangles[i];
  1449. if (!ttri)
  1450. continue;
  1451. if (mMode != modeWireframe && mMode != modeSolid &&
  1452. ttri->texture != lastTexture)
  1453. {
  1454. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1455. glBindTexture(GL_TEXTURE_2D, ttri->texture+1);
  1456. lastTexture = ttri->texture;
  1457. }
  1458. tmpRenderModelMesh(r_mesh, ttri);
  1459. }
  1460. }
  1461. void Render::setSkyMesh(int index, bool rot)
  1462. {
  1463. mSkyMesh = index;
  1464. mSkyMeshRotation = rot;
  1465. }
  1466. void Render::ViewModel(entity_t *ent, int index)
  1467. {
  1468. skeletal_model_t *model;
  1469. if (!ent)
  1470. {
  1471. return;
  1472. }
  1473. model = gOpenRaider->mGame->mWorld.getModel(index);
  1474. if (model)
  1475. {
  1476. ent->modelId = index;
  1477. printf("Viewmodel skeletal model %i\n", model->id);
  1478. }
  1479. }
  1480. void Render::addSkeletalModel(SkeletalModel *mdl)
  1481. {
  1482. mModels.push_back(mdl);
  1483. }
  1484. void Render::updateViewVolume()
  1485. {
  1486. matrix_t proj;
  1487. matrix_t mdl;
  1488. glGetFloatv(GL_PROJECTION_MATRIX, proj);
  1489. glGetFloatv(GL_MODELVIEW_MATRIX, mdl);
  1490. mViewVolume.updateFrame(proj, mdl);
  1491. }
  1492. bool Render::isVisible(float bbox_min[3], float bbox_max[3])
  1493. {
  1494. // For debugging purposes
  1495. if (mMode == Render::modeWireframe)
  1496. {
  1497. //glPointSize(5.0);
  1498. //glColor3fv(PINK);
  1499. //glBegin(GL_POINTS);
  1500. //glVertex3fv(bbox_min);
  1501. //glVertex3fv(bbox_max);
  1502. //glEnd();
  1503. draw_bbox_color(bbox_min, bbox_max, true, PINK, RED);
  1504. }
  1505. return mViewVolume.isBboxInFrustum(bbox_min, bbox_max);
  1506. }
  1507. bool Render::isVisible(float x, float y, float z)
  1508. {
  1509. // For debugging purposes
  1510. if (mMode == Render::modeWireframe)
  1511. {
  1512. glPointSize(5.0);
  1513. glColor3fv(PINK);
  1514. glBegin(GL_POINTS);
  1515. glVertex3f(x, y, z);
  1516. glEnd();
  1517. }
  1518. return (mViewVolume.isPointInFrustum(x, y, z));
  1519. }
  1520. bool Render::isVisible(float x, float y, float z, float radius)
  1521. {
  1522. // For debugging purposes
  1523. if (mMode == Render::modeWireframe)
  1524. {
  1525. glPointSize(5.0);
  1526. glColor3fv(PINK);
  1527. glBegin(GL_POINTS);
  1528. glVertex3f(x, y, z);
  1529. glEnd();
  1530. }
  1531. return (mViewVolume.isSphereInFrustum(x, y, z, radius));
  1532. }