Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

gl_light.c (14896B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // r_light.c
     21 
     22 #include "gl_local.h"
     23 
     24 int	r_dlightframecount;
     25 
     26 #define	DLIGHT_CUTOFF	64
     27 
     28 /*
     29 =============================================================================
     30 
     31 DYNAMIC LIGHTS BLEND RENDERING
     32 
     33 =============================================================================
     34 */
     35 
     36 void R_RenderDlight (dlight_t *light)
     37 {
     38 	int		i, j;
     39 	float	a;
     40 	vec3_t	v;
     41 	float	rad;
     42 
     43 	rad = light->intensity * 0.35;
     44 
     45 	VectorSubtract (light->origin, r_origin, v);
     46 #if 0
     47 	// FIXME?
     48 	if (VectorLength (v) < rad)
     49 	{	// view is inside the dlight
     50 		V_AddBlend (light->color[0], light->color[1], light->color[2], light->intensity * 0.0003, v_blend);
     51 		return;
     52 	}
     53 #endif
     54 
     55 	qglBegin (GL_TRIANGLE_FAN);
     56 	qglColor3f (light->color[0]*0.2, light->color[1]*0.2, light->color[2]*0.2);
     57 	for (i=0 ; i<3 ; i++)
     58 		v[i] = light->origin[i] - vpn[i]*rad;
     59 	qglVertex3fv (v);
     60 	qglColor3f (0,0,0);
     61 	for (i=16 ; i>=0 ; i--)
     62 	{
     63 		a = i/16.0 * M_PI*2;
     64 		for (j=0 ; j<3 ; j++)
     65 			v[j] = light->origin[j] + vright[j]*cos(a)*rad
     66 				+ vup[j]*sin(a)*rad;
     67 		qglVertex3fv (v);
     68 	}
     69 	qglEnd ();
     70 }
     71 
     72 /*
     73 =============
     74 R_RenderDlights
     75 =============
     76 */
     77 void R_RenderDlights (void)
     78 {
     79 	int		i;
     80 	dlight_t	*l;
     81 
     82 	if (!gl_flashblend->value)
     83 		return;
     84 
     85 	r_dlightframecount = r_framecount + 1;	// because the count hasn't
     86 											//  advanced yet for this frame
     87 	qglDepthMask (0);
     88 	qglDisable (GL_TEXTURE_2D);
     89 	qglShadeModel (GL_SMOOTH);
     90 	qglEnable (GL_BLEND);
     91 	qglBlendFunc (GL_ONE, GL_ONE);
     92 
     93 	l = r_newrefdef.dlights;
     94 	for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++)
     95 		R_RenderDlight (l);
     96 
     97 	qglColor3f (1,1,1);
     98 	qglDisable (GL_BLEND);
     99 	qglEnable (GL_TEXTURE_2D);
    100 	qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    101 	qglDepthMask (1);
    102 }
    103 
    104 
    105 /*
    106 =============================================================================
    107 
    108 DYNAMIC LIGHTS
    109 
    110 =============================================================================
    111 */
    112 
    113 /*
    114 =============
    115 R_MarkLights
    116 =============
    117 */
    118 void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
    119 {
    120 	cplane_t	*splitplane;
    121 	float		dist;
    122 	msurface_t	*surf;
    123 	int			i;
    124 	
    125 	if (node->contents != -1)
    126 		return;
    127 
    128 	splitplane = node->plane;
    129 	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
    130 	
    131 	if (dist > light->intensity-DLIGHT_CUTOFF)
    132 	{
    133 		R_MarkLights (light, bit, node->children[0]);
    134 		return;
    135 	}
    136 	if (dist < -light->intensity+DLIGHT_CUTOFF)
    137 	{
    138 		R_MarkLights (light, bit, node->children[1]);
    139 		return;
    140 	}
    141 		
    142 // mark the polygons
    143 	surf = r_worldmodel->surfaces + node->firstsurface;
    144 	for (i=0 ; i<node->numsurfaces ; i++, surf++)
    145 	{
    146 		if (surf->dlightframe != r_dlightframecount)
    147 		{
    148 			surf->dlightbits = 0;
    149 			surf->dlightframe = r_dlightframecount;
    150 		}
    151 		surf->dlightbits |= bit;
    152 	}
    153 
    154 	R_MarkLights (light, bit, node->children[0]);
    155 	R_MarkLights (light, bit, node->children[1]);
    156 }
    157 
    158 
    159 /*
    160 =============
    161 R_PushDlights
    162 =============
    163 */
    164 void R_PushDlights (void)
    165 {
    166 	int		i;
    167 	dlight_t	*l;
    168 
    169 	if (gl_flashblend->value)
    170 		return;
    171 
    172 	r_dlightframecount = r_framecount + 1;	// because the count hasn't
    173 											//  advanced yet for this frame
    174 	l = r_newrefdef.dlights;
    175 	for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++)
    176 		R_MarkLights ( l, 1<<i, r_worldmodel->nodes );
    177 }
    178 
    179 
    180 /*
    181 =============================================================================
    182 
    183 LIGHT SAMPLING
    184 
    185 =============================================================================
    186 */
    187 
    188 vec3_t			pointcolor;
    189 cplane_t		*lightplane;		// used as shadow plane
    190 vec3_t			lightspot;
    191 
    192 int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
    193 {
    194 	float		front, back, frac;
    195 	int			side;
    196 	cplane_t	*plane;
    197 	vec3_t		mid;
    198 	msurface_t	*surf;
    199 	int			s, t, ds, dt;
    200 	int			i;
    201 	mtexinfo_t	*tex;
    202 	byte		*lightmap;
    203 	int			maps;
    204 	int			r;
    205 
    206 	if (node->contents != -1)
    207 		return -1;		// didn't hit anything
    208 	
    209 // calculate mid point
    210 
    211 // FIXME: optimize for axial
    212 	plane = node->plane;
    213 	front = DotProduct (start, plane->normal) - plane->dist;
    214 	back = DotProduct (end, plane->normal) - plane->dist;
    215 	side = front < 0;
    216 	
    217 	if ( (back < 0) == side)
    218 		return RecursiveLightPoint (node->children[side], start, end);
    219 	
    220 	frac = front / (front-back);
    221 	mid[0] = start[0] + (end[0] - start[0])*frac;
    222 	mid[1] = start[1] + (end[1] - start[1])*frac;
    223 	mid[2] = start[2] + (end[2] - start[2])*frac;
    224 	
    225 // go down front side	
    226 	r = RecursiveLightPoint (node->children[side], start, mid);
    227 	if (r >= 0)
    228 		return r;		// hit something
    229 		
    230 	if ( (back < 0) == side )
    231 		return -1;		// didn't hit anuthing
    232 		
    233 // check for impact on this node
    234 	VectorCopy (mid, lightspot);
    235 	lightplane = plane;
    236 
    237 	surf = r_worldmodel->surfaces + node->firstsurface;
    238 	for (i=0 ; i<node->numsurfaces ; i++, surf++)
    239 	{
    240 		if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 
    241 			continue;	// no lightmaps
    242 
    243 		tex = surf->texinfo;
    244 		
    245 		s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
    246 		t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];;
    247 
    248 		if (s < surf->texturemins[0] ||
    249 		t < surf->texturemins[1])
    250 			continue;
    251 		
    252 		ds = s - surf->texturemins[0];
    253 		dt = t - surf->texturemins[1];
    254 		
    255 		if ( ds > surf->extents[0] || dt > surf->extents[1] )
    256 			continue;
    257 
    258 		if (!surf->samples)
    259 			return 0;
    260 
    261 		ds >>= 4;
    262 		dt >>= 4;
    263 
    264 		lightmap = surf->samples;
    265 		VectorCopy (vec3_origin, pointcolor);
    266 		if (lightmap)
    267 		{
    268 			vec3_t scale;
    269 
    270 			lightmap += 3*(dt * ((surf->extents[0]>>4)+1) + ds);
    271 
    272 			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
    273 					maps++)
    274 			{
    275 				for (i=0 ; i<3 ; i++)
    276 					scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
    277 
    278 				pointcolor[0] += lightmap[0] * scale[0] * (1.0/255);
    279 				pointcolor[1] += lightmap[1] * scale[1] * (1.0/255);
    280 				pointcolor[2] += lightmap[2] * scale[2] * (1.0/255);
    281 				lightmap += 3*((surf->extents[0]>>4)+1) *
    282 						((surf->extents[1]>>4)+1);
    283 			}
    284 		}
    285 		
    286 		return 1;
    287 	}
    288 
    289 // go down back side
    290 	return RecursiveLightPoint (node->children[!side], mid, end);
    291 }
    292 
    293 /*
    294 ===============
    295 R_LightPoint
    296 ===============
    297 */
    298 void R_LightPoint (vec3_t p, vec3_t color)
    299 {
    300 	vec3_t		end;
    301 	float		r;
    302 	int			lnum;
    303 	dlight_t	*dl;
    304 	float		light;
    305 	vec3_t		dist;
    306 	float		add;
    307 	
    308 	if (!r_worldmodel->lightdata)
    309 	{
    310 		color[0] = color[1] = color[2] = 1.0;
    311 		return;
    312 	}
    313 	
    314 	end[0] = p[0];
    315 	end[1] = p[1];
    316 	end[2] = p[2] - 2048;
    317 	
    318 	r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
    319 	
    320 	if (r == -1)
    321 	{
    322 		VectorCopy (vec3_origin, color);
    323 	}
    324 	else
    325 	{
    326 		VectorCopy (pointcolor, color);
    327 	}
    328 
    329 	//
    330 	// add dynamic lights
    331 	//
    332 	light = 0;
    333 	dl = r_newrefdef.dlights;
    334 	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++, dl++)
    335 	{
    336 		VectorSubtract (currententity->origin,
    337 						dl->origin,
    338 						dist);
    339 		add = dl->intensity - VectorLength(dist);
    340 		add *= (1.0/256);
    341 		if (add > 0)
    342 		{
    343 			VectorMA (color, add, dl->color, color);
    344 		}
    345 	}
    346 
    347 	VectorScale (color, gl_modulate->value, color);
    348 }
    349 
    350 
    351 //===================================================================
    352 
    353 static float s_blocklights[34*34*3];
    354 /*
    355 ===============
    356 R_AddDynamicLights
    357 ===============
    358 */
    359 void R_AddDynamicLights (msurface_t *surf)
    360 {
    361 	int			lnum;
    362 	int			sd, td;
    363 	float		fdist, frad, fminlight;
    364 	vec3_t		impact, local;
    365 	int			s, t;
    366 	int			i;
    367 	int			smax, tmax;
    368 	mtexinfo_t	*tex;
    369 	dlight_t	*dl;
    370 	float		*pfBL;
    371 	float		fsacc, ftacc;
    372 
    373 	smax = (surf->extents[0]>>4)+1;
    374 	tmax = (surf->extents[1]>>4)+1;
    375 	tex = surf->texinfo;
    376 
    377 	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
    378 	{
    379 		if ( !(surf->dlightbits & (1<<lnum) ) )
    380 			continue;		// not lit by this light
    381 
    382 		dl = &r_newrefdef.dlights[lnum];
    383 		frad = dl->intensity;
    384 		fdist = DotProduct (dl->origin, surf->plane->normal) -
    385 				surf->plane->dist;
    386 		frad -= fabs(fdist);
    387 		// rad is now the highest intensity on the plane
    388 
    389 		fminlight = DLIGHT_CUTOFF;	// FIXME: make configurable?
    390 		if (frad < fminlight)
    391 			continue;
    392 		fminlight = frad - fminlight;
    393 
    394 		for (i=0 ; i<3 ; i++)
    395 		{
    396 			impact[i] = dl->origin[i] -
    397 					surf->plane->normal[i]*fdist;
    398 		}
    399 
    400 		local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0];
    401 		local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1];
    402 
    403 		pfBL = s_blocklights;
    404 		for (t = 0, ftacc = 0 ; t<tmax ; t++, ftacc += 16)
    405 		{
    406 			td = local[1] - ftacc;
    407 			if ( td < 0 )
    408 				td = -td;
    409 
    410 			for ( s=0, fsacc = 0 ; s<smax ; s++, fsacc += 16, pfBL += 3)
    411 			{
    412 				sd = Q_ftol( local[0] - fsacc );
    413 
    414 				if ( sd < 0 )
    415 					sd = -sd;
    416 
    417 				if (sd > td)
    418 					fdist = sd + (td>>1);
    419 				else
    420 					fdist = td + (sd>>1);
    421 
    422 				if ( fdist < fminlight )
    423 				{
    424 					pfBL[0] += ( frad - fdist ) * dl->color[0];
    425 					pfBL[1] += ( frad - fdist ) * dl->color[1];
    426 					pfBL[2] += ( frad - fdist ) * dl->color[2];
    427 				}
    428 			}
    429 		}
    430 	}
    431 }
    432 
    433 
    434 /*
    435 ** R_SetCacheState
    436 */
    437 void R_SetCacheState( msurface_t *surf )
    438 {
    439 	int maps;
    440 
    441 	for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
    442 		 maps++)
    443 	{
    444 		surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white;
    445 	}
    446 }
    447 
    448 /*
    449 ===============
    450 R_BuildLightMap
    451 
    452 Combine and scale multiple lightmaps into the floating format in blocklights
    453 ===============
    454 */
    455 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
    456 {
    457 	int			smax, tmax;
    458 	int			r, g, b, a, max;
    459 	int			i, j, size;
    460 	byte		*lightmap;
    461 	float		scale[4];
    462 	int			nummaps;
    463 	float		*bl;
    464 	lightstyle_t	*style;
    465 	int monolightmap;
    466 
    467 	if ( surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) )
    468 		ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface");
    469 
    470 	smax = (surf->extents[0]>>4)+1;
    471 	tmax = (surf->extents[1]>>4)+1;
    472 	size = smax*tmax;
    473 	if (size > (sizeof(s_blocklights)>>4) )
    474 		ri.Sys_Error (ERR_DROP, "Bad s_blocklights size");
    475 
    476 // set to full bright if no light data
    477 	if (!surf->samples)
    478 	{
    479 		int maps;
    480 
    481 		for (i=0 ; i<size*3 ; i++)
    482 			s_blocklights[i] = 255;
    483 		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
    484 			 maps++)
    485 		{
    486 			style = &r_newrefdef.lightstyles[surf->styles[maps]];
    487 		}
    488 		goto store;
    489 	}
    490 
    491 	// count the # of maps
    492 	for ( nummaps = 0 ; nummaps < MAXLIGHTMAPS && surf->styles[nummaps] != 255 ;
    493 		 nummaps++)
    494 		;
    495 
    496 	lightmap = surf->samples;
    497 
    498 	// add all the lightmaps
    499 	if ( nummaps == 1 )
    500 	{
    501 		int maps;
    502 
    503 		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
    504 			 maps++)
    505 		{
    506 			bl = s_blocklights;
    507 
    508 			for (i=0 ; i<3 ; i++)
    509 				scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
    510 
    511 			if ( scale[0] == 1.0F &&
    512 				 scale[1] == 1.0F &&
    513 				 scale[2] == 1.0F )
    514 			{
    515 				for (i=0 ; i<size ; i++, bl+=3)
    516 				{
    517 					bl[0] = lightmap[i*3+0];
    518 					bl[1] = lightmap[i*3+1];
    519 					bl[2] = lightmap[i*3+2];
    520 				}
    521 			}
    522 			else
    523 			{
    524 				for (i=0 ; i<size ; i++, bl+=3)
    525 				{
    526 					bl[0] = lightmap[i*3+0] * scale[0];
    527 					bl[1] = lightmap[i*3+1] * scale[1];
    528 					bl[2] = lightmap[i*3+2] * scale[2];
    529 				}
    530 			}
    531 			lightmap += size*3;		// skip to next lightmap
    532 		}
    533 	}
    534 	else
    535 	{
    536 		int maps;
    537 
    538 		memset( s_blocklights, 0, sizeof( s_blocklights[0] ) * size * 3 );
    539 
    540 		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
    541 			 maps++)
    542 		{
    543 			bl = s_blocklights;
    544 
    545 			for (i=0 ; i<3 ; i++)
    546 				scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
    547 
    548 			if ( scale[0] == 1.0F &&
    549 				 scale[1] == 1.0F &&
    550 				 scale[2] == 1.0F )
    551 			{
    552 				for (i=0 ; i<size ; i++, bl+=3 )
    553 				{
    554 					bl[0] += lightmap[i*3+0];
    555 					bl[1] += lightmap[i*3+1];
    556 					bl[2] += lightmap[i*3+2];
    557 				}
    558 			}
    559 			else
    560 			{
    561 				for (i=0 ; i<size ; i++, bl+=3)
    562 				{
    563 					bl[0] += lightmap[i*3+0] * scale[0];
    564 					bl[1] += lightmap[i*3+1] * scale[1];
    565 					bl[2] += lightmap[i*3+2] * scale[2];
    566 				}
    567 			}
    568 			lightmap += size*3;		// skip to next lightmap
    569 		}
    570 	}
    571 
    572 // add all the dynamic lights
    573 	if (surf->dlightframe == r_framecount)
    574 		R_AddDynamicLights (surf);
    575 
    576 // put into texture format
    577 store:
    578 	stride -= (smax<<2);
    579 	bl = s_blocklights;
    580 
    581 	monolightmap = gl_monolightmap->string[0];
    582 
    583 	if ( monolightmap == '0' )
    584 	{
    585 		for (i=0 ; i<tmax ; i++, dest += stride)
    586 		{
    587 			for (j=0 ; j<smax ; j++)
    588 			{
    589 				
    590 				r = Q_ftol( bl[0] );
    591 				g = Q_ftol( bl[1] );
    592 				b = Q_ftol( bl[2] );
    593 
    594 				// catch negative lights
    595 				if (r < 0)
    596 					r = 0;
    597 				if (g < 0)
    598 					g = 0;
    599 				if (b < 0)
    600 					b = 0;
    601 
    602 				/*
    603 				** determine the brightest of the three color components
    604 				*/
    605 				if (r > g)
    606 					max = r;
    607 				else
    608 					max = g;
    609 				if (b > max)
    610 					max = b;
    611 
    612 				/*
    613 				** alpha is ONLY used for the mono lightmap case.  For this reason
    614 				** we set it to the brightest of the color components so that 
    615 				** things don't get too dim.
    616 				*/
    617 				a = max;
    618 
    619 				/*
    620 				** rescale all the color components if the intensity of the greatest
    621 				** channel exceeds 1.0
    622 				*/
    623 				if (max > 255)
    624 				{
    625 					float t = 255.0F / max;
    626 
    627 					r = r*t;
    628 					g = g*t;
    629 					b = b*t;
    630 					a = a*t;
    631 				}
    632 
    633 				dest[0] = r;
    634 				dest[1] = g;
    635 				dest[2] = b;
    636 				dest[3] = a;
    637 
    638 				bl += 3;
    639 				dest += 4;
    640 			}
    641 		}
    642 	}
    643 	else
    644 	{
    645 		for (i=0 ; i<tmax ; i++, dest += stride)
    646 		{
    647 			for (j=0 ; j<smax ; j++)
    648 			{
    649 				
    650 				r = Q_ftol( bl[0] );
    651 				g = Q_ftol( bl[1] );
    652 				b = Q_ftol( bl[2] );
    653 
    654 				// catch negative lights
    655 				if (r < 0)
    656 					r = 0;
    657 				if (g < 0)
    658 					g = 0;
    659 				if (b < 0)
    660 					b = 0;
    661 
    662 				/*
    663 				** determine the brightest of the three color components
    664 				*/
    665 				if (r > g)
    666 					max = r;
    667 				else
    668 					max = g;
    669 				if (b > max)
    670 					max = b;
    671 
    672 				/*
    673 				** alpha is ONLY used for the mono lightmap case.  For this reason
    674 				** we set it to the brightest of the color components so that 
    675 				** things don't get too dim.
    676 				*/
    677 				a = max;
    678 
    679 				/*
    680 				** rescale all the color components if the intensity of the greatest
    681 				** channel exceeds 1.0
    682 				*/
    683 				if (max > 255)
    684 				{
    685 					float t = 255.0F / max;
    686 
    687 					r = r*t;
    688 					g = g*t;
    689 					b = b*t;
    690 					a = a*t;
    691 				}
    692 
    693 				/*
    694 				** So if we are doing alpha lightmaps we need to set the R, G, and B
    695 				** components to 0 and we need to set alpha to 1-alpha.
    696 				*/
    697 				switch ( monolightmap )
    698 				{
    699 				case 'L':
    700 				case 'I':
    701 					r = a;
    702 					g = b = 0;
    703 					break;
    704 				case 'C':
    705 					// try faking colored lighting
    706 					a = 255 - ((r+g+b)/3);
    707 					r *= a/255.0;
    708 					g *= a/255.0;
    709 					b *= a/255.0;
    710 					break;
    711 				case 'A':
    712 				default:
    713 					r = g = b = 0;
    714 					a = 255 - a;
    715 					break;
    716 				}
    717 
    718 				dest[0] = r;
    719 				dest[1] = g;
    720 				dest[2] = b;
    721 				dest[3] = a;
    722 
    723 				bl += 3;
    724 				dest += 4;
    725 			}
    726 		}
    727 	}
    728 }
    729