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