csgo-2018-source/bitmap/floatbitmap2.cpp

152 lines
4.6 KiB
C++
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//===== Copyright <20> 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 );
}