-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-#include "qrad.h"\r
-\r
-#define MAX_LSTYLES 256\r
-\r
-typedef struct\r
-{\r
- dface_t *faces[2];\r
- qboolean coplanar;\r
-} edgeshare_t;\r
-\r
-edgeshare_t edgeshare[MAX_MAP_EDGES];\r
-\r
-int facelinks[MAX_MAP_FACES];\r
-int planelinks[2][MAX_MAP_PLANES];\r
-\r
-/*\r
-============\r
-LinkPlaneFaces\r
-============\r
-*/\r
-void LinkPlaneFaces (void)\r
-{\r
- int i;\r
- dface_t *f;\r
-\r
- f = dfaces;\r
- for (i=0 ; i<numfaces ; i++, f++)\r
- {\r
- facelinks[i] = planelinks[f->side][f->planenum];\r
- planelinks[f->side][f->planenum] = i;\r
- }\r
-}\r
-\r
-/*\r
-============\r
-PairEdges\r
-============\r
-*/\r
-void PairEdges (void)\r
-{\r
- int i, j, k;\r
- dface_t *f;\r
- edgeshare_t *e;\r
-\r
- f = dfaces;\r
- for (i=0 ; i<numfaces ; i++, f++)\r
- {\r
- for (j=0 ; j<f->numedges ; j++)\r
- {\r
- k = dsurfedges[f->firstedge + j];\r
- if (k < 0)\r
- {\r
- e = &edgeshare[-k];\r
- e->faces[1] = f;\r
- }\r
- else\r
- {\r
- e = &edgeshare[k];\r
- e->faces[0] = f;\r
- }\r
-\r
- if (e->faces[0] && e->faces[1])\r
- {\r
- // determine if coplanar\r
- if (e->faces[0]->planenum == e->faces[1]->planenum)\r
- e->coplanar = true;\r
- }\r
- }\r
- }\r
-}\r
-\r
-/*\r
-=================================================================\r
-\r
- POINT TRIANGULATION\r
-\r
-=================================================================\r
-*/\r
-\r
-typedef struct triedge_s\r
-{\r
- int p0, p1;\r
- vec3_t normal;\r
- vec_t dist;\r
- struct triangle_s *tri;\r
-} triedge_t;\r
-\r
-typedef struct triangle_s\r
-{\r
- triedge_t *edges[3];\r
-} triangle_t;\r
-\r
-#define MAX_TRI_POINTS 1024\r
-#define MAX_TRI_EDGES (MAX_TRI_POINTS*6)\r
-#define MAX_TRI_TRIS (MAX_TRI_POINTS*2)\r
-\r
-typedef struct\r
-{\r
- int numpoints;\r
- int numedges;\r
- int numtris;\r
- dplane_t *plane;\r
- triedge_t *edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS];\r
- patch_t *points[MAX_TRI_POINTS];\r
- triedge_t edges[MAX_TRI_EDGES];\r
- triangle_t tris[MAX_TRI_TRIS];\r
-} triangulation_t;\r
-\r
-/*\r
-===============\r
-AllocTriangulation\r
-===============\r
-*/\r
-triangulation_t *AllocTriangulation (dplane_t *plane)\r
-{\r
- triangulation_t *t;\r
-\r
- t = malloc(sizeof(triangulation_t));\r
- t->numpoints = 0;\r
- t->numedges = 0;\r
- t->numtris = 0;\r
-\r
- t->plane = plane;\r
-\r
-// memset (t->edgematrix, 0, sizeof(t->edgematrix));\r
-\r
- return t;\r
-}\r
-\r
-/*\r
-===============\r
-FreeTriangulation\r
-===============\r
-*/\r
-void FreeTriangulation (triangulation_t *tr)\r
-{\r
- free (tr);\r
-}\r
-\r
-\r
-triedge_t *FindEdge (triangulation_t *trian, int p0, int p1)\r
-{\r
- triedge_t *e, *be;\r
- vec3_t v1;\r
- vec3_t normal;\r
- vec_t dist;\r
-\r
- if (trian->edgematrix[p0][p1])\r
- return trian->edgematrix[p0][p1];\r
-\r
- if (trian->numedges > MAX_TRI_EDGES-2)\r
- Error ("trian->numedges > MAX_TRI_EDGES-2");\r
-\r
- VectorSubtract (trian->points[p1]->origin, trian->points[p0]->origin, v1);\r
- VectorNormalize (v1, v1);\r
- CrossProduct (v1, trian->plane->normal, normal);\r
- dist = DotProduct (trian->points[p0]->origin, normal);\r
-\r
- e = &trian->edges[trian->numedges];\r
- e->p0 = p0;\r
- e->p1 = p1;\r
- e->tri = NULL;\r
- VectorCopy (normal, e->normal);\r
- e->dist = dist;\r
- trian->numedges++;\r
- trian->edgematrix[p0][p1] = e;\r
-\r
- be = &trian->edges[trian->numedges];\r
- be->p0 = p1;\r
- be->p1 = p0;\r
- be->tri = NULL;\r
- VectorSubtract (vec3_origin, normal, be->normal);\r
- be->dist = -dist;\r
- trian->numedges++;\r
- trian->edgematrix[p1][p0] = be;\r
-\r
- return e;\r
-}\r
-\r
-triangle_t *AllocTriangle (triangulation_t *trian)\r
-{\r
- triangle_t *t;\r
-\r
- if (trian->numtris >= MAX_TRI_TRIS)\r
- Error ("trian->numtris >= MAX_TRI_TRIS");\r
-\r
- t = &trian->tris[trian->numtris];\r
- trian->numtris++;\r
-\r
- return t;\r
-}\r
-\r
-/*\r
-============\r
-TriEdge_r\r
-============\r
-*/\r
-void TriEdge_r (triangulation_t *trian, triedge_t *e)\r
-{\r
- int i, bestp;\r
- vec3_t v1, v2;\r
- vec_t *p0, *p1, *p;\r
- vec_t best, ang;\r
- triangle_t *nt;\r
-\r
- if (e->tri)\r
- return; // allready connected by someone\r
-\r
- // find the point with the best angle\r
- p0 = trian->points[e->p0]->origin;\r
- p1 = trian->points[e->p1]->origin;\r
- best = 1.1;\r
- for (i=0 ; i< trian->numpoints ; i++)\r
- {\r
- p = trian->points[i]->origin;\r
- // a 0 dist will form a degenerate triangle\r
- if (DotProduct(p, e->normal) - e->dist < 0)\r
- continue; // behind edge\r
- VectorSubtract (p0, p, v1);\r
- VectorSubtract (p1, p, v2);\r
- if (!VectorNormalize (v1,v1))\r
- continue;\r
- if (!VectorNormalize (v2,v2))\r
- continue;\r
- ang = DotProduct (v1, v2);\r
- if (ang < best)\r
- {\r
- best = ang;\r
- bestp = i;\r
- }\r
- }\r
- if (best >= 1)\r
- return; // edge doesn't match anything\r
-\r
- // make a new triangle\r
- nt = AllocTriangle (trian);\r
- nt->edges[0] = e;\r
- nt->edges[1] = FindEdge (trian, e->p1, bestp);\r
- nt->edges[2] = FindEdge (trian, bestp, e->p0);\r
- for (i=0 ; i<3 ; i++)\r
- nt->edges[i]->tri = nt;\r
- TriEdge_r (trian, FindEdge (trian, bestp, e->p1));\r
- TriEdge_r (trian, FindEdge (trian, e->p0, bestp));\r
-}\r
-\r
-/*\r
-============\r
-TriangulatePoints\r
-============\r
-*/\r
-void TriangulatePoints (triangulation_t *trian)\r
-{\r
- vec_t d, bestd;\r
- vec3_t v1;\r
- int bp1, bp2, i, j;\r
- vec_t *p1, *p2;\r
- triedge_t *e, *e2;\r
-\r
- if (trian->numpoints < 2)\r
- return;\r
-\r
- // find the two closest points\r
- bestd = 9999;\r
- for (i=0 ; i<trian->numpoints ; i++)\r
- {\r
- p1 = trian->points[i]->origin;\r
- for (j=i+1 ; j<trian->numpoints ; j++)\r
- {\r
- p2 = trian->points[j]->origin;\r
- VectorSubtract (p2, p1, v1);\r
- d = VectorLength (v1);\r
- if (d < bestd)\r
- {\r
- bestd = d;\r
- bp1 = i;\r
- bp2 = j;\r
- }\r
- }\r
- }\r
-\r
- e = FindEdge (trian, bp1, bp2);\r
- e2 = FindEdge (trian, bp2, bp1);\r
- TriEdge_r (trian, e);\r
- TriEdge_r (trian, e2);\r
-}\r
-\r
-/*\r
-===============\r
-AddPointToTriangulation\r
-===============\r
-*/\r
-void AddPointToTriangulation (patch_t *patch, triangulation_t *trian)\r
-{\r
- int pnum;\r
-\r
- pnum = trian->numpoints;\r
- if (pnum == MAX_TRI_POINTS)\r
- Error ("trian->numpoints == MAX_TRI_POINTS");\r
- trian->points[pnum] = patch;\r
- trian->numpoints++;\r
-}\r
-\r
-/*\r
-===============\r
-LerpTriangle\r
-===============\r
-*/\r
-void LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color)\r
-{\r
- patch_t *p1, *p2, *p3;\r
- vec3_t base, d1, d2;\r
- float x, y, x1, y1, x2, y2;\r
-\r
- p1 = trian->points[t->edges[0]->p0];\r
- p2 = trian->points[t->edges[1]->p0];\r
- p3 = trian->points[t->edges[2]->p0];\r
-\r
- VectorCopy (p1->totallight, base);\r
- VectorSubtract (p2->totallight, base, d1);\r
- VectorSubtract (p3->totallight, base, d2);\r
-\r
- x = DotProduct (point, t->edges[0]->normal) - t->edges[0]->dist;\r
- y = DotProduct (point, t->edges[2]->normal) - t->edges[2]->dist;\r
-\r
- x1 = 0;\r
- y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist;\r
-\r
- x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist;\r
- y2 = 0;\r
-\r
- if (fabs(y1)<ON_EPSILON || fabs(x2)<ON_EPSILON)\r
- {\r
- VectorCopy (base, color);\r
- return;\r
- }\r
-\r
- VectorMA (base, x/x2, d2, color);\r
- VectorMA (color, y/y1, d1, color);\r
-}\r
-\r
-qboolean PointInTriangle (vec3_t point, triangle_t *t)\r
-{\r
- int i;\r
- triedge_t *e;\r
- vec_t d;\r
-\r
- for (i=0 ; i<3 ; i++)\r
- {\r
- e = t->edges[i];\r
- d = DotProduct (e->normal, point) - e->dist;\r
- if (d < 0)\r
- return false; // not inside\r
- }\r
-\r
- return true;\r
-}\r
-\r
-/*\r
-===============\r
-SampleTriangulation\r
-===============\r
-*/\r
-void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color)\r
-{\r
- triangle_t *t;\r
- triedge_t *e;\r
- vec_t d, best;\r
- patch_t *p0, *p1;\r
- vec3_t v1, v2;\r
- int i, j;\r
-\r
- if (trian->numpoints == 0)\r
- {\r
- VectorClear (color);\r
- return;\r
- }\r
- if (trian->numpoints == 1)\r
- {\r
- VectorCopy (trian->points[0]->totallight, color);\r
- return;\r
- }\r
-\r
- // search for triangles\r
- for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++)\r
- {\r
- if (!PointInTriangle (point, t))\r
- continue;\r
-\r
- // this is it\r
- LerpTriangle (trian, t, point, color);\r
- return;\r
- }\r
- \r
- // search for exterior edge\r
- for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++)\r
- {\r
- if (e->tri)\r
- continue; // not an exterior edge\r
-\r
- d = DotProduct (point, e->normal) - e->dist;\r
- if (d < 0)\r
- continue; // not in front of edge\r
-\r
- p0 = trian->points[e->p0];\r
- p1 = trian->points[e->p1];\r
- \r
- VectorSubtract (p1->origin, p0->origin, v1);\r
- VectorNormalize (v1, v1);\r
- VectorSubtract (point, p0->origin, v2);\r
- d = DotProduct (v2, v1);\r
- if (d < 0)\r
- continue;\r
- if (d > 1)\r
- continue;\r
- for (i=0 ; i<3 ; i++)\r
- color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]);\r
- return;\r
- }\r
-\r
- // search for nearest point\r
- best = 99999;\r
- p1 = NULL;\r
- for (j=0 ; j<trian->numpoints ; j++)\r
- {\r
- p0 = trian->points[j];\r
- VectorSubtract (point, p0->origin, v1);\r
- d = VectorLength (v1);\r
- if (d < best)\r
- {\r
- best = d;\r
- p1 = p0;\r
- }\r
- }\r
-\r
- if (!p1)\r
- Error ("SampleTriangulation: no points");\r
-\r
- VectorCopy (p1->totallight, color);\r
-}\r
-\r
-/*\r
-=================================================================\r
-\r
- LIGHTMAP SAMPLE GENERATION\r
-\r
-=================================================================\r
-*/\r
-\r
-\r
-#define SINGLEMAP (64*64*4)\r
-\r
-typedef struct\r
-{\r
- vec_t facedist;\r
- vec3_t facenormal;\r
-\r
- int numsurfpt;\r
- vec3_t surfpt[SINGLEMAP];\r
-\r
- vec3_t modelorg; // for origined bmodels\r
-\r
- vec3_t texorg;\r
- vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]\r
- vec3_t textoworld[2]; // world = texorg + s * textoworld[0]\r
-\r
- vec_t exactmins[2], exactmaxs[2];\r
- \r
- int texmins[2], texsize[2];\r
- int surfnum;\r
- dface_t *face;\r
-} lightinfo_t;\r
-\r
-\r
-/*\r
-================\r
-CalcFaceExtents\r
-\r
-Fills in s->texmins[] and s->texsize[]\r
-also sets exactmins[] and exactmaxs[]\r
-================\r
-*/\r
-void CalcFaceExtents (lightinfo_t *l)\r
-{\r
- dface_t *s;\r
- vec_t mins[2], maxs[2], val;\r
- int i,j, e;\r
- dvertex_t *v;\r
- texinfo_t *tex;\r
- vec3_t vt;\r
-\r
- s = l->face;\r
-\r
- mins[0] = mins[1] = 999999;\r
- maxs[0] = maxs[1] = -99999;\r
-\r
- tex = &texinfo[s->texinfo];\r
- \r
- for (i=0 ; i<s->numedges ; i++)\r
- {\r
- e = dsurfedges[s->firstedge+i];\r
- if (e >= 0)\r
- v = dvertexes + dedges[e].v[0];\r
- else\r
- v = dvertexes + dedges[-e].v[1];\r
- \r
-// VectorAdd (v->point, l->modelorg, vt);\r
- VectorCopy (v->point, vt);\r
-\r
- for (j=0 ; j<2 ; j++)\r
- {\r
- val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3];\r
- if (val < mins[j])\r
- mins[j] = val;\r
- if (val > maxs[j])\r
- maxs[j] = val;\r
- }\r
- }\r
-\r
- for (i=0 ; i<2 ; i++)\r
- { \r
- l->exactmins[i] = mins[i];\r
- l->exactmaxs[i] = maxs[i];\r
- \r
- mins[i] = floor(mins[i]/16);\r
- maxs[i] = ceil(maxs[i]/16);\r
-\r
- l->texmins[i] = mins[i];\r
- l->texsize[i] = maxs[i] - mins[i];\r
- if (l->texsize[0] * l->texsize[1] > SINGLEMAP/4) // div 4 for extrasamples\r
- Error ("Surface to large to map");\r
- }\r
-}\r
-\r
-/*\r
-================\r
-CalcFaceVectors\r
-\r
-Fills in texorg, worldtotex. and textoworld\r
-================\r
-*/\r
-void CalcFaceVectors (lightinfo_t *l)\r
-{\r
- texinfo_t *tex;\r
- int i, j;\r
- vec3_t texnormal;\r
- vec_t distscale;\r
- vec_t dist, len;\r
- int w, h;\r
-\r
- tex = &texinfo[l->face->texinfo];\r
- \r
-// convert from float to double\r
- for (i=0 ; i<2 ; i++)\r
- for (j=0 ; j<3 ; j++)\r
- l->worldtotex[i][j] = tex->vecs[i][j];\r
-\r
-// calculate a normal to the texture axis. points can be moved along this\r
-// without changing their S/T\r
- texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2]\r
- - tex->vecs[1][2]*tex->vecs[0][1];\r
- texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0]\r
- - tex->vecs[1][0]*tex->vecs[0][2];\r
- texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1]\r
- - tex->vecs[1][1]*tex->vecs[0][0];\r
- VectorNormalize (texnormal, texnormal);\r
-\r
-// flip it towards plane normal\r
- distscale = DotProduct (texnormal, l->facenormal);\r
- if (!distscale)\r
- {\r
- Sys_FPrintf( SYS_VRB, "WARNING: Texture axis perpendicular to face\n");\r
- distscale = 1;\r
- }\r
- if (distscale < 0)\r
- {\r
- distscale = -distscale;\r
- VectorSubtract (vec3_origin, texnormal, texnormal);\r
- } \r
-\r
-// distscale is the ratio of the distance along the texture normal to\r
-// the distance along the plane normal\r
- distscale = 1/distscale;\r
-\r
- for (i=0 ; i<2 ; i++)\r
- {\r
- len = VectorLength (l->worldtotex[i]);\r
- dist = DotProduct (l->worldtotex[i], l->facenormal);\r
- dist *= distscale;\r
- VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]);\r
- VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]);\r
- }\r
-\r
-\r
-// calculate texorg on the texture plane\r
- for (i=0 ; i<3 ; i++)\r
- l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];\r
-\r
-// project back to the face plane\r
- dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;\r
- dist *= distscale;\r
- VectorMA (l->texorg, -dist, texnormal, l->texorg);\r
-\r
- // compensate for org'd bmodels\r
- VectorAdd (l->texorg, l->modelorg, l->texorg);\r
-\r
- // total sample count\r
- h = l->texsize[1]+1;\r
- w = l->texsize[0]+1;\r
- l->numsurfpt = w * h;\r
-}\r
-\r
-/*\r
-=================\r
-CalcPoints\r
-\r
-For each texture aligned grid point, back project onto the plane\r
-to get the world xyz value of the sample point\r
-=================\r
-*/\r
-void CalcPoints (lightinfo_t *l, float sofs, float tofs)\r
-{\r
- int i;\r
- int s, t, j;\r
- int w, h, step;\r
- vec_t starts, startt, us, ut;\r
- vec_t *surf;\r
- vec_t mids, midt;\r
- vec3_t facemid;\r
- dleaf_t *leaf;\r
-\r
- surf = l->surfpt[0];\r
- mids = (l->exactmaxs[0] + l->exactmins[0])/2;\r
- midt = (l->exactmaxs[1] + l->exactmins[1])/2;\r
-\r
- for (j=0 ; j<3 ; j++)\r
- facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt;\r
-\r
- h = l->texsize[1]+1;\r
- w = l->texsize[0]+1;\r
- l->numsurfpt = w * h;\r
-\r
- starts = l->texmins[0]*16;\r
- startt = l->texmins[1]*16;\r
- step = 16;\r
-\r
-\r
- for (t=0 ; t<h ; t++)\r
- {\r
- for (s=0 ; s<w ; s++, surf+=3)\r
- {\r
- us = starts + (s+sofs)*step;\r
- ut = startt + (t+tofs)*step;\r
-\r
-\r
- // if a line can be traced from surf to facemid, the point is good\r
- for (i=0 ; i<6 ; i++)\r
- {\r
- // calculate texture point\r
- for (j=0 ; j<3 ; j++)\r
- surf[j] = l->texorg[j] + l->textoworld[0][j]*us\r
- + l->textoworld[1][j]*ut;\r
-\r
- leaf = Rad_PointInLeaf (surf);\r
- if (leaf->contents != CONTENTS_SOLID)\r
- {\r
- if (!TestLine_r (0, facemid, surf))\r
- break; // got it\r
- }\r
-\r
- // nudge it\r
- if (i & 1)\r
- {\r
- if (us > mids)\r
- {\r
- us -= 8;\r
- if (us < mids)\r
- us = mids;\r
- }\r
- else\r
- {\r
- us += 8;\r
- if (us > mids)\r
- us = mids;\r
- }\r
- }\r
- else\r
- {\r
- if (ut > midt)\r
- {\r
- ut -= 8;\r
- if (ut < midt)\r
- ut = midt;\r
- }\r
- else\r
- {\r
- ut += 8;\r
- if (ut > midt)\r
- ut = midt;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- \r
-}\r
-\r
-\r
-//==============================================================\r
-\r
-\r
-\r
-#define MAX_STYLES 32\r
-typedef struct\r
-{\r
- int numsamples;\r
- float *origins;\r
- int numstyles;\r
- int stylenums[MAX_STYLES];\r
- float *samples[MAX_STYLES];\r
-} facelight_t;\r
-\r
-directlight_t *directlights[MAX_MAP_LEAFS];\r
-facelight_t facelight[MAX_MAP_FACES];\r
-int numdlights;\r
-\r
-/*\r
-==================\r
-FindTargetEntity\r
-==================\r
-*/\r
-entity_t *FindTargetEntity (char *target)\r
-{\r
- int i;\r
- char *n;\r
-\r
- for (i=0 ; i<num_entities ; i++)\r
- {\r
- n = ValueForKey (&entities[i], "targetname");\r
- if (!strcmp (n, target))\r
- return &entities[i];\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-//#define DIRECT_LIGHT 3000\r
-#define DIRECT_LIGHT 3\r
-\r
-/*\r
-=============\r
-CreateDirectLights\r
-=============\r
-*/\r
-void CreateDirectLights (void)\r
-{\r
- int i;\r
- patch_t *p;\r
- directlight_t *dl;\r
- dleaf_t *leaf;\r
- int cluster;\r
- entity_t *e, *e2;\r
- char *name;\r
- char *target;\r
- float angle;\r
- vec3_t dest;\r
- char *_color;\r
- float intensity;\r
-\r
- //\r
- // surfaces\r
- //\r
- for (i=0, p=patches ; i< (int) num_patches ; i++, p++)\r
- {\r
- if (p->totallight[0] < DIRECT_LIGHT\r
- && p->totallight[1] < DIRECT_LIGHT\r
- && p->totallight[2] < DIRECT_LIGHT)\r
- continue;\r
-\r
- numdlights++;\r
- dl = malloc(sizeof(directlight_t));\r
- memset (dl, 0, sizeof(*dl));\r
-\r
- VectorCopy (p->origin, dl->origin);\r
-\r
- leaf = Rad_PointInLeaf (dl->origin);\r
- cluster = leaf->cluster;\r
- dl->next = directlights[cluster];\r
- directlights[cluster] = dl;\r
-\r
- dl->type = emit_surface;\r
- VectorCopy (p->plane->normal, dl->normal);\r
-\r
- dl->intensity = ColorNormalize (p->totallight, dl->color);\r
- dl->intensity *= p->area * direct_scale;\r
- VectorClear (p->totallight); // all sent now\r
- }\r
-\r
- //\r
- // entities\r
- //\r
- for (i=0 ; i<num_entities ; i++)\r
- {\r
- e = &entities[i];\r
- name = ValueForKey (e, "classname");\r
- if (strncmp (name, "light", 5))\r
- continue;\r
-\r
- numdlights++;\r
- dl = malloc(sizeof(directlight_t));\r
- memset (dl, 0, sizeof(*dl));\r
-\r
- GetVectorForKey (e, "origin", dl->origin);\r
- dl->style = FloatForKey (e, "_style");\r
- if (!dl->style)\r
- dl->style = FloatForKey (e, "style");\r
- if (dl->style < 0 || dl->style >= MAX_LSTYLES)\r
- dl->style = 0;\r
-\r
- leaf = Rad_PointInLeaf (dl->origin);\r
- cluster = leaf->cluster;\r
-\r
- dl->next = directlights[cluster];\r
- directlights[cluster] = dl;\r
-\r
- intensity = FloatForKey (e, "light");\r
- if (!intensity)\r
- intensity = FloatForKey (e, "_light");\r
- if (!intensity)\r
- intensity = 300;\r
- _color = ValueForKey (e, "_color");\r
- if (_color && _color[0])\r
- {\r
- sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);\r
- ColorNormalize (dl->color, dl->color);\r
- }\r
- else\r
- dl->color[0] = dl->color[1] = dl->color[2] = 1.0;\r
- dl->intensity = intensity*entity_scale;\r
- dl->type = emit_point;\r
-\r
- target = ValueForKey (e, "target");\r
-\r
- if (!strcmp (name, "light_spot") || target[0])\r
- {\r
- dl->type = emit_spotlight;\r
- dl->stopdot = FloatForKey (e, "_cone");\r
- if (!dl->stopdot)\r
- dl->stopdot = 10;\r
- dl->stopdot = cos(dl->stopdot/180*3.14159);\r
- if (target[0])\r
- { // point towards target\r
- e2 = FindTargetEntity (target);\r
- if (!e2)\r
- Sys_Printf ("WARNING: light at (%i %i %i) has missing target\n",\r
- (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);\r
- else\r
- {\r
- GetVectorForKey (e2, "origin", dest);\r
- VectorSubtract (dest, dl->origin, dl->normal);\r
- VectorNormalize (dl->normal, dl->normal);\r
- }\r
- }\r
- else\r
- { // point down angle\r
- angle = FloatForKey (e, "angle");\r
- if (angle == ANGLE_UP)\r
- {\r
- dl->normal[0] = dl->normal[1] = 0;\r
- dl->normal[2] = 1;\r
- }\r
- else if (angle == ANGLE_DOWN)\r
- {\r
- dl->normal[0] = dl->normal[1] = 0;\r
- dl->normal[2] = -1;\r
- }\r
- else\r
- {\r
- dl->normal[2] = 0;\r
- dl->normal[0] = cos (angle/180*3.14159);\r
- dl->normal[1] = sin (angle/180*3.14159);\r
- }\r
- }\r
- }\r
- }\r
-\r
- Sys_FPrintf( SYS_VRB, "%i direct lights\n", numdlights);\r
-}\r
-\r
-/*\r
-=============\r
-GatherSampleLight\r
-\r
-Lightscale is the normalizer for multisampling\r
-=============\r
-*/\r
-void GatherSampleLight (vec3_t pos, vec3_t normal,\r
- float **styletable, int offset, int mapsize, float lightscale)\r
-{\r
- int i;\r
- directlight_t *l;\r
- byte pvs[(MAX_MAP_LEAFS+7)/8];\r
- vec3_t delta;\r
- float dot, dot2;\r
- float dist;\r
- float scale;\r
- float *dest;\r
-\r
- // get the PVS for the pos to limit the number of checks\r
- if (!PvsForOrigin (pos, pvs))\r
- {\r
- return;\r
- }\r
-\r
- for (i = 0 ; i<dvis->numclusters ; i++)\r
- {\r
- if ( ! (pvs[ i>>3] & (1<<(i&7))) )\r
- continue;\r
-\r
- for (l=directlights[i] ; l ; l=l->next)\r
- {\r
- VectorSubtract (l->origin, pos, delta);\r
- dist = VectorNormalize (delta, delta);\r
- dot = DotProduct (delta, normal);\r
- if (dot <= 0.001)\r
- continue; // behind sample surface\r
-\r
- switch (l->type)\r
- {\r
- case emit_point:\r
- // linear falloff\r
- scale = (l->intensity - dist) * dot;\r
- break;\r
-\r
- case emit_surface:\r
- dot2 = -DotProduct (delta, l->normal);\r
- if (dot2 <= 0.001)\r
- goto skipadd; // behind light surface\r
- scale = (l->intensity / (dist*dist) ) * dot * dot2;\r
- break;\r
-\r
- case emit_spotlight:\r
- // linear falloff\r
- dot2 = -DotProduct (delta, l->normal);\r
- if (dot2 <= l->stopdot)\r
- goto skipadd; // outside light cone\r
- scale = (l->intensity - dist) * dot;\r
- break;\r
- default:\r
- Error ("Bad l->type");\r
- }\r
-\r
- if (TestLine_r (0, pos, l->origin))\r
- continue; // occluded\r
-\r
- if (scale <= 0)\r
- continue;\r
-\r
- // if this style doesn't have a table yet, allocate one\r
- if (!styletable[l->style])\r
- {\r
- styletable[l->style] = malloc (mapsize);\r
- memset (styletable[l->style], 0, mapsize);\r
- }\r
-\r
- dest = styletable[l->style] + offset; \r
- // add some light to it\r
- VectorMA (dest, scale*lightscale, l->color, dest);\r
-\r
-skipadd: ;\r
- }\r
- }\r
-\r
-}\r
-\r
-/*\r
-=============\r
-AddSampleToPatch\r
-\r
-Take the sample's collected light and\r
-add it back into the apropriate patch\r
-for the radiosity pass.\r
-\r
-The sample is added to all patches that might include\r
-any part of it. They are counted and averaged, so it\r
-doesn't generate extra light.\r
-=============\r
-*/\r
-void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum)\r
-{\r
- patch_t *patch;\r
- vec3_t mins, maxs;\r
- int i;\r
-\r
- if (numbounce == 0)\r
- return;\r
- if (color[0] + color[1] + color[2] < 3)\r
- return;\r
-\r
- for (patch = face_patches[facenum] ; patch ; patch=patch->next)\r
- {\r
- // see if the point is in this patch (roughly)\r
- WindingBounds (patch->winding, mins, maxs);\r
- for (i=0 ; i<3 ; i++)\r
- {\r
- if (mins[i] > pos[i] + 16)\r
- goto nextpatch;\r
- if (maxs[i] < pos[i] - 16)\r
- goto nextpatch;\r
- }\r
-\r
- // add the sample to the patch\r
- patch->samples++;\r
- VectorAdd (patch->samplelight, color, patch->samplelight);\r
-nextpatch:;\r
- }\r
-\r
-}\r
-\r
-\r
-/*\r
-=============\r
-BuildFacelights\r
-=============\r
-*/\r
-float sampleofs[5][2] = \r
-{ {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} };\r
-\r
-\r
-void BuildFacelights (int facenum)\r
-{\r
- dface_t *f;\r
- lightinfo_t l[5];\r
- float *styletable[MAX_LSTYLES];\r
- int i, j;\r
- float *spot;\r
- patch_t *patch;\r
- int numsamples;\r
- int tablesize;\r
- facelight_t *fl;\r
- \r
- f = &dfaces[facenum];\r
-\r
- if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )\r
- return; // non-lit texture\r
-\r
- memset (styletable,0, sizeof(styletable));\r
-\r
- if (extrasamples)\r
- numsamples = 5;\r
- else\r
- numsamples = 1;\r
- for (i=0 ; i<numsamples ; i++)\r
- {\r
- memset (&l[i], 0, sizeof(l[i]));\r
- l[i].surfnum = facenum;\r
- l[i].face = f;\r
- VectorCopy (dplanes[f->planenum].normal, l[i].facenormal);\r
- l[i].facedist = dplanes[f->planenum].dist;\r
- if (f->side)\r
- {\r
- VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal);\r
- l[i].facedist = -l[i].facedist;\r
- }\r
-\r
- // get the origin offset for rotating bmodels\r
- VectorCopy (face_offset[facenum], l[i].modelorg);\r
-\r
- CalcFaceVectors (&l[i]);\r
- CalcFaceExtents (&l[i]);\r
- CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]);\r
- }\r
-\r
- tablesize = l[0].numsurfpt * sizeof(vec3_t);\r
- styletable[0] = malloc(tablesize);\r
- memset (styletable[0], 0, tablesize);\r
-\r
- fl = &facelight[facenum];\r
- fl->numsamples = l[0].numsurfpt;\r
- fl->origins = malloc (tablesize);\r
- memcpy (fl->origins, l[0].surfpt, tablesize);\r
-\r
- for (i=0 ; i<l[0].numsurfpt ; i++)\r
- {\r
- for (j=0 ; j<numsamples ; j++)\r
- {\r
- GatherSampleLight (l[j].surfpt[i], l[0].facenormal, styletable,\r
- i*3, tablesize, 1.0/numsamples);\r
- }\r
-\r
- // contribute the sample to one or more patches\r
- AddSampleToPatch (l[0].surfpt[i], styletable[0]+i*3, facenum);\r
- }\r
-\r
- // average up the direct light on each patch for radiosity\r
- for (patch = face_patches[facenum] ; patch ; patch=patch->next)\r
- {\r
- if (patch->samples)\r
- {\r
- VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight);\r
- }\r
- else\r
- {\r
-// printf ("patch with no samples\n");\r
- }\r
- }\r
-\r
- for (i=0 ; i<MAX_LSTYLES ; i++)\r
- {\r
- if (!styletable[i])\r
- continue;\r
- if (fl->numstyles == MAX_STYLES)\r
- break;\r
- fl->samples[fl->numstyles] = styletable[i];\r
- fl->stylenums[fl->numstyles] = i;\r
- fl->numstyles++;\r
- }\r
-\r
- // the light from DIRECT_LIGHTS is sent out, but the\r
- // texture itself should still be full bright\r
-\r
- if (face_patches[facenum]->baselight[0] >= DIRECT_LIGHT ||\r
- face_patches[facenum]->baselight[1] >= DIRECT_LIGHT ||\r
- face_patches[facenum]->baselight[2] >= DIRECT_LIGHT\r
- )\r
- {\r
- spot = fl->samples[0];\r
- for (i=0 ; i<l[0].numsurfpt ; i++, spot+=3)\r
- {\r
- VectorAdd (spot, face_patches[facenum]->baselight, spot);\r
- }\r
- }\r
-}\r
-\r
-\r
-/*\r
-=============\r
-FinalLightFace\r
-\r
-Add the indirect lighting on top of the direct\r
-lighting and save into final map format\r
-=============\r
-*/\r
-void FinalLightFace (int facenum)\r
-{\r
- dface_t *f;\r
- int i, j, k, st;\r
- vec3_t lb;\r
- patch_t *patch;\r
- triangulation_t *trian;\r
- facelight_t *fl;\r
- float minlight;\r
- float max, newmax;\r
- byte *dest;\r
- int pfacenum;\r
- vec3_t facemins, facemaxs;\r
-\r
- f = &dfaces[facenum];\r
- fl = &facelight[facenum];\r
-\r
- if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )\r
- return; // non-lit texture\r
-\r
- ThreadLock ();\r
- f->lightofs = lightdatasize;\r
- lightdatasize += fl->numstyles*(fl->numsamples*3);\r
-\r
-// add green sentinals between lightmaps\r
-#if 0\r
-lightdatasize += 64*3;\r
-for (i=0 ; i<64 ; i++)\r
-dlightdata[lightdatasize-(i+1)*3 + 1] = 255;\r
-#endif\r
-\r
- if (lightdatasize > MAX_MAP_LIGHTING)\r
- Error ("MAX_MAP_LIGHTING");\r
- ThreadUnlock ();\r
-\r
- f->styles[0] = 0;\r
- f->styles[1] = f->styles[2] = f->styles[3] = 0xff;\r
-\r
- //\r
- // set up the triangulation\r
- //\r
- if (numbounce > 0)\r
- {\r
- ClearBounds (facemins, facemaxs);\r
- for (i=0 ; i<f->numedges ; i++)\r
- {\r
- int ednum;\r
-\r
- ednum = dsurfedges[f->firstedge+i];\r
- if (ednum >= 0)\r
- AddPointToBounds (dvertexes[dedges[ednum].v[0]].point,\r
- facemins, facemaxs);\r
- else\r
- AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point,\r
- facemins, facemaxs);\r
- }\r
-\r
- trian = AllocTriangulation (&dplanes[f->planenum]);\r
-\r
- // for all faces on the plane, add the nearby patches\r
- // to the triangulation\r
- for (pfacenum = planelinks[f->side][f->planenum]\r
- ; pfacenum ; pfacenum = facelinks[pfacenum])\r
- {\r
- for (patch = face_patches[pfacenum] ; patch ; patch=patch->next)\r
- {\r
- for (i=0 ; i < 3 ; i++)\r
- {\r
- if (facemins[i] - patch->origin[i] > subdiv*2)\r
- break;\r
- if (patch->origin[i] - facemaxs[i] > subdiv*2)\r
- break;\r
- }\r
- if (i != 3)\r
- continue; // not needed for this face\r
- AddPointToTriangulation (patch, trian);\r
- }\r
- }\r
- for (i=0 ; i<trian->numpoints ; i++)\r
- memset (trian->edgematrix[i], 0, trian->numpoints*sizeof(trian->edgematrix[0][0]) );\r
- TriangulatePoints (trian);\r
- }\r
- \r
- //\r
- // sample the triangulation\r
- //\r
-\r
- // _minlight allows models that have faces that would not be\r
- // illuminated to receive a mottled light pattern instead of\r
- // black\r
- minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;\r
-\r
- dest = &dlightdata[f->lightofs];\r
-\r
- if (fl->numstyles > MAXLIGHTMAPS)\r
- {\r
- fl->numstyles = MAXLIGHTMAPS;\r
- Sys_Printf ("face with too many lightstyles: (%f %f %f)\n",\r
- face_patches[facenum]->origin[0],\r
- face_patches[facenum]->origin[1],\r
- face_patches[facenum]->origin[2]\r
- );\r
- }\r
-\r
- for (st=0 ; st<fl->numstyles ; st++)\r
- {\r
- f->styles[st] = fl->stylenums[st];\r
- for (j=0 ; j<fl->numsamples ; j++)\r
- {\r
- VectorCopy ( (fl->samples[st]+j*3), lb);\r
- if (numbounce > 0 && st == 0)\r
- {\r
- vec3_t add;\r
-\r
- SampleTriangulation (fl->origins + j*3, trian, add);\r
- VectorAdd (lb, add, lb);\r
- }\r
- // add an ambient term if desired\r
- lb[0] += ambient; \r
- lb[1] += ambient; \r
- lb[2] += ambient; \r
-\r
- VectorScale (lb, lightscale, lb);\r
-\r
- // we need to clamp without allowing hue to change\r
- for (k=0 ; k<3 ; k++)\r
- if (lb[k] < 1)\r
- lb[k] = 1;\r
- max = lb[0];\r
- if (lb[1] > max)\r
- max = lb[1];\r
- if (lb[2] > max)\r
- max = lb[2];\r
- newmax = max;\r
- if (newmax < 0)\r
- newmax = 0; // roundoff problems\r
- if (newmax < minlight)\r
- {\r
- newmax = minlight + (rand()%48);\r
- }\r
- if (newmax > maxlight)\r
- newmax = maxlight;\r
-\r
- for (k=0 ; k<3 ; k++)\r
- {\r
- *dest++ = lb[k]*newmax/max;\r
- }\r
- }\r
- }\r
-\r
- if (numbounce > 0)\r
- FreeTriangulation (trian);\r
-}\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#include "qrad.h"
+
+#define MAX_LSTYLES 256
+
+typedef struct
+{
+ dface_t *faces[2];
+ qboolean coplanar;
+} edgeshare_t;
+
+edgeshare_t edgeshare[MAX_MAP_EDGES];
+
+int facelinks[MAX_MAP_FACES];
+int planelinks[2][MAX_MAP_PLANES];
+
+/*
+============
+LinkPlaneFaces
+============
+*/
+void LinkPlaneFaces (void)
+{
+ int i;
+ dface_t *f;
+
+ f = dfaces;
+ for (i=0 ; i<numfaces ; i++, f++)
+ {
+ facelinks[i] = planelinks[f->side][f->planenum];
+ planelinks[f->side][f->planenum] = i;
+ }
+}
+
+/*
+============
+PairEdges
+============
+*/
+void PairEdges (void)
+{
+ int i, j, k;
+ dface_t *f;
+ edgeshare_t *e;
+
+ f = dfaces;
+ for (i=0 ; i<numfaces ; i++, f++)
+ {
+ for (j=0 ; j<f->numedges ; j++)
+ {
+ k = dsurfedges[f->firstedge + j];
+ if (k < 0)
+ {
+ e = &edgeshare[-k];
+ e->faces[1] = f;
+ }
+ else
+ {
+ e = &edgeshare[k];
+ e->faces[0] = f;
+ }
+
+ if (e->faces[0] && e->faces[1])
+ {
+ // determine if coplanar
+ if (e->faces[0]->planenum == e->faces[1]->planenum)
+ e->coplanar = true;
+ }
+ }
+ }
+}
+
+/*
+=================================================================
+
+ POINT TRIANGULATION
+
+=================================================================
+*/
+
+typedef struct triedge_s
+{
+ int p0, p1;
+ vec3_t normal;
+ vec_t dist;
+ struct triangle_s *tri;
+} triedge_t;
+
+typedef struct triangle_s
+{
+ triedge_t *edges[3];
+} triangle_t;
+
+#define MAX_TRI_POINTS 1024
+#define MAX_TRI_EDGES (MAX_TRI_POINTS*6)
+#define MAX_TRI_TRIS (MAX_TRI_POINTS*2)
+
+typedef struct
+{
+ int numpoints;
+ int numedges;
+ int numtris;
+ dplane_t *plane;
+ triedge_t *edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS];
+ patch_t *points[MAX_TRI_POINTS];
+ triedge_t edges[MAX_TRI_EDGES];
+ triangle_t tris[MAX_TRI_TRIS];
+} triangulation_t;
+
+/*
+===============
+AllocTriangulation
+===============
+*/
+triangulation_t *AllocTriangulation (dplane_t *plane)
+{
+ triangulation_t *t;
+
+ t = malloc(sizeof(triangulation_t));
+ t->numpoints = 0;
+ t->numedges = 0;
+ t->numtris = 0;
+
+ t->plane = plane;
+
+// memset (t->edgematrix, 0, sizeof(t->edgematrix));
+
+ return t;
+}
+
+/*
+===============
+FreeTriangulation
+===============
+*/
+void FreeTriangulation (triangulation_t *tr)
+{
+ free (tr);
+}
+
+
+triedge_t *FindEdge (triangulation_t *trian, int p0, int p1)
+{
+ triedge_t *e, *be;
+ vec3_t v1;
+ vec3_t normal;
+ vec_t dist;
+
+ if (trian->edgematrix[p0][p1])
+ return trian->edgematrix[p0][p1];
+
+ if (trian->numedges > MAX_TRI_EDGES-2)
+ Error ("trian->numedges > MAX_TRI_EDGES-2");
+
+ VectorSubtract (trian->points[p1]->origin, trian->points[p0]->origin, v1);
+ VectorNormalize (v1, v1);
+ CrossProduct (v1, trian->plane->normal, normal);
+ dist = DotProduct (trian->points[p0]->origin, normal);
+
+ e = &trian->edges[trian->numedges];
+ e->p0 = p0;
+ e->p1 = p1;
+ e->tri = NULL;
+ VectorCopy (normal, e->normal);
+ e->dist = dist;
+ trian->numedges++;
+ trian->edgematrix[p0][p1] = e;
+
+ be = &trian->edges[trian->numedges];
+ be->p0 = p1;
+ be->p1 = p0;
+ be->tri = NULL;
+ VectorSubtract (vec3_origin, normal, be->normal);
+ be->dist = -dist;
+ trian->numedges++;
+ trian->edgematrix[p1][p0] = be;
+
+ return e;
+}
+
+triangle_t *AllocTriangle (triangulation_t *trian)
+{
+ triangle_t *t;
+
+ if (trian->numtris >= MAX_TRI_TRIS)
+ Error ("trian->numtris >= MAX_TRI_TRIS");
+
+ t = &trian->tris[trian->numtris];
+ trian->numtris++;
+
+ return t;
+}
+
+/*
+============
+TriEdge_r
+============
+*/
+void TriEdge_r (triangulation_t *trian, triedge_t *e)
+{
+ int i, bestp;
+ vec3_t v1, v2;
+ vec_t *p0, *p1, *p;
+ vec_t best, ang;
+ triangle_t *nt;
+
+ if (e->tri)
+ return; // allready connected by someone
+
+ // find the point with the best angle
+ p0 = trian->points[e->p0]->origin;
+ p1 = trian->points[e->p1]->origin;
+ best = 1.1;
+ for (i=0 ; i< trian->numpoints ; i++)
+ {
+ p = trian->points[i]->origin;
+ // a 0 dist will form a degenerate triangle
+ if (DotProduct(p, e->normal) - e->dist < 0)
+ continue; // behind edge
+ VectorSubtract (p0, p, v1);
+ VectorSubtract (p1, p, v2);
+ if (!VectorNormalize (v1,v1))
+ continue;
+ if (!VectorNormalize (v2,v2))
+ continue;
+ ang = DotProduct (v1, v2);
+ if (ang < best)
+ {
+ best = ang;
+ bestp = i;
+ }
+ }
+ if (best >= 1)
+ return; // edge doesn't match anything
+
+ // make a new triangle
+ nt = AllocTriangle (trian);
+ nt->edges[0] = e;
+ nt->edges[1] = FindEdge (trian, e->p1, bestp);
+ nt->edges[2] = FindEdge (trian, bestp, e->p0);
+ for (i=0 ; i<3 ; i++)
+ nt->edges[i]->tri = nt;
+ TriEdge_r (trian, FindEdge (trian, bestp, e->p1));
+ TriEdge_r (trian, FindEdge (trian, e->p0, bestp));
+}
+
+/*
+============
+TriangulatePoints
+============
+*/
+void TriangulatePoints (triangulation_t *trian)
+{
+ vec_t d, bestd;
+ vec3_t v1;
+ int bp1, bp2, i, j;
+ vec_t *p1, *p2;
+ triedge_t *e, *e2;
+
+ if (trian->numpoints < 2)
+ return;
+
+ // find the two closest points
+ bestd = 9999;
+ for (i=0 ; i<trian->numpoints ; i++)
+ {
+ p1 = trian->points[i]->origin;
+ for (j=i+1 ; j<trian->numpoints ; j++)
+ {
+ p2 = trian->points[j]->origin;
+ VectorSubtract (p2, p1, v1);
+ d = VectorLength (v1);
+ if (d < bestd)
+ {
+ bestd = d;
+ bp1 = i;
+ bp2 = j;
+ }
+ }
+ }
+
+ e = FindEdge (trian, bp1, bp2);
+ e2 = FindEdge (trian, bp2, bp1);
+ TriEdge_r (trian, e);
+ TriEdge_r (trian, e2);
+}
+
+/*
+===============
+AddPointToTriangulation
+===============
+*/
+void AddPointToTriangulation (patch_t *patch, triangulation_t *trian)
+{
+ int pnum;
+
+ pnum = trian->numpoints;
+ if (pnum == MAX_TRI_POINTS)
+ Error ("trian->numpoints == MAX_TRI_POINTS");
+ trian->points[pnum] = patch;
+ trian->numpoints++;
+}
+
+/*
+===============
+LerpTriangle
+===============
+*/
+void LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color)
+{
+ patch_t *p1, *p2, *p3;
+ vec3_t base, d1, d2;
+ float x, y, x1, y1, x2, y2;
+
+ p1 = trian->points[t->edges[0]->p0];
+ p2 = trian->points[t->edges[1]->p0];
+ p3 = trian->points[t->edges[2]->p0];
+
+ VectorCopy (p1->totallight, base);
+ VectorSubtract (p2->totallight, base, d1);
+ VectorSubtract (p3->totallight, base, d2);
+
+ x = DotProduct (point, t->edges[0]->normal) - t->edges[0]->dist;
+ y = DotProduct (point, t->edges[2]->normal) - t->edges[2]->dist;
+
+ x1 = 0;
+ y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist;
+
+ x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist;
+ y2 = 0;
+
+ if (fabs(y1)<ON_EPSILON || fabs(x2)<ON_EPSILON)
+ {
+ VectorCopy (base, color);
+ return;
+ }
+
+ VectorMA (base, x/x2, d2, color);
+ VectorMA (color, y/y1, d1, color);
+}
+
+qboolean PointInTriangle (vec3_t point, triangle_t *t)
+{
+ int i;
+ triedge_t *e;
+ vec_t d;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ e = t->edges[i];
+ d = DotProduct (e->normal, point) - e->dist;
+ if (d < 0)
+ return false; // not inside
+ }
+
+ return true;
+}
+
+/*
+===============
+SampleTriangulation
+===============
+*/
+void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color)
+{
+ triangle_t *t;
+ triedge_t *e;
+ vec_t d, best;
+ patch_t *p0, *p1;
+ vec3_t v1, v2;
+ int i, j;
+
+ if (trian->numpoints == 0)
+ {
+ VectorClear (color);
+ return;
+ }
+ if (trian->numpoints == 1)
+ {
+ VectorCopy (trian->points[0]->totallight, color);
+ return;
+ }
+
+ // search for triangles
+ for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++)
+ {
+ if (!PointInTriangle (point, t))
+ continue;
+
+ // this is it
+ LerpTriangle (trian, t, point, color);
+ return;
+ }
+
+ // search for exterior edge
+ for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++)
+ {
+ if (e->tri)
+ continue; // not an exterior edge
+
+ d = DotProduct (point, e->normal) - e->dist;
+ if (d < 0)
+ continue; // not in front of edge
+
+ p0 = trian->points[e->p0];
+ p1 = trian->points[e->p1];
+
+ VectorSubtract (p1->origin, p0->origin, v1);
+ VectorNormalize (v1, v1);
+ VectorSubtract (point, p0->origin, v2);
+ d = DotProduct (v2, v1);
+ if (d < 0)
+ continue;
+ if (d > 1)
+ continue;
+ for (i=0 ; i<3 ; i++)
+ color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]);
+ return;
+ }
+
+ // search for nearest point
+ best = 99999;
+ p1 = NULL;
+ for (j=0 ; j<trian->numpoints ; j++)
+ {
+ p0 = trian->points[j];
+ VectorSubtract (point, p0->origin, v1);
+ d = VectorLength (v1);
+ if (d < best)
+ {
+ best = d;
+ p1 = p0;
+ }
+ }
+
+ if (!p1)
+ Error ("SampleTriangulation: no points");
+
+ VectorCopy (p1->totallight, color);
+}
+
+/*
+=================================================================
+
+ LIGHTMAP SAMPLE GENERATION
+
+=================================================================
+*/
+
+
+#define SINGLEMAP (64*64*4)
+
+typedef struct
+{
+ vec_t facedist;
+ vec3_t facenormal;
+
+ int numsurfpt;
+ vec3_t surfpt[SINGLEMAP];
+
+ vec3_t modelorg; // for origined bmodels
+
+ vec3_t texorg;
+ vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]
+ vec3_t textoworld[2]; // world = texorg + s * textoworld[0]
+
+ vec_t exactmins[2], exactmaxs[2];
+
+ int texmins[2], texsize[2];
+ int surfnum;
+ dface_t *face;
+} lightinfo_t;
+
+
+/*
+================
+CalcFaceExtents
+
+Fills in s->texmins[] and s->texsize[]
+also sets exactmins[] and exactmaxs[]
+================
+*/
+void CalcFaceExtents (lightinfo_t *l)
+{
+ dface_t *s;
+ vec_t mins[2], maxs[2], val;
+ int i,j, e;
+ dvertex_t *v;
+ texinfo_t *tex;
+ vec3_t vt;
+
+ s = l->face;
+
+ mins[0] = mins[1] = 999999;
+ maxs[0] = maxs[1] = -99999;
+
+ tex = &texinfo[s->texinfo];
+
+ for (i=0 ; i<s->numedges ; i++)
+ {
+ e = dsurfedges[s->firstedge+i];
+ if (e >= 0)
+ v = dvertexes + dedges[e].v[0];
+ else
+ v = dvertexes + dedges[-e].v[1];
+
+// VectorAdd (v->point, l->modelorg, vt);
+ VectorCopy (v->point, vt);
+
+ for (j=0 ; j<2 ; j++)
+ {
+ val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3];
+ if (val < mins[j])
+ mins[j] = val;
+ if (val > maxs[j])
+ maxs[j] = val;
+ }
+ }
+
+ for (i=0 ; i<2 ; i++)
+ {
+ l->exactmins[i] = mins[i];
+ l->exactmaxs[i] = maxs[i];
+
+ mins[i] = floor(mins[i]/16);
+ maxs[i] = ceil(maxs[i]/16);
+
+ l->texmins[i] = mins[i];
+ l->texsize[i] = maxs[i] - mins[i];
+ if (l->texsize[0] * l->texsize[1] > SINGLEMAP/4) // div 4 for extrasamples
+ Error ("Surface to large to map");
+ }
+}
+
+/*
+================
+CalcFaceVectors
+
+Fills in texorg, worldtotex. and textoworld
+================
+*/
+void CalcFaceVectors (lightinfo_t *l)
+{
+ texinfo_t *tex;
+ int i, j;
+ vec3_t texnormal;
+ vec_t distscale;
+ vec_t dist, len;
+ int w, h;
+
+ tex = &texinfo[l->face->texinfo];
+
+// convert from float to double
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<3 ; j++)
+ l->worldtotex[i][j] = tex->vecs[i][j];
+
+// calculate a normal to the texture axis. points can be moved along this
+// without changing their S/T
+ texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2]
+ - tex->vecs[1][2]*tex->vecs[0][1];
+ texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0]
+ - tex->vecs[1][0]*tex->vecs[0][2];
+ texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1]
+ - tex->vecs[1][1]*tex->vecs[0][0];
+ VectorNormalize (texnormal, texnormal);
+
+// flip it towards plane normal
+ distscale = DotProduct (texnormal, l->facenormal);
+ if (!distscale)
+ {
+ Sys_FPrintf( SYS_VRB, "WARNING: Texture axis perpendicular to face\n");
+ distscale = 1;
+ }
+ if (distscale < 0)
+ {
+ distscale = -distscale;
+ VectorSubtract (vec3_origin, texnormal, texnormal);
+ }
+
+// distscale is the ratio of the distance along the texture normal to
+// the distance along the plane normal
+ distscale = 1/distscale;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ len = VectorLength (l->worldtotex[i]);
+ dist = DotProduct (l->worldtotex[i], l->facenormal);
+ dist *= distscale;
+ VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]);
+ VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]);
+ }
+
+
+// calculate texorg on the texture plane
+ for (i=0 ; i<3 ; i++)
+ l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
+
+// project back to the face plane
+ dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
+ dist *= distscale;
+ VectorMA (l->texorg, -dist, texnormal, l->texorg);
+
+ // compensate for org'd bmodels
+ VectorAdd (l->texorg, l->modelorg, l->texorg);
+
+ // total sample count
+ h = l->texsize[1]+1;
+ w = l->texsize[0]+1;
+ l->numsurfpt = w * h;
+}
+
+/*
+=================
+CalcPoints
+
+For each texture aligned grid point, back project onto the plane
+to get the world xyz value of the sample point
+=================
+*/
+void CalcPoints (lightinfo_t *l, float sofs, float tofs)
+{
+ int i;
+ int s, t, j;
+ int w, h, step;
+ vec_t starts, startt, us, ut;
+ vec_t *surf;
+ vec_t mids, midt;
+ vec3_t facemid;
+ dleaf_t *leaf;
+
+ surf = l->surfpt[0];
+ mids = (l->exactmaxs[0] + l->exactmins[0])/2;
+ midt = (l->exactmaxs[1] + l->exactmins[1])/2;
+
+ for (j=0 ; j<3 ; j++)
+ facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt;
+
+ h = l->texsize[1]+1;
+ w = l->texsize[0]+1;
+ l->numsurfpt = w * h;
+
+ starts = l->texmins[0]*16;
+ startt = l->texmins[1]*16;
+ step = 16;
+
+
+ for (t=0 ; t<h ; t++)
+ {
+ for (s=0 ; s<w ; s++, surf+=3)
+ {
+ us = starts + (s+sofs)*step;
+ ut = startt + (t+tofs)*step;
+
+
+ // if a line can be traced from surf to facemid, the point is good
+ for (i=0 ; i<6 ; i++)
+ {
+ // calculate texture point
+ for (j=0 ; j<3 ; j++)
+ surf[j] = l->texorg[j] + l->textoworld[0][j]*us
+ + l->textoworld[1][j]*ut;
+
+ leaf = Rad_PointInLeaf (surf);
+ if (leaf->contents != CONTENTS_SOLID)
+ {
+ if (!TestLine_r (0, facemid, surf))
+ break; // got it
+ }
+
+ // nudge it
+ if (i & 1)
+ {
+ if (us > mids)
+ {
+ us -= 8;
+ if (us < mids)
+ us = mids;
+ }
+ else
+ {
+ us += 8;
+ if (us > mids)
+ us = mids;
+ }
+ }
+ else
+ {
+ if (ut > midt)
+ {
+ ut -= 8;
+ if (ut < midt)
+ ut = midt;
+ }
+ else
+ {
+ ut += 8;
+ if (ut > midt)
+ ut = midt;
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+//==============================================================
+
+
+
+#define MAX_STYLES 32
+typedef struct
+{
+ int numsamples;
+ float *origins;
+ int numstyles;
+ int stylenums[MAX_STYLES];
+ float *samples[MAX_STYLES];
+} facelight_t;
+
+directlight_t *directlights[MAX_MAP_LEAFS];
+facelight_t facelight[MAX_MAP_FACES];
+int numdlights;
+
+/*
+==================
+FindTargetEntity
+==================
+*/
+entity_t *FindTargetEntity (char *target)
+{
+ int i;
+ char *n;
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ n = ValueForKey (&entities[i], "targetname");
+ if (!strcmp (n, target))
+ return &entities[i];
+ }
+
+ return NULL;
+}
+
+//#define DIRECT_LIGHT 3000
+#define DIRECT_LIGHT 3
+
+/*
+=============
+CreateDirectLights
+=============
+*/
+void CreateDirectLights (void)
+{
+ int i;
+ patch_t *p;
+ directlight_t *dl;
+ dleaf_t *leaf;
+ int cluster;
+ entity_t *e, *e2;
+ char *name;
+ char *target;
+ float angle;
+ vec3_t dest;
+ char *_color;
+ float intensity;
+
+ //
+ // surfaces
+ //
+ for (i=0, p=patches ; i< (int) num_patches ; i++, p++)
+ {
+ if (p->totallight[0] < DIRECT_LIGHT
+ && p->totallight[1] < DIRECT_LIGHT
+ && p->totallight[2] < DIRECT_LIGHT)
+ continue;
+
+ numdlights++;
+ dl = malloc(sizeof(directlight_t));
+ memset (dl, 0, sizeof(*dl));
+
+ VectorCopy (p->origin, dl->origin);
+
+ leaf = Rad_PointInLeaf (dl->origin);
+ cluster = leaf->cluster;
+ dl->next = directlights[cluster];
+ directlights[cluster] = dl;
+
+ dl->type = emit_surface;
+ VectorCopy (p->plane->normal, dl->normal);
+
+ dl->intensity = ColorNormalize (p->totallight, dl->color);
+ dl->intensity *= p->area * direct_scale;
+ VectorClear (p->totallight); // all sent now
+ }
+
+ //
+ // entities
+ //
+ for (i=0 ; i<num_entities ; i++)
+ {
+ e = &entities[i];
+ name = ValueForKey (e, "classname");
+ if (strncmp (name, "light", 5))
+ continue;
+
+ numdlights++;
+ dl = malloc(sizeof(directlight_t));
+ memset (dl, 0, sizeof(*dl));
+
+ GetVectorForKey (e, "origin", dl->origin);
+ dl->style = FloatForKey (e, "_style");
+ if (!dl->style)
+ dl->style = FloatForKey (e, "style");
+ if (dl->style < 0 || dl->style >= MAX_LSTYLES)
+ dl->style = 0;
+
+ leaf = Rad_PointInLeaf (dl->origin);
+ cluster = leaf->cluster;
+
+ dl->next = directlights[cluster];
+ directlights[cluster] = dl;
+
+ intensity = FloatForKey (e, "light");
+ if (!intensity)
+ intensity = FloatForKey (e, "_light");
+ if (!intensity)
+ intensity = 300;
+ _color = ValueForKey (e, "_color");
+ if (_color && _color[0])
+ {
+ sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
+ ColorNormalize (dl->color, dl->color);
+ }
+ else
+ dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
+ dl->intensity = intensity*entity_scale;
+ dl->type = emit_point;
+
+ target = ValueForKey (e, "target");
+
+ if (!strcmp (name, "light_spot") || target[0])
+ {
+ dl->type = emit_spotlight;
+ dl->stopdot = FloatForKey (e, "_cone");
+ if (!dl->stopdot)
+ dl->stopdot = 10;
+ dl->stopdot = cos(dl->stopdot/180*3.14159);
+ if (target[0])
+ { // point towards target
+ e2 = FindTargetEntity (target);
+ if (!e2)
+ Sys_Printf ("WARNING: light at (%i %i %i) has missing target\n",
+ (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
+ else
+ {
+ GetVectorForKey (e2, "origin", dest);
+ VectorSubtract (dest, dl->origin, dl->normal);
+ VectorNormalize (dl->normal, dl->normal);
+ }
+ }
+ else
+ { // point down angle
+ angle = FloatForKey (e, "angle");
+ if (angle == ANGLE_UP)
+ {
+ dl->normal[0] = dl->normal[1] = 0;
+ dl->normal[2] = 1;
+ }
+ else if (angle == ANGLE_DOWN)
+ {
+ dl->normal[0] = dl->normal[1] = 0;
+ dl->normal[2] = -1;
+ }
+ else
+ {
+ dl->normal[2] = 0;
+ dl->normal[0] = cos (angle/180*3.14159);
+ dl->normal[1] = sin (angle/180*3.14159);
+ }
+ }
+ }
+ }
+
+ Sys_FPrintf( SYS_VRB, "%i direct lights\n", numdlights);
+}
+
+/*
+=============
+GatherSampleLight
+
+Lightscale is the normalizer for multisampling
+=============
+*/
+void GatherSampleLight (vec3_t pos, vec3_t normal,
+ float **styletable, int offset, int mapsize, float lightscale)
+{
+ int i;
+ directlight_t *l;
+ byte pvs[(MAX_MAP_LEAFS+7)/8];
+ vec3_t delta;
+ float dot, dot2;
+ float dist;
+ float scale;
+ float *dest;
+
+ // get the PVS for the pos to limit the number of checks
+ if (!PvsForOrigin (pos, pvs))
+ {
+ return;
+ }
+
+ for (i = 0 ; i<dvis->numclusters ; i++)
+ {
+ if ( ! (pvs[ i>>3] & (1<<(i&7))) )
+ continue;
+
+ for (l=directlights[i] ; l ; l=l->next)
+ {
+ VectorSubtract (l->origin, pos, delta);
+ dist = VectorNormalize (delta, delta);
+ dot = DotProduct (delta, normal);
+ if (dot <= 0.001)
+ continue; // behind sample surface
+
+ switch (l->type)
+ {
+ case emit_point:
+ // linear falloff
+ scale = (l->intensity - dist) * dot;
+ break;
+
+ case emit_surface:
+ dot2 = -DotProduct (delta, l->normal);
+ if (dot2 <= 0.001)
+ goto skipadd; // behind light surface
+ scale = (l->intensity / (dist*dist) ) * dot * dot2;
+ break;
+
+ case emit_spotlight:
+ // linear falloff
+ dot2 = -DotProduct (delta, l->normal);
+ if (dot2 <= l->stopdot)
+ goto skipadd; // outside light cone
+ scale = (l->intensity - dist) * dot;
+ break;
+ default:
+ Error ("Bad l->type");
+ }
+
+ if (TestLine_r (0, pos, l->origin))
+ continue; // occluded
+
+ if (scale <= 0)
+ continue;
+
+ // if this style doesn't have a table yet, allocate one
+ if (!styletable[l->style])
+ {
+ styletable[l->style] = malloc (mapsize);
+ memset (styletable[l->style], 0, mapsize);
+ }
+
+ dest = styletable[l->style] + offset;
+ // add some light to it
+ VectorMA (dest, scale*lightscale, l->color, dest);
+
+skipadd: ;
+ }
+ }
+
+}
+
+/*
+=============
+AddSampleToPatch
+
+Take the sample's collected light and
+add it back into the apropriate patch
+for the radiosity pass.
+
+The sample is added to all patches that might include
+any part of it. They are counted and averaged, so it
+doesn't generate extra light.
+=============
+*/
+void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum)
+{
+ patch_t *patch;
+ vec3_t mins, maxs;
+ int i;
+
+ if (numbounce == 0)
+ return;
+ if (color[0] + color[1] + color[2] < 3)
+ return;
+
+ for (patch = face_patches[facenum] ; patch ; patch=patch->next)
+ {
+ // see if the point is in this patch (roughly)
+ WindingBounds (patch->winding, mins, maxs);
+ for (i=0 ; i<3 ; i++)
+ {
+ if (mins[i] > pos[i] + 16)
+ goto nextpatch;
+ if (maxs[i] < pos[i] - 16)
+ goto nextpatch;
+ }
+
+ // add the sample to the patch
+ patch->samples++;
+ VectorAdd (patch->samplelight, color, patch->samplelight);
+nextpatch:;
+ }
+
+}
+
+
+/*
+=============
+BuildFacelights
+=============
+*/
+float sampleofs[5][2] =
+{ {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} };
+
+
+void BuildFacelights (int facenum)
+{
+ dface_t *f;
+ lightinfo_t l[5];
+ float *styletable[MAX_LSTYLES];
+ int i, j;
+ float *spot;
+ patch_t *patch;
+ int numsamples;
+ int tablesize;
+ facelight_t *fl;
+
+ f = &dfaces[facenum];
+
+ if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )
+ return; // non-lit texture
+
+ memset (styletable,0, sizeof(styletable));
+
+ if (extrasamples)
+ numsamples = 5;
+ else
+ numsamples = 1;
+ for (i=0 ; i<numsamples ; i++)
+ {
+ memset (&l[i], 0, sizeof(l[i]));
+ l[i].surfnum = facenum;
+ l[i].face = f;
+ VectorCopy (dplanes[f->planenum].normal, l[i].facenormal);
+ l[i].facedist = dplanes[f->planenum].dist;
+ if (f->side)
+ {
+ VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal);
+ l[i].facedist = -l[i].facedist;
+ }
+
+ // get the origin offset for rotating bmodels
+ VectorCopy (face_offset[facenum], l[i].modelorg);
+
+ CalcFaceVectors (&l[i]);
+ CalcFaceExtents (&l[i]);
+ CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]);
+ }
+
+ tablesize = l[0].numsurfpt * sizeof(vec3_t);
+ styletable[0] = malloc(tablesize);
+ memset (styletable[0], 0, tablesize);
+
+ fl = &facelight[facenum];
+ fl->numsamples = l[0].numsurfpt;
+ fl->origins = malloc (tablesize);
+ memcpy (fl->origins, l[0].surfpt, tablesize);
+
+ for (i=0 ; i<l[0].numsurfpt ; i++)
+ {
+ for (j=0 ; j<numsamples ; j++)
+ {
+ GatherSampleLight (l[j].surfpt[i], l[0].facenormal, styletable,
+ i*3, tablesize, 1.0/numsamples);
+ }
+
+ // contribute the sample to one or more patches
+ AddSampleToPatch (l[0].surfpt[i], styletable[0]+i*3, facenum);
+ }
+
+ // average up the direct light on each patch for radiosity
+ for (patch = face_patches[facenum] ; patch ; patch=patch->next)
+ {
+ if (patch->samples)
+ {
+ VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight);
+ }
+ else
+ {
+// printf ("patch with no samples\n");
+ }
+ }
+
+ for (i=0 ; i<MAX_LSTYLES ; i++)
+ {
+ if (!styletable[i])
+ continue;
+ if (fl->numstyles == MAX_STYLES)
+ break;
+ fl->samples[fl->numstyles] = styletable[i];
+ fl->stylenums[fl->numstyles] = i;
+ fl->numstyles++;
+ }
+
+ // the light from DIRECT_LIGHTS is sent out, but the
+ // texture itself should still be full bright
+
+ if (face_patches[facenum]->baselight[0] >= DIRECT_LIGHT ||
+ face_patches[facenum]->baselight[1] >= DIRECT_LIGHT ||
+ face_patches[facenum]->baselight[2] >= DIRECT_LIGHT
+ )
+ {
+ spot = fl->samples[0];
+ for (i=0 ; i<l[0].numsurfpt ; i++, spot+=3)
+ {
+ VectorAdd (spot, face_patches[facenum]->baselight, spot);
+ }
+ }
+}
+
+
+/*
+=============
+FinalLightFace
+
+Add the indirect lighting on top of the direct
+lighting and save into final map format
+=============
+*/
+void FinalLightFace (int facenum)
+{
+ dface_t *f;
+ int i, j, k, st;
+ vec3_t lb;
+ patch_t *patch;
+ triangulation_t *trian;
+ facelight_t *fl;
+ float minlight;
+ float max, newmax;
+ byte *dest;
+ int pfacenum;
+ vec3_t facemins, facemaxs;
+
+ f = &dfaces[facenum];
+ fl = &facelight[facenum];
+
+ if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) )
+ return; // non-lit texture
+
+ ThreadLock ();
+ f->lightofs = lightdatasize;
+ lightdatasize += fl->numstyles*(fl->numsamples*3);
+
+// add green sentinals between lightmaps
+#if 0
+lightdatasize += 64*3;
+for (i=0 ; i<64 ; i++)
+dlightdata[lightdatasize-(i+1)*3 + 1] = 255;
+#endif
+
+ if (lightdatasize > MAX_MAP_LIGHTING)
+ Error ("MAX_MAP_LIGHTING");
+ ThreadUnlock ();
+
+ f->styles[0] = 0;
+ f->styles[1] = f->styles[2] = f->styles[3] = 0xff;
+
+ //
+ // set up the triangulation
+ //
+ if (numbounce > 0)
+ {
+ ClearBounds (facemins, facemaxs);
+ for (i=0 ; i<f->numedges ; i++)
+ {
+ int ednum;
+
+ ednum = dsurfedges[f->firstedge+i];
+ if (ednum >= 0)
+ AddPointToBounds (dvertexes[dedges[ednum].v[0]].point,
+ facemins, facemaxs);
+ else
+ AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point,
+ facemins, facemaxs);
+ }
+
+ trian = AllocTriangulation (&dplanes[f->planenum]);
+
+ // for all faces on the plane, add the nearby patches
+ // to the triangulation
+ for (pfacenum = planelinks[f->side][f->planenum]
+ ; pfacenum ; pfacenum = facelinks[pfacenum])
+ {
+ for (patch = face_patches[pfacenum] ; patch ; patch=patch->next)
+ {
+ for (i=0 ; i < 3 ; i++)
+ {
+ if (facemins[i] - patch->origin[i] > subdiv*2)
+ break;
+ if (patch->origin[i] - facemaxs[i] > subdiv*2)
+ break;
+ }
+ if (i != 3)
+ continue; // not needed for this face
+ AddPointToTriangulation (patch, trian);
+ }
+ }
+ for (i=0 ; i<trian->numpoints ; i++)
+ memset (trian->edgematrix[i], 0, trian->numpoints*sizeof(trian->edgematrix[0][0]) );
+ TriangulatePoints (trian);
+ }
+
+ //
+ // sample the triangulation
+ //
+
+ // _minlight allows models that have faces that would not be
+ // illuminated to receive a mottled light pattern instead of
+ // black
+ minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;
+
+ dest = &dlightdata[f->lightofs];
+
+ if (fl->numstyles > MAXLIGHTMAPS)
+ {
+ fl->numstyles = MAXLIGHTMAPS;
+ Sys_Printf ("face with too many lightstyles: (%f %f %f)\n",
+ face_patches[facenum]->origin[0],
+ face_patches[facenum]->origin[1],
+ face_patches[facenum]->origin[2]
+ );
+ }
+
+ for (st=0 ; st<fl->numstyles ; st++)
+ {
+ f->styles[st] = fl->stylenums[st];
+ for (j=0 ; j<fl->numsamples ; j++)
+ {
+ VectorCopy ( (fl->samples[st]+j*3), lb);
+ if (numbounce > 0 && st == 0)
+ {
+ vec3_t add;
+
+ SampleTriangulation (fl->origins + j*3, trian, add);
+ VectorAdd (lb, add, lb);
+ }
+ // add an ambient term if desired
+ lb[0] += ambient;
+ lb[1] += ambient;
+ lb[2] += ambient;
+
+ VectorScale (lb, lightscale, lb);
+
+ // we need to clamp without allowing hue to change
+ for (k=0 ; k<3 ; k++)
+ if (lb[k] < 1)
+ lb[k] = 1;
+ max = lb[0];
+ if (lb[1] > max)
+ max = lb[1];
+ if (lb[2] > max)
+ max = lb[2];
+ newmax = max;
+ if (newmax < 0)
+ newmax = 0; // roundoff problems
+ if (newmax < minlight)
+ {
+ newmax = minlight + (rand()%48);
+ }
+ if (newmax > maxlight)
+ newmax = maxlight;
+
+ for (k=0 ; k<3 ; k++)
+ {
+ *dest++ = lb[k]*newmax/max;
+ }
+ }
+ }
+
+ if (numbounce > 0)
+ FreeTriangulation (trian);
+}