1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4 
5 This file is part of Quake 2 Tools source code.
6 
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 #include "qrad.h"
23 
24 #define	MAX_LSTYLES	256
25 
26 typedef struct
27 {
28 	dface_t		*faces[2];
29 	qboolean	coplanar;
30 } edgeshare_t;
31 
32 edgeshare_t	edgeshare[MAX_MAP_EDGES];
33 
34 int			facelinks[MAX_MAP_FACES];
35 int			planelinks[2][MAX_MAP_PLANES];
36 
37 /*
38 ============
39 LinkPlaneFaces
40 ============
41 */
LinkPlaneFaces(void)42 void LinkPlaneFaces (void)
43 {
44 	int		i;
45 	dface_t	*f;
46 
47 	f = dfaces;
48 	for (i=0 ; i<numfaces ; i++, f++)
49 	{
50 		facelinks[i] = planelinks[f->side][f->planenum];
51 		planelinks[f->side][f->planenum] = i;
52 	}
53 }
54 
55 /*
56 ============
57 PairEdges
58 ============
59 */
PairEdges(void)60 void PairEdges (void)
61 {
62 	int		i, j, k;
63 	dface_t	*f;
64 	edgeshare_t	*e;
65 
66 	f = dfaces;
67 	for (i=0 ; i<numfaces ; i++, f++)
68 	{
69 		for (j=0 ; j<f->numedges ; j++)
70 		{
71 			k = dsurfedges[f->firstedge + j];
72 			if (k < 0)
73 			{
74 				e = &edgeshare[-k];
75 				e->faces[1] = f;
76 			}
77 			else
78 			{
79 				e = &edgeshare[k];
80 				e->faces[0] = f;
81 			}
82 
83 			if (e->faces[0] && e->faces[1])
84 			{
85 				// determine if coplanar
86 				if (e->faces[0]->planenum == e->faces[1]->planenum)
87 					e->coplanar = true;
88 			}
89 		}
90 	}
91 }
92 
93 /*
94 =================================================================
95 
96   POINT TRIANGULATION
97 
98 =================================================================
99 */
100 
101 typedef struct triedge_s
102 {
103 	int			p0, p1;
104 	vec3_t		normal;
105 	vec_t		dist;
106 	struct triangle_s	*tri;
107 } triedge_t;
108 
109 typedef struct triangle_s
110 {
111 	triedge_t	*edges[3];
112 } triangle_t;
113 
114 #define	MAX_TRI_POINTS		1024
115 #define	MAX_TRI_EDGES		(MAX_TRI_POINTS*6)
116 #define	MAX_TRI_TRIS		(MAX_TRI_POINTS*2)
117 
118 typedef struct
119 {
120 	int			numpoints;
121 	int			numedges;
122 	int			numtris;
123 	dplane_t	*plane;
124 	triedge_t	*edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS];
125 	patch_t		*points[MAX_TRI_POINTS];
126 	triedge_t	edges[MAX_TRI_EDGES];
127 	triangle_t	tris[MAX_TRI_TRIS];
128 } triangulation_t;
129 
130 /*
131 ===============
132 AllocTriangulation
133 ===============
134 */
AllocTriangulation(dplane_t * plane)135 triangulation_t	*AllocTriangulation (dplane_t *plane)
136 {
137 	triangulation_t	*t;
138 
139 	t = malloc(sizeof(triangulation_t));
140 	t->numpoints = 0;
141 	t->numedges = 0;
142 	t->numtris = 0;
143 
144 	t->plane = plane;
145 
146 //	memset (t->edgematrix, 0, sizeof(t->edgematrix));
147 
148 	return t;
149 }
150 
151 /*
152 ===============
153 FreeTriangulation
154 ===============
155 */
FreeTriangulation(triangulation_t * tr)156 void FreeTriangulation (triangulation_t *tr)
157 {
158 	free (tr);
159 }
160 
161 
FindEdge(triangulation_t * trian,int p0,int p1)162 triedge_t	*FindEdge (triangulation_t *trian, int p0, int p1)
163 {
164 	triedge_t	*e, *be;
165 	vec3_t		v1;
166 	vec3_t		normal;
167 	vec_t		dist;
168 
169 	if (trian->edgematrix[p0][p1])
170 		return trian->edgematrix[p0][p1];
171 
172 	if (trian->numedges > MAX_TRI_EDGES-2)
173 		Error ("trian->numedges > MAX_TRI_EDGES-2");
174 
175 	VectorSubtract (trian->points[p1]->origin, trian->points[p0]->origin, v1);
176 	VectorNormalize (v1, v1);
177 	CrossProduct (v1, trian->plane->normal, normal);
178 	dist = DotProduct (trian->points[p0]->origin, normal);
179 
180 	e = &trian->edges[trian->numedges];
181 	e->p0 = p0;
182 	e->p1 = p1;
183 	e->tri = NULL;
184 	VectorCopy (normal, e->normal);
185 	e->dist = dist;
186 	trian->numedges++;
187 	trian->edgematrix[p0][p1] = e;
188 
189 	be = &trian->edges[trian->numedges];
190 	be->p0 = p1;
191 	be->p1 = p0;
192 	be->tri = NULL;
193 	VectorSubtract (vec3_origin, normal, be->normal);
194 	be->dist = -dist;
195 	trian->numedges++;
196 	trian->edgematrix[p1][p0] = be;
197 
198 	return e;
199 }
200 
AllocTriangle(triangulation_t * trian)201 triangle_t	*AllocTriangle (triangulation_t *trian)
202 {
203 	triangle_t	*t;
204 
205 	if (trian->numtris >= MAX_TRI_TRIS)
206 		Error ("trian->numtris >= MAX_TRI_TRIS");
207 
208 	t = &trian->tris[trian->numtris];
209 	trian->numtris++;
210 
211 	return t;
212 }
213 
214 /*
215 ============
216 TriEdge_r
217 ============
218 */
TriEdge_r(triangulation_t * trian,triedge_t * e)219 void TriEdge_r (triangulation_t *trian, triedge_t *e)
220 {
221 	int		i, bestp;
222 	vec3_t	v1, v2;
223 	vec_t	*p0, *p1, *p;
224 	vec_t	best, ang;
225 	triangle_t	*nt;
226 
227 	if (e->tri)
228 		return;		// allready connected by someone
229 
230 	// find the point with the best angle
231 	p0 = trian->points[e->p0]->origin;
232 	p1 = trian->points[e->p1]->origin;
233 	best = 1.1;
234 	for (i=0 ; i< trian->numpoints ; i++)
235 	{
236 		p = trian->points[i]->origin;
237 		// a 0 dist will form a degenerate triangle
238 		if (DotProduct(p, e->normal) - e->dist < 0)
239 			continue;	// behind edge
240 		VectorSubtract (p0, p, v1);
241 		VectorSubtract (p1, p, v2);
242 		if (!VectorNormalize (v1,v1))
243 			continue;
244 		if (!VectorNormalize (v2,v2))
245 			continue;
246 		ang = DotProduct (v1, v2);
247 		if (ang < best)
248 		{
249 			best = ang;
250 			bestp = i;
251 		}
252 	}
253 	if (best >= 1)
254 		return;		// edge doesn't match anything
255 
256 	// make a new triangle
257 	nt = AllocTriangle (trian);
258 	nt->edges[0] = e;
259 	nt->edges[1] = FindEdge (trian, e->p1, bestp);
260 	nt->edges[2] = FindEdge (trian, bestp, e->p0);
261 	for (i=0 ; i<3 ; i++)
262 		nt->edges[i]->tri = nt;
263 	TriEdge_r (trian, FindEdge (trian, bestp, e->p1));
264 	TriEdge_r (trian, FindEdge (trian, e->p0, bestp));
265 }
266 
267 /*
268 ============
269 TriangulatePoints
270 ============
271 */
TriangulatePoints(triangulation_t * trian)272 void TriangulatePoints (triangulation_t *trian)
273 {
274 	vec_t	d, bestd;
275 	vec3_t	v1;
276 	int		bp1, bp2, i, j;
277 	vec_t	*p1, *p2;
278 	triedge_t	*e, *e2;
279 
280 	if (trian->numpoints < 2)
281 		return;
282 
283 	// find the two closest points
284 	bestd = 9999;
285 	for (i=0 ; i<trian->numpoints ; i++)
286 	{
287 		p1 = trian->points[i]->origin;
288 		for (j=i+1 ; j<trian->numpoints ; j++)
289 		{
290 			p2 = trian->points[j]->origin;
291 			VectorSubtract (p2, p1, v1);
292 			d = VectorLength (v1);
293 			if (d < bestd)
294 			{
295 				bestd = d;
296 				bp1 = i;
297 				bp2 = j;
298 			}
299 		}
300 	}
301 
302 	e = FindEdge (trian, bp1, bp2);
303 	e2 = FindEdge (trian, bp2, bp1);
304 	TriEdge_r (trian, e);
305 	TriEdge_r (trian, e2);
306 }
307 
308 /*
309 ===============
310 AddPointToTriangulation
311 ===============
312 */
AddPointToTriangulation(patch_t * patch,triangulation_t * trian)313 void AddPointToTriangulation (patch_t *patch, triangulation_t *trian)
314 {
315 	int			pnum;
316 
317 	pnum = trian->numpoints;
318 	if (pnum == MAX_TRI_POINTS)
319 		Error ("trian->numpoints == MAX_TRI_POINTS");
320 	trian->points[pnum] = patch;
321 	trian->numpoints++;
322 }
323 
324 /*
325 ===============
326 LerpTriangle
327 ===============
328 */
LerpTriangle(triangulation_t * trian,triangle_t * t,vec3_t point,vec3_t color)329 void	LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color)
330 {
331 	patch_t		*p1, *p2, *p3;
332 	vec3_t		base, d1, d2;
333 	float		x, y, x1, y1, x2, y2;
334 
335 	p1 = trian->points[t->edges[0]->p0];
336 	p2 = trian->points[t->edges[1]->p0];
337 	p3 = trian->points[t->edges[2]->p0];
338 
339 	VectorCopy (p1->totallight, base);
340 	VectorSubtract (p2->totallight, base, d1);
341 	VectorSubtract (p3->totallight, base, d2);
342 
343 	x = DotProduct (point, t->edges[0]->normal) - t->edges[0]->dist;
344 	y = DotProduct (point, t->edges[2]->normal) - t->edges[2]->dist;
345 
346 	x1 = 0;
347 	y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist;
348 
349 	x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist;
350 	y2 = 0;
351 
352 	if (fabs(y1)<ON_EPSILON || fabs(x2)<ON_EPSILON)
353 	{
354 		VectorCopy (base, color);
355 		return;
356 	}
357 
358 	VectorMA (base, x/x2, d2, color);
359 	VectorMA (color, y/y1, d1, color);
360 }
361 
PointInTriangle(vec3_t point,triangle_t * t)362 qboolean PointInTriangle (vec3_t point, triangle_t *t)
363 {
364 	int		i;
365 	triedge_t	*e;
366 	vec_t	d;
367 
368 	for (i=0 ; i<3 ; i++)
369 	{
370 		e = t->edges[i];
371 		d = DotProduct (e->normal, point) - e->dist;
372 		if (d < 0)
373 			return false;	// not inside
374 	}
375 
376 	return true;
377 }
378 
379 /*
380 ===============
381 SampleTriangulation
382 ===============
383 */
SampleTriangulation(vec3_t point,triangulation_t * trian,vec3_t color)384 void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color)
385 {
386 	triangle_t	*t;
387 	triedge_t	*e;
388 	vec_t		d, best;
389 	patch_t		*p0, *p1;
390 	vec3_t		v1, v2;
391 	int			i, j;
392 
393 	if (trian->numpoints == 0)
394 	{
395 		VectorClear (color);
396 		return;
397 	}
398 	if (trian->numpoints == 1)
399 	{
400 		VectorCopy (trian->points[0]->totallight, color);
401 		return;
402 	}
403 
404 	// search for triangles
405 	for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++)
406 	{
407 		if (!PointInTriangle (point, t))
408 			continue;
409 
410 		// this is it
411 		LerpTriangle (trian, t, point, color);
412 		return;
413 	}
414 
415 	// search for exterior edge
416 	for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++)
417 	{
418 		if (e->tri)
419 			continue;		// not an exterior edge
420 
421 		d = DotProduct (point, e->normal) - e->dist;
422 		if (d < 0)
423 			continue;	// not in front of edge
424 
425 		p0 = trian->points[e->p0];
426 		p1 = trian->points[e->p1];
427 
428 		VectorSubtract (p1->origin, p0->origin, v1);
429 		VectorNormalize (v1, v1);
430 		VectorSubtract (point, p0->origin, v2);
431 		d = DotProduct (v2, v1);
432 		if (d < 0)
433 			continue;
434 		if (d > 1)
435 			continue;
436 		for (i=0 ; i<3 ; i++)
437 			color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]);
438 		return;
439 	}
440 
441 	// search for nearest point
442 	best = 99999;
443 	p1 = NULL;
444 	for (j=0 ; j<trian->numpoints ; j++)
445 	{
446 		p0 = trian->points[j];
447 		VectorSubtract (point, p0->origin, v1);
448 		d = VectorLength (v1);
449 		if (d < best)
450 		{
451 			best = d;
452 			p1 = p0;
453 		}
454 	}
455 
456 	if (!p1)
457 		Error ("SampleTriangulation: no points");
458 
459 	VectorCopy (p1->totallight, color);
460 }
461 
462 /*
463 =================================================================
464 
465   LIGHTMAP SAMPLE GENERATION
466 
467 =================================================================
468 */
469 
470 
471 #define	SINGLEMAP	(64*64*4)
472 
473 typedef struct
474 {
475 	vec_t	facedist;
476 	vec3_t	facenormal;
477 
478 	int		numsurfpt;
479 	vec3_t	surfpt[SINGLEMAP];
480 
481 	vec3_t	modelorg;		// for origined bmodels
482 
483 	vec3_t	texorg;
484 	vec3_t	worldtotex[2];	// s = (world - texorg) . worldtotex[0]
485 	vec3_t	textoworld[2];	// world = texorg + s * textoworld[0]
486 
487 	vec_t	exactmins[2], exactmaxs[2];
488 
489 	int		texmins[2], texsize[2];
490 	int		surfnum;
491 	dface_t	*face;
492 } lightinfo_t;
493 
494 
495 /*
496 ================
497 CalcFaceExtents
498 
499 Fills in s->texmins[] and s->texsize[]
500 also sets exactmins[] and exactmaxs[]
501 ================
502 */
CalcFaceExtents(lightinfo_t * l)503 void CalcFaceExtents (lightinfo_t *l)
504 {
505 	dface_t *s;
506 	vec_t	mins[2], maxs[2], val;
507 	int		i,j, e;
508 	dvertex_t	*v;
509 	texinfo_t	*tex;
510 	vec3_t		vt;
511 
512 	s = l->face;
513 
514 	mins[0] = mins[1] = 999999;
515 	maxs[0] = maxs[1] = -99999;
516 
517 	tex = &texinfo[s->texinfo];
518 
519 	for (i=0 ; i<s->numedges ; i++)
520 	{
521 		e = dsurfedges[s->firstedge+i];
522 		if (e >= 0)
523 			v = dvertexes + dedges[e].v[0];
524 		else
525 			v = dvertexes + dedges[-e].v[1];
526 
527 //		VectorAdd (v->point, l->modelorg, vt);
528 		VectorCopy (v->point, vt);
529 
530 		for (j=0 ; j<2 ; j++)
531 		{
532 			val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3];
533 			if (val < mins[j])
534 				mins[j] = val;
535 			if (val > maxs[j])
536 				maxs[j] = val;
537 		}
538 	}
539 
540 	for (i=0 ; i<2 ; i++)
541 	{
542 		l->exactmins[i] = mins[i];
543 		l->exactmaxs[i] = maxs[i];
544 
545 		mins[i] = floor(mins[i]/16);
546 		maxs[i] = ceil(maxs[i]/16);
547 
548 		l->texmins[i] = mins[i];
549 		l->texsize[i] = maxs[i] - mins[i];
550 		if (l->texsize[0] * l->texsize[1] > SINGLEMAP/4)	// div 4 for extrasamples
551 			Error ("Surface to large to map");
552 	}
553 }
554 
555 /*
556 ================
557 CalcFaceVectors
558 
559 Fills in texorg, worldtotex. and textoworld
560 ================
561 */
CalcFaceVectors(lightinfo_t * l)562 void CalcFaceVectors (lightinfo_t *l)
563 {
564 	texinfo_t	*tex;
565 	int			i, j;
566 	vec3_t	texnormal;
567 	vec_t	distscale;
568 	vec_t	dist, len;
569 	int			w, h;
570 
571 	tex = &texinfo[l->face->texinfo];
572 
573 // convert from float to double
574 	for (i=0 ; i<2 ; i++)
575 		for (j=0 ; j<3 ; j++)
576 			l->worldtotex[i][j] = tex->vecs[i][j];
577 
578 // calculate a normal to the texture axis.  points can be moved along this
579 // without changing their S/T
580 	texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2]
581 		- tex->vecs[1][2]*tex->vecs[0][1];
582 	texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0]
583 		- tex->vecs[1][0]*tex->vecs[0][2];
584 	texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1]
585 		- tex->vecs[1][1]*tex->vecs[0][0];
586 	VectorNormalize (texnormal, texnormal);
587 
588 // flip it towards plane normal
589 	distscale = DotProduct (texnormal, l->facenormal);
590 	if (!distscale)
591 	{
592 		qprintf ("WARNING: Texture axis perpendicular to face\n");
593 		distscale = 1;
594 	}
595 	if (distscale < 0)
596 	{
597 		distscale = -distscale;
598 		VectorSubtract (vec3_origin, texnormal, texnormal);
599 	}
600 
601 // distscale is the ratio of the distance along the texture normal to
602 // the distance along the plane normal
603 	distscale = 1/distscale;
604 
605 	for (i=0 ; i<2 ; i++)
606 	{
607 		len = VectorLength (l->worldtotex[i]);
608 		dist = DotProduct (l->worldtotex[i], l->facenormal);
609 		dist *= distscale;
610 		VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]);
611 		VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]);
612 	}
613 
614 
615 // calculate texorg on the texture plane
616 	for (i=0 ; i<3 ; i++)
617 		l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
618 
619 // project back to the face plane
620 	dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
621 	dist *= distscale;
622 	VectorMA (l->texorg, -dist, texnormal, l->texorg);
623 
624 	// compensate for org'd bmodels
625 	VectorAdd (l->texorg, l->modelorg, l->texorg);
626 
627 	// total sample count
628 	h = l->texsize[1]+1;
629 	w = l->texsize[0]+1;
630 	l->numsurfpt = w * h;
631 }
632 
633 /*
634 =================
635 CalcPoints
636 
637 For each texture aligned grid point, back project onto the plane
638 to get the world xyz value of the sample point
639 =================
640 */
CalcPoints(lightinfo_t * l,float sofs,float tofs)641 void CalcPoints (lightinfo_t *l, float sofs, float tofs)
642 {
643 	int		i;
644 	int		s, t, j;
645 	int		w, h, step;
646 	vec_t	starts, startt, us, ut;
647 	vec_t	*surf;
648 	vec_t	mids, midt;
649 	vec3_t	facemid;
650 	dleaf_t	*leaf;
651 
652 	surf = l->surfpt[0];
653 	mids = (l->exactmaxs[0] + l->exactmins[0])/2;
654 	midt = (l->exactmaxs[1] + l->exactmins[1])/2;
655 
656 	for (j=0 ; j<3 ; j++)
657 		facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt;
658 
659 	h = l->texsize[1]+1;
660 	w = l->texsize[0]+1;
661 	l->numsurfpt = w * h;
662 
663 	starts = l->texmins[0]*16;
664 	startt = l->texmins[1]*16;
665 	step = 16;
666 
667 
668 	for (t=0 ; t<h ; t++)
669 	{
670 		for (s=0 ; s<w ; s++, surf+=3)
671 		{
672 			us = starts + (s+sofs)*step;
673 			ut = startt + (t+tofs)*step;
674 
675 
676 		// if a line can be traced from surf to facemid, the point is good
677 			for (i=0 ; i<6 ; i++)
678 			{
679 			// calculate texture point
680 				for (j=0 ; j<3 ; j++)
681 					surf[j] = l->texorg[j] + l->textoworld[0][j]*us
682 					+ l->textoworld[1][j]*ut;
683 
684 				leaf = PointInLeaf (surf);
685 				if (leaf->contents != CONTENTS_SOLID)
686 				{
687 					if (!TestLine_r (0, facemid, surf))
688 						break;	// got it
689 				}
690 
691 				// nudge it
692 				if (i & 1)
693 				{
694 					if (us > mids)
695 					{
696 						us -= 8;
697 						if (us < mids)
698 							us = mids;
699 					}
700 					else
701 					{
702 						us += 8;
703 						if (us > mids)
704 							us = mids;
705 					}
706 				}
707 				else
708 				{
709 					if (ut > midt)
710 					{
711 						ut -= 8;
712 						if (ut < midt)
713 							ut = midt;
714 					}
715 					else
716 					{
717 						ut += 8;
718 						if (ut > midt)
719 							ut = midt;
720 					}
721 				}
722 			}
723 		}
724 	}
725 
726 }
727 
728 
729 //==============================================================
730 
731 
732 
733 #define	MAX_STYLES	32
734 typedef struct
735 {
736 	int			numsamples;
737 	float		*origins;
738 	int			numstyles;
739 	int			stylenums[MAX_STYLES];
740 	float		*samples[MAX_STYLES];
741 } facelight_t;
742 
743 directlight_t	*directlights[MAX_MAP_LEAFS];
744 facelight_t		facelight[MAX_MAP_FACES];
745 int				numdlights;
746 
747 /*
748 ==================
749 FindTargetEntity
750 ==================
751 */
FindTargetEntity(char * target)752 entity_t *FindTargetEntity (char *target)
753 {
754 	int		i;
755 	char	*n;
756 
757 	for (i=0 ; i<num_entities ; i++)
758 	{
759 		n = ValueForKey (&entities[i], "targetname");
760 		if (!strcmp (n, target))
761 			return &entities[i];
762 	}
763 
764 	return NULL;
765 }
766 
767 //#define	DIRECT_LIGHT	3000
768 #define	DIRECT_LIGHT	3
769 
770 /*
771 =============
772 CreateDirectLights
773 =============
774 */
CreateDirectLights(void)775 void CreateDirectLights (void)
776 {
777 	int		i;
778 	patch_t	*p;
779 	directlight_t	*dl;
780 	dleaf_t	*leaf;
781 	int		cluster;
782 	entity_t	*e, *e2;
783 	char	*name;
784 	char	*target;
785 	float	angle;
786 	vec3_t	dest;
787 	char	*_color;
788 	float	intensity;
789 
790 	//
791 	// surfaces
792 	//
793 	for (i=0, p=patches ; i<num_patches ; i++, p++)
794 	{
795 		if (p->totallight[0] < DIRECT_LIGHT
796 			&& p->totallight[1] < DIRECT_LIGHT
797 			&& p->totallight[2] < DIRECT_LIGHT)
798 			continue;
799 
800 		numdlights++;
801 		dl = malloc(sizeof(directlight_t));
802 		memset (dl, 0, sizeof(*dl));
803 
804 		VectorCopy (p->origin, dl->origin);
805 
806 		leaf = PointInLeaf (dl->origin);
807 		cluster = leaf->cluster;
808 		dl->next = directlights[cluster];
809 		directlights[cluster] = dl;
810 
811 		dl->type = emit_surface;
812 		VectorCopy (p->plane->normal, dl->normal);
813 
814 		dl->intensity = ColorNormalize (p->totallight, dl->color);
815 		dl->intensity *= p->area * direct_scale;
816 		VectorClear (p->totallight);	// all sent now
817 	}
818 
819 	//
820 	// entities
821 	//
822 	for (i=0 ; i<num_entities ; i++)
823 	{
824 		e = &entities[i];
825 		name = ValueForKey (e, "classname");
826 		if (strncmp (name, "light", 5))
827 			continue;
828 
829 		numdlights++;
830 		dl = malloc(sizeof(directlight_t));
831 		memset (dl, 0, sizeof(*dl));
832 
833 		GetVectorForKey (e, "origin", dl->origin);
834 		dl->style = FloatForKey (e, "_style");
835 		if (!dl->style)
836 			dl->style = FloatForKey (e, "style");
837 		if (dl->style < 0 || dl->style >= MAX_LSTYLES)
838 			dl->style = 0;
839 
840 		leaf = PointInLeaf (dl->origin);
841 		cluster = leaf->cluster;
842 
843 		dl->next = directlights[cluster];
844 		directlights[cluster] = dl;
845 
846 		intensity = FloatForKey (e, "light");
847 		if (!intensity)
848 			intensity = FloatForKey (e, "_light");
849 		if (!intensity)
850 			intensity = 300;
851 		_color = ValueForKey (e, "_color");
852 		if (_color && _color[1])
853 		{
854 			sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
855 			ColorNormalize (dl->color, dl->color);
856 		}
857 		else
858 			dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
859 		dl->intensity = intensity*entity_scale;
860 		dl->type = emit_point;
861 
862 		target = ValueForKey (e, "target");
863 
864 		if (!strcmp (name, "light_spot") || target[0])
865 		{
866 			dl->type = emit_spotlight;
867 			dl->stopdot = FloatForKey (e, "_cone");
868 			if (!dl->stopdot)
869 				dl->stopdot = 10;
870 			dl->stopdot = cos(dl->stopdot/180*3.14159);
871 			if (target[0])
872 			{	// point towards target
873 				e2 = FindTargetEntity (target);
874 				if (!e2)
875 					printf ("WARNING: light at (%i %i %i) has missing target\n",
876 					(int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
877 				else
878 				{
879 					GetVectorForKey (e2, "origin", dest);
880 					VectorSubtract (dest, dl->origin, dl->normal);
881 					VectorNormalize (dl->normal, dl->normal);
882 				}
883 			}
884 			else
885 			{	// point down angle
886 				angle = FloatForKey (e, "angle");
887 				if (angle == ANGLE_UP)
888 				{
889 					dl->normal[0] = dl->normal[1] = 0;
890 					dl->normal[2] = 1;
891 				}
892 				else if (angle == ANGLE_DOWN)
893 				{
894 					dl->normal[0] = dl->normal[1] = 0;
895 					dl->normal[2] = -1;
896 				}
897 				else
898 				{
899 					dl->normal[2] = 0;
900 					dl->normal[0] = cos (angle/180*3.14159);
901 					dl->normal[1] = sin (angle/180*3.14159);
902 				}
903 			}
904 		}
905 	}
906 
907 	qprintf ("%i direct lights\n", numdlights);
908 }
909 
910 /*
911 =============
912 GatherSampleLight
913 
914 Lightscale is the normalizer for multisampling
915 =============
916 */
GatherSampleLight(vec3_t pos,vec3_t normal,float ** styletable,int offset,int mapsize,float lightscale)917 void GatherSampleLight (vec3_t pos, vec3_t normal,
918 			float **styletable, int offset, int mapsize, float lightscale)
919 {
920 	int				i;
921 	directlight_t	*l;
922 	byte			pvs[(MAX_MAP_LEAFS+7)/8];
923 	vec3_t			delta;
924 	float			dot, dot2;
925 	float			dist;
926 	float			scale;
927 	float			*dest;
928 
929 	// get the PVS for the pos to limit the number of checks
930 	if (!PvsForOrigin (pos, pvs))
931 	{
932 		return;
933 	}
934 
935 	for (i = 0 ; i<dvis->numclusters ; i++)
936 	{
937 		if ( ! (pvs[ i>>3] & (1<<(i&7))) )
938 			continue;
939 
940 		for (l=directlights[i] ; l ; l=l->next)
941 		{
942 			VectorSubtract (l->origin, pos, delta);
943 			dist = VectorNormalize (delta, delta);
944 			dot = DotProduct (delta, normal);
945 			if (dot <= 0.001)
946 				continue;	// behind sample surface
947 
948 			switch (l->type)
949 			{
950 			case emit_point:
951 				// linear falloff
952 				scale = (l->intensity - dist) * dot;
953 				break;
954 
955 			case emit_surface:
956 				dot2 = -DotProduct (delta, l->normal);
957 				if (dot2 <= 0.001)
958 					goto skipadd;	// behind light surface
959 				scale = (l->intensity / (dist*dist) ) * dot * dot2;
960 				break;
961 
962 			case emit_spotlight:
963 				// linear falloff
964 				dot2 = -DotProduct (delta, l->normal);
965 				if (dot2 <= l->stopdot)
966 					goto skipadd;	// outside light cone
967 				scale = (l->intensity - dist) * dot;
968 				break;
969 			default:
970 				Error ("Bad l->type");
971 			}
972 
973 			if (TestLine_r (0, pos, l->origin))
974 				continue;	// occluded
975 
976 			if (scale <= 0)
977 				continue;
978 
979 			// if this style doesn't have a table yet, allocate one
980 			if (!styletable[l->style])
981 			{
982 				styletable[l->style] = malloc (mapsize);
983 				memset (styletable[l->style], 0, mapsize);
984 			}
985 
986 			dest = styletable[l->style] + offset;
987 			// add some light to it
988 			VectorMA (dest, scale*lightscale, l->color, dest);
989 
990 skipadd: ;
991 		}
992 	}
993 
994 }
995 
996 /*
997 =============
998 AddSampleToPatch
999 
1000 Take the sample's collected light and
1001 add it back into the apropriate patch
1002 for the radiosity pass.
1003 
1004 The sample is added to all patches that might include
1005 any part of it.  They are counted and averaged, so it
1006 doesn't generate extra light.
1007 =============
1008 */
AddSampleToPatch(vec3_t pos,vec3_t color,int facenum)1009 void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum)
1010 {
1011 	patch_t	*patch;
1012 	vec3_t	mins, maxs;
1013 	int		i;
1014 
1015 	if (numbounce == 0)
1016 		return;
1017 	if (color[0] + color[1] + color[2] < 3)
1018 		return;
1019 
1020 	for (patch = face_patches[facenum] ; patch ; patch=patch->next)
1021 	{
1022 		// see if the point is in this patch (roughly)
1023 		WindingBounds (patch->winding, mins, maxs);
1024 		for (i=0 ; i<3 ; i++)
1025 		{
1026 			if (mins[i] > pos[i] + 16)
1027 				goto nextpatch;
1028 			if (maxs[i] < pos[i] - 16)
1029 				goto nextpatch;
1030 		}
1031 
1032 		// add the sample to the patch
1033 		patch->samples++;
1034 		VectorAdd (patch->samplelight, color, patch->samplelight);
1035 nextpatch:;
1036 	}
1037 
1038 }
1039 
1040 
1041 /*
1042 =============
1043 BuildFacelights
1044 =============
1045 */
1046 float	sampleofs[5][2] =
1047 {  {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} };
1048 
1049 
BuildFacelights(int facenum)1050 void BuildFacelights (int facenum)
1051 {
1052 	dface_t	*f;
1053 	lightinfo_t	l[5];
1054 	float		*styletable[MAX_LSTYLES];
1055 	int			i, j;
1056 	float		*spot;
1057 	patch_t		*patch;
1058 	int			numsamples;
1059 	int			tablesize;
1060 	facelight_t		*fl;
1061 
1062 	f = &dfaces[facenum];
1063 
1064 	if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )
1065 		return;		// non-lit texture
1066 
1067 	memset (styletable,0, sizeof(styletable));
1068 
1069 	if (extrasamples)
1070 		numsamples = 5;
1071 	else
1072 		numsamples = 1;
1073 	for (i=0 ; i<numsamples ; i++)
1074 	{
1075 		memset (&l[i], 0, sizeof(l[i]));
1076 		l[i].surfnum = facenum;
1077 		l[i].face = f;
1078 		VectorCopy (dplanes[f->planenum].normal, l[i].facenormal);
1079 		l[i].facedist = dplanes[f->planenum].dist;
1080 		if (f->side)
1081 		{
1082 			VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal);
1083 			l[i].facedist = -l[i].facedist;
1084 		}
1085 
1086 		// get the origin offset for rotating bmodels
1087 		VectorCopy (face_offset[facenum], l[i].modelorg);
1088 
1089 		CalcFaceVectors (&l[i]);
1090 		CalcFaceExtents (&l[i]);
1091 		CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]);
1092 	}
1093 
1094 	tablesize = l[0].numsurfpt * sizeof(vec3_t);
1095 	styletable[0] = malloc(tablesize);
1096 	memset (styletable[0], 0, tablesize);
1097 
1098 	fl = &facelight[facenum];
1099 	fl->numsamples = l[0].numsurfpt;
1100 	fl->origins = malloc (tablesize);
1101 	memcpy (fl->origins, l[0].surfpt, tablesize);
1102 
1103 	for (i=0 ; i<l[0].numsurfpt ; i++)
1104 	{
1105 		for (j=0 ; j<numsamples ; j++)
1106 		{
1107 			GatherSampleLight (l[j].surfpt[i], l[0].facenormal, styletable,
1108 				i*3, tablesize, 1.0/numsamples);
1109 		}
1110 
1111 		// contribute the sample to one or more patches
1112 		AddSampleToPatch (l[0].surfpt[i], styletable[0]+i*3, facenum);
1113 	}
1114 
1115 	// average up the direct light on each patch for radiosity
1116 	for (patch = face_patches[facenum] ; patch ; patch=patch->next)
1117 	{
1118 		if (patch->samples)
1119 		{
1120 			VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight);
1121 		}
1122 		else
1123 		{
1124 //			printf ("patch with no samples\n");
1125 		}
1126 	}
1127 
1128 	for (i=0 ; i<MAX_LSTYLES ; i++)
1129 	{
1130 		if (!styletable[i])
1131 			continue;
1132 		if (fl->numstyles == MAX_STYLES)
1133 			break;
1134 		fl->samples[fl->numstyles] = styletable[i];
1135 		fl->stylenums[fl->numstyles] = i;
1136 		fl->numstyles++;
1137 	}
1138 
1139 	// the light from DIRECT_LIGHTS is sent out, but the
1140 	// texture itself should still be full bright
1141 
1142 	if (face_patches[facenum]->baselight[0] >= DIRECT_LIGHT ||
1143 		face_patches[facenum]->baselight[1] >= DIRECT_LIGHT ||
1144 		face_patches[facenum]->baselight[2] >= DIRECT_LIGHT
1145 		)
1146 	{
1147 		spot = fl->samples[0];
1148 		for (i=0 ; i<l[0].numsurfpt ; i++, spot+=3)
1149 		{
1150 			VectorAdd (spot, face_patches[facenum]->baselight, spot);
1151 		}
1152 	}
1153 }
1154 
1155 
1156 /*
1157 =============
1158 FinalLightFace
1159 
1160 Add the indirect lighting on top of the direct
1161 lighting and save into final map format
1162 =============
1163 */
FinalLightFace(int facenum)1164 void FinalLightFace (int facenum)
1165 {
1166 	dface_t		*f;
1167 	int			i, j, k, st;
1168 	vec3_t		lb;
1169 	patch_t		*patch;
1170 	triangulation_t	*trian;
1171 	facelight_t	*fl;
1172 	float		minlight;
1173 	float		max, newmax;
1174 	byte		*dest;
1175 	int			pfacenum;
1176 	vec3_t		facemins, facemaxs;
1177 
1178 	f = &dfaces[facenum];
1179 	fl = &facelight[facenum];
1180 
1181 	if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )
1182 		return;		// non-lit texture
1183 
1184 	ThreadLock ();
1185 	f->lightofs = lightdatasize;
1186 	lightdatasize += fl->numstyles*(fl->numsamples*3);
1187 
1188 // add green sentinals between lightmaps
1189 #if 0
1190 lightdatasize += 64*3;
1191 for (i=0 ; i<64 ; i++)
1192 dlightdata[lightdatasize-(i+1)*3 + 1] = 255;
1193 #endif
1194 
1195 	if (lightdatasize > MAX_MAP_LIGHTING)
1196 		Error ("MAX_MAP_LIGHTING");
1197 	ThreadUnlock ();
1198 
1199 	f->styles[0] = 0;
1200 	f->styles[1] = f->styles[2] = f->styles[3] = 0xff;
1201 
1202 	//
1203 	// set up the triangulation
1204 	//
1205 	if (numbounce > 0)
1206 	{
1207 		ClearBounds (facemins, facemaxs);
1208 		for (i=0 ; i<f->numedges ; i++)
1209 		{
1210 			int		ednum;
1211 
1212 			ednum = dsurfedges[f->firstedge+i];
1213 			if (ednum >= 0)
1214 				AddPointToBounds (dvertexes[dedges[ednum].v[0]].point,
1215 				facemins, facemaxs);
1216 			else
1217 				AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point,
1218 				facemins, facemaxs);
1219 		}
1220 
1221 		trian = AllocTriangulation (&dplanes[f->planenum]);
1222 
1223 		// for all faces on the plane, add the nearby patches
1224 		// to the triangulation
1225 		for (pfacenum = planelinks[f->side][f->planenum]
1226 			; pfacenum ; pfacenum = facelinks[pfacenum])
1227 		{
1228 			for (patch = face_patches[pfacenum] ; patch ; patch=patch->next)
1229 			{
1230 				for (i=0 ; i < 3 ; i++)
1231 				{
1232 					if (facemins[i] - patch->origin[i] > subdiv*2)
1233 						break;
1234 					if (patch->origin[i] - facemaxs[i] > subdiv*2)
1235 						break;
1236 				}
1237 				if (i != 3)
1238 					continue;	// not needed for this face
1239 				AddPointToTriangulation (patch, trian);
1240 			}
1241 		}
1242 		for (i=0 ; i<trian->numpoints ; i++)
1243 			memset (trian->edgematrix[i], 0, trian->numpoints*sizeof(trian->edgematrix[0][0]) );
1244 		TriangulatePoints (trian);
1245 	}
1246 
1247 	//
1248 	// sample the triangulation
1249 	//
1250 
1251 	// _minlight allows models that have faces that would not be
1252 	// illuminated to receive a mottled light pattern instead of
1253 	// black
1254 	minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;
1255 
1256 	dest = &dlightdata[f->lightofs];
1257 
1258 	if (fl->numstyles > MAXLIGHTMAPS)
1259 	{
1260 		fl->numstyles = MAXLIGHTMAPS;
1261 		printf ("face with too many lightstyles: (%f %f %f)\n",
1262 			face_patches[facenum]->origin[0],
1263 			face_patches[facenum]->origin[1],
1264 			face_patches[facenum]->origin[2]
1265 			);
1266 	}
1267 
1268 	for (st=0 ; st<fl->numstyles ; st++)
1269 	{
1270 		f->styles[st] = fl->stylenums[st];
1271 		for (j=0 ; j<fl->numsamples ; j++)
1272 		{
1273 			VectorCopy ( (fl->samples[st]+j*3), lb);
1274 			if (numbounce > 0 && st == 0)
1275 			{
1276 				vec3_t	add;
1277 
1278 				SampleTriangulation (fl->origins + j*3, trian, add);
1279 				VectorAdd (lb, add, lb);
1280 			}
1281 			// add an ambient term if desired
1282 			lb[0] += ambient;
1283 			lb[1] += ambient;
1284 			lb[2] += ambient;
1285 
1286 			VectorScale (lb, lightscale, lb);
1287 
1288 			// we need to clamp without allowing hue to change
1289 			for (k=0 ; k<3 ; k++)
1290 				if (lb[k] < 1)
1291 					lb[k] = 1;
1292 			max = lb[0];
1293 			if (lb[1] > max)
1294 				max = lb[1];
1295 			if (lb[2] > max)
1296 				max = lb[2];
1297 			newmax = max;
1298 			if (newmax < 0)
1299 				newmax = 0;		// roundoff problems
1300 			if (newmax < minlight)
1301 			{
1302 				newmax = minlight + (rand()%48);
1303 			}
1304 			if (newmax > maxlight)
1305 				newmax = maxlight;
1306 
1307 			for (k=0 ; k<3 ; k++)
1308 			{
1309 				*dest++ = lb[k]*newmax/max;
1310 			}
1311 		}
1312 	}
1313 
1314 	if (numbounce > 0)
1315 		FreeTriangulation (trian);
1316 }
1317