You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.9 KiB
144 lines
3.9 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//===========================================================================// |
|
|
|
#include <tier0/platform.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <math.h> |
|
#include <stdlib.h> |
|
#include "bitmap/float_bm.h" |
|
|
|
|
|
static float ScaleValue(float f, float overbright) |
|
{ |
|
// map a value between 0..255 to the scale factor |
|
int ival=f; |
|
return ival*(overbright/255.0); |
|
} |
|
|
|
static float IScaleValue(float f, float overbright) |
|
{ |
|
f*=(1.0/overbright); |
|
int ival=min(255,(int)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),orig.Pixel(x,y,1)),orig.Pixel(x,y,2)); |
|
if (maxc==0.0) |
|
{ |
|
// pixel is black. any scale value is fine. |
|
newbm.Pixel(x,y,3)=newscale; |
|
for(int c=0;c<3;c++) |
|
newbm.Pixel(x,y,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,3)=newscale; |
|
for(int c=0;c<3;c++) |
|
newbm.Pixel(x,y,c)=orig.Pixel(x,y,c)/(scale_we_will_get); |
|
} |
|
} |
|
} |
|
|
|
|
|
void FloatBitMap_t::Uncompress(float overbright) |
|
{ |
|
for(int y=0;y<Height;y++) |
|
for(int x=0;x<Width;x++) |
|
{ |
|
int iactual_alpha_value=255.0*Pixel(x,y,3); |
|
float actual_alpha_value=iactual_alpha_value*(1.0/255.0); |
|
for(int c=0;c<3;c++) |
|
{ |
|
int iactual_color_value=255.0*Pixel(x,y,c); |
|
float actual_color_value=iactual_color_value*(1.0/255.0); |
|
Pixel(x,y,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(Width,Height); |
|
// first, saturate to max overbright |
|
for(int y=0;y<Height;y++) |
|
for(int x=0;x<Width;x++) |
|
for(int c=0;c<3;c++) |
|
Pixel(x,y,c)=min(overbright,Pixel(x,y,c)); |
|
// first pass - choose nominal scale values to convert to rgb,scale |
|
for(int y=0;y<Height;y++) |
|
for(int x=0;x<Width;x++) |
|
{ |
|
// determine maximum component |
|
float maxc=max(max(Pixel(x,y,0),Pixel(x,y,1)),Pixel(x,y,2)); |
|
if (maxc==0) |
|
{ |
|
for(int c=0;c<4;c++) |
|
TmpFBM.Pixel(x,y,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,3)=closest_iscale; |
|
for(int c=0;c<3;c++) |
|
TmpFBM.Pixel(x,y,c)=Pixel(x,y,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<Height;y++) |
|
{ |
|
for(int x=0;x<Width;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,Width*Height*4*sizeof(float)); |
|
} |
|
#endif |
|
|
|
memcpy(RGBAData,TmpFBM.RGBAData,Width*Height*4*sizeof(float)); |
|
// now, map scale to real value |
|
for(int y=0;y<Height;y++) |
|
for(int x=0;x<Width;x++) |
|
Pixel(x,y,3)*=(1.0/255.0); |
|
}
|
|
|