]> icculus.org git repositories - theoddone33/hhexen.git/blob - opengl/ogl_rl.c
osezer patch 008
[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 = (float *)malloc(sizeof(float)*numvrts);
234         for(i=0; i<numvrts; i++) distances[i] = PointDist2D(&origvrts[i].x);
235         
236         // Make a distance modification.
237         vrts = (fvertex_t *)malloc(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         free (vrts);
305         free (distances);
306 }
307
308 void SetVertexColor(float light, float dist, float alpha)
309 {
310         float real = light - (dist-32)/maxLightDist * (1-light);
311         float minimum = light*light + (light-.63)/2;
312         if(real < minimum) real = minimum; // Clamp it.
313         // Add extra light.
314         real += extralight/16.0;
315         // Check for torch.
316         if(viewplayer->fixedcolormap)
317         {
318                 // Colormap 1 is the brightest. I'm guessing 16 would be the darkest.
319                 int ll = 16-viewplayer->fixedcolormap;
320                 float d = (1024-dist)/512.0;
321                 float newmin = d*ll/15.0;
322                 if(real < newmin) real = newmin;
323         }
324         glColor4f(real, real, real, alpha);     // Too real? Hope real gets clamped.
325 }
326
327 // This is only for solid, non-masked primitives.
328 void RL_RenderList(rendlist_t *rl)
329 {
330         int                     i;
331         float           tcleft, tcright, tctop, tcbottom;
332         rendquad_t      *cq;
333
334         if(!rl->numquads) return;       // The list is empty.
335
336         // Bind the right texture.
337         glBindTexture(GL_TEXTURE_2D, curtex=rl->tex);
338
339         // Check what kind of primitives there are on the list.
340         // There can only be one kind on each list.
341         if(rl->quads->flags & RQF_FLAT) // Check the first primitive.
342         {
343                 // There's only triangles here, I see.                          
344                 glBegin(GL_TRIANGLES);
345                 for(i=0; i<rl->numquads; i++)
346                 {
347                         cq = rl->quads+i;
348                         if(cq->flags & RQF_MISSING_WALL)
349                         {
350                                 // This triangle is REALLY a quad that originally had no 
351                                 // texture. We have to render it as two triangles.
352                                 tcright = (tcleft=0) + cq->u.q.len/cq->texw;
353                                 tcbottom = (tctop=0) + (cq->top - cq->u.q.bottom)/cq->texh;
354                                 
355                                 SetVertexColor(cq->light, cq->dist[0], 1);
356                                 glTexCoord2f(tcleft, tctop);
357                                 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
358
359                                 SetVertexColor(cq->light, cq->dist[1], 1);
360                                 glTexCoord2f(tcright, tctop);
361                                 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
362
363                                 glTexCoord2f(tcright, tcbottom);
364                                 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
365
366                                 // The other triangle.
367                                 glTexCoord2f(tcright, tcbottom);
368                                 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
369
370                                 SetVertexColor(cq->light, cq->dist[0], 1);
371                                 glTexCoord2f(tcleft, tcbottom);
372                                 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
373
374                                 glTexCoord2f(tcleft, tctop);
375                                 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
376                                 continue;
377                         }
378
379                         // The vertices.
380                         SetVertexColor(cq->light, cq->dist[0], 1);
381                         glTexCoord2f((cq->v1[VX]+cq->texoffx)/cq->texw,
382                                 (cq->v1[VY]+cq->texoffy)/cq->texh);
383                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
384
385                         SetVertexColor(cq->light, cq->dist[1], 1);
386                         glTexCoord2f((cq->v2[VX]+cq->texoffx)/cq->texw,
387                                 (cq->v2[VY]+cq->texoffy)/cq->texh);
388                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
389
390                         SetVertexColor(cq->light, cq->dist[2], 1);
391                         glTexCoord2f((cq->u.v3[VX]+cq->texoffx)/cq->texw,
392                                 (cq->u.v3[VY]+cq->texoffy)/cq->texh);
393                         glVertex3f(cq->u.v3[VX], cq->top, cq->u.v3[VY]);
394                 }
395                 glEnd();
396         }
397         else
398         {
399                 // Render quads.
400                 glBegin(GL_QUADS);
401                 for(i=0; i<rl->numquads; i++)
402                 {
403                         cq = rl->quads+i;
404
405                         // Calculate relative texture coordinates.
406                         tcright = (tcleft=cq->texoffx/(float)cq->texw) + cq->u.q.len/cq->texw;
407                         tcbottom = (tctop=cq->texoffy/cq->texh) + (cq->top - cq->u.q.bottom)/cq->texh;
408
409                         // The vertices.
410                         SetVertexColor(cq->light, cq->dist[0], 1);
411                         glTexCoord2f(tcleft, tcbottom);
412                         glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
413
414                         glTexCoord2f(tcleft, tctop);
415                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
416
417                         SetVertexColor(cq->light, cq->dist[1], 1);
418                         glTexCoord2f(tcright, tctop);
419                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
420
421                         glTexCoord2f(tcright, tcbottom);
422                         glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
423                 }
424                 glEnd();
425         }
426 }
427
428 // Masked lists only include quads.
429 void RL_RenderMaskedList(rendlist_t *mrl)
430 {
431         int                     i;
432         float           tcleft, tcright, tctop, tcbottom;
433         rendquad_t      *cq;
434         
435         if(!mrl->numquads) return;      // No quads to render, I'm afraid.
436
437         // Curtex is used to keep track of the current texture.
438         // Zero also denotes that no glBegin() has yet been called.
439         curtex = 0;
440
441         // Render quads.
442         for(i=mrl->numquads-1; i>=0; i--)       // Render back to front.
443         {
444                 cq = mrl->quads+i;
445
446                 // Calculate relative texture coordinates.
447                 tcright = (tcleft=cq->texoffx/cq->texw) + cq->u.q.len/cq->texw;
448                 tcbottom = (tctop=cq->texoffy/cq->texh) + (cq->top - cq->u.q.bottom)/cq->texh;
449
450                 // Is there a need to change the texture?
451                 if(curtex != cq->masktex)       
452                 {
453                         if(curtex) glEnd();     // Finish with the old texture.
454                         glBindTexture(GL_TEXTURE_2D, curtex=cq->masktex);
455                         glBegin(GL_QUADS);      // I love OpenGL.
456                 }
457                 
458                 // The vertices.
459                 SetVertexColor(cq->light, cq->dist[0], 1);
460                 glTexCoord2f(tcleft, tcbottom);
461                 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
462
463                 glTexCoord2f(tcleft, tctop);
464                 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
465
466                 SetVertexColor(cq->light, cq->dist[1], 1);
467                 glTexCoord2f(tcright, tctop);
468                 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
469
470                 glTexCoord2f(tcright, tcbottom);
471                 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
472         }
473         if(curtex) glEnd();     // If something was drawn, finish with it.
474 }
475
476 void RL_RenderSkyMaskLists()
477 {
478 #if 0
479         int                     i;
480         rendlist_t      *smrl = &invsky_rlist, *skyw = &invskywall_rlist;
481         rendquad_t      *cq;
482
483         if(!smrl->numquads && !skyw->numquads) return; // Nothing to do here.
484
485         // Nothing gets written to the color buffer.
486
487     // NOTE: glEnd() below causes segfault in Mesa 3.0 if binding texture 0.
488     // I don't think texture 0 is defined when this is called.
489         //glBindTexture(GL_TEXTURE_2D, 0);
490     glDisable( GL_TEXTURE_2D );
491
492         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
493         glColor4f(1, 1, 1, 1);  // Just to be sure.
494
495
496         if(smrl->numquads)
497         {
498                 glBegin(GL_TRIANGLES);
499                 for(i=0; i<smrl->numquads; i++)
500                 {
501                         cq = smrl->quads+i;
502                         // ONLY the vertices, please.
503                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
504                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
505                         glVertex3f(cq->u.v3[VX], cq->top, cq->u.v3[VY]);
506                 }
507                 glEnd();                
508         }
509
510         // Then the walls.
511         if(skyw->numquads)
512         {
513                 glBegin(GL_QUADS);
514                 for(i=0; i<skyw->numquads; i++)
515                 {
516                         cq = skyw->quads + i;
517                         // Only the verts.
518                         glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
519                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
520                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
521                         glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
522                 }
523                 glEnd();
524         }
525
526     glEnable( GL_TEXTURE_2D );
527
528         // Restore normal write mode.
529         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
530 #endif
531 }
532
533 void RL_RenderDynLightLists()
534 {
535         int                     i;
536         rendlist_t      *frl = &dlflat_rlist, *wrl = &dlwall_rlist;
537         rendquad_t      *cq;
538
539         if(!frl->numquads && !wrl->numquads) return; // Nothing to do.
540
541         // Setup the correct rendering state.   
542         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
543         // Disable fog.
544         glDisable(GL_FOG);
545         // This'll allow multiple light quads to be rendered on top of each other.
546         glDepthMask(GL_FALSE); 
547         glDepthFunc(GL_LEQUAL);
548         // Set up addition blending. The source is added to the destination.
549         glBlendFunc(GL_DST_COLOR, GL_ONE);
550
551         // The light texture.
552         glBindTexture(GL_TEXTURE_2D, curtex=OGL_PrepareLightTexture());
553
554         // The flats.
555         if(frl->numquads)
556         {
557                 glBegin(GL_TRIANGLES);
558                 for(i=0; i<frl->numquads; i++)
559                 {
560                         cq = frl->quads + i;
561                         // Set the color.
562                         glColor3f(cq->light, cq->light, cq->light);
563                         // The vertices.                        
564                         glTexCoord2f((cq->texoffx - cq->v1[VX])/cq->texw,
565                                 (cq->texoffy - cq->v1[VY])/cq->texh);
566                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
567
568                         glTexCoord2f((cq->texoffx - cq->v2[VX])/cq->texw,
569                                 (cq->texoffy - cq->v2[VY])/cq->texh);
570                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
571
572                         glTexCoord2f((cq->texoffx - cq->u.v3[VX])/cq->texw,
573                                 (cq->texoffy - cq->u.v3[VY])/cq->texh);
574                         glVertex3f(cq->u.v3[VX], cq->top, cq->u.v3[VY]);
575                 }
576                 glEnd();
577         }       
578
579         // The walls.
580         if(wrl->numquads)
581         {
582                 float tctl[2], tcbr[2]; // Top left and bottom right.
583                 glBegin(GL_QUADS);
584                 for(i=0; i<wrl->numquads; i++)
585                 {
586                         cq = wrl->quads + i;
587                         // Set the color.
588                         glColor3f(cq->light, cq->light, cq->light);
589
590                         // Calculate the texture coordinates.
591                         tcbr[VX] = (tctl[VX]=-cq->texoffx/cq->texw) + cq->u.q.len/cq->texw;
592                         tcbr[VY] = (tctl[VY]=cq->texoffy/cq->texh) + (cq->top - cq->u.q.bottom)/cq->texh;
593
594                         // The vertices.
595                         glTexCoord2f(tctl[VX], tcbr[VY]);
596                         glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
597
598                         glTexCoord2f(tctl[VX], tctl[VY]);
599                         glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
600
601                         glTexCoord2f(tcbr[VX], tctl[VY]);
602                         glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
603
604                         glTexCoord2f(tcbr[VX], tcbr[VY]);
605                         glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
606                 }
607                 glEnd();
608         }
609
610         // Restore the original rendering state.
611         glPopAttrib();
612 }
613
614
615 void RL_RenderAllLists()
616 {
617         int     i;
618
619         // The sky might be visible. Render the needed hemispheres.
620         R_RenderSkyHemispheres(skyhemispheres);                         
621         RL_RenderSkyMaskLists(); //&invsky_rlist, &invskywall_rlist);
622         for(i=0; i<numrlists; i++) RL_RenderList(rlists+i);
623         RL_RenderDynLightLists();
624         RL_RenderMaskedList(&masked_rlist);
625 }
626