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