1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
44 ydnar: moved to here 2001-02-04
47 void ColorToBytes( const float *color, byte *colorBytes, float scale )
55 /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
59 /* make a local copy */
60 VectorScale( color, scale, sample );
63 gamma = 1.0f / lightmapGamma;
64 for( i = 0; i < 3; i++ )
66 /* handle negative light */
67 if( sample[ i ] < 0.0f )
74 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
77 if (lightmapExposure == 1)
79 /* clamp with color normalization */
81 if( sample[ 1 ] > max )
83 if( sample[ 2 ] > max )
86 VectorScale( sample, (255.0f / max), sample );
90 if (lightmapExposure==0)
92 lightmapExposure=1.0f;
94 inv=1.f/lightmapExposure;
98 if( sample[ 1 ] > max )
100 if( sample[ 2 ] > max )
103 dif = (1- exp(-max * inv) ) * 255;
121 /* compensate for ingame overbrighting/bitshifting */
122 VectorScale( sample, (1.0f / lightmapCompensate), sample );
125 colorBytes[ 0 ] = sample[ 0 ];
126 colorBytes[ 1 ] = sample[ 1 ];
127 colorBytes[ 2 ] = sample[ 2 ];
132 /* -------------------------------------------------------------------------------
134 this section deals with phong shading (normal interpolation across brush faces)
136 ------------------------------------------------------------------------------- */
140 smooths together coincident vertex normals across the bsp
143 #define MAX_SAMPLES 256
144 #define THETA_EPSILON 0.000001
145 #define EQUAL_NORMAL_EPSILON 0.01
147 void SmoothNormals( void )
149 int i, j, k, f, cs, numVerts, numVotes, fOld, start;
150 float shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
151 bspDrawSurface_t *ds;
155 vec3_t average, diff;
156 int indexes[ MAX_SAMPLES ];
157 vec3_t votes[ MAX_SAMPLES ];
160 /* allocate shade angle table */
161 shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
162 memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
164 /* allocate smoothed table */
165 cs = (numBSPDrawVerts / 8) + 1;
166 smoothed = safe_malloc( cs );
167 memset( smoothed, 0, cs );
169 /* set default shade angle */
170 defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
173 /* run through every surface and flag verts belonging to non-lightmapped surfaces
174 and set per-vertex smoothing angle */
175 for( i = 0; i < numBSPDrawSurfaces; i++ )
178 ds = &bspDrawSurfaces[ i ];
180 /* get shader for shade angle */
181 si = surfaceInfos[ i ].si;
182 if( si->shadeAngleDegrees )
183 shadeAngle = DEG2RAD( si->shadeAngleDegrees );
185 shadeAngle = defaultShadeAngle;
186 if( shadeAngle > maxShadeAngle )
187 maxShadeAngle = shadeAngle;
190 for( j = 0; j < ds->numVerts; j++ )
192 f = ds->firstVert + j;
193 shadeAngles[ f ] = shadeAngle;
194 if( ds->surfaceType == MST_TRIANGLE_SOUP )
195 smoothed[ f >> 3 ] |= (1 << (f & 7));
198 /* ydnar: optional force-to-trisoup */
199 if( trisoup && ds->surfaceType == MST_PLANAR )
201 ds->surfaceType = MST_TRIANGLE_SOUP;
202 ds->lightmapNum[ 0 ] = -3;
206 /* bail if no surfaces have a shade angle */
207 if( maxShadeAngle == 0 )
216 start = I_FloatTime();
218 /* go through the list of vertexes */
219 for( i = 0; i < numBSPDrawVerts; i++ )
222 f = 10 * i / numBSPDrawVerts;
226 Sys_Printf( "%i...", f );
229 /* already smoothed? */
230 if( smoothed[ i >> 3 ] & (1 << (i & 7)) )
234 VectorClear( average );
238 /* build a table of coincident vertexes */
239 for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )
241 /* already smoothed? */
242 if( smoothed[ j >> 3 ] & (1 << (j & 7)) )
246 if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse )
249 /* use smallest shade angle */
250 shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);
252 /* check shade angle */
253 dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );
256 else if( dot < -1.0 )
258 testAngle = acos( dot ) + THETA_EPSILON;
259 if( testAngle >= shadeAngle )
261 //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
264 //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
266 /* add to the list */
267 indexes[ numVerts++ ] = j;
270 smoothed[ j >> 3 ] |= (1 << (j & 7));
272 /* see if this normal has already been voted */
273 for( k = 0; k < numVotes; k++ )
275 VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );
276 if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
277 fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
278 fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
282 /* add a new vote? */
283 if( k == numVotes && numVotes < MAX_SAMPLES )
285 VectorAdd( average, bspDrawVerts[ j ].normal, average );
286 VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );
291 /* don't average for less than 2 verts */
296 if( VectorNormalize( average, average ) > 0 )
299 for( j = 0; j < numVerts; j++ )
300 VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );
304 /* free the tables */
309 Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
314 /* -------------------------------------------------------------------------------
316 this section deals with phong shaded lightmap tracing
318 ------------------------------------------------------------------------------- */
320 /* 9th rewrite (recursive subdivision of a lightmap triangle) */
324 calculates the st tangent vectors for normalmapping
327 static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv )
334 /* calculate barycentric basis for the triangle */
335 bb = (dv[ 1 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 2 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]) - (dv[ 2 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 1 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]);
336 if( fabs( bb ) < 0.00000001f )
340 for( i = 0; i < numVerts; i++ )
342 /* calculate s tangent vector */
343 s = dv[ i ]->st[ 0 ] + 10.0f;
344 t = dv[ i ]->st[ 1 ];
345 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
346 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
347 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
349 stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
350 stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
351 stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
353 VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );
354 VectorNormalize( stv[ i ], stv[ i ] );
356 /* calculate t tangent vector */
357 s = dv[ i ]->st[ 0 ];
358 t = dv[ i ]->st[ 1 ] + 10.0f;
359 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
360 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
361 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
363 ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
364 ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
365 ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
367 VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );
368 VectorNormalize( ttv[ i ], ttv[ i ] );
371 //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
372 //% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
375 /* return to caller */
384 perterbs the normal by the shader's normalmap in tangent space
387 static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
394 VectorCopy( dv->normal, pNormal );
396 /* sample normalmap */
397 if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse )
400 /* remap sampled normal from [0,255] to [-1,-1] */
401 for( i = 0; i < 3; i++ )
402 bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f);
404 /* scale tangent vectors and add to original normal */
405 VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );
406 VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );
407 VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );
409 /* renormalize and return */
410 VectorNormalize( pNormal, pNormal );
417 maps a luxel for triangle bv at
421 #define BOGUS_NUDGE -99999.0f
423 static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
425 int i, x, y, numClusters, *clusters, pointCluster, *cluster;
426 float *luxel, *origin, *normal, d, lightmapSampleOffset;
433 vec4_t sideplane, hostplane;
438 static float nudges[][ 2 ] =
440 //%{ 0, 0 }, /* try center first */
441 { -NUDGE, 0 }, /* left */
442 { NUDGE, 0 }, /* right */
443 { 0, NUDGE }, /* up */
444 { 0, -NUDGE }, /* down */
445 { -NUDGE, NUDGE }, /* left/up */
446 { NUDGE, -NUDGE }, /* right/down */
447 { NUDGE, NUDGE }, /* right/up */
448 { -NUDGE, -NUDGE }, /* left/down */
449 { BOGUS_NUDGE, BOGUS_NUDGE }
453 /* find luxel xy coords (fixme: subtract 0.5?) */
454 x = dv->lightmap[ 0 ][ 0 ];
455 y = dv->lightmap[ 0 ][ 1 ];
458 else if( x >= lm->sw )
462 else if( y >= lm->sh )
465 /* set shader and cluster list */
469 numClusters = info->numSurfaceClusters;
470 clusters = &surfaceClusters[ info->firstSurfaceCluster ];
479 /* get luxel, origin, cluster, and normal */
480 luxel = SUPER_LUXEL( 0, x, y );
481 origin = SUPER_ORIGIN( x, y );
482 normal = SUPER_NORMAL( x, y );
483 cluster = SUPER_CLUSTER( x, y );
485 /* don't attempt to remap occluded luxels for planar surfaces */
486 if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL )
489 /* only average the normal for premapped luxels */
490 else if( (*cluster) >= 0 )
492 /* do bumpmap calculations */
494 PerturbNormal( dv, si, pNormal, stv, ttv );
496 VectorCopy( dv->normal, pNormal );
498 /* add the additional normal data */
499 VectorAdd( normal, pNormal, normal );
504 /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */
508 /* axial lightmap projection */
509 if( lm->vecs != NULL )
511 /* calculate an origin for the sample from the lightmap vectors */
512 VectorCopy( lm->origin, origin );
513 for( i = 0; i < 3; i++ )
515 /* add unless it's the axis, which is taken care of later */
516 if( i == lm->axisNum )
518 origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]);
521 /* project the origin onto the plane */
522 d = DotProduct( origin, plane ) - plane[ 3 ];
523 d /= plane[ lm->axisNum ];
524 origin[ lm->axisNum ] -= d;
527 /* non axial lightmap projection (explicit xyz) */
529 VectorCopy( dv->xyz, origin );
531 //////////////////////
532 //27's test to make sure samples stay within the triangle boundaries
533 //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
534 //2) if it does, nudge it onto the correct side.
536 if (worldverts!=NULL)
540 VectorCopy(worldverts[j],cverts[j]);
542 PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
548 //build plane using 2 edges and a normal
551 VectorCopy(cverts[next],temp);
552 VectorAdd(temp,hostplane,temp);
553 PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
555 //planetest sample point
556 e=DotProduct(origin,sideplane);
561 //VectorClear(origin);
562 //Move the sample point back inside triangle bounds
563 origin[0]-=sideplane[0]*(e+1);
564 origin[1]-=sideplane[1]*(e+1);
565 origin[2]-=sideplane[2]*(e+1);
574 ////////////////////////
576 /* planar surfaces have precalculated lightmap vectors for nudging */
577 if( lm->plane != NULL )
579 VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );
580 VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );
581 VectorCopy( lm->plane, vecs[ 2 ] );
584 /* non-planar surfaces must calculate them */
588 VectorCopy( plane, vecs[ 2 ] );
590 VectorCopy( dv->normal, vecs[ 2 ] );
591 MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );
594 /* push the origin off the surface a bit */
596 lightmapSampleOffset = si->lightmapSampleOffset;
598 lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;
599 if( lm->axisNum < 0 )
600 VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );
601 else if( vecs[ 2 ][ lm->axisNum ] < 0.0f )
602 origin[ lm->axisNum ] -= lightmapSampleOffset;
604 origin[ lm->axisNum ] += lightmapSampleOffset;
606 VectorCopy(origin,origintwo);
607 origintwo[0]+=vecs[2][0];
608 origintwo[1]+=vecs[2][1];
609 origintwo[2]+=vecs[2][2];
612 pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
614 /* another retarded hack, storing nudge count in luxel[ 1 ] */
617 /* point in solid? (except in dark mode) */
618 if( pointCluster < 0 && dark == qfalse )
620 /* nudge the the location around */
622 while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )
624 /* nudge the vector around a bit */
625 for( i = 0; i < 3; i++ )
627 /* set nudged point*/
628 nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
632 /* get pvs cluster */
633 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
634 //if( pointCluster >= 0 )
635 // VectorCopy( nudged, origin );
640 /* as a last resort, if still in solid, try drawvert origin offset by normal (except in dark mode) */
641 if( pointCluster < 0 && si != NULL && dark == qfalse )
643 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
644 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
645 //if( pointCluster >= 0 )
646 // VectorCopy( nudged, origin );
651 if( pointCluster < 0 )
653 (*cluster) = CLUSTER_OCCLUDED;
654 VectorClear( origin );
655 VectorClear( normal );
661 //% Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );
663 /* do bumpmap calculations */
665 PerturbNormal( dv, si, pNormal, stv, ttv );
667 VectorCopy( dv->normal, pNormal );
669 /* store the cluster and normal */
670 (*cluster) = pointCluster;
671 VectorCopy( pNormal, normal );
673 /* store explicit mapping pass and implicit mapping pass */
688 recursively subdivides a triangle until its edges are shorter
689 than the distance between two luxels (thanks jc :)
692 static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
694 bspDrawVert_t mid, *dv2[ 3 ];
698 /* map the vertexes */
700 MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
701 MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
702 MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
708 float *a, *b, dx, dy, dist, maxDist;
711 /* find the longest edge and split it */
714 for( i = 0; i < 3; i++ )
717 a = dv[ i ]->lightmap[ 0 ];
718 b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
721 dx = a[ 0 ] - b[ 0 ];
722 dy = a[ 1 ] - b[ 1 ];
723 dist = (dx * dx) + (dy * dy); //% sqrt( (dx * dx) + (dy * dy) );
733 /* try to early out */
734 if( max < 0 || maxDist <= subdivideThreshold ) /* ydnar: was i < 0 instead of max < 0 (?) */
738 /* split the longest edge and map it */
739 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
740 MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
742 /* push the point up a little bit to account for fp creep (fixme: revisit this) */
743 //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
745 /* recurse to first triangle */
746 VectorCopy( dv, dv2 );
748 MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
750 /* recurse to second triangle */
751 VectorCopy( dv, dv2 );
752 dv2[ (max + 1) % 3 ] = ∣
753 MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
760 seed function for MapTriangle_r()
761 requires a cw ordered triangle
764 static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial )
768 vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
769 vec3_t worldverts[ 3 ];
772 /* get plane if possible */
773 if( lm->plane != NULL )
775 VectorCopy( lm->plane, plane );
776 plane[ 3 ] = lm->plane[ 3 ];
779 /* otherwise make one from the points */
780 else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
783 /* check to see if we need to calculate texture->world tangent vectors */
784 if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) )
795 VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
796 VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
797 VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
799 /* map the vertexes */
800 MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
801 MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
802 MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
804 /* 2002-11-20: prefer axial triangle edges */
807 /* subdivide the triangle */
808 MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
812 for( i = 0; i < 3; i++ )
815 bspDrawVert_t *dv2[ 3 ];
819 a = dv[ i ]->lightmap[ 0 ];
820 b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
822 /* make degenerate triangles for mapping edges */
823 if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f )
826 dv2[ 1 ] = dv[ (i + 1) % 3 ];
827 dv2[ 2 ] = dv[ (i + 1) % 3 ];
829 /* map the degenerate triangle */
830 MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
841 recursively subdivides a quad until its edges are shorter
842 than the distance between two luxels
845 static void MapQuad_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ], vec4_t plane, vec3_t stv[ 4 ], vec3_t ttv[ 4 ] )
847 bspDrawVert_t mid[ 2 ], *dv2[ 4 ];
854 float *a, *b, dx, dy, dist, maxDist;
857 /* find the longest edge and split it */
860 for( i = 0; i < 4; i++ )
863 a = dv[ i ]->lightmap[ 0 ];
864 b = dv[ (i + 1) % 4 ]->lightmap[ 0 ];
867 dx = a[ 0 ] - b[ 0 ];
868 dy = a[ 1 ] - b[ 1 ];
869 dist = (dx * dx) + (dy * dy); //% sqrt( (dx * dx) + (dy * dy) );
879 /* try to early out */
880 if( max < 0 || maxDist <= subdivideThreshold )
884 /* we only care about even/odd edges */
887 /* split the longest edges */
888 LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] );
889 LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
891 /* map the vertexes */
892 MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
893 MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
898 /* recurse to first quad */
900 dv2[ 1 ] = &mid[ 0 ];
901 dv2[ 2 ] = &mid[ 1 ];
903 MapQuad_r( lm, info, dv2, plane, stv, ttv );
905 /* recurse to second quad */
906 dv2[ 0 ] = &mid[ 0 ];
909 dv2[ 3 ] = &mid[ 1 ];
910 MapQuad_r( lm, info, dv2, plane, stv, ttv );
916 /* recurse to first quad */
919 dv2[ 2 ] = &mid[ 0 ];
920 dv2[ 3 ] = &mid[ 1 ];
921 MapQuad_r( lm, info, dv2, plane, stv, ttv );
923 /* recurse to second quad */
924 dv2[ 0 ] = &mid[ 1 ];
925 dv2[ 1 ] = &mid[ 0 ];
928 MapQuad_r( lm, info, dv2, plane, stv, ttv );
936 seed function for MapQuad_r()
937 requires a cw ordered triangle quad
940 #define QUAD_PLANAR_EPSILON 0.5f
942 static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] )
946 vec3_t *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];
949 /* get plane if possible */
950 if( lm->plane != NULL )
952 VectorCopy( lm->plane, plane );
953 plane[ 3 ] = lm->plane[ 3 ];
956 /* otherwise make one from the points */
957 else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
960 /* 4th point must fall on the plane */
961 dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];
962 if( fabs( dist ) > QUAD_PLANAR_EPSILON )
965 /* check to see if we need to calculate texture->world tangent vectors */
966 if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) )
977 /* map the vertexes */
978 MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
979 MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
980 MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
981 MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
983 /* subdivide the quad */
984 MapQuad_r( lm, info, dv, plane, stv, ttv );
992 maps the locations, normals, and pvs clusters for a raw lightmap
995 #define VectorDivide( in, d, out ) VectorScale( in, (1.0f / (d)), out ) //% (out)[ 0 ] = (in)[ 0 ] / (d), (out)[ 1 ] = (in)[ 1 ] / (d), (out)[ 2 ] = (in)[ 2 ] / (d)
997 void MapRawLightmap( int rawLightmapNum )
999 int n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;
1000 float *luxel, *origin, *normal, samples, radius, pass;
1002 bspDrawSurface_t *ds;
1003 surfaceInfo_t *info;
1004 mesh_t src, *subdivided, *mesh;
1005 bspDrawVert_t *verts, *dv[ 4 ], fake;
1008 /* bail if this number exceeds the number of raw lightmaps */
1009 if( rawLightmapNum >= numRawLightmaps )
1013 lm = &rawLightmaps[ rawLightmapNum ];
1015 /* -----------------------------------------------------------------
1016 map referenced surfaces onto the raw lightmap
1017 ----------------------------------------------------------------- */
1019 /* walk the list of surfaces on this raw lightmap */
1020 for( n = 0; n < lm->numLightSurfaces; n++ )
1022 /* with > 1 surface per raw lightmap, clear occluded */
1025 for( y = 0; y < lm->sh; y++ )
1027 for( x = 0; x < lm->sw; x++ )
1030 cluster = SUPER_CLUSTER( x, y );
1032 *cluster = CLUSTER_UNMAPPED;
1038 num = lightSurfaces[ lm->firstLightSurface + n ];
1039 ds = &bspDrawSurfaces[ num ];
1040 info = &surfaceInfos[ num ];
1042 /* bail if no lightmap to calculate */
1043 if( info->lm != lm )
1049 /* map the surface onto the lightmap origin/cluster/normal buffers */
1050 switch( ds->surfaceType )
1054 verts = yDrawVerts + ds->firstVert;
1056 /* map the triangles */
1057 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1059 for( i = 0; i < ds->numIndexes; i += 3 )
1061 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1062 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1063 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1064 MapTriangle( lm, info, dv, mapNonAxial );
1070 /* make a mesh from the drawsurf */
1071 src.width = ds->patchWidth;
1072 src.height = ds->patchHeight;
1073 src.verts = &yDrawVerts[ ds->firstVert ];
1074 //% subdivided = SubdivideMesh( src, 8, 512 );
1075 subdivided = SubdivideMesh2( src, info->patchIterations );
1077 /* fit it to the curve and remove colinear verts on rows/columns */
1078 PutMeshOnCurve( *subdivided );
1079 mesh = RemoveLinearMeshColumnsRows( subdivided );
1080 FreeMesh( subdivided );
1083 verts = mesh->verts;
1089 Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",
1090 lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],
1091 lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],
1092 lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );
1096 /* map the mesh quads */
1099 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1101 for( y = 0; y < (mesh->height - 1); y++ )
1103 for( x = 0; x < (mesh->width - 1); x++ )
1106 pw[ 0 ] = x + (y * mesh->width);
1107 pw[ 1 ] = x + ((y + 1) * mesh->width);
1108 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1109 pw[ 3 ] = x + 1 + (y * mesh->width);
1110 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
1115 /* get drawverts and map first triangle */
1116 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1117 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1118 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1119 MapTriangle( lm, info, dv, mapNonAxial );
1121 /* get drawverts and map second triangle */
1122 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1123 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1124 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1125 MapTriangle( lm, info, dv, mapNonAxial );
1132 for( y = 0; y < (mesh->height - 1); y++ )
1134 for( x = 0; x < (mesh->width - 1); x++ )
1137 pw[ 0 ] = x + (y * mesh->width);
1138 pw[ 1 ] = x + ((y + 1) * mesh->width);
1139 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1140 pw[ 3 ] = x + 1 + (y * mesh->width);
1146 /* attempt to map quad first */
1147 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1148 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1149 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1150 dv[ 3 ] = &verts[ pw[ r + 3 ] ];
1151 if( MapQuad( lm, info, dv ) )
1154 /* get drawverts and map first triangle */
1155 MapTriangle( lm, info, dv, mapNonAxial );
1157 /* get drawverts and map second triangle */
1158 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1159 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1160 MapTriangle( lm, info, dv, mapNonAxial );
1175 /* -----------------------------------------------------------------
1176 average and clean up luxel normals
1177 ----------------------------------------------------------------- */
1179 /* walk the luxels */
1180 for( y = 0; y < lm->sh; y++ )
1182 for( x = 0; x < lm->sw; x++ )
1185 luxel = SUPER_LUXEL( 0, x, y );
1186 normal = SUPER_NORMAL( x, y );
1187 cluster = SUPER_CLUSTER( x, y );
1189 /* only look at mapped luxels */
1193 /* the normal data could be the sum of multiple samples */
1194 if( luxel[ 3 ] > 1.0f )
1195 VectorNormalize( normal, normal );
1197 /* mark this luxel as having only one normal */
1202 /* non-planar surfaces stop here */
1203 if( lm->plane == NULL )
1206 /* -----------------------------------------------------------------
1207 map occluded or unuxed luxels
1208 ----------------------------------------------------------------- */
1210 /* walk the luxels */
1211 radius = floor( superSample / 2 );
1212 radius = radius > 0 ? radius : 1.0f;
1214 for( pass = 2.0f; pass <= radius; pass += 1.0f )
1216 for( y = 0; y < lm->sh; y++ )
1218 for( x = 0; x < lm->sw; x++ )
1221 luxel = SUPER_LUXEL( 0, x, y );
1222 normal = SUPER_NORMAL( x, y );
1223 cluster = SUPER_CLUSTER( x, y );
1225 /* only look at unmapped luxels */
1226 if( *cluster != CLUSTER_UNMAPPED )
1229 /* divine a normal and origin from neighboring luxels */
1230 VectorClear( fake.xyz );
1231 VectorClear( fake.normal );
1232 fake.lightmap[ 0 ][ 0 ] = x; //% 0.0001 + x;
1233 fake.lightmap[ 0 ][ 1 ] = y; //% 0.0001 + y;
1235 for( sy = (y - 1); sy <= (y + 1); sy++ )
1237 if( sy < 0 || sy >= lm->sh )
1240 for( sx = (x - 1); sx <= (x + 1); sx++ )
1242 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1245 /* get neighboring luxel */
1246 luxel = SUPER_LUXEL( 0, sx, sy );
1247 origin = SUPER_ORIGIN( sx, sy );
1248 normal = SUPER_NORMAL( sx, sy );
1249 cluster = SUPER_CLUSTER( sx, sy );
1251 /* only consider luxels mapped in previous passes */
1252 if( *cluster < 0 || luxel[ 0 ] >= pass )
1255 /* add its distinctiveness to our own */
1256 VectorAdd( fake.xyz, origin, fake.xyz );
1257 VectorAdd( fake.normal, normal, fake.normal );
1258 samples += luxel[ 3 ];
1263 if( samples == 0.0f )
1267 VectorDivide( fake.xyz, samples, fake.xyz );
1268 //% VectorDivide( fake.normal, samples, fake.normal );
1269 if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )
1272 /* map the fake vert */
1273 MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1278 /* -----------------------------------------------------------------
1279 average and clean up luxel normals
1280 ----------------------------------------------------------------- */
1282 /* walk the luxels */
1283 for( y = 0; y < lm->sh; y++ )
1285 for( x = 0; x < lm->sw; x++ )
1288 luxel = SUPER_LUXEL( 0, x, y );
1289 normal = SUPER_NORMAL( x, y );
1290 cluster = SUPER_CLUSTER( x, y );
1292 /* only look at mapped luxels */
1296 /* the normal data could be the sum of multiple samples */
1297 if( luxel[ 3 ] > 1.0f )
1298 VectorNormalize( normal, normal );
1300 /* mark this luxel as having only one normal */
1308 for( y = 0; y < lm->sh; y++ )
1310 for( x = 0; x < lm->sw; x++ )
1315 cluster = SUPER_CLUSTER( x, y );
1316 origin = SUPER_ORIGIN( x, y );
1317 normal = SUPER_NORMAL( x, y );
1318 luxel = SUPER_LUXEL( x, y );
1323 /* check if within the bounding boxes of all surfaces referenced */
1324 ClearBounds( mins, maxs );
1325 for( n = 0; n < lm->numLightSurfaces; n++ )
1328 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
1329 TOL = info->sampleSize + 2;
1330 AddPointToBounds( info->mins, mins, maxs );
1331 AddPointToBounds( info->maxs, mins, maxs );
1332 if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&
1333 origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&
1334 origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )
1339 if( n < lm->numLightSurfaces )
1342 /* report bogus origin */
1343 Sys_Printf( "%6d [%2d,%2d] (%4d): XYZ(%+4.1f %+4.1f %+4.1f) LO(%+4.1f %+4.1f %+4.1f) HI(%+4.1f %+4.1f %+4.1f) <%3.0f>\n",
1344 rawLightmapNum, x, y, *cluster,
1345 origin[ 0 ], origin[ 1 ], origin[ 2 ],
1346 mins[ 0 ], mins[ 1 ], mins[ 2 ],
1347 maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
1358 sets up dirtmap (ambient occlusion)
1361 #define DIRT_CONE_ANGLE 88 /* degrees */
1362 #define DIRT_NUM_ANGLE_STEPS 16
1363 #define DIRT_NUM_ELEVATION_STEPS 3
1364 #define DIRT_NUM_VECTORS (DIRT_NUM_ANGLE_STEPS * DIRT_NUM_ELEVATION_STEPS)
1366 static vec3_t dirtVectors[ DIRT_NUM_VECTORS ];
1367 static int numDirtVectors = 0;
1369 void SetupDirt( void )
1372 float angle, elevation, angleStep, elevationStep;
1376 Sys_FPrintf( SYS_VRB, "--- SetupDirt ---\n" );
1378 /* calculate angular steps */
1379 angleStep = DEG2RAD( 360.0f / DIRT_NUM_ANGLE_STEPS );
1380 elevationStep = DEG2RAD( DIRT_CONE_ANGLE / DIRT_NUM_ELEVATION_STEPS );
1384 for( i = 0, angle = 0.0f; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1386 /* iterate elevation */
1387 for( j = 0, elevation = elevationStep * 0.5f; j < DIRT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1389 dirtVectors[ numDirtVectors ][ 0 ] = sin( elevation ) * cos( angle );
1390 dirtVectors[ numDirtVectors ][ 1 ] = sin( elevation ) * sin( angle );
1391 dirtVectors[ numDirtVectors ][ 2 ] = cos( elevation );
1396 /* emit some statistics */
1397 Sys_FPrintf( SYS_VRB, "%9d dirtmap vectors\n", numDirtVectors );
1403 calculates dirt value for a given sample
1406 float DirtForSample( trace_t *trace )
1409 float gatherDirt, outDirt, angle, elevation, ooDepth;
1410 vec3_t normal, worldUp, myUp, myRt, temp, direction, displacement;
1416 if( trace == NULL || trace->cluster < 0 )
1421 ooDepth = 1.0f / dirtDepth;
1422 VectorCopy( trace->normal, normal );
1424 /* check if the normal is aligned to the world-up */
1425 if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1427 if( normal[ 2 ] == 1.0f )
1429 VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1430 VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1432 else if( normal[ 2 ] == -1.0f )
1434 VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1435 VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1440 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1441 CrossProduct( normal, worldUp, myRt );
1442 VectorNormalize( myRt, myRt );
1443 CrossProduct( myRt, normal, myUp );
1444 VectorNormalize( myUp, myUp );
1447 /* 1 = random mode, 0 (well everything else) = non-random mode */
1451 for( i = 0; i < numDirtVectors; i++ )
1453 /* get random vector */
1454 angle = Random() * DEG2RAD( 360.0f );
1455 elevation = Random() * DEG2RAD( DIRT_CONE_ANGLE );
1456 temp[ 0 ] = cos( angle ) * sin( elevation );
1457 temp[ 1 ] = sin( angle ) * sin( elevation );
1458 temp[ 2 ] = cos( elevation );
1460 /* transform into tangent space */
1461 direction[ 0 ] = myRt[ 0 ] * temp[ 0 ] + myUp[ 0 ] * temp[ 1 ] + normal[ 0 ] * temp[ 2 ];
1462 direction[ 1 ] = myRt[ 1 ] * temp[ 0 ] + myUp[ 1 ] * temp[ 1 ] + normal[ 1 ] * temp[ 2 ];
1463 direction[ 2 ] = myRt[ 2 ] * temp[ 0 ] + myUp[ 2 ] * temp[ 1 ] + normal[ 2 ] * temp[ 2 ];
1466 VectorMA( trace->origin, dirtDepth, direction, trace->end );
1467 SetupTrace( trace );
1473 VectorSubtract( trace->hit, trace->origin, displacement );
1474 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1480 /* iterate through ordered vectors */
1481 for( i = 0; i < numDirtVectors; i++ )
1483 /* transform vector into tangent space */
1484 direction[ 0 ] = myRt[ 0 ] * dirtVectors[ i ][ 0 ] + myUp[ 0 ] * dirtVectors[ i ][ 1 ] + normal[ 0 ] * dirtVectors[ i ][ 2 ];
1485 direction[ 1 ] = myRt[ 1 ] * dirtVectors[ i ][ 0 ] + myUp[ 1 ] * dirtVectors[ i ][ 1 ] + normal[ 1 ] * dirtVectors[ i ][ 2 ];
1486 direction[ 2 ] = myRt[ 2 ] * dirtVectors[ i ][ 0 ] + myUp[ 2 ] * dirtVectors[ i ][ 1 ] + normal[ 2 ] * dirtVectors[ i ][ 2 ];
1489 VectorMA( trace->origin, dirtDepth, direction, trace->end );
1490 SetupTrace( trace );
1496 VectorSubtract( trace->hit, trace->origin, displacement );
1497 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1503 VectorMA( trace->origin, dirtDepth, normal, trace->end );
1504 SetupTrace( trace );
1510 VectorSubtract( trace->hit, trace->origin, displacement );
1511 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1515 if( gatherDirt <= 0.0f )
1518 /* apply gain (does this even do much? heh) */
1519 outDirt = pow( gatherDirt / (numDirtVectors + 1), dirtGain );
1520 if( outDirt > 1.0f )
1524 outDirt *= dirtScale;
1525 if( outDirt > 1.0f )
1528 /* return to sender */
1529 return 1.0f - outDirt;
1536 calculates dirty fraction for each luxel
1539 void DirtyRawLightmap( int rawLightmapNum )
1541 int i, x, y, sx, sy, *cluster;
1542 float *origin, *normal, *dirt, *dirt2, average, samples;
1544 surfaceInfo_t *info;
1548 /* bail if this number exceeds the number of raw lightmaps */
1549 if( rawLightmapNum >= numRawLightmaps )
1553 lm = &rawLightmaps[ rawLightmapNum ];
1556 trace.testOcclusion = qtrue;
1557 trace.forceSunlight = qfalse;
1558 trace.recvShadows = lm->recvShadows;
1559 trace.numSurfaces = lm->numLightSurfaces;
1560 trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1561 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1562 trace.testAll = qfalse;
1564 /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1565 trace.twoSided = qfalse;
1566 for( i = 0; i < trace.numSurfaces; i++ )
1569 info = &surfaceInfos[ trace.surfaces[ i ] ];
1571 /* check twosidedness */
1572 if( info->si->twoSided )
1574 trace.twoSided = qtrue;
1580 for( y = 0; y < lm->sh; y++ )
1582 for( x = 0; x < lm->sw; x++ )
1585 cluster = SUPER_CLUSTER( x, y );
1586 origin = SUPER_ORIGIN( x, y );
1587 normal = SUPER_NORMAL( x, y );
1588 dirt = SUPER_DIRT( x, y );
1590 /* set default dirt */
1593 /* only look at mapped luxels */
1598 trace.cluster = *cluster;
1599 VectorCopy( origin, trace.origin );
1600 VectorCopy( normal, trace.normal );
1603 *dirt = DirtForSample( &trace );
1607 /* testing no filtering */
1611 for( y = 0; y < lm->sh; y++ )
1613 for( x = 0; x < lm->sw; x++ )
1616 cluster = SUPER_CLUSTER( x, y );
1617 dirt = SUPER_DIRT( x, y );
1619 /* filter dirt by adjacency to unmapped luxels */
1622 for( sy = (y - 1); sy <= (y + 1); sy++ )
1624 if( sy < 0 || sy >= lm->sh )
1627 for( sx = (x - 1); sx <= (x + 1); sx++ )
1629 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1632 /* get neighboring luxel */
1633 cluster = SUPER_CLUSTER( sx, sy );
1634 dirt2 = SUPER_DIRT( sx, sy );
1635 if( *cluster < 0 || *dirt2 <= 0.0f )
1644 if( samples <= 0.0f )
1649 if( samples <= 0.0f )
1653 *dirt = average / samples;
1662 calculates the pvs cluster, origin, normal of a sub-luxel
1665 static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )
1667 int i, *cluster, *cluster2;
1668 float *origin, *origin2, *normal; //% , *normal2;
1669 vec3_t originVecs[ 2 ]; //% , normalVecs[ 2 ];
1672 /* calulate x vector */
1673 if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )
1675 cluster = SUPER_CLUSTER( x, y );
1676 origin = SUPER_ORIGIN( x, y );
1677 //% normal = SUPER_NORMAL( x, y );
1678 cluster2 = SUPER_CLUSTER( x + 1, y );
1679 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
1680 //% normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
1682 else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )
1684 cluster = SUPER_CLUSTER( x - 1, y );
1685 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
1686 //% normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
1687 cluster2 = SUPER_CLUSTER( x, y );
1688 origin2 = SUPER_ORIGIN( x, y );
1689 //% normal2 = SUPER_NORMAL( x, y );
1692 Sys_Printf( "WARNING: Spurious lightmap S vector\n" );
1694 VectorSubtract( origin2, origin, originVecs[ 0 ] );
1695 //% VectorSubtract( normal2, normal, normalVecs[ 0 ] );
1697 /* calulate y vector */
1698 if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )
1700 cluster = SUPER_CLUSTER( x, y );
1701 origin = SUPER_ORIGIN( x, y );
1702 //% normal = SUPER_NORMAL( x, y );
1703 cluster2 = SUPER_CLUSTER( x, y + 1 );
1704 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
1705 //% normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
1707 else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )
1709 cluster = SUPER_CLUSTER( x, y - 1 );
1710 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
1711 //% normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
1712 cluster2 = SUPER_CLUSTER( x, y );
1713 origin2 = SUPER_ORIGIN( x, y );
1714 //% normal2 = SUPER_NORMAL( x, y );
1717 Sys_Printf( "WARNING: Spurious lightmap T vector\n" );
1719 VectorSubtract( origin2, origin, originVecs[ 1 ] );
1720 //% VectorSubtract( normal2, normal, normalVecs[ 1 ] );
1722 /* calculate new origin */
1723 //% VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );
1724 //% VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );
1725 for( i = 0; i < 3; i++ )
1726 sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);
1729 *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );
1730 if( *sampleCluster < 0 )
1733 /* calculate new normal */
1734 //% VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );
1735 //% VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );
1736 //% if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )
1738 normal = SUPER_NORMAL( x, y );
1739 VectorCopy( normal, sampleNormal );
1747 SubsampleRawLuxel_r()
1748 recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
1751 static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel )
1753 int b, samples, mapped, lighted;
1756 vec3_t origin[ 4 ], normal[ 4 ];
1757 float biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
1758 vec3_t color, total;
1762 if( lightLuxel[ 3 ] >= lightSamples )
1766 VectorClear( total );
1770 /* make 2x2 subsample stamp */
1771 for( b = 0; b < 4; b++ )
1774 VectorCopy( sampleOrigin, origin[ b ] );
1776 /* calculate position */
1777 if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )
1784 /* increment sample count */
1785 luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
1788 trace->cluster = *cluster;
1789 VectorCopy( origin[ b ], trace->origin );
1790 VectorCopy( normal[ b ], trace->normal );
1794 LightContributionToSample( trace );
1796 /* add to totals (fixme: make contrast function) */
1797 VectorCopy( trace->color, luxel[ b ] );
1798 VectorAdd( total, trace->color, total );
1799 if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
1803 /* subsample further? */
1804 if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&
1805 (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&
1806 lighted != 0 && lighted != mapped )
1808 for( b = 0; b < 4; b++ )
1810 if( cluster[ b ] < 0 )
1812 SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] );
1817 //% VectorClear( color );
1819 VectorCopy( lightLuxel, color );
1821 for( b = 0; b < 4; b++ )
1823 if( cluster[ b ] < 0 )
1825 VectorAdd( color, luxel[ b ], color );
1833 color[ 0 ] /= samples;
1834 color[ 1 ] /= samples;
1835 color[ 2 ] /= samples;
1838 VectorCopy( color, lightLuxel );
1839 lightLuxel[ 3 ] += 1.0f;
1846 IlluminateRawLightmap()
1847 illuminates the luxels
1850 #define STACK_LL_SIZE (SUPER_LUXEL_SIZE * 64 * 64)
1851 #define LIGHT_LUXEL( x, y ) (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1853 void IlluminateRawLightmap( int rawLightmapNum )
1855 int i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum;
1856 int *cluster, *cluster2, mapped, lighted, totalLighted;
1858 surfaceInfo_t *info;
1859 qboolean filterColor, filterDir;
1861 float *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
1862 float *lightLuxels, *lightLuxel, samples, filterRadius, weight;
1863 vec3_t color, averageColor, averageDir, total, temp, temp2;
1864 float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1866 float stackLightLuxels[ STACK_LL_SIZE ];
1871 /* bail if this number exceeds the number of raw lightmaps */
1872 if( rawLightmapNum >= numRawLightmaps )
1876 lm = &rawLightmaps[ rawLightmapNum ];
1879 trace.testOcclusion = !noTrace;
1880 trace.forceSunlight = qfalse;
1881 trace.recvShadows = lm->recvShadows;
1882 trace.numSurfaces = lm->numLightSurfaces;
1883 trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1884 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1886 /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1887 trace.twoSided = qfalse;
1888 for( i = 0; i < trace.numSurfaces; i++ )
1891 info = &surfaceInfos[ trace.surfaces[ i ] ];
1893 /* check twosidedness */
1894 if( info->si->twoSided )
1896 trace.twoSided = qtrue;
1901 /* create a culled light list for this raw lightmap */
1902 CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
1904 /* -----------------------------------------------------------------
1906 ----------------------------------------------------------------- */
1909 numLuxelsIlluminated += (lm->sw * lm->sh);
1911 /* test debugging state */
1912 if( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap )
1914 /* debug fill the luxels */
1915 for( y = 0; y < lm->sh; y++ )
1917 for( x = 0; x < lm->sw; x++ )
1920 cluster = SUPER_CLUSTER( x, y );
1922 /* only fill mapped luxels */
1926 /* get particulars */
1927 luxel = SUPER_LUXEL( 0, x, y );
1928 origin = SUPER_ORIGIN( x, y );
1929 normal = SUPER_NORMAL( x, y );
1931 /* color the luxel with raw lightmap num? */
1933 VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
1935 /* color the luxel with lightmap axis? */
1936 else if( debugAxis )
1938 luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
1939 luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
1940 luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
1943 /* color the luxel with luxel cluster? */
1944 else if( debugCluster )
1945 VectorCopy( debugColors[ *cluster % 12 ], luxel );
1947 /* color the luxel with luxel origin? */
1948 else if( debugOrigin )
1950 VectorSubtract( lm->maxs, lm->mins, temp );
1951 VectorScale( temp, (1.0f / 255.0f), temp );
1952 VectorSubtract( origin, lm->mins, temp2 );
1953 luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
1954 luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
1955 luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
1958 /* color the luxel with the normal */
1959 else if( normalmap )
1961 luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
1962 luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
1963 luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
1966 /* otherwise clear it */
1968 VectorClear( luxel );
1977 /* allocate temporary per-light luxel storage */
1978 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
1979 if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
1980 lightLuxels = stackLightLuxels;
1982 lightLuxels = safe_malloc( llSize );
1985 //% memset( lm->superLuxels[ 0 ], 0, llSize );
1987 /* set ambient color */
1988 for( y = 0; y < lm->sh; y++ )
1990 for( x = 0; x < lm->sw; x++ )
1993 cluster = SUPER_CLUSTER( x, y );
1994 luxel = SUPER_LUXEL( 0, x, y );
1995 normal = SUPER_NORMAL( x, y );
1996 deluxel = SUPER_DELUXEL( x, y );
1998 /* blacken unmapped clusters */
2000 VectorClear( luxel );
2005 VectorCopy( ambientColor, luxel );
2007 VectorScale( normal, 0.00390625f, deluxel );
2013 /* clear styled lightmaps */
2014 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2015 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2017 if( lm->superLuxels[ lightmapNum ] != NULL )
2018 memset( lm->superLuxels[ lightmapNum ], 0, size );
2021 /* debugging code */
2022 //% if( trace.numLights <= 0 )
2023 //% Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2025 /* walk light list */
2026 for( i = 0; i < trace.numLights; i++ )
2029 trace.light = trace.lights[ i ];
2032 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2034 if( lm->styles[ lightmapNum ] == trace.light->style ||
2035 lm->styles[ lightmapNum ] == LS_NONE )
2039 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2040 if( lightmapNum >= MAX_LIGHTMAPS )
2042 Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2047 memset( lightLuxels, 0, llSize );
2050 /* initial pass, one sample per luxel */
2051 for( y = 0; y < lm->sh; y++ )
2053 for( x = 0; x < lm->sw; x++ )
2056 cluster = SUPER_CLUSTER( x, y );
2060 /* get particulars */
2061 lightLuxel = LIGHT_LUXEL( x, y );
2062 deluxel = SUPER_DELUXEL( x, y );
2063 origin = SUPER_ORIGIN( x, y );
2064 normal = SUPER_NORMAL( x, y );
2066 ////////// 27's temp hack for testing edge clipping ////
2067 if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2069 lightLuxel[ 1 ] = 255;
2070 lightLuxel[ 3 ] = 1.0f;
2075 /* set contribution count */
2076 lightLuxel[ 3 ] = 1.0f;
2079 trace.cluster = *cluster;
2080 VectorCopy( origin, trace.origin );
2081 VectorCopy( normal, trace.normal );
2083 /* get light for this sample */
2084 LightContributionToSample( &trace );
2085 VectorCopy( trace.color, lightLuxel );
2088 if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2092 /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2095 /* color to grayscale (photoshop rgb weighting) */
2096 brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f;
2097 brightness *= (1.0 / 255.0);
2098 VectorScale( trace.direction, brightness, trace.direction );
2099 VectorAdd( deluxel, trace.direction, deluxel );
2104 /* don't even bother with everything else if nothing was lit */
2105 if( totalLighted == 0 )
2108 /* determine filter radius */
2109 filterRadius = lm->filterRadius > trace.light->filterRadius
2111 : trace.light->filterRadius;
2112 if( filterRadius < 0.0f )
2113 filterRadius = 0.0f;
2115 /* set luxel filter radius */
2116 luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
2117 if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
2118 luxelFilterRadius = 1;
2120 /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2121 /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2122 if( lightSamples > 1 && luxelFilterRadius == 0 )
2125 for( y = 0; y < (lm->sh - 1); y++ )
2127 for( x = 0; x < (lm->sw - 1); x++ )
2132 VectorClear( total );
2134 /* test 2x2 stamp */
2135 for( t = 0; t < 4; t++ )
2137 /* set sample coords */
2138 sx = x + tests[ t ][ 0 ];
2139 sy = y + tests[ t ][ 1 ];
2142 cluster = SUPER_CLUSTER( sx, sy );
2148 lightLuxel = LIGHT_LUXEL( sx, sy );
2149 VectorAdd( total, lightLuxel, total );
2150 if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
2154 /* if total color is under a certain amount, then don't bother subsampling */
2155 if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
2158 /* if all 4 pixels are either in shadow or light, then don't subsample */
2159 if( lighted != 0 && lighted != mapped )
2161 for( t = 0; t < 4; t++ )
2163 /* set sample coords */
2164 sx = x + tests[ t ][ 0 ];
2165 sy = y + tests[ t ][ 1 ];
2168 cluster = SUPER_CLUSTER( sx, sy );
2171 lightLuxel = LIGHT_LUXEL( sx, sy );
2172 origin = SUPER_ORIGIN( sx, sy );
2174 /* only subsample shadowed luxels */
2175 //% if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2179 SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel );
2181 /* debug code to colorize subsampled areas to yellow */
2182 //% luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2183 //% VectorSet( luxel, 255, 204, 0 );
2190 /* tertiary pass, apply dirt map (ambient occlusion) */
2194 for( y = 0; y < lm->sh; y++ )
2196 for( x = 0; x < lm->sw; x++ )
2199 cluster = SUPER_CLUSTER( x, y );
2203 /* get particulars */
2204 lightLuxel = LIGHT_LUXEL( x, y );
2205 dirt = SUPER_DIRT( x, y );
2207 /* scale light value */
2208 VectorScale( lightLuxel, *dirt, lightLuxel );
2213 /* allocate sampling lightmap storage */
2214 if( lm->superLuxels[ lightmapNum ] == NULL )
2216 /* allocate sampling lightmap storage */
2217 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2218 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2219 memset( lm->superLuxels[ lightmapNum ], 0, size );
2223 if( lightmapNum > 0 )
2225 lm->styles[ lightmapNum ] = trace.light->style;
2226 //% Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2229 /* copy to permanent luxels */
2230 for( y = 0; y < lm->sh; y++ )
2232 for( x = 0; x < lm->sw; x++ )
2234 /* get cluster and origin */
2235 cluster = SUPER_CLUSTER( x, y );
2238 origin = SUPER_ORIGIN( x, y );
2241 if( luxelFilterRadius )
2244 VectorClear( averageColor );
2247 /* cheaper distance-based filtering */
2248 for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
2250 if( sy < 0 || sy >= lm->sh )
2253 for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
2255 if( sx < 0 || sx >= lm->sw )
2258 /* get particulars */
2259 cluster = SUPER_CLUSTER( sx, sy );
2262 lightLuxel = LIGHT_LUXEL( sx, sy );
2265 weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
2266 weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
2268 /* scale luxel by filter weight */
2269 VectorScale( lightLuxel, weight, color );
2270 VectorAdd( averageColor, color, averageColor );
2276 if( samples <= 0.0f )
2279 /* scale into luxel */
2280 luxel = SUPER_LUXEL( lightmapNum, x, y );
2283 /* handle negative light */
2284 if( trace.light->flags & LIGHT_NEGATIVE )
2286 luxel[ 0 ] -= averageColor[ 0 ] / samples;
2287 luxel[ 1 ] -= averageColor[ 1 ] / samples;
2288 luxel[ 2 ] -= averageColor[ 2 ] / samples;
2291 /* handle normal light */
2294 luxel[ 0 ] += averageColor[ 0 ] / samples;
2295 luxel[ 1 ] += averageColor[ 1 ] / samples;
2296 luxel[ 2 ] += averageColor[ 2 ] / samples;
2303 /* get particulars */
2304 lightLuxel = LIGHT_LUXEL( x, y );
2305 luxel = SUPER_LUXEL( lightmapNum, x, y );
2307 /* handle negative light */
2308 if( trace.light->flags & LIGHT_NEGATIVE )
2309 VectorScale( averageColor, -1.0f, averageColor );
2314 /* handle negative light */
2315 if( trace.light->flags & LIGHT_NEGATIVE )
2316 VectorSubtract( luxel, lightLuxel, luxel );
2318 /* handle normal light */
2320 VectorAdd( luxel, lightLuxel, luxel );
2326 /* free temporary luxels */
2327 if( lightLuxels != stackLightLuxels )
2328 free( lightLuxels );
2331 /* free light list */
2332 FreeTraceLights( &trace );
2334 /* -----------------------------------------------------------------
2336 ----------------------------------------------------------------- */
2340 /* walk lightmaps */
2341 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2344 if( lm->superLuxels[ lightmapNum ] == NULL )
2347 /* apply floodlight to each luxel */
2348 for( y = 0; y < lm->sh; y++ )
2350 for( x = 0; x < lm->sw; x++ )
2353 cluster = SUPER_CLUSTER( x, y );
2354 //% if( *cluster < 0 )
2357 /* get particulars */
2358 luxel = SUPER_LUXEL( lightmapNum, x, y );
2359 floodlight = SUPER_FLOODLIGHT( x, y );
2361 flood[0]=floodlightRGB[0]*floodlightIntensity;
2362 flood[1]=floodlightRGB[1]*floodlightIntensity;
2363 flood[2]=floodlightRGB[2]*floodlightIntensity;
2365 /* scale light value */
2366 VectorScale( flood, *floodlight, flood );
2371 if (luxel[3]==0) luxel[3]=1;
2379 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2382 if( lm->superLuxels[ lightmapNum ] == NULL )
2385 for( y = 0; y < lm->sh; y++ )
2387 for( x = 0; x < lm->sw; x++ )
2390 cluster = SUPER_CLUSTER( x, y );
2391 //% if( *cluster < 0 )
2394 /* get particulars */
2395 luxel = SUPER_LUXEL( lightmapNum, x, y );
2396 normal = SUPER_NORMAL ( x, y );
2398 luxel[0]=(normal[0]*127)+127;
2399 luxel[1]=(normal[1]*127)+127;
2400 luxel[2]=(normal[2]*127)+127;
2406 /* -----------------------------------------------------------------
2408 ----------------------------------------------------------------- */
2412 /* walk lightmaps */
2413 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2416 if( lm->superLuxels[ lightmapNum ] == NULL )
2419 /* apply dirt to each luxel */
2420 for( y = 0; y < lm->sh; y++ )
2422 for( x = 0; x < lm->sw; x++ )
2425 cluster = SUPER_CLUSTER( x, y );
2426 //% if( *cluster < 0 )
2429 /* get particulars */
2430 luxel = SUPER_LUXEL( lightmapNum, x, y );
2431 dirt = SUPER_DIRT( x, y );
2434 VectorScale( luxel, *dirt, luxel );
2438 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2444 /* -----------------------------------------------------------------
2446 ----------------------------------------------------------------- */
2448 /* walk lightmaps */
2449 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2452 if( lm->superLuxels[ lightmapNum ] == NULL )
2455 /* average occluded luxels from neighbors */
2456 for( y = 0; y < lm->sh; y++ )
2458 for( x = 0; x < lm->sw; x++ )
2460 /* get particulars */
2461 cluster = SUPER_CLUSTER( x, y );
2462 luxel = SUPER_LUXEL( lightmapNum, x, y );
2463 deluxel = SUPER_DELUXEL( x, y );
2464 normal = SUPER_NORMAL( x, y );
2466 /* determine if filtering is necessary */
2467 filterColor = qfalse;
2470 (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
2471 filterColor = qtrue;
2472 if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
2475 if( !filterColor && !filterDir )
2478 /* choose seed amount */
2479 VectorClear( averageColor );
2480 VectorClear( averageDir );
2483 /* walk 3x3 matrix */
2484 for( sy = (y - 1); sy <= (y + 1); sy++ )
2486 if( sy < 0 || sy >= lm->sh )
2489 for( sx = (x - 1); sx <= (x + 1); sx++ )
2491 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
2494 /* get neighbor's particulars */
2495 cluster2 = SUPER_CLUSTER( sx, sy );
2496 luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
2497 deluxel2 = SUPER_DELUXEL( sx, sy );
2499 /* ignore unmapped/unlit luxels */
2500 if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
2501 (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )
2504 /* add its distinctiveness to our own */
2505 VectorAdd( averageColor, luxel2, averageColor );
2506 samples += luxel2[ 3 ];
2508 VectorAdd( averageDir, deluxel2, averageDir );
2513 if( samples <= 0.0f )
2516 /* dark lightmap seams */
2519 if( lightmapNum == 0 )
2520 VectorMA( averageColor, 2.0f, ambientColor, averageColor );
2527 VectorDivide( averageColor, samples, luxel );
2531 VectorDivide( averageDir, samples, deluxel );
2533 /* set cluster to -3 */
2535 *cluster = CLUSTER_FLOODED;
2544 IlluminateVertexes()
2545 light the surface vertexes
2548 #define VERTEX_NUDGE 4.0f
2550 void IlluminateVertexes( int num )
2552 int i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
2553 int lightmapNum, numAvg;
2554 float samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
2555 vec3_t origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
2556 bspDrawSurface_t *ds;
2557 surfaceInfo_t *info;
2559 bspDrawVert_t *verts;
2563 /* get surface, info, and raw lightmap */
2564 ds = &bspDrawSurfaces[ num ];
2565 info = &surfaceInfos[ num ];
2568 /* -----------------------------------------------------------------
2569 illuminate the vertexes
2570 ----------------------------------------------------------------- */
2572 /* calculate vertex lighting for surfaces without lightmaps */
2573 if( lm == NULL || cpmaHack )
2576 trace.testOcclusion = (cpmaHack && lm != NULL) ? qfalse : !noTrace;
2577 trace.forceSunlight = info->si->forceSunlight;
2578 trace.recvShadows = info->recvShadows;
2579 trace.numSurfaces = 1;
2580 trace.surfaces = #
2581 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2583 /* twosided lighting */
2584 trace.twoSided = info->si->twoSided;
2586 /* make light list for this surface */
2587 CreateTraceLightsForSurface( num, &trace );
2590 verts = yDrawVerts + ds->firstVert;
2592 memset( avgColors, 0, sizeof( avgColors ) );
2594 /* walk the surface verts */
2595 for( i = 0; i < ds->numVerts; i++ )
2597 /* get vertex luxel */
2598 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2600 /* color the luxel with raw lightmap num? */
2602 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
2604 /* color the luxel with luxel origin? */
2605 else if( debugOrigin )
2607 VectorSubtract( info->maxs, info->mins, temp );
2608 VectorScale( temp, (1.0f / 255.0f), temp );
2609 VectorSubtract( origin, lm->mins, temp2 );
2610 radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2611 radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2612 radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);