]> icculus.org git repositories - theoddone33/hhexen.git/blob - opengl/ogl_rl.c
Initial revision
[theoddone33/hhexen.git] / opengl / ogl_rl.c
1
2 //**************************************************************************
3 //**
4 //** OGL_RL.C
5 //**
6 //**************************************************************************
7
8 // HEADER FILES ------------------------------------------------------------
9
10 #ifdef __WIN32
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
13 #endif
14
15 #include <math.h>
16 #include <GL/gl.h>
17 #include <stdlib.h>
18 #include "h2def.h"
19 #include "ogl_def.h"
20 #include "ogl_rl.h"
21
22 // MACROS ------------------------------------------------------------------
23
24 // TYPES -------------------------------------------------------------------
25
26 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
27
28 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
29
30 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
31
32 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
33
34 extern int                      skyhemispheres;
35 extern int                      dlMaxRad; // Dynamic lights maximum radius.
36
37 // PUBLIC DATA DEFINITIONS -------------------------------------------------
38
39 int numrlists=0;                        // Number of rendering lists.
40 float maxLightDist = 1024;
41
42 // PRIVATE DATA DEFINITIONS ------------------------------------------------
43
44 static rendlist_t *rlists=0;    // The list of rendering lists.
45 static rendlist_t masked_rlist; // Rendering list for masked textures.
46 static rendlist_t invsky_rlist; // List for invisible sky triangles.
47 static rendlist_t invskywall_rlist; // List for invisible sky walls (w/skyfix).
48 static rendlist_t dlwall_rlist, dlflat_rlist; // Dynamic lighting for walls/flats.
49
50 // CODE --------------------------------------------------------------------
51
52 void RL_Init()
53 {
54         numrlists = 0;
55         rlists = 0;
56         memset(&masked_rlist, 0, sizeof(masked_rlist));
57         memset(&invsky_rlist, 0, sizeof(invsky_rlist));
58         memset(&invskywall_rlist, 0, sizeof(invskywall_rlist));
59         memset(&dlwall_rlist, 0, sizeof(dlwall_rlist));
60         memset(&dlflat_rlist, 0, sizeof(dlflat_rlist));
61 }
62
63 void RL_DestroyList(rendlist_t *rl)
64 {
65         // All the list data will be destroyed.
66         free(rl->quads);
67         memset(rl, 0, sizeof(rendlist_t));
68 }
69
70 void RL_DeleteLists()
71 {
72         int             i;
73
74         // Delete all lists.
75         for(i=0; i<numrlists; i++) RL_DestroyList(rlists+i);
76         RL_DestroyList(&masked_rlist);
77         RL_DestroyList(&invsky_rlist);
78         RL_DestroyList(&invskywall_rlist);
79         RL_DestroyList(&dlwall_rlist);
80         RL_DestroyList(&dlflat_rlist);
81
82         free(rlists);
83         rlists = 0;
84         numrlists = 0;
85 }
86
87 // Reset the indices.
88 void RL_ClearLists()
89 {
90         int             i;
91         for(i=0; i<numrlists; i++) rlists[i].numquads = 0;
92         masked_rlist.numquads = 0;
93         invsky_rlist.numquads = 0;
94         invskywall_rlist.numquads = 0;
95         dlwall_rlist.numquads = 0;
96         dlflat_rlist.numquads = 0;
97         skyhemispheres = 0;
98 }
99
100 static void RL_DynLightQuad(rendquad_t *quad, lumobj_t *lum)
101 {
102         //rendquad_t    dlq;
103
104         // Prepare the texture so we know its dimensions.
105         OGL_PrepareLightTexture();
106 //      glBindTexture(GL_TEXTURE_2D, 0);
107         //glPointSize(5);
108         // Is the quad a wall or a flat?
109         if(quad->flags & RQF_FLAT)
110         {
111                 // Process all marked light sources.
112 /*              for(i=0; i<numLuminous; i++)
113                 {
114                         lumobj_t *lum = luminousList + i;*/
115
116                         // This is a light.
117                         quad->flags |= RQF_LIGHT;
118                         quad->texw = texw*2;
119                         quad->texh = texh*2;
120
121                         // Determine the light level.
122
123                         // The texture offset is what actually determines where the
124                         // dynamic light map will be rendered. For light quads the
125                         // texture offset is global.
126                         quad->texoffx = FIX2FLT(lum->thing->x) + dlMaxRad;
127                         quad->texoffy = FIX2FLT(lum->thing->y) + dlMaxRad;
128                         // Add a slight offset to the height to avoid Z buffer fighting.
129                         //quad->top += quad->flags & RQF_FLOOR_FACING? .5 : -.5;
130                         // Add the flat to the dlflat rendering list.                   
131                         //RL_AddQuad(&dlq, 0);
132
133                         /*glBegin(GL_POINTS);
134                         glColor3f(1, 1, 1);
135                         glVertex3f(FIX2FLT(lum->thing->x), FIX2FLT(lum->thing->y), z32);
136                         glEnd();*/
137 //              }
138         }
139 }
140
141 static rendlist_t *RL_FindList(GLuint tex)
142 {
143         int     i;
144         rendlist_t *dest;
145
146         for(i=0; i<numrlists; i++)
147                 if(rlists[i].tex == tex)
148                         return rlists+i;
149
150         // Then create a new list.
151         rlists = (rendlist_t*)realloc(rlists, sizeof(rendlist_t) * ++numrlists);
152         dest = rlists + numrlists-1;
153         memset(dest, 0, sizeof(rendlist_t));
154         dest->tex = tex;
155         return dest;
156 }
157
158 // Here we will add the quad to the correct rendering list, creating 
159 // a new list if necessary.
160 void RL_AddQuad(rendquad_t *quad, GLuint quadtex)
161 {
162         rendlist_t      *dest = 0;      // The destination list.
163         rendquad_t      *dq;            // Quad in the dest list.
164         
165         // Masked quads go to the masked list.
166         if(quad->flags & RQF_MASKED) 
167                 dest = &masked_rlist;
168         else if(quad->flags & RQF_SKY_MASK_WALL)
169                 dest = &invskywall_rlist;
170         else if(quad->flags & RQF_LIGHT) // Dynamic lights?
171                 dest = &dlwall_rlist;
172         else
173         {
174                 // Find a suitable list. This can get a bit redundant for large
175                 // numbers of primitives of the same texture (oh yeah, this is 
176                 // a real cycle-eater).
177                 dest = RL_FindList(quadtex);
178         }
179         // Now we have a destination list. This is the only place where
180         // quads are added. 
181         if(++dest->numquads > dest->listsize)           // See if we have to allocate more memory.
182         {
183                 dest->listsize = dest->numquads+10;             
184                 dest->quads = (rendquad_t*)realloc(dest->quads, 
185                         sizeof(rendquad_t) * dest->listsize);
186         }
187         dq = dest->quads + dest->numquads-1;
188         memcpy(dq, quad, sizeof(rendquad_t));
189         
190         // Let a masked quad know its texture.
191         if(quad->flags & RQF_MASKED) 
192         {
193                 dq->masktex = quadtex;
194                 if(!quadtex) I_Error("RL_AddQuad: There can't be a masked quad with no texture.\n");
195         }
196 }
197
198 subsector_t *currentssec;
199
200 // Adds a series of flat quads (triangles) as a fan.
201 void RL_AddFlatQuads(rendquad_t *base, GLuint quadtex, int numvrts, 
202                                          fvertex_t *origvrts, int dir)
203 {
204         fvertex_t       *vtx;
205         rendlist_t      *dest;
206         rendquad_t      *qi;
207         int                     i, firstquad;
208         float           *distances, middist;
209         fvertex_t       *vrts;
210
211         if(!numvrts) return;    // No data, can't do anything.
212
213         if(base->flags & RQF_SKY_MASK)
214                 dest = &invsky_rlist;
215         else if(base->flags & RQF_LIGHT)
216                 dest = &dlflat_rlist;
217         else
218                 // First find the right list.
219                 dest = RL_FindList(quadtex);
220         
221         // Check that there's enough room.
222         firstquad = dest->numquads;
223         dest->numquads += numvrts-2;
224         if(dest->numquads > dest->listsize)
225         {
226                 // Allocate more memory.
227                 dest->listsize = dest->numquads + 20;
228                 dest->quads = (rendquad_t*)realloc(dest->quads, 
229                         sizeof(rendquad_t) * dest->listsize);   
230         }
231
232         // Calculate the distance to each vertex.
233         distances = _alloca(sizeof(float)*numvrts);
234         for(i=0; i<numvrts; i++) distances[i] = PointDist2D(&origvrts[i].x);
235         
236         // Make a distance modification.
237         vrts = _alloca(sizeof(fvertex_t)*numvrts);
238         memcpy(vrts, origvrts, sizeof(fvertex_t)*numvrts);      
239         middist = PointDist2D(&currentssec->midpoint.x);
240         if(!(base->flags & RQF_LIGHT) && middist > 256)
241         {
242                 for(i=0; i<numvrts; i++)
243                 {
244                         float dx = vrts[i].x - currentssec->midpoint.x,
245                                 dy = vrts[i].y - currentssec->midpoint.y,
246                                 dlen = sqrt(dx*dx + dy*dy);
247                         if(!dlen) continue;
248                         vrts[i].x += dx/dlen * (middist-256)/128;
249                         vrts[i].y += dy/dlen * (middist-256)/128;
250                 }
251         }
252
253         // Add them as a fan.
254         if(dir == 0)    // Normal direction.
255         {
256                 // All triangles share the first vertex.
257                 base->v1[VX] = vrts->x; 
258                 base->v1[VY] = vrts->y;
259                 base->dist[0] = distances[0];
260
261                 for(i=2, qi=dest->quads+firstquad; i<numvrts; i++, qi++)
262                 {
263                         memcpy(qi, base, sizeof(rendquad_t));
264                         // The second vertex is the previous from this one.
265                         vtx = vrts+i-1;
266                         qi->v2[VX] = vtx->x;
267                         qi->v2[VY] = vtx->y;
268                         qi->dist[1] = distances[i-1];
269                         // The third vertex is naturally the current one.
270                         vtx = vrts+i;
271                         qi->u.v3[VX] = vtx->x;
272                         qi->u.v3[VY] = vtx->y;
273                         qi->dist[2] = distances[i];
274                         
275                         if(base->flags & RQF_LIGHT) RL_DynLightQuad(qi, (lumobj_t*)quadtex);
276                 }
277         }
278         else    // Reverse direction?
279         {
280                 // All triangles share the last vertex.
281                 vtx = vrts + numvrts-1;
282                 base->v1[VX] = vtx->x;
283                 base->v1[VY] = vtx->y;
284                 base->dist[0] = distances[numvrts-1];
285
286                 for(i=numvrts-3, qi=dest->quads+firstquad; i>=0; i--, qi++)
287                 {
288                         memcpy(qi, base, sizeof(rendquad_t));
289                         // The second vertex is the next from this one.
290                         vtx = vrts+i+1;
291                         qi->v2[VX] = vtx->x;
292                         qi->v2[VY] = vtx->y;
293                         qi->dist[1] = distances[i+1];
294                         // The third vertex is naturally the current one.
295                         vtx = vrts+i;
296                         qi->u.v3[VX] = vtx->x;
297                         qi->u.v3[VY] = vtx->y;
298                         qi->dist[2] = distances[i];
299
300 //                      if(useDynLights) RL_DynLightQuad(qi);
301                         if(base->flags & RQF_LIGHT) RL_DynLightQuad(qi, (lumobj_t*)quadtex);
302                 }
303         }       
304 }
305
306 void SetVertexColor(float light, float dist, float alpha)
307 {
308         float real = light - (dist-32)/maxLightDist * (1-light);
309         float minimum = light*light + (light-.63)/2;
310         if(real < minimum) real = minimum; // Clamp it.
311         // Add extra light.
312         real += extralight/16.0;
313         // Check for torch.
314         if(viewplayer->fixedcolormap)
315         {
316                 // Colormap 1 is the brightest. I'm guessing 16 would be the darkest.
317                 int ll = 16-viewplayer->fixedcolormap;
318                 float d = (1024-dist)/512.0;
319                 float newmin = d*ll/15.0;
320                 if(real < newmin) real = newmin;
321         }
322         glColor4f(real, real, real, alpha);     // Too real? Hope real gets clamped.
323 }
324
325 // This is only for solid, non-masked primitives.
326 void RL_RenderList(rendlist_t *rl)
327 {
328         int                     i;
329         float           tcleft, tcright, tctop, tcbottom;
330         rendquad_t      *cq;
331
332         if(!rl->numquads) return;       // The list is empty.
333
334         // Bind the right texture.
335         glBindTexture(GL_TEXTURE_2D, curtex=rl->tex);
336
337         // Check what kind of primitives there are on the list.
338         // There can only be one kind on each list.
339         if(rl->quads->flags & RQF_FLAT) // Check the first primitive.
340         {
341                 // There's only triangles here, I see.                          
342                 glBegin(GL_TRIANGLES);
343                 for(i=0; i<rl->numquads; i++)
344                 {
345                         cq = rl->quads+i;
346                         if(cq->flags & RQF_MISSING_WALL)
347                         {
348                                 // This triangle is REALLY a quad that originally had no 
349                                 // texture. We have to render it as two triangles.
350                                 tcright = (tcleft=0) + cq->u.q.len/cq->texw;
351                                 tcbottom = (tctop=0) + (cq->top - cq->u.q.bottom)/cq->texh;
352                                 
353                                 SetVertexColor(cq->light, cq->dist[0], 1);
354                                 glTexCoord2f(tcleft, tctop);
355                                 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
356
357                                 SetVertexColor(cq->light, cq->dist[1], 1);
358                                 glTexCoord2f(tcright, tctop);
359                                 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
360
361                                 glTexCoord2f(tcright, tcbottom);
362                                 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
363
364                                 // The other triangle.
365                                 glTexCoord2f(tcright, tcbottom);
366                                 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
367
368                                 SetVertexColor(cq->light, cq->dist[0], 1);
369                                 glTexCoord2f(tcleft, tcbottom);
370                                 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
371
372                                 glTexCoord2f(tcleft, tctop);
373                                 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
374                                 continue;
375                         }
376
377                         // The vertices.
378                         SetVertexColor(cq->light, cq->dist[0], 1);
379                         glTexCoord2f((cq->v1[VX]+cq->texoffx)/cq->texw,
380                                 (cq->v1[VY]+cq->texoffy)/cq->texh);
381                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
382
383                         SetVertexColor(cq->light, cq->dist[1], 1);
384                         glTexCoord2f((cq->v2[VX]+cq->texoffx)/cq->texw,
385                                 (cq->v2[VY]+cq->texoffy)/cq->texh);
386                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
387
388                         SetVertexColor(cq->light, cq->dist[2], 1);
389                         glTexCoord2f((cq->u.v3[VX]+cq->texoffx)/cq->texw,
390                                 (cq->u.v3[VY]+cq->texoffy)/cq->texh);
391                         glVertex3f(cq->u.v3[VX], cq->top, cq->u.v3[VY]);
392                 }
393                 glEnd();
394         }
395         else
396         {
397                 // Render quads.
398                 glBegin(GL_QUADS);
399                 for(i=0; i<rl->numquads; i++)
400                 {
401                         cq = rl->quads+i;
402
403                         // Calculate relative texture coordinates.
404                         tcright = (tcleft=cq->texoffx/(float)cq->texw) + cq->u.q.len/cq->texw;
405                         tcbottom = (tctop=cq->texoffy/cq->texh) + (cq->top - cq->u.q.bottom)/cq->texh;
406
407                         // The vertices.
408                         SetVertexColor(cq->light, cq->dist[0], 1);
409                         glTexCoord2f(tcleft, tcbottom);
410                         glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
411
412                         glTexCoord2f(tcleft, tctop);
413                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
414
415                         SetVertexColor(cq->light, cq->dist[1], 1);
416                         glTexCoord2f(tcright, tctop);
417                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
418
419                         glTexCoord2f(tcright, tcbottom);
420                         glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
421                 }
422                 glEnd();
423         }
424 }
425
426 // Masked lists only include quads.
427 void RL_RenderMaskedList(rendlist_t *mrl)
428 {
429         int                     i;
430         float           tcleft, tcright, tctop, tcbottom;
431         rendquad_t      *cq;
432         
433         if(!mrl->numquads) return;      // No quads to render, I'm afraid.
434
435         // Curtex is used to keep track of the current texture.
436         // Zero also denotes that no glBegin() has yet been called.
437         curtex = 0;
438
439         // Render quads.
440         for(i=mrl->numquads-1; i>=0; i--)       // Render back to front.
441         {
442                 cq = mrl->quads+i;
443
444                 // Calculate relative texture coordinates.
445                 tcright = (tcleft=cq->texoffx/cq->texw) + cq->u.q.len/cq->texw;
446                 tcbottom = (tctop=cq->texoffy/cq->texh) + (cq->top - cq->u.q.bottom)/cq->texh;
447
448                 // Is there a need to change the texture?
449                 if(curtex != cq->masktex)       
450                 {
451                         if(curtex) glEnd();     // Finish with the old texture.
452                         glBindTexture(GL_TEXTURE_2D, curtex=cq->masktex);
453                         glBegin(GL_QUADS);      // I love OpenGL.
454                 }
455                 
456                 // The vertices.
457                 SetVertexColor(cq->light, cq->dist[0], 1);
458                 glTexCoord2f(tcleft, tcbottom);
459                 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
460
461                 glTexCoord2f(tcleft, tctop);
462                 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
463
464                 SetVertexColor(cq->light, cq->dist[1], 1);
465                 glTexCoord2f(tcright, tctop);
466                 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
467
468                 glTexCoord2f(tcright, tcbottom);
469                 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
470         }
471         if(curtex) glEnd();     // If something was drawn, finish with it.
472 }
473
474 void RL_RenderSkyMaskLists()
475 {
476 #if 0
477         int                     i;
478         rendlist_t      *smrl = &invsky_rlist, *skyw = &invskywall_rlist;
479         rendquad_t      *cq;
480
481         if(!smrl->numquads && !skyw->numquads) return; // Nothing to do here.
482
483         // Nothing gets written to the color buffer.
484
485     // NOTE: glEnd() below causes segfault in Mesa 3.0 if binding texture 0.
486     // I don't think texture 0 is defined when this is called.
487         //glBindTexture(GL_TEXTURE_2D, 0);
488     glDisable( GL_TEXTURE_2D );
489
490         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
491         glColor4f(1, 1, 1, 1);  // Just to be sure.
492
493
494         if(smrl->numquads)
495         {
496                 glBegin(GL_TRIANGLES);
497                 for(i=0; i<smrl->numquads; i++)
498                 {
499                         cq = smrl->quads+i;
500                         // ONLY the vertices, please.
501                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
502                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
503                         glVertex3f(cq->u.v3[VX], cq->top, cq->u.v3[VY]);
504                 }
505                 glEnd();                
506         }
507
508         // Then the walls.
509         if(skyw->numquads)
510         {
511                 glBegin(GL_QUADS);
512                 for(i=0; i<skyw->numquads; i++)
513                 {
514                         cq = skyw->quads + i;
515                         // Only the verts.
516                         glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
517                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
518                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
519                         glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
520                 }
521                 glEnd();
522         }
523
524     glEnable( GL_TEXTURE_2D );
525
526         // Restore normal write mode.
527         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
528 #endif
529 }
530
531 void RL_RenderDynLightLists()
532 {
533         int                     i;
534         rendlist_t      *frl = &dlflat_rlist, *wrl = &dlwall_rlist;
535         rendquad_t      *cq;
536
537         if(!frl->numquads && !wrl->numquads) return; // Nothing to do.
538
539         // Setup the correct rendering state.   
540         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
541         // Disable fog.
542         glDisable(GL_FOG);
543         // This'll allow multiple light quads to be rendered on top of each other.
544         glDepthMask(GL_FALSE); 
545         glDepthFunc(GL_LEQUAL);
546         // Set up addition blending. The source is added to the destination.
547         glBlendFunc(GL_DST_COLOR, GL_ONE);
548
549         // The light texture.
550         glBindTexture(GL_TEXTURE_2D, curtex=OGL_PrepareLightTexture());
551
552         // The flats.
553         if(frl->numquads)
554         {
555                 glBegin(GL_TRIANGLES);
556                 for(i=0; i<frl->numquads; i++)
557                 {
558                         cq = frl->quads + i;
559                         // Set the color.
560                         glColor3f(cq->light, cq->light, cq->light);
561                         // The vertices.                        
562                         glTexCoord2f((cq->texoffx - cq->v1[VX])/cq->texw,
563                                 (cq->texoffy - cq->v1[VY])/cq->texh);
564                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
565
566                         glTexCoord2f((cq->texoffx - cq->v2[VX])/cq->texw,
567                                 (cq->texoffy - cq->v2[VY])/cq->texh);
568                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
569
570                         glTexCoord2f((cq->texoffx - cq->u.v3[VX])/cq->texw,
571                                 (cq->texoffy - cq->u.v3[VY])/cq->texh);
572                         glVertex3f(cq->u.v3[VX], cq->top, cq->u.v3[VY]);
573                 }
574                 glEnd();
575         }       
576
577         // The walls.
578         if(wrl->numquads)
579         {
580                 float tctl[2], tcbr[2]; // Top left and bottom right.
581                 glBegin(GL_QUADS);
582                 for(i=0; i<wrl->numquads; i++)
583                 {
584                         cq = wrl->quads + i;
585                         // Set the color.
586                         glColor3f(cq->light, cq->light, cq->light);
587
588                         // Calculate the texture coordinates.
589                         tcbr[VX] = (tctl[VX]=-cq->texoffx/cq->texw) + cq->u.q.len/cq->texw;
590                         tcbr[VY] = (tctl[VY]=cq->texoffy/cq->texh) + (cq->top - cq->u.q.bottom)/cq->texh;
591
592                         // The vertices.
593                         glTexCoord2f(tctl[VX], tcbr[VY]);
594                         glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
595
596                         glTexCoord2f(tctl[VX], tctl[VY]);
597                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
598
599                         glTexCoord2f(tcbr[VX], tctl[VY]);
600                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
601
602                         glTexCoord2f(tcbr[VX], tcbr[VY]);
603                         glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
604                 }
605                 glEnd();
606         }
607
608         // Restore the original rendering state.
609         glPopAttrib();
610 }
611
612
613 void RL_RenderAllLists()
614 {
615         int     i;
616
617         // The sky might be visible. Render the needed hemispheres.
618         R_RenderSkyHemispheres(skyhemispheres);                         
619         RL_RenderSkyMaskLists(); //&invsky_rlist, &invskywall_rlist);
620         for(i=0; i<numrlists; i++) RL_RenderList(rlists+i);
621         RL_RenderDynLightLists();
622         RL_RenderMaskedList(&masked_rlist);
623 }
624