#include "externals.hh" #include "bloom.hh" #include "profiling.hh" #include "globals.hh" #include "odbg.hh" namespace { static char const* const Name_( "BLOOOOM!" ); } #define PSTART() Globals::Profiler( ).start( Name_ ) #define PEND() do { glFinish( ); Globals::Profiler( ).end( Name_ ); } while ( 0 ) T_BloomPass::T_BloomPass( __rw__ T_Texture& input ) : input_( input ) , // txBlur0_( input.width( ) , input.height( ) , E_TexType::RGB16F , BloomLevels ) , txBlur1_( input.width( ) , input.height( ) , E_TexType::RGB16F , BloomLevels ) , // filterParams_{ 1.6 , 1.2 , .95 } , blurWeights_{ 0.324 , 0.232 , 0.0855 , 0.0205 } , blurSize_{ 1.3 } { txBlur0_.wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); txBlur1_.wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); Globals::ODbg( ).registerTexture( txBlur0_ , E_ODbgMode::HDR , "Bloom" ); for ( auto i = 0u ; i < BloomLevels ; i ++ ) { rtBlur0_.add( T_RendertargetSetup( ).add( txBlur0_ , i ).create( ) ); rtBlur1_.add( T_RendertargetSetup( ).add( txBlur1_ , i ).create( ) ); } auto& sm( Globals::Shaders( ) ); spHighpass_ = sm.pipeline({ "fullscreen.v.glsl" , "bloom-highpass.f.glsl" }); spDownsample_ = sm.pipeline({ "fullscreen.v.glsl" , "downsample.f.glsl" }); spBlur_ = sm.pipeline({ "fullscreen.v.glsl" , "blur-pass.f.glsl" }); } void T_BloomPass::render( ) { if ( !( spHighpass_.valid( ) && spBlur_.valid( ) && spDownsample_.valid( ) ) ) { return; } PSTART( ); auto& tm( Globals::Textures( ) ); { rtBlur0_[ 0 ].activate( ); const auto hpf( spHighpass_.program( E_ShaderType::FRAGMENT ) ); enum { U_TEXTURE = 0 , U_LOD = 1 , U_INPUT_SIZE = 2 , U_PARAMS = 3 , }; tm.bind( 0 , input_ ); spHighpass_.enable( ); glProgramUniform1i( hpf , U_TEXTURE , 0 ); glProgramUniform1i( hpf , U_LOD , 0 ); glProgramUniform2f( hpf , U_INPUT_SIZE , input_.width( ) , input_.height( ) ); glProgramUniform3fv( hpf , U_PARAMS , 1 , filterParams_ ); glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); } enum { U_TEXTURE = 0 , U_OUTPUT_SIZE = 1 , U_SOURCE_LOD = 2 , U_DIRECTION = 3 , U_WEIGHTS = 4 , }; const auto dsf( spDownsample_.program( E_ShaderType::FRAGMENT ) ); const auto bpf( spBlur_.program( E_ShaderType::FRAGMENT ) ); glProgramUniform1i( dsf , 0 , 0 ); glProgramUniform4fv( bpf , U_WEIGHTS , 1 , blurWeights_ ); glProgramUniform1i( bpf , U_TEXTURE , 0 ); for ( auto i = 0u ; i < BloomLevels ; i ++ ) { if ( i > 0 ) { spDownsample_.enable( ); rtBlur0_[ i ].activate( ); tm.bind( 0 , txBlur0_ ); glProgramUniform2f( dsf , 1 , txBlur0_.width( ) >> i , txBlur0_.height( ) >> i ); glProgramUniform1i( dsf , 2 , i - 1 ); glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); } spBlur_.enable( ); glProgramUniform2f( bpf , U_OUTPUT_SIZE , rtBlur0_[ i ].width( ) , rtBlur0_[ i ].height( ) ); glProgramUniform1i( bpf , U_SOURCE_LOD , i ); rtBlur1_[ i ].activate( ); glProgramUniform2f( bpf , U_DIRECTION , blurSize_ , 0 ); tm.bind( 0 , txBlur0_ ); glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); rtBlur0_[ i ].activate( ); glProgramUniform2f( bpf , U_DIRECTION , 0 , blurSize_ ); tm.bind( 0 , txBlur1_ ); glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); } PEND( ); } void T_BloomPass::makeUI( ) { if ( !ImGui::CollapsingHeader( "Bloom" ) ) { return; } ImGui::DragFloat3( "Filter" , filterParams_ , .01f , 0.1 , 10 ); ImGui::DragFloat4( "Weights" , blurWeights_ , .001f , 0. , 10 ); ImGui::DragFloat( "Blur size" , &blurSize_ , .001f , 0. , 10 ); }