if ( scale <= 0.0f ) {
scale = 1.0f;
}
+ /* globally */
+ scale *= lightmapBrightness;
/* make a local copy */
VectorScale( color, scale, sample );
/* compensate for ingame overbrighting/bitshifting */
VectorScale( sample, ( 1.0f / lightmapCompensate ), sample );
+ /* contrast */
+ if ( lightmapContrast != 1.0f ){
+ for ( i = 0; i < 3; i++ ){
+ sample[i] = lightmapContrast * ( sample[i] - 128 ) + 128;
+ if ( sample[i] < 0 ){
+ sample[i] = 0;
+ }
+ }
+ if ( ( sample[0] > 255 ) || ( sample[1] > 255 ) || ( sample[2] > 255 ) ) {
+ max = sample[0] > sample[1] ? sample[0] : sample[1];
+ max = max > sample[2] ? max : sample[2];
+ sample[0] = sample[0] * 255 / max;
+ sample[1] = sample[1] * 255 / max;
+ sample[2] = sample[2] * 255 / max;
+ }
+ }
+
/* sRGB lightmaps */
if ( lightmapsRGB ) {
sample[0] = floor( Image_sRGBFloatFromLinearFloat( sample[0] * ( 1.0 / 255.0 ) ) * 255.0 + 0.5 );
colorBytes[ 2 ] = sample[ 2 ];
}
+/*
+ * Same as ColorToBytes, but if the output color will never contain zero
+ * components. Used to avoid returning 0 0 0 due to an ioq3 issue. Reason
+ * to also map 0 0 1 to 1 1 1 is to ensure monotonicity in the color mapping
+ * to prevent banding-like artifacts on lightmaps.
+ */
+void ColorToBytesNonZero( const float *color, byte *colorBytes, float scale) {
+ int i;
+ ColorToBytes(color, colorBytes, scale);
+ for (i = 0; i < 3; ++i)
+ if (colorBytes[i] == 0)
+ colorBytes[i] = 1;
+}
/* -------------------------------------------------------------------------------
/* allocate shade angle table */
- shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
- memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
+ shadeAngles = safe_malloc0( numBSPDrawVerts * sizeof( float ) );
/* allocate smoothed table */
cs = ( numBSPDrawVerts / 8 ) + 1;
- smoothed = safe_malloc( cs );
- memset( smoothed, 0, cs );
+ smoothed = safe_malloc0( cs );
/* set default shade angle */
defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
origin2 = SUPER_ORIGIN( x, y );
//% normal2 = SUPER_NORMAL( x, y );
}
- else {
+ else{
Sys_FPrintf( SYS_WRN, "WARNING: Spurious lightmap T vector\n" );
}
}
/* set luxel filter radius */
- luxelFilterRadius = lm->sampleSize != 0 ? superSample * filterRadius / lm->sampleSize : 0;
+ luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
if ( luxelFilterRadius == 0 && ( filterRadius > 0.0f || filter ) ) {
luxelFilterRadius = 1;
}
/* allocate sampling flags storage */
- if ( ( lightSamples > 1 || lightRandomSamples ) && luxelFilterRadius == 0 ) {
+ if ( lightSamples > 1 || lightRandomSamples ) {
size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
if ( lm->superFlags == NULL ) {
lm->superFlags = safe_malloc( size );
}
/* check for evilness */
- if ( trace.forceSubsampling > 1.0f && ( lightSamples > 1 || lightRandomSamples ) && luxelFilterRadius == 0 ) {
- totalLighted++;
+ if ( trace.forceSubsampling > 1.0f && ( lightSamples > 1 || lightRandomSamples ) ) {
+ totalLighted++;
*flag |= FLAG_FORCE_SUBSAMPLING; /* force */
}
/* add to count */
/* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
/* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
- if ( ( lightSamples > 1 || lightRandomSamples ) && luxelFilterRadius == 0 ) {
+ if ( lightSamples > 1 || lightRandomSamples ) {
/* walk luxels */
for ( y = 0; y < ( lm->sh - 1 ); y++ )
{
if ( lm->superLuxels[ lightmapNum ] == NULL ) {
/* allocate sampling lightmap storage */
size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
- lm->superLuxels[ lightmapNum ] = safe_malloc( size );
- memset( lm->superLuxels[ lightmapNum ], 0, size );
+ lm->superLuxels[ lightmapNum ] = safe_malloc0( size );
}
/* set style */
int i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
int lightmapNum, numAvg;
float samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
- vec3_t origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
+ vec3_t temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
bspDrawSurface_t *ds;
surfaceInfo_t *info;
rawLightmap_t *lm;
else if ( debugOrigin ) {
VectorSubtract( info->maxs, info->mins, temp );
VectorScale( temp, ( 1.0f / 255.0f ), temp );
- VectorSubtract( origin, lm->mins, temp2 );
+ VectorSubtract( verts[ i ].xyz, info->mins, temp2 );
radVertLuxel[ 0 ] = info->mins[ 0 ] + ( temp[ 0 ] * temp2[ 0 ] );
radVertLuxel[ 1 ] = info->mins[ 1 ] + ( temp[ 1 ] * temp2[ 1 ] );
radVertLuxel[ 2 ] = info->mins[ 2 ] + ( temp[ 2 ] * temp2[ 2 ] );
radVertLuxel[ 2 ] = ( verts[ i ].normal[ 2 ] + 1.0f ) * 127.5f;
}
+ else if ( info->si->noVertexLight ) {
+ VectorSet( radVertLuxel, 127.5f, 127.5f, 127.5f );
+ }
+
+ else if ( noVertexLighting > 0 ) {
+ VectorSet( radVertLuxel, 127.5f * noVertexLighting, 127.5f * noVertexLighting, 127.5f * noVertexLighting );
+ }
+
/* illuminate the vertex */
else
{
trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + ( VERTEX_NUDGE * z1 );
/* try at nudged origin */
- trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
+ trace.cluster = ClusterForPointExtFilter( trace.origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
if ( trace.cluster < 0 ) {
continue;
}
VectorCopy( debugColors[ num % 12 ], radVertLuxel );
}
+ else if ( info->si->noVertexLight ) {
+ VectorSet( radVertLuxel, 127.5f, 127.5f, 127.5f );
+ }
+
+ else if ( noVertexLighting > 0 ) {
+ VectorSet( radVertLuxel, 127.5f * noVertexLighting, 127.5f * noVertexLighting, 127.5f * noVertexLighting );
+ }
+
/* divine color from the superluxels */
else
{
continue;
}
+ if( lm->styles[lightmapNum] != LS_NORMAL && lm->styles[lightmapNum] != LS_NONE ) // isStyleLight
+ continue;
+
/* apply floodlight to each luxel */
for ( y = 0; y < lm->sh; y++ )
{