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