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