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(&currentshadowlight->vis[0], lightvis, MAX_MAP_LEAFS/8);
1995 		Q_memcpy(&currentshadowlight->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