/
noire-dev
/
SourceTech
Обзор
Документация
Войти
/
noire-dev
/
SourceTech
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
sourcetech
code/renderer/tr_light.c
260 строк
7 KB
noire-dev
Update: 2025-11-04 16:13
04 ноя 2025, 07:13
04 ноя 2025, 07:13
5d4a874
Код
Авторство
О чём код?
/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake III Arena source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // tr_light.c #include "tr_local.h" #define DLIGHT_AT_RADIUS 16 // at the edge of a dlight's influence, this amount of light will be added #define DLIGHT_MINIMUM_RADIUS 16 // never calculate a range less than this to prevent huge light numbers /* =============== R_TransformDlights Transforms the origins of an array of dlights. Used by both the front end (for DlightBmodel) and the back end (before doing the lighting calculation) =============== */ void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { int i; vec3_t temp, temp2; for ( i = 0 ; i < count ; i++, dl++ ) { VectorSubtract( dl->origin, or->origin, temp ); dl->transformed[0] = DotProduct( temp, or->axis[0] ); dl->transformed[1] = DotProduct( temp, or->axis[1] ); dl->transformed[2] = DotProduct( temp, or->axis[2] ); if ( dl->linear ) { VectorSubtract( dl->origin2, or->origin, temp2 ); dl->transformed2[0] = DotProduct( temp2, or->axis[0] ); dl->transformed2[1] = DotProduct( temp2, or->axis[1] ); dl->transformed2[2] = DotProduct( temp2, or->axis[2] ); } } } /* ============================================================================= LIGHT SAMPLING ============================================================================= */ /* ================= R_SetupEntityLightingGrid ================= */ static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) { vec3_t lightOrigin; int pos[3]; int i, j; byte *gridData; float frac[3]; int gridStep[3]; vec3_t direction; if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { // separate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); } else { VectorCopy( ent->e.origin, lightOrigin ); } VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); for ( i = 0 ; i < 3 ; i++ ) { float v; v = lightOrigin[i]*tr.world->lightGridInverseSize[i]; pos[i] = floor( v ); frac[i] = v - pos[i]; if ( pos[i] < 0 ) { pos[i] = 0; } else if ( pos[i] > tr.world->lightGridBounds[i] - 1 ) { pos[i] = tr.world->lightGridBounds[i] - 1; } } VectorClear( ent->ambientLight ); VectorClear( ent->directedLight ); VectorClear( direction ); assert( tr.world->lightGridData ); // NULL with -nolight maps // trilerp the light value gridStep[0] = 8; gridStep[1] = 8 * tr.world->lightGridBounds[0]; gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1]; gridData = tr.world->lightGridData + pos[0] * gridStep[0] + pos[1] * gridStep[1] + pos[2] * gridStep[2]; for ( i = 0 ; i < 8 ; i++ ) { float factor; byte *data; int lat, lng; vec3_t normal; factor = 1.0; data = gridData; for ( j = 0 ; j < 3 ; j++ ) { if ( i & (1<<j) ) { if ( pos[j] + 1 > tr.world->lightGridBounds[j] - 1 ) { break; // ignore values outside lightgrid } factor *= frac[j]; data += gridStep[j]; } else { factor *= (1.0f - frac[j]); } } if ( j != 3 ) { continue; } if ( !(data[0]+data[1]+data[2]) ) { continue; // ignore samples in walls } ent->ambientLight[0] += factor * data[0]; ent->ambientLight[1] += factor * data[1]; ent->ambientLight[2] += factor * data[2]; ent->directedLight[0] += factor * data[3]; ent->directedLight[1] += factor * data[4]; ent->directedLight[2] += factor * data[5]; lat = data[7]; lng = data[6]; lat *= (FUNCTABLE_SIZE/256); lng *= (FUNCTABLE_SIZE/256); // decode X as cos( lat ) * sin( long ) // decode Y as sin( lat ) * sin( long ) // decode Z as cos( long ) normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; VectorMA( direction, factor, normal, direction ); } VectorScale( ent->ambientLight, 3.50, ent->ambientLight ); VectorScale( ent->directedLight, 0.50, ent->directedLight ); VectorNormalize2( direction, ent->lightDir ); } /* ================= R_SetupEntityLighting Calculates all the lighting values that will be used by the Calc_* functions ================= */ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { int i; const dlight_t *dl; float power; vec3_t dir; float d; vec3_t lightDir; vec3_t lightOrigin; // lighting calculations if ( ent->lightingCalculated ) { return; } ent->lightingCalculated = qtrue; // // trace a sample point down to find ambient light // if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { // separate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); } else { VectorCopy( ent->e.origin, lightOrigin ); } // if NOWORLDMODEL, only use dynamic lights (menu system, etc) if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) && tr.world->lightGridData ) { R_SetupEntityLightingGrid( ent ); } else { ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[2] = tr.identityLight * 150; ent->directedLight[0] = ent->directedLight[1] = ent->directedLight[2] = tr.identityLight * 150; VectorCopy( tr.sunDirection, ent->lightDir ); } // // modify the light by dynamic lights // d = VectorLength( ent->directedLight ); VectorScale( ent->lightDir, d, lightDir ); for ( i = 0 ; i < refdef->num_dlights ; i++ ) { dl = &refdef->dlights[i]; VectorSubtract( dl->origin, lightOrigin, dir ); d = VectorNormalize( dir ); power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); if ( d < DLIGHT_MINIMUM_RADIUS ) { d = DLIGHT_MINIMUM_RADIUS; } d = power / ( d * d ); VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); VectorMA( lightDir, d, dir, lightDir ); } // clamp ambient for ( i = 0 ; i < 3 ; i++ ) { if ( ent->ambientLight[i] > tr.identityLightByte ) { ent->ambientLight[i] = tr.identityLightByte; } } // save out the byte packet version ((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] ); // -EC-: don't use ri.ftol to avoid precision losses ((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] ); ((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] ); ((byte *)&ent->ambientLightInt)[3] = 0xff; // transform the direction to local space VectorNormalize( lightDir ); ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); }