2 //**************************************************************************
6 //**************************************************************************
8 // HEADER FILES ------------------------------------------------------------
11 #define WIN32_LEAN_AND_MEAN
22 // MACROS ------------------------------------------------------------------
24 // TYPES -------------------------------------------------------------------
26 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
28 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
30 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
32 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
34 extern int skyhemispheres;
35 extern int dlMaxRad; // Dynamic lights maximum radius.
37 // PUBLIC DATA DEFINITIONS -------------------------------------------------
39 int numrlists=0; // Number of rendering lists.
40 float maxLightDist = 1024;
42 // PRIVATE DATA DEFINITIONS ------------------------------------------------
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.
50 // CODE --------------------------------------------------------------------
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));
63 void RL_DestroyList(rendlist_t *rl)
65 // All the list data will be destroyed.
67 memset(rl, 0, sizeof(rendlist_t));
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);
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;
100 static void RL_DynLightQuad(rendquad_t *quad, lumobj_t *lum)
104 // Prepare the texture so we know its dimensions.
105 OGL_PrepareLightTexture();
106 // glBindTexture(GL_TEXTURE_2D, 0);
108 // Is the quad a wall or a flat?
109 if(quad->flags & RQF_FLAT)
111 // Process all marked light sources.
112 /* for(i=0; i<numLuminous; i++)
114 lumobj_t *lum = luminousList + i;*/
117 quad->flags |= RQF_LIGHT;
121 // Determine the light level.
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);
133 /*glBegin(GL_POINTS);
135 glVertex3f(FIX2FLT(lum->thing->x), FIX2FLT(lum->thing->y), z32);
141 static rendlist_t *RL_FindList(GLuint tex)
146 for(i=0; i<numrlists; i++)
147 if(rlists[i].tex == tex)
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));
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)
162 rendlist_t *dest = 0; // The destination list.
163 rendquad_t *dq; // Quad in the dest list.
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;
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);
179 // Now we have a destination list. This is the only place where
181 if(++dest->numquads > dest->listsize) // See if we have to allocate more memory.
183 dest->listsize = dest->numquads+10;
184 dest->quads = (rendquad_t*)realloc(dest->quads,
185 sizeof(rendquad_t) * dest->listsize);
187 dq = dest->quads + dest->numquads-1;
188 memcpy(dq, quad, sizeof(rendquad_t));
190 // Let a masked quad know its texture.
191 if(quad->flags & RQF_MASKED)
193 dq->masktex = quadtex;
194 if(!quadtex) I_Error("RL_AddQuad: There can't be a masked quad with no texture.\n");
198 subsector_t *currentssec;
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)
208 float *distances, middist;
211 if(!numvrts) return; // No data, can't do anything.
213 if(base->flags & RQF_SKY_MASK)
214 dest = &invsky_rlist;
215 else if(base->flags & RQF_LIGHT)
216 dest = &dlflat_rlist;
218 // First find the right list.
219 dest = RL_FindList(quadtex);
221 // Check that there's enough room.
222 firstquad = dest->numquads;
223 dest->numquads += numvrts-2;
224 if(dest->numquads > dest->listsize)
226 // Allocate more memory.
227 dest->listsize = dest->numquads + 20;
228 dest->quads = (rendquad_t*)realloc(dest->quads,
229 sizeof(rendquad_t) * dest->listsize);
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);
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(¤tssec->midpoint.x);
240 if(!(base->flags & RQF_LIGHT) && middist > 256)
242 for(i=0; i<numvrts; i++)
244 float dx = vrts[i].x - currentssec->midpoint.x,
245 dy = vrts[i].y - currentssec->midpoint.y,
246 dlen = sqrt(dx*dx + dy*dy);
248 vrts[i].x += dx/dlen * (middist-256)/128;
249 vrts[i].y += dy/dlen * (middist-256)/128;
253 // Add them as a fan.
254 if(dir == 0) // Normal direction.
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];
261 for(i=2, qi=dest->quads+firstquad; i<numvrts; i++, qi++)
263 memcpy(qi, base, sizeof(rendquad_t));
264 // The second vertex is the previous from this one.
268 qi->dist[1] = distances[i-1];
269 // The third vertex is naturally the current one.
271 qi->u.v3[VX] = vtx->x;
272 qi->u.v3[VY] = vtx->y;
273 qi->dist[2] = distances[i];
275 if(base->flags & RQF_LIGHT) RL_DynLightQuad(qi, (lumobj_t*)quadtex);
278 else // Reverse direction?
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];
286 for(i=numvrts-3, qi=dest->quads+firstquad; i>=0; i--, qi++)
288 memcpy(qi, base, sizeof(rendquad_t));
289 // The second vertex is the next from this one.
293 qi->dist[1] = distances[i+1];
294 // The third vertex is naturally the current one.
296 qi->u.v3[VX] = vtx->x;
297 qi->u.v3[VY] = vtx->y;
298 qi->dist[2] = distances[i];
300 // if(useDynLights) RL_DynLightQuad(qi);
301 if(base->flags & RQF_LIGHT) RL_DynLightQuad(qi, (lumobj_t*)quadtex);
308 void SetVertexColor(float light, float dist, float alpha)
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.
314 real += extralight/16.0;
316 if(viewplayer->fixedcolormap)
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;
324 glColor4f(real, real, real, alpha); // Too real? Hope real gets clamped.
327 // This is only for solid, non-masked primitives.
328 void RL_RenderList(rendlist_t *rl)
331 float tcleft, tcright, tctop, tcbottom;
334 if(!rl->numquads) return; // The list is empty.
336 // Bind the right texture.
337 glBindTexture(GL_TEXTURE_2D, curtex=rl->tex);
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.
343 // There's only triangles here, I see.
344 glBegin(GL_TRIANGLES);
345 for(i=0; i<rl->numquads; i++)
348 if(cq->flags & RQF_MISSING_WALL)
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;
355 SetVertexColor(cq->light, cq->dist[0], 1);
356 glTexCoord2f(tcleft, tctop);
357 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
359 SetVertexColor(cq->light, cq->dist[1], 1);
360 glTexCoord2f(tcright, tctop);
361 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
363 glTexCoord2f(tcright, tcbottom);
364 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
366 // The other triangle.
367 glTexCoord2f(tcright, tcbottom);
368 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
370 SetVertexColor(cq->light, cq->dist[0], 1);
371 glTexCoord2f(tcleft, tcbottom);
372 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
374 glTexCoord2f(tcleft, tctop);
375 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
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]);
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]);
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]);
401 for(i=0; i<rl->numquads; i++)
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;
410 SetVertexColor(cq->light, cq->dist[0], 1);
411 glTexCoord2f(tcleft, tcbottom);
412 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
414 glTexCoord2f(tcleft, tctop);
415 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
417 SetVertexColor(cq->light, cq->dist[1], 1);
418 glTexCoord2f(tcright, tctop);
419 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
421 glTexCoord2f(tcright, tcbottom);
422 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
428 // Masked lists only include quads.
429 void RL_RenderMaskedList(rendlist_t *mrl)
432 float tcleft, tcright, tctop, tcbottom;
435 if(!mrl->numquads) return; // No quads to render, I'm afraid.
437 // Curtex is used to keep track of the current texture.
438 // Zero also denotes that no glBegin() has yet been called.
442 for(i=mrl->numquads-1; i>=0; i--) // Render back to front.
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;
450 // Is there a need to change the texture?
451 if(curtex != cq->masktex)
453 if(curtex) glEnd(); // Finish with the old texture.
454 glBindTexture(GL_TEXTURE_2D, curtex=cq->masktex);
455 glBegin(GL_QUADS); // I love OpenGL.
459 SetVertexColor(cq->light, cq->dist[0], 1);
460 glTexCoord2f(tcleft, tcbottom);
461 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
463 glTexCoord2f(tcleft, tctop);
464 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
466 SetVertexColor(cq->light, cq->dist[1], 1);
467 glTexCoord2f(tcright, tctop);
468 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
470 glTexCoord2f(tcright, tcbottom);
471 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
473 if(curtex) glEnd(); // If something was drawn, finish with it.
476 void RL_RenderSkyMaskLists()
480 rendlist_t *smrl = &invsky_rlist, *skyw = &invskywall_rlist;
483 if(!smrl->numquads && !skyw->numquads) return; // Nothing to do here.
485 // Nothing gets written to the color buffer.
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 );
492 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
493 glColor4f(1, 1, 1, 1); // Just to be sure.
498 glBegin(GL_TRIANGLES);
499 for(i=0; i<smrl->numquads; 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]);
514 for(i=0; i<skyw->numquads; i++)
516 cq = skyw->quads + i;
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]);
526 glEnable( GL_TEXTURE_2D );
528 // Restore normal write mode.
529 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
533 void RL_RenderDynLightLists()
536 rendlist_t *frl = &dlflat_rlist, *wrl = &dlwall_rlist;
539 if(!frl->numquads && !wrl->numquads) return; // Nothing to do.
541 // Setup the correct rendering state.
542 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
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);
551 // The light texture.
552 glBindTexture(GL_TEXTURE_2D, curtex=OGL_PrepareLightTexture());
557 glBegin(GL_TRIANGLES);
558 for(i=0; i<frl->numquads; i++)
562 glColor3f(cq->light, cq->light, cq->light);
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]);
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]);
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]);
582 float tctl[2], tcbr[2]; // Top left and bottom right.
584 for(i=0; i<wrl->numquads; i++)
588 glColor3f(cq->light, cq->light, cq->light);
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;
595 glTexCoord2f(tctl[VX], tcbr[VY]);
596 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
598 glTexCoord2f(tctl[VX], tctl[VY]);
599 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
601 glTexCoord2f(tcbr[VX], tctl[VY]);
602 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
604 glTexCoord2f(tcbr[VX], tcbr[VY]);
605 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
610 // Restore the original rendering state.
615 void RL_RenderAllLists()
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);