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 = _alloca(sizeof(float)*numvrts);
234 for(i=0; i<numvrts; i++) distances[i] = PointDist2D(&origvrts[i].x);
236 // Make a distance modification.
237 vrts = _alloca(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);
306 void SetVertexColor(float light, float dist, float alpha)
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.
312 real += extralight/16.0;
314 if(viewplayer->fixedcolormap)
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;
322 glColor4f(real, real, real, alpha); // Too real? Hope real gets clamped.
325 // This is only for solid, non-masked primitives.
326 void RL_RenderList(rendlist_t *rl)
329 float tcleft, tcright, tctop, tcbottom;
332 if(!rl->numquads) return; // The list is empty.
334 // Bind the right texture.
335 glBindTexture(GL_TEXTURE_2D, curtex=rl->tex);
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.
341 // There's only triangles here, I see.
342 glBegin(GL_TRIANGLES);
343 for(i=0; i<rl->numquads; i++)
346 if(cq->flags & RQF_MISSING_WALL)
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;
353 SetVertexColor(cq->light, cq->dist[0], 1);
354 glTexCoord2f(tcleft, tctop);
355 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
357 SetVertexColor(cq->light, cq->dist[1], 1);
358 glTexCoord2f(tcright, tctop);
359 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
361 glTexCoord2f(tcright, tcbottom);
362 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
364 // The other triangle.
365 glTexCoord2f(tcright, tcbottom);
366 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
368 SetVertexColor(cq->light, cq->dist[0], 1);
369 glTexCoord2f(tcleft, tcbottom);
370 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
372 glTexCoord2f(tcleft, tctop);
373 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
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]);
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]);
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]);
399 for(i=0; i<rl->numquads; i++)
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;
408 SetVertexColor(cq->light, cq->dist[0], 1);
409 glTexCoord2f(tcleft, tcbottom);
410 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
412 glTexCoord2f(tcleft, tctop);
413 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
415 SetVertexColor(cq->light, cq->dist[1], 1);
416 glTexCoord2f(tcright, tctop);
417 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
419 glTexCoord2f(tcright, tcbottom);
420 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
426 // Masked lists only include quads.
427 void RL_RenderMaskedList(rendlist_t *mrl)
430 float tcleft, tcright, tctop, tcbottom;
433 if(!mrl->numquads) return; // No quads to render, I'm afraid.
435 // Curtex is used to keep track of the current texture.
436 // Zero also denotes that no glBegin() has yet been called.
440 for(i=mrl->numquads-1; i>=0; i--) // Render back to front.
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;
448 // Is there a need to change the texture?
449 if(curtex != cq->masktex)
451 if(curtex) glEnd(); // Finish with the old texture.
452 glBindTexture(GL_TEXTURE_2D, curtex=cq->masktex);
453 glBegin(GL_QUADS); // I love OpenGL.
457 SetVertexColor(cq->light, cq->dist[0], 1);
458 glTexCoord2f(tcleft, tcbottom);
459 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
461 glTexCoord2f(tcleft, tctop);
462 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
464 SetVertexColor(cq->light, cq->dist[1], 1);
465 glTexCoord2f(tcright, tctop);
466 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
468 glTexCoord2f(tcright, tcbottom);
469 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
471 if(curtex) glEnd(); // If something was drawn, finish with it.
474 void RL_RenderSkyMaskLists()
478 rendlist_t *smrl = &invsky_rlist, *skyw = &invskywall_rlist;
481 if(!smrl->numquads && !skyw->numquads) return; // Nothing to do here.
483 // Nothing gets written to the color buffer.
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 );
490 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
491 glColor4f(1, 1, 1, 1); // Just to be sure.
496 glBegin(GL_TRIANGLES);
497 for(i=0; i<smrl->numquads; 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]);
512 for(i=0; i<skyw->numquads; i++)
514 cq = skyw->quads + i;
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]);
524 glEnable( GL_TEXTURE_2D );
526 // Restore normal write mode.
527 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
531 void RL_RenderDynLightLists()
534 rendlist_t *frl = &dlflat_rlist, *wrl = &dlwall_rlist;
537 if(!frl->numquads && !wrl->numquads) return; // Nothing to do.
539 // Setup the correct rendering state.
540 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
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);
549 // The light texture.
550 glBindTexture(GL_TEXTURE_2D, curtex=OGL_PrepareLightTexture());
555 glBegin(GL_TRIANGLES);
556 for(i=0; i<frl->numquads; i++)
560 glColor3f(cq->light, cq->light, cq->light);
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]);
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]);
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]);
580 float tctl[2], tcbr[2]; // Top left and bottom right.
582 for(i=0; i<wrl->numquads; i++)
586 glColor3f(cq->light, cq->light, cq->light);
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;
593 glTexCoord2f(tctl[VX], tcbr[VY]);
594 glVertex3f(cq->v1[VX], cq->u.q.bottom, cq->v1[VY]);
596 glTexCoord2f(tctl[VX], tctl[VY]);
597 glVertex3f(cq->v1[VX], cq->top, cq->v1[VY]);
599 glTexCoord2f(tcbr[VX], tctl[VY]);
600 glVertex3f(cq->v2[VX], cq->top, cq->v2[VY]);
602 glTexCoord2f(tcbr[VX], tcbr[VY]);
603 glVertex3f(cq->v2[VX], cq->u.q.bottom, cq->v2[VY]);
608 // Restore the original rendering state.
613 void RL_RenderAllLists()
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);