diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /bitmap/float_bm.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'bitmap/float_bm.cpp')
| -rw-r--r-- | bitmap/float_bm.cpp | 729 |
1 files changed, 729 insertions, 0 deletions
diff --git a/bitmap/float_bm.cpp b/bitmap/float_bm.cpp new file mode 100644 index 0000000..33ab8c1 --- /dev/null +++ b/bitmap/float_bm.cpp @@ -0,0 +1,729 @@ +//========= 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" +#include <tier2/tier2.h> +#include "bitmap/imageformat.h" +#include "bitmap/tgaloader.h" +#include "tier1/strtools.h" +#include "filesystem.h" + + +#define SQ(x) ((x)*(x)) + +// linear interpolate between 2 control points (L,R) + + +inline float LinInterp(float frac, float L, float R) +{ + return (((R-L) * frac) + L); +} + +// bilinear interpolate between 4 control points (UL,UR,LL,LR) + +inline float BiLinInterp(float Xfrac, float Yfrac, float UL, float UR, float LL, float LR) +{ + float iu = LinInterp(Xfrac, UL, UR); + float il = LinInterp(Xfrac, LL, LR); + + return( LinInterp(Yfrac, iu, il) ); +} + +FloatBitMap_t::FloatBitMap_t(int width, int height) +{ + RGBAData=0; + AllocateRGB(width,height); +} + +FloatBitMap_t::FloatBitMap_t(FloatBitMap_t const *orig) +{ + RGBAData=0; + AllocateRGB(orig->Width,orig->Height); + memcpy(RGBAData,orig->RGBAData,Width*Height*sizeof(float)*4); +} + +static char GetChar(FileHandle_t &f) +{ + char a; + g_pFullFileSystem->Read(&a,1,f); + return a; +} + +static int GetInt(FileHandle_t &f) +{ + char buf[100]; + char *bout=buf; + for(;;) + { + char c=GetChar(f); + if ((c<'0') || (c>'9')) + break; + *(bout++)=c; + } + *(bout++)=0; + return atoi(buf); + +} + +#define PFM_MAX_XSIZE 2048 + +bool FloatBitMap_t::LoadFromPFM(char const *fname) +{ + FileHandle_t f = g_pFullFileSystem->Open(fname, "rb"); + if (f) + { + if( ( GetChar(f) == 'P' ) && (GetChar(f) == 'F' ) && ( GetChar(f) == '\n' )) + { + Width=GetInt(f); + Height=GetInt(f); + + // eat crap until the next newline + while( GetChar(f) != '\n') + { + } + + // printf("file %s w=%d h=%d\n",fname,Width,Height); + AllocateRGB(Width,Height); + + for( int y = Height-1; y >= 0; y-- ) + { + float linebuffer[PFM_MAX_XSIZE*3]; + g_pFullFileSystem->Read(linebuffer,3*Width*sizeof(float),f); + for(int x=0;x<Width;x++) + { + for(int c=0;c<3;c++) + { + Pixel(x,y,c)=linebuffer[x*3+c]; + } + } + } + } + g_pFullFileSystem->Close( f ); // close file after reading + } + return (RGBAData!=0); +} + +bool FloatBitMap_t::WritePFM(char const *fname) +{ + FileHandle_t f = g_pFullFileSystem->Open(fname, "wb"); + + if ( f ) + { + g_pFullFileSystem->FPrintf(f,"PF\n%d %d\n-1.000000\n",Width,Height); + for( int y = Height-1; y >= 0; y-- ) + { + float linebuffer[PFM_MAX_XSIZE*3]; + for(int x=0;x<Width;x++) + { + for(int c=0;c<3;c++) + { + linebuffer[x*3+c]=Pixel(x,y,c); + } + } + g_pFullFileSystem->Write(linebuffer,3*Width*sizeof(float),f); + } + g_pFullFileSystem->Close(f); + + return true; + } + + return false; +} + + +float FloatBitMap_t::InterpolatedPixel(float x, float y, int comp) const +{ + int Top= floor(y); + float Yfrac= y - Top; + int Bot= min(Height-1,Top+1); + int Left= floor(x); + float Xfrac= x - Left; + int Right= min(Width-1,Left+1); + return + BiLinInterp(Xfrac, Yfrac, + Pixel(Left, Top, comp), + Pixel(Right, Top, comp), + Pixel(Left, Bot, comp), + Pixel(Right, Bot, comp)); + +} + +//----------------------------------------------------------------- +// resize (with bilinear filter) truecolor bitmap in place + +void FloatBitMap_t::ReSize(int NewWidth, int NewHeight) +{ + float XRatio= (float)Width / (float)NewWidth; + float YRatio= (float)Height / (float)NewHeight; + float SourceX, SourceY, Xfrac, Yfrac; + int Top, Bot, Left, Right; + + float *newrgba=new float[NewWidth * NewHeight * 4]; + + SourceY= 0; + for(int y=0;y<NewHeight;y++) + { + Yfrac= SourceY - floor(SourceY); + Top= SourceY; + Bot= SourceY+1; + if (Bot>=Height) Bot= Height-1; + SourceX= 0; + for(int x=0;x<NewWidth;x++) + { + Xfrac= SourceX - floor(SourceX); + Left= SourceX; + Right= SourceX+1; + if (Right>=Width) Right= Width-1; + for(int c=0;c<4;c++) + { + newrgba[4*(y*NewWidth+x)+c] = BiLinInterp(Xfrac, Yfrac, + Pixel(Left, Top, c), + Pixel(Right, Top, c), + Pixel(Left, Bot, c), + Pixel(Right, Bot, c)); + } + SourceX+= XRatio; + } + SourceY+= YRatio; + } + + delete[] RGBAData; + RGBAData=newrgba; + + Width=NewWidth; + Height=NewHeight; +} + +struct TGAHeader_t +{ + unsigned char id_length, colormap_type, image_type; + unsigned char colormap_index0,colormap_index1, colormap_length0,colormap_length1; + unsigned char colormap_size; + unsigned char x_origin0,x_origin1, y_origin0,y_origin1, width0, width1,height0,height1; + unsigned char pixel_size, attributes; +}; + +bool FloatBitMap_t::WriteTGAFile(char const *filename) const +{ + FileHandle_t f = g_pFullFileSystem->Open(filename, "wb"); + if (f) + { + TGAHeader_t myheader; + memset(&myheader,0,sizeof(myheader)); + myheader.image_type=2; + myheader.pixel_size=32; + myheader.width0= Width & 0xff; + myheader.width1= (Width>>8); + myheader.height0= Height & 0xff; + myheader.height1= (Height>>8); + myheader.attributes=0x20; + g_pFullFileSystem->Write(&myheader,sizeof(myheader),f); + // now, write the pixels + for(int y=0;y<Height;y++) + { + for(int x=0;x<Width;x++) + { + PixRGBAF fpix = PixelRGBAF( x, y ); + PixRGBA8 pix8 = PixRGBAF_to_8( fpix ); + + g_pFullFileSystem->Write(&pix8.Blue,1,f); + g_pFullFileSystem->Write(&pix8.Green,1,f); + g_pFullFileSystem->Write(&pix8.Red,1,f); + g_pFullFileSystem->Write(&pix8.Alpha,1,f); + } + } + g_pFullFileSystem->Close( f ); // close file after reading + + return true; + } + return false; +} + + +FloatBitMap_t::FloatBitMap_t(char const *tgafilename) +{ + RGBAData=0; + + // load from a tga or pfm + if (Q_stristr(tgafilename, ".pfm")) + { + LoadFromPFM(tgafilename); + return; + } + + int width1, height1; + ImageFormat imageFormat1; + float gamma1; + + if( !TGALoader::GetInfo( tgafilename, &width1, &height1, &imageFormat1, &gamma1 ) ) + { + printf( "error loading %s\n", tgafilename); + exit( -1 ); + } + AllocateRGB(width1,height1); + + uint8 *pImage1Tmp = + new uint8 [ImageLoader::GetMemRequired( width1, height1, 1, imageFormat1, false )]; + + if( !TGALoader::Load( pImage1Tmp, tgafilename, width1, height1, imageFormat1, 2.2f, false ) ) + { + printf( "error loading %s\n", tgafilename); + exit( -1 ); + } + uint8 *pImage1 = + new uint8 [ImageLoader::GetMemRequired( width1, height1, 1, IMAGE_FORMAT_ABGR8888, false )]; + + ImageLoader::ConvertImageFormat( pImage1Tmp, imageFormat1, pImage1, IMAGE_FORMAT_ABGR8888, width1, height1, 0, 0 ); + + for(int y=0;y<height1;y++) + { + for(int x=0;x<width1;x++) + { + for(int c=0;c<4;c++) + { + Pixel(x,y,3-c)=pImage1[c+4*(x+(y*width1))]/255.0; + } + } + } + + delete[] pImage1; + delete[] pImage1Tmp; +} + +FloatBitMap_t::~FloatBitMap_t(void) +{ + if (RGBAData) + delete[] RGBAData; +} + + +FloatBitMap_t *FloatBitMap_t::QuarterSize(void) const +{ + // generate a new bitmap half on each axis + + FloatBitMap_t *newbm=new FloatBitMap_t(Width/2,Height/2); + for(int y=0;y<Height/2;y++) + for(int x=0;x<Width/2;x++) + { + for(int c=0;c<4;c++) + newbm->Pixel(x,y,c)=((Pixel(x*2,y*2,c)+Pixel(x*2+1,y*2,c)+ + Pixel(x*2,y*2+1,c)+Pixel(x*2+1,y*2+1,c))/4); + } + return newbm; +} + +FloatBitMap_t *FloatBitMap_t::QuarterSizeBlocky(void) const +{ + // generate a new bitmap half on each axis + + FloatBitMap_t *newbm=new FloatBitMap_t(Width/2,Height/2); + for(int y=0;y<Height/2;y++) + for(int x=0;x<Width/2;x++) + { + for(int c=0;c<4;c++) + newbm->Pixel(x,y,c)=Pixel(x*2,y*2,c); + } + return newbm; +} + +Vector FloatBitMap_t::AverageColor(void) +{ + Vector ret(0,0,0); + for(int y=0;y<Height;y++) + for(int x=0;x<Width;x++) + for(int c=0;c<3;c++) + ret[c]+=Pixel(x,y,c); + ret*=1.0/(Width*Height); + return ret; +} + +float FloatBitMap_t::BrightestColor(void) +{ + float ret=0.0; + for(int y=0;y<Height;y++) + for(int x=0;x<Width;x++) + { + Vector v(Pixel(x,y,0),Pixel(x,y,1),Pixel(x,y,2)); + ret=max(ret,v.Length()); + } + return ret; +} + +template <class T> static inline void SWAP(T & a, T & b) +{ + T temp=a; + a=b; + b=temp; +} + +void FloatBitMap_t::RaiseToPower(float power) +{ + 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)=pow((float)MAX(0.0,Pixel(x,y,c)),(float)power); + +} + +void FloatBitMap_t::Logize(void) +{ + 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)=log(1.0+Pixel(x,y,c)); + +} + +void FloatBitMap_t::UnLogize(void) +{ + 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)=exp(Pixel(x,y,c))-1; +} + + +void FloatBitMap_t::Clear(float r, float g, float b, float alpha) +{ + for(int y=0;y<Height;y++) + for(int x=0;x<Width;x++) + { + Pixel(x,y,0)=r; + Pixel(x,y,1)=g; + Pixel(x,y,2)=b; + Pixel(x,y,3)=alpha; + } +} + +void FloatBitMap_t::ScaleRGB(float scale_factor) +{ + 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)*=scale_factor; +} + +static int dx[4]={0,-1,1,0}; +static int dy[4]={-1,0,0,1}; + +#define NDELTAS 4 + +void FloatBitMap_t::SmartPaste(FloatBitMap_t const &b, int xofs, int yofs, uint32 Flags) +{ + // now, need to make Difference map + FloatBitMap_t DiffMap0(this); + FloatBitMap_t DiffMap1(this); + FloatBitMap_t DiffMap2(this); + FloatBitMap_t DiffMap3(this); + FloatBitMap_t *deltas[4]={&DiffMap0,&DiffMap1,&DiffMap2,&DiffMap3}; + for(int x=0;x<Width;x++) + for(int y=0;y<Height;y++) + for(int c=0;c<3;c++) + { + for(int i=0;i<NDELTAS;i++) + { + int x1=x+dx[i]; + int y1=y+dy[i]; + x1=MAX(0,x1); + x1=MIN(Width-1,x1); + y1=MAX(0,y1); + y1=MIN(Height-1,y1); + float dx1=Pixel(x,y,c)-Pixel(x1,y1,c); + deltas[i]->Pixel(x,y,c)=dx1; + } + } + for(int x=1;x<b.Width-1;x++) + for(int y=1;y<b.Height-1;y++) + for(int c=0;c<3;c++) + { + for(int i=0;i<NDELTAS;i++) + { + float diff=b.Pixel(x,y,c)-b.Pixel(x+dx[i],y+dy[i],c); + deltas[i]->Pixel(x+xofs,y+yofs,c)=diff; + if (Flags & SPFLAGS_MAXGRADIENT) + { + float dx1=Pixel(x+xofs,y+yofs,c)-Pixel(x+dx[i]+xofs,y+dy[i]+yofs,c); + if (fabs(dx1)>fabs(diff)) + deltas[i]->Pixel(x+xofs,y+yofs,c)=dx1; + } + } + } + + // now, calculate modifiability + for(int x=0;x<Width;x++) + for(int y=0;y<Height;y++) + { + float modify=0; + if ( + (x>xofs+1) && (x<=xofs+b.Width-2) && + (y>yofs+1) && (y<=yofs+b.Height-2)) + modify=1; + Alpha(x,y)=modify; + } + + // // now, force a fex pixels in center to be constant + // int midx=xofs+b.Width/2; + // int midy=yofs+b.Height/2; + // for(x=midx-10;x<midx+10;x++) + // for(int y=midy-10;y<midy+10;y++) + // { + // Alpha(x,y)=0; + // for(int c=0;c<3;c++) + // Pixel(x,y,c)=b.Pixel(x-xofs,y-yofs,c); + // } + Poisson(deltas,6000,Flags); +} + +void FloatBitMap_t::ScaleGradients(void) +{ + // now, need to make Difference map + FloatBitMap_t DiffMap0(this); + FloatBitMap_t DiffMap1(this); + FloatBitMap_t DiffMap2(this); + FloatBitMap_t DiffMap3(this); + FloatBitMap_t *deltas[4]={&DiffMap0,&DiffMap1,&DiffMap2,&DiffMap3}; + double gsum=0.0; + for(int x=0;x<Width;x++) + for(int y=0;y<Height;y++) + for(int c=0;c<3;c++) + { + for(int i=0;i<NDELTAS;i++) + { + int x1=x+dx[i]; + int y1=y+dy[i]; + x1=MAX(0,x1); + x1=MIN(Width-1,x1); + y1=MAX(0,y1); + y1=MIN(Height-1,y1); + float dx1=Pixel(x,y,c)-Pixel(x1,y1,c); + deltas[i]->Pixel(x,y,c)=dx1; + gsum+=fabs(dx1); + } + } + // now, reduce gradient changes + // float gavg=gsum/(Width*Height); + for(int x=0;x<Width;x++) + for(int y=0;y<Height;y++) + for(int c=0;c<3;c++) + { + for(int i=0;i<NDELTAS;i++) + { + float norml=1.1*deltas[i]->Pixel(x,y,c); + // if (norml<0.0) + // norml=-pow(-norml,1.2); + // else + // norml=pow(norml,1.2); + deltas[i]->Pixel(x,y,c)=norml; + } + } + + // now, calculate modifiability + for(int x=0;x<Width;x++) + for(int y=0;y<Height;y++) + { + float modify=0; + if ( + (x>0) && (x<Width-1) && + (y) && (y<Height-1)) + { + modify=1; + Alpha(x,y)=modify; + } + } + + Poisson(deltas,2200,0); +} + + + +void FloatBitMap_t::MakeTileable(void) +{ + FloatBitMap_t rslta(this); + // now, need to make Difference map + FloatBitMap_t DiffMapX(this); + FloatBitMap_t DiffMapY(this); + // set each pixel=avg-pixel + FloatBitMap_t *cursrc=&rslta; + for(int x=1;x<Width-1;x++) + for(int y=1;y<Height-1;y++) + for(int c=0;c<3;c++) + { + DiffMapX.Pixel(x,y,c)=Pixel(x,y,c)-Pixel(x+1,y,c); + DiffMapY.Pixel(x,y,c)=Pixel(x,y,c)-Pixel(x,y+1,c); + } + // initialize edge conditions + for(int x=0;x<Width;x++) + { + for(int c=0;c<3;c++) + { + float a=0.5*(Pixel(x,Height-1,c)+=Pixel(x,0,c)); + rslta.Pixel(x,Height-1,c)=a; + rslta.Pixel(x,0,c)=a; + } + } + for(int y=0;y<Height;y++) + { + for(int c=0;c<3;c++) + { + float a=0.5*(Pixel(Width-1,y,c)+Pixel(0,y,c)); + rslta.Pixel(Width-1,y,c)=a; + rslta.Pixel(0,y,c)=a; + } + } + FloatBitMap_t rsltb(&rslta); + FloatBitMap_t *curdst=&rsltb; + + // now, ready to iterate + for(int pass=0;pass<10;pass++) + { + float error=0.0; + for(int x=1;x<Width-1;x++) + for(int y=1;y<Height-1;y++) + for(int c=0;c<3;c++) + { + float desiredx=DiffMapX.Pixel(x,y,c)+cursrc->Pixel(x+1,y,c); + float desiredy=DiffMapY.Pixel(x,y,c)+cursrc->Pixel(x,y+1,c); + float desired=0.5*(desiredy+desiredx); + curdst->Pixel(x,y,c)=FLerp(cursrc->Pixel(x,y,c),desired,0.5); + error+=SQ(desired-cursrc->Pixel(x,y,c)); + } + SWAP(cursrc,curdst); + } + // paste result + for(int x=0;x<Width;x++) + for(int y=0;y<Height;y++) + for(int c=0;c<3;c++) + Pixel(x,y,c)=curdst->Pixel(x,y,c); +} + + +void FloatBitMap_t::GetAlphaBounds(int &minx, int &miny, int &maxx,int &maxy) +{ + for(minx=0;minx<Width;minx++) + { + int y; + for(y=0;y<Height;y++) + if (Alpha(minx,y)) + break; + if (y!=Height) + break; + } + for(maxx=Width-1;maxx>=0;maxx--) + { + int y; + for(y=0;y<Height;y++) + if (Alpha(maxx,y)) + break; + if (y!=Height) + break; + } + for(miny=0;minx<Height;miny++) + { + int x; + for(x=minx;x<=maxx;x++) + if (Alpha(x,miny)) + break; + if (x<maxx) + break; + } + for(maxy=Height-1;maxy>=0;maxy--) + { + int x; + for(x=minx;x<=maxx;x++) + if (Alpha(x,maxy)) + break; + if (x<maxx) + break; + } +} + +void FloatBitMap_t::Poisson(FloatBitMap_t *deltas[4], + int n_iters, + uint32 flags // SPF_xxx + ) +{ + int minx,miny,maxx,maxy; + GetAlphaBounds(minx,miny,maxx,maxy); + minx=MAX(1,minx); + miny=MAX(1,miny); + maxx=MIN(Width-2,maxx); + maxy=MIN(Height-2,maxy); + if (((maxx-minx)>25) && (maxy-miny)>25) + { + // perform at low resolution + FloatBitMap_t *lowdeltas[NDELTAS]; + for(int i=0;i<NDELTAS;i++) + lowdeltas[i]=deltas[i]->QuarterSize(); + FloatBitMap_t *tmp=QuarterSize(); + tmp->Poisson(lowdeltas,n_iters*4,flags); + // now, propagate results from tmp to us + for(int x=0;x<tmp->Width;x++) + for(int y=0;y<tmp->Height;y++) + for(int xi=0;xi<2;xi++) + for(int yi=0;yi<2;yi++) + if (Alpha(x*2+xi,y*2+yi)) + { + for(int c=0;c<3;c++) + Pixel(x*2+xi,y*2+yi,c)= + FLerp(Pixel(x*2+xi,y*2+yi,c),tmp->Pixel(x,y,c),Alpha(x*2+xi,y*2+yi)); + } + char fname[80]; + sprintf(fname,"sub%dx%d.tga",tmp->Width,tmp->Height); + tmp->WriteTGAFile(fname); + sprintf(fname,"submrg%dx%d.tga",tmp->Width,tmp->Height); + WriteTGAFile(fname); + delete tmp; + for(int i=0;i<NDELTAS;i++) + delete lowdeltas[i]; + } + FloatBitMap_t work1(this); + FloatBitMap_t work2(this); + FloatBitMap_t *curdst=&work1; + FloatBitMap_t *cursrc=&work2; + // now, ready to iterate + while(n_iters--) + { + float error=0.0; + for(int x=minx;x<=maxx;x++) + { + for(int y=miny;y<=maxy;y++) + { + if (Alpha(x,y)) + { + for(int c=0;c<3;c++) + { + float desired=0.0; + for(int i=0;i<NDELTAS;i++) + desired+=deltas[i]->Pixel(x,y,c)+cursrc->Pixel(x+dx[i],y+dy[i],c); + desired*=(1.0/NDELTAS); + // desired=FLerp(Pixel(x,y,c),desired,Alpha(x,y)); + curdst->Pixel(x,y,c)=FLerp(cursrc->Pixel(x,y,c),desired,0.5); + error+=SQ(desired-cursrc->Pixel(x,y,c)); + } + } + SWAP(cursrc,curdst); + } + } + } + // paste result + for(int x=0;x<Width;x++) + { + for(int y=0;y<Height;y++) + { + for(int c=0;c<3;c++) + { + Pixel(x,y,c)=curdst->Pixel(x,y,c); + } + } + } +} + + |