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