Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

tr_light.c (10745B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // tr_light.c
     23 
     24 #include "tr_local.h"
     25 
     26 #define	DLIGHT_AT_RADIUS		16
     27 // at the edge of a dlight's influence, this amount of light will be added
     28 
     29 #define	DLIGHT_MINIMUM_RADIUS	16		
     30 // never calculate a range less than this to prevent huge light numbers
     31 
     32 
     33 /*
     34 ===============
     35 R_TransformDlights
     36 
     37 Transforms the origins of an array of dlights.
     38 Used by both the front end (for DlightBmodel) and
     39 the back end (before doing the lighting calculation)
     40 ===============
     41 */
     42 void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) {
     43 	int		i;
     44 	vec3_t	temp;
     45 
     46 	for ( i = 0 ; i < count ; i++, dl++ ) {
     47 		VectorSubtract( dl->origin, or->origin, temp );
     48 		dl->transformed[0] = DotProduct( temp, or->axis[0] );
     49 		dl->transformed[1] = DotProduct( temp, or->axis[1] );
     50 		dl->transformed[2] = DotProduct( temp, or->axis[2] );
     51 	}
     52 }
     53 
     54 /*
     55 =============
     56 R_DlightBmodel
     57 
     58 Determine which dynamic lights may effect this bmodel
     59 =============
     60 */
     61 void R_DlightBmodel( bmodel_t *bmodel ) {
     62 	int			i, j;
     63 	dlight_t	*dl;
     64 	int			mask;
     65 	msurface_t	*surf;
     66 
     67 	// transform all the lights
     68 	R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );
     69 
     70 	mask = 0;
     71 	for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
     72 		dl = &tr.refdef.dlights[i];
     73 
     74 		// see if the point is close enough to the bounds to matter
     75 		for ( j = 0 ; j < 3 ; j++ ) {
     76 			if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
     77 				break;
     78 			}
     79 			if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
     80 				break;
     81 			}
     82 		}
     83 		if ( j < 3 ) {
     84 			continue;
     85 		}
     86 
     87 		// we need to check this light
     88 		mask |= 1 << i;
     89 	}
     90 
     91 	tr.currentEntity->needDlights = (mask != 0);
     92 
     93 	// set the dlight bits in all the surfaces
     94 	for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
     95 		surf = bmodel->firstSurface + i;
     96 
     97 		if ( *surf->data == SF_FACE ) {
     98 			((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
     99 		} else if ( *surf->data == SF_GRID ) {
    100 			((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
    101 		} else if ( *surf->data == SF_TRIANGLES ) {
    102 			((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
    103 		}
    104 	}
    105 }
    106 
    107 
    108 /*
    109 =============================================================================
    110 
    111 LIGHT SAMPLING
    112 
    113 =============================================================================
    114 */
    115 
    116 extern	cvar_t	*r_ambientScale;
    117 extern	cvar_t	*r_directedScale;
    118 extern	cvar_t	*r_debugLight;
    119 
    120 /*
    121 =================
    122 R_SetupEntityLightingGrid
    123 
    124 =================
    125 */
    126 static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
    127 	vec3_t	lightOrigin;
    128 	int		pos[3];
    129 	int		i, j;
    130 	byte	*gridData;
    131 	float	frac[3];
    132 	int		gridStep[3];
    133 	vec3_t	direction;
    134 	float	totalFactor;
    135 
    136 	if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
    137 		// seperate lightOrigins are needed so an object that is
    138 		// sinking into the ground can still be lit, and so
    139 		// multi-part models can be lit identically
    140 		VectorCopy( ent->e.lightingOrigin, lightOrigin );
    141 	} else {
    142 		VectorCopy( ent->e.origin, lightOrigin );
    143 	}
    144 
    145 	VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
    146 	for ( i = 0 ; i < 3 ; i++ ) {
    147 		float	v;
    148 
    149 		v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
    150 		pos[i] = floor( v );
    151 		frac[i] = v - pos[i];
    152 		if ( pos[i] < 0 ) {
    153 			pos[i] = 0;
    154 		} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
    155 			pos[i] = tr.world->lightGridBounds[i] - 1;
    156 		}
    157 	}
    158 
    159 	VectorClear( ent->ambientLight );
    160 	VectorClear( ent->directedLight );
    161 	VectorClear( direction );
    162 
    163 	assert( tr.world->lightGridData ); // bk010103 - NULL with -nolight maps
    164 
    165 	// trilerp the light value
    166 	gridStep[0] = 8;
    167 	gridStep[1] = 8 * tr.world->lightGridBounds[0];
    168 	gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
    169 	gridData = tr.world->lightGridData + pos[0] * gridStep[0]
    170 		+ pos[1] * gridStep[1] + pos[2] * gridStep[2];
    171 
    172 	totalFactor = 0;
    173 	for ( i = 0 ; i < 8 ; i++ ) {
    174 		float	factor;
    175 		byte	*data;
    176 		int		lat, lng;
    177 		vec3_t	normal;
    178 		#if idppc
    179 		float d0, d1, d2, d3, d4, d5;
    180 		#endif
    181 		factor = 1.0;
    182 		data = gridData;
    183 		for ( j = 0 ; j < 3 ; j++ ) {
    184 			if ( i & (1<<j) ) {
    185 				factor *= frac[j];
    186 				data += gridStep[j];
    187 			} else {
    188 				factor *= (1.0f - frac[j]);
    189 			}
    190 		}
    191 
    192 		if ( !(data[0]+data[1]+data[2]) ) {
    193 			continue;	// ignore samples in walls
    194 		}
    195 		totalFactor += factor;
    196 		#if idppc
    197 		d0 = data[0]; d1 = data[1]; d2 = data[2];
    198 		d3 = data[3]; d4 = data[4]; d5 = data[5];
    199 
    200 		ent->ambientLight[0] += factor * d0;
    201 		ent->ambientLight[1] += factor * d1;
    202 		ent->ambientLight[2] += factor * d2;
    203 
    204 		ent->directedLight[0] += factor * d3;
    205 		ent->directedLight[1] += factor * d4;
    206 		ent->directedLight[2] += factor * d5;
    207 		#else
    208 		ent->ambientLight[0] += factor * data[0];
    209 		ent->ambientLight[1] += factor * data[1];
    210 		ent->ambientLight[2] += factor * data[2];
    211 
    212 		ent->directedLight[0] += factor * data[3];
    213 		ent->directedLight[1] += factor * data[4];
    214 		ent->directedLight[2] += factor * data[5];
    215 		#endif
    216 		lat = data[7];
    217 		lng = data[6];
    218 		lat *= (FUNCTABLE_SIZE/256);
    219 		lng *= (FUNCTABLE_SIZE/256);
    220 
    221 		// decode X as cos( lat ) * sin( long )
    222 		// decode Y as sin( lat ) * sin( long )
    223 		// decode Z as cos( long )
    224 
    225 		normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
    226 		normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
    227 		normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
    228 
    229 		VectorMA( direction, factor, normal, direction );
    230 	}
    231 
    232 	if ( totalFactor > 0 && totalFactor < 0.99 ) {
    233 		totalFactor = 1.0f / totalFactor;
    234 		VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
    235 		VectorScale( ent->directedLight, totalFactor, ent->directedLight );
    236 	}
    237 
    238 	VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
    239 	VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
    240 
    241 	VectorNormalize2( direction, ent->lightDir );
    242 }
    243 
    244 
    245 /*
    246 ===============
    247 LogLight
    248 ===============
    249 */
    250 static void LogLight( trRefEntity_t *ent ) {
    251 	int	max1, max2;
    252 
    253 	if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
    254 		return;
    255 	}
    256 
    257 	max1 = ent->ambientLight[0];
    258 	if ( ent->ambientLight[1] > max1 ) {
    259 		max1 = ent->ambientLight[1];
    260 	} else if ( ent->ambientLight[2] > max1 ) {
    261 		max1 = ent->ambientLight[2];
    262 	}
    263 
    264 	max2 = ent->directedLight[0];
    265 	if ( ent->directedLight[1] > max2 ) {
    266 		max2 = ent->directedLight[1];
    267 	} else if ( ent->directedLight[2] > max2 ) {
    268 		max2 = ent->directedLight[2];
    269 	}
    270 
    271 	ri.Printf( PRINT_ALL, "amb:%i  dir:%i\n", max1, max2 );
    272 }
    273 
    274 /*
    275 =================
    276 R_SetupEntityLighting
    277 
    278 Calculates all the lighting values that will be used
    279 by the Calc_* functions
    280 =================
    281 */
    282 void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
    283 	int				i;
    284 	dlight_t		*dl;
    285 	float			power;
    286 	vec3_t			dir;
    287 	float			d;
    288 	vec3_t			lightDir;
    289 	vec3_t			lightOrigin;
    290 
    291 	// lighting calculations 
    292 	if ( ent->lightingCalculated ) {
    293 		return;
    294 	}
    295 	ent->lightingCalculated = qtrue;
    296 
    297 	//
    298 	// trace a sample point down to find ambient light
    299 	//
    300 	if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
    301 		// seperate lightOrigins are needed so an object that is
    302 		// sinking into the ground can still be lit, and so
    303 		// multi-part models can be lit identically
    304 		VectorCopy( ent->e.lightingOrigin, lightOrigin );
    305 	} else {
    306 		VectorCopy( ent->e.origin, lightOrigin );
    307 	}
    308 
    309 	// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
    310 	if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) 
    311 		&& tr.world->lightGridData ) {
    312 		R_SetupEntityLightingGrid( ent );
    313 	} else {
    314 		ent->ambientLight[0] = ent->ambientLight[1] = 
    315 			ent->ambientLight[2] = tr.identityLight * 150;
    316 		ent->directedLight[0] = ent->directedLight[1] = 
    317 			ent->directedLight[2] = tr.identityLight * 150;
    318 		VectorCopy( tr.sunDirection, ent->lightDir );
    319 	}
    320 
    321 	// bonus items and view weapons have a fixed minimum add
    322 	if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
    323 		// give everything a minimum light add
    324 		ent->ambientLight[0] += tr.identityLight * 32;
    325 		ent->ambientLight[1] += tr.identityLight * 32;
    326 		ent->ambientLight[2] += tr.identityLight * 32;
    327 	}
    328 
    329 	//
    330 	// modify the light by dynamic lights
    331 	//
    332 	d = VectorLength( ent->directedLight );
    333 	VectorScale( ent->lightDir, d, lightDir );
    334 
    335 	for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
    336 		dl = &refdef->dlights[i];
    337 		VectorSubtract( dl->origin, lightOrigin, dir );
    338 		d = VectorNormalize( dir );
    339 
    340 		power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
    341 		if ( d < DLIGHT_MINIMUM_RADIUS ) {
    342 			d = DLIGHT_MINIMUM_RADIUS;
    343 		}
    344 		d = power / ( d * d );
    345 
    346 		VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
    347 		VectorMA( lightDir, d, dir, lightDir );
    348 	}
    349 
    350 	// clamp ambient
    351 	for ( i = 0 ; i < 3 ; i++ ) {
    352 		if ( ent->ambientLight[i] > tr.identityLightByte ) {
    353 			ent->ambientLight[i] = tr.identityLightByte;
    354 		}
    355 	}
    356 
    357 	if ( r_debugLight->integer ) {
    358 		LogLight( ent );
    359 	}
    360 
    361 	// save out the byte packet version
    362 	((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] );
    363 	((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] );
    364 	((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] );
    365 	((byte *)&ent->ambientLightInt)[3] = 0xff;
    366 	
    367 	// transform the direction to local space
    368 	VectorNormalize( lightDir );
    369 	ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
    370 	ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
    371 	ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
    372 }
    373 
    374 /*
    375 =================
    376 R_LightForPoint
    377 =================
    378 */
    379 int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
    380 {
    381 	trRefEntity_t ent;
    382 	
    383 	// bk010103 - this segfaults with -nolight maps
    384 	if ( tr.world->lightGridData == NULL )
    385 	  return qfalse;
    386 
    387 	Com_Memset(&ent, 0, sizeof(ent));
    388 	VectorCopy( point, ent.e.origin );
    389 	R_SetupEntityLightingGrid( &ent );
    390 	VectorCopy(ent.ambientLight, ambientLight);
    391 	VectorCopy(ent.directedLight, directedLight);
    392 	VectorCopy(ent.lightDir, lightDir);
    393 
    394 	return qtrue;
    395 }