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