diff --git a/Makefile b/Makefile index a654009..bbb0418 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ DEMO = \ imgui_impl_sdl.o \ utilities.o \ texture.o \ - rendertarget.o + rendertarget.o \ + bloom.o DEMO_DEPS = $(DEMO:%.o=.%.d) diff --git a/bloom.cc b/bloom.cc new file mode 100644 index 0000000..edf83b1 --- /dev/null +++ b/bloom.cc @@ -0,0 +1,127 @@ +#include "externals.hh" +#include "utilities.hh" +#include "texture.hh" +#include "rendertarget.hh" +#include "bloom.hh" + + +T_BloomPass::T_BloomPass( + __rd__ const uint32_t width , + __rd__ const uint32_t height , + __rw__ T_FilesWatcher& watcher , + __rw__ T_Texture& input ) + : input_( input ) , + spHighpass_( GL_FRAGMENT_SHADER , watcher ) , + spBlur_( GL_FRAGMENT_SHADER , watcher ) , + spCombine_( GL_FRAGMENT_SHADER , watcher ) , + // + txInput_( width , height , E_TexType::RGB16F ) , + rtInput_( T_RendertargetSetup( ).add( txInput_ , 0 ).create( ) ) , + // + txBlur0_( width , height , E_TexType::RGB16F , BloomLevels ) , + txBlur1_( width , height , E_TexType::RGB16F , BloomLevels ) +{ + txInput_.wrap( E_TexWrap::CLAMP_BORDER ).samplingMode( E_TexSampling::LINEAR ); + txBlur0_.wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); + txBlur1_.wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); + + for ( int i = 0 ; i < 5 ; i ++ ) { + rtBlur0_.push_back( T_RendertargetSetup( ).add( txBlur0_ , i ).create( ) ); + rtBlur1_.push_back( T_RendertargetSetup( ).add( txBlur1_ , i ).create( ) ); + } + + spHighpass_.addFile( "bloom-highpass.glsl" ); + spBlur_.addFile( "blur-pass.glsl" ); + spCombine_.addFile( "bloom-combine.glsl" ); + + spHighpass_.load( ); + spBlur_.load( ); + spCombine_.load( ); +} + +void T_BloomPass::render( ) +{ + if ( spHighpass_.activate( ) ) { + enum { + U_TEXTURE = 0 , + U_LOD = 1 , + U_INPUT_SIZE = 2 , + U_PARAMS = 3 , + }; + rtInput_.activate( ); + T_TextureBinding tb( 0 ); + tb.set( U_TEXTURE , input_ ); + tb.bind( ); + glUniform1i( U_LOD , 0 ); + glUniform2f( U_INPUT_SIZE , + input_.width( ) , + input_.height( ) ); + glUniform3f( U_PARAMS , 1.6 , 1.2 , .95 ); + glRectf( -1, -1 , 1 , 1 ); + } + + if ( spBlur_.activate( ) ) { + enum { + U_TEXTURE = 0 , + U_OUTPUT_SIZE = 1 , + U_INPUT_SIZE = 2 , + U_SOURCE_LOD = 3 , + U_DIRECTION = 4 , + U_WEIGHTS = 5 , + }; + glUniform4f( U_WEIGHTS , 0.324 , 0.232 , 0.0855 , 0.0205 ); + for ( int i = 0 ; i < 5 ; i ++ ) { + // IB RMO B0 B1 B0 B1 B0 + // OB B0/0 B1/0 B0/1 B1/1 B0/2 B1/2 + // SLOD: 0 0 0 1 1 2 + // IW: W W W W/2 W/2 W/4 + // OW: W W W/2 W/2 W/4 W/4 + T_TextureBinding tb( 0 ); + uint32_t w , h; + if ( i == 0 ) { + tb.set( U_TEXTURE , input_ ); + w = input_.width( ); + h = input_.height( ); + } else { + tb.set( U_TEXTURE , txBlur1_ ); + w = txBlur1_.width( ) >> ( i - 1 ); + h = txBlur1_.height( ) >> ( i - 1 ); + } + + const uint32_t slod = i > 0 ? ( i - 1 ) : 0; + rtBlur0_[ i ].activate( ); + glUniform2f( U_OUTPUT_SIZE , rtBlur0_[ i ].width( ) , + rtBlur0_[ i ].height( ) ); + glUniform1i( U_SOURCE_LOD , slod ); + glUniform2f( U_INPUT_SIZE , w , h ); + + glUniform2f( U_DIRECTION , 1 , 0 ); + tb.bind( ); + glRectf( -1 , -1 , 1 , 1 ); + + rtBlur1_[ i ].activate( ); + tb.set( U_TEXTURE , txBlur0_ ); + tb.bind( ); + glUniform2f( U_DIRECTION , 0 , 1 ); + glUniform1i( U_SOURCE_LOD , i ); + glUniform2f( U_INPUT_SIZE , + rtBlur0_[ i ].width( ) , + rtBlur0_[ i ].height( ) ); + glRectf( -1 , -1 , 1 , 1 ); + } + } + + T_Rendertarget::MainOutput( ); + glClearColor( 1 , 0 , 1 , 1 ); + glClear( GL_COLOR_BUFFER_BIT ); + if ( spCombine_.activate( ) ) { + T_TextureBinding main( 0 ) , blur( 1 ); + main.set( 0 , input_ ); + main.bind( ); + blur.set( 1 , txBlur1_ ); + blur.bind( ); + glUniform2f( 2 , input_.width( ) , input_.height( ) ); + glRectf( -1, -1 , 1 , 1 ); + glBindTexture( GL_TEXTURE_2D , 0 ); + } +} diff --git a/bloom.hh b/bloom.hh new file mode 100644 index 0000000..6fa0d5d --- /dev/null +++ b/bloom.hh @@ -0,0 +1,40 @@ +#pragma once +#ifndef REAL_BUILD +# define REAL_BUILD +# include "externals.hh" +# include "texture.hh" +# include "rendertarget.hh" +# include "utilities.hh" +# undef REAL_BUILD +#endif + + +struct T_BloomPass +{ + static constexpr uint32_t BloomLevels = 5; + + T_BloomPass( ) = delete; + T_BloomPass( T_BloomPass const& ) = delete; + T_BloomPass( T_BloomPass&& ) = delete; + + T_BloomPass( __rd__ const uint32_t width , + __rd__ const uint32_t height , + __rw__ T_FilesWatcher& watcher , + __rw__ T_Texture& input ); + + void render( ); + + + private: + T_Texture& input_; + + T_ShaderProgram spHighpass_; + T_ShaderProgram spBlur_; + T_ShaderProgram spCombine_; + + T_Texture txInput_; + T_Rendertarget rtInput_; + + T_Texture txBlur0_ , txBlur1_; + std::vector< T_Rendertarget > rtBlur0_ , rtBlur1_; +}; diff --git a/main.cc b/main.cc index eb45d02..252dcfa 100644 --- a/main.cc +++ b/main.cc @@ -4,6 +4,7 @@ #include "utilities.hh" #include "texture.hh" #include "rendertarget.hh" +#include "bloom.hh" /*= T_Main ===================================================================*/ @@ -30,18 +31,11 @@ struct T_Main T_FilesWatcher watcher; std::unique_ptr< T_ShaderProgram > spRaymarch; std::unique_ptr< T_ShaderProgram > spCopy; - std::unique_ptr< T_ShaderProgram > spBloomFilter; - std::unique_ptr< T_ShaderProgram > spBlur; - std::unique_ptr< T_ShaderProgram > spBloomCombine; std::unique_ptr< T_Texture > txRaymarchOutput; std::unique_ptr< T_Rendertarget > rtRaymarchOutput; - std::unique_ptr< T_Texture > txBloomInput; - std::unique_ptr< T_Rendertarget > rtBloomInput; - - std::unique_ptr< T_Texture > txBlur0 , txBlur1; - std::vector< std::unique_ptr< T_Rendertarget > > rtBlur0 , rtBlur1; + std::unique_ptr< T_BloomPass > bloomPass; void startIteration( ); void handleCapture( ); @@ -80,22 +74,8 @@ T_Main::T_Main( ) rtRaymarchOutput = std::make_unique < T_Rendertarget >( T_RendertargetSetup( ).add( *txRaymarchOutput ).create( ) ); - txBloomInput = std::make_unique< T_Texture >( - 1280 , 720 , E_TexType::RGB16F ); - txBloomInput->wrap( E_TexWrap::CLAMP_BORDER ).samplingMode( E_TexSampling::LINEAR ); - rtBloomInput = std::make_unique < T_Rendertarget >( - T_RendertargetSetup( ).add( *txBloomInput ).create( ) ); - - txBlur0 = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F , 5 ); - txBlur0->wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); - txBlur1 = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F , 5 ); - txBlur1->wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); - for ( int i = 0 ; i < 5 ; i ++ ) { - rtBlur0.push_back( std::make_unique< T_Rendertarget >( - T_RendertargetSetup( ).add( *txBlur0 , i ).create( ) ) ); - rtBlur1.push_back( std::make_unique< T_Rendertarget >( - T_RendertargetSetup( ).add( *txBlur1 , i ).create( ) ) ); - } + bloomPass = std::make_unique< T_BloomPass >( + 1280 , 720 , watcher , *txRaymarchOutput ); } void T_Main::mainLoop( ) @@ -221,100 +201,7 @@ void T_Main::render( ) glRectf( -1, -1 , 1 , 1 ); } - - if ( spBloomFilter->activate( ) ) { - enum { - U_TEXTURE = 0 , - U_LOD = 1 , - U_INPUT_SIZE = 2 , - U_PARAMS = 3 , - }; - rtBloomInput->activate( ); - T_TextureBinding tb( 0 ); - tb.set( U_TEXTURE , *txRaymarchOutput ); - tb.bind( ); - glUniform1i( U_LOD , 0 ); - glUniform2f( U_INPUT_SIZE , - txRaymarchOutput->width( ) , - txRaymarchOutput->height( ) ); - glUniform3f( U_PARAMS , 1.6 , 1.2 , .95 ); - glRectf( -1, -1 , 1 , 1 ); - } - - if ( spBlur->activate( ) ) { - enum { - U_TEXTURE = 0 , - U_OUTPUT_SIZE = 1 , - U_INPUT_SIZE = 2 , - U_SOURCE_LOD = 3 , - U_DIRECTION = 4 , - U_WEIGHTS = 5 , - }; - glUniform4f( U_WEIGHTS , 0.324 , 0.232 , 0.0855 , 0.0205 ); - for ( int i = 0 ; i < 5 ; i ++ ) { - // IB RMO B0 B1 B0 B1 B0 - // OB B0/0 B1/0 B0/1 B1/1 B0/2 B1/2 - // SLOD: 0 0 0 1 1 2 - // IW: W W W W/2 W/2 W/4 - // OW: W W W/2 W/2 W/4 W/4 - T_TextureBinding tb( 0 ); - uint32_t w , h; - if ( i == 0 ) { - tb.set( U_TEXTURE , *txBloomInput ); - w = txRaymarchOutput->width( ); - h = txRaymarchOutput->height( ); - } else { - tb.set( U_TEXTURE , *txBlur1 ); - w = txBlur1->width( ) >> ( i - 1 ); - h = txBlur1->height( ) >> ( i - 1 ); - } - - const uint32_t slod = i > 0 ? ( i - 1 ) : 0; - rtBlur0[ i ]->activate( ); -#ifdef INTRUSIVE_TRACES - printf( "BLUR %d/H IT %p SLOD %d IS %dx%d OS %dx%d\n" , - i , &(*( i == 0 ? txBloomInput : txBlur1 ) ) , - slod , w , h , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); -#endif - glUniform2f( U_OUTPUT_SIZE , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); - glUniform1i( U_SOURCE_LOD , slod ); - glUniform2f( U_INPUT_SIZE , w , h ); - - glUniform2f( U_DIRECTION , 1 , 0 ); - tb.bind( ); - glRectf( -1 , -1 , 1 , 1 ); - - rtBlur1[ i ]->activate( ); - tb.set( U_TEXTURE , *txBlur0 ); - tb.bind( ); - glUniform2f( U_DIRECTION , 0 , 1 ); - glUniform1i( U_SOURCE_LOD , i ); - glUniform2f( U_INPUT_SIZE , - rtBlur0[ i ]->width( ) , - rtBlur0[ i ]->height( ) ); - glRectf( -1 , -1 , 1 , 1 ); -#ifdef INTRUSIVE_TRACES - printf( "BLUR %d/V IT %p SLOD %d IS %dx%d OS %dx%d\n" , - i , &(*( txBlur0 ) ) , - i , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) , - rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); -#endif - } - } - - T_Rendertarget::MainOutput( ); - glClearColor( 1 , 0 , 1 , 1 ); - glClear( GL_COLOR_BUFFER_BIT ); - if ( spBloomCombine->activate( ) ) { - T_TextureBinding main( 0 ) , blur( 1 ); - main.set( 0 , *txRaymarchOutput ); - main.bind( ); - blur.set( 1 , *txBlur1 ); - blur.bind( ); - glUniform2f( 2 , dspSize.x , dspSize.y ); - glRectf( -1, -1 , 1 , 1 ); - glBindTexture( GL_TEXTURE_2D , 0 ); - } + bloomPass->render( ); glUseProgram( 0 ); ImGui::Render( ); @@ -334,18 +221,6 @@ void T_Main::initProgram( ) spCopy = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spCopy->addFile( "copy.glsl" ); spCopy->load( ); - - spBloomFilter = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); - spBloomFilter->addFile( "bloom-highpass.glsl" ); - spBloomFilter->load( ); - - spBlur = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); - spBlur->addFile( "blur-pass.glsl" ); - spBlur->load( ); - - spBloomCombine = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); - spBloomCombine->addFile( "bloom-combine.glsl" ); - spBloomCombine->load( ); }