]> icculus.org git repositories - theoddone33/hhexen.git/blob - opengl/ogl_rend.c
osezer patch 009
[theoddone33/hhexen.git] / opengl / ogl_rend.c
1 //**************************************************************************
2 //**
3 //** OGL_DRAW.C
4 //**
5 //** Version:           1.0
6 //** Last Build:        -?-
7 //** Author:            jk
8 //**
9 //** Rendering lists and other rendering.
10 //**
11 //**************************************************************************
12
13 // HEADER FILES ------------------------------------------------------------
14
15 #ifdef __WIN32
16 #define WIN32_LEAN_AND_MEAN
17 #include <windows.h>
18 #endif
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <malloc.h>
23 #include <math.h>
24 #include <GL/gl.h>
25 #include <GL/glu.h>
26 #include "h2def.h"
27 #include "r_local.h"
28 #include "p_local.h"
29 #include "ogl_def.h"
30 #include "m_bams.h"
31 #include "ogl_rl.h"
32
33 // MACROS ------------------------------------------------------------------
34
35 // TYPES -------------------------------------------------------------------
36
37 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
38
39 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
40
41 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
42
43 static void OGL_ProjectionMatrix();
44 void RL_DynLightQuad(rendquad_t *quad, lumobj_t *lum);
45 void DL_Clear();
46
47 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
48
49 int     useDynLights = 0;
50 int sbarscale = 20;
51 extern fadeout_t        fadeOut[2];             // For both skies.
52 extern int                      skyhemispheres;
53
54 // PUBLIC DATA DEFINITIONS -------------------------------------------------
55
56 boolean         whitefog = false;               // Is the white fog in use?
57 boolean         special200;
58
59 float           vx, vy, vz, vang, vpitch;
60
61 boolean         willRenderSprites = true, freezeRLs = false;
62
63 lumobj_t        *luminousList = 0;
64 int                     numLuminous = 0, maxLuminous = 0;
65 int                     dlMaxRad = 64; // Dynamic lights maximum radius.
66
67 // PRIVATE DATA DEFINITIONS ------------------------------------------------
68
69 static int viewpw, viewph;      // Viewport size.
70 static float nearClip, farClip;
71 static float yfov;
72 static float viewsidex, viewsidey;      // For the black fog.
73
74 static boolean firstsubsector;          // No range checking for the first one.
75
76 // CODE --------------------------------------------------------------------
77
78 // How far the point is from the viewside plane?
79 float PointDist2D(float c[2])
80 {
81 /*          (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
82         s = -----------------------------
83                         L**2
84         Luckily, L**2 is one. dist = s*L. Even more luckily, L is also one.
85 */
86         float dist = (vz-c[VY])*viewsidex - (vx-c[VX])*viewsidey;
87         if(dist < 0) return -dist;      // Always return positive.
88         return dist;
89 }
90
91 // ---------------------------------------------------
92
93 void OGL_InitData()
94 {
95         OGL_TexInit();          // OpenGL texture manager.
96         bamsInit();                     // Binary angle calculations.
97         C_Init();                       // Clipper.
98         RL_Init();                      // Rendering lists.
99 }
100
101 void OGL_ResetData()    // Called before starting a new level.
102 {
103         OGL_TexReset();         // Textures are deleted (at least skies need this???).
104         RL_DeleteLists();       // The rendering lists are destroyed.
105
106         // We'll delete the sky textures. New ones will be generated for each level.
107         //glDeleteTextures(2, skynames);
108         //skynames[0] = skynames[1] = 0;
109         
110         // Ready for new fadeout colors.
111         fadeOut[0].set = fadeOut[1].set = 0;
112
113         DL_Clear();
114 }
115
116 void OGL_InitRenderer() // Initializes the renderer to 2D state.
117 {
118         GLfloat fogcol[4] = { .7f, .7f, .7f, 1 };
119
120 //      PC_Init(&clipperclock);
121 //      PC_Init(&rlclock);
122 //      PC_Init(&miscclock);
123
124         // The variables.
125         nearClip = 5;
126         farClip = 8000; 
127
128         // Here we configure the OpenGL state and set projection matrix.
129         glFrontFace(GL_CW);
130         glDisable(GL_CULL_FACE);
131         glCullFace(GL_BACK);
132         glDisable(GL_DEPTH_TEST);
133         glDepthFunc(GL_LESS);
134         glEnable(GL_TEXTURE_2D);
135         //glPolygonMode(GL_FRONT, GL_LINE);
136
137         // The projection matrix.
138         glMatrixMode(GL_PROJECTION);
139         glLoadIdentity();
140         gluOrtho2D(0,320,200,0);
141
142         // Initialize the modelview matrix.
143         glMatrixMode(GL_MODELVIEW);
144         glLoadIdentity();
145
146         // Clear also the texture matrix (I'm not using this, though).
147         glMatrixMode(GL_TEXTURE);
148         glLoadIdentity();
149
150         // Alpha blending is a go!
151         glEnable(GL_BLEND);
152         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
153         glEnable(GL_ALPHA_TEST);
154         glAlphaFunc(GL_GREATER, 0);
155
156         // Default state for the white fog is off.
157         whitefog = false;
158         glDisable(GL_FOG);
159         glFogi(GL_FOG_MODE, GL_LINEAR);
160         glFogi(GL_FOG_END, 3500);       // This should be tweaked a bit.
161         glFogfv(GL_FOG_COLOR, fogcol);
162
163         /*glEnable(GL_POLYGON_SMOOTH);
164         glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);*/
165
166         // Check the performance counter.
167         /*{
168                 LARGE_INTEGER freq;
169                 __int64 start, end;
170                 QueryPerformanceFrequency(&freq);
171                 QueryPerformanceCounter((LARGE_INTEGER*)&start);
172                 printf( "Performance counter frequency: %I64d counts per second.\n", freq);
173                 QueryPerformanceCounter((LARGE_INTEGER*)&end);
174                 printf( "(the printing of that took %I64d tics)\n", end-start);
175         }*/
176
177         // We don't want any hassles with uninitialized names, do we?
178         //skynames[0] = skynames[1] = 0;
179 }
180
181 void OGL_UseWhiteFog(int yes)
182 {
183         if(!whitefog && yes)
184         {
185                 // White fog is turned on.
186                 whitefog = true;
187                 glEnable(GL_FOG);
188         }
189         else if(whitefog && !yes)
190         {
191                 // White fog must be turned off.
192                 whitefog = false;
193                 glDisable(GL_FOG);
194         }
195         // Otherwise we won't do a thing.
196 }
197
198 void OGL_SwitchTo3DState()
199 {
200 //      extern int setblocks;
201         
202         // Push the 2D state on the stack.
203         glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
204         glMatrixMode(GL_PROJECTION);
205         glPushMatrix();
206         glMatrixMode(GL_MODELVIEW);
207         glPushMatrix();
208
209         // Enable some.. things.
210         glEnable(GL_CULL_FACE);
211         glEnable(GL_DEPTH_TEST);
212
213         // Set the viewport.
214         if(viewheight != SCREENHEIGHT)
215         {
216                 int svx = viewwindowx * screenWidth/320,
217                         svy = viewwindowy * screenHeight/200;
218                 viewpw = viewwidth * screenWidth/320;
219                 viewph = viewheight * screenHeight/200 + 1;
220                 glViewport(svx, screenHeight-svy-viewph, viewpw, viewph);
221         }
222         else
223         {
224                 viewpw = screenWidth;
225                 viewph = screenHeight;
226         }
227
228         // The 3D projection matrix.
229         OGL_ProjectionMatrix();
230 }
231
232 void OGL_Restore2DState(int step)
233 {
234         if(step == 1)
235         {
236                 extern int screenblocks;                
237                 glMatrixMode(GL_PROJECTION);
238                 glLoadIdentity();
239                 gluOrtho2D(0, 320, (screenblocks<11)?161:200, 0);
240                 glMatrixMode(GL_MODELVIEW);
241                 glLoadIdentity();
242         }
243         // Retrieve the old state.
244         if(step == 2)
245         {
246                 glMatrixMode(GL_PROJECTION);
247                 glPopMatrix();
248                 glMatrixMode(GL_MODELVIEW);
249                 glPopMatrix();
250                 glPopAttrib();
251         }
252 }
253
254 static void OGL_ProjectionMatrix()
255 {
256         // We're assuming pixels are squares... well, they are nowadays.
257         float aspect = (float)viewpw/(float)viewph;
258         //float aspect = 1.0;
259         glMatrixMode(GL_PROJECTION);
260         glLoadIdentity();
261         gluPerspective(yfov=90.0/aspect, aspect, nearClip, farClip);
262         // We'd like to have a left-handed coordinate system.
263         glScalef(1,1,-1);
264 }
265
266 static void OGL_ModelViewMatrix()
267 {
268         vx = FIX2FLT(viewx);
269         vy = FIX2FLT(viewz);
270         vz = FIX2FLT(viewy);
271         vang = viewangle / (float)ANGLE_MAX * 360 - 90;
272
273         glMatrixMode(GL_MODELVIEW);
274         glLoadIdentity();
275         glRotatef(vpitch=viewpitch * 85.0/110.0, 1, 0, 0);
276         glRotatef(vang, 0, 1, 0);
277         glScalef(1, 1.2f, 1);   // This is the aspect correction.
278         glTranslatef(-vx,-vy,-vz);
279 }
280
281
282 // *VERY* similar to SegFacingDir(). Well, this is actually the same
283 // function, only a more general version.
284 static int SegFacingPoint(float v1[2], float v2[2], float p[2])
285 {
286         float nx = v1[VY]-v2[VY], ny = v2[VX]-v1[VX];
287         float pvx = v1[VX]-p[VX], pvy = v1[VY]-p[VY];
288         // The dot product.
289         if(nx*pvx+ny*pvy > 0) return 1; // Facing front.
290         return 0;       // Facing away.
291 }
292
293 static void projectVector(float a[2], float b[2], float *a_on_b)
294 {
295         int             c;
296         float   factor = (a[0]*b[0] + a[1]*b[1]) / (b[0]*b[0] + b[1]*b[1]);
297         for(c=0; c<2; c++) a_on_b[c] = factor * b[c];
298 }
299
300 // Create dynamic light quads, if necessary.
301 static void DL_ProcessWall(rendquad_t *quad, float v1[2], float v2[2])
302 {
303         int                     i, c;
304         rendquad_t      dlq;
305         float           pntLight[2];
306         float           vecLight[2]; // Vector from v1 to light point.
307         float           uvecWall[2], uvecWallNormal[2]; // Unit vectors.
308         float           vecDist[2];
309         float           dist;           // Distance between light source and wall.
310
311         // We can't handle masked walls. The alpha...
312         if(quad->flags & RQF_MASKED) return;
313
314         for(i=0; i<numLuminous; i++)
315         {
316                 lumobj_t *lum = luminousList + i;
317                 // If the light is not in use, we skip it.
318                 if(!lum->use) continue;
319                 // First we must check orientation. Backfaces aren't lighted, naturally.
320                 pntLight[VX] = FIX2FLT(lum->thing->x);
321                 pntLight[VY] = FIX2FLT(lum->thing->y);
322                 if(!SegFacingPoint(v1, v2, pntLight)) continue;
323                 // Make a copy of the original.
324                 memcpy(&dlq, quad, sizeof(dlq));
325                 // Copy the given end points.
326                 memcpy(dlq.v1, v1, sizeof(v1));
327                 memcpy(dlq.v2, v2, sizeof(v2));
328                 dlq.flags |= RQF_LIGHT; // This is a light texture.
329                 dlq.texw = dlq.texh = dlMaxRad*2;
330                 // The wall vector.
331                 for(c=0; c<2; c++)
332             uvecWall[c] = (quad->v2[c] - quad->v1[c]) / quad->u.q.len;
333                 // The normal.
334                 uvecWallNormal[VX] = uvecWall[VY];
335                 uvecWallNormal[VY] = -uvecWall[VX];
336                 // The relative position of the light source.
337                 for(c=0; c<2; c++) vecLight[c] = pntLight[c] - quad->v1[c];
338                 // The distance vector. VecLight projected on the normal vector.
339                 projectVector(vecLight, uvecWallNormal, vecDist);
340                 // The accurate distance from the wall to the light.
341                 dist = sqrt(vecDist[0]*vecDist[0] + vecDist[1]*vecDist[1]);
342                 if(dist > dlMaxRad) continue; // Too far away.
343                 // Now we can calculate the intensity of the light.
344                 dlq.light = 1.5f - 1.5f*dist/dlMaxRad;
345                 // Do a scalar projection for the offset.
346                 dlq.texoffx = vecLight[0]*uvecWall[0] + vecLight[1]*uvecWall[1] - dlMaxRad;
347                 // There is no need to draw the *whole* wall always. Adjust the start
348                 // and end points so that only a relevant portion is included.
349                 if(dlq.texoffx > dlq.u.q.len) continue; // Doesn't fit on the wall.
350                 if(dlq.texoffx < -dlq.texw) continue; // Ditto, but in the other direction.
351                 if(dlq.texoffx > 0)
352                 {
353                         for(c=0; c<2; c++) dlq.v1[c] += dlq.texoffx * uvecWall[c];
354                         if(dlq.texoffx+dlq.texw <= dlq.u.q.len) // Fits completely?
355                         {
356                                 for(c=0; c<2; c++) dlq.v2[c] = dlq.v1[c] + dlq.texw*uvecWall[c];
357                                 dlq.u.q.len = dlq.texw;
358                         }
359                         else // Doesn't fit.
360                                 dlq.u.q.len -= dlq.texoffx;
361                         dlq.texoffx = 0;
362                 }
363                 else // It goes off to the left.
364                 {
365                         if(dlq.texoffx+dlq.texw <= dlq.u.q.len) // Fits completely?
366                         {
367                                 for(c=0; c<2; c++) dlq.v2[c] = dlq.v1[c] + (dlq.texw+dlq.texoffx)*uvecWall[c];
368                                 dlq.u.q.len = dlq.texw + dlq.texoffx;
369                         }
370                 }
371                 // The vertical offset is easy to determine.
372                 dlq.texoffy = FIX2FLT(lum->thing->z)+lum->top-lum->height/2 + dlMaxRad - dlq.top;
373                 if(dlq.texoffy < -dlq.top+dlq.u.q.bottom) continue;
374                 if(dlq.texoffy > dlq.texh) continue;
375                 if(dlq.top+dlq.texoffy-dlq.texh >= dlq.u.q.bottom) // Fits completely?
376                         dlq.u.q.bottom = dlq.top+dlq.texoffy-dlq.texh;
377                 if(dlq.texoffy < 0)
378                 {
379                         dlq.top += dlq.texoffy;
380                         dlq.texoffy = 0;
381                 }
382                 // As a final touch, move the light quad a bit away from the wall
383                 // to avoid z-fighting.
384                 for(c=0; c<2; c++) 
385                 {
386                         dlq.v1[c] += .2 * uvecWallNormal[c];
387                         dlq.v2[c] += .2 * uvecWallNormal[c];
388                 }
389                 // Now we can give the new quad to the rendering engine.
390                 RL_AddQuad(&dlq, 0);
391         }
392 }
393
394 static int SegFacingDir(float v1[2], float v2[2])
395 {
396         float nx = v1[VY]-v2[VY], ny = v2[VX]-v1[VX];
397         float vvx = v1[VX]-vx, vvy = v1[VY]-vz;
398
399         // The dot product.
400         if(nx*vvx+ny*vvy > 0) return 1; // Facing front.
401         return 0;       // Facing away.
402 }
403
404 // The sector height should've been checked by now.
405 void R_RenderWallSeg(seg_t *seg, sector_t *frontsec, boolean accurate)
406 {
407         sector_t                *backsec = seg->backsector;
408         side_t                  *sid = seg->sidedef;
409         line_t                  *ldef = seg->linedef;
410         float                   ffloor = FIX2FLT(frontsec->floorheight);
411         float                   fceil = FIX2FLT(frontsec->ceilingheight);
412         float                   bfloor, bceil, fsh = fceil-ffloor, bsh;
413         float                   tcyoff;
414         rendquad_t              quad;
415         float                   origv1[2], origv2[2];   // The original end points, for dynlights.
416
417         memset(&quad, 0, sizeof(quad));         // Clear the quad.
418
419         // Get the start and end points. Full floating point conversion is
420         // actually only necessary for polyobjs.
421         if(accurate)
422         {
423                 quad.v1[VX] = FIX2FLT(seg->v1->x);
424                 quad.v1[VY] = FIX2FLT(seg->v1->y);
425                 quad.v2[VX] = FIX2FLT(seg->v2->x);
426                 quad.v2[VY] = FIX2FLT(seg->v2->y);
427                 // These are the original vertices, copy them.
428                 memcpy(origv1, quad.v1, sizeof(origv1));
429                 memcpy(origv2, quad.v2, sizeof(origv2));
430         }
431         else
432         {
433                 float dx, dy;
434                 // Not-so-accurate.
435                 quad.v1[VX] = Q_FIX2FLT(seg->v1->x);
436                 quad.v1[VY] = Q_FIX2FLT(seg->v1->y);
437                 quad.v2[VX] = Q_FIX2FLT(seg->v2->x);
438                 quad.v2[VY] = Q_FIX2FLT(seg->v2->y);
439                 // The original vertex. For dlights.
440                 memcpy(origv1, quad.v1, sizeof(origv1));
441                 memcpy(origv2, quad.v2, sizeof(origv2));
442                 // Make the very small crack-hiding adjustment.
443                 dx = quad.v2[VX] - quad.v1[VX];
444                 dy = quad.v2[VY] - quad.v1[VY];
445                 quad.v2[VX] += dx/seg->len/4;
446                 quad.v2[VY] += dy/seg->len/4;
447         }
448
449         // Let's first check which way this seg is facing.
450         if(!SegFacingDir(quad.v1, quad.v2)) return;     // The wrong direction?
451
452         // Calculate the distances.
453         quad.dist[0] = PointDist2D(quad.v1);
454         quad.dist[1] = PointDist2D(quad.v2);
455
456         // Calculate the lightlevel.
457         quad.light = frontsec->lightlevel;
458         /*if(quad.v1[VX] == quad.v2[VX]) quad.light += 16;
459         if(quad.v1[VY] == quad.v2[VY]) quad.light -= 16;*/
460         quad.light /= 255.0;
461
462         // This line is now seen in the map.
463         ldef->flags |= ML_MAPPED;
464
465         // Some texture coordinates.
466         quad.texoffx = (sid->textureoffset>>FRACBITS)+(seg->offset>>FRACBITS);
467         quad.u.q.len = seg->len;
468         tcyoff = Q_FIX2FLT(sid->rowoffset);
469
470         // The middle texture, single sided.
471         if(sid->midtexture && !backsec)
472         {
473                 curtex = OGL_PrepareTexture(sid->midtexture);           
474                 quad.texoffy = tcyoff;
475                 if(ldef->flags & ML_DONTPEGBOTTOM)
476                         quad.texoffy += texh-fsh;
477
478                 // Fill in the remaining quad data.
479                 quad.flags = 0;
480                 quad.top = fceil;
481                 quad.u.q.bottom = ffloor;
482                 quad.texw = texw;
483                 quad.texh = texh;
484                 RL_AddQuad(&quad, curtex);
485                 if(useDynLights) DL_ProcessWall(&quad, origv1, origv2);
486
487                 //printf( "Solid segment in sector %p.\n", frontsec);
488                 // This is guaranteed to be a solid segment.
489                 C_AddViewRelSeg(quad.v1[VX],quad.v1[VY],quad.v2[VX],quad.v2[VY]);
490         }
491         // The skyfix?
492         if(frontsec->skyfix)
493         {
494                 if(!backsec || (backsec && (backsec->ceilingheight+(backsec->skyfix<<FRACBITS) < 
495                         frontsec->ceilingheight+(frontsec->skyfix<<FRACBITS))))// ||
496                         //backsec->floorheight == frontsec->ceilingheight)))
497                 {
498                         quad.flags = RQF_SKY_MASK_WALL;
499                         quad.top = fceil + frontsec->skyfix;
500                         quad.u.q.bottom = fceil;
501                         RL_AddQuad(&quad, curtex);
502                         if(useDynLights) DL_ProcessWall(&quad, origv1, origv2);
503                 }
504         }
505         // If there is a back sector we may need upper and lower walls.
506         if(backsec)     // A twosided seg?
507         {
508                 bfloor = FIX2FLT(backsec->floorheight);
509                 bceil = FIX2FLT(backsec->ceilingheight);
510                 bsh = bceil - bfloor;
511                 if(bsh <= 0 || bceil <= ffloor || bfloor >= fceil)
512                 {
513                         //printf( "Solid segment in sector %p (backvol=0).\n", frontsec);
514                         // The backsector has no space. This is a solid segment.
515                         C_AddViewRelSeg(quad.v1[VX],quad.v1[VY],quad.v2[VX],quad.v2[VY]);
516                 }
517                 if(sid->midtexture)     // Quite probably a masked texture.
518                 {
519                         float mceil = (bceil<fceil)?bceil:fceil,
520                                 mfloor = (bfloor>ffloor)?bfloor:ffloor,
521                                 msh = mceil - mfloor;
522                         if(msh > 0)
523                         {
524                                 curtex = OGL_PrepareTexture(sid->midtexture);
525                                 // Calculate the texture coordinates. Also restrict
526                                 // vertical tiling (if masked) by adjusting mceil and mfloor.
527                                 if(texmask)     // A masked texture?
528                                 {
529                                         quad.flags = RQF_MASKED;
530                                         quad.texoffy = 0;
531                                         // We don't allow vertical tiling.
532                                         if(ldef->flags & ML_DONTPEGBOTTOM)
533                                         {
534                                                 mfloor += tcyoff;
535                                                 mceil = mfloor + texh;
536                                         }
537                                         else
538                                         {
539                                                 mceil += tcyoff;
540                                                 mfloor = mceil - texh;
541                                         }
542                                 }
543                                 else // Normal texture.
544                                 {
545                                         quad.flags = 0;
546                                         quad.texoffy = tcyoff;
547                                         if(ldef->flags & ML_DONTPEGBOTTOM) // Lower unpegged. Align bottom.
548                                                 quad.texoffy += texh-msh;
549                                 }
550                                 // Fill in the remainder of the data.
551                                 quad.top = mceil;
552                                 quad.u.q.bottom = mfloor;
553                                 quad.texw = texw;
554                                 quad.texh = texh;
555                                 RL_AddQuad(&quad, curtex);
556                                 if(useDynLights) DL_ProcessWall(&quad, origv1, origv2);
557                         }
558                 }
559                 // Upper wall.
560                 if(bceil < fceil && !(frontsec->ceilingpic == skyflatnum && backsec->ceilingpic == skyflatnum))
561                 {
562                         float topwh = fceil - bceil;
563                         if(sid->toptexture)     // A texture present?
564                         {
565                                 curtex = OGL_PrepareTexture(sid->toptexture);
566                                 // Calculate texture coordinates.
567                                 quad.texoffy = tcyoff;
568                                 if(!(ldef->flags & ML_DONTPEGTOP))
569                                 {
570                                         // Normal alignment to bottom.
571                                         quad.texoffy += texh-topwh;
572                                 }                                                               
573                                 quad.flags = 0;                         
574                         }
575                         else
576                         {
577                                 // No texture? Bad thing. You don't deserve texture 
578                                 // coordinates. Take the ceiling texture.
579                                 curtex = OGL_PrepareFlat(frontsec->ceilingpic);                         
580                                 quad.flags = RQF_FLAT | RQF_MISSING_WALL;
581                         }
582                         quad.top = fceil;
583                         quad.u.q.bottom = bceil;
584                         quad.texw = texw;
585                         quad.texh = texh;
586                         RL_AddQuad(&quad, curtex);
587                         if(useDynLights) DL_ProcessWall(&quad, origv1, origv2);
588                 }
589                 // Lower wall.
590                 if(bfloor > ffloor && !(frontsec->floorpic == skyflatnum && backsec->floorpic == skyflatnum))
591                 {
592                         if(sid->bottomtexture)  // There is a texture?
593                         {
594                                 curtex = OGL_PrepareTexture(sid->bottomtexture);
595                                 // Calculate texture coordinates.
596                                 quad.texoffy = tcyoff;
597                                 if(ldef->flags & ML_DONTPEGBOTTOM)
598                                 {
599                                         // Lower unpegged. Align with normal middle texture.
600                                         //quad.texoffy += fsh-texh;
601                                         quad.texoffy += fceil-bfloor;
602                                 }
603                                 quad.flags = 0;
604                         }
605                         else
606                         {
607                                 // No texture? Again!
608                                 curtex = OGL_PrepareFlat(frontsec->floorpic);
609                                 quad.flags = RQF_FLAT | RQF_MISSING_WALL;
610                         }
611                         quad.top = bfloor;
612                         quad.u.q.bottom = ffloor;
613                         quad.texw = texw;
614                         quad.texh = texh;
615                         RL_AddQuad(&quad, curtex);
616                         if(useDynLights) DL_ProcessWall(&quad, origv1, origv2);
617                 }
618         }
619 }
620
621 void R_HandleSectorSpecials(sector_t *sect)
622 {
623         int     scrollOffset = leveltime>>1 & 63;
624
625         switch(sect->special)
626         { // Handle scrolling flats
627         case 201: case 202: case 203: // Scroll_North_xxx
628                 sect->flatoffy = (63-scrollOffset) << (sect->special-201);
629                 break;
630         case 204: case 205: case 206: // Scroll_East_xxx
631                 sect->flatoffx = (63-scrollOffset) << (sect->special-204);
632                 break;
633         case 207: case 208: case 209: // Scroll_South_xxx
634                 sect->flatoffy = scrollOffset << (sect->special-207);
635                 break;
636         case 210: case 211: case 212: // Scroll_West_xxx
637                 sect->flatoffx = scrollOffset << (sect->special-210);
638                 break;
639         case 213: case 214: case 215: // Scroll_NorthWest_xxx
640                 sect->flatoffx = scrollOffset << (sect->special-213);
641                 sect->flatoffy = (63-scrollOffset) << (sect->special-213);
642                 break;
643         case 216: case 217: case 218: // Scroll_NorthEast_xxx
644                 sect->flatoffx = (63-scrollOffset) << (sect->special-216);
645                 sect->flatoffy = (63-scrollOffset) << (sect->special-216);
646                 break;
647         case 219: case 220: case 221: // Scroll_SouthEast_xxx
648                 sect->flatoffx = (63-scrollOffset) << (sect->special-219);
649                 sect->flatoffy = scrollOffset << (sect->special-219);
650                 break;
651         case 222: case 223: case 224: // Scroll_SouthWest_xxx
652                 sect->flatoffx = scrollOffset << (sect->special-222);
653                 sect->flatoffy = scrollOffset << (sect->special-222);
654                 break;
655         default:
656                 sect->flatoffx = sect->flatoffy = 0;
657                 break;
658         }
659 }
660
661 void DL_Clear()
662 {
663         free(luminousList);
664         luminousList = 0;
665         maxLuminous = numLuminous = 0;
666 }
667
668 boolean DL_AddLuminous(mobj_t *thing)
669 {
670         if(thing->frame & FF_FULLBRIGHT && !(thing->flags2&MF2_DONTDRAW))
671         {
672                 spritedef_t *sprdef;
673                 spriteframe_t *sprframe;
674                 int lump;
675                 lumobj_t *lum;
676
677                 // Only allocate memory when it's needed.
678                 if(++numLuminous > maxLuminous)
679                         luminousList = realloc(luminousList, sizeof(lumobj_t) * (maxLuminous+=5));
680                 lum = luminousList + numLuminous-1;
681                 lum->thing = thing;
682                 // We need to know how tall the thing currently is.
683                 sprdef = &sprites[thing->sprite];
684                 sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK ];
685                 if(sprframe->rotate)
686                         lump = sprframe->lump[(R_PointToAngle(thing->x, thing->y) - thing->angle + (unsigned)(ANG45/2)*9) >> 29];
687                 else
688                         lump = sprframe->lump[0];
689                 // This'll ensure we have up-to-date information.
690                 OGL_PrepareSprite(lump);
691                 lum->top = FIX2FLT(spritetopoffset[lump] - lum->thing->floorclip);
692                 lum->height = spriteheights[lump];
693                 //printf( "%p: t:%.2f h:%.2f\n", thing, lum->top, lum->height);
694         }
695         return true;
696 }
697
698 // We want to know which luminous objects are close enough the subsector.
699 void DL_MarkForSubsector(subsector_t *sub)
700 {
701         int             i;
702         float   minx, miny, maxx, maxy; // Subsector bounding box.
703
704         // First determine the subsector bounding box based on
705         // the edge points.
706         /*maxx = minx = sub->edgeverts[0].x;
707         maxy = miny = sub->edgeverts[0].y;
708         for(i=1; i<sub->numedgeverts; i++)
709         {
710                 float x = sub->edgeverts[i].x, y = sub->edgeverts[i].y;
711                 if(x > maxx) maxx = x;
712                 if(x < minx) minx = x;
713                 if(y > maxy) maxy = y;
714                 if(y < miny) miny = y;
715         }
716         // Adjust the bounding box to include the maximum radius of the
717         // dynamic lights (64).
718         maxx += dlMaxRad; minx -= dlMaxRad;
719         maxy += dlMaxRad; miny -= dlMaxRad;*/
720         
721         // Adjust the bounding box to include the maximum radius of the
722         // dynamic lights (64).
723         minx = sub->bbox[0].x - dlMaxRad;
724         miny = sub->bbox[0].y - dlMaxRad;
725         maxx = sub->bbox[1].x + dlMaxRad; 
726         maxy = sub->bbox[1].y + dlMaxRad; 
727         // Now check all the luminous objects and mark those that
728         // are close enough.
729         for(i=0; i<numLuminous; i++)
730         {
731                 lumobj_t *lum = luminousList + i;
732                 float x = Q_FIX2FLT(lum->thing->x), y = Q_FIX2FLT(lum->thing->y);
733                 // By default the luminous object isn't used.
734                 lum->use = false;
735                 // Is inside the bounding box?
736                 if(x > minx && y > miny && x < maxx && y < maxy)
737                         lum->use = true;
738         }
739 }
740         
741 void R_RenderSubsector(int ssecidx)
742 {
743         subsector_t             *ssec = subsectors+ssecidx;
744         extern subsector_t *currentssec;
745         int                             i;
746         seg_t                   *seg;
747         sector_t                *sect = ssec->sector;
748         float                   ffloor = FIX2FLT(sect->floorheight);
749         float                   fceil = FIX2FLT(sect->ceilingheight);
750         rendquad_t              triangle;
751
752         if(fceil-ffloor <= 0) 
753         {
754                 return; // Skip this, no volume.
755         }
756
757         if(!firstsubsector)
758         {
759                 if(!C_CheckSubsector(ssec)) return;     // This isn't visible.
760         }
761         else
762                 firstsubsector = false;
763
764 //      printf( "*** Rendering subsector %d (sector %p)\n", ssecidx, sect);
765
766         currentssec = ssec;
767
768         // Sprites for this sector have to be drawn. This must be done before
769         // the segments of this subsector are added to the clipper. Otherwise
770         // the sprites would get clipped by them, and that wouldn't be right.
771         R_AddSprites(sect);
772
773         // Dynamic lights?
774         if(useDynLights) DL_MarkForSubsector(ssec);
775
776         // Draw the walls.
777         for(i=0, seg=segs+ssec->firstline; i<ssec->numlines; i++, seg++)
778                 R_RenderWallSeg(seg, sect, false);
779
780         // Is there a polyobj on board?
781         if(ssec->poly)
782                 for(i=0; i<ssec->poly->numsegs; i++)
783                         R_RenderWallSeg(ssec->poly->segs[i], sect, true);
784
785         // The floor.
786         memset(&triangle, 0, sizeof(triangle));
787         triangle.flags = RQF_FLAT | RQF_FLOOR_FACING;   // This is a flat floor triangle.
788         triangle.light = sect->lightlevel / 255.0;
789         if(viewz > sect->floorheight) // && vpitch < yfov)
790         {
791                 // Check for sky... in the floor?
792                 if(sect->floorpic == skyflatnum) 
793                 {
794                         triangle.flags |= RQF_SKY_MASK;
795                         skyhemispheres |= SKYHEMI_LOWER;
796                         if(sect->special == 200) special200 = true;
797                 }
798                 curtex = OGL_PrepareFlat(sect->floorpic);
799                 triangle.texw = texw;
800                 triangle.texh = texh;
801                 triangle.texoffx = sect->flatoffx;
802                 triangle.texoffy = sect->flatoffy;
803                 triangle.top = ffloor;
804                 // The first vertex is always the first in the whole list.
805                 RL_AddFlatQuads(&triangle, curtex, ssec->numedgeverts, ssec->edgeverts, 0);
806                 // Dynamic lights.              
807                 if(useDynLights && sect->floorpic != skyflatnum)
808                 {
809                         triangle.flags |= RQF_LIGHT;
810                         triangle.top += .05f;   // An adjustment.
811                         for(i=0; i<numLuminous; i++)
812                         {
813                                 lumobj_t *lum = luminousList + i;
814                                 float z, hdiff;
815                                 if(!lum->use) continue;
816
817                                 z = FIX2FLT(lum->thing->z);
818                                 // Check that we're on the right side.
819                                 if(z+lum->top < triangle.top) continue; // Under it.
820                                 // Check that the height difference isn't too big.
821                                 z += lum->top - lum->height/2;  // Center Z.
822                                 if((hdiff=fabs(triangle.top-z)) > dlMaxRad) continue;
823                                 triangle.light = 1.5f - 1.5f*hdiff/dlMaxRad;                            
824                                 // We can add the light quads.
825                                 RL_AddFlatQuads(&triangle, (int)lum, ssec->numedgeverts, ssec->origedgeverts, 0);
826                         }
827                 }
828         }
829         // And the roof.
830         triangle.flags = RQF_FLAT;
831         triangle.light = sect->lightlevel / 255.0;
832         if(viewz < sect->ceilingheight) //&& vpitch > -yfov)
833         {
834                 // Check for sky.
835                 if(sect->ceilingpic == skyflatnum) 
836                 {
837                         triangle.flags |= RQF_SKY_MASK;
838                         skyhemispheres |= SKYHEMI_UPPER;
839                         if(sect->special == 200) special200 = true;
840                 }
841                 curtex = OGL_PrepareFlat(sect->ceilingpic);
842                 triangle.texw = texw;
843                 triangle.texh = texh;
844                 triangle.texoffx = 0;
845                 triangle.texoffy = 0;
846                 triangle.top = fceil + sect->skyfix;
847                 // The first vertex is always the last in the whole list.
848                 RL_AddFlatQuads(&triangle, curtex, ssec->numedgeverts, ssec->edgeverts, 1);
849                 // Dynamic lights.
850                 if(useDynLights && sect->ceilingpic != skyflatnum)
851                 {
852                         triangle.flags |= RQF_LIGHT;
853                         triangle.top -= .05f;   // An adjustment.
854                         for(i=0; i<numLuminous; i++)
855                         {
856                                 lumobj_t *lum = luminousList + i;
857                                 float z, hdiff;
858                                 if(!lum->use) continue;
859
860                                 z = FIX2FLT(lum->thing->z);
861                                 // Check that we're on the right side.
862                                 if(z+lum->top-lum->height > triangle.top) continue; // Under it.
863                                 // Check that the height difference isn't too big.
864                                 z += lum->top - lum->height/2;  // Center Z.
865                                 if((hdiff=fabs(triangle.top-z)) > dlMaxRad) continue;
866                                 triangle.light = 1.5f - 1.5f*hdiff/dlMaxRad;                            
867                                 // We can add the light quads.
868                                 RL_AddFlatQuads(&triangle, (int)lum, ssec->numedgeverts, ssec->origedgeverts, 1);
869                         }
870                 }
871         }
872 }
873
874 void R_RenderNode(int bspnum)
875 {
876         node_t          *bsp;
877         int             side;
878
879         // If the clipper is full we're pretty much done.
880         if(cliphead)
881                 if(cliphead->start == 0 && cliphead->end == BANG_MAX)
882                         return;
883
884         if (bspnum & NF_SUBSECTOR)
885         {
886                 if (bspnum == -1)
887                         R_RenderSubsector(0);
888                 else
889                         R_RenderSubsector(bspnum&(~NF_SUBSECTOR));
890                 return;
891         }
892
893         bsp = &nodes[bspnum];
894
895 //
896 // decide which side the view point is on
897 //
898         side = R_PointOnSide (viewx, viewy, bsp);
899         
900         R_RenderNode (bsp->children[side]); // recursively divide front space
901
902 /*      if(cliphead->start == 0 && cliphead->end == BANG_MAX)
903                 return; // We can stop rendering.*/
904
905         //if (R_CheckBBox (bsp->bbox[side^1]))    // possibly divide back space
906         // We can't use that, unfortunately.
907         R_RenderNode (bsp->children[side^1]);
908         
909 }
910
911 void R_RenderMap()
912 {
913         int                     i;
914         binangle        viewside;
915
916         // This is all the clearing we'll do.
917         glClear(GL_DEPTH_BUFFER_BIT);
918
919         // Setup the modelview matrix.
920         OGL_ModelViewMatrix();
921
922         // Let's scroll some floors. This way we have to check them all,
923         // but there's no redundancy. And this really isn't all that expensive.
924         for(i=0; i<numsectors; i++) R_HandleSectorSpecials(sectors+i);
925
926 //      clippercount = 0;
927 //      rlcount = 0;
928
929         if(!freezeRLs)
930         {
931                 RL_ClearLists();        // Clear the lists for new quads.
932                 C_ClearRanges();        // Clear the clipper.
933                 if(useDynLights)        // Maintain luminous objects list.
934                 {
935                         numLuminous = 0;        // Clear the luminous object list.
936                         
937                         // Add all the luminous objects to the list.
938                         for(i=0; i<numsectors; i++)
939                         {
940                                 sector_t *sec = sectors + i;
941                                 mobj_t *iter;
942                                 for(iter=sec->thinglist; iter; iter=iter->snext)
943
944                         //for(k=0; k<bmapheight; k++)
945                         //      for(i=0; i<bmapwidth; i++)
946                                         //P_BlockThingsIterator(i, k, DL_AddLuminous);
947                                         DL_AddLuminous(iter);
948                         }
949                 }
950
951                 // Add the backside clipping range, vpitch allowing.
952                 if(vpitch <= 90-yfov/2 && vpitch >= -90+yfov/2)
953                 {
954                         float a = fabs(vpitch) / (90-yfov/2);
955                         binangle startAngle = (binangle) BANG_45*(1+a);
956                         binangle angLen = BANG_180 - startAngle;                                                                                                                                                                        
957                         viewside = (viewangle>>16) + startAngle;
958                         C_SafeAddRange(viewside, viewside+angLen);
959                         C_SafeAddRange(viewside+angLen, viewside+2*angLen);
960                         //C_SafeAddRange(viewside+BANG_135, viewside+2*BANG_135);
961                 }
962                 // The viewside line for the black fog distance calculations.
963                 viewsidex = -FIX2FLT(viewsin);
964                 viewsidey = FIX2FLT(viewcos);
965
966                 // We don't want subsector clipchecking for the first subsector.
967                 //misccount = I_GetPerformanceCount();
968                 firstsubsector = true;
969                 special200 = false;
970                 R_RenderNode(numnodes-1);
971                 //misccount = I_GetPerformanceCount()-misccount;
972         }
973         RL_RenderAllLists();
974
975         // Clipping fragmentation happens when there are holes in the walls.
976         /*if(cliphead->next)
977         {
978                 clipnode_t *ci;
979                 printf("\nTic: %d, Clipnodes are fragmented:\n", gametic);
980                 for(ci=cliphead; ci; ci=ci->next)
981                         printf( "range %p: %4x => %4x (%d)\n",ci,ci->start,ci->end,ci->used);
982                 I_Error("---Fragmented clipper---\n");
983         }*/
984 }
985
986 void R_RenderSprite(vissprite_t *spr)
987 {
988         float bot,top;
989 //      float off = FIX2FLT(spriteoffset[spr->patch]);
990         float w = FIX2FLT(spritewidth[spr->patch]);
991         int sprh;
992         float p2w = FindNextPower2((int)w), p2h;
993         float v1[2];//, v2[2];
994         //float sinrv, cosrv;
995         float tcleft, tcright;
996         float alpha;
997         //float thangle;
998
999         // Set the texture.
1000         OGL_SetSprite(spr->patch);
1001         sprh = spriteheights[spr->patch];
1002         p2h = FindNextPower2(sprh);
1003
1004 //      v1[VX] = FIX2FLT(spr->gx);
1005         //v1[VY] = FIX2FLT(spr->gy);
1006
1007         // Set the lighting and alpha.
1008         if(spr->mobjflags & MF_SHADOW)
1009                 alpha = .333f;
1010         else if(spr->mobjflags & MF_ALTSHADOW)
1011                 alpha = .666f;
1012         else
1013                 alpha = 1;
1014
1015         if(spr->lightlevel < 0)
1016                 glColor4f(1, 1, 1, alpha);
1017         else
1018         {
1019                 v1[VX] = Q_FIX2FLT(spr->gx);
1020                 v1[VY] = Q_FIX2FLT(spr->gy);
1021                 SetVertexColor(spr->lightlevel/255.0, PointDist2D(v1), alpha);
1022         }
1023
1024 /*      thangle = BANG2RAD(bamsAtan2((v1[VY]-vz)*10,(v1[VX]-vx)*10))-PI/2;
1025         sinrv = sin(thangle);
1026         cosrv = cos(thangle);*/
1027         
1028         // We must find the correct positioning using the sector floor and ceiling
1029         // heights as an aid.
1030         /*top = FIX2FLT(spr->gzt) + 4 - FIX2FLT(spr->floorclip);
1031         bot = top - sprh;*/
1032         top = FIX2FLT(spr->gzt);
1033         if(sprh < spr->secceil-spr->secfloor)   // Sprite fits in, adjustment possible?
1034         {
1035                 // Check top.
1036                 if(top > spr->secceil) top = spr->secceil;
1037                 // Check bottom.
1038                 if(top-sprh < spr->secfloor)
1039                         top = spr->secfloor+sprh;
1040         }
1041         // Adjust by the floor clip.
1042         top -= FIX2FLT(spr->floorclip);
1043         bot = top - sprh;
1044                 
1045 /*      v1[VX] -= cosrv*off;
1046         v1[VY] -= sinrv*off;
1047         v2[VX] = v1[VX] + cosrv*w;
1048         v2[VY] = v1[VY] + sinrv*w;*/
1049
1050         if(spr->xiscale < 0)
1051         {
1052                 // This is the flipped version.
1053                 tcleft = w/p2w;
1054                 tcright = 0;
1055         }
1056         else
1057         {
1058                 // No flipping; the normal version.
1059                 tcleft = 0;
1060                 tcright = w/p2w;
1061         }
1062
1063         // Choose the color for the sprite.
1064         /*glColor4f(1, 1, 1, (spr->mobjflags&MF_SHADOW)? .333 
1065                 : (spr->mobjflags&MF_ALTSHADOW)? .666 : 1);*/
1066
1067         glBegin(GL_QUADS);
1068         glTexCoord2f(tcleft, 0);
1069         glVertex3f(spr->v1[VX], top, spr->v1[VY]);
1070
1071         glTexCoord2f(tcright, 0);
1072         glVertex3f(spr->v2[VX], top, spr->v2[VY]);
1073
1074         glTexCoord2f(tcright, sprh/p2h);
1075         glVertex3f(spr->v2[VX], bot, spr->v2[VY]);
1076
1077         glTexCoord2f(tcleft, sprh/p2h);
1078         glVertex3f(spr->v1[VX], bot, spr->v1[VY]);
1079         glEnd();
1080 }
1081
1082 void OGL_DrawPSprite(int x, int y, float scale, int flip, int lump)
1083 {
1084         int             w,h;
1085         float   tcx, tcy;
1086
1087         OGL_SetSprite(lump);
1088         w = spritewidth[lump]>>FRACBITS;
1089         h = spriteheights[lump];
1090         tcx = NextPower2Ratio(w);
1091         tcy = NextPower2Ratio(h);
1092         
1093         glBegin(GL_QUADS);
1094
1095         glTexCoord2f((flip)? tcx : 0, 0);
1096         glVertex2f(x, y);
1097
1098         glTexCoord2f((flip)? 0 : tcx, 0);
1099         glVertex2f(x+w*scale, y);
1100
1101         glTexCoord2f((flip)? 0 : tcx, tcy);
1102         glVertex2f(x+w*scale, y+h*scale);
1103
1104         glTexCoord2f((flip)? tcx : 0, tcy);
1105         glVertex2f(x, y+h*scale);
1106
1107         glEnd();
1108 }
1109