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 }