//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //===========================================================================// #include #include #include #include #include #include "bitmap/float_bm.h" #include #include "tier0/threadtools.h" #include "tier0/progressbar.h" struct TBFCalculationContext { int min_y,max_y; // range to calculate in this thread int thread_number; int radius_in_pixels; float edge_threshold_value; FloatBitMap_t const *orig_bm; FloatBitMap_t *dest_bm; }; static unsigned TBFCalculationThreadFN( void *ctx1 ) { TBFCalculationContext *ctx = (TBFCalculationContext *) ctx1; for(int y=ctx->min_y; y <= ctx->max_y; y++) { if ( ctx->thread_number == 0 ) ReportProgress("Performing bilateral filter",(1+ctx->max_y-ctx->min_y), y-ctx->min_y); for(int x=0; x < ctx->dest_bm->Width; x++) for(int c=0;c<4;c++) { float sum_weights=0; float filter_sum=0; float centerp=ctx->orig_bm->Pixel(x,y,c); for(int iy=-ctx->radius_in_pixels; iy <= ctx->radius_in_pixels; iy++) for(int ix=-ctx->radius_in_pixels; ix <= ctx->radius_in_pixels; ix++) { float this_p=ctx->orig_bm->PixelWrapped(x+ix,y+iy,c); // caluclate the g() term. We use a gaussian float exp1=(ix*ix+iy*iy)*(1.0/(2.0*ctx->radius_in_pixels*.033)); float g=exp(-exp1); // calculate the "similarity" term. We use a triangle filter float s=1.0; float cdiff=fabs(centerp-this_p); s= (cdiff>ctx->edge_threshold_value)?0: FLerp(1,0,0,ctx->edge_threshold_value,cdiff); sum_weights += s*g; filter_sum += s*g*this_p; } ctx->dest_bm->Pixel(x,y,c)=filter_sum/sum_weights; } } return 0; } void FloatBitMap_t::TileableBilateralFilter( int radius_in_pixels, float edge_threshold_value ) { FloatBitMap_t orig( this ); // need a copy for the source TBFCalculationContext ctxs[32]; ctxs[0].radius_in_pixels = radius_in_pixels; ctxs[0].edge_threshold_value = edge_threshold_value; ctxs[0].orig_bm = &orig; ctxs[0].dest_bm = this; int nthreads = min( 32, (int)GetCPUInformation()->m_nPhysicalProcessors ); ThreadHandle_t waithandles[32]; int starty=0; int ystep=Height/nthreads; for(int t=0;t