1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2006 Robert Beckebans <trebor_7@users.sourceforge.net>
5 
6 This file is part of XreaL source code.
7 
8 XreaL source code 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 XreaL source code 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 XreaL source code; 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 /*
28 ===============
29 R_TransformDlights
30 
31 Transforms the origins of an array of dlights.
32 Used by both the front end (for DlightBmodel) and
33 the back end (before doing the lighting calculation)
34 ===============
35 */
R_TransformDlights(int count,trRefDlight_t * dl,orientationr_t * or)36 void R_TransformDlights(int count, trRefDlight_t * dl, orientationr_t * or)
37 {
38 	int             i;
39 	vec3_t          temp;
40 
41 	for(i = 0; i < count; i++, dl++)
42 	{
43 		VectorSubtract(dl->l.origin, or->origin, temp);
44 		dl->transformed[0] = DotProduct(temp, or->axis[0]);
45 		dl->transformed[1] = DotProduct(temp, or->axis[1]);
46 		dl->transformed[2] = DotProduct(temp, or->axis[2]);
47 	}
48 }
49 
50 /*
51 =============
52 R_AddBrushModelInteractions
53 
54 Determine which dynamic lights may effect this bmodel
55 =============
56 */
R_AddBrushModelInteractions(trRefEntity_t * ent,trRefDlight_t * light)57 void R_AddBrushModelInteractions(trRefEntity_t * ent, trRefDlight_t * light)
58 {
59 	int             i;
60 	msurface_t     *surf;
61 	bmodel_t       *bModel = NULL;
62 	model_t        *pModel = NULL;
63 	interactionType_t iaType = IA_DEFAULT;
64 
65 	// cull the entire model if it is outside the view frustum
66 	// and we don't care about proper shadowing
67 	if(ent->cull == CULL_OUT)
68 	{
69 		if(r_shadows->integer <= 2 || light->l.noShadows)
70 			return;
71 		else
72 			iaType = IA_SHADOWONLY;
73 	}
74 	else
75 	{
76 		if(r_shadows->integer <= 2)
77 			iaType = IA_LIGHTONLY;
78 	}
79 
80 	pModel = R_GetModelByHandle(ent->e.hModel);
81 	bModel = pModel->bmodel;
82 
83 	// do a quick AABB cull
84 	if(!BoundsIntersect(light->worldBounds[0], light->worldBounds[1], ent->worldBounds[0], ent->worldBounds[1]))
85 	{
86 		tr.pc.c_dlightSurfacesCulled += bModel->numSurfaces;
87 		return;
88 	}
89 
90 	// do a more expensive and precise light frustum cull
91 	if(!r_noLightFrustums->integer)
92 	{
93 		if(R_CullLightWorldBounds(light, ent->worldBounds) == CULL_OUT)
94 		{
95 			tr.pc.c_dlightSurfacesCulled += bModel->numSurfaces;
96 			return;
97 		}
98 	}
99 
100 	// set the dlight bits in all the surfaces
101 	for(i = 0; i < bModel->numSurfaces; i++)
102 	{
103 		surf = bModel->firstSurface + i;
104 
105 		// FIXME: do more culling?
106 
107 		/*
108 		   if(*surf->data == SF_FACE)
109 		   {
110 		   ((srfSurfaceFace_t *) surf->data)->dlightBits[tr.smpFrame] = mask;
111 		   }
112 		   else if(*surf->data == SF_GRID)
113 		   {
114 		   ((srfGridMesh_t *) surf->data)->dlightBits[tr.smpFrame] = mask;
115 		   }
116 		   else if(*surf->data == SF_TRIANGLES)
117 		   {
118 		   ((srfTriangles_t *) surf->data)->dlightBits[tr.smpFrame] = mask;
119 		   }
120 		 */
121 
122 		// skip all surfaces that don't matter for lighting only pass
123 		if(surf->shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))
124 			continue;
125 
126 		R_AddDlightInteraction(light, surf->data, surf->shader, 0, NULL, 0, NULL, iaType);
127 		tr.pc.c_dlightSurfaces++;
128 	}
129 }
130 
131 
132 /*
133 =============================================================================
134 
135 LIGHT SAMPLING
136 
137 =============================================================================
138 */
139 
140 
141 
142 /*
143 =================
144 R_SetupEntityLightingGrid
145 =================
146 */
R_SetupEntityLightingGrid(trRefEntity_t * ent)147 static void R_SetupEntityLightingGrid(trRefEntity_t * ent)
148 {
149 	vec3_t          lightOrigin;
150 	int             pos[3];
151 	int             i, j;
152 	byte           *gridData;
153 	float           frac[3];
154 	int             gridStep[3];
155 	vec3_t          direction;
156 	float           totalFactor;
157 
158 	if(ent->e.renderfx & RF_LIGHTING_ORIGIN)
159 	{
160 		// seperate lightOrigins are needed so an object that is
161 		// sinking into the ground can still be lit, and so
162 		// multi-part models can be lit identically
163 		VectorCopy(ent->e.lightingOrigin, lightOrigin);
164 	}
165 	else
166 	{
167 		VectorCopy(ent->e.origin, lightOrigin);
168 	}
169 
170 	VectorSubtract(lightOrigin, tr.world->lightGridOrigin, lightOrigin);
171 	for(i = 0; i < 3; i++)
172 	{
173 		float           v;
174 
175 		v = lightOrigin[i] * tr.world->lightGridInverseSize[i];
176 		pos[i] = floor(v);
177 		frac[i] = v - pos[i];
178 		if(pos[i] < 0)
179 		{
180 			pos[i] = 0;
181 		}
182 		else if(pos[i] >= tr.world->lightGridBounds[i] - 1)
183 		{
184 			pos[i] = tr.world->lightGridBounds[i] - 1;
185 		}
186 	}
187 
188 	VectorClear(ent->ambientLight);
189 	VectorClear(ent->directedLight);
190 	VectorClear(direction);
191 
192 	assert(tr.world->lightGridData);	// bk010103 - NULL with -nolight maps
193 
194 	// trilerp the light value
195 	gridStep[0] = 8;
196 	gridStep[1] = 8 * tr.world->lightGridBounds[0];
197 	gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
198 	gridData = tr.world->lightGridData + pos[0] * gridStep[0] + pos[1] * gridStep[1] + pos[2] * gridStep[2];
199 
200 	totalFactor = 0;
201 	for(i = 0; i < 8; i++)
202 	{
203 		float           factor;
204 		byte           *data;
205 		int             lat, lng;
206 		vec3_t          normal;
207 
208 #if idppc
209 		float           d0, d1, d2, d3, d4, d5;
210 #endif
211 		factor = 1.0;
212 		data = gridData;
213 		for(j = 0; j < 3; j++)
214 		{
215 			if(i & (1 << j))
216 			{
217 				factor *= frac[j];
218 				data += gridStep[j];
219 			}
220 			else
221 			{
222 				factor *= (1.0f - frac[j]);
223 			}
224 		}
225 
226 		if(!(data[0] + data[1] + data[2]))
227 		{
228 			continue;			// ignore samples in walls
229 		}
230 		totalFactor += factor;
231 #if idppc
232 		d0 = data[0];
233 		d1 = data[1];
234 		d2 = data[2];
235 		d3 = data[3];
236 		d4 = data[4];
237 		d5 = data[5];
238 
239 		ent->ambientLight[0] += factor * d0;
240 		ent->ambientLight[1] += factor * d1;
241 		ent->ambientLight[2] += factor * d2;
242 
243 		ent->directedLight[0] += factor * d3;
244 		ent->directedLight[1] += factor * d4;
245 		ent->directedLight[2] += factor * d5;
246 #else
247 		ent->ambientLight[0] += factor * data[0];
248 		ent->ambientLight[1] += factor * data[1];
249 		ent->ambientLight[2] += factor * data[2];
250 
251 		ent->directedLight[0] += factor * data[3];
252 		ent->directedLight[1] += factor * data[4];
253 		ent->directedLight[2] += factor * data[5];
254 #endif
255 		lat = data[7];
256 		lng = data[6];
257 		lat *= (FUNCTABLE_SIZE / 256);
258 		lng *= (FUNCTABLE_SIZE / 256);
259 
260 		// decode X as cos( lat ) * sin( long )
261 		// decode Y as sin( lat ) * sin( long )
262 		// decode Z as cos( long )
263 
264 		normal[0] = tr.sinTable[(lat + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK] * tr.sinTable[lng];
265 		normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
266 		normal[2] = tr.sinTable[(lng + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK];
267 
268 		VectorMA(direction, factor, normal, direction);
269 	}
270 
271 	if(totalFactor > 0 && totalFactor < 0.99)
272 	{
273 		totalFactor = 1.0f / totalFactor;
274 		VectorScale(ent->ambientLight, totalFactor, ent->ambientLight);
275 		VectorScale(ent->directedLight, totalFactor, ent->directedLight);
276 	}
277 
278 	VectorScale(ent->ambientLight, r_ambientScale->value, ent->ambientLight);
279 	VectorScale(ent->directedLight, r_directedScale->value, ent->directedLight);
280 
281 	VectorNormalize2(direction, ent->lightDir);
282 }
283 
284 
285 /*
286 ===============
287 LogLight
288 ===============
289 */
LogLight(trRefEntity_t * ent)290 static void LogLight(trRefEntity_t * ent)
291 {
292 	int             max1, max2;
293 
294 	if(!(ent->e.renderfx & RF_FIRST_PERSON))
295 	{
296 		return;
297 	}
298 
299 	max1 = ent->ambientLight[0];
300 	if(ent->ambientLight[1] > max1)
301 	{
302 		max1 = ent->ambientLight[1];
303 	}
304 	else if(ent->ambientLight[2] > max1)
305 	{
306 		max1 = ent->ambientLight[2];
307 	}
308 
309 	max2 = ent->directedLight[0];
310 	if(ent->directedLight[1] > max2)
311 	{
312 		max2 = ent->directedLight[1];
313 	}
314 	else if(ent->directedLight[2] > max2)
315 	{
316 		max2 = ent->directedLight[2];
317 	}
318 
319 	ri.Printf(PRINT_ALL, "amb:%i  dir:%i\n", max1, max2);
320 }
321 
322 /*
323 =================
324 R_SetupEntityLighting
325 
326 Calculates all the lighting values that will be used
327 by the Calc_* functions
328 =================
329 */
R_SetupEntityLighting(const trRefdef_t * refdef,trRefEntity_t * ent)330 void R_SetupEntityLighting(const trRefdef_t * refdef, trRefEntity_t * ent)
331 {
332 	int             i;
333 	vec3_t          lightDir;
334 	vec3_t          lightOrigin;
335 	float           d;
336 
337 	// lighting calculations
338 	if(ent->lightingCalculated)
339 	{
340 		return;
341 	}
342 	ent->lightingCalculated = qtrue;
343 
344 	// trace a sample point down to find ambient light
345 	if(ent->e.renderfx & RF_LIGHTING_ORIGIN)
346 	{
347 		// seperate lightOrigins are needed so an object that is
348 		// sinking into the ground can still be lit, and so
349 		// multi-part models can be lit identically
350 		VectorCopy(ent->e.lightingOrigin, lightOrigin);
351 	}
352 	else
353 	{
354 		VectorCopy(ent->e.origin, lightOrigin);
355 	}
356 
357 	// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
358 	if(!(refdef->rdflags & RDF_NOWORLDMODEL) && tr.world->lightGridData)
359 	{
360 		R_SetupEntityLightingGrid(ent);
361 	}
362 	else
363 	{
364 		ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[2] = tr.identityLight * 150;
365 		ent->directedLight[0] = ent->directedLight[1] = ent->directedLight[2] = tr.identityLight * 150;
366 		VectorCopy(tr.sunDirection, ent->lightDir);
367 	}
368 
369 	// bonus items and view weapons have a fixed minimum add
370 	if(1 /* ent->e.renderfx & RF_MINLIGHT */ )
371 	{
372 		// give everything a minimum light add
373 		ent->ambientLight[0] += tr.identityLight * 32;
374 		ent->ambientLight[1] += tr.identityLight * 32;
375 		ent->ambientLight[2] += tr.identityLight * 32;
376 	}
377 
378 	// clamp ambient
379 	for(i = 0; i < 3; i++)
380 	{
381 		if(ent->ambientLight[i] > tr.identityLightByte)
382 		{
383 			ent->ambientLight[i] = tr.identityLightByte;
384 		}
385 	}
386 
387 	if(r_debugLight->integer)
388 	{
389 		LogLight(ent);
390 	}
391 
392 	// save out the byte packet version
393 	((byte *) & ent->ambientLightInt)[0] = myftol(ent->ambientLight[0]);
394 	((byte *) & ent->ambientLightInt)[1] = myftol(ent->ambientLight[1]);
395 	((byte *) & ent->ambientLightInt)[2] = myftol(ent->ambientLight[2]);
396 	((byte *) & ent->ambientLightInt)[3] = 0xff;
397 
398 	// transform the direction to local space
399 	d = VectorLength(ent->directedLight);
400 	VectorScale(ent->lightDir, d, lightDir);
401 	VectorNormalize(lightDir);
402 	ent->lightDir[0] = DotProduct(lightDir, ent->e.axis[0]);
403 	ent->lightDir[1] = DotProduct(lightDir, ent->e.axis[1]);
404 	ent->lightDir[2] = DotProduct(lightDir, ent->e.axis[2]);
405 }
406 
407 /*
408 =================
409 R_LightForPoint
410 =================
411 */
R_LightForPoint(vec3_t point,vec3_t ambientLight,vec3_t directedLight,vec3_t lightDir)412 int R_LightForPoint(vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir)
413 {
414 	trRefEntity_t   ent;
415 
416 	// bk010103 - this segfaults with -nolight maps
417 	if(tr.world->lightGridData == NULL)
418 		return qfalse;
419 
420 	Com_Memset(&ent, 0, sizeof(ent));
421 	VectorCopy(point, ent.e.origin);
422 	R_SetupEntityLightingGrid(&ent);
423 	VectorCopy(ent.ambientLight, ambientLight);
424 	VectorCopy(ent.directedLight, directedLight);
425 	VectorCopy(ent.lightDir, lightDir);
426 
427 	return qtrue;
428 }
429 
430 
431 /*
432 =================
433 R_SetupDlightOrigin
434 Tr3B - needs finished transformMatrix
435 =================
436 */
R_SetupDlightOrigin(trRefDlight_t * dl)437 void R_SetupDlightOrigin(trRefDlight_t * dl)
438 {
439 	vec3_t          transformed;
440 
441 	MatrixTransformNormal(dl->transformMatrix, dl->l.center, transformed);
442 	VectorAdd(dl->l.origin, transformed, dl->origin);
443 }
444 
445 /*
446 =================
447 R_SetupDlightLocalBounds
448 =================
449 */
R_SetupDlightLocalBounds(trRefDlight_t * dl)450 void R_SetupDlightLocalBounds(trRefDlight_t * dl)
451 {
452 	switch (dl->l.rlType)
453 	{
454 		default:
455 		case RL_OMNI:
456 		{
457 			dl->localBounds[0][0] = dl->l.radius[0];
458 			dl->localBounds[0][1] = dl->l.radius[1];
459 			dl->localBounds[0][2] = dl->l.radius[2];
460 			dl->localBounds[1][0] = -dl->l.radius[0];
461 			dl->localBounds[1][1] = -dl->l.radius[1];
462 			dl->localBounds[1][2] = -dl->l.radius[2];
463 			break;
464 		}
465 
466 		case RL_PROJ:
467 		{
468 			dl->localBounds[0][0] = dl->l.radius[0];
469 			dl->localBounds[0][1] = dl->l.radius[1];
470 			dl->localBounds[0][2] = dl->l.radius[2];
471 			dl->localBounds[1][0] = 0;
472 			dl->localBounds[1][1] = -dl->l.radius[1];
473 			dl->localBounds[1][2] = -dl->l.radius[2];
474 			break;
475 		}
476 	}
477 }
478 
479 /*
480 =================
481 R_SetupDlightWorldBounds
482 Tr3B - needs finished transformMatrix
483 =================
484 */
R_SetupDlightWorldBounds(trRefDlight_t * dl)485 void R_SetupDlightWorldBounds(trRefDlight_t * dl)
486 {
487 	int             j;
488 	vec3_t          v, transformed;
489 
490 	ClearBounds(dl->worldBounds[0], dl->worldBounds[1]);
491 
492 	for(j = 0; j < 8; j++)
493 	{
494 		v[0] = dl->localBounds[j & 1][0];
495 		v[1] = dl->localBounds[(j >> 1) & 1][1];
496 		v[2] = dl->localBounds[(j >> 2) & 1][2];
497 
498 		// transform local bounds vertices into world space
499 		MatrixTransformPoint(dl->transformMatrix, v, transformed);
500 
501 		AddPointToBounds(transformed, dl->worldBounds[0], dl->worldBounds[1]);
502 	}
503 }
504 
505 /*
506 =================
507 R_SetupDlightFrustum
508 =================
509 */
R_SetupDlightFrustum(trRefDlight_t * dl)510 void R_SetupDlightFrustum(trRefDlight_t * dl)
511 {
512 	switch (dl->l.rlType)
513 	{
514 		case RL_OMNI:
515 		{
516 			int             i;
517 			vec3_t          planeNormal;
518 			vec3_t          planeOrigin;
519 
520 			for(i = 0; i < 3; i++)
521 			{
522 				VectorCopy(dl->l.origin, planeOrigin);
523 
524 				VectorNegate(dl->l.axis[i], planeNormal);
525 				planeOrigin[i] += dl->l.radius[i];
526 
527 				VectorCopy(planeNormal, dl->frustum[i].normal);
528 				dl->frustum[i].type = PlaneTypeForNormal(planeNormal);
529 				dl->frustum[i].dist = DotProduct(planeOrigin, planeNormal);
530 				SetPlaneSignbits(&dl->frustum[i]);
531 			}
532 
533 			for(i = 0; i < 3; i++)
534 			{
535 				VectorCopy(dl->l.origin, planeOrigin);
536 
537 				VectorCopy(dl->l.axis[i], planeNormal);
538 				planeOrigin[i] -= dl->l.radius[i];
539 
540 				VectorCopy(planeNormal, dl->frustum[i + 3].normal);
541 				dl->frustum[i + 3].type = PlaneTypeForNormal(planeNormal);
542 				dl->frustum[i + 3].dist = DotProduct(planeOrigin, planeNormal);
543 				SetPlaneSignbits(&dl->frustum[i + 3]);
544 			}
545 			break;
546 		}
547 
548 		default:
549 			break;
550 	}
551 }
552 
553 
554 /*
555 =================
556 R_SetupDlightProjection
557 =================
558 */
R_SetupDlightProjection(trRefDlight_t * dl)559 void R_SetupDlightProjection(trRefDlight_t * dl)
560 {
561 	switch (dl->l.rlType)
562 	{
563 		case RL_OMNI:
564 		{
565 			MatrixSetupScale(dl->projectionMatrix, 1.0 / dl->l.radius[0], 1.0 / dl->l.radius[1], 1.0 / dl->l.radius[2]);
566 			break;
567 		}
568 
569 		case RL_PROJ:
570 		{
571 #if 1
572 			float           xMin, xMax, yMin, yMax;
573 			float           width, height, depth;
574 			float           zNear, zFar;
575 			float           fovX, fovY;
576 			vec3_t          target, right, up;
577 			float          *proj = dl->projectionMatrix;
578 
579 			MatrixTransformNormal(dl->transformMatrix, dl->l.target, target);
580 			MatrixTransformNormal(dl->transformMatrix, dl->l.right, right);
581 			MatrixTransformNormal(dl->transformMatrix, dl->l.up, up);
582 
583 			fovX = 30;
584 			fovY = R_CalcFov(fovX, VectorLength(right) * 2, VectorLength(up) * 2);
585 
586 			zNear = 1.0;
587 			zFar = VectorLength(target);
588 
589 			xMax = zNear * tan(fovX * M_PI / 360.0f);
590 			xMin = -xMax;
591 
592 			yMax = zNear * tan(fovY * M_PI / 360.0f);
593 			yMin = -yMax;
594 
595 			width = xMax - xMin;
596 			height = yMax - yMin;
597 			depth = zFar - zNear;
598 
599 			// standard OpenGL projection matrix
600 			proj[0] = 2 * zNear / width;
601 			proj[4] = 0;
602 			proj[8] = (xMax + xMin) / width;
603 			proj[12] = 0;
604 
605 			proj[1] = 0;
606 			proj[5] = 2 * zNear / height;
607 			proj[9] = (yMax + yMin) / height;
608 			proj[13] = 0;
609 
610 			proj[2] = 0;
611 			proj[6] = 0;
612 			proj[10] = -(zFar + zNear) / depth;
613 			proj[14] = -2 * zFar * zNear / depth;
614 
615 			proj[3] = 0;
616 			proj[7] = 0;
617 			proj[11] = -1;
618 			proj[15] = 0;
619 
620 			// HACK: rotate transform into the direction we are facing
621 			MatrixMultiplyRotation(proj, 90, 90, 0);
622 #else
623 			// Tr3B - recoded from GtkRadiant entity plugin source
624 			int             i;
625 			vec4_t          lightProject[4];
626 			vec4_t          frustum[6];
627 			vec3_t          start, stop;
628 			vec3_t          right, up;
629 			vec4_t          targetGlobal;
630 			float           rLen, uLen, fLen;
631 			vec3_t          normal;
632 			vec_t           dist;
633 			vec3_t          falloff;
634 
635 			float          *proj = dl->projectionMatrix;
636 
637 			//MatrixTransformNormal(dl->transformMatrix, dl->l.target, target);
638 			//MatrixTransformNormal(dl->transformMatrix, dl->l.right, right);
639 			//MatrixTransformNormal(dl->transformMatrix, dl->l.up, up);
640 
641 
642 			VectorNormalize2(dl->l.target, start);
643 			VectorCopy(dl->l.target, stop);
644 
645 			rLen = VectorNormalize2(dl->l.right, right);
646 			uLen = VectorNormalize2(dl->l.up, up);
647 
648 			CrossProduct(up, right, normal);
649 			dist = DotProduct(dl->l.target, normal);
650 
651 			if(dist < 0)
652 			{
653 				dist = -dist;
654 				VectorInverse(normal);
655 			}
656 
657 			VectorScale(right, (0.5f * dist) / rLen, right);
658 			VectorScale(up, -(0.5f * dist) / uLen, up);
659 
660 			VectorCopy(normal, lightProject[2]);
661 			lightProject[2][3] = 0;
662 
663 			VectorCopy(right, lightProject[0]);
664 			lightProject[0][3] = 0;
665 
666 			VectorCopy(up, lightProject[1]);
667 			lightProject[1][3] = 0;
668 
669 			// now offset to center
670 			VectorCopy(dl->l.target, targetGlobal);
671 			targetGlobal[3] = 1;
672 
673 			{
674 				float           a, b, ofs;
675 				a = DotProduct4(targetGlobal, lightProject[0]);
676 				b = DotProduct4(targetGlobal, lightProject[2]);
677 				ofs = 0.5f - a / b;
678 
679 				VectorMA4(lightProject[0], ofs, lightProject[2], lightProject[0]);
680 			}
681 			{
682 				float           a, b, ofs;
683 				a = DotProduct4(targetGlobal, lightProject[1]);
684 				b = DotProduct4(targetGlobal, lightProject[2]);
685 				ofs = 0.5f - a / b;
686 
687 				VectorMA4(lightProject[1], ofs, lightProject[2], lightProject[1]);
688 			}
689 
690 			// set the falloff vector
691 			VectorSubtract(stop, start, falloff);
692 			fLen = VectorNormalize(falloff);
693 			if(fLen <= 0)
694 			{
695 				fLen = 1;
696 			}
697 			VectorScale(falloff, (1.0f / fLen), falloff);
698 
699 			VectorCopy(falloff, lightProject[3]);
700 			lightProject[3][3] = -DotProduct(start, falloff);
701 
702 			// we want the planes of s=0, s=q, t=0, and t=q
703 
704 			// left
705 			VectorCopy4(lightProject[0], frustum[0]);
706 
707 			// bottom
708 			VectorCopy4(lightProject[1], frustum[1]);
709 
710 			// right
711 			VectorSubtract(lightProject[2], lightProject[0], frustum[2]);
712 			frustum[2][3] = lightProject[2][3] - lightProject[0][3];
713 
714 			// top
715 			VectorSubtract(lightProject[2], lightProject[1], frustum[3]);
716 			frustum[3][3] = lightProject[2][3] - lightProject[1][3];
717 
718 			// we want the planes of s=0 and s=1 for front and rear clipping planes
719 
720 			// front
721 			VectorCopy4(lightProject[3], frustum[4]);
722 
723 			// back
724 			VectorNegate(lightProject[3], frustum[5]);
725 			frustum[5][3] = lightProject[3][3] - 1.0f;
726 
727 			MatrixFromPlanes(proj, frustum[0], frustum[1], frustum[2], frustum[3], frustum[4], frustum[5]);
728 
729 			for(i = 0; i < 6; i++)
730 			{
731 				PlaneNormalize(frustum[i]);
732 				VectorNegate(frustum[i], dl->frustum[i].normal);
733 				dl->frustum[i].type = PlaneTypeForNormal(dl->frustum[i].normal);
734 				dl->frustum[i].dist = frustum[i][3];
735 				SetPlaneSignbits(&dl->frustum[i]);
736 			}
737 #endif
738 			break;
739 		}
740 
741 		default:
742 			ri.Error(ERR_DROP, "R_SetupDlightProjection: Bad rlType");
743 	}
744 }
745 
746 /*
747 =================
748 R_AddDlightInteraction
749 =================
750 */
R_AddDlightInteraction(trRefDlight_t * light,surfaceType_t * surface,shader_t * surfaceShader,int numLightIndexes,int * lightIndexes,int numShadowIndexes,int * shadowIndexes,interactionType_t iaType)751 void R_AddDlightInteraction(trRefDlight_t * light, surfaceType_t * surface, shader_t * surfaceShader, int numLightIndexes, int *lightIndexes, int numShadowIndexes, int *shadowIndexes, interactionType_t iaType)
752 {
753 	int             iaIndex;
754 	interaction_t  *ia;
755 	interaction_t  *iaLast;
756 
757 	// skip all surfaces that don't matter for lighting only pass
758 	if(surfaceShader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))
759 		return;
760 
761 	if(!surfaceShader->interactLight && iaType == IA_LIGHTONLY)
762 		return;
763 
764 	// instead of checking for overflow, we just mask the index
765 	// so it wraps around
766 	iaIndex = tr.refdef.numInteractions & INTERACTION_MASK;
767 	ia = &tr.refdef.interactions[iaIndex];
768 	tr.refdef.numInteractions++;
769 
770 	// connect to interaction grid
771 	if(light->firstInteractionIndex == -1)
772 	{
773 		light->firstInteractionIndex = iaIndex;
774 	}
775 
776 	if(light->lastInteractionIndex != -1)
777 	{
778 		iaLast = &tr.refdef.interactions[light->lastInteractionIndex];
779 
780 		iaLast->next = ia;
781 
782 		if(light->lastInteractionIndex == INTERACTION_MASK)
783 		{
784 			light->noSort = qtrue;
785 		}
786 	}
787 
788 	light->lastInteractionIndex = iaIndex;
789 
790 	// update counters
791 	light->numInteractions++;
792 
793 	switch (iaType)
794 	{
795 		case IA_SHADOWONLY:
796 			light->numShadowOnlyInteractions++;
797 			break;
798 
799 		case IA_LIGHTONLY:
800 			light->numLightOnlyInteractions++;
801 			break;
802 
803 		default:
804 			break;
805 	}
806 
807 	// check what kind of attenuationShader is used
808 	if(!light->l.attenuationShader)
809 	{
810 		if(light->isStatic)
811 		{
812 			switch (light->l.rlType)
813 			{
814 				default:
815 				case RL_OMNI:
816 					ia->dlightShader = tr.defaultPointLightShader;
817 					break;
818 
819 				case RL_PROJ:
820 					ia->dlightShader = tr.defaultProjectedLightShader;
821 					break;
822 			}
823 		}
824 		else
825 		{
826 			switch (light->l.rlType)
827 			{
828 				default:
829 				case RL_OMNI:
830 					ia->dlightShader = tr.defaultDynamicLightShader;
831 					break;
832 
833 				case RL_PROJ:
834 					ia->dlightShader = tr.defaultProjectedLightShader;
835 					break;
836 			}
837 		}
838 	}
839 	else
840 	{
841 		ia->dlightShader = R_GetShaderByHandle(light->l.attenuationShader);
842 	}
843 
844 	ia->next = NULL;
845 
846 	ia->type = iaType;
847 
848 	ia->dlight = light;
849 	ia->entity = tr.currentEntity;
850 	ia->surface = surface;
851 	ia->surfaceShader = surfaceShader;
852 
853 	ia->numLightIndexes = numLightIndexes;
854 	ia->lightIndexes = lightIndexes;
855 
856 	ia->numShadowIndexes = numShadowIndexes;
857 	ia->shadowIndexes = shadowIndexes;
858 
859 	ia->scissorX = light->scissor.coords[0];
860 	ia->scissorY = light->scissor.coords[1];
861 	ia->scissorWidth = light->scissor.coords[2] - light->scissor.coords[0];
862 	ia->scissorHeight = light->scissor.coords[3] - light->scissor.coords[1];
863 
864 	if(qglDepthBoundsEXT)
865 	{
866 		ia->depthNear = light->depthBounds[0];
867 		ia->depthFar = light->depthBounds[1];
868 		ia->noDepthBoundsTest = light->noDepthBoundsTest;
869 	}
870 
871 	if(light->isStatic)
872 	{
873 		tr.pc.c_slightInteractions++;
874 	}
875 	else
876 	{
877 		tr.pc.c_dlightInteractions++;
878 	}
879 }
880 
881 
882 /*
883 =================
884 InteractionCompare
885 compare function for qsort()
886 =================
887 */
InteractionCompare(const void * a,const void * b)888 static int InteractionCompare(const void *a, const void *b)
889 {
890 #if 1
891 	// shader first
892 	if(((interaction_t *) a)->surfaceShader < ((interaction_t *) b)->surfaceShader)
893 		return -1;
894 
895 	else if(((interaction_t *) a)->surfaceShader > ((interaction_t *) b)->surfaceShader)
896 		return 1;
897 #endif
898 
899 #if 1
900 	// then entity
901 	if(((interaction_t *) a)->entity == &tr.worldEntity && ((interaction_t *) b)->entity != &tr.worldEntity)
902 		return -1;
903 
904 	else if(((interaction_t *) a)->entity != &tr.worldEntity && ((interaction_t *) b)->entity == &tr.worldEntity)
905 		return 1;
906 
907 	else if(((interaction_t *) a)->entity < ((interaction_t *) b)->entity)
908 		return -1;
909 
910 	else if(((interaction_t *) a)->entity > ((interaction_t *) b)->entity)
911 		return 1;
912 #endif
913 
914 	return 0;
915 }
916 
917 /*
918 =================
919 R_SortInteractions
920 =================
921 */
R_SortInteractions(trRefDlight_t * light)922 void R_SortInteractions(trRefDlight_t * light)
923 {
924 	int             i;
925 	interaction_t  *ia;
926 	interaction_t  *iaLast;
927 
928 	if(r_noInteractionSort->integer)
929 	{
930 		return;
931 	}
932 
933 	if(!light->numInteractions || light->noSort)
934 	{
935 		return;
936 	}
937 
938 	ia = &tr.refdef.interactions[light->firstInteractionIndex];
939 
940 	// sort by material etc. for geometry batching in the renderer backend
941 	qsort(ia, light->numInteractions, sizeof(interaction_t), InteractionCompare);
942 
943 	// fix linked list
944 	iaLast = NULL;
945 	for(i = 0; i < light->numInteractions; i++)
946 	{
947 		ia = &tr.refdef.interactions[light->firstInteractionIndex + i];
948 
949 		if(iaLast)
950 		{
951 			iaLast->next = ia;
952 		}
953 
954 		ia->next = NULL;
955 
956 		iaLast = ia;
957 	}
958 }
959 
960 
961 /*
962 =================
963 R_IntersectRayPlane
964 =================
965 */
R_IntersectRayPlane(const vec3_t v1,const vec3_t v2,cplane_t * plane,vec3_t res)966 static void R_IntersectRayPlane(const vec3_t v1, const vec3_t v2, cplane_t * plane, vec3_t res)
967 {
968 	vec3_t          v;
969 	float           sect;
970 
971 	VectorSubtract(v1, v2, v);
972 	sect = -(DotProduct(plane->normal, v1) - plane->dist) / DotProduct(plane->normal, v);
973 	VectorScale(v, sect, v);
974 	VectorAdd(v1, v, res);
975 }
976 
977 
978 /*
979 =================
980 R_AddPointToLightScissor
981 =================
982 */
R_AddPointToLightScissor(trRefDlight_t * light,const vec3_t world)983 static void R_AddPointToLightScissor(trRefDlight_t * light, const vec3_t world)
984 {
985 	vec4_t          eye, clip, normalized, window;
986 
987 	R_TransformWorldToClip(world, tr.viewParms.world.viewMatrix, tr.viewParms.projectionMatrix, eye, clip);
988 	R_TransformClipToWindow(clip, &tr.viewParms, normalized, window);
989 
990 	if(window[0] > light->scissor.coords[2])
991 		light->scissor.coords[2] = (int)window[0];
992 
993 	if(window[0] < light->scissor.coords[0])
994 		light->scissor.coords[0] = (int)window[0];
995 
996 	if(window[1] > light->scissor.coords[3])
997 		light->scissor.coords[3] = (int)window[1];
998 
999 	if(window[1] < light->scissor.coords[1])
1000 		light->scissor.coords[1] = (int)window[1];
1001 }
1002 
1003 /*
1004 =================
1005 R_AddEdgeToLightScissor
1006 =================
1007 */
R_AddEdgeToLightScissor(trRefDlight_t * light,vec3_t local1,vec3_t local2)1008 static void R_AddEdgeToLightScissor(trRefDlight_t * light, vec3_t local1, vec3_t local2)
1009 {
1010 	int             i;
1011 	vec3_t          intersect;
1012 	vec3_t          world1, world2;
1013 	qboolean        side1, side2;
1014 	cplane_t       *frust;
1015 
1016 	for(i = 0; i < FRUSTUM_PLANES; i++)
1017 	{
1018 		R_LocalPointToWorld(local1, world1);
1019 		R_LocalPointToWorld(local2, world2);
1020 
1021 		frust = &tr.viewParms.frustum[i];
1022 
1023 		// check edge to frustrum plane
1024 		side1 = ((DotProduct(frust->normal, world1) - frust->dist) >= 0.0);
1025 		side2 = ((DotProduct(frust->normal, world2) - frust->dist) >= 0.0);
1026 
1027 		if(!side1 && !side2)
1028 			continue;					// edge behind plane
1029 
1030 		if(!side1 || !side2)
1031 			R_IntersectRayPlane(world1, world2, frust, intersect);
1032 
1033 		if(!side1)
1034 		{
1035 			VectorCopy(intersect, world1);
1036 		}
1037 		else if(!side2)
1038 		{
1039 			VectorCopy(intersect, world2);
1040 		}
1041 
1042 		R_AddPointToLightScissor(light, world1);
1043 		R_AddPointToLightScissor(light, world2);
1044 	}
1045 }
1046 
1047 /*
1048 =================
1049 R_SetDlightScissor
1050 Recturns the screen space rectangle taken by the box.
1051 	(Clips the box to the near plane to have correct results even if the box intersects the near plane)
1052 Tr3B - recoded from Tenebrae2
1053 =================
1054 */
R_SetupDlightScissor(trRefDlight_t * light)1055 void R_SetupDlightScissor(trRefDlight_t * light)
1056 {
1057 	vec3_t          v1, v2;
1058 
1059 	light->scissor.coords[0] = tr.viewParms.viewportX;
1060 	light->scissor.coords[1] = tr.viewParms.viewportY;
1061 	light->scissor.coords[2] = tr.viewParms.viewportX + tr.viewParms.viewportWidth;
1062 	light->scissor.coords[3] = tr.viewParms.viewportY + tr.viewParms.viewportHeight;
1063 
1064 	if(r_noLightScissors->integer || R_CullLightPoint(light, tr.viewParms.or.origin) == CULL_IN)
1065 	{
1066 		return;
1067 	}
1068 
1069 	// transform local light corners to world space -> eye space -> clip space -> window space
1070 	// and extend the light scissor's mins maxs by resulting window coords
1071 	light->scissor.coords[0] = 100000000;
1072 	light->scissor.coords[1] = 100000000;
1073 	light->scissor.coords[2] = -100000000;
1074 	light->scissor.coords[3] = -100000000;
1075 
1076 	// top plane
1077 	VectorSet(v1, light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1078 	VectorSet(v2, light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1079 	R_AddEdgeToLightScissor(light, v1, v2);
1080 
1081 	VectorSet(v1, light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1082 	VectorSet(v2, light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1083 	R_AddEdgeToLightScissor(light, v1, v2);
1084 
1085 	VectorSet(v1, light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1086 	VectorSet(v2, light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1087 	R_AddEdgeToLightScissor(light, v1, v2);
1088 
1089 	VectorSet(v1, light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1090 	VectorSet(v2, light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1091 	R_AddEdgeToLightScissor(light, v1, v2);
1092 
1093 	// bottom plane
1094 	VectorSet(v1, light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1095 	VectorSet(v2, light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1096 	R_AddEdgeToLightScissor(light, v1, v2);
1097 
1098 	VectorSet(v1, light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1099 	VectorSet(v2, light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1100 	R_AddEdgeToLightScissor(light, v1, v2);
1101 
1102 	VectorSet(v1, light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1103 	VectorSet(v2, light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1104 	R_AddEdgeToLightScissor(light, v1, v2);
1105 
1106 	VectorSet(v1, light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1107 	VectorSet(v2, light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1108 	R_AddEdgeToLightScissor(light, v1, v2);
1109 
1110 	// sides
1111 	VectorSet(v1, light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1112 	VectorSet(v2, light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1113 	R_AddEdgeToLightScissor(light, v1, v2);
1114 
1115 	VectorSet(v1, light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1116 	VectorSet(v2, light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1117 	R_AddEdgeToLightScissor(light, v1, v2);
1118 
1119 	VectorSet(v1, light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1120 	VectorSet(v2, light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1121 	R_AddEdgeToLightScissor(light, v1, v2);
1122 
1123 	VectorSet(v1, light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1124 	VectorSet(v2, light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1125 	R_AddEdgeToLightScissor(light, v1, v2);
1126 }
1127 
1128 
1129 /*
1130 =================
1131 R_SetupDlightDepthBounds
1132 =================
1133 */
R_SetupDlightDepthBounds(trRefDlight_t * dl)1134 void R_SetupDlightDepthBounds(trRefDlight_t * dl)
1135 {
1136 	int             i, j;
1137 	vec3_t          v, world;
1138 	vec4_t          eye, clip, normalized, window;
1139 	float           depthMin, depthMax;
1140 
1141 	if(qglDepthBoundsEXT)
1142 	{
1143 		tr.pc.c_depthBoundsTestsRejected++;
1144 
1145 		depthMin = 1.0;
1146 		depthMax = 0.0;
1147 
1148 		for(j = 0; j < 8; j++)
1149 		{
1150 			v[0] = dl->localBounds[j & 1][0];
1151 			v[1] = dl->localBounds[(j >> 1) & 1][1];
1152 			v[2] = dl->localBounds[(j >> 2) & 1][2];
1153 
1154 			// transform local bounds vertices into world space
1155 			MatrixTransformPoint(dl->transformMatrix, v, world);
1156 
1157 			R_TransformWorldToClip(world, tr.viewParms.world.viewMatrix, tr.viewParms.projectionMatrix, eye, clip);
1158 
1159 			// check to see if the point is completely off screen
1160 			for(i = 0; i < 3; i++)
1161 			{
1162 				if(clip[i] >= clip[3] || clip[i] <= -clip[3])
1163 				{
1164 					dl->noDepthBoundsTest = qtrue;
1165 					return;
1166 				}
1167 			}
1168 
1169 			R_TransformClipToWindow(clip, &tr.viewParms, normalized, window);
1170 
1171 			if(window[0] < 0 || window[0] >= tr.viewParms.viewportWidth
1172 			|| window[1] < 0 || window[1] >= tr.viewParms.viewportHeight)
1173 			{
1174 				// shouldn't happen, since we check the clip[] above, except for FP rounding
1175 				dl->noDepthBoundsTest = qtrue;
1176 				return;
1177 			}
1178 
1179 			depthMin = min(normalized[2], depthMin);
1180 			depthMax = max(normalized[2], depthMax);
1181 		}
1182 
1183 		if(depthMin > depthMax)
1184 		{
1185 			// light behind near plane or clipped
1186 			dl->noDepthBoundsTest = qtrue;
1187 		}
1188 		else
1189 		{
1190 			dl->noDepthBoundsTest = qfalse;
1191 			dl->depthBounds[0] = depthMin;
1192 			dl->depthBounds[1] = depthMax;
1193 
1194 			tr.pc.c_depthBoundsTestsRejected--;
1195 			tr.pc.c_depthBoundsTests++;
1196 		}
1197 	}
1198 }
1199 
1200 /*
1201 =================
1202 R_CullLightPoint
1203 
1204 Returns CULL_IN, CULL_CLIP, or CULL_OUT
1205 =================
1206 */
R_CullLightPoint(trRefDlight_t * light,const vec3_t p)1207 int R_CullLightPoint(trRefDlight_t * light, const vec3_t p)
1208 {
1209 	int             i;
1210 	cplane_t       *frust;
1211 	float           dist;
1212 
1213 	// check against frustum planes
1214 	for(i = 0; i < 6; i++)
1215 	{
1216 		frust = &light->frustum[i];
1217 
1218 		dist = DotProduct(p, frust->normal) - frust->dist;
1219 		if(dist < 0)
1220 		{
1221 			// completely outside frustum
1222 			return CULL_OUT;
1223 		}
1224 	}
1225 
1226 	// completely inside frustum
1227 	return CULL_IN;
1228 }
1229 
1230 /*
1231 =================
1232 R_CullLightTriangle
1233 
1234 Returns CULL_IN, CULL_CLIP, or CULL_OUT
1235 =================
1236 */
R_CullLightTriangle(trRefDlight_t * light,vec3_t verts[3])1237 int R_CullLightTriangle(trRefDlight_t * light, vec3_t verts[3])
1238 {
1239 	int             i;
1240 	vec3_t          worldBounds[2];
1241 
1242 	if(r_nocull->integer)
1243 	{
1244 		return CULL_CLIP;
1245 	}
1246 
1247 	// calc AABB of the triangle
1248 	ClearBounds(worldBounds[0], worldBounds[1]);
1249 	for(i = 0; i < 3; i++)
1250 	{
1251 		AddPointToBounds(verts[i], worldBounds[0], worldBounds[1]);
1252 	}
1253 
1254 	return R_CullLightWorldBounds(light, worldBounds);
1255 }
1256 
1257 /*
1258 =================
1259 R_CullLightTriangle
1260 
1261 Returns CULL_IN, CULL_CLIP, or CULL_OUT
1262 =================
1263 */
R_CullLightWorldBounds(trRefDlight_t * light,vec3_t worldBounds[2])1264 int R_CullLightWorldBounds(trRefDlight_t * light, vec3_t worldBounds[2])
1265 {
1266 	int             i;
1267 	cplane_t       *frust;
1268 	qboolean        anyClip;
1269 	int             r;
1270 
1271 	if(r_nocull->integer)
1272 	{
1273 		return CULL_CLIP;
1274 	}
1275 
1276 	// check against frustum planes
1277 	anyClip = qfalse;
1278 	for(i = 0; i < 6; i++)
1279 	{
1280 		frust = &light->frustum[i];
1281 
1282 		r = BoxOnPlaneSide(worldBounds[0], worldBounds[1], frust);
1283 
1284 		if(r == 2)
1285 		{
1286 			// completely outside frustum
1287 			return CULL_OUT;
1288 		}
1289 		if(r == 3)
1290 		{
1291 			anyClip = qtrue;
1292 		}
1293 	}
1294 
1295 	if(!anyClip)
1296 	{
1297 		// completely inside frustum
1298 		return CULL_IN;
1299 	}
1300 
1301 	// partially clipped
1302 	return CULL_CLIP;
1303 }
1304