iphone_render.c 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766
  1. /*
  2. * iphoneRender.c
  3. * doom
  4. *
  5. * Created by John Carmack on 4/29/09.
  6. * Copyright 2009 id Software. All rights reserved.
  7. *
  8. */
  9. /*
  10. Copyright (C) 2009 Id Software, Inc.
  11. This program is free software; you can redistribute it and/or
  12. modify it under the terms of the GNU General Public License
  13. as published by the Free Software Foundation; either version 2
  14. of the License, or (at your option) any later version.
  15. This program is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <math.h>
  26. #include "SDL_opengl.h"
  27. #include "doomtype.h"
  28. #include "w_wad.h"
  29. #include "m_argv.h"
  30. #include "d_event.h"
  31. #include "v_video.h"
  32. #include "doomstat.h"
  33. #include "r_bsp.h"
  34. #include "r_main.h"
  35. #include "r_draw.h"
  36. #include "r_sky.h"
  37. #include "r_plane.h"
  38. #include "r_data.h"
  39. #include "r_things.h"
  40. #include "r_fps.h"
  41. #include "p_maputl.h"
  42. #include "m_bbox.h"
  43. #include "lprintf.h"
  44. #include "gl_intern.h"
  45. #include "gl_struct.h"
  46. // If the Doom levels had been built with realistic visibility
  47. // taken into account for the sky areas, we could just draw the
  48. // sky first and then the walls, but that gives artifacts where
  49. // you see some sectors floating in the sky now. This causes
  50. // the walls to draw extended top and bottom sections for skies.
  51. #define SKYWALLS
  52. #define MINZ (FRACUNIT*4)
  53. #define BASEYCENTER 100
  54. #define MINZ_FLOAT 4
  55. typedef struct {
  56. GLTexture *tex;
  57. side_t *side;
  58. int flag; // GLDWF_TOP, GLDWF_M1S, etc
  59. } sortLine_t;
  60. #define MAX_SORT_LINES 4096
  61. sortLine_t sortLines[MAX_SORT_LINES];
  62. int numSortLines;
  63. typedef struct {
  64. GLTexture *texture;
  65. sector_t *sector;
  66. boolean ceiling;
  67. } sortSectorPlane_t;
  68. #define MAX_SECTOR_PLANES 1024
  69. sortSectorPlane_t sectorPlanes[MAX_SECTOR_PLANES];
  70. int numSectorPlanes;
  71. typedef struct {
  72. GLTexture *tex;
  73. } sortSprite_t;
  74. // Cleared to 0 at frame start.
  75. // Individual columns will be set to 1 as occluding segments are processed.
  76. // An occluding segment is either a one-sided line, a line that has a back
  77. // sector with equal floor and ceiling heights, a line with a back ceiling
  78. // height lower than the fron floor height, or a line with a back floor height
  79. // higher than the front ceiling height.
  80. // Entire nodes are culled when their bounds does not include a 0 column.
  81. // Individual line segments are culled when their span does not include 0 columns.
  82. // Sprites could be checked against it, but it may not be worth it.
  83. char occlusion[MAX_SCREENWIDTH+2]; // +2 for guard columns to avoid clamping
  84. // when the iphone is upside down, the occlusion segments are reversed
  85. boolean reversedLandscape;
  86. // this matrix is exactly what GL uses, but there will still
  87. // be floating point differences between the GPU and CPU
  88. float glMVPmatrix[16];
  89. // if any sector textures are the sky texture, we will draw the sky and
  90. // ignore those sector geometries
  91. boolean skyIsVisible;
  92. // these should really be initialized based on viewwidth somewhere...
  93. float halfWidthFloat = 240.0f;
  94. // used during debugging to isolate incorrect culling
  95. int failCount;
  96. // Some of the two sided line segments in the original game don't have a valid
  97. // texture, so stick something there instead of leaving a gaping hole in the world.
  98. GLTexture *defaultTexture;
  99. // just for the sky texture setup
  100. float yaw;
  101. // counters
  102. int c_occludedSprites;
  103. int c_sectors;
  104. int c_subsectors;
  105. // test options
  106. int testClear = 0;
  107. int testNewRenderer = 0;
  108. int showRenderTime;
  109. int blendAll;
  110. void BuildIndexedTriangles();
  111. void BuildSideSegs();
  112. void IR_MergeSectors( int fromSector, int intoSector ) {
  113. // E3M8 (and possibly others somewhere) has a bad sector
  114. // classification with two stray lines in sector 2 that
  115. // should be a part of sector 1. This makes both of the
  116. // sectors "broken" and unable to be properly tesselated.
  117. assert( (unsigned)fromSector < numsectors );
  118. assert( (unsigned)intoSector < numsectors );
  119. sector_t *fromSectorPtr = &sectors[fromSector];
  120. sector_t *intoSectorPtr = &sectors[intoSector];
  121. int moveLines = 0;
  122. for ( int i = 0 ; i < numlines ; i++ ) {
  123. if ( lines[i].frontsector == fromSectorPtr ) {
  124. moveLines++;
  125. } else if ( lines[i].backsector == fromSectorPtr ) {
  126. moveLines++;
  127. }
  128. }
  129. // add these lines to intoSector
  130. // Unfortunately, the sector->lines list is not allocated per-sector, but
  131. // is a single block for the entire level, so we can't realloc it. I'm
  132. // going to just let the new table leak.
  133. line_t **newLines = Z_Malloc( ( intoSectorPtr->linecount + moveLines ) * sizeof( *intoSectorPtr->lines ),
  134. PU_LEVEL,0);
  135. memcpy( newLines, intoSectorPtr->lines, intoSectorPtr->linecount * sizeof( *newLines ) );
  136. intoSectorPtr->lines = newLines;
  137. for ( int i = 0 ; i < numlines ; i++ ) {
  138. if ( lines[i].frontsector == fromSectorPtr ) {
  139. intoSectorPtr->lines[intoSectorPtr->linecount++] = &lines[i];
  140. lines[i].frontsector = intoSectorPtr;
  141. } else if ( lines[i].backsector == fromSectorPtr ) {
  142. intoSectorPtr->lines[intoSectorPtr->linecount++] = &lines[i];
  143. lines[i].backsector = intoSectorPtr;
  144. }
  145. }
  146. // change all the segs
  147. for ( int i = 0 ; i < numsegs ; i++ ) {
  148. if ( segs[i].frontsector == fromSectorPtr ) {
  149. segs[i].frontsector = intoSectorPtr;
  150. }
  151. if ( segs[i].backsector == fromSectorPtr ) {
  152. segs[i].backsector = intoSectorPtr;
  153. }
  154. }
  155. // change all the sides to point to the new one
  156. for ( int i = 0 ; i < numsides ; i++ ) {
  157. if ( sides[i].sector == fromSectorPtr ) {
  158. sides[i].sector = intoSectorPtr;
  159. }
  160. }
  161. // change all the subsectors to point to the new one
  162. for ( int i = 0 ; i < numsubsectors ; i++ ) {
  163. if ( subsectors[i].sector == fromSectorPtr ) {
  164. subsectors[i].sector = intoSectorPtr;
  165. }
  166. }
  167. // make fromSector vestigial so it doesn't get tesselated
  168. fromSectorPtr->linecount = 0;
  169. }
  170. void IR_InitLevel() {
  171. BuildIndexedTriangles(); // convert the loops into indexed triangles
  172. BuildSideSegs(); // create a seg_t for each side_t so we can draw the
  173. // unclipped versions that fit perfectly with the sectors
  174. // find something else used in the level for a default texture
  175. for ( int i = 0 ; i < numsides ; i++ ) {
  176. if ( sides[i].toptexture ) {
  177. defaultTexture=gld_RegisterTexture(sides[i].toptexture, true, false);
  178. if ( defaultTexture ) {
  179. break;
  180. }
  181. }
  182. }
  183. assert( defaultTexture );
  184. }
  185. float lightDistance = 10.0f; // in prBoom MAP_SCALE units, increasing this makes things get dimmer faster
  186. #define MAX_LIGHT_DROP 96
  187. float lightingVector[3]; // transform and scale [ x y 1 ] to get color units to subtract
  188. static int FadedLighting( float x, float y, int sectorLightLevel ) {
  189. // Ramp down the lightover lightDistance world units.
  190. // Triangles that extend across behind the view origin and past
  191. // the lightDistance clamping boundary will not have completely linear fading,
  192. // but nobody should notice.
  193. // A proportional drop in lighting sounds like a better idea, but
  194. // this linear drop seems to look nicer. It's not like Doom's
  195. // lighting is realistic in any case...
  196. int idist = x * lightingVector[0] + y * lightingVector[1] + lightingVector[2];
  197. if ( idist < 0 ) {
  198. idist = 0;
  199. } else if ( idist > MAX_LIGHT_DROP ) {
  200. idist = MAX_LIGHT_DROP;
  201. }
  202. sectorLightLevel -= idist;
  203. if ( sectorLightLevel < 0 ) {
  204. sectorLightLevel = 0;
  205. }
  206. if ( sectorLightLevel > 255 ) {
  207. sectorLightLevel = 255;
  208. }
  209. return sectorLightLevel | (sectorLightLevel<<8) | (sectorLightLevel<<16) | (255<<24);
  210. }
  211. //
  212. // IR_ProjectSprite
  213. // Generates a vissprite for a thing if it might be visible.
  214. //
  215. static void IR_ProjectSprite (mobj_t* thing, int lightlevel)
  216. {
  217. fixed_t gzt; // killough 3/27/98
  218. fixed_t tx;
  219. fixed_t xscale;
  220. int x1;
  221. int x2;
  222. spritedef_t *sprdef;
  223. spriteframe_t *sprframe;
  224. int lump;
  225. boolean flip;
  226. // transform the origin point
  227. fixed_t tr_x, tr_y;
  228. fixed_t fx, fy, fz;
  229. fixed_t gxt, gyt;
  230. fixed_t tz;
  231. int width;
  232. fx = thing->x;
  233. fy = thing->y;
  234. fz = thing->z;
  235. tr_x = fx - viewx;
  236. tr_y = fy - viewy;
  237. gxt = FixedMul(tr_x,viewcos);
  238. gyt = -FixedMul(tr_y,viewsin);
  239. tz = gxt-gyt;
  240. // thing is behind view plane?
  241. if (tz < MINZ)
  242. return;
  243. xscale = FixedDiv(projection, tz);
  244. gxt = -FixedMul(tr_x,viewsin);
  245. gyt = FixedMul(tr_y,viewcos);
  246. tx = -(gyt+gxt);
  247. // too far off the side?
  248. if (D_abs(tx)>(tz<<2))
  249. return;
  250. // decide which patch to use for sprite relative to player
  251. #ifdef RANGECHECK
  252. if ((unsigned) thing->sprite >= (unsigned)numsprites)
  253. I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite);
  254. #endif
  255. sprdef = &sprites[thing->sprite];
  256. #ifdef RANGECHECK
  257. if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
  258. I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite,
  259. thing->frame);
  260. #endif
  261. if (!sprdef->spriteframes)
  262. I_Error ("R_ProjectSprite: Missing spriteframes %i : %i", thing->sprite,
  263. thing->frame);
  264. sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
  265. if (sprframe->rotate)
  266. {
  267. // choose a different rotation based on player view
  268. // JDC: this could be better...
  269. angle_t ang = R_PointToAngle(fx, fy);
  270. unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
  271. lump = sprframe->lump[rot];
  272. flip = (boolean) sprframe->flip[rot];
  273. }
  274. else
  275. {
  276. // use single rotation for all views
  277. lump = sprframe->lump[0];
  278. flip = (boolean) sprframe->flip[0];
  279. }
  280. {
  281. const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
  282. /* calculate edges of the shape
  283. * cph 2003/08/1 - fraggle points out that this offset must be flipped
  284. * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */
  285. if (flip) {
  286. tx -= (patch->width - patch->leftoffset) << FRACBITS;
  287. } else {
  288. tx -= patch->leftoffset << FRACBITS;
  289. }
  290. x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS;
  291. tx += patch->width<<FRACBITS;
  292. x2 = ((centerxfrac + FixedMul (tx,xscale) ) >> FRACBITS) - 1;
  293. gzt = fz + (patch->topoffset << FRACBITS);
  294. width = patch->width;
  295. // JDC: we don't care if they never get freed,
  296. // so don't bother changing the zone tag status each time
  297. //R_UnlockPatchNum(lump+firstspritelump);
  298. }
  299. // off the side?
  300. if (x1 > viewwidth || x2 < 0)
  301. return;
  302. // killough 4/9/98: clip things which are out of view due to height
  303. // e6y: fix of hanging decoration disappearing in Batman Doom MAP02
  304. // centeryfrac -> viewheightfrac
  305. if (fz > viewz + FixedDiv(viewheightfrac, xscale) ||
  306. gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale))
  307. return;
  308. // JDC: clip to the occlusio buffer
  309. int testLow = x1 < 0 ? 0 : x1;
  310. int testHigh = x2 >= viewwidth ? viewwidth - 1 : x2;
  311. //if ( reversedLandscape ) {
  312. // testLow = viewwidth-1-testLow;
  313. // testHigh = viewwidth-1-testHigh;
  314. //}
  315. if ( !memchr( occlusion+testLow, 0, testHigh - testLow ) ) {
  316. c_occludedSprites++;
  317. return;
  318. }
  319. // ------------ gld_AddSprite ----------
  320. mobj_t *pSpr= thing;
  321. GLSprite sprite;
  322. float voff,hoff;
  323. sprite.scale= FixedDiv(projectiony, tz);
  324. if (pSpr->frame & FF_FULLBRIGHT)
  325. sprite.light = 255;
  326. else
  327. sprite.light = pSpr->subsector->sector->lightlevel+(extralight<<5);
  328. sprite.cm=CR_LIMIT+(int)((pSpr->flags & MF_TRANSLATION) >> (MF_TRANSSHIFT));
  329. sprite.gltexture=gld_RegisterPatch(lump+firstspritelump,sprite.cm);
  330. if (!sprite.gltexture)
  331. return;
  332. sprite.shadow = (pSpr->flags & MF_SHADOW) != 0;
  333. sprite.trans = (pSpr->flags & MF_TRANSLUCENT) != 0;
  334. if (movement_smooth)
  335. {
  336. sprite.x = (float)(-pSpr->PrevX + FixedMul (tic_vars.frac, -pSpr->x - (-pSpr->PrevX)))/MAP_SCALE;
  337. sprite.y = (float)(pSpr->PrevZ + FixedMul (tic_vars.frac, pSpr->z - pSpr->PrevZ))/MAP_SCALE;
  338. sprite.z = (float)(pSpr->PrevY + FixedMul (tic_vars.frac, pSpr->y - pSpr->PrevY))/MAP_SCALE;
  339. }
  340. else
  341. {
  342. sprite.x=-(float)pSpr->x/MAP_SCALE;
  343. sprite.y= (float)pSpr->z/MAP_SCALE;
  344. sprite.z= (float)pSpr->y/MAP_SCALE;
  345. }
  346. sprite.vt=0.0f;
  347. sprite.vb=(float)sprite.gltexture->height/(float)sprite.gltexture->tex_height;
  348. if (flip)
  349. {
  350. sprite.ul=0.0f;
  351. sprite.ur=(float)sprite.gltexture->width/(float)sprite.gltexture->tex_width;
  352. }
  353. else
  354. {
  355. sprite.ul=(float)sprite.gltexture->width/(float)sprite.gltexture->tex_width;
  356. sprite.ur=0.0f;
  357. }
  358. hoff=(float)sprite.gltexture->leftoffset/(float)(MAP_COEFF);
  359. voff=(float)sprite.gltexture->topoffset/(float)(MAP_COEFF);
  360. sprite.x1=hoff-((float)sprite.gltexture->realtexwidth/(float)(MAP_COEFF));
  361. sprite.x2=hoff;
  362. sprite.y1=voff;
  363. sprite.y2=voff-((float)sprite.gltexture->realtexheight/(float)(MAP_COEFF));
  364. // JDC: don't let sprites poke below the ground level.
  365. // Software rendering Doom didn't use depth buffering,
  366. // so sprites always got drawn on top of the flat they
  367. // were on, but in GL they tend to get a couple pixel
  368. // rows clipped off.
  369. if ( sprite.y2 < 0 ) {
  370. sprite.y1 -= sprite.y2;
  371. sprite.y2 = 0;
  372. }
  373. if (gld_drawinfo.num_sprites>=gld_drawinfo.max_sprites)
  374. {
  375. gld_drawinfo.max_sprites+=128;
  376. gld_drawinfo.sprites=Z_Realloc(gld_drawinfo.sprites,gld_drawinfo.max_sprites*sizeof(GLSprite),PU_LEVEL,0);
  377. }
  378. gld_drawinfo.sprites[gld_drawinfo.num_sprites++]=sprite;
  379. }
  380. // JDC: removed the 0.001f epsilons that were presumably added
  381. // to try to hide T-junction cracks, but now that we are drawing
  382. // source lines instead of clipped segs, it is a non-problem.
  383. #define LINE seg->linedef
  384. #define CALC_Y_VALUES(w, lineheight, floor_height, ceiling_height)\
  385. (w).ytop=((float)(ceiling_height)/(float)MAP_SCALE);\
  386. (w).ybottom=((float)(floor_height)/(float)MAP_SCALE);\
  387. lineheight=((float)fabs(((ceiling_height)/(float)FRACUNIT)-((floor_height)/(float)FRACUNIT)))
  388. #define OU(w,seg) (((float)((seg)->sidedef->textureoffset+(seg)->offset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_width)
  389. #define OV(w,seg) (((float)((seg)->sidedef->rowoffset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_height)
  390. #define OV_PEG(w,seg,v_offset) (OV((w),(seg))-(((float)(v_offset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_height))
  391. #define CALC_TEX_VALUES_TOP(w, seg, peg, linelength, lineheight)\
  392. (w).flag=GLDWF_TOP;\
  393. (w).ul=OU((w),(seg))+(0.0f);\
  394. (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\
  395. (peg)?\
  396. (\
  397. (w).vb=OV((w),(seg))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\
  398. (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\
  399. ):(\
  400. (w).vt=OV((w),(seg))+(0.0f),\
  401. (w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\
  402. )
  403. #define CALC_TEX_VALUES_MIDDLE1S(w, seg, peg, linelength, lineheight)\
  404. (w).flag=GLDWF_M1S;\
  405. (w).ul=OU((w),(seg))+(0.0f);\
  406. (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\
  407. (peg)?\
  408. (\
  409. (w).vb=OV((w),(seg))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\
  410. (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\
  411. ):(\
  412. (w).vt=OV((w),(seg))+(0.0f),\
  413. (w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\
  414. )
  415. #define CALC_TEX_VALUES_MIDDLE2S(w, seg, peg, linelength, lineheight)\
  416. (w).flag=GLDWF_M2S;\
  417. (w).ul=OU((w),(seg))+(0.0f);\
  418. (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\
  419. (peg)?\
  420. (\
  421. (w).vb=((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\
  422. (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\
  423. ):(\
  424. (w).vt=(0.0f),\
  425. (w).vb=((float)(lineheight)/(float)(w).gltexture->buffer_height)\
  426. )
  427. #define CALC_TEX_VALUES_BOTTOM(w, seg, peg, linelength, lineheight, v_offset)\
  428. (w).flag=GLDWF_BOT;\
  429. (w).ul=OU((w),(seg))+(0.0f);\
  430. (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->realtexwidth);\
  431. (peg)?\
  432. (\
  433. (w).vb=OV_PEG((w),(seg),(v_offset))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\
  434. (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\
  435. ):(\
  436. (w).vt=OV((w),(seg))+(0.0f),\
  437. (w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\
  438. )
  439. // e6y
  440. // Sky textures with a zero index should be forced
  441. // See third episode of requiem.wad
  442. #define SKYTEXTURE_PRBOOM(sky1,sky2)\
  443. if ((sky1) & PL_SKYFLAT)\
  444. {\
  445. const line_t *l = &lines[sky1 & ~PL_SKYFLAT];\
  446. const side_t *s = *l->sidenum + sides;\
  447. wall.gltexture=gld_RegisterTexture(texturetranslation[s->toptexture], false, texturetranslation[s->toptexture]==skytexture);\
  448. wall.skyyaw=-2.0f*((-(float)((viewangle+s->textureoffset)>>ANGLETOFINESHIFT)*360.0f/FINEANGLES)/90.0f);\
  449. wall.skyymid = 200.0f/319.5f*(((float)s->rowoffset/(float)FRACUNIT - 28.0f)/100.0f);\
  450. wall.flag = l->special==272 ? GLDWF_SKY : GLDWF_SKYFLIP;\
  451. }\
  452. else\
  453. if ((sky2) & PL_SKYFLAT)\
  454. {\
  455. const line_t *l = &lines[sky2 & ~PL_SKYFLAT];\
  456. const side_t *s = *l->sidenum + sides;\
  457. wall.gltexture=gld_RegisterTexture(texturetranslation[s->toptexture], false, texturetranslation[s->toptexture]==skytexture);\
  458. wall.skyyaw=-2.0f*((-(float)((viewangle+s->textureoffset)>>ANGLETOFINESHIFT)*360.0f/FINEANGLES)/90.0f);\
  459. wall.skyymid = 200.0f/319.5f*(((float)s->rowoffset/(float)FRACUNIT - 28.0f)/100.0f);\
  460. wall.flag = l->special==272 ? GLDWF_SKY : GLDWF_SKYFLIP;\
  461. }\
  462. else\
  463. {\
  464. wall.gltexture=gld_RegisterTexture(skytexture, false, true);\
  465. wall.skyyaw=-2.0f*((yaw+90.0f)/90.0f);\
  466. wall.skyymid = 200.0f/319.5f*((100.0f)/100.0f);\
  467. wall.flag = GLDWF_SKY;\
  468. };
  469. #define SKYTEXTURE(sky1,sky2)\
  470. wall.gltexture=NULL;\
  471. wall.flag = GLDWF_SKY;
  472. #define ADDWALL(wall)\
  473. {\
  474. if (gld_drawinfo.num_walls>=gld_drawinfo.max_walls)\
  475. {\
  476. gld_drawinfo.max_walls+=128;\
  477. gld_drawinfo.walls=Z_Realloc(gld_drawinfo.walls,gld_drawinfo.max_walls*sizeof(GLWall),PU_LEVEL,0);\
  478. }\
  479. gld_drawinfo.walls[gld_drawinfo.num_walls++]=*wall;\
  480. };
  481. extern GLSeg *gl_segs;
  482. extern byte rendermarker;
  483. extern byte *segrendered;
  484. extern int tran_filter_pct;
  485. void IR_AddWall(seg_t *seg)
  486. {
  487. GLWall wall;
  488. GLTexture *temptex;
  489. sector_t *thefrontsector;
  490. sector_t *thebacksector;
  491. sector_t ftempsec; // needed for R_FakeFlat
  492. sector_t btempsec; // needed for R_FakeFlat
  493. float lineheight;
  494. int rellight = 0;
  495. wall.glseg=NULL;
  496. wall.side = seg->sidedef;
  497. thefrontsector=R_FakeFlat(seg->frontsector, &ftempsec, NULL, NULL, false); // for boom effects
  498. if (!thefrontsector)
  499. return;
  500. // JDC: improve this lighting tweak
  501. rellight = seg->linedef->dx==0? +8 : seg->linedef->dy==0 ? -8 : 0;
  502. int light = thefrontsector->lightlevel+rellight+(extralight<<5);
  503. wall.light = MAX(MIN((light),255),0);
  504. wall.alpha=1.0f;
  505. wall.gltexture=NULL;
  506. if (!seg->backsector) /* onesided */
  507. {
  508. #ifdef SKYWALLS
  509. if (thefrontsector->ceilingpic==skyflatnum)
  510. {
  511. wall.ytop=255.0f;
  512. wall.ybottom=(float)thefrontsector->ceilingheight/MAP_SCALE;
  513. SKYTEXTURE(thefrontsector->sky,thefrontsector->sky);
  514. ADDWALL(&wall);
  515. }
  516. if (thefrontsector->floorpic==skyflatnum)
  517. {
  518. wall.ytop=(float)thefrontsector->floorheight/MAP_SCALE;
  519. wall.ybottom=-255.0f;
  520. SKYTEXTURE(thefrontsector->sky,thefrontsector->sky);
  521. ADDWALL(&wall);
  522. }
  523. #endif
  524. temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->midtexture], true, false);
  525. if (temptex)
  526. {
  527. wall.gltexture=temptex;
  528. CALC_Y_VALUES(wall, lineheight, thefrontsector->floorheight, thefrontsector->ceilingheight);
  529. CALC_TEX_VALUES_MIDDLE1S(
  530. wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0,
  531. seg->length, lineheight
  532. );
  533. ADDWALL(&wall);
  534. }
  535. }
  536. else /* twosided */
  537. {
  538. int floor_height,ceiling_height;
  539. thebacksector=R_FakeFlat(seg->backsector, &btempsec, NULL, NULL, true); // for boom effects
  540. if(!thebacksector)
  541. return;
  542. /* toptexture */
  543. ceiling_height=thefrontsector->ceilingheight;
  544. floor_height=thebacksector->ceilingheight;
  545. #ifdef SKYWALLS
  546. if (thefrontsector->ceilingpic==skyflatnum)
  547. {
  548. wall.ytop=255.0f;
  549. if (
  550. // e6y
  551. // Fix for HOM in the starting area on Memento Mori map29 and on map30.
  552. // old code: (thebacksector->ceilingheight==thebacksector->floorheight) &&
  553. (thebacksector->ceilingheight==thebacksector->floorheight||(thebacksector->ceilingheight<=thefrontsector->floorheight)) &&
  554. (thebacksector->ceilingpic==skyflatnum)
  555. )
  556. {
  557. wall.ybottom=(float)thebacksector->floorheight/MAP_SCALE;
  558. SKYTEXTURE(thefrontsector->sky,thebacksector->sky);
  559. ADDWALL(&wall);
  560. }
  561. else
  562. {
  563. if ( (texturetranslation[seg->sidedef->toptexture]!=NO_TEXTURE) )
  564. {
  565. // e6y
  566. // It corrects some problem with sky, but I do not remember which one
  567. // old code: wall.ybottom=(float)thefrontsector->ceilingheight/MAP_SCALE;
  568. wall.ybottom=(float)MAX(thefrontsector->ceilingheight,thebacksector->ceilingheight)/MAP_SCALE;
  569. SKYTEXTURE(thefrontsector->sky,thebacksector->sky);
  570. ADDWALL(&wall);
  571. }
  572. else
  573. if ( (thebacksector->ceilingheight <= thefrontsector->floorheight) ||
  574. (thebacksector->ceilingpic != skyflatnum) )
  575. {
  576. wall.ybottom=(float)thebacksector->ceilingheight/MAP_SCALE;
  577. SKYTEXTURE(thefrontsector->sky,thebacksector->sky);
  578. ADDWALL(&wall);
  579. }
  580. }
  581. }
  582. #endif
  583. if (floor_height<ceiling_height)
  584. {
  585. if (!((thefrontsector->ceilingpic==skyflatnum) && (thebacksector->ceilingpic==skyflatnum)))
  586. {
  587. temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->toptexture], true, false);
  588. if ( !temptex ) {
  589. temptex = defaultTexture; // it seems some line segments have bad data...
  590. }
  591. wall.gltexture=temptex;
  592. CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height);
  593. CALC_TEX_VALUES_TOP(
  594. wall, seg, (LINE->flags & (ML_DONTPEGBOTTOM | ML_DONTPEGTOP))==0,
  595. seg->length, lineheight
  596. );
  597. ADDWALL(&wall);
  598. }
  599. }
  600. /* midtexture */
  601. //e6y
  602. if (comp[comp_maskedanim])
  603. temptex=gld_RegisterTexture(seg->sidedef->midtexture, true, false);
  604. else
  605. // e6y
  606. // Animated middle textures with a zero index should be forced
  607. // See spacelab.wad (http://www.doomworld.com/idgames/index.php?id=6826)
  608. temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->midtexture], true, true);
  609. if (temptex && seg->sidedef->midtexture != NO_TEXTURE)
  610. {
  611. wall.gltexture=temptex;
  612. if ( (LINE->flags & ML_DONTPEGBOTTOM) >0)
  613. {
  614. if (seg->backsector->ceilingheight<=seg->frontsector->floorheight)
  615. goto bottomtexture;
  616. floor_height=MAX(seg->frontsector->floorheight,seg->backsector->floorheight)+(seg->sidedef->rowoffset);
  617. ceiling_height=floor_height+(wall.gltexture->realtexheight<<FRACBITS);
  618. }
  619. else
  620. {
  621. if (seg->backsector->ceilingheight<=seg->frontsector->floorheight)
  622. goto bottomtexture;
  623. ceiling_height=MIN(seg->frontsector->ceilingheight,seg->backsector->ceilingheight)+(seg->sidedef->rowoffset);
  624. floor_height=ceiling_height-(wall.gltexture->realtexheight<<FRACBITS);
  625. }
  626. // e6y
  627. // The fix for wrong middle texture drawing
  628. // if it exceeds the boundaries of its floor and ceiling
  629. /*CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height);
  630. CALC_TEX_VALUES_MIDDLE2S(
  631. wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0,
  632. segs[seg->iSegID].length, lineheight
  633. );*/
  634. {
  635. int floormax, ceilingmin, linelen;
  636. float mip;
  637. mip = (float)wall.gltexture->realtexheight/(float)wall.gltexture->buffer_height;
  638. // if ( (texturetranslation[seg->sidedef->bottomtexture]!=R_TextureNumForName("-")) )
  639. if (seg->sidedef->bottomtexture)
  640. floormax=MAX(seg->frontsector->floorheight,seg->backsector->floorheight);
  641. else
  642. floormax=floor_height;
  643. if (seg->sidedef->toptexture)
  644. ceilingmin=MIN(seg->frontsector->ceilingheight,seg->backsector->ceilingheight);
  645. else
  646. ceilingmin=ceiling_height;
  647. linelen=abs(ceiling_height-floor_height);
  648. wall.ytop=((float)MIN(ceilingmin, ceiling_height)/(float)MAP_SCALE);
  649. wall.ybottom=((float)MAX(floormax, floor_height)/(float)MAP_SCALE);
  650. wall.flag=GLDWF_M2S;
  651. wall.ul=OU((wall),(seg))+(0.0f);
  652. wall.ur=OU(wall,(seg))+((seg->length)/(float)wall.gltexture->buffer_width);
  653. if (floormax<=floor_height)
  654. wall.vb=mip*1.0f;
  655. else
  656. wall.vb=mip*((float)(ceiling_height - floormax))/linelen;
  657. if (ceilingmin>=ceiling_height)
  658. wall.vt=0.0f;
  659. else
  660. wall.vt=mip*((float)(ceiling_height - ceilingmin))/linelen;
  661. }
  662. if (seg->linedef->tranlump >= 0 && general_translucency)
  663. wall.alpha=(float)tran_filter_pct/100.0f;
  664. wall.alpha=1.0f;
  665. ADDWALL(&wall);
  666. }
  667. bottomtexture:
  668. /* bottomtexture */
  669. ceiling_height=thebacksector->floorheight;
  670. floor_height=thefrontsector->floorheight;
  671. #ifdef SKYWALLS
  672. if (thefrontsector->floorpic==skyflatnum)
  673. {
  674. wall.ybottom=-255.0f;
  675. if (
  676. (thebacksector->ceilingheight==thebacksector->floorheight) &&
  677. (thebacksector->floorpic==skyflatnum)
  678. )
  679. {
  680. wall.ytop=(float)thebacksector->floorheight/MAP_SCALE;
  681. SKYTEXTURE(thefrontsector->sky,thebacksector->sky);
  682. ADDWALL(&wall);
  683. }
  684. else
  685. {
  686. if ( (texturetranslation[seg->sidedef->bottomtexture]!=NO_TEXTURE) )
  687. {
  688. wall.ytop=(float)thefrontsector->floorheight/MAP_SCALE;
  689. SKYTEXTURE(thefrontsector->sky,thebacksector->sky);
  690. ADDWALL(&wall);
  691. }
  692. else
  693. if ( (thebacksector->floorheight >= thefrontsector->ceilingheight) ||
  694. (thebacksector->floorpic != skyflatnum) )
  695. {
  696. wall.ytop=(float)thebacksector->floorheight/MAP_SCALE;
  697. SKYTEXTURE(thefrontsector->sky,thebacksector->sky);
  698. ADDWALL(&wall);
  699. }
  700. }
  701. }
  702. #endif
  703. if (floor_height<ceiling_height)
  704. {
  705. temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->bottomtexture], true, false);
  706. if ( !temptex ) {
  707. temptex = defaultTexture; // it seems some line segments have bad data...
  708. }
  709. wall.gltexture=temptex;
  710. CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height);
  711. CALC_TEX_VALUES_BOTTOM(
  712. wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0,
  713. seg->length, lineheight,
  714. floor_height-thefrontsector->ceilingheight
  715. );
  716. ADDWALL(&wall);
  717. }
  718. }
  719. }
  720. #undef LINE
  721. #undef CALC_Y_VALUES
  722. #undef OU
  723. #undef OV
  724. #undef OV_PEG
  725. #undef CALC_TEX_VALUES_TOP
  726. #undef CALC_TEX_VALUES_MIDDLE1S
  727. #undef CALC_TEX_VALUES_MIDDLE2S
  728. #undef CALC_TEX_VALUES_BOTTOM
  729. #undef SKYTEXTURE
  730. #undef ADDWALL
  731. /*
  732. TransformAndClipSegment
  733. Converts a world coordinate line segment to screen space.
  734. Returns false if the segment is off screen.
  735. There would be some savings if all the points in a subsector
  736. were transformed and clip tested as a unit, instead of as discrete segments.
  737. */
  738. boolean TransformAndClipSegment( float v[2][2], float ends[2] ) {
  739. float clip[2][4];
  740. // if we are in iphone reverse-landscape mode, we need
  741. // to flip the coordinates around
  742. float *v0, *v1;
  743. //if ( reversedLandscape ) {
  744. // v0 = v[1];
  745. // v1 = v[0];
  746. //} else {
  747. v0 = v[0];
  748. v1 = v[1];
  749. //}
  750. // transform from model to clip space
  751. // because the iPhone screen hardware is portrait mode,
  752. // we need to look at the Y axis for the segment ends,
  753. // not the X axis.
  754. clip[0][1] = v0[0] * glMVPmatrix[1] + v0[1] * glMVPmatrix[2*4+1] + glMVPmatrix[3*4+1];
  755. clip[0][3] = v0[0] * glMVPmatrix[3] + v0[1] * glMVPmatrix[2*4+3] + glMVPmatrix[3*4+3];
  756. clip[1][1] = v1[0] * glMVPmatrix[1] + v1[1] * glMVPmatrix[2*4+1] + glMVPmatrix[3*4+1];
  757. clip[1][3] = v1[0] * glMVPmatrix[3] + v1[1] * glMVPmatrix[2*4+3] + glMVPmatrix[3*4+3];
  758. float d0, d1;
  759. // clip to the near plane
  760. float nearClip = 0.01f;
  761. d0 = clip[0][3] - nearClip;
  762. d1 = clip[1][3] - nearClip;
  763. if ( d0 < 0 && d1 < 0 ) {
  764. // near clipped
  765. return false;
  766. }
  767. if ( d0 < 0 ) {
  768. float f = d0 / ( d0 - d1 );
  769. clip[0][1] = clip[0][1] + f * ( clip[1][1] - clip[0][1] );
  770. clip[0][3] = nearClip;
  771. } else if ( d1 < 0 ) {
  772. float f = d1 / ( d1 - d0 );
  773. clip[1][1] = clip[1][1] + f * ( clip[0][1] - clip[1][1] );
  774. clip[1][3] = nearClip;
  775. }
  776. if ( clip[0][1] > clip[0][3] ) {
  777. // entire segment is off the right side of the screen
  778. return false;
  779. }
  780. if ( clip[1][1] < -clip[1][3] ) {
  781. // entire segment is off the left side of the screen
  782. return false;
  783. }
  784. // project
  785. for ( int i = 0 ; i < 2 ; i++ ) {
  786. float x = viewwidth * ( ( clip[i][1] / clip[i][3] ) * 0.5f + 0.5f );
  787. if ( x < 0 ) {
  788. x = 0;
  789. } else if ( x > viewwidth ) {
  790. x = viewwidth;
  791. }
  792. ends[i] = x;
  793. }
  794. // part of the segment is on screen
  795. return true;
  796. }
  797. /*
  798. IR_Subsector
  799. All possible culling should be performed here, but most calculations should be
  800. deferred until draw time, rather than storing intermediate values that are
  801. later referenced.
  802. Don't make this static, or the compiler inlines it in the recursive node
  803. function, which bloats the stack.
  804. */
  805. void IR_Subsector(int num)
  806. {
  807. subsector_t *sub = &subsectors[num];
  808. c_subsectors++;
  809. // at this point we know that at least part of the subsector is
  810. // not covered in the occlusion array
  811. // if the sector that this subsector is a part of has not already had its
  812. // planes and sprites added, add them now.
  813. sector_t *thefrontsector = sub->sector;
  814. int lightlevel = thefrontsector->lightlevel+(extralight<<5);
  815. // There can be several subsectors in each sector due to non-convex
  816. // sectors or BSP splits, but we draw the floors, ceilings and lines
  817. // with a single draw call for the entire thing, so ensure that they
  818. // are only added once per frame.
  819. if ( thefrontsector->validcount != validcount ) {
  820. thefrontsector->validcount = validcount;
  821. c_sectors++;
  822. GLFlat flat;
  823. flat.sectornum = thefrontsector->iSectorID;
  824. flat.light = lightlevel;
  825. flat.uoffs= 0; // no support in standard doom
  826. flat.voffs= 0;
  827. if ( thefrontsector->floorheight < viewz ) {
  828. if (thefrontsector->floorpic == skyflatnum) {
  829. skyIsVisible = true;
  830. } else {
  831. // get the texture. flattranslation is maintained by doom and
  832. // contains the number of the current animation frame
  833. GLTexture *tex = gld_RegisterFlat(flattranslation[thefrontsector->floorpic], true);
  834. if ( tex ) {
  835. sectorPlanes[numSectorPlanes].texture = tex;
  836. sectorPlanes[numSectorPlanes].ceiling = false;
  837. sectorPlanes[numSectorPlanes].sector = thefrontsector;
  838. numSectorPlanes++;
  839. }
  840. }
  841. }
  842. if ( thefrontsector->ceilingheight > viewz ) {
  843. if (thefrontsector->ceilingpic == skyflatnum) {
  844. skyIsVisible = true;
  845. } else {
  846. // get the texture. flattranslation is maintained by doom and
  847. // contains the number of the current animation frame
  848. GLTexture *tex = gld_RegisterFlat(flattranslation[thefrontsector->ceilingpic], true);
  849. if ( tex ) {
  850. sectorPlanes[numSectorPlanes].texture = tex;
  851. sectorPlanes[numSectorPlanes].ceiling = true;
  852. sectorPlanes[numSectorPlanes].sector = thefrontsector;
  853. numSectorPlanes++;
  854. }
  855. }
  856. }
  857. // Add all the sprites in this sector.
  858. // It would be better if they were linked into all the subsectors, because
  859. // we could do more accurate occlusion culling. With non-convex sectors,
  860. // occasionally a sprite will be added in a rear portion of the sector that
  861. // would have been occluded away if everything was done in BSP subsector order.
  862. for ( mobj_t *thing = thefrontsector->thinglist; thing; thing = thing->snext) {
  863. IR_ProjectSprite( thing, lightlevel );
  864. }
  865. }
  866. // If a segment in this subsector is not fully occluded, mark
  867. // the line that it is a part of as needing to be drawn. Because
  868. // we are using a depth buffer, we can draw complete line segments
  869. // instead of just segments.
  870. for ( int i = 0 ; i < sub->numlines ; i++ ) {
  871. seg_t *seg = &segs[sub->firstline+i];
  872. line_t *line = seg->linedef;
  873. // Determine if it will completely occlude farther objects.
  874. // Given that changing sector heights is much less common than
  875. // traversing lines during every render, it would be marginally better if
  876. // lines had an "occluder" flag on them that was updated as sectors
  877. // moved, but it hardly matters.
  878. boolean occluder;
  879. if ( seg->backsector == NULL ||
  880. seg->backsector->floorheight >= seg->backsector->ceilingheight ||
  881. seg->backsector->floorheight >= seg->frontsector->ceilingheight ||
  882. seg->backsector->ceilingheight <= seg->frontsector->floorheight ) {
  883. // this segment can't be seen past, so fill in the occlusion table
  884. occluder = true;
  885. } else {
  886. // If the line has already been made visible and we don't need to
  887. // update the occlusion buffer, we don't need to do anything else here.
  888. // This happens when a line is split into multiple segs, and also
  889. // when the line is reached from the backsector. In the backsector
  890. // case, it would be back-face culled, but this test throws it out
  891. // without having to transform and clip the ends.
  892. if ( line->validcount == validcount ) {
  893. continue;
  894. }
  895. // check to see if the seg won't draw any walls at all
  896. // we won't fill in the occlusion table for this
  897. occluder = false;
  898. }
  899. // transform and clip the two endpoints
  900. float v[2][2];
  901. float floatEnds[2];
  902. v[0][0] = -seg->v1->x/MAP_SCALE;
  903. v[0][1] = seg->v1->y/MAP_SCALE;
  904. v[1][0] = -seg->v2->x/MAP_SCALE;
  905. v[1][1] = seg->v2->y/MAP_SCALE;
  906. if ( !TransformAndClipSegment( v, floatEnds ) ) {
  907. // the line is off to the side or facing away
  908. continue;
  909. }
  910. // Allow segs that we consider to be slightly back
  911. // facing to still pass through, because GPU floating
  912. // point calculations may not see them exactly the same.
  913. if ( floatEnds[0] > floatEnds[1] + 1.0f ) {
  914. // back face
  915. continue;
  916. }
  917. // Check it against the occlusion buffer.
  918. // Because the perspective divide is not going to be bit-exact between
  919. // the CPU and GPU, we check an extra column here. That will result
  920. // in an occasional line being drawn that might not need to be, but
  921. // it avoids missing columns.
  922. int checkMin = floor( floatEnds[0] - 1 );
  923. int checkMax = ceil( floatEnds[1] + 1 );
  924. if ( checkMin < 0 ) {
  925. checkMin = 0;
  926. }
  927. if ( checkMax > viewwidth ) {
  928. checkMax = viewwidth;
  929. }
  930. if ( !memchr( occlusion + checkMin, 0, checkMax - checkMin ) ) {
  931. failCount++;
  932. // every column it would touch is already solid, so it isn't visible
  933. continue;
  934. }
  935. if ( occluder ) {
  936. // It is important to update the occlusion array as individual
  937. // segs are processed to maintain pure front to back order. If
  938. // the occlusion buffer was updated by complete lines, it would
  939. // result in some elements being incorrectly occlusion culled.
  940. // Use a consistant fill rule for the occlusion, which is only
  941. // referenced by the CPU, and should be water tight.
  942. int fillMin = (int) (floatEnds[0]+0.5);
  943. int fillMax = (int) (floatEnds[1]+0.5);
  944. if ( fillMax > fillMin ) {
  945. memset( occlusion + fillMin, 1, fillMax-fillMin );
  946. }
  947. }
  948. if ( line->validcount == validcount ) {
  949. continue;
  950. }
  951. line->validcount = validcount;
  952. // this line can show up on the automap now
  953. line->flags |= ML_MAPPED;
  954. // Adding a line may generate up to four drawn walls -- a top wall,
  955. // a bottom wall, a perforated middle wall, and a sky wall.
  956. // Use the complete, unclipped segment for the side
  957. IR_AddWall( &seg->sidedef->sideSeg );
  958. }
  959. }
  960. PUREFUNC static int IR_PointOnSide(fixed_t x, fixed_t y, const node_t *node)
  961. {
  962. // JDC: these early tests probably aren't worth it on iphone...
  963. if (!node->dx)
  964. return x <= node->x ? node->dy > 0 : node->dy < 0;
  965. if (!node->dy)
  966. return y <= node->y ? node->dx < 0 : node->dx > 0;
  967. x -= node->x;
  968. y -= node->y;
  969. // Try to quickly decide by looking at sign bits.
  970. if ((node->dy ^ node->dx ^ x ^ y) < 0)
  971. return (node->dy ^ x) < 0; // (left is negative)
  972. return (__int64_t)y * (__int64_t)node->dx >= (__int64_t)x * (__int64_t)node->dy;
  973. }
  974. static const int checkcoord[12][4] = // killough -- static const
  975. {
  976. {3,0,2,1},
  977. {3,0,2,0},
  978. {3,1,2,0},
  979. {0},
  980. {2,0,2,1},
  981. {0,0,0,0},
  982. {3,1,3,0},
  983. {0},
  984. {2,0,3,1},
  985. {2,1,3,1},
  986. {2,1,3,0}
  987. };
  988. static boolean IR_IsBBoxCompletelyOccluded(const fixed_t *bspcoord) {
  989. // conservatively accept if close to the box, so
  990. // we don't need to worry about the near clip plane
  991. // in TrnasformAndClipSegment. Mapscale is 128*fracunit
  992. // and nearclip is 0.1, so accepting 2 fracunits away works.
  993. if ( viewx > bspcoord[BOXLEFT]-2*FRACUNIT && viewx < bspcoord[BOXRIGHT] + 2*FRACUNIT
  994. && viewy > bspcoord[BOXBOTTOM]-2*FRACUNIT && viewy < bspcoord[BOXTOP] + 2*FRACUNIT ) {
  995. return false;
  996. }
  997. // Find the corners of the box
  998. // that define the edges from current viewpoint.
  999. int boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) +
  1000. (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8);
  1001. const int *check = checkcoord[boxpos];
  1002. float v[2][2];
  1003. v[0][0] = -bspcoord[check[0]]/MAP_SCALE;
  1004. v[0][1] = bspcoord[check[1]]/MAP_SCALE;
  1005. v[1][0] = -bspcoord[check[2]]/MAP_SCALE;
  1006. v[1][1] = bspcoord[check[3]]/MAP_SCALE;
  1007. float ends[2];
  1008. if ( !TransformAndClipSegment( v, ends ) ) {
  1009. // the line is off to the side or facing away
  1010. return true;
  1011. }
  1012. if ( ends[0] >= ends[1] ) {
  1013. return true;
  1014. }
  1015. assert( ends[0] >= 0 );
  1016. assert( ends[1] <= viewwidth );
  1017. // Check it against the occlusion buffer, with an extra column
  1018. // of slop to account for GPU / CPU floating point differences.
  1019. if ( !memchr( occlusion + (int)ends[0], 0, (int)ends[1]-(int)ends[0]+1 ) ) {
  1020. // every column it would touch is already solid, so it isn't visible
  1021. return true;
  1022. }
  1023. // there are gaps, so we may need to draw something
  1024. return false;
  1025. }
  1026. /*
  1027. RenderBSPNode
  1028. Renders all subsectors below a given node,
  1029. traversing subtree recursively.
  1030. Because this function is recursive, avoid doing work that
  1031. would give a large stack frame. Important that the compiler
  1032. doesn't inline big functions.
  1033. */
  1034. static void IR_RenderBSPNode( int bspnum ) {
  1035. while (!(bspnum & NF_SUBSECTOR)) {
  1036. // decision node
  1037. const node_t *bsp = &nodes[bspnum];
  1038. // Decide which side the view point is on.
  1039. int side = IR_PointOnSide(viewx, viewy, bsp);
  1040. // check the front space
  1041. if ( !IR_IsBBoxCompletelyOccluded(bsp->bbox[side]) ) {
  1042. IR_RenderBSPNode( bsp->children[side] );
  1043. }
  1044. // continue down the back space
  1045. if ( IR_IsBBoxCompletelyOccluded( bsp->bbox[side^1]) ) {
  1046. return;
  1047. }
  1048. bspnum = bsp->children[side^1];
  1049. }
  1050. // subsector with contents
  1051. // add all the drawable elements in the subsector
  1052. if ( bspnum == -1 ) {
  1053. bspnum = 0;
  1054. }
  1055. bspnum &= ~NF_SUBSECTOR;
  1056. IR_Subsector( bspnum );
  1057. }
  1058. typedef struct {
  1059. void *texture;
  1060. void *user;
  1061. } texSort_t;
  1062. static int TexSort( const void *a, const void *b ) {
  1063. if ( ((texSort_t *)a)->texture < ((texSort_t *)b)->texture ) {
  1064. return -1;
  1065. }
  1066. return 1;
  1067. }
  1068. int SysIphoneMicroseconds();
  1069. void SetImmediateModeGLVertexArrays();
  1070. extern float yaw;
  1071. extern GLTexture **gld_GLTextures;
  1072. extern GLTexture **gld_GLPatchTextures;
  1073. extern GLVertex *gld_vertexes;
  1074. extern GLTexcoord *gld_texcoords;
  1075. #define MAX_DRAW_INDEXES 0x10000
  1076. unsigned short drawIndexes[MAX_DRAW_INDEXES];
  1077. int numDrawIndexes;
  1078. drawVert_t drawVerts[MAX_DRAW_VERTS];
  1079. int numDrawVerts;
  1080. void NewDrawScene(player_t *player) // JDC: new version
  1081. {
  1082. int i,k;
  1083. glDisable( GL_ALPHA_TEST );
  1084. glDisable(GL_CULL_FACE);
  1085. glDisable(GL_FOG);
  1086. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  1087. glEnableClientState(GL_VERTEX_ARRAY);
  1088. glDisableClientState(GL_COLOR_ARRAY);
  1089. // Use the 2x texture combiner mode to allow the game to be brightened up
  1090. // above the normal maximum. All calculated color values for lighting will
  1091. // be multiplied by a value ranging from 0.5 for original brightness, up to
  1092. // 1.0 for 2x brightness. This combine mode will be canceled after all
  1093. // the 3D and view weapon drawing is completed, so the hud elements are
  1094. // drawn at normal brightness.
  1095. glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
  1096. glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0 );
  1097. // opaque skies, flats, and walls write to the depth buffer and don't blend
  1098. glDisable( GL_BLEND );
  1099. glDepthMask( 1 );
  1100. // debug tool to check for things being drawn that shouldn't be
  1101. if ( blendAll ) {
  1102. glClearColor( 0, 0, 0, 0 );
  1103. glClear( GL_COLOR_BUFFER_BIT );
  1104. glEnable( GL_BLEND );
  1105. glDisable( GL_DEPTH_TEST );
  1106. glBlendFunc( GL_ONE, GL_ONE );
  1107. skyIsVisible = false;
  1108. }
  1109. // debug tool to look for pixel cracks
  1110. if ( testClear ) {
  1111. glClearColor( 1, 0, 0, 0 );
  1112. glClear( GL_COLOR_BUFFER_BIT );
  1113. skyIsVisible = false;
  1114. }
  1115. //-----------------------------------------
  1116. // draw the sky if needed
  1117. //-----------------------------------------
  1118. if ( skyIsVisible ) {
  1119. float s;
  1120. float y;
  1121. // Note that these texcoords would have to be corrected
  1122. // for different screen aspect ratios or fields of view!
  1123. s = ((yaw+90.0f)/90.0f);
  1124. y = 1 - 2 * 128.0 / 200;
  1125. // With identity matricies, the vertex coordinates
  1126. // can just be in the 0-1 range.
  1127. glMatrixMode( GL_MODELVIEW );
  1128. glPushMatrix();
  1129. glLoadIdentity();
  1130. glMatrixMode( GL_PROJECTION );
  1131. glPushMatrix();
  1132. glLoadIdentity();
  1133. gld_BindTexture( gld_RegisterTexture( skytexture, true, true ) );
  1134. glColor4f( 0.5, 0.5, 0.5, 1.0 ); // native texture color, not double bright
  1135. glBegin(GL_TRIANGLE_STRIP);
  1136. glTexCoord2f( s, 1 ); glVertex3f(-1,y,0.999);
  1137. glTexCoord2f( s, 0 ); glVertex3f(-1,1,0.999);
  1138. glTexCoord2f( s+1, 1 ); glVertex3f(1,y,0.999);
  1139. glTexCoord2f( s+1, 0 ); glVertex3f(1,1,0.999);
  1140. glEnd();
  1141. // back to the normal drawing matrix
  1142. glPopMatrix();
  1143. glMatrixMode( GL_MODELVIEW );
  1144. glPopMatrix();
  1145. }
  1146. // walls and flats use the drawVerts array for everything
  1147. glTexCoordPointer(2,GL_FLOAT,sizeof(drawVert_t),drawVerts[0].st);
  1148. glVertexPointer(3,GL_FLOAT,sizeof(drawVert_t),drawVerts[0].xyz);
  1149. glColorPointer(4,GL_UNSIGNED_BYTE,sizeof(drawVert_t),drawVerts[0].rgba);
  1150. // everything will draw at full brightness in this case
  1151. if (player->fixedcolormap) {
  1152. glColor4f(1.0f, 1.0f, 1.0f, 1.0f );
  1153. glDisableClientState(GL_COLOR_ARRAY);
  1154. } else {
  1155. glEnableClientState( GL_COLOR_ARRAY );
  1156. }
  1157. int c_drawElements = 0;
  1158. numDrawIndexes = 0;
  1159. //-----------------------------------------
  1160. // draw all the walls, sky walls sorted first
  1161. //-----------------------------------------
  1162. // sort the walls by texture
  1163. texSort_t *wallSort = alloca( sizeof( wallSort[0] ) * gld_drawinfo.num_walls );
  1164. for (i=0 ; i < gld_drawinfo.num_walls ; i++ ) {
  1165. GLWall *wall = &gld_drawinfo.walls[i];
  1166. wallSort[i].texture = wall->gltexture;
  1167. wallSort[i].user = wall;
  1168. }
  1169. qsort( wallSort, gld_drawinfo.num_walls, sizeof( wallSort[0] ), TexSort );
  1170. // continue building drawverts after the floor and ceiling data
  1171. int tempDrawVert = numDrawVerts;
  1172. // alpha tested walls will use half alpha to get the best edging effects
  1173. glAlphaFunc( GL_GREATER, 0.5 );
  1174. for (i=0 ; i < gld_drawinfo.num_walls ; i++ ) {
  1175. texSort_t *sort = &wallSort[i];
  1176. GLWall *wall = sort->user;
  1177. rendered_segs++;
  1178. // add two tris to draw the wall
  1179. drawIndexes[numDrawIndexes+0] = tempDrawVert;
  1180. drawIndexes[numDrawIndexes+1] = tempDrawVert+1;
  1181. drawIndexes[numDrawIndexes+2] = tempDrawVert+2;
  1182. drawIndexes[numDrawIndexes+3] = tempDrawVert+1;
  1183. drawIndexes[numDrawIndexes+4] = tempDrawVert+2;
  1184. drawIndexes[numDrawIndexes+5] = tempDrawVert+3;
  1185. numDrawIndexes += 6;
  1186. unsigned char rgba[4];
  1187. rgba[0] = rgba[1] = rgba[2] = wall->light;
  1188. rgba[3] = 255;
  1189. int lightInt = *(int *)rgba;
  1190. drawVerts[tempDrawVert].st[0] = wall->ul;
  1191. drawVerts[tempDrawVert].st[1] = wall->vt;
  1192. drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v1->x / MAP_SCALE;
  1193. drawVerts[tempDrawVert].xyz[1] = wall->ytop;
  1194. drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v1->y / MAP_SCALE;
  1195. lightInt = FadedLighting( drawVerts[tempDrawVert].xyz[0], drawVerts[tempDrawVert].xyz[2], wall->light );
  1196. *(int *)drawVerts[tempDrawVert].rgba = lightInt;
  1197. tempDrawVert++;
  1198. drawVerts[tempDrawVert].st[0] = wall->ul;
  1199. drawVerts[tempDrawVert].st[1] = wall->vb;
  1200. drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v1->x / MAP_SCALE;
  1201. drawVerts[tempDrawVert].xyz[1] = wall->ybottom;
  1202. drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v1->y / MAP_SCALE;
  1203. *(int *)drawVerts[tempDrawVert].rgba = lightInt;
  1204. tempDrawVert++;
  1205. drawVerts[tempDrawVert].st[0] = wall->ur;
  1206. drawVerts[tempDrawVert].st[1] = wall->vt;
  1207. drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v2->x / MAP_SCALE;
  1208. drawVerts[tempDrawVert].xyz[1] = wall->ytop;
  1209. drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v2->y / MAP_SCALE;
  1210. lightInt = FadedLighting( drawVerts[tempDrawVert].xyz[0], drawVerts[tempDrawVert].xyz[2], wall->light );
  1211. *(int *)drawVerts[tempDrawVert].rgba = lightInt;
  1212. tempDrawVert++;
  1213. drawVerts[tempDrawVert].st[0] = wall->ur;
  1214. drawVerts[tempDrawVert].st[1] = wall->vb;
  1215. drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v2->x / MAP_SCALE;
  1216. drawVerts[tempDrawVert].xyz[1] = wall->ybottom;
  1217. drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v2->y / MAP_SCALE;
  1218. *(int *)drawVerts[tempDrawVert].rgba = lightInt;
  1219. tempDrawVert++;
  1220. // only draw when textures change
  1221. if ( i == gld_drawinfo.num_walls-1 || sort->texture != (sort+1)->texture ) {
  1222. if ( numDrawIndexes ) {
  1223. if ( wall->flag == GLDWF_SKY ) {
  1224. // we aren't actually drawing anything with this,
  1225. // we are just masking off areas in the depth
  1226. // buffer so nothing can overwrite the already
  1227. // drawn sky image
  1228. glColorMask( 0, 0, 0, 0 );
  1229. }
  1230. if ( wall->flag == GLDWF_M2S ) {
  1231. glEnable( GL_ALPHA_TEST );
  1232. }
  1233. if ( wall->gltexture ) { // skies are texture = NULL
  1234. gld_BindTexture( wall->gltexture );
  1235. }
  1236. glDrawElements( GL_TRIANGLES, numDrawIndexes, GL_UNSIGNED_SHORT,
  1237. drawIndexes );
  1238. if ( wall->flag == GLDWF_M1S ) {
  1239. glDisable( GL_ALPHA_TEST );
  1240. }
  1241. if ( wall->flag == GLDWF_SKY ) {
  1242. glColorMask( 1, 1, 1, 1 );
  1243. }
  1244. numDrawIndexes = 0;
  1245. tempDrawVert = numDrawVerts;
  1246. c_drawElements++;
  1247. }
  1248. }
  1249. }
  1250. //-----------------------------------------
  1251. // draw all the flats
  1252. //
  1253. // If we were able to directly fill the GPU command buffers,
  1254. // we would be using multiple DrawArrays instead of a single DrawElements,
  1255. // and we would fill the plane height and color in as we copied vertexes
  1256. // from a single set of verts per sector, but because the driver validation
  1257. // overhead is the main poison on the iPhone currently, it is better to
  1258. // duplicate the windings for the floors and ceilings, patch the
  1259. // vertex data, and generate new index lists to minimize the number of
  1260. // draw calls.
  1261. //-----------------------------------------
  1262. // sort the flats by texture
  1263. qsort( sectorPlanes, numSectorPlanes, sizeof( sectorPlanes[0] ), TexSort );
  1264. // draw them in texture order
  1265. for (i=0 ; i < numSectorPlanes ; i++ ) {
  1266. sortSectorPlane_t *sort = &sectorPlanes[i];
  1267. sector_t *sector = sort->sector;
  1268. drawVert_t *dv = sector->verts[(int)sort->ceiling];
  1269. // Patch the height values if they have changed since the last draw.
  1270. float y = sort->ceiling ? sector->ceilingheight : sector->floorheight;
  1271. y *= ( 1.0 / MAP_SCALE );
  1272. if ( y != dv->xyz[1] ) {
  1273. for ( int j = 0 ; j < sector->numVerts ; j++ ) {
  1274. (dv+j)->xyz[1] = y;
  1275. }
  1276. }
  1277. // per-vertex faded light color
  1278. int light = sector->lightlevel + (extralight<<5);
  1279. if ( light > 255 ) {
  1280. light = 255;
  1281. }
  1282. for ( int j = 0 ; j < sector->numVerts ; j++ ) {
  1283. *(int *)(dv+j)->rgba = FadedLighting( (dv+j)->xyz[0], (dv+j)->xyz[2], light );
  1284. }
  1285. // copy the indexes
  1286. assert( numDrawIndexes + sector->numIndexes < MAX_DRAW_INDEXES );
  1287. memcpy( drawIndexes + numDrawIndexes, sector->indexes[(int)sort->ceiling], sector->numIndexes*sizeof(drawIndexes[0]) );
  1288. numDrawIndexes += sector->numIndexes;
  1289. // only change textures when necessary
  1290. if ( i == numSectorPlanes - 1 || sort->texture != (sort+1)->texture ) {
  1291. if ( numDrawIndexes ) {
  1292. gld_BindFlat( sort->texture );
  1293. glDrawElements( GL_TRIANGLES, numDrawIndexes, GL_UNSIGNED_SHORT,
  1294. drawIndexes );
  1295. numDrawIndexes = 0;
  1296. c_drawElements++;
  1297. }
  1298. }
  1299. }
  1300. glDisableClientState( GL_COLOR_ARRAY );
  1301. // back to our immediate mode vertex arrays
  1302. SetImmediateModeGLVertexArrays();
  1303. //-----------------------------------------
  1304. // draw all the sprites
  1305. //-----------------------------------------
  1306. // transparent sprites blend and don't write to the depth buffer
  1307. glEnable( GL_BLEND );
  1308. glDepthMask( 0 );
  1309. glEnable( GL_ALPHA_TEST );
  1310. // get the screen space vector for sprites
  1311. float yaws = -sin( yaw * 3.141592657 / 180.0 );
  1312. float yawc = -cos( yaw * 3.141592657 / 180.0 );
  1313. int c_spriteBind = 0;
  1314. int c_spriteDraw = 0;
  1315. while( 1 )
  1316. {
  1317. // pick out the sprites from farthest to nearest
  1318. fixed_t max_scale=INT_MAX;
  1319. k=-1;
  1320. for (i=0 ; i < gld_drawinfo.num_sprites ; i++ ) {
  1321. GLSprite *sprite = &gld_drawinfo.sprites[i];
  1322. if (sprite->scale<max_scale)
  1323. {
  1324. max_scale=sprite->scale;
  1325. k=i;
  1326. }
  1327. }
  1328. if ( k == -1 ) {
  1329. break;
  1330. }
  1331. GLSprite *sprite = &gld_drawinfo.sprites[k];
  1332. sprite->scale=INT_MAX;
  1333. if ( sprite->gltexture != last_gltexture ) {
  1334. c_spriteBind++;
  1335. }
  1336. c_spriteDraw++;
  1337. gld_BindPatch(sprite->gltexture,sprite->cm);
  1338. if(sprite->shadow)
  1339. {
  1340. glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
  1341. glColor4f(0.2f,0.2f,0.2f,0.33f);
  1342. glAlphaFunc( GL_GREATER, 0.1 ); // don't alpha test away the blended-down version
  1343. }
  1344. else
  1345. {
  1346. float flight = (float)sprite->light*(1.0f/255);
  1347. // We could do the distance-lighting here, but leaving the sprites
  1348. // brighter is a good accent in most cases. There are a few places
  1349. // where environmental sprites look a little wrong, but it is probably
  1350. // better in general.
  1351. if (player->fixedcolormap) {
  1352. flight = 1.0; // light amp goggles
  1353. }
  1354. glColor4f(flight, flight, flight, 1.0f );
  1355. }
  1356. glBegin(GL_TRIANGLE_STRIP);
  1357. glTexCoord2f(sprite->ul, sprite->vt);
  1358. glVertex3f(sprite->x + sprite->x1 * yawc, sprite->y + sprite->y1, sprite->z + sprite->x1 * yaws );
  1359. glTexCoord2f(sprite->ur, sprite->vt);
  1360. glVertex3f(sprite->x + sprite->x2 * yawc, sprite->y + sprite->y1, sprite->z + sprite->x2 * yaws );
  1361. glTexCoord2f(sprite->ul, sprite->vb);
  1362. glVertex3f(sprite->x + sprite->x1 * yawc, sprite->y + sprite->y2, sprite->z + sprite->x1 * yaws );
  1363. glTexCoord2f(sprite->ur, sprite->vb);
  1364. glVertex3f(sprite->x + sprite->x2 * yawc, sprite->y + sprite->y2, sprite->z + sprite->x2 * yaws );
  1365. glEnd();
  1366. if(sprite->shadow)
  1367. {
  1368. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1369. glAlphaFunc( GL_GREATER, 0.5 );
  1370. }
  1371. }
  1372. glDisable( GL_ALPHA_TEST );
  1373. glDepthMask( 1 );
  1374. }
  1375. static float roll = 0.0f;
  1376. /* JDC static */ float yaw = 0.0f;
  1377. static float inv_yaw = 0.0f;
  1378. static float pitch = 0.0f;
  1379. #define __glPi 3.14159265358979323846
  1380. static void infinitePerspective(GLdouble fovy, GLdouble aspect, GLdouble znear)
  1381. {
  1382. GLfloat left, right, bottom, top; // JDC: was GLdouble
  1383. GLfloat m[16]; // JDC: was GLdouble
  1384. top = znear * tan(fovy * __glPi / 360.0);
  1385. bottom = -top;
  1386. left = bottom * aspect;
  1387. right = top * aspect;
  1388. //qglFrustum(left, right, bottom, top, znear, zfar);
  1389. m[ 0] = (2 * znear) / (right - left);
  1390. m[ 4] = 0;
  1391. m[ 8] = (right + left) / (right - left);
  1392. m[12] = 0;
  1393. m[ 1] = 0;
  1394. m[ 5] = (2 * znear) / (top - bottom);
  1395. m[ 9] = (top + bottom) / (top - bottom);
  1396. m[13] = 0;
  1397. m[ 2] = 0;
  1398. m[ 6] = 0;
  1399. //m[10] = - (zfar + znear) / (zfar - znear);
  1400. //m[14] = - (2 * zfar * znear) / (zfar - znear);
  1401. m[10] = -1;
  1402. m[14] = -2 * znear;
  1403. m[ 3] = 0;
  1404. m[ 7] = 0;
  1405. m[11] = -1;
  1406. m[15] = 0;
  1407. glMultMatrixf(m); // JDC: was glMultMatrixd
  1408. }
  1409. /*
  1410. IR_RenderPlayerView
  1411. Replace the prBoom rendering code with a higher performance
  1412. version. Most of the fancy new features are gone, because I
  1413. have no idea what the reight test cases would be for them.
  1414. */
  1415. void IR_RenderPlayerView (player_t* player) {
  1416. int start = 0;
  1417. if ( showRenderTime ) {
  1418. start = SysIphoneMicroseconds();
  1419. }
  1420. viewplayer = player;
  1421. tic_vars.frac = FRACUNIT;
  1422. viewx = player->mo->x;
  1423. viewy = player->mo->y;
  1424. viewz = player->viewz;
  1425. viewangle = player->mo->angle;
  1426. extralight = player->extralight; // gun flashes
  1427. yaw=270.0f-(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES;
  1428. viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
  1429. viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
  1430. // IR goggles
  1431. if (player->fixedcolormap) {
  1432. fixedcolormap = fullcolormap + player->fixedcolormap*256*sizeof(lighttable_t);
  1433. } else {
  1434. fixedcolormap = 0;
  1435. }
  1436. // this is used to tell if a line, sector, or sprite is going to be drawn this frame
  1437. validcount++;
  1438. // clear the 1D occlusion buffer, set a final guard column to occluded so we can
  1439. // check an extra pixel to account for slight floating point differences between
  1440. // the GPU and CPU transformations
  1441. assert( viewwidth <= MAX_SCREENWIDTH );
  1442. memset( occlusion, 0, sizeof( occlusion ) );
  1443. occlusion[viewwidth] = 1;
  1444. float trY ;
  1445. float xCamera,yCamera;
  1446. extern int screenblocks;
  1447. int height;
  1448. gld_SetPalette(-1);
  1449. if (screenblocks == 11)
  1450. height = SCREENHEIGHT;
  1451. else if (screenblocks == 10)
  1452. height = SCREENHEIGHT;
  1453. else
  1454. height = (screenblocks*SCREENHEIGHT/10) & ~7;
  1455. glViewport(viewwindowx, SCREENHEIGHT-(height+viewwindowy-((height-viewheight)/2)), viewwidth, height);
  1456. glScissor(viewwindowx, SCREENHEIGHT-(viewheight+viewwindowy), viewwidth, viewheight);
  1457. glEnable(GL_SCISSOR_TEST);
  1458. glEnable(GL_DEPTH_TEST);
  1459. glDisable(GL_FOG);
  1460. glShadeModel(GL_SMOOTH);
  1461. // Player coordinates
  1462. xCamera=-(float)viewx/MAP_SCALE;
  1463. yCamera=(float)viewy/MAP_SCALE;
  1464. trY=(float)viewz/MAP_SCALE;
  1465. yaw=270.0f-(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES;
  1466. inv_yaw=-90.0f+(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES;
  1467. #ifdef _DEBUG
  1468. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1469. #else
  1470. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1471. #endif
  1472. // To make it easier to accurately mimic the GL model to screen transformation,
  1473. // this is set up so that the projection transformation is also done in the
  1474. // modelview matrix, leaving the projection matrix as an identity. This means
  1475. // that things done in eye space, like lighting and fog, won't work, but
  1476. // we don't need them.
  1477. glMatrixMode(GL_PROJECTION);
  1478. glLoadIdentity();
  1479. glMatrixMode(GL_MODELVIEW);
  1480. glLoadIdentity();
  1481. infinitePerspective(64.0f, 320.0f/200.0f, 5.0f/100.0f);
  1482. glRotatef(roll, 0.0f, 0.0f, 1.0f);
  1483. glRotatef(pitch, 1.0f, 0.0f, 0.0f);
  1484. glRotatef(yaw, 0.0f, 1.0f, 0.0f);
  1485. glTranslatef(-xCamera, -trY, -yCamera);
  1486. // read back the matrix so we can do exact calculations that match
  1487. // what GL is doing. It would probably be better to build the matricies
  1488. // ourselves and just do a loadMatrix...
  1489. glGetFloatv( GL_MODELVIEW_MATRIX, glMVPmatrix );
  1490. // setup the vector for calculating light fades, which is just a scale
  1491. // of the forward vector
  1492. lightingVector[0] = lightDistance * glMVPmatrix[2];
  1493. lightingVector[1] = lightDistance * glMVPmatrix[10];
  1494. lightingVector[2] = lightDistance * glMVPmatrix[14];
  1495. rendermarker++;
  1496. gld_drawinfo.num_walls=0;
  1497. gld_drawinfo.num_flats=0;
  1498. gld_drawinfo.num_sprites=0;
  1499. gld_drawinfo.num_drawitems=0;
  1500. c_occludedSprites = 0;
  1501. c_sectors = 0;
  1502. c_subsectors = 0;
  1503. numSectorPlanes = 0;
  1504. failCount = 0;
  1505. // Find everything we need to draw, but don't draw anything yet,
  1506. // because we want to sort by texture to reduce GL driver overhead.
  1507. IR_RenderBSPNode( numnodes-1 );
  1508. NewDrawScene(player);
  1509. gld_EndDrawScene();
  1510. if ( showRenderTime ) {
  1511. int end = SysIphoneMicroseconds();
  1512. printf( "%i usec\n", end - start );
  1513. }
  1514. }