1 /*
2 Copyright (C) 2001-2002 Charles Hollemeersch
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 PENTA: the whole file is freakin penta...
20
21 */
22
23 // gl_shadow.c stencil shadow support for quake
24
25 #include "quakedef.h"
26
27 int numShadowLights;
28 int numStaticShadowLights;
29 int numUsedShadowLights; //number of shadow lights acutally drawn this frame
30
31 shadowlight_t shadowlights[MAXSHADOWLIGHTS];
32 shadowlight_t *usedshadowlights[MAXUSEDSHADOWLIGHS];
33 shadowlight_t *currentshadowlight;
34
35
36 int volumeCmdsBuff[MAX_VOLUME_COMMANDS+128]; //Hack protect against slight overflows
37 float volumeVertsBuff[MAX_VOLUME_VERTS+128];
38 lightcmd_t lightCmdsBuff[MAX_LIGHT_COMMANDS+128];
39 int numVolumeCmds;
40 int numLightCmds;
41 int numVolumeVerts;
42
43 msurface_t *shadowchain; //linked list of polygons that are shadowed
44 byte *lightvis;
45 byte worldvis[MAX_MAP_LEAFS/8];
46
47 /* -DC- isn't that volumeVertsBuff ?
48 vec3_t volumevertices[MAX_VOLUME_VERTICES];//buffer for the vertices of the shadow volume
49 int usedvolumevertices;
50 */
51
52 void DrawVolumeFromCmds(int *volumeCmds, lightcmd_t *lightCmds, float *volumeVerts);
53 void DrawAttentFromCmds(lightcmd_t *lightCmds);
54 void DrawBumpFromCmds(lightcmd_t *lightCmds);
55 void DrawSpecularBumpFromCmds(lightcmd_t *lightCmds);
56 void PrecalcVolumesForLight(model_t *model);
57 int getVertexIndexFromSurf(msurface_t *surf, int index, model_t *model);
58 qboolean R_ContributeFrame(shadowlight_t *light);
59
60 /*
61 =============
62 AllocShadowLight
63 =============
64 */
AllocShadowLight(void)65 shadowlight_t* AllocShadowLight(void) {
66
67 if (numShadowLights >= MAXSHADOWLIGHTS) {
68 return NULL;
69 }
70
71 shadowlights[numShadowLights].owner = NULL;
72 numShadowLights++;
73 return &shadowlights[numShadowLights-1];
74 }
75
76 /*
77 =============
78 R_ShadowFromDlight
79 =============
80 */
R_ShadowFromDlight(dlight_t * light)81 void R_ShadowFromDlight(dlight_t *light) {
82
83 shadowlight_t *l;
84
85 l = AllocShadowLight();
86 if (!l) return;
87
88 VectorCopy(light->origin,l->origin);
89 l->radius = light->radius;
90 l->color[0] = light->color[0];
91 l->color[1] = light->color[1];
92 l->color[2] = light->color[2];
93 l->baseColor[0] = light->color[0];
94 l->baseColor[1] = light->color[1];
95 l->baseColor[2] = light->color[2];
96 l->style = 0;
97 l->brightness = 1;
98 l->isStatic = false;
99 l->numVisSurf = 0;
100 l->visSurf = NULL;
101 l->style = light->style;
102 l->owner = light->owner;
103
104 //VectorCopy(light->angles,l->angles);
105
106 //We use some different angle convention
107 l->angles[1] = light->angles[0];
108 l->angles[0] = light->angles[2];
109 l->angles[2] = light->angles[1];
110
111 l->filtercube = light->filtercube;
112 l->rspeed = 0;
113 l->cubescale = 1;
114 l->castShadow = true;
115
116 //Some people will be instulted by the mere existence of this flag.
117 if (light->pflags & PFLAG_NOSHADOW) {
118 l->castShadow = false;
119 } else {
120 l->castShadow = true;
121 }
122
123 if (light->pflags & PFLAG_HALO) {
124 l->halo = true;
125 } else {
126 l->halo = false;
127 }
128 }
129
130
131 #define NUM_CUBEMAPS 64
132 int cubemap_tex_obj [NUM_CUBEMAPS];
133
134
135 /*
136 =============
137 R_CubeMapLookup
138 =============
139 */
R_CubeMapLookup(int i)140 int R_CubeMapLookup(int i) {
141
142 if (i > NUM_CUBEMAPS) {
143 return 0;
144 } else {
145 if (!cubemap_tex_obj[i]) {
146 cubemap_tex_obj[i] = GL_LoadCubeMap(i);
147 }
148 return cubemap_tex_obj[i];
149 }
150 }
151
152 /*
153 =============
154 R_ShadowFromEntity
155 =============
156 */
R_ShadowFromEntity(entity_t * ent)157 void R_ShadowFromEntity(entity_t *ent) {
158
159 shadowlight_t *l;
160
161 l = AllocShadowLight();
162 if (!l) return;
163
164 VectorCopy(ent->origin,l->origin);
165 l->radius = 350;
166 l->color[0] = 1;
167 l->color[1] = 1;
168 l->color[2] = 1;
169 l->style = 0;
170 l->brightness = 1;
171 l->isStatic = false;
172 l->numVisSurf = 0;
173 l->visSurf = NULL;
174 l->style = 0;
175 l->owner = ent;
176
177 l->style = ent->style;
178
179 if (ent->light_lev != 0) {
180 l->radius = ent->light_lev;
181 } else {
182 l->radius = 350;
183 }
184
185 VectorCopy(ent->color,l->baseColor);
186
187 if ((l->baseColor[0] == 0) && (l->baseColor[1] == 0) && (l->baseColor[2] == 0)) {
188 l->baseColor[0] = 1;
189 l->baseColor[1] = 1;
190 l->baseColor[2] = 1;
191 }
192
193 if (ent->skinnum >= 16) {
194 l->filtercube = R_CubeMapLookup(ent->skinnum);
195 } else {
196 l->filtercube = 0;
197 }
198
199 //We use some different angle convention
200 l->angles[1] = ent->angles[0];
201 l->angles[0] = ent->angles[2];
202 l->angles[2] = ent->angles[1];
203
204
205 l->rspeed = ent->alpha*512;
206 l->cubescale = 1;
207
208 //Some people will be instulted by the mere existence of this flag.
209 if (ent->pflags & PFLAG_NOSHADOW) {
210 l->castShadow = false;
211 } else {
212 l->castShadow = true;
213 }
214
215 if (ent->pflags & PFLAG_HALO) {
216 l->halo = true;
217 } else {
218 l->halo = false;
219 }
220
221 }
222
223 /*
224 =============
225 R_MarkDLights
226
227 Adds dynamic lights to the shadow light list
228 =============
229 */
R_MarkDlights(void)230 void R_MarkDlights (void)
231 {
232 int i;
233 dlight_t *l;
234
235 l = cl_dlights;
236 for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
237 {
238 if (l->die < cl.time || !l->radius)
239 continue;
240 R_ShadowFromDlight(l);
241 }
242 }
243
244
245 /*
246 =============
247 R_MarkEntities
248
249 Adds entities that have a lightsource attched to
250 the shadow light list.
251 (used for static ents)
252 We just check if they have a torch/flame model or not.
253 =============
254 */
R_MarkEntities(void)255 void R_MarkEntities (void)
256 {
257 int i;
258 entity_t *current;
259
260 for (i=0 ; i<cl.num_statics; i++)
261 {
262 current = &cl_static_entities[i];
263
264 if (!strcmp (current->model->name, "progs/flame2.mdl")
265 || !strcmp (current->model->name, "progs/flame.mdl") )
266 {
267 R_ShadowFromEntity(current);
268 }
269 }
270 }
271
272 int cut_ent;
273
274 /*
275 =============
276 R_InitShadowsForFrame
277
278 Do per frame intitialization for the shadows
279 =============
280 */
R_InitShadowsForFrame(void)281 void R_InitShadowsForFrame(void) {
282
283 byte *vis;
284 int i;
285
286 numShadowLights = numStaticShadowLights;
287
288 R_MarkDlights (); //add dynamic lights to the list
289 // R_ShadowFromPlayer();//give the player some sort of torch
290
291 numUsedShadowLights = 0;
292
293 //if (cut_ent) Con_Printf("cut ents: %i\n",cut_ent);
294 cut_ent = 0;
295 Q_memset (&worldvis, 0, MAX_MAP_LEAFS/8); //all invisible
296
297 vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
298 Q_memcpy(&worldvis, vis, MAX_MAP_LEAFS/8);
299
300 for (i=0; i<numShadowLights; i++) {
301 currentshadowlight = &shadowlights[i];
302 if (R_ContributeFrame(currentshadowlight)) {
303 currentshadowlight->visible = true;
304 if (numUsedShadowLights < MAXUSEDSHADOWLIGHS) {
305 usedshadowlights[numUsedShadowLights] = currentshadowlight;
306 numUsedShadowLights++;
307 } else {
308 Con_Printf("R_InitShadowsForFrame: More than MAXUSEDSHADOWLIGHS lights for frame\n");
309 }
310 } else {
311 currentshadowlight->visible = false;
312 }
313 }
314 }
315
316
R_MarkShadowSurf(msurface_t * surf,shadowlight_t * light)317 qboolean R_MarkShadowSurf(msurface_t *surf, shadowlight_t *light)
318 {
319 mplane_t *plane;
320 float dist;
321 glpoly_t *poly;
322
323 //we don't cast shadows with water
324 if (( surf->flags & SURF_DRAWTURB ) || ( surf->flags & SURF_DRAWSKY )) {
325 return false;
326 }
327
328 plane = surf->plane;
329
330 poly = surf->polys;
331
332 if (poly->lightTimestamp == r_lightTimestamp) {
333 return false;
334 }
335
336 switch (plane->type)
337 {
338 case PLANE_X:
339 dist = light->origin[0] - plane->dist;
340 break;
341 case PLANE_Y:
342 dist = light->origin[1] - plane->dist;
343 break;
344 case PLANE_Z:
345 dist = light->origin[2] - plane->dist;
346 break;
347 default:
348 dist = DotProduct (light->origin, plane->normal) - plane->dist;
349 break;
350 }
351
352 //the normals are flipped when surf_planeback is 1
353 if (((surf->flags & SURF_PLANEBACK) && (dist > 0)) ||
354 (!(surf->flags & SURF_PLANEBACK) && (dist < 0)))
355 {
356 return false;
357 }
358
359 //the normals are flipped when surf_planeback is 1
360 if ( abs(dist) > light->radius)
361 {
362 return false;
363 }
364
365 poly->lightTimestamp = r_lightTimestamp;
366
367 return true;
368 }
369
370 #define MAX_LEAF_LIST 32
371 mleaf_t *leafList[MAX_LEAF_LIST];
372 int numLeafList;
373 extern vec3_t r_emins, r_emaxs; // <AWE> added "extern".
374
375 /*
376 =============
377
378 InShadowEntity
379
380 Some efrag based sceme may cut even more ents!
381 =============
382 */
383
InShadowEntity(entity_t * ent)384 qboolean InShadowEntity(entity_t *ent) {
385
386 int i, leafindex;
387
388 model_t *entmodel = ent->model;
389 vec3_t dst;
390 float radius, d;
391
392 radius = entmodel->radius;
393 VectorSubtract (currentshadowlight->origin, ent->origin, dst);
394 d = Length (dst);
395
396 if (d < (currentshadowlight->radius + radius)) {
397
398 if (sh_noefrags.value) return true;
399
400 for (i=0; i<ent->numleafs;i++) {
401 leafindex = ent->leafnums[i];
402 //leaf ent is in is visible from light
403 if (currentshadowlight->entvis[leafindex>>3] & (1<<(leafindex&7)))
404 {
405 return true;
406 }
407 }
408 if (ent->numleafs == 0) {
409 //Con_Printf("Ent with no leafs");
410 return true;
411 }
412 return false;
413 }
414 return false;
415 }
416
417 /*
418 =============
419
420 R_VisibleEntity
421
422 Adds shadow casting ents to the list
423 =============
424 */
MarkShadowEntities()425 void MarkShadowEntities() {
426
427 int i;
428 vec3_t mins, maxs;
429
430 if (!r_drawentities.value)
431 return;
432
433 cl_numlightvisedicts = 0;
434 for (i=0 ; i<cl_numvisedicts ; i++)
435 {
436 currententity = cl_visedicts[i];
437
438 if ((currententity->model->flags & EF_NOSHADOW) && (currententity->model->flags & EF_FULLBRIGHT)) {
439 continue;
440 }
441
442 if (mirror) {
443 VectorAdd (currententity->origin,currententity->model->mins, mins);
444 VectorAdd (currententity->origin,currententity->model->maxs, maxs);
445 if (mirror_clipside == BoxOnPlaneSide(mins, maxs, mirror_plane)) {
446 continue;
447 }
448
449 if ( BoxOnPlaneSide(mins, maxs, &mirror_far_plane) == 1) {
450 return;
451 }
452 }
453
454 //Dont cast shadows with the ent this light is attached to because
455 //when the light is partially in the model shadows will look weird.
456 //FIXME: Model is not lit by its own light.
457 if (currententity != currentshadowlight->owner)
458 {
459 if (InShadowEntity(currententity)) {
460 currententity->lightTimestamp = r_lightTimestamp;
461 cl_lightvisedicts[cl_numlightvisedicts] = currententity;
462 cl_numlightvisedicts++;
463 } else cut_ent++;
464 }
465 }
466 }
467
468 /*
469 =============
470 R_ProjectSphere
471
472 Returns the rectangle the sphere will be in when it is drawn.
473 FIXME: This is crappy code we draw a "sprite" and project those points
474 it should be possible to analytically derive a eq.
475
476 =============
477 */
R_ProjectSphere(shadowlight_t * light,int * rect)478 void R_ProjectSphere (shadowlight_t *light, int *rect)
479 {
480 int i, j;
481 float a;
482 vec3_t v, vp2;
483 float rad;
484 double minx, maxx, miny, maxy;
485 double px, py, pz;
486
487 rad = light->radius;
488 /*
489 rect[0] = 100;
490 rect[1] = 100;
491 rect[2] = 300;
492 rect[3] = 300;
493
494 return;
495 */
496 VectorSubtract (light->origin, r_origin, v);
497
498 //dave - slight fix
499 VectorSubtract (light->origin, r_origin, vp2);
500 VectorNormalize(vp2);
501
502 minx = 1000000;
503 miny = 1000000;
504 maxx = -1000000;
505 maxy = -1000000;
506
507 for (i=16 ; i>=0 ; i--)
508 {
509 a = i/16.0 * M_PI*2;
510 for (j=0 ; j<3 ; j++)
511 v[j] = light->origin[j] + vright[j]*cos(a)*rad + vup[j]*sin(a)*rad;
512
513 gluProject(v[0], v[1], v[2], r_Dworld_matrix, r_Dproject_matrix,
514 (GLint *) r_Iviewport, &px, &py, &pz); // <AWE> added cast.
515
516 if (px > maxx) maxx = px;
517 if (px < minx) minx = px;
518 if (py > maxy) maxy = py;
519 if (py < miny) miny = py;
520
521 }
522
523 rect[0] = (int)minx;
524 rect[1] = (int)miny;
525 rect[2] = (int)maxx;
526 rect[3] = (int)maxy;
527 }
528
529 /**************************************************************
530
531 World model shadow volumes
532
533 ***************************************************************/
534
535
536 /*
537 =============
538
539 HasSharedLeaves
540
541 Returns true if both vis arrays have shared leafs visible.
542 FIXME: compare bytes at a time (what does quake fill the unused bits with??)
543 =============
544 */
HasSharedLeafs(byte * v1,byte * v2)545 qboolean HasSharedLeafs(byte *v1, byte *v2) {
546
547 int i;
548
549 for (i=0 ; i<cl.worldmodel->numleafs ; i++)
550 {
551 if (v1[i>>3] & (1<<(i&7)))
552 {
553 if (v2[i>>3] & (1<<(i&7)))
554 return true;
555 }
556 }
557 return false;
558 }
559
560 /*
561 =============
562
563 R_MarkShadowCasting
564
565 Fills the shadow chain with polygons we should consider.
566
567 Polygons that will be added are:
568 1. In the light volume. (sphere)
569 2. "Visible" to the light.
570
571 Visible is:
572 a. facing the light (dotprod > 0)
573 b. in a leaf that is visible from the light's leaf. (based on vis data)
574
575 This is crude for satic lights we use extra tricks (svbsp / revis) to
576 reduce the number of polyons.
577 =============
578 */
R_MarkShadowCasting(shadowlight_t * light,mnode_t * node)579 void R_MarkShadowCasting (shadowlight_t *light, mnode_t *node)
580 {
581 mplane_t *plane;
582 float dist;
583 msurface_t **surf;
584 mleaf_t *leaf;
585 int c,leafindex;
586
587 if (node->contents < 0) {
588 //we are in a leaf
589 leaf = (mleaf_t *)node;
590 leafindex = leaf->index-1;
591
592 //is this leaf visible from the light
593 if (!(lightvis[leafindex>>3] & (1<<(leafindex&7)))) {
594 return;
595 }
596
597 c = leaf->nummarksurfaces;
598 surf = leaf->firstmarksurface;
599
600 for (c=0; c<leaf->nummarksurfaces; c++, surf++) {
601
602 if (R_MarkShadowSurf ((*surf), light)) {
603 (*surf)->shadowchain = shadowchain;
604 shadowchain = (*surf);
605 //svBsp_NumKeptPolys++;
606 }
607 }
608
609 return;
610 }
611
612 plane = node->plane;
613 dist = DotProduct (light->origin, plane->normal) - plane->dist;
614
615 if (dist > light->radius)
616 {
617 R_MarkShadowCasting (light, node->children[0]);
618 return;
619 }
620 if (dist < -light->radius)
621 {
622 R_MarkShadowCasting (light, node->children[1]);
623 return;
624 }
625
626 R_MarkShadowCasting (light, node->children[0]);
627 R_MarkShadowCasting (light, node->children[1]);
628 }
629
SphereInFrustum(vec3_t o,float radius)630 float SphereInFrustum( vec3_t o, float radius )
631 {
632 int p;
633 float d;
634
635 for( p = 0; p < 6; p++ )
636 {
637 d = frustumPlanes[p][0] * o[0] + frustumPlanes[p][1] * o[1] + frustumPlanes[p][2] * o[2] + frustumPlanes[p][3];
638 if( d <= -radius )
639 return 0;
640 }
641 return d + radius;
642 }
643
644 /*
645 =============
646 R_ContributeFrame
647
648 Returns true if the light should be rendered.
649
650 =============
651 */
R_ContributeFrame(shadowlight_t * light)652 qboolean R_ContributeFrame (shadowlight_t *light)
653 {
654 mleaf_t *lightleaf;
655 float dist;
656
657 float b = d_lightstylevalue[light->style]/255.0;
658
659 light->color[0] = light->baseColor[0] * b;
660 light->color[1] = light->baseColor[1] * b;
661 light->color[2] = light->baseColor[2] * b;
662
663 //verry soft light, don't bother.
664 if (b < 0.1) return false;
665
666 //frustum scissor testing
667 dist = SphereInFrustum(light->origin, light->radius);
668 if (dist == 0) {
669 //whole sphere is out ouf frustum so cut it.
670 return false;
671 }
672
673 //fully/partially in frustum
674
675 if (!sh_noscissor.value) {
676 vec3_t dst;
677 float d;
678 VectorSubtract (light->origin, r_refdef.vieworg, dst);
679 d = Length (dst);
680
681 if (d > light->radius) {
682
683 R_ProjectSphere (light, light->scizz.coords);
684 //glScissor(light->scizz.coords[0], light->scizz.coords[1],
685 // light->scizz.coords[2]-light->scizz.coords[0], light->scizz.coords[3]-light->scizz.coords[1]);
686 } else {
687 //viewport is ofs/width based
688 light->scizz.coords[0] = r_Iviewport[0];
689 light->scizz.coords[1] = r_Iviewport[1];
690 light->scizz.coords[2] = r_Iviewport[0]+r_Iviewport[2];
691 light->scizz.coords[3] = r_Iviewport[1]+r_Iviewport[3];
692 //glScissor(r_Iviewport[0], r_Iviewport[1], r_Iviewport[2], r_Iviewport[3]);
693 }
694 }
695
696 //r_lightTimestamp++;
697
698 shadowchain = NULL;
699 if (light->isStatic) {
700 lightvis = &light->vis[0];
701 } else {
702 lightleaf = Mod_PointInLeaf (light->origin, cl.worldmodel);
703 lightvis = Mod_LeafPVS (lightleaf, cl.worldmodel);
704 Q_memcpy(&light->vis,lightvis,MAX_MAP_LEAFS/8);
705 Q_memcpy(&light->entvis, lightvis, MAX_MAP_LEAFS/8);
706 }
707
708 if (HasSharedLeafs(lightvis,&worldvis[0])) {
709
710 //light->visible = true;
711 //numUsedShadowLights++;
712
713 //mark shadow casting ents
714 //MarkShadowEntities();
715
716 //mark shadow casting polygons
717 //if (!light->isStatic) {
718 // R_MarkShadowCasting ( light, cl.worldmodel->nodes);
719 //} else {
720 // return true;
721 //}
722 //return (shadowchain) ? true : false;
723 return true;
724 } else {
725 return false;
726 }
727
728
729 }
730
731 /*
732 =============
733 R_FillShadowChain
734
735 Returns true if the light should be rendered.
736
737 =============
738 */
R_FillShadowChain(shadowlight_t * light)739 qboolean R_FillShadowChain (shadowlight_t *light)
740 {
741
742 r_lightTimestamp++;
743
744 shadowchain = NULL;
745
746 lightvis = &light->vis[0];
747 //numUsedShadowLights++;
748
749 //mark shadow casting ents
750 MarkShadowEntities();
751
752 //mark shadow casting polygons
753 if (!light->isStatic) {
754 R_MarkShadowCasting ( light, cl.worldmodel->nodes);
755 } else {
756 return true;
757 }
758
759 return (shadowchain) ? true : false;
760 }
761
762 void *VolumeVertsPointer;
763 /*
764 =============
765 R_ConstructShadowVolume
766
767 Calculate the shadow volume commands for the light.
768 (only if dynamic)
769 =============
770 */
R_ConstructShadowVolume(shadowlight_t * light)771 void R_ConstructShadowVolume(shadowlight_t *light) {
772
773 if (!light->isStatic) {
774 PrecalcVolumesForLight(cl.worldmodel);
775 light->volumeCmds = &volumeCmdsBuff[0];
776 light->volumeVerts = &volumeVertsBuff[0];
777 light->lightCmds = &lightCmdsBuff[0];
778 }
779
780 VolumeVertsPointer = light->volumeVerts;
781
782 if (gl_var) {
783 if (light->numVolumeVerts < AGP_BUFFER_SIZE/4) {
784 memcpy(AGP_Buffer,light->volumeVerts,light->numVolumeVerts*4);
785 VolumeVertsPointer = AGP_Buffer;
786 }
787 }
788 }
789
790 /*
791 =============
792 R_DrawShadowVolume
793
794 Draws the shadow volume, for statics this is the precalc one
795 for dynamics this is the R_ConstructShadowVolume one.
796
797 =============
798 */
R_DrawShadowVolume(shadowlight_t * light)799 void R_DrawShadowVolume(shadowlight_t *light) {
800
801
802 glDisable(GL_TEXTURE_2D);
803
804 /* if (!light->isStatic) {
805 glColor3f(0,1,0);
806 DrawVolumeFromCmds (&volumeCmdsBuff[0], &lightCmdsBuff[0]);
807 } else {
808 */
809 glColor3f(1,0,0);
810 DrawVolumeFromCmds (light->volumeCmds, light->lightCmds, VolumeVertsPointer);
811 // }
812
813 glColor3f(1,1,1);
814 glEnable(GL_TEXTURE_2D);
815 }
816
817
818 /**************************************************************
819
820
821 Brush model shadow volume support
822
823
824 ***************************************************************/
825
826 /*
827 =============
828 R_MarkBrushModelSurfaces
829
830 Set the light timestamps of the brush model.
831 =============
832 */
R_MarkBrushModelSurfaces(entity_t * e)833 void R_MarkBrushModelSurfaces(entity_t *e) {
834
835 vec3_t mins, maxs;
836 int i;
837 msurface_t *psurf;
838 model_t *clmodel;
839 qboolean rotated;
840
841 vec3_t oldlightorigin;
842 //backup light origin since we will have to translate
843 //light into model space
844 VectorCopy (currentshadowlight->origin, oldlightorigin);
845
846 currententity = e;
847 currenttexture = -1;
848
849 clmodel = e->model;
850
851 if (e->angles[0] || e->angles[1] || e->angles[2])
852 {
853 rotated = true;
854 for (i=0 ; i<3 ; i++)
855 {
856 mins[i] = e->origin[i] - clmodel->radius;
857 maxs[i] = e->origin[i] + clmodel->radius;
858 }
859 }
860 else
861 {
862 rotated = false;
863 VectorAdd (e->origin, clmodel->mins, mins);
864 VectorAdd (e->origin, clmodel->maxs, maxs);
865 }
866
867 VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
868 VectorSubtract (currentshadowlight->origin, e->origin, currentshadowlight->origin);
869 if (rotated)
870 {
871 vec3_t temp;
872 vec3_t forward, right, up;
873
874 VectorCopy (modelorg, temp);
875 AngleVectors (e->angles, forward, right, up);
876 modelorg[0] = DotProduct (temp, forward);
877 modelorg[1] = -DotProduct (temp, right);
878 modelorg[2] = DotProduct (temp, up);
879
880 VectorCopy (currentshadowlight->origin, temp);
881 currentshadowlight->origin[0] = DotProduct (temp, forward);
882 currentshadowlight->origin[1] = -DotProduct (temp, right);
883 currentshadowlight->origin[2] = DotProduct (temp, up);
884
885 }
886
887 psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
888
889 glPushMatrix ();
890 e->angles[0] = -e->angles[0]; // stupid quake bug
891 R_RotateForEntity (e);
892 e->angles[0] = -e->angles[0]; // stupid quake bug
893
894
895 for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
896 {
897 R_MarkShadowSurf(psurf, currentshadowlight);
898 }
899
900 VectorCopy(oldlightorigin,currentshadowlight->origin);
901 glPopMatrix ();
902 }
903
904
905 /*
906 =============
907 R_DrawBrushModelVolumes
908
909 Draw the shadow volumes of the brush model.
910 They are dynamically calculated.
911 =============
912 */
913 /*
914 void R_DrawBrushModelVolumes(entity_t *e) {
915
916 int j, k;
917 vec3_t mins, maxs;
918 int i, numsurfaces;
919 msurface_t *surf;
920 float dot;
921 mplane_t *pplane;
922 model_t *clmodel;
923 qboolean rotated;
924 glpoly_t *poly;
925 vec3_t v1,*v2;
926 float scale;
927 qboolean shadow;
928 vec3_t temp[32];
929
930
931 vec3_t oldlightorigin;
932
933 //backup light origin since we will have to translate
934 //light into model space
935 VectorCopy (currentshadowlight->origin, oldlightorigin);
936
937 currententity = e;
938 currenttexture = -1;
939
940 clmodel = e->model;
941
942 if (e->angles[0] || e->angles[1] || e->angles[2])
943 {
944 rotated = true;
945 for (i=0 ; i<3 ; i++)
946 {
947 mins[i] = e->origin[i] - clmodel->radius;
948 maxs[i] = e->origin[i] + clmodel->radius;
949 }
950 }
951 else
952 {
953 rotated = false;
954 VectorAdd (e->origin, clmodel->mins, mins);
955 VectorAdd (e->origin, clmodel->maxs, maxs);
956 }
957
958 VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
959 VectorSubtract (currentshadowlight->origin, e->origin, currentshadowlight->origin);
960 if (rotated)
961 {
962 vec3_t temp;
963 vec3_t forward, right, up;
964
965 VectorCopy (modelorg, temp);
966 AngleVectors (e->angles, forward, right, up);
967 modelorg[0] = DotProduct (temp, forward);
968 modelorg[1] = -DotProduct (temp, right);
969 modelorg[2] = DotProduct (temp, up);
970
971 VectorCopy (currentshadowlight->origin, temp);
972 currentshadowlight->origin[0] = DotProduct (temp, forward);
973 currentshadowlight->origin[1] = -DotProduct (temp, right);
974 currentshadowlight->origin[2] = DotProduct (temp, up);
975
976 }
977
978 surf = &clmodel->surfaces[clmodel->firstmodelsurface];
979
980 glPushMatrix ();
981 e->angles[0] = -e->angles[0]; // stupid quake bug
982 R_RotateForEntity (e);
983 e->angles[0] = -e->angles[0]; // stupid quake bug
984
985 for (i=0 ; i<clmodel->nummodelsurfaces ; i++, surf++)
986 {
987 if (surf->polys->lightTimestamp != r_lightTimestamp) continue;
988
989 poly = surf->polys;
990
991 for (j=0 ; j<surf->numedges ; j++)
992 {
993 v2 = (vec3_t *)&poly->verts[j];
994 VectorSubtract ( (*v2) ,currentshadowlight->origin, v1);
995 scale = Length (v1);
996
997 if (sh_visiblevolumes.value)
998 VectorScale (v1, (1/scale)*50, v1);
999 else
1000 VectorScale (v1, (1/scale)*currentshadowlight->radius*2, v1);
1001
1002 VectorAdd (v1, (*v2), temp[j]);
1003 }
1004
1005 //check if neighbouring polygons are shadowed
1006 for (j=0 ; j<surf->numedges ; j++)
1007 {
1008 shadow = false;
1009
1010 if (poly->neighbours[j] != NULL) {
1011 if ( poly->neighbours[j]->lightTimestamp != poly->lightTimestamp) {
1012 shadow = true;
1013 }
1014 } else {
1015 shadow = true;
1016 }
1017
1018 if (shadow) {
1019
1020 //we extend the shadow volumes by projecting them on the
1021 //light's sphere.
1022 //This sometimes gives problems when the light is verry close to a big
1023 //polygon. But further extending the volume wastes fill rate.
1024 //So ill have to fix it.
1025
1026 glBegin(GL_QUAD_STRIP);
1027 glVertex3fv(&poly->verts[j][0]);
1028 glVertex3fv(&temp[j][0]);
1029 glVertex3fv(&poly->verts[((j+1)% poly->numverts)][0]);
1030 glVertex3fv(&temp[((j+1)% poly->numverts)][0]);
1031 glEnd();
1032 }
1033 }
1034
1035 //Draw near light cap
1036 glBegin(GL_POLYGON);
1037 for (j=0; j<surf->numedges ; j++)
1038 {
1039 glVertex3fv(&poly->verts[j][0]);
1040 }
1041 glEnd();
1042
1043 //Draw extruded cap
1044 glBegin(GL_POLYGON);
1045 for (j=surf->numedges-1; j>=0 ; j--)
1046 {
1047 glVertex3fv(&temp[j][0]);
1048 }
1049 glEnd();
1050 }
1051
1052 //PrecalcVolumesForLight(clmodel);
1053
1054 VectorCopy(oldlightorigin,currentshadowlight->origin);
1055 glPopMatrix ();
1056 }
1057
1058 */
1059 /*
1060 =============
1061 R_DrawBrushModelVolumes
1062
1063 Draw the shadow volumes of the brush model.
1064 They are dynamically calculated.
1065 =============
1066 */
1067
R_DrawBrushModelVolumes(entity_t * e)1068 void R_DrawBrushModelVolumes(entity_t *e) {
1069
1070 model_t *model = e->model;
1071 msurface_t *surf;
1072 glpoly_t *poly;
1073 int i, j, count;
1074 brushlightinstant_t *ins = e->brushlightinstant;
1075
1076 count = 0;
1077
1078
1079 glPushMatrix ();
1080 e->angles[0] = -e->angles[0]; // stupid quake bug
1081 R_RotateForEntity (e);
1082 e->angles[0] = -e->angles[0]; // stupid quake bug
1083
1084
1085 surf = &model->surfaces[model->firstmodelsurface];
1086 for (i=0; i<model->nummodelsurfaces; i++, surf++)
1087 {
1088 if (!ins->polygonVis[i]) continue;
1089
1090 poly = surf->polys;
1091 //extrude edges
1092 for (j=0 ; j<surf->numedges ; j++)
1093 {
1094 if (ins->neighbourVis[count+j]) {
1095 glBegin(GL_QUAD_STRIP);
1096 //glVertex3fv(&poly->verts[j][0]);
1097 glVertex3fv((float *)(&globalVertexTable[surf->polys->firstvertex+j]));
1098 glVertex3fv(&ins->extvertices[count+j][0]);
1099 //glVertex3fv(&poly->verts[((j+1)% poly->numverts)][0]);
1100 glVertex3fv((float *)(&globalVertexTable[surf->polys->firstvertex+((j+1)% poly->numverts)]));
1101 glVertex3fv(&ins->extvertices[count+((j+1)% poly->numverts) ][0]);
1102 glEnd();
1103 }
1104 }
1105
1106 //Draw near light cap
1107 glBegin(GL_TRIANGLE_FAN);
1108 for (j=0; j<surf->numedges ; j++)
1109 {
1110 //glVertex3fv(&poly->verts[j][0]);
1111 glVertex3fv((float *)(&globalVertexTable[surf->polys->firstvertex+j]));
1112 }
1113 glEnd();
1114
1115 //Draw extruded cap
1116 glBegin(GL_TRIANGLE_FAN);
1117 for (j=surf->numedges-1; j>=0 ; j--)
1118 {
1119 glVertex3fv(&ins->extvertices[count+j][0]);
1120 }
1121 glEnd();
1122
1123 count+=surf->numedges;
1124 }
1125
1126 glPopMatrix ();
1127 }
1128
1129
1130 /**************************************************************
1131
1132 Shadow volume precalculation & storing
1133
1134 ***************************************************************/
1135
1136
1137 /*
1138 =============
1139
1140 getVertexIndexFromSurf
1141
1142 Gets index of the i'th vertex of the surface in the models vertex array
1143 =============
1144 */
getVertexIndexFromSurf(msurface_t * surf,int index,model_t * model)1145 int getVertexIndexFromSurf(msurface_t *surf, int index, model_t *model) {
1146
1147 int lindex = model->surfedges[surf->firstedge + index];
1148 medge_t *r_pedge;
1149
1150 if (lindex > 0)
1151 {
1152 r_pedge = &model->edges[lindex];
1153 //if (r_pedge->v[0] == 0) Con_Printf("moord en brand");
1154 return r_pedge->v[0];
1155 }
1156 else
1157 {
1158 r_pedge = &model->edges[-lindex];
1159 //if (r_pedge->v[1] == 0) Con_Printf("moord en brand");
1160 return r_pedge->v[1];
1161 }
1162 }
1163
1164 /*
1165 =============
1166
1167 PrecalcVolumesForLight
1168
1169 This will create arrays with gl-commands that define the shadow volumes
1170 (something similar to the mesh arrays that are created.)
1171 They are stored for static lights and recalculated every frame for dynamic ones.
1172 Non calculated vertices are not saved in the list but the index in the vertex array
1173 of the model is saved.
1174
1175 We store them in volumeCmdsBuff and lightCmdsBuff
1176
1177 =============
1178 */
PrecalcVolumesForLight(model_t * model)1179 void PrecalcVolumesForLight(model_t *model) {
1180
1181 msurface_t *surf;
1182
1183 int *volumeCmds = &volumeCmdsBuff[0];
1184 lightcmd_t *lightCmds = &lightCmdsBuff[0];
1185 float *volumeVerts = &volumeVertsBuff[0];
1186 int volumePos = 0;
1187 int lightPos = 0;
1188 int vertPos = 0;
1189 int startVerts, startNearVerts, numPos = 0, stripLen = 0, i;
1190 glpoly_t *poly;
1191 qboolean lastshadow;
1192 vec3_t v1, *v2, vert1;
1193 float scale;
1194 qboolean shadow;
1195
1196 vec3_t *s, *t, nearPt, nearToVert;
1197 float dist, colorscale;
1198 mplane_t *splitplane;
1199 int j;
1200 float *v;
1201
1202 surf = shadowchain;
1203
1204 //1. Calculate shadow volumes
1205
1206 while (surf)
1207 {
1208
1209 poly = surf->polys;
1210
1211 if (( surf->flags & SURF_DRAWTURB ) || ( surf->flags & SURF_DRAWSKY )) {
1212 surf = surf->shadowchain;
1213 Con_Printf ("Water/Sky in shadow chain!!");
1214 continue;
1215 }
1216
1217
1218 //a. far cap
1219 // volumeCmds[volumePos++] = GL_POLYGON;
1220 volumeCmds[volumePos++] = GL_TRIANGLE_FAN;
1221 volumeCmds[volumePos++] = surf->numedges;
1222
1223 startVerts = (int)vertPos/3;
1224 for (i=0 ; i<surf->numedges ; i++)
1225 {
1226 //v2 = (vec3_t *)&poly->verts[i];
1227 v2 = (vec3_t *)(&globalVertexTable[surf->polys->firstvertex+i]);
1228 VectorSubtract ( (*v2), currentshadowlight->origin, v1);
1229
1230 scale = Length (v1);
1231 if (sh_visiblevolumes.value) {
1232 //make them short so that we see them
1233 VectorScale (v1, (1/scale)*50, v1);
1234 } else {
1235 //we don't have to be afraid they will clip with the far plane
1236 //since we use the infinite matrix trick
1237 VectorScale (v1, (1/scale)* currentshadowlight->radius*10, v1);
1238 }
1239
1240
1241 VectorAdd (v1, (*v2) ,vert1);
1242 VectorCopy (vert1, ((vec3_t *)(volumeVerts+vertPos))[0]);
1243 vertPos+=3;
1244
1245 volumeCmds[volumePos++] = startVerts+(surf->numedges-(i+1));
1246 }
1247
1248 //copy vertices
1249 startNearVerts = (int)vertPos/3;
1250 for (i=0 ; i<surf->numedges ; i++)
1251 {
1252 //v2 = (vec3_t *)&poly->verts[i];
1253 v2 = (vec3_t *)(&globalVertexTable[surf->polys->firstvertex+i]);
1254 /*(float)*/volumeVerts[vertPos++] = (*v2)[0]; // <AWE> lvalue cast. what da...?
1255 /*(float)*/volumeVerts[vertPos++] = (*v2)[1]; // <AWE> a float is a float is a...
1256 /*(float)*/volumeVerts[vertPos++] = (*v2)[2];
1257 }
1258
1259
1260 if (vertPos > MAX_VOLUME_VERTS) {
1261 Con_Printf ("More than MAX_VOLUME_VERTS vetices! %i\n", volumePos);
1262 break;
1263 }
1264
1265
1266 //b. borders of volume
1267 //we make quad strips if we have continuous borders
1268 lastshadow = false;
1269
1270 for (i=0 ; i<surf->numedges ; i++)
1271 {
1272
1273 shadow = false;
1274
1275 if (poly->neighbours[i] != NULL) {
1276 if ( poly->neighbours[i]->lightTimestamp != poly->lightTimestamp) {
1277 shadow = true;
1278 }
1279 } else {
1280 shadow = true;
1281 }
1282
1283 if (shadow) {
1284
1285 if (!lastshadow) {
1286 //begin new strip
1287 volumeCmds[volumePos++] = GL_QUAD_STRIP;
1288 numPos = volumePos;
1289 volumeCmds[volumePos++] = 4;
1290 stripLen = 2;
1291
1292 //copy vertices
1293 volumeCmds[volumePos++] = startNearVerts+i;//-getVertexIndexFromSurf(surf, i, model);
1294 volumeCmds[volumePos++] = startVerts+i;
1295
1296 }
1297
1298 volumeCmds[volumePos++] = startNearVerts+((i+1)%poly->numverts);//-getVertexIndexFromSurf(surf, (i+1)%poly->numverts, model);
1299 volumeCmds[volumePos++] = startVerts+((i+1)%poly->numverts);
1300
1301 stripLen+=2;
1302
1303 } else {
1304 if (lastshadow) {
1305 //close list up
1306 volumeCmds[numPos] = stripLen;
1307 }
1308 }
1309 lastshadow = shadow;
1310 }
1311
1312 if (lastshadow) {
1313 //close list up
1314 volumeCmds[numPos] = stripLen;
1315 }
1316
1317 if (volumePos > MAX_VOLUME_COMMANDS) {
1318 Con_Printf ("More than MAX_VOLUME_COMMANDS commands! %i\n", volumePos);
1319 break;
1320 }
1321
1322 //c. glow surfaces/texture coordinates
1323 //leftright vectors of plane
1324 s = (vec3_t *)&surf->texinfo->vecs[0];
1325 t = (vec3_t *)&surf->texinfo->vecs[1];
1326
1327 /*
1328 VectorNormalize(*s);
1329 VectorNormalize(*t);
1330 */
1331
1332 splitplane = surf->plane;
1333
1334 dist = DotProduct (currentshadowlight->origin, splitplane->normal) - splitplane->dist;
1335
1336
1337 dist = abs(dist);
1338
1339 if (dist > currentshadowlight->radius) Con_Printf("Polygon to far\n");
1340 ProjectPlane (currentshadowlight->origin, (*s), (*t), nearPt);
1341
1342 scale = 1 /((2 * currentshadowlight->radius) - dist);
1343 colorscale = (1 - (dist / currentshadowlight->radius));
1344
1345 if (colorscale <0) colorscale = 0;
1346
1347 lightCmds[lightPos++].asInt = GL_TRIANGLE_FAN;
1348
1349 lightCmds[lightPos++].asVoid = surf;
1350 lightCmds[lightPos++].asFloat = currentshadowlight->color[0]*colorscale;
1351 lightCmds[lightPos++].asFloat = currentshadowlight->color[1]*colorscale;
1352 lightCmds[lightPos++].asFloat = currentshadowlight->color[2]*colorscale;
1353 lightCmds[lightPos++].asFloat = colorscale;
1354
1355 //v = poly->verts[0];
1356 v = (float *)(&globalVertexTable[surf->polys->firstvertex]);
1357 for (j=0 ; j<poly->numverts ; j++, v+= VERTEXSIZE)
1358 {
1359 // Project the light image onto the face
1360 VectorSubtract (v, nearPt, nearToVert);
1361
1362 // Get our texture coordinates, transform into tangent plane
1363 lightCmds[lightPos++].asVec = DotProduct (nearToVert, (*s)) * scale + 0.5;
1364 lightCmds[lightPos++].asVec = DotProduct (nearToVert, (*t)) * scale + 0.5;
1365
1366 //calculate local light vector and put it into tangent space
1367 {
1368 vec3_t lightDir, tsLightDir;
1369
1370 VectorSubtract( currentshadowlight->origin,v,lightDir);
1371
1372 if (surf->flags & SURF_PLANEBACK) {
1373 tsLightDir[2] = -DotProduct(lightDir,surf->plane->normal);
1374 } else {
1375 tsLightDir[2] = DotProduct(lightDir,surf->plane->normal);
1376 }
1377
1378 tsLightDir[1] = -DotProduct(lightDir,(*t));
1379 tsLightDir[0] = DotProduct(lightDir,(*s));
1380 lightCmds[lightPos++].asVec = tsLightDir[0];
1381 lightCmds[lightPos++].asVec = tsLightDir[1];
1382 lightCmds[lightPos++].asVec = tsLightDir[2];
1383 }
1384 }
1385 if (lightPos > MAX_LIGHT_COMMANDS) {
1386 Con_Printf ("More than MAX_LIGHT_COMMANDS commands %i\n", lightPos);
1387 break;
1388 }
1389
1390 surf = surf->shadowchain;
1391 }
1392
1393 //Con_Printf("used %i\n",volumePos);
1394 //finish them off with 0
1395 lightCmds[lightPos++].asInt = 0;
1396 volumeCmds[volumePos++] = 0;
1397
1398 numLightCmds = lightPos;
1399 numVolumeCmds = volumePos;
1400 numVolumeVerts = vertPos;
1401 }
1402 /*
1403 =============
1404 DrawVolumeFromCmds
1405
1406 Draws the generated commands as shadow volumes
1407 =============
1408 */
DrawVolumeFromCmds(int * volumeCmds,lightcmd_t * lightCmds,float * volumeVerts)1409 void DrawVolumeFromCmds(int *volumeCmds, lightcmd_t *lightCmds, float *volumeVerts) {
1410
1411 int command, num, i;
1412 int volumePos = 0;
1413 int lightPos = 0;
1414 // int count = 0; // <AWE> no longer required.
1415 msurface_t *surf;
1416 float *v;
1417
1418 glVertexPointer(3, GL_FLOAT, 0, volumeVerts);
1419 glEnableClientState(GL_VERTEX_ARRAY);
1420
1421 while (1) {
1422 command = volumeCmds[volumePos++];
1423 if (command == 0) break; //end of list
1424 num = volumeCmds[volumePos++];
1425
1426 glDrawElements(command,num,GL_UNSIGNED_INT,&volumeCmds[volumePos]);
1427 volumePos+=num;
1428
1429 /*glBegin(command);
1430
1431 if ((command == GL_QUAD_STRIP) || (command == GL_QUADS)) {
1432 for (i=0; i<num; i++) {
1433 ind = volumeCmds[volumePos++];
1434 // glVertex3fv((float *)(&volumeCmds[ind]));
1435 glVertex3fv(&volumeVerts[ind*3]);
1436 }
1437 } else {
1438 //caps point inwards
1439 //volumePos+=num*3;
1440 for (i=0; i<num; i++) {
1441 ind = volumeCmds[volumePos++];
1442 //extuded verts have w component
1443 //glVertex3fv((float *)(volumeCmds+(volumePos-(i+1)*3)));
1444 glVertex3fv(&volumeVerts[ind*3]);
1445 }
1446 //volumePos+=num*3;
1447 }
1448
1449 glEnd();*/
1450 // count++; // <AWE> no longer required.
1451 }
1452
1453 glDisableClientState(GL_VERTEX_ARRAY);
1454
1455 //Con_Printf("%i objects drawn\n",count);
1456 if (sh_visiblevolumes.value) return;
1457
1458 while (1) {
1459
1460 command = lightCmds[lightPos++].asInt;
1461 if (command == 0) break; //end of list
1462
1463 surf = lightCmds[lightPos++].asVoid;
1464 lightPos+=4; //skip color
1465 num = surf->polys->numverts;
1466
1467 glBegin(command);
1468 //v = surf->polys->verts[0];
1469 v = (float *)(&globalVertexTable[surf->polys->firstvertex]);
1470 for (i=0; i<num; i++, v+= VERTEXSIZE) {
1471 //skip attent texture coord.
1472 lightPos+=2;
1473 //skip tangent space light vector
1474 lightPos+=3;
1475 glVertex3fv(&v[0]);
1476 }
1477 glEnd();
1478 }
1479
1480 }
1481
1482 /*
1483 =============
1484 R_RenderGlow
1485
1486 Render a halo around a light.
1487 The idea is similar to the UT2003 lensflares.
1488 =============
1489 */
1490
1491 //speed at wich halo grows fainter when it gets occluded
1492 #define HALO_FALLOF 2
1493 //the scale the alpa is multipied with (none is verry bright)
1494 #define HALO_ALPHA_SCALE 0.7
1495 //the maximum radius (in pixels) of the halo
1496 #define HALO_SIZE 30
1497 //the distance of the eye at wich the halo stops shrinking
1498 #define HALO_MIN_DIST 300
R_RenderGlow(shadowlight_t * light)1499 void R_RenderGlow (shadowlight_t *light)
1500 {
1501 vec3_t hit = {0, 0, 0};
1502 double x,y,z;
1503 float fdist,realz;
1504 int ofsx, ofsy;
1505 qboolean hitWorld;
1506
1507 if (!light->halo || gl_wireframe.value)
1508 return;
1509
1510 //trace a from the eye to the light source
1511 TraceLine (r_refdef.vieworg, light->origin, hit);
1512
1513 //if it's not visible anymore slowly fade it
1514 if (Length(hit) != 0) {
1515 light->haloalpha = light->haloalpha - (cl.time - cl.oldtime)*HALO_FALLOF;
1516 if (light->haloalpha < 0) return;
1517 hitWorld = true;
1518 } else
1519 hitWorld = false;
1520
1521 /*
1522 VectorSubtract(r_refdef.vieworg, light->origin, dist);
1523 fdist = Length(dist);
1524 if (fdist < HALO_MIN_DIST) fdist = HALO_MIN_DIST;
1525 fdist = (1-1/fdist)*HALO_SIZE;
1526 */
1527 fdist = HALO_SIZE;
1528
1529 gluProject(light->origin[0], light->origin[1], light->origin[2], r_Dworld_matrix,
1530 r_Dproject_matrix, (GLint *) r_Iviewport, &x, &y, &z); // <AWE> added cast.
1531
1532 //Con_Printf("Viewp %i %i %i %i\n",r_Iviewport[0],r_Iviewport[1],r_Iviewport[2],r_Iviewport[3]);
1533 if (!hitWorld) {
1534 //we didn't hit any bsp try to read the z buffer (wich is totally utterly freakingly
1535 // �ber evil!)
1536 glReadPixels((int)x,(int)y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&realz);
1537 if (realz < z) {
1538 light->haloalpha = light->haloalpha - (cl.time - cl.oldtime)*HALO_FALLOF;
1539 if (light->haloalpha < 0) return;
1540 } else {
1541 //nothing in the way make it fully bright
1542 light->haloalpha = 1.0;
1543 }
1544 }
1545
1546 ofsx = r_Iviewport[0];
1547 ofsy = r_Iviewport[1];
1548 x = x;
1549 y = glheight-y;
1550
1551 x = (x/(float)glwidth)*vid.width;
1552 y = (y/(float)glheight)*vid.height;
1553
1554 //glDisable (GL_TEXTURE_2D)
1555 GL_Bind(halo_texture_object);
1556 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1557 glShadeModel (GL_SMOOTH);
1558 glEnable (GL_BLEND);
1559 glBlendFunc (GL_SRC_ALPHA, GL_ONE);
1560 glDisable(GL_ALPHA_TEST);
1561
1562
1563
1564 glBegin (GL_QUADS);
1565
1566 glColor4f(light->color[0],light->color[1],light->color[2],light->haloalpha*HALO_ALPHA_SCALE);
1567 //glColor4f(1,1,1,light->haloalpha);
1568 glTexCoord2f (0, 0);
1569 glVertex2f (x-fdist, y-fdist);
1570 glTexCoord2f (1, 0);
1571 glVertex2f (x+fdist, y-fdist);
1572 glTexCoord2f (1, 1);
1573 glVertex2f (x+fdist, y+fdist);
1574 glTexCoord2f (0, 1);
1575 glVertex2f (x-fdist, y+fdist);
1576
1577 glEnd ();
1578 /*
1579 rad = 40;//light->radius * 0.35;
1580
1581 VectorSubtract (light->origin, r_origin, v);
1582
1583 //dave - slight fix
1584 VectorSubtract (light->origin, r_origin, vp2);
1585 VectorNormalize(vp2);
1586
1587
1588 glBegin (GL_TRIANGLE_FAN);
1589 glColor3f (light->color[0]*0.2,light->color[1]*0.2,light->color[2]*0.2);
1590 for (i=0 ; i<3 ; i++)
1591 v[i] = light->origin[i] - vp2[i]*rad;
1592 glVertex3fv (v);
1593 glColor3f (0,0,0);
1594 for (i=16 ; i>=0 ; i--)
1595 {
1596 a = i/16.0 * M_PI*2;
1597 for (j=0 ; j<3 ; j++)
1598 v[j] = light->origin[j] + vright[j]*cos(a)*rad
1599 + vup[j]*sin(a)*rad;
1600 glVertex3fv (v);
1601 }
1602 glEnd ();
1603 */
1604 glEnable(GL_ALPHA_TEST);
1605 glColor3f (1,1,1);
1606 glDisable (GL_BLEND);
1607 //glEnable (GL_TEXTURE_2D);
1608 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1609 glDepthMask (1);
1610 glColor3f (1,1,1);
1611 }
1612
1613 /**************************************************************
1614
1615 Shadow volume bsp's
1616
1617 Some of this suff should be put in gl_svbsp.c
1618
1619 ***************************************************************/
1620
1621 svnode_t *currentlightroot;
1622 vec3_t testvect = {10,10,10};
1623
1624 /*
1625 ================
1626 CutLeafs
1627
1628 Removes leaves that were cut by using the svbsp from the light's
1629 visibility list.
1630 This gains some speed in certain cases.
1631 ================
1632 */
CutLeafs(byte * vis)1633 void CutLeafs(byte *vis) {
1634
1635 int c, i;
1636 msurface_t **surf;
1637 mleaf_t *leaf;
1638 qboolean found;
1639 int removed = 0;
1640
1641 if (sh_norevis.value) return;
1642
1643 for (i=0 ; i<cl.worldmodel->numleafs ; i++)//overloop alle leafs
1644 {
1645
1646 if (vis[i>>3] & (1<<(i&7)))
1647 {
1648 //this leaf is visible from the leaf the current light (in a brute force way)
1649 //now check if we entirely cut this leaf by means of the svbsp
1650 leaf = &cl.worldmodel->leafs[i];
1651 c = leaf->nummarksurfaces;
1652 surf = leaf->firstmarksurface;
1653
1654 if (leaf->index != i) Con_Printf("Weird leaf index %i, %i\n",i,leaf->index);
1655 found = false;
1656 for (c=0; c<leaf->nummarksurfaces; c++, surf++) {
1657 if ((*surf)->polys->lightTimestamp == r_lightTimestamp) {
1658 found = true;
1659 break;
1660 }
1661 }
1662
1663 if (!found) {
1664 //set vis bit on false
1665 vis[i>>3] &= ~(1<<(i&7));
1666 removed++;
1667 }
1668 }
1669 }
1670
1671 //Con_Printf(" Removed leafs: %i\n", removed);
1672 }
1673
1674 /*
1675 ================
1676 AddToShadowBsp
1677
1678 Add a surface as potential shadow caster to the svbsp, it can be
1679 cut when it is occluded by other surfaces.
1680 ================
1681 */
AddToShadowBsp(msurface_t * surf)1682 void AddToShadowBsp(msurface_t *surf) {
1683 vec3_t surfvects[32];
1684 int numsurfvects;
1685 int i;
1686 float *v;
1687
1688 /*
1689 PENTA: removed we checked this twice
1690
1691 //we don't cast shadows with water
1692 if (( surf->flags & SURF_DRAWTURB ) || ( surf->flags & SURF_DRAWSKY )) {
1693 return;
1694 }
1695
1696 plane = surf->plane;
1697
1698 switch (plane->type)
1699 {
1700 case PLANE_X:
1701 dist = currentshadowlight->origin[0] - plane->dist;
1702 break;
1703 case PLANE_Y:
1704 dist = currentshadowlight->origin[1] - plane->dist;
1705 break;
1706 case PLANE_Z:
1707 dist = currentshadowlight->origin[2] - plane->dist;
1708 break;
1709 default:
1710 dist = DotProduct (currentshadowlight->origin, plane->normal) - plane->dist;
1711 break;
1712 }
1713
1714 //the normals are flipped when surf_planeback is 1
1715 if (((surf->flags & SURF_PLANEBACK) && (dist > 0)) ||
1716 (!(surf->flags & SURF_PLANEBACK) && (dist < 0)))
1717 {
1718 return;
1719 }
1720
1721 //the normals are flipped when surf_planeback is 1
1722 if ( abs(dist) > currentshadowlight->radius)
1723 {
1724 return;
1725 }
1726
1727 */
1728
1729 //FIXME: use constant instead of 32
1730 if (surf->numedges > 32) {
1731 Con_Printf("Error: to many edges");
1732 return;
1733 }
1734
1735 surf->visframe = 0;
1736 //Make temp copy of suface polygon
1737 numsurfvects = surf->numedges;
1738 for (i=0, v=(float *)(&globalVertexTable[surf->polys->firstvertex]); i<numsurfvects; i++, v+=VERTEXSIZE) {
1739 VectorCopy(v,surfvects[i]);
1740 }
1741
1742 if (!sh_nosvbsp.value) {
1743 svBsp_NumAddedPolys++;
1744 R_AddShadowCaster(currentlightroot,surfvects,numsurfvects,surf,0);
1745 } else {
1746 surf->shadowchain = shadowchain;
1747 surf->polys->lightTimestamp = r_lightTimestamp;
1748 shadowchain = surf;
1749 svBsp_NumKeptPolys++;
1750 }
1751 }
1752
1753 /*
1754 ================
1755 R_RecursiveShadowAdd
1756
1757 Add surfaces front to back to the shadow bsp.
1758 ================
1759 */
R_RecursiveShadowAdd(mnode_t * node)1760 void R_RecursiveShadowAdd(mnode_t *node)
1761 {
1762 int c, side;
1763 mplane_t *plane;
1764 msurface_t *surf;
1765 double dot;
1766
1767 if (node->contents == CONTENTS_SOLID) {
1768 return; // solid
1769 }
1770
1771 if (node->contents < 0) {
1772 return; // leaf
1773 }
1774
1775 //find which side of the node we are on
1776
1777 plane = node->plane;
1778
1779 switch (plane->type)
1780 {
1781 case PLANE_X:
1782 dot = currentshadowlight->origin[0] - plane->dist;
1783 break;
1784 case PLANE_Y:
1785 dot = currentshadowlight->origin[1] - plane->dist;
1786 break;
1787 case PLANE_Z:
1788 dot = currentshadowlight->origin[2] - plane->dist;
1789 break;
1790 default:
1791 dot = DotProduct (currentshadowlight->origin, plane->normal) - plane->dist;
1792 break;
1793 }
1794
1795 if (dot >= 0)
1796 side = 0;
1797 else
1798 side = 1;
1799
1800 //recurse down the children, front side first
1801 R_RecursiveShadowAdd (node->children[side]);
1802
1803
1804 //draw stuff
1805 c = node->numsurfaces;
1806
1807 if (c)
1808 {
1809
1810 surf = cl.worldmodel->surfaces + node->firstsurface;
1811 do
1812 {
1813 if (surf->polys) {
1814 if ((surf->polys->lightTimestamp == r_lightTimestamp))
1815 {
1816 AddToShadowBsp (surf);
1817 }
1818 }
1819 surf++;
1820 } while (--c);
1821 }
1822
1823 //recurse down the back side
1824 R_RecursiveShadowAdd (node->children[!side]);
1825 }
1826
1827 /*
1828 ===============
1829 R_MarkLightLeaves
1830
1831 Marks nodes from the light, this is used for
1832 gross culling during svbsp creation.
1833 ===============
1834 */
1835
R_MarkLightLeaves(void)1836 void R_MarkLightLeaves (void)
1837 {
1838 byte solid[4096];
1839 mleaf_t *lightleaf;
1840
1841 //we use the same timestamp as for rendering (may cause errors maybe)
1842 r_visframecount++;
1843 lightleaf = Mod_PointInLeaf (currentshadowlight->origin, cl.worldmodel);
1844
1845 if (r_novis.value)
1846 {
1847 lightvis = solid;
1848 memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
1849 }
1850 else
1851 lightvis = Mod_LeafPVS (lightleaf, cl.worldmodel);
1852 }
1853
1854
1855 /*
1856 ================
1857 ShadowVolumeBsp
1858
1859 Create the shadow volume bsp for currentshadowlight
1860 ================
1861 */
ShadowVolumeBsp()1862 void ShadowVolumeBsp() {
1863 currentlightroot = R_CreateEmptyTree();
1864 R_MarkLightLeaves();
1865 R_MarkShadowCasting (currentshadowlight,cl.worldmodel->nodes);
1866 shadowchain = NULL;
1867 svBsp_NumKeptPolys = 0;
1868 R_RecursiveShadowAdd(cl.worldmodel->nodes);
1869 }
1870
1871 int done = 0;
1872
1873 /*
1874 ================
1875 R_CalcSvBsp
1876
1877 Called for every static ent during spawning of the client
1878 ================
1879 */
R_CalcSvBsp(entity_t * ent)1880 void R_CalcSvBsp(entity_t *ent) {
1881
1882 int i;
1883 msurface_t *surf;
1884 msurface_t *s;
1885 texture_t *t;
1886
1887 //Con_Printf("Shadow volumes start\n");
1888
1889 if (ent->model == NULL) {
1890 Con_Printf("null model");
1891 return;
1892 }
1893
1894 if (!strcmp (ent->model->name, "progs/flame2.mdl")
1895 || !strcmp (ent->model->name, "progs/flame.mdl")
1896 || !strcmp (ent->model->name, "progs/s_light.spr")
1897 || !strcmp (ent->model->name, "progs/b_light.spr")
1898 || !strcmp (ent->model->name, "progs/w_light.spr"))
1899 {
1900 shadowchain = NULL;
1901 done++;
1902
1903 //Con_Printf("->Light %i\n",done);
1904
1905
1906 r_lightTimestamp++;
1907 r_framecount++;
1908
1909 svBsp_NumCutPolys = 0;
1910 svBsp_NumKeptPolys = 0;
1911 svBsp_NumAddedPolys = 0;
1912
1913 //Create a light and make it static
1914 R_ShadowFromEntity(ent);
1915 numStaticShadowLights++;
1916
1917 if (numShadowLights >= MAXSHADOWLIGHTS) {
1918 Con_Printf("R_CalcSvBsp: More than MAXSHADOWLIGHTS lights");
1919 return;
1920 }
1921
1922 currentshadowlight = &shadowlights[numShadowLights-1];
1923
1924 //Hack: support quake light_* entities
1925 if (!strcmp (ent->model->name, "progs/flame2.mdl")) {
1926 currentshadowlight->baseColor[0] = 1;
1927 currentshadowlight->baseColor[1] = 0.9;
1928 currentshadowlight->baseColor[2] = 0.75;
1929 } else if (!strcmp (ent->model->name, "progs/flame.mdl")) {
1930 currentshadowlight->baseColor[0] = 1;
1931 currentshadowlight->baseColor[1] = 0.9;
1932 currentshadowlight->baseColor[2] = 0.75;
1933 } else if (!strcmp (ent->model->name, "progs/s_light.spr")) {
1934 currentshadowlight->baseColor[0] = 1;
1935 currentshadowlight->baseColor[1] = 0.9;
1936 currentshadowlight->baseColor[2] = 0.75;
1937 }
1938
1939 currentshadowlight->isStatic = true;
1940
1941 //Calculate visible polygons
1942 ShadowVolumeBsp();
1943
1944 //Print stats
1945 /*
1946 Con_Printf(" Thrown away: %i\n",svBsp_NumAddedPolys-svBsp_NumKeptPolys);
1947 Con_Printf(" Total in volume: %i\n",svBsp_NumKeptPolys);
1948 */
1949
1950 currentshadowlight->visSurf = Hunk_Alloc(4*svBsp_NumKeptPolys);
1951 currentshadowlight->numVisSurf = svBsp_NumKeptPolys;
1952 surf = shadowchain;
1953
1954 //Clear texture chains
1955 for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1956 {
1957 if (!cl.worldmodel->textures[i]) continue;
1958 cl.worldmodel->textures[i]->texturechain = NULL;
1959 }
1960
1961 //Remark polys since polygons may have been removed since the last time stamp
1962 r_lightTimestamp++;
1963 for (i=0; i<svBsp_NumKeptPolys; i++,surf = surf->shadowchain) {
1964 surf->polys->lightTimestamp = r_lightTimestamp;
1965 currentshadowlight->visSurf[i] = surf;
1966 //put it in the correct texture chain
1967 surf->texturechain = surf->texinfo->texture->texturechain;
1968 surf->texinfo->texture->texturechain = surf;
1969 }
1970
1971 //Sort surfs in our list per texture
1972 shadowchain = NULL;
1973 for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1974 {
1975 t = cl.worldmodel->textures[i];
1976 if (!t)
1977 continue;
1978 s = t->texturechain;
1979 if (!s)
1980 continue;
1981 else
1982 {
1983 for ( ; s ; s=s->texturechain) {
1984 s->shadowchain = shadowchain;
1985 shadowchain = s;
1986 }
1987 }
1988 t->texturechain = NULL;
1989 }
1990
1991 //Recalculate vis for this light
1992 currentshadowlight->leaf = Mod_PointInLeaf (currentshadowlight->origin, cl.worldmodel);
1993 lightvis = Mod_LeafPVS (currentshadowlight->leaf, cl.worldmodel);
1994 Q_memcpy(¤tshadowlight->vis[0], lightvis, MAX_MAP_LEAFS/8);
1995 Q_memcpy(¤tshadowlight->entvis[0], lightvis, MAX_MAP_LEAFS/8);
1996 CutLeafs(currentshadowlight->vis);
1997
1998 //Precalculate the shadow volume / glow-texcoords
1999 PrecalcVolumesForLight(cl.worldmodel);
2000 currentshadowlight->volumeCmds = Hunk_Alloc(4*numVolumeCmds);
2001 Q_memcpy(currentshadowlight->volumeCmds, &volumeCmdsBuff, 4*numVolumeCmds);
2002
2003 currentshadowlight->volumeVerts = Hunk_Alloc(4*numVolumeVerts);
2004 currentshadowlight->numVolumeVerts = numVolumeVerts;
2005 Q_memcpy(currentshadowlight->volumeVerts, &volumeVertsBuff, 4*numVolumeVerts);
2006
2007 currentshadowlight->lightCmds = Hunk_Alloc(4*numLightCmds);
2008 Q_memcpy(currentshadowlight->lightCmds, &lightCmdsBuff, 4*numLightCmds);
2009 //Con_Printf("light done\n");
2010 } else {
2011 //Con_Printf("thrown away");
2012 }
2013
2014 }
2015
2016 #define surfaceLightRadius 350.0
2017
2018 /*
2019 Not used places lights in front of things that look like lights in a map
2020 */
LightFromSurface(msurface_t * surf)2021 void LightFromSurface(msurface_t *surf) {
2022 vec3_t center, orig, normal;
2023 glpoly_t *poly;
2024 float *v, invnum;
2025 int i;
2026 shadowlight_t *light;
2027 qboolean tooClose;
2028 entity_t fakeEnt;
2029
2030 poly = surf->polys;
2031 invnum = 1.0/poly->numverts;
2032
2033 //Calculate origin for the light we are possibly going to spawn
2034 //v = poly->verts[0];
2035 v = (float *)(&globalVertexTable[poly->firstvertex]);
2036 center[0] = center[1] = center[2] = 0;
2037 for (i=0 ; i<poly->numverts ; i++, v+= VERTEXSIZE)
2038 {
2039 VectorAdd(center,v,center);
2040 }
2041 VectorScale(center,invnum,center);
2042
2043 if (surf->flags & SURF_PLANEBACK) {
2044 VectorScale(surf->plane->normal,-1,normal);
2045 } else {
2046 VectorCopy(surf->plane->normal,normal);
2047 }
2048
2049 VectorMA(center,16,normal,orig);
2050
2051
2052 //not to close to other lights then add it
2053
2054 tooClose = false;
2055 for (i=0; i<numShadowLights; i++) {
2056 vec3_t dist;
2057 float length;
2058 light = &shadowlights[i];
2059 VectorSubtract(orig,light->origin,dist);
2060 length = Length(dist);
2061
2062 if (length < (surfaceLightRadius*sh_radiusscale.value + light->radius*sh_radiusscale.value)) {
2063 tooClose = true;
2064 }
2065 }
2066
2067
2068 if (!tooClose) {
2069 Q_memset(&fakeEnt,0,sizeof(entity_t));
2070 fakeEnt.light_lev = surfaceLightRadius;
2071 VectorCopy(orig,fakeEnt.origin);
2072 fakeEnt.model = Mod_ForName("progs/w_light.spr",true);
2073 R_CalcSvBsp(&fakeEnt);
2074 Con_Printf("Added surface light");
2075 }
2076
2077 }
2078
2079 /**
2080
2081 Hacked entitiy loading code, this parses the entities client side to find lights in it
2082
2083 **/
2084
LightFromFile(vec3_t orig)2085 void LightFromFile(vec3_t orig) {
2086 int i;
2087 shadowlight_t *light;
2088 qboolean tooClose;
2089 entity_t fakeEnt;
2090
2091
2092
2093
2094 //not to close to other lights then add it
2095
2096 tooClose = false;
2097 for (i=0; i<numShadowLights; i++) {
2098 vec3_t dist;
2099 float length;
2100 light = &shadowlights[i];
2101 VectorSubtract(orig,light->origin,dist);
2102 length = Length(dist);
2103
2104 if (length < (surfaceLightRadius*sh_radiusscale.value + light->radius*sh_radiusscale.value)) {
2105 tooClose = true;
2106 }
2107 }
2108
2109
2110 if (!tooClose) {
2111 Q_memset(&fakeEnt,0,sizeof(entity_t));
2112 fakeEnt.light_lev = surfaceLightRadius;
2113 VectorCopy(orig,fakeEnt.origin);
2114 fakeEnt.model = Mod_ForName("progs/w_light.spr",true);
2115 R_CalcSvBsp(&fakeEnt);
2116 //Con_Printf("Added file light");
2117 }
2118
2119
2120 }
2121
2122
ParseVector(char * s,float * d)2123 void ParseVector (char *s, float *d)
2124 {
2125 int i;
2126 char string[128];
2127 char *v, *w;
2128
2129 strncpy (string, s,sizeof(string));
2130 v = string;
2131 w = string;
2132 for (i=0 ; i<3 ; i++)
2133 {
2134 while (*v && *v != ' ')
2135 v++;
2136 *v = 0;
2137 d[i] = atof (w);
2138 w = v = v+1;
2139 }
2140 }
2141
2142
2143
ParseEnt(char * data,qboolean * isLight,vec3_t origin)2144 char *ParseEnt (char *data, qboolean *isLight, vec3_t origin)
2145 {
2146 qboolean init;
2147 char keyname[256];
2148 qboolean foundworld = false;
2149 init = false;
2150
2151 // go through all the dictionary pairs
2152 while (1)
2153 {
2154 // parse key
2155 data = COM_Parse (data);
2156 if (com_token[0] == '}')
2157 break;
2158 if (!data)
2159 Sys_Error ("ParseEnt: EOF without closing brace");
2160
2161 strncpy (keyname, com_token,sizeof(keyname));
2162
2163 // parse value
2164 data = COM_Parse (data);
2165 if (!data)
2166 Sys_Error ("ED_ParseEntity: EOF without closing brace");
2167
2168 if (com_token[0] == '}')
2169 Sys_Error ("ED_ParseEntity: closing brace without data");
2170
2171 init = true;
2172
2173
2174 if (!strcmp(keyname, "classname")) {
2175 if (!strcmp(com_token, "light")) {
2176 *isLight = true;
2177 } else {
2178 *isLight = false;
2179 }
2180 } else if (!strcmp(keyname, "origin")) {
2181 ParseVector(com_token, origin);
2182 } else if (!strcmp(keyname, "_noautolight")) {
2183 Con_Printf("Automatic light gen disabled\n");//XYW \n
2184 foundworld = true;
2185 } else if (!strcmp(keyname, "_skybox")) {
2186 strncpy(skybox_name,com_token,sizeof(skybox_name));
2187 } else if (!strcmp(keyname, "_cloudspeed")) {
2188 skybox_cloudspeed = atof(com_token);
2189 } else if (!strcmp(keyname, "_lightmapbright")) {
2190 Cvar_Set("sh_lightmapbright",com_token);
2191 Con_Printf("Lightmap brightness set to %f\n",sh_lightmapbright.value);
2192 } else if (!strcmp(keyname, "_fog_color")) {
2193 ParseVector(com_token, origin);
2194 Cvar_SetValue("fog_r",origin[0]);
2195 Cvar_SetValue("fog_g",origin[1]);
2196 Cvar_SetValue("fog_b",origin[2]);
2197 } else if (!strcmp(keyname, "_fog_start")) {
2198 Cvar_Set("fog_start",com_token);
2199 } else if (!strcmp(keyname, "_fog_end")) {
2200 Cvar_Set("fog_end",com_token);
2201 } else {
2202
2203 //just do nothing
2204
2205 }
2206 }
2207
2208
2209
2210 if (foundworld) return NULL;
2211 return data;
2212 }
2213
LoadLightsFromFile(char * data)2214 void LoadLightsFromFile (char *data)
2215 {
2216 qboolean isLight;
2217 vec3_t origin;
2218
2219 Cvar_SetValue ("fog_start",0.0);
2220 Cvar_SetValue ("fog_end",0.0);
2221
2222 // parse ents
2223 while (1)
2224 {
2225 // parse the opening brace
2226 data = COM_Parse (data);
2227 if (!data)
2228 break;
2229 if (com_token[0] != '{')
2230 Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
2231
2232 isLight = false;
2233 data = ParseEnt (data, &isLight, origin);
2234 if (isLight) {
2235 LightFromFile(origin);
2236 //Con_Printf("found light in file");
2237 }
2238 }
2239
2240 if ((!fog_start.value) && (!fog_end.value)) {
2241 Cvar_SetValue ("fog_enabled",0.0);
2242 }
2243 }
2244
R_AutomaticLightPos()2245 void R_AutomaticLightPos() {
2246
2247 /*
2248 for (i=0; i<m->numsurfaces; i++) {
2249 surf = &m->surfaces[i];
2250 if (strstr(surf->texinfo->texture->name,"light")) {
2251 LightFromSurface(surf);
2252 }
2253 }*/
2254
2255 LoadLightsFromFile(cl.worldmodel->entities);
2256 }
2257