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