2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #define MAX_LSTYLES 256
31 edgeshare_t edgeshare[MAX_MAP_EDGES];
33 int facelinks[MAX_MAP_FACES];
34 int planelinks[2][MAX_MAP_PLANES];
41 void LinkPlaneFaces( void ){
46 for ( i = 0 ; i < numfaces ; i++, f++ )
48 facelinks[i] = planelinks[f->side][f->planenum];
49 planelinks[f->side][f->planenum] = i;
58 void PairEdges( void ){
64 for ( i = 0 ; i < numfaces ; i++, f++ )
66 for ( j = 0 ; j < f->numedges ; j++ )
68 k = dsurfedges[f->firstedge + j];
79 if ( e->faces[0] && e->faces[1] ) {
80 // determine if coplanar
81 if ( e->faces[0]->planenum == e->faces[1]->planenum ) {
90 =================================================================
94 =================================================================
97 typedef struct triedge_s
102 struct triangle_s *tri;
105 typedef struct triangle_s
110 #define MAX_TRI_POINTS 1024
111 #define MAX_TRI_EDGES ( MAX_TRI_POINTS * 6 )
112 #define MAX_TRI_TRIS ( MAX_TRI_POINTS * 2 )
120 triedge_t *edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS];
121 patch_t *points[MAX_TRI_POINTS];
122 triedge_t edges[MAX_TRI_EDGES];
123 triangle_t tris[MAX_TRI_TRIS];
131 triangulation_t *AllocTriangulation( dplane_t *plane ){
134 t = malloc( sizeof( triangulation_t ) );
141 // memset (t->edgematrix, 0, sizeof(t->edgematrix));
151 void FreeTriangulation( triangulation_t *tr ){
156 triedge_t *FindEdge( triangulation_t *trian, int p0, int p1 ){
162 if ( trian->edgematrix[p0][p1] ) {
163 return trian->edgematrix[p0][p1];
166 if ( trian->numedges > MAX_TRI_EDGES - 2 ) {
167 Error( "trian->numedges > MAX_TRI_EDGES-2" );
170 VectorSubtract( trian->points[p1]->origin, trian->points[p0]->origin, v1 );
171 VectorNormalize( v1, v1 );
172 CrossProduct( v1, trian->plane->normal, normal );
173 dist = DotProduct( trian->points[p0]->origin, normal );
175 e = &trian->edges[trian->numedges];
179 VectorCopy( normal, e->normal );
182 trian->edgematrix[p0][p1] = e;
184 be = &trian->edges[trian->numedges];
188 VectorSubtract( vec3_origin, normal, be->normal );
191 trian->edgematrix[p1][p0] = be;
196 triangle_t *AllocTriangle( triangulation_t *trian ){
199 if ( trian->numtris >= MAX_TRI_TRIS ) {
200 Error( "trian->numtris >= MAX_TRI_TRIS" );
203 t = &trian->tris[trian->numtris];
214 void TriEdge_r( triangulation_t *trian, triedge_t *e ){
222 return; // allready connected by someone
225 // find the point with the best angle
226 p0 = trian->points[e->p0]->origin;
227 p1 = trian->points[e->p1]->origin;
229 for ( i = 0 ; i < trian->numpoints ; i++ )
231 p = trian->points[i]->origin;
232 // a 0 dist will form a degenerate triangle
233 if ( DotProduct( p, e->normal ) - e->dist < 0 ) {
234 continue; // behind edge
236 VectorSubtract( p0, p, v1 );
237 VectorSubtract( p1, p, v2 );
238 if ( !VectorNormalize( v1,v1 ) ) {
241 if ( !VectorNormalize( v2,v2 ) ) {
244 ang = DotProduct( v1, v2 );
251 return; // edge doesn't match anything
254 // make a new triangle
255 nt = AllocTriangle( trian );
257 nt->edges[1] = FindEdge( trian, e->p1, bestp );
258 nt->edges[2] = FindEdge( trian, bestp, e->p0 );
259 for ( i = 0 ; i < 3 ; i++ )
260 nt->edges[i]->tri = nt;
261 TriEdge_r( trian, FindEdge( trian, bestp, e->p1 ) );
262 TriEdge_r( trian, FindEdge( trian, e->p0, bestp ) );
270 void TriangulatePoints( triangulation_t *trian ){
277 if ( trian->numpoints < 2 ) {
281 // find the two closest points
283 for ( i = 0 ; i < trian->numpoints ; i++ )
285 p1 = trian->points[i]->origin;
286 for ( j = i + 1 ; j < trian->numpoints ; j++ )
288 p2 = trian->points[j]->origin;
289 VectorSubtract( p2, p1, v1 );
290 d = VectorLength( v1 );
299 e = FindEdge( trian, bp1, bp2 );
300 e2 = FindEdge( trian, bp2, bp1 );
301 TriEdge_r( trian, e );
302 TriEdge_r( trian, e2 );
307 AddPointToTriangulation
310 void AddPointToTriangulation( patch_t *patch, triangulation_t *trian ){
313 pnum = trian->numpoints;
314 if ( pnum == MAX_TRI_POINTS ) {
315 Error( "trian->numpoints == MAX_TRI_POINTS" );
317 trian->points[pnum] = patch;
326 void LerpTriangle( triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color ){
327 patch_t *p1, *p2, *p3;
329 float x, y, x1, y1, x2, y2;
331 p1 = trian->points[t->edges[0]->p0];
332 p2 = trian->points[t->edges[1]->p0];
333 p3 = trian->points[t->edges[2]->p0];
335 VectorCopy( p1->totallight, base );
336 VectorSubtract( p2->totallight, base, d1 );
337 VectorSubtract( p3->totallight, base, d2 );
339 x = DotProduct( point, t->edges[0]->normal ) - t->edges[0]->dist;
340 y = DotProduct( point, t->edges[2]->normal ) - t->edges[2]->dist;
343 y1 = DotProduct( p2->origin, t->edges[2]->normal ) - t->edges[2]->dist;
345 x2 = DotProduct( p3->origin, t->edges[0]->normal ) - t->edges[0]->dist;
348 if ( fabs( y1 ) < ON_EPSILON || fabs( x2 ) < ON_EPSILON ) {
349 VectorCopy( base, color );
353 VectorMA( base, x / x2, d2, color );
354 VectorMA( color, y / y1, d1, color );
357 qboolean PointInTriangle( vec3_t point, triangle_t *t ){
362 for ( i = 0 ; i < 3 ; i++ )
365 d = DotProduct( e->normal, point ) - e->dist;
367 return false; // not inside
379 void SampleTriangulation( vec3_t point, triangulation_t *trian, vec3_t color ){
387 if ( trian->numpoints == 0 ) {
388 VectorClear( color );
391 if ( trian->numpoints == 1 ) {
392 VectorCopy( trian->points[0]->totallight, color );
396 // search for triangles
397 for ( t = trian->tris, j = 0 ; j < trian->numtris ; t++, j++ )
399 if ( !PointInTriangle( point, t ) ) {
404 LerpTriangle( trian, t, point, color );
408 // search for exterior edge
409 for ( e = trian->edges, j = 0 ; j < trian->numedges ; e++, j++ )
412 continue; // not an exterior edge
415 d = DotProduct( point, e->normal ) - e->dist;
417 continue; // not in front of edge
420 p0 = trian->points[e->p0];
421 p1 = trian->points[e->p1];
423 VectorSubtract( p1->origin, p0->origin, v1 );
424 VectorNormalize( v1, v1 );
425 VectorSubtract( point, p0->origin, v2 );
426 d = DotProduct( v2, v1 );
433 for ( i = 0 ; i < 3 ; i++ )
434 color[i] = p0->totallight[i] + d * ( p1->totallight[i] - p0->totallight[i] );
438 // search for nearest point
441 for ( j = 0 ; j < trian->numpoints ; j++ )
443 p0 = trian->points[j];
444 VectorSubtract( point, p0->origin, v1 );
445 d = VectorLength( v1 );
453 Error( "SampleTriangulation: no points" );
456 VectorCopy( p1->totallight, color );
460 =================================================================
462 LIGHTMAP SAMPLE GENERATION
464 =================================================================
468 #define SINGLEMAP ( 64 * 64 * 4 )
476 vec3_t surfpt[SINGLEMAP];
478 vec3_t modelorg; // for origined bmodels
481 vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]
482 vec3_t textoworld[2]; // world = texorg + s * textoworld[0]
484 vec_t exactmins[2], exactmaxs[2];
486 int texmins[2], texsize[2];
496 Fills in s->texmins[] and s->texsize[]
497 also sets exactmins[] and exactmaxs[]
500 void CalcFaceExtents( lightinfo_t *l ){
502 vec_t mins[2], maxs[2], val;
510 mins[0] = mins[1] = 999999;
511 maxs[0] = maxs[1] = -99999;
513 tex = &texinfo[s->texinfo];
515 for ( i = 0 ; i < s->numedges ; i++ )
517 e = dsurfedges[s->firstedge + i];
519 v = dvertexes + dedges[e].v[0];
522 v = dvertexes + dedges[-e].v[1];
525 // VectorAdd (v->point, l->modelorg, vt);
526 VectorCopy( v->point, vt );
528 for ( j = 0 ; j < 2 ; j++ )
530 val = DotProduct( vt, tex->vecs[j] ) + tex->vecs[j][3];
531 if ( val < mins[j] ) {
534 if ( val > maxs[j] ) {
540 for ( i = 0 ; i < 2 ; i++ )
542 l->exactmins[i] = mins[i];
543 l->exactmaxs[i] = maxs[i];
545 mins[i] = floor( mins[i] / 16 );
546 maxs[i] = ceil( maxs[i] / 16 );
548 l->texmins[i] = mins[i];
549 l->texsize[i] = maxs[i] - mins[i];
550 if ( l->texsize[0] * l->texsize[1] > SINGLEMAP / 4 ) { // div 4 for extrasamples
551 Error( "Surface to large to map" );
560 Fills in texorg, worldtotex. and textoworld
563 void CalcFaceVectors( lightinfo_t *l ){
571 tex = &texinfo[l->face->texinfo];
573 // convert from float to double
574 for ( i = 0 ; i < 2 ; i++ )
575 for ( j = 0 ; j < 3 ; j++ )
576 l->worldtotex[i][j] = tex->vecs[i][j];
578 // calculate a normal to the texture axis. points can be moved along this
579 // without changing their S/T
580 texnormal[0] = tex->vecs[1][1] * tex->vecs[0][2]
581 - tex->vecs[1][2] * tex->vecs[0][1];
582 texnormal[1] = tex->vecs[1][2] * tex->vecs[0][0]
583 - tex->vecs[1][0] * tex->vecs[0][2];
584 texnormal[2] = tex->vecs[1][0] * tex->vecs[0][1]
585 - tex->vecs[1][1] * tex->vecs[0][0];
586 VectorNormalize( texnormal, texnormal );
588 // flip it towards plane normal
589 distscale = DotProduct( texnormal, l->facenormal );
591 Sys_FPrintf( SYS_VRB, "WARNING: Texture axis perpendicular to face\n" );
594 if ( distscale < 0 ) {
595 distscale = -distscale;
596 VectorSubtract( vec3_origin, texnormal, texnormal );
599 // distscale is the ratio of the distance along the texture normal to
600 // the distance along the plane normal
601 distscale = 1 / distscale;
603 for ( i = 0 ; i < 2 ; i++ )
605 len = VectorLength( l->worldtotex[i] );
606 dist = DotProduct( l->worldtotex[i], l->facenormal );
608 VectorMA( l->worldtotex[i], -dist, texnormal, l->textoworld[i] );
609 VectorScale( l->textoworld[i], ( 1 / len ) * ( 1 / len ), l->textoworld[i] );
613 // calculate texorg on the texture plane
614 for ( i = 0 ; i < 3 ; i++ )
615 l->texorg[i] = -tex->vecs[0][3] * l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
617 // project back to the face plane
618 dist = DotProduct( l->texorg, l->facenormal ) - l->facedist - 1;
620 VectorMA( l->texorg, -dist, texnormal, l->texorg );
622 // compensate for org'd bmodels
623 VectorAdd( l->texorg, l->modelorg, l->texorg );
625 // total sample count
626 h = l->texsize[1] + 1;
627 w = l->texsize[0] + 1;
628 l->numsurfpt = w * h;
635 For each texture aligned grid point, back project onto the plane
636 to get the world xyz value of the sample point
639 void CalcPoints( lightinfo_t *l, float sofs, float tofs ){
643 vec_t starts, startt, us, ut;
650 mids = ( l->exactmaxs[0] + l->exactmins[0] ) / 2;
651 midt = ( l->exactmaxs[1] + l->exactmins[1] ) / 2;
653 for ( j = 0 ; j < 3 ; j++ )
654 facemid[j] = l->texorg[j] + l->textoworld[0][j] * mids + l->textoworld[1][j] * midt;
656 h = l->texsize[1] + 1;
657 w = l->texsize[0] + 1;
658 l->numsurfpt = w * h;
660 starts = l->texmins[0] * 16;
661 startt = l->texmins[1] * 16;
665 for ( t = 0 ; t < h ; t++ )
667 for ( s = 0 ; s < w ; s++, surf += 3 )
669 us = starts + ( s + sofs ) * step;
670 ut = startt + ( t + tofs ) * step;
673 // if a line can be traced from surf to facemid, the point is good
674 for ( i = 0 ; i < 6 ; i++ )
676 // calculate texture point
677 for ( j = 0 ; j < 3 ; j++ )
678 surf[j] = l->texorg[j] + l->textoworld[0][j] * us
679 + l->textoworld[1][j] * ut;
681 leaf = Rad_PointInLeaf( surf );
682 if ( leaf->contents != CONTENTS_SOLID ) {
683 if ( !TestLine_r( 0, facemid, surf ) ) {
727 //==============================================================
731 #define MAX_STYLES 32
737 int stylenums[MAX_STYLES];
738 float *samples[MAX_STYLES];
741 directlight_t *directlights[MAX_MAP_LEAFS];
742 facelight_t facelight[MAX_MAP_FACES];
750 entity_t *FindTargetEntity( char *target ){
754 for ( i = 0 ; i < num_entities ; i++ )
756 n = ValueForKey( &entities[i], "targetname" );
757 if ( !strcmp( n, target ) ) {
765 //#define DIRECT_LIGHT 3000
766 #define DIRECT_LIGHT 3
773 void CreateDirectLights( void ){
790 for ( i = 0, p = patches ; i < (int) num_patches ; i++, p++ )
792 if ( p->totallight[0] < DIRECT_LIGHT
793 && p->totallight[1] < DIRECT_LIGHT
794 && p->totallight[2] < DIRECT_LIGHT ) {
799 dl = malloc( sizeof( directlight_t ) );
800 memset( dl, 0, sizeof( *dl ) );
802 VectorCopy( p->origin, dl->origin );
804 leaf = Rad_PointInLeaf( dl->origin );
805 cluster = leaf->cluster;
806 dl->next = directlights[cluster];
807 directlights[cluster] = dl;
809 dl->type = emit_surface;
810 VectorCopy( p->plane->normal, dl->normal );
812 dl->intensity = ColorNormalize( p->totallight, dl->color );
813 dl->intensity *= p->area * direct_scale;
814 VectorClear( p->totallight ); // all sent now
820 for ( i = 0 ; i < num_entities ; i++ )
823 name = ValueForKey( e, "classname" );
824 if ( strncmp( name, "light", 5 ) ) {
829 dl = malloc( sizeof( directlight_t ) );
830 memset( dl, 0, sizeof( *dl ) );
832 GetVectorForKey( e, "origin", dl->origin );
833 dl->style = FloatForKey( e, "_style" );
835 dl->style = FloatForKey( e, "style" );
837 if ( dl->style < 0 || dl->style >= MAX_LSTYLES ) {
841 leaf = Rad_PointInLeaf( dl->origin );
842 cluster = leaf->cluster;
844 dl->next = directlights[cluster];
845 directlights[cluster] = dl;
847 intensity = FloatForKey( e, "light" );
849 intensity = FloatForKey( e, "_light" );
854 _color = ValueForKey( e, "_color" );
855 if ( _color && _color[0] ) {
856 sscanf( _color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2] );
857 ColorNormalize( dl->color, dl->color );
860 dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
862 dl->intensity = intensity * entity_scale;
863 dl->type = emit_point;
865 target = ValueForKey( e, "target" );
867 if ( !strcmp( name, "light_spot" ) || target[0] ) {
868 dl->type = emit_spotlight;
869 dl->stopdot = FloatForKey( e, "_cone" );
870 if ( !dl->stopdot ) {
873 dl->stopdot = cos( dl->stopdot / 180 * 3.14159 );
874 if ( target[0] ) { // point towards target
875 e2 = FindTargetEntity( target );
877 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
878 (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2] );
882 GetVectorForKey( e2, "origin", dest );
883 VectorSubtract( dest, dl->origin, dl->normal );
884 VectorNormalize( dl->normal, dl->normal );
888 { // point down angle
889 angle = FloatForKey( e, "angle" );
890 if ( angle == ANGLE_UP ) {
891 dl->normal[0] = dl->normal[1] = 0;
894 else if ( angle == ANGLE_DOWN ) {
895 dl->normal[0] = dl->normal[1] = 0;
901 dl->normal[0] = cos( angle / 180 * 3.14159 );
902 dl->normal[1] = sin( angle / 180 * 3.14159 );
908 Sys_FPrintf( SYS_VRB, "%i direct lights\n", numdlights );
915 Lightscale is the normalizer for multisampling
918 void GatherSampleLight( vec3_t pos, vec3_t normal,
919 float **styletable, int offset, int mapsize, float lightscale ){
922 byte pvs[( MAX_MAP_LEAFS + 7 ) / 8];
929 // get the PVS for the pos to limit the number of checks
930 if ( !PvsForOrigin( pos, pvs ) ) {
934 for ( i = 0 ; i < dvis->numclusters ; i++ )
936 if ( !( pvs[ i >> 3] & ( 1 << ( i & 7 ) ) ) ) {
940 for ( l = directlights[i] ; l ; l = l->next )
942 VectorSubtract( l->origin, pos, delta );
943 dist = VectorNormalize( delta, delta );
944 dot = DotProduct( delta, normal );
945 if ( dot <= 0.001 ) {
946 continue; // behind sample surface
953 scale = ( l->intensity - dist ) * dot;
957 dot2 = -DotProduct( delta, l->normal );
958 if ( dot2 <= 0.001 ) {
959 goto skipadd; // behind light surface
961 scale = ( l->intensity / ( dist * dist ) ) * dot * dot2;
966 dot2 = -DotProduct( delta, l->normal );
967 if ( dot2 <= l->stopdot ) {
968 goto skipadd; // outside light cone
970 scale = ( l->intensity - dist ) * dot;
973 Error( "Bad l->type" );
976 if ( TestLine_r( 0, pos, l->origin ) ) {
977 continue; // occluded
984 // if this style doesn't have a table yet, allocate one
985 if ( !styletable[l->style] ) {
986 styletable[l->style] = malloc( mapsize );
987 memset( styletable[l->style], 0, mapsize );
990 dest = styletable[l->style] + offset;
991 // add some light to it
992 VectorMA( dest, scale * lightscale, l->color, dest );
1004 Take the sample's collected light and
1005 add it back into the apropriate patch
1006 for the radiosity pass.
1008 The sample is added to all patches that might include
1009 any part of it. They are counted and averaged, so it
1010 doesn't generate extra light.
1013 void AddSampleToPatch( vec3_t pos, vec3_t color, int facenum ){
1018 if ( numbounce == 0 ) {
1021 if ( color[0] + color[1] + color[2] < 3 ) {
1025 for ( patch = face_patches[facenum] ; patch ; patch = patch->next )
1027 // see if the point is in this patch (roughly)
1028 WindingBounds( patch->winding, mins, maxs );
1029 for ( i = 0 ; i < 3 ; i++ )
1031 if ( mins[i] > pos[i] + 16 ) {
1034 if ( maxs[i] < pos[i] - 16 ) {
1039 // add the sample to the patch
1041 VectorAdd( patch->samplelight, color, patch->samplelight );
1053 float sampleofs[5][2] =
1054 { {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} };
1057 void BuildFacelights( int facenum ){
1060 float *styletable[MAX_LSTYLES];
1068 f = &dfaces[facenum];
1070 if ( texinfo[f->texinfo].flags & ( SURF_WARP | SURF_SKY ) ) {
1071 return; // non-lit texture
1074 memset( styletable,0, sizeof( styletable ) );
1076 if ( extrasamples ) {
1082 for ( i = 0 ; i < numsamples ; i++ )
1084 memset( &l[i], 0, sizeof( l[i] ) );
1085 l[i].surfnum = facenum;
1087 VectorCopy( dplanes[f->planenum].normal, l[i].facenormal );
1088 l[i].facedist = dplanes[f->planenum].dist;
1090 VectorSubtract( vec3_origin, l[i].facenormal, l[i].facenormal );
1091 l[i].facedist = -l[i].facedist;
1094 // get the origin offset for rotating bmodels
1095 VectorCopy( face_offset[facenum], l[i].modelorg );
1097 CalcFaceVectors( &l[i] );
1098 CalcFaceExtents( &l[i] );
1099 CalcPoints( &l[i], sampleofs[i][0], sampleofs[i][1] );
1102 tablesize = l[0].numsurfpt * sizeof( vec3_t );
1103 styletable[0] = malloc( tablesize );
1104 memset( styletable[0], 0, tablesize );
1106 fl = &facelight[facenum];
1107 fl->numsamples = l[0].numsurfpt;
1108 fl->origins = malloc( tablesize );
1109 memcpy( fl->origins, l[0].surfpt, tablesize );
1111 for ( i = 0 ; i < l[0].numsurfpt ; i++ )
1113 for ( j = 0 ; j < numsamples ; j++ )
1115 GatherSampleLight( l[j].surfpt[i], l[0].facenormal, styletable,
1116 i * 3, tablesize, 1.0 / numsamples );
1119 // contribute the sample to one or more patches
1120 AddSampleToPatch( l[0].surfpt[i], styletable[0] + i * 3, facenum );
1123 // average up the direct light on each patch for radiosity
1124 for ( patch = face_patches[facenum] ; patch ; patch = patch->next )
1126 if ( patch->samples ) {
1127 VectorScale( patch->samplelight, 1.0 / patch->samples, patch->samplelight );
1131 // printf ("patch with no samples\n");
1135 for ( i = 0 ; i < MAX_LSTYLES ; i++ )
1137 if ( !styletable[i] ) {
1140 if ( fl->numstyles == MAX_STYLES ) {
1143 fl->samples[fl->numstyles] = styletable[i];
1144 fl->stylenums[fl->numstyles] = i;
1148 // the light from DIRECT_LIGHTS is sent out, but the
1149 // texture itself should still be full bright
1151 if ( face_patches[facenum]->baselight[0] >= DIRECT_LIGHT ||
1152 face_patches[facenum]->baselight[1] >= DIRECT_LIGHT ||
1153 face_patches[facenum]->baselight[2] >= DIRECT_LIGHT
1155 spot = fl->samples[0];
1156 for ( i = 0 ; i < l[0].numsurfpt ; i++, spot += 3 )
1158 VectorAdd( spot, face_patches[facenum]->baselight, spot );
1168 Add the indirect lighting on top of the direct
1169 lighting and save into final map format
1172 void FinalLightFace( int facenum ){
1177 triangulation_t *trian;
1183 vec3_t facemins, facemaxs;
1185 f = &dfaces[facenum];
1186 fl = &facelight[facenum];
1188 if ( texinfo[f->texinfo].flags & ( SURF_WARP | SURF_SKY ) ) {
1189 return; // non-lit texture
1193 f->lightofs = lightdatasize;
1194 lightdatasize += fl->numstyles * ( fl->numsamples * 3 );
1196 // add green sentinals between lightmaps
1198 lightdatasize += 64 * 3;
1199 for ( i = 0 ; i < 64 ; i++ )
1200 dlightdata[lightdatasize - ( i + 1 ) * 3 + 1] = 255;
1203 if ( lightdatasize > MAX_MAP_LIGHTING ) {
1204 Error( "MAX_MAP_LIGHTING" );
1209 f->styles[1] = f->styles[2] = f->styles[3] = 0xff;
1212 // set up the triangulation
1214 if ( numbounce > 0 ) {
1215 ClearBounds( facemins, facemaxs );
1216 for ( i = 0 ; i < f->numedges ; i++ )
1220 ednum = dsurfedges[f->firstedge + i];
1222 AddPointToBounds( dvertexes[dedges[ednum].v[0]].point,
1223 facemins, facemaxs );
1226 AddPointToBounds( dvertexes[dedges[-ednum].v[1]].point,
1227 facemins, facemaxs );
1231 trian = AllocTriangulation( &dplanes[f->planenum] );
1233 // for all faces on the plane, add the nearby patches
1234 // to the triangulation
1235 for ( pfacenum = planelinks[f->side][f->planenum]
1236 ; pfacenum ; pfacenum = facelinks[pfacenum] )
1238 for ( patch = face_patches[pfacenum] ; patch ; patch = patch->next )
1240 for ( i = 0 ; i < 3 ; i++ )
1242 if ( facemins[i] - patch->origin[i] > subdiv * 2 ) {
1245 if ( patch->origin[i] - facemaxs[i] > subdiv * 2 ) {
1250 continue; // not needed for this face
1252 AddPointToTriangulation( patch, trian );
1255 for ( i = 0 ; i < trian->numpoints ; i++ )
1256 memset( trian->edgematrix[i], 0, trian->numpoints * sizeof( trian->edgematrix[0][0] ) );
1257 TriangulatePoints( trian );
1261 // sample the triangulation
1264 // _minlight allows models that have faces that would not be
1265 // illuminated to receive a mottled light pattern instead of
1267 minlight = FloatForKey( face_entity[facenum], "_minlight" ) * 128;
1269 dest = &dlightdata[f->lightofs];
1271 if ( fl->numstyles > MAXLIGHTMAPS ) {
1272 fl->numstyles = MAXLIGHTMAPS;
1273 Sys_Printf( "face with too many lightstyles: (%f %f %f)\n",
1274 face_patches[facenum]->origin[0],
1275 face_patches[facenum]->origin[1],
1276 face_patches[facenum]->origin[2]
1280 for ( st = 0 ; st < fl->numstyles ; st++ )
1282 f->styles[st] = fl->stylenums[st];
1283 for ( j = 0 ; j < fl->numsamples ; j++ )
1285 VectorCopy( ( fl->samples[st] + j * 3 ), lb );
1286 if ( numbounce > 0 && st == 0 ) {
1289 SampleTriangulation( fl->origins + j * 3, trian, add );
1290 VectorAdd( lb, add, lb );
1292 // add an ambient term if desired
1297 VectorScale( lb, lightscale, lb );
1299 // we need to clamp without allowing hue to change
1300 for ( k = 0 ; k < 3 ; k++ )
1305 if ( lb[1] > max ) {
1308 if ( lb[2] > max ) {
1313 newmax = 0; // roundoff problems
1315 if ( newmax < minlight ) {
1316 newmax = minlight + ( rand() % 48 );
1318 if ( newmax > maxlight ) {
1322 for ( k = 0 ; k < 3 ; k++ )
1324 *dest++ = lb[k] * newmax / max;
1329 if ( numbounce > 0 ) {
1330 FreeTriangulation( trian );