152 lines
4.6 KiB
C++
152 lines
4.6 KiB
C++
//===== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//===========================================================================//
|
|
|
|
#include <tier0/platform.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include "bitmap/floatbitmap.h"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
static float ScaleValue( float f, float overbright )
|
|
{
|
|
// map a value between 0..255 to the scale factor
|
|
int ival = ( int )f;
|
|
return ival * ( overbright / 255.0 );
|
|
}
|
|
|
|
static float IScaleValue( float f, float overbright )
|
|
{
|
|
f *= ( 1.0 / overbright );
|
|
int ival = ( int )MIN( 255, ceil( f * 255.0 ));
|
|
return ival;
|
|
}
|
|
|
|
void MaybeSetScaleVaue( FloatBitMap_t const & orig, FloatBitMap_t & newbm, int x, int y,
|
|
float newscale, float overbright )
|
|
{
|
|
// clamp the given scale value to the legal range for that pixel and regnerate the rgb
|
|
// components.
|
|
float maxc = MAX( MAX( orig.Pixel( x, y, 0, 0 ), orig.Pixel( x, y, 0, 1 )), orig.Pixel( x, y, 0, 2 ));
|
|
if ( maxc == 0.0 )
|
|
{
|
|
// pixel is black. any scale value is fine.
|
|
newbm.Pixel( x, y, 0, 3 ) = newscale;
|
|
for( int c = 0;c < 3;c++ )
|
|
newbm.Pixel( x, y, 0, c ) = 0;
|
|
}
|
|
else
|
|
{
|
|
// float desired_floatscale=maxc;
|
|
float scale_we_will_get = ScaleValue( newscale, overbright );
|
|
// if (scale_we_will_get >= desired_floatscale )
|
|
{
|
|
newbm.Pixel( x, y, 0, 3 ) = newscale;
|
|
for( int c = 0;c < 3;c++ )
|
|
newbm.Pixel( x, y, 0, c ) = orig.Pixel( x, y, 0, c ) / ( scale_we_will_get );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FloatBitMap_t::Uncompress( float overbright )
|
|
{
|
|
for( int y = 0;y < NumRows();y++ )
|
|
for( int x = 0;x < NumCols();x++ )
|
|
{
|
|
int iactual_alpha_value = ( int )( 255.0 * Pixel( x, y, 0, 3 ) );
|
|
float actual_alpha_value = iactual_alpha_value * ( 1.0 / 255.0 );
|
|
for( int c = 0;c < 3;c++ )
|
|
{
|
|
int iactual_color_value = ( int )( 255.0 * Pixel( x, y, 0, c ) );
|
|
float actual_color_value = iactual_color_value * ( 1.0 / 255.0 );
|
|
Pixel( x, y, 0, c ) = actual_alpha_value * actual_color_value * overbright;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define GAUSSIAN_WIDTH 5
|
|
#define SQ(x) ((x)*(x))
|
|
|
|
void FloatBitMap_t::CompressTo8Bits( float overbright )
|
|
{
|
|
FloatBitMap_t TmpFBM( NumCols(), NumRows() );
|
|
// first, saturate to max overbright
|
|
for( int y = 0;y < NumRows();y++ )
|
|
for( int x = 0;x < NumCols();x++ )
|
|
for( int c = 0;c < 3;c++ )
|
|
Pixel( x, y, 0, c ) = MIN( overbright, Pixel( x, y, 0, c ));
|
|
// first pass - choose nominal scale values to convert to rgb,scale
|
|
for( int y = 0;y < NumRows();y++ )
|
|
for( int x = 0;x < NumCols();x++ )
|
|
{
|
|
// determine maximum component
|
|
float maxc = MAX( MAX( Pixel( x, y, 0, 0 ), Pixel( x, y, 0, 1 )), Pixel( x, y, 0, 2 ));
|
|
if ( maxc == 0 )
|
|
{
|
|
for( int c = 0;c < 4;c++ )
|
|
TmpFBM.Pixel( x, y, 0, c ) = 0;
|
|
}
|
|
else
|
|
{
|
|
float desired_floatscale = maxc;
|
|
float closest_iscale = IScaleValue( desired_floatscale, overbright );
|
|
float scale_value_we_got = ScaleValue( closest_iscale, overbright );
|
|
TmpFBM.Pixel( x, y, 0, 3 ) = closest_iscale;
|
|
for( int c = 0;c < 3;c++ )
|
|
TmpFBM.Pixel( x, y, 0, c ) = Pixel( x, y, 0, c ) / scale_value_we_got;
|
|
}
|
|
}
|
|
// now, refine scale values
|
|
#ifdef FILTER_TO_REDUCE_LERP_ARTIFACTS
|
|
// I haven't been able to come up with a filter which eleiminates objectionable artifacts on all
|
|
// source textures. So, I've gone to doing the lerping in the shader.
|
|
int pass = 0;
|
|
while( pass < 1 )
|
|
{
|
|
FloatBitMap_t temp_filtered( & TmpFBM );
|
|
for( int y = 0;y < NumRows();y++ )
|
|
{
|
|
for( int x = 0;x < NumCols();x++ )
|
|
{
|
|
float sum_scales = 0.0;
|
|
float sum_weights = 0.0;
|
|
for( int yofs =- GAUSSIAN_WIDTH;yofs <= GAUSSIAN_WIDTH;yofs++ )
|
|
for( int xofs =- GAUSSIAN_WIDTH;xofs <= GAUSSIAN_WIDTH;xofs++ )
|
|
{
|
|
float r = 0.456 * GAUSSIAN_WIDTH;
|
|
r = 0.26 * GAUSSIAN_WIDTH;
|
|
float x1 = xofs / r;
|
|
float y1 = yofs / r;
|
|
float a = ( SQ( x1 ) + SQ( y1 )) / ( 2.0 * SQ( r ));
|
|
float w = exp( - a );
|
|
sum_scales += w * TmpFBM.PixelClamped( x + xofs, y + yofs, 3 );
|
|
sum_weights += w;
|
|
}
|
|
int new_trial_scale = sum_scales * ( 1.0 / sum_weights );
|
|
MaybeSetScaleVaue( * this, temp_filtered, x, y, new_trial_scale, overbright );
|
|
}
|
|
}
|
|
pass++;
|
|
memcpy( TmpFBM.RGBAData, temp_filtered.RGBAData, NumCols() * NumRows() * 4 * sizeof( float ));
|
|
}
|
|
#endif
|
|
|
|
CopyAttrFrom( TmpFBM, FBM_ATTR_RED );
|
|
CopyAttrFrom( TmpFBM, FBM_ATTR_GREEN );
|
|
CopyAttrFrom( TmpFBM, FBM_ATTR_BLUE );
|
|
CopyAttrFrom( TmpFBM, FBM_ATTR_ALPHA );
|
|
|
|
// now, map scale to real value
|
|
for( int y = 0; y < NumRows(); y++ )
|
|
for( int x = 0; x < NumCols(); x++ )
|
|
Pixel( x, y, 0, 3 ) *= ( 1.0 / 255.0 );
|
|
}
|