2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\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
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
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
23 #define MAX_LSTYLES 256
\r
31 edgeshare_t edgeshare[MAX_MAP_EDGES];
\r
33 int facelinks[MAX_MAP_FACES];
\r
34 int planelinks[2][MAX_MAP_PLANES];
\r
41 void LinkPlaneFaces (void)
\r
47 for (i=0 ; i<numfaces ; i++, f++)
\r
49 facelinks[i] = planelinks[f->side][f->planenum];
\r
50 planelinks[f->side][f->planenum] = i;
\r
59 void PairEdges (void)
\r
66 for (i=0 ; i<numfaces ; i++, f++)
\r
68 for (j=0 ; j<f->numedges ; j++)
\r
70 k = dsurfedges[f->firstedge + j];
\r
82 if (e->faces[0] && e->faces[1])
\r
84 // determine if coplanar
\r
85 if (e->faces[0]->planenum == e->faces[1]->planenum)
\r
93 =================================================================
\r
97 =================================================================
\r
100 typedef struct triedge_s
\r
105 struct triangle_s *tri;
\r
108 typedef struct triangle_s
\r
110 triedge_t *edges[3];
\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
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
134 triangulation_t *AllocTriangulation (dplane_t *plane)
\r
136 triangulation_t *t;
\r
138 t = malloc(sizeof(triangulation_t));
\r
145 // memset (t->edgematrix, 0, sizeof(t->edgematrix));
\r
155 void FreeTriangulation (triangulation_t *tr)
\r
161 triedge_t *FindEdge (triangulation_t *trian, int p0, int p1)
\r
168 if (trian->edgematrix[p0][p1])
\r
169 return trian->edgematrix[p0][p1];
\r
171 if (trian->numedges > MAX_TRI_EDGES-2)
\r
172 Error ("trian->numedges > MAX_TRI_EDGES-2");
\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
179 e = &trian->edges[trian->numedges];
\r
183 VectorCopy (normal, e->normal);
\r
186 trian->edgematrix[p0][p1] = e;
\r
188 be = &trian->edges[trian->numedges];
\r
192 VectorSubtract (vec3_origin, normal, be->normal);
\r
195 trian->edgematrix[p1][p0] = be;
\r
200 triangle_t *AllocTriangle (triangulation_t *trian)
\r
204 if (trian->numtris >= MAX_TRI_TRIS)
\r
205 Error ("trian->numtris >= MAX_TRI_TRIS");
\r
207 t = &trian->tris[trian->numtris];
\r
218 void TriEdge_r (triangulation_t *trian, triedge_t *e)
\r
222 vec_t *p0, *p1, *p;
\r
227 return; // allready connected by someone
\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
233 for (i=0 ; i< trian->numpoints ; i++)
\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
243 if (!VectorNormalize (v2,v2))
\r
245 ang = DotProduct (v1, v2);
\r
253 return; // edge doesn't match anything
\r
255 // make a new triangle
\r
256 nt = AllocTriangle (trian);
\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
271 void TriangulatePoints (triangulation_t *trian)
\r
275 int bp1, bp2, i, j;
\r
279 if (trian->numpoints < 2)
\r
282 // find the two closest points
\r
284 for (i=0 ; i<trian->numpoints ; i++)
\r
286 p1 = trian->points[i]->origin;
\r
287 for (j=i+1 ; j<trian->numpoints ; j++)
\r
289 p2 = trian->points[j]->origin;
\r
290 VectorSubtract (p2, p1, v1);
\r
291 d = VectorLength (v1);
\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
309 AddPointToTriangulation
\r
312 void AddPointToTriangulation (patch_t *patch, triangulation_t *trian)
\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
328 void LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color)
\r
330 patch_t *p1, *p2, *p3;
\r
331 vec3_t base, d1, d2;
\r
332 float x, y, x1, y1, x2, y2;
\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
338 VectorCopy (p1->totallight, base);
\r
339 VectorSubtract (p2->totallight, base, d1);
\r
340 VectorSubtract (p3->totallight, base, d2);
\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
346 y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist;
\r
348 x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist;
\r
351 if (fabs(y1)<ON_EPSILON || fabs(x2)<ON_EPSILON)
\r
353 VectorCopy (base, color);
\r
357 VectorMA (base, x/x2, d2, color);
\r
358 VectorMA (color, y/y1, d1, color);
\r
361 qboolean PointInTriangle (vec3_t point, triangle_t *t)
\r
367 for (i=0 ; i<3 ; i++)
\r
370 d = DotProduct (e->normal, point) - e->dist;
\r
372 return false; // not inside
\r
380 SampleTriangulation
\r
383 void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color)
\r
392 if (trian->numpoints == 0)
\r
394 VectorClear (color);
\r
397 if (trian->numpoints == 1)
\r
399 VectorCopy (trian->points[0]->totallight, color);
\r
403 // search for triangles
\r
404 for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++)
\r
406 if (!PointInTriangle (point, t))
\r
410 LerpTriangle (trian, t, point, color);
\r
414 // search for exterior edge
\r
415 for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++)
\r
418 continue; // not an exterior edge
\r
420 d = DotProduct (point, e->normal) - e->dist;
\r
422 continue; // not in front of edge
\r
424 p0 = trian->points[e->p0];
\r
425 p1 = trian->points[e->p1];
\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
435 for (i=0 ; i<3 ; i++)
\r
436 color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]);
\r
440 // search for nearest point
\r
443 for (j=0 ; j<trian->numpoints ; j++)
\r
445 p0 = trian->points[j];
\r
446 VectorSubtract (point, p0->origin, v1);
\r
447 d = VectorLength (v1);
\r
456 Error ("SampleTriangulation: no points");
\r
458 VectorCopy (p1->totallight, color);
\r
462 =================================================================
\r
464 LIGHTMAP SAMPLE GENERATION
\r
466 =================================================================
\r
470 #define SINGLEMAP (64*64*4)
\r
478 vec3_t surfpt[SINGLEMAP];
\r
480 vec3_t modelorg; // for origined bmodels
\r
483 vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]
\r
484 vec3_t textoworld[2]; // world = texorg + s * textoworld[0]
\r
486 vec_t exactmins[2], exactmaxs[2];
\r
488 int texmins[2], texsize[2];
\r
498 Fills in s->texmins[] and s->texsize[]
\r
499 also sets exactmins[] and exactmaxs[]
\r
502 void CalcFaceExtents (lightinfo_t *l)
\r
505 vec_t mins[2], maxs[2], val;
\r
513 mins[0] = mins[1] = 999999;
\r
514 maxs[0] = maxs[1] = -99999;
\r
516 tex = &texinfo[s->texinfo];
\r
518 for (i=0 ; i<s->numedges ; i++)
\r
520 e = dsurfedges[s->firstedge+i];
\r
522 v = dvertexes + dedges[e].v[0];
\r
524 v = dvertexes + dedges[-e].v[1];
\r
526 // VectorAdd (v->point, l->modelorg, vt);
\r
527 VectorCopy (v->point, vt);
\r
529 for (j=0 ; j<2 ; j++)
\r
531 val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3];
\r
539 for (i=0 ; i<2 ; i++)
\r
541 l->exactmins[i] = mins[i];
\r
542 l->exactmaxs[i] = maxs[i];
\r
544 mins[i] = floor(mins[i]/16);
\r
545 maxs[i] = ceil(maxs[i]/16);
\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
558 Fills in texorg, worldtotex. and textoworld
\r
561 void CalcFaceVectors (lightinfo_t *l)
\r
570 tex = &texinfo[l->face->texinfo];
\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
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
587 // flip it towards plane normal
\r
588 distscale = DotProduct (texnormal, l->facenormal);
\r
591 Sys_FPrintf( SYS_VRB, "WARNING: Texture axis perpendicular to face\n");
\r
596 distscale = -distscale;
\r
597 VectorSubtract (vec3_origin, texnormal, texnormal);
\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
604 for (i=0 ; i<2 ; i++)
\r
606 len = VectorLength (l->worldtotex[i]);
\r
607 dist = DotProduct (l->worldtotex[i], l->facenormal);
\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
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
618 // project back to the face plane
\r
619 dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
\r
621 VectorMA (l->texorg, -dist, texnormal, l->texorg);
\r
623 // compensate for org'd bmodels
\r
624 VectorAdd (l->texorg, l->modelorg, l->texorg);
\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
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
640 void CalcPoints (lightinfo_t *l, float sofs, float tofs)
\r
645 vec_t starts, startt, us, ut;
\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
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
658 h = l->texsize[1]+1;
\r
659 w = l->texsize[0]+1;
\r
660 l->numsurfpt = w * h;
\r
662 starts = l->texmins[0]*16;
\r
663 startt = l->texmins[1]*16;
\r
667 for (t=0 ; t<h ; t++)
\r
669 for (s=0 ; s<w ; s++, surf+=3)
\r
671 us = starts + (s+sofs)*step;
\r
672 ut = startt + (t+tofs)*step;
\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
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
683 leaf = Rad_PointInLeaf (surf);
\r
684 if (leaf->contents != CONTENTS_SOLID)
\r
686 if (!TestLine_r (0, facemid, surf))
\r
728 //==============================================================
\r
732 #define MAX_STYLES 32
\r
738 int stylenums[MAX_STYLES];
\r
739 float *samples[MAX_STYLES];
\r
742 directlight_t *directlights[MAX_MAP_LEAFS];
\r
743 facelight_t facelight[MAX_MAP_FACES];
\r
751 entity_t *FindTargetEntity (char *target)
\r
756 for (i=0 ; i<num_entities ; i++)
\r
758 n = ValueForKey (&entities[i], "targetname");
\r
759 if (!strcmp (n, target))
\r
760 return &entities[i];
\r
766 //#define DIRECT_LIGHT 3000
\r
767 #define DIRECT_LIGHT 3
\r
774 void CreateDirectLights (void)
\r
792 for (i=0, p=patches ; i< (int) num_patches ; i++, p++)
\r
794 if (p->totallight[0] < DIRECT_LIGHT
\r
795 && p->totallight[1] < DIRECT_LIGHT
\r
796 && p->totallight[2] < DIRECT_LIGHT)
\r
800 dl = malloc(sizeof(directlight_t));
\r
801 memset (dl, 0, sizeof(*dl));
\r
803 VectorCopy (p->origin, dl->origin);
\r
805 leaf = Rad_PointInLeaf (dl->origin);
\r
806 cluster = leaf->cluster;
\r
807 dl->next = directlights[cluster];
\r
808 directlights[cluster] = dl;
\r
810 dl->type = emit_surface;
\r
811 VectorCopy (p->plane->normal, dl->normal);
\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
821 for (i=0 ; i<num_entities ; i++)
\r
824 name = ValueForKey (e, "classname");
\r
825 if (strncmp (name, "light", 5))
\r
829 dl = malloc(sizeof(directlight_t));
\r
830 memset (dl, 0, sizeof(*dl));
\r
832 GetVectorForKey (e, "origin", dl->origin);
\r
833 dl->style = FloatForKey (e, "_style");
\r
835 dl->style = FloatForKey (e, "style");
\r
836 if (dl->style < 0 || dl->style >= MAX_LSTYLES)
\r
839 leaf = Rad_PointInLeaf (dl->origin);
\r
840 cluster = leaf->cluster;
\r
842 dl->next = directlights[cluster];
\r
843 directlights[cluster] = dl;
\r
845 intensity = FloatForKey (e, "light");
\r
847 intensity = FloatForKey (e, "_light");
\r
850 _color = ValueForKey (e, "_color");
\r
851 if (_color && _color[0])
\r
853 sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
\r
854 ColorNormalize (dl->color, dl->color);
\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
861 target = ValueForKey (e, "target");
\r
863 if (!strcmp (name, "light_spot") || target[0])
\r
865 dl->type = emit_spotlight;
\r
866 dl->stopdot = FloatForKey (e, "_cone");
\r
869 dl->stopdot = cos(dl->stopdot/180*3.14159);
\r
871 { // point towards target
\r
872 e2 = FindTargetEntity (target);
\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
878 GetVectorForKey (e2, "origin", dest);
\r
879 VectorSubtract (dest, dl->origin, dl->normal);
\r
880 VectorNormalize (dl->normal, dl->normal);
\r
884 { // point down angle
\r
885 angle = FloatForKey (e, "angle");
\r
886 if (angle == ANGLE_UP)
\r
888 dl->normal[0] = dl->normal[1] = 0;
\r
891 else if (angle == ANGLE_DOWN)
\r
893 dl->normal[0] = dl->normal[1] = 0;
\r
894 dl->normal[2] = -1;
\r
899 dl->normal[0] = cos (angle/180*3.14159);
\r
900 dl->normal[1] = sin (angle/180*3.14159);
\r
906 Sys_FPrintf( SYS_VRB, "%i direct lights\n", numdlights);
\r
913 Lightscale is the normalizer for multisampling
\r
916 void GatherSampleLight (vec3_t pos, vec3_t normal,
\r
917 float **styletable, int offset, int mapsize, float lightscale)
\r
921 byte pvs[(MAX_MAP_LEAFS+7)/8];
\r
928 // get the PVS for the pos to limit the number of checks
\r
929 if (!PvsForOrigin (pos, pvs))
\r
934 for (i = 0 ; i<dvis->numclusters ; i++)
\r
936 if ( ! (pvs[ i>>3] & (1<<(i&7))) )
\r
939 for (l=directlights[i] ; l ; l=l->next)
\r
941 VectorSubtract (l->origin, pos, delta);
\r
942 dist = VectorNormalize (delta, delta);
\r
943 dot = DotProduct (delta, normal);
\r
945 continue; // behind sample surface
\r
951 scale = (l->intensity - dist) * dot;
\r
955 dot2 = -DotProduct (delta, l->normal);
\r
957 goto skipadd; // behind light surface
\r
958 scale = (l->intensity / (dist*dist) ) * dot * dot2;
\r
961 case emit_spotlight:
\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
969 Error ("Bad l->type");
\r
972 if (TestLine_r (0, pos, l->origin))
\r
973 continue; // occluded
\r
978 // if this style doesn't have a table yet, allocate one
\r
979 if (!styletable[l->style])
\r
981 styletable[l->style] = malloc (mapsize);
\r
982 memset (styletable[l->style], 0, mapsize);
\r
985 dest = styletable[l->style] + offset;
\r
986 // add some light to it
\r
987 VectorMA (dest, scale*lightscale, l->color, dest);
\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
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
1008 void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum)
\r
1011 vec3_t mins, maxs;
\r
1014 if (numbounce == 0)
\r
1016 if (color[0] + color[1] + color[2] < 3)
\r
1019 for (patch = face_patches[facenum] ; patch ; patch=patch->next)
\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
1025 if (mins[i] > pos[i] + 16)
\r
1027 if (maxs[i] < pos[i] - 16)
\r
1031 // add the sample to the patch
\r
1033 VectorAdd (patch->samplelight, color, patch->samplelight);
\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
1049 void BuildFacelights (int facenum)
\r
1053 float *styletable[MAX_LSTYLES];
\r
1061 f = &dfaces[facenum];
\r
1063 if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )
\r
1064 return; // non-lit texture
\r
1066 memset (styletable,0, sizeof(styletable));
\r
1072 for (i=0 ; i<numsamples ; i++)
\r
1074 memset (&l[i], 0, sizeof(l[i]));
\r
1075 l[i].surfnum = facenum;
\r
1077 VectorCopy (dplanes[f->planenum].normal, l[i].facenormal);
\r
1078 l[i].facedist = dplanes[f->planenum].dist;
\r
1081 VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal);
\r
1082 l[i].facedist = -l[i].facedist;
\r
1085 // get the origin offset for rotating bmodels
\r
1086 VectorCopy (face_offset[facenum], l[i].modelorg);
\r
1088 CalcFaceVectors (&l[i]);
\r
1089 CalcFaceExtents (&l[i]);
\r
1090 CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]);
\r
1093 tablesize = l[0].numsurfpt * sizeof(vec3_t);
\r
1094 styletable[0] = malloc(tablesize);
\r
1095 memset (styletable[0], 0, tablesize);
\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
1102 for (i=0 ; i<l[0].numsurfpt ; i++)
\r
1104 for (j=0 ; j<numsamples ; j++)
\r
1106 GatherSampleLight (l[j].surfpt[i], l[0].facenormal, styletable,
\r
1107 i*3, tablesize, 1.0/numsamples);
\r
1110 // contribute the sample to one or more patches
\r
1111 AddSampleToPatch (l[0].surfpt[i], styletable[0]+i*3, facenum);
\r
1114 // average up the direct light on each patch for radiosity
\r
1115 for (patch = face_patches[facenum] ; patch ; patch=patch->next)
\r
1117 if (patch->samples)
\r
1119 VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight);
\r
1123 // printf ("patch with no samples\n");
\r
1127 for (i=0 ; i<MAX_LSTYLES ; i++)
\r
1129 if (!styletable[i])
\r
1131 if (fl->numstyles == MAX_STYLES)
\r
1133 fl->samples[fl->numstyles] = styletable[i];
\r
1134 fl->stylenums[fl->numstyles] = i;
\r
1138 // the light from DIRECT_LIGHTS is sent out, but the
\r
1139 // texture itself should still be full bright
\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
1146 spot = fl->samples[0];
\r
1147 for (i=0 ; i<l[0].numsurfpt ; i++, spot+=3)
\r
1149 VectorAdd (spot, face_patches[facenum]->baselight, spot);
\r
1159 Add the indirect lighting on top of the direct
\r
1160 lighting and save into final map format
\r
1163 void FinalLightFace (int facenum)
\r
1169 triangulation_t *trian;
\r
1172 float max, newmax;
\r
1175 vec3_t facemins, facemaxs;
\r
1177 f = &dfaces[facenum];
\r
1178 fl = &facelight[facenum];
\r
1180 if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )
\r
1181 return; // non-lit texture
\r
1184 f->lightofs = lightdatasize;
\r
1185 lightdatasize += fl->numstyles*(fl->numsamples*3);
\r
1187 // add green sentinals between lightmaps
\r
1189 lightdatasize += 64*3;
\r
1190 for (i=0 ; i<64 ; i++)
\r
1191 dlightdata[lightdatasize-(i+1)*3 + 1] = 255;
\r
1194 if (lightdatasize > MAX_MAP_LIGHTING)
\r
1195 Error ("MAX_MAP_LIGHTING");
\r
1199 f->styles[1] = f->styles[2] = f->styles[3] = 0xff;
\r
1202 // set up the triangulation
\r
1204 if (numbounce > 0)
\r
1206 ClearBounds (facemins, facemaxs);
\r
1207 for (i=0 ; i<f->numedges ; i++)
\r
1211 ednum = dsurfedges[f->firstedge+i];
\r
1213 AddPointToBounds (dvertexes[dedges[ednum].v[0]].point,
\r
1214 facemins, facemaxs);
\r
1216 AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point,
\r
1217 facemins, facemaxs);
\r
1220 trian = AllocTriangulation (&dplanes[f->planenum]);
\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
1227 for (patch = face_patches[pfacenum] ; patch ; patch=patch->next)
\r
1229 for (i=0 ; i < 3 ; i++)
\r
1231 if (facemins[i] - patch->origin[i] > subdiv*2)
\r
1233 if (patch->origin[i] - facemaxs[i] > subdiv*2)
\r
1237 continue; // not needed for this face
\r
1238 AddPointToTriangulation (patch, trian);
\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
1247 // sample the triangulation
\r
1250 // _minlight allows models that have faces that would not be
\r
1251 // illuminated to receive a mottled light pattern instead of
\r
1253 minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;
\r
1255 dest = &dlightdata[f->lightofs];
\r
1257 if (fl->numstyles > MAXLIGHTMAPS)
\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
1267 for (st=0 ; st<fl->numstyles ; st++)
\r
1269 f->styles[st] = fl->stylenums[st];
\r
1270 for (j=0 ; j<fl->numsamples ; j++)
\r
1272 VectorCopy ( (fl->samples[st]+j*3), lb);
\r
1273 if (numbounce > 0 && st == 0)
\r
1277 SampleTriangulation (fl->origins + j*3, trian, add);
\r
1278 VectorAdd (lb, add, lb);
\r
1280 // add an ambient term if desired
\r
1281 lb[0] += ambient;
\r
1282 lb[1] += ambient;
\r
1283 lb[2] += ambient;
\r
1285 VectorScale (lb, lightscale, lb);
\r
1287 // we need to clamp without allowing hue to change
\r
1288 for (k=0 ; k<3 ; k++)
\r
1298 newmax = 0; // roundoff problems
\r
1299 if (newmax < minlight)
\r
1301 newmax = minlight + (rand()%48);
\r
1303 if (newmax > maxlight)
\r
1304 newmax = maxlight;
\r
1306 for (k=0 ; k<3 ; k++)
\r
1308 *dest++ = lb[k]*newmax/max;
\r
1313 if (numbounce > 0)
\r
1314 FreeTriangulation (trian);
\r