1 /*
2 * r_light.c
3 *
4 * $Id: gl_rlight.c,v 1.17 2007-09-14 14:10:01 sezero Exp $
5 *
6 * Copyright (C) 1996-1997 Id Software, Inc.
7 * Copyright (C) 1997-1998 Raven Software Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 *
18 * See the GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "quakedef.h"
26
27 static int r_dlightframecount;
28
29
30 /*
31 ==================
32 R_AnimateLight
33 ==================
34 */
R_AnimateLight(void)35 void R_AnimateLight (void)
36 {
37 int i, c, v;
38 int defaultLocus;
39 int locusHz[3];
40
41 defaultLocus = locusHz[0] = (int)(cl.time*10);
42 locusHz[1] = (int)(cl.time*20);
43 locusHz[2] = (int)(cl.time*30);
44 for (i = 0; i < MAX_LIGHTSTYLES; i++)
45 {
46 if (!cl_lightstyle[i].length)
47 { // No style def
48 d_lightstylevalue[i] = 256;
49 continue;
50 }
51 c = cl_lightstyle[i].map[0];
52 if (c == '1' || c == '2' || c == '3')
53 { // Explicit anim rate
54 if (cl_lightstyle[i].length == 1)
55 { // Bad style def
56 d_lightstylevalue[i] = 256;
57 continue;
58 }
59 v = locusHz[c-'1'] % (cl_lightstyle[i].length-1);
60 d_lightstylevalue[i] = (cl_lightstyle[i].map[v+1]-'a')*22;
61 continue;
62 }
63 // Default anim rate (10 Hz)
64 v = defaultLocus % cl_lightstyle[i].length;
65 d_lightstylevalue[i] = (cl_lightstyle[i].map[v]-'a')*22;
66 }
67 }
68
69 /*
70 =============================================================================
71
72 DYNAMIC LIGHTS BLEND RENDERING
73
74 =============================================================================
75 */
76
AddLightBlend(float r,float g,float b,float a2)77 static void AddLightBlend (float r, float g, float b, float a2)
78 {
79 float a;
80
81 v_blend[3] = a = v_blend[3] + a2*(1-v_blend[3]);
82
83 a2 = a2/a;
84
85 v_blend[0] = v_blend[1]*(1-a2) + r*a2;
86 v_blend[1] = v_blend[1]*(1-a2) + g*a2;
87 v_blend[2] = v_blend[2]*(1-a2) + b*a2;
88 }
89
90
91 #define DLIGHT_BUBBLE_WEDGES 16
92 static float bubble_sintable[DLIGHT_BUBBLE_WEDGES+1];
93 static float bubble_costable[DLIGHT_BUBBLE_WEDGES+1];
94
R_InitBubble(void)95 void R_InitBubble (void)
96 {
97 float a;
98 int i;
99 float *bub_sin, *bub_cos;
100
101 bub_sin = bubble_sintable;
102 bub_cos = bubble_costable;
103
104 for (i = DLIGHT_BUBBLE_WEDGES; i >= 0; i--)
105 {
106 a = i / ((float)DLIGHT_BUBBLE_WEDGES) * M_PI * 2;
107 *bub_sin++ = sin(a);
108 *bub_cos++ = cos(a);
109 }
110 }
111
112
R_RenderDlight(dlight_t * light)113 static void R_RenderDlight (dlight_t *light)
114 {
115 int i, j;
116 vec3_t v;
117 float rad;
118 float *bub_sin, *bub_cos;
119
120 bub_sin = bubble_sintable;
121 bub_cos = bubble_costable;
122 rad = light->radius * 0.35;
123
124 VectorSubtract (light->origin, r_origin, v);
125 if (VectorLength (v) < rad)
126 { // view is inside the dlight
127 AddLightBlend (1, 0.5, 0, light->radius * 0.0003);
128 return;
129 }
130
131 glBegin_fp (GL_TRIANGLE_FAN);
132
133 if (light->color[0] || light->color[1] || light->color[2])
134 {
135 glColor4fv_fp (light->color);
136 }
137 else
138 {
139 #ifndef H2W
140 glColor3f_fp (0.2,0.1,0.0);
141 #else
142 glColor3f_fp (0.2,0.1,0.05); // changed dimlight effect
143 #endif
144 }
145
146 for (i = 0; i < 3; i++)
147 v[i] = light->origin[i] - vpn[i]*rad;
148
149 glVertex3fv_fp (v);
150 glColor3f_fp (0,0,0);
151
152 for (i = DLIGHT_BUBBLE_WEDGES; i >= 0; i--)
153 {
154 for (j = 0; j < 3; j++)
155 v[j] = light->origin[j] + (vright[j] * (*bub_cos) + vup[j] * (*bub_sin)) * rad;
156
157 bub_sin++;
158 bub_cos++;
159
160 glVertex3fv_fp (v);
161 }
162 glEnd_fp ();
163 }
164
165 /*
166 =============
167 R_RenderDlights
168 =============
169 */
R_RenderDlights(void)170 void R_RenderDlights (void)
171 {
172 int i;
173 dlight_t *l;
174
175 if (!gl_flashblend.integer)
176 return;
177
178 r_dlightframecount = r_framecount + 1; // because the count hasn't
179 // advanced yet for this frame
180 glDepthMask_fp (0);
181 glDisable_fp (GL_TEXTURE_2D);
182 glShadeModel_fp (GL_SMOOTH);
183 glEnable_fp (GL_BLEND);
184 glBlendFunc_fp (GL_ONE, GL_ONE);
185
186 l = cl_dlights;
187 for (i = 0; i < MAX_DLIGHTS; i++, l++)
188 {
189 if (l->die < cl.time || !l->radius)
190 continue;
191 R_RenderDlight (l);
192 }
193
194 glColor3f_fp (1,1,1);
195 glDisable_fp (GL_BLEND);
196 glEnable_fp (GL_TEXTURE_2D);
197 glBlendFunc_fp (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
198 glDepthMask_fp (1);
199 }
200
201
202 /*
203 =============================================================================
204
205 DYNAMIC LIGHTS
206
207 =============================================================================
208 */
209
210 /*
211 =============
212 R_MarkLights
213 =============
214 */
215 #if 0 /* the original version from ID */
216 void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
217 {
218 mplane_t *splitplane;
219 float dist;
220 msurface_t *surf;
221 int i;
222
223 if (node->contents < 0)
224 return;
225
226 splitplane = node->plane;
227 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
228
229 if (dist > light->radius)
230 {
231 R_MarkLights (light, bit, node->children[0]);
232 return;
233 }
234 if (dist < -light->radius)
235 {
236 R_MarkLights (light, bit, node->children[1]);
237 return;
238 }
239
240 // mark the polygons
241 surf = cl.worldmodel->surfaces + node->firstsurface;
242 for (i = 0; i < node->numsurfaces; i++, surf++)
243 {
244 if (surf->dlightframe != r_dlightframecount)
245 {
246 surf->dlightbits = 0;
247 surf->dlightframe = r_dlightframecount;
248 }
249 surf->dlightbits |= bit;
250 }
251
252 R_MarkLights (light, bit, node->children[0]);
253 R_MarkLights (light, bit, node->children[1]);
254 }
255 #else /* the major speedup version by Lord Havoc */
R_MarkLights(dlight_t * light,int bit,mnode_t * node)256 void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
257 {
258 mplane_t *splitplane;
259 float l, dist, maxdist;
260 msurface_t *surf;
261 int i, j, s, t;
262 vec3_t impact;
263
264 loc0:
265 if (node->contents < 0)
266 return;
267
268 splitplane = node->plane;
269 if (splitplane->type < 3)
270 dist = light->origin[splitplane->type] - splitplane->dist;
271 else
272 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
273
274 if (dist > light->radius)
275 {
276 node = node->children[0];
277 goto loc0;
278 }
279 if (dist < -light->radius)
280 {
281 node = node->children[1];
282 goto loc0;
283 }
284
285 maxdist = light->radius * light->radius;
286
287 // mark the polygons
288 surf = cl.worldmodel->surfaces + node->firstsurface;
289 for (i = 0; i < node->numsurfaces; i++, surf++)
290 { // eliminates marking of surfaces too far away from light,
291 // thus preventing unnecessary renders and uploads
292 for (j = 0; j < 3; j++)
293 impact[j] = light->origin[j] - surf->plane->normal[j]*dist;
294
295 // clamp center of light to corner and check brightness
296 l = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
297 s = l + 0.5;
298 if (s < 0)
299 s = 0;
300 else if (s > surf->extents[0])
301 s = surf->extents[0];
302 s = l - s;
303 l = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
304 t = l + 0.5;
305 if (t < 0)
306 t = 0;
307 else if (t > surf->extents[1])
308 t = surf->extents[1];
309 t = l - t;
310
311 // compare to minimum light
312 if ((s*s + t*t + dist*dist) < maxdist)
313 {
314 if (surf->dlightframe != r_dlightframecount)
315 { // not dynamic until now
316 surf->dlightbits = bit;
317 surf->dlightframe = r_dlightframecount;
318 }
319 else // already dynamic
320 surf->dlightbits |= bit;
321 }
322 }
323
324 if (node->children[0]->contents >= 0)
325 R_MarkLights (light, bit, node->children[0]);
326 if (node->children[1]->contents >= 0)
327 R_MarkLights (light, bit, node->children[1]);
328 }
329 #endif /* end of 2 R_MarkLights versions */
330
331
332 /*
333 =============
334 R_PushDlights
335 =============
336 */
R_PushDlights(void)337 void R_PushDlights (void)
338 {
339 int i;
340 dlight_t *l;
341
342 if (gl_flashblend.integer)
343 return;
344
345 r_dlightframecount = r_framecount + 1; // because the count hasn't
346 // advanced yet for this frame
347 l = cl_dlights;
348
349 for (i = 0; i < MAX_DLIGHTS; i++, l++)
350 {
351 if (l->die < cl.time || !l->radius)
352 continue;
353 R_MarkLights ( l, 1<<i, cl.worldmodel->nodes );
354 }
355 }
356
357
358 /*
359 =============================================================================
360
361 LIGHT SAMPLING
362
363 =============================================================================
364 */
365
366 vec3_t lightspot;
367
RecursiveLightPoint(mnode_t * node,vec3_t start,vec3_t end)368 static int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
369 {
370 int r;
371 float front, back, frac;
372 int side;
373 mplane_t *plane;
374 vec3_t mid;
375 msurface_t *surf;
376 int s, t, ds, dt;
377 int i;
378 mtexinfo_t *tex;
379 byte *lightmap;
380 unsigned int scale;
381 int maps;
382
383 if (node->contents < 0)
384 return -1; // didn't hit anything
385
386 // calculate mid point
387
388 // FIXME: optimize for axial
389 plane = node->plane;
390 front = DotProduct (start, plane->normal) - plane->dist;
391 back = DotProduct (end, plane->normal) - plane->dist;
392 side = front < 0;
393
394 if ( (back < 0) == side)
395 return RecursiveLightPoint (node->children[side], start, end);
396
397 frac = front / (front-back);
398 mid[0] = start[0] + (end[0] - start[0])*frac;
399 mid[1] = start[1] + (end[1] - start[1])*frac;
400 mid[2] = start[2] + (end[2] - start[2])*frac;
401
402 // go down front side
403 r = RecursiveLightPoint (node->children[side], start, mid);
404 if (r >= 0)
405 return r; // hit something
406
407 if ( (back < 0) == side )
408 return -1; // didn't hit anything
409
410 // check for impact on this node
411 VectorCopy (mid, lightspot);
412
413 surf = cl.worldmodel->surfaces + node->firstsurface;
414 for (i = 0; i < node->numsurfaces; i++, surf++)
415 {
416 if (surf->flags & SURF_DRAWTILED)
417 continue; // no lightmaps
418
419 tex = surf->texinfo;
420
421 /* added double casts so that 64 bit/sse2 builds' precision
422 * matches that of x87 floating point. took from QuakeSpasm,
423 * patch by Eric Wasylishen. */
424 s = DotProductDBL(mid, tex->vecs[0]) + (double)tex->vecs[0][3];
425 t = DotProductDBL(mid, tex->vecs[1]) + (double)tex->vecs[1][3];
426
427 if (s < surf->texturemins[0] || t < surf->texturemins[1])
428 continue;
429
430 ds = s - surf->texturemins[0];
431 dt = t - surf->texturemins[1];
432
433 if (ds > surf->extents[0] || dt > surf->extents[1])
434 continue;
435
436 if (!surf->samples)
437 return 0;
438
439 ds >>= 4;
440 dt >>= 4;
441
442 lightmap = surf->samples;
443 r = 0;
444 if (lightmap)
445 {
446 lightmap += dt * ((surf->extents[0] >> 4) + 1) + ds;
447
448 for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++)
449 {
450 scale = d_lightstylevalue[surf->styles[maps]];
451 r += *lightmap * scale;
452 lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1);
453 }
454
455 r >>= 8;
456 }
457
458 return r;
459 }
460
461 // go down back side
462 return RecursiveLightPoint (node->children[!side], mid, end);
463 }
464
R_LightPoint(vec3_t p)465 int R_LightPoint (vec3_t p)
466 {
467 vec3_t end;
468 int r;
469
470 if (!cl.worldmodel->lightdata)
471 return 255;
472
473 end[0] = p[0];
474 end[1] = p[1];
475 end[2] = p[2] - 2048;
476
477 r = RecursiveLightPoint (cl.worldmodel->nodes, p, end);
478
479 if (r == -1)
480 r = 0;
481
482 return r;
483 }
484
485
RecursiveLightPointColor(vec3_t color,mnode_t * node,vec3_t start,vec3_t end)486 static int RecursiveLightPointColor (vec3_t color, mnode_t *node, vec3_t start, vec3_t end)
487 {
488 float front, back, frac;
489 vec3_t mid;
490
491 loc0:
492 if (node->contents < 0)
493 return false; // didn't hit anything
494
495 // calculate mid point
496 if (node->plane->type < 3)
497 {
498 front = start[node->plane->type] - node->plane->dist;
499 back = end[node->plane->type] - node->plane->dist;
500 }
501 else
502 {
503 front = DotProduct(start, node->plane->normal) - node->plane->dist;
504 back = DotProduct(end, node->plane->normal) - node->plane->dist;
505 }
506 // LordHavoc: optimized recursion
507 if ((back < 0) == (front < 0))
508 {
509 node = node->children[front < 0];
510 goto loc0;
511 }
512
513 frac = front / (front-back);
514 mid[0] = start[0] + (end[0] - start[0])*frac;
515 mid[1] = start[1] + (end[1] - start[1])*frac;
516 mid[2] = start[2] + (end[2] - start[2])*frac;
517
518 // go down front side
519 if (RecursiveLightPointColor (color, node->children[front < 0], start, mid))
520 return true; // hit something
521 else
522 {
523 int i, ds, dt;
524 msurface_t *surf;
525 // check for impact on this node
526 VectorCopy (mid, lightspot);
527 surf = cl.worldmodel->surfaces + node->firstsurface;
528 for (i = 0; i < node->numsurfaces; i++, surf++)
529 {
530 if (surf->flags & SURF_DRAWTILED)
531 continue; // no lightmaps
532 ds = (int) ((float) DotProduct(mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
533 dt = (int) ((float) DotProduct(mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
534 if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
535 continue;
536
537 ds -= surf->texturemins[0];
538 dt -= surf->texturemins[1];
539
540 if (ds > surf->extents[0] || dt > surf->extents[1])
541 continue;
542 if (surf->samples)
543 {
544 // LordHavoc: enhanced to interpolate lighting
545 byte *lightmap;
546 float scale;
547 int maps, line3,
548 dsfrac = ds & 15,
549 dtfrac = dt & 15,
550 r00 = 0, g00 = 0, b00 = 0,
551 r01 = 0, g01 = 0, b01 = 0,
552 r10 = 0, g10 = 0, b10 = 0,
553 r11 = 0, g11 = 0, b11 = 0;
554
555 line3 = ((surf->extents[0]>>4) + 1) * 3;
556 lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4) + 1) + (ds>>4)) * 3;
557 for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++)
558 {
559 scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
560 r00 += (float) lightmap[0] * scale;
561 g00 += (float) lightmap[1] * scale;
562 b00 += (float) lightmap[2] * scale;
563 r01 += (float) lightmap[3] * scale;
564 g01 += (float) lightmap[4] * scale;
565 b01 += (float) lightmap[5] * scale;
566 r10 += (float) lightmap[line3+0] * scale;
567 g10 += (float) lightmap[line3+1] * scale;
568 b10 += (float) lightmap[line3+2] * scale;
569 r11 += (float) lightmap[line3+3] * scale;
570 g11 += (float) lightmap[line3+4] * scale;
571 b11 += (float) lightmap[line3+5] * scale;
572 lightmap += ((surf->extents[0]>>4) + 1) * ((surf->extents[1]>>4) + 1) * 3;
573 }
574 color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
575 color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));
576 color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));
577 }
578 return true; // success
579 }
580 // go down back side
581 return RecursiveLightPointColor (color, node->children[front >= 0], mid, end);
582 }
583 }
584
585 vec3_t lightcolor;
586
R_LightPointColor(vec3_t p)587 float R_LightPointColor (vec3_t p)
588 {
589 vec3_t end;
590
591 if (!cl.worldmodel->lightdata)
592 {
593 lightcolor[0] = lightcolor[1] = lightcolor[2] = 255.0;
594 return 255.0;
595 }
596
597 end[0] = p[0];
598 end[1] = p[1];
599 end[2] = p[2] - 2048;
600
601 lightcolor[0] = lightcolor[1] = lightcolor[2] = 0;
602 RecursiveLightPointColor (lightcolor, cl.worldmodel->nodes, p, end);
603 return (lightcolor[0] + lightcolor[1] + lightcolor[2]) / 3.0;
604 }
605
606