From b2be3dcb8cd8e2467b9d1d7baa3ee82bbd883498 Mon Sep 17 00:00:00 2001 From: Emmanuel Benoit Date: Sun, 1 Oct 2017 18:51:02 +0200 Subject: [PATCH] Depth of field!!! --- Makefile | 2 + TODO | 2 + bloom.cc | 24 +-------- bloom.hh | 5 +- combine.cc | 59 ++++++++++++++++++++++ bloom-combine.glsl => combine.glsl | 0 combine.hh | 34 +++++++++++++ dof-common.glsl | 61 ++++++++++++++++++++++ dof-pass1.glsl | 8 +++ dof-pass2.glsl | 15 ++++++ dof.cc | 81 ++++++++++++++++++++++++++++++ dof.hh | 41 +++++++++++++++ fsquad.glsl | 12 +++++ main.cc | 14 +++++- map.glsl | 2 +- raymarch-header.glsl | 3 +- raymarcher.cc | 37 +++++++++----- raymarcher.glsl | 3 +- raymarcher.hh | 4 +- rendertarget.cc | 8 ++- texture.cc | 7 ++- utilities.cc | 50 +++++++++++++++++- utilities.hh | 17 +++++++ 23 files changed, 441 insertions(+), 48 deletions(-) create mode 100644 combine.cc rename bloom-combine.glsl => combine.glsl (100%) create mode 100644 combine.hh create mode 100644 dof-common.glsl create mode 100644 dof-pass1.glsl create mode 100644 dof-pass2.glsl create mode 100644 dof.cc create mode 100644 dof.hh create mode 100644 fsquad.glsl diff --git a/Makefile b/Makefile index 4bdc3b5..34b6db7 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,8 @@ DEMO = \ rendertarget.o \ raymarcher.o \ bloom.o \ + dof.o \ + combine.o \ profiling.o DEMO_DEPS = $(DEMO:%.o=.%.d) diff --git a/TODO b/TODO index d5e77a7..79b216f 100644 --- a/TODO +++ b/TODO @@ -11,6 +11,8 @@ Post-processing: * Lens dirt Technical: +* Use program pipelines +* Use uniform buffers * GLSL with includes * GLSL constants generator * Common handling for parameters diff --git a/bloom.cc b/bloom.cc index 7c86933..9e69415 100644 --- a/bloom.cc +++ b/bloom.cc @@ -20,16 +20,13 @@ T_BloomPass::T_BloomPass( spHighpass_( GL_FRAGMENT_SHADER , watcher ) , spDownsample_( GL_FRAGMENT_SHADER , watcher ) , spBlur_( GL_FRAGMENT_SHADER , watcher ) , - spCombine_( GL_FRAGMENT_SHADER , watcher ) , // 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 } , - combineStrength_( 0.45 ) , - combineAttenuation_( 0.3 ) + blurSize_{ 1.3 } { txBlur0_.wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); txBlur1_.wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); @@ -42,12 +39,10 @@ T_BloomPass::T_BloomPass( spHighpass_.addFile( "bloom-highpass.glsl" ); spDownsample_.addFile( "downsample.glsl" ); spBlur_.addFile( "blur-pass.glsl" ); - spCombine_.addFile( "bloom-combine.glsl" ); spHighpass_.load( ); spDownsample_.load( ); spBlur_.load( ); - spCombine_.load( ); } void T_BloomPass::render( ) @@ -113,21 +108,6 @@ void T_BloomPass::render( ) 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 , txBlur0_ ); - blur.bind( ); - glUniform2f( 2 , input_.width( ) , input_.height( ) ); - glUniform2f( 3 , combineStrength_ , combineAttenuation_ ); - glRectf( -1, -1 , 1 , 1 ); - glBindTexture( GL_TEXTURE_2D , 0 ); - } - PEND( ); } @@ -140,6 +120,4 @@ void T_BloomPass::makeUI( ) ImGui::DragFloat3( "Filter" , filterParams_ , .01f , 0.1 , 10 ); ImGui::DragFloat4( "Weights" , blurWeights_ , .001f , 0. , 10 ); ImGui::DragFloat( "Blur size" , &blurSize_ , .001f , 0. , 10 ); - ImGui::DragFloat( "Initial strength" , &combineStrength_ , .001f , 0. , 10 ); - ImGui::DragFloat( "Attenuation" , &combineAttenuation_ , .001f , 0. , 1 ); } diff --git a/bloom.hh b/bloom.hh index 4f1cef1..ea31403 100644 --- a/bloom.hh +++ b/bloom.hh @@ -23,13 +23,14 @@ struct T_BloomPass void render( ); void makeUI( ); + T_Texture& output( ) { return txBlur0_; } + private: T_Texture& input_; T_ShaderProgram spHighpass_; T_ShaderProgram spDownsample_; T_ShaderProgram spBlur_; - T_ShaderProgram spCombine_; T_Texture txBlur0_ , txBlur1_; std::vector< T_Rendertarget > rtBlur0_ , rtBlur1_; @@ -37,6 +38,4 @@ struct T_BloomPass float filterParams_[ 3 ]; float blurWeights_[ 4 ]; float blurSize_; - float combineStrength_; - float combineAttenuation_; }; diff --git a/combine.cc b/combine.cc new file mode 100644 index 0000000..95aafc3 --- /dev/null +++ b/combine.cc @@ -0,0 +1,59 @@ +#include "externals.hh" +#include "utilities.hh" +#include "texture.hh" +#include "rendertarget.hh" +#include "combine.hh" +#include "bloom.hh" +#include "profiling.hh" + +namespace { + static const std::string Name_( "Combine" ); +} + +#define PSTART() T_Profiler::Profiler.start( Name_ ) +#define PEND() do { glFinish( ); T_Profiler::Profiler.end( Name_ ); } while ( 0 ) + + +T_CombinePass::T_CombinePass( + __rw__ T_FilesWatcher& watcher , + __rw__ T_Texture& image , + __rw__ T_Texture& bloom ) + : txImage_( image ) , txBloom_( bloom ) , + program_( GL_FRAGMENT_SHADER , watcher ) , + bloomStrength_( 0.45 ) , + bloomAttenuation_( 0.3 ) +{ + program_.addFile( "combine.glsl" ); + program_.load( ); +} + +void T_CombinePass::render( ) +{ + PSTART( ); + T_Rendertarget::MainOutput( ); + glClearColor( 1 , 0 , 1 , 1 ); + glClear( GL_COLOR_BUFFER_BIT ); + if ( program_.activate( ) ) { + T_TextureBinding main( 0 ) , blur( 1 ); + main.set( 0 , txImage_ ); + main.bind( ); + blur.set( 1 , txBloom_ ); + blur.bind( ); + glUniform2f( 2 , txImage_.width( ) , txImage_.height( ) ); + glUniform2f( 3 , bloomStrength_ , bloomAttenuation_ ); + glRectf( -1, -1 , 1 , 1 ); + glBindTexture( GL_TEXTURE_2D , 0 ); + } + PEND( ); +} + +void T_CombinePass::makeUI( ) +{ + if ( !ImGui::CollapsingHeader( "Combine" ) ) { + return; + } + + ImGui::DragFloat( "Bloom strength" , &bloomStrength_ , .001f , 0. , 10 ); + ImGui::DragFloat( "Bloom attenuation" , &bloomAttenuation_ , .001f , 0. , 1 ); +} + diff --git a/bloom-combine.glsl b/combine.glsl similarity index 100% rename from bloom-combine.glsl rename to combine.glsl diff --git a/combine.hh b/combine.hh new file mode 100644 index 0000000..0e431cf --- /dev/null +++ b/combine.hh @@ -0,0 +1,34 @@ +#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_CombinePass +{ + T_CombinePass( ) = delete; + T_CombinePass( T_CombinePass const& ) = delete; + T_CombinePass( T_CombinePass&& ) = delete; + + T_CombinePass( __rw__ T_FilesWatcher& watcher , + __rw__ T_Texture& image , + __rw__ T_Texture& bloom ); + + void render( ); + void makeUI( ); + + private: + T_Texture& txImage_; + T_Texture& txBloom_; + + T_ShaderProgram program_; + + float bloomStrength_; + float bloomAttenuation_; +}; + diff --git a/dof-common.glsl b/dof-common.glsl new file mode 100644 index 0000000..aba3547 --- /dev/null +++ b/dof-common.glsl @@ -0,0 +1,61 @@ +#version 450 core + +//#define USE_RANDOM + +layout( location = 0 ) uniform sampler2D u_Input; +layout( location = 1 ) uniform sampler2D u_Depth; +layout( location = 2 ) uniform vec4 u_Parameters; +layout( location = 3 ) uniform float u_Samples; +layout( location = 4 ) uniform vec3 u_ResolutionTime; + +#define uSharpDist (u_Parameters.x) +#define uSharpRange (u_Parameters.y) +#define uBlurFalloff (u_Parameters.z) +#define uMaxBlur (u_Parameters.w) + +#define uResolution (u_ResolutionTime.xy) +#define uTime (u_ResolutionTime.z) + +float CoC( float z ) +{ + return uMaxBlur * min( 1 , + max( 0 , abs( z - uSharpDist ) - uSharpRange ) / uBlurFalloff ); +} + +layout( location = 0 ) out vec3 o_Color; + +float hash1( vec2 p ) +{ + p = fract(p * vec2(5.3987, 5.4421)); + p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); + return fract(p.x * p.y * 95.4307); +} + +// z: z at UV +// coc: blur radius at UV +// uv: initial coordinate +// blurvec: smudge direction +vec3 depthDirectionalBlur( float z , float coc , vec2 uv , vec2 blurvec ) +{ + vec3 sumcol = vec3( 0. ); + for ( int i = 0 ; i < u_Samples ; i++ ) { + float r = i; +#ifdef USE_RANDOM + r += hash1( uv + float( i + uTime ) ) - .5; +#endif + r = r / float( u_Samples - 1 ) - .5; + vec2 p = uv + r * coc * blurvec; + vec3 smpl = texture( u_Input , p ).xyz; + float sz = texture( u_Depth , p ).x; + if ( sz < z ) { + // if sample is closer consider it's CoC + p = uv + r * min( coc , CoC( sz ) ) * blurvec; + p = uv + r * CoC( sz ) * blurvec; + smpl = texture( u_Input , p ).xyz; + } + sumcol += smpl; + } + sumcol /= float( u_Samples ); + sumcol = max( sumcol , 0. ); + return sumcol; +} diff --git a/dof-pass1.glsl b/dof-pass1.glsl new file mode 100644 index 0000000..d55f187 --- /dev/null +++ b/dof-pass1.glsl @@ -0,0 +1,8 @@ +void main() +{ + vec2 uv = gl_FragCoord.xy / uResolution; + vec2 blurvec = vec2( 0 , 1 ) / uResolution; + + float z = texture( u_Depth , uv ).x; + o_Color = depthDirectionalBlur( z , CoC( z ) , uv , blurvec ); +} diff --git a/dof-pass2.glsl b/dof-pass2.glsl new file mode 100644 index 0000000..77f2298 --- /dev/null +++ b/dof-pass2.glsl @@ -0,0 +1,15 @@ +void main() +{ + vec2 uv = gl_FragCoord.xy / uResolution; + float z = texture( u_Depth , uv ).x; + + vec2 blurdir = vec2( 1.0 , 0.577350269189626 ); + vec2 blurvec = normalize( blurdir ) / uResolution; + vec3 color0 = depthDirectionalBlur( z , CoC( z ) , uv , blurvec ); + + blurdir.x = -1; + blurvec = normalize( blurdir ) / uResolution; + vec3 color1 = depthDirectionalBlur( z , CoC( z ) , uv , blurvec ); + + o_Color = min( color0 , color1 ); +} diff --git a/dof.cc b/dof.cc new file mode 100644 index 0000000..a10df7f --- /dev/null +++ b/dof.cc @@ -0,0 +1,81 @@ +#include "externals.hh" +#include "utilities.hh" +#include "texture.hh" +#include "rendertarget.hh" +#include "dof.hh" +#include "profiling.hh" + +namespace { + static const std::string Name_( "DoF" ); +} + +#define PSTART() T_Profiler::Profiler.start( Name_ ) +#define PEND() do { glFinish( ); T_Profiler::Profiler.end( Name_ ); } while ( 0 ) + + +T_DoFPass::T_DoFPass( + __rw__ T_FilesWatcher& watcher , + __rw__ T_Texture& imageInput , + __rw__ T_Texture& depthInput ) + : imageInput_( imageInput ) , depthInput_( depthInput ) , + spPass1_( GL_FRAGMENT_SHADER , watcher ) , + spPass2_( GL_FRAGMENT_SHADER , watcher ) , + txPass1_( imageInput.width( ) , imageInput.height( ) , + E_TexType::RGB16F ) , + txOutput_( imageInput.width( ) , imageInput.height( ) , + E_TexType::RGB16F ) , + rtPass1_( T_RendertargetSetup( ).add( txPass1_ ).create( ) ) , + rtPass2_( T_RendertargetSetup( ).add( txOutput_ ).create( ) ) , + filterParams_{ 10 , 2 , 5 , 16 } , + nSamples_( 16 ) +{ + spPass1_.addFile( "dof-common.glsl" ); + spPass1_.addFile( "dof-pass1.glsl" ); + spPass1_.load( ); + + spPass2_.addFile( "dof-common.glsl" ); + spPass2_.addFile( "dof-pass2.glsl" ); + spPass2_.load( ); +} + +void T_DoFPass::render( ) +{ + PSTART( ); + enum { + U_INPUT = 0 , + U_DEPTH = 1 , + U_PARAMS = 2 , + U_SAMPLES = 3 , + U_RES_TIME = 4 + }; + T_TextureBinding tb0( 0 ) , tb1( 1 ); + if ( spPass1_.activate( ) && rtPass1_.activate( ) ) { + tb0.set( U_INPUT , imageInput_ ); + tb1.set( U_DEPTH , depthInput_ ); + tb0.bind( ); + tb1.bind( ); + glUniform4fv( U_PARAMS , 1 , filterParams_ ); + glUniform1f( U_SAMPLES , nSamples_ ); + glUniform3f( U_RES_TIME , imageInput_.width( ) , + imageInput_.height( ) , + 0 ); + glRectf( -1 , -1 , 1 , 1 ); + } + if ( spPass2_.activate( ) && rtPass2_.activate( ) ) { + tb0.set( U_INPUT , txPass1_ ); + tb1.set( U_DEPTH , depthInput_ ); + tb0.bind( ); + tb1.bind( ); + glUniform4fv( U_PARAMS , 1 , filterParams_ ); + glUniform1f( U_SAMPLES , nSamples_ ); + glUniform3f( U_RES_TIME , imageInput_.width( ) , + imageInput_.height( ) , + 0 ); + glRectf( -1 , -1 , 1 , 1 ); + } + PEND( ); +} + +void T_DoFPass::makeUI( ) +{ +} diff --git a/dof.hh b/dof.hh new file mode 100644 index 0000000..dcf0630 --- /dev/null +++ b/dof.hh @@ -0,0 +1,41 @@ +#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_DoFPass +{ + T_DoFPass( ) = delete; + T_DoFPass( T_DoFPass const& ) = delete; + T_DoFPass( T_DoFPass&& ) = delete; + + T_DoFPass( __rw__ T_FilesWatcher& watcher , + __rw__ T_Texture& imageInput , + __rw__ T_Texture& depthInput ); + + void render( ); + void makeUI( ); + + T_Texture& output( ) { return txOutput_; } + + private: + T_Texture& imageInput_; + T_Texture& depthInput_; + + T_ShaderProgram spPass1_; + T_ShaderProgram spPass2_; + + T_Texture txPass1_ , txOutput_; + T_Rendertarget rtPass1_ , rtPass2_; + + // SharpDist/SharpRange/Falloff/MaxBlur + float filterParams_[ 4 ]; + int nSamples_; +}; + diff --git a/fsquad.glsl b/fsquad.glsl new file mode 100644 index 0000000..b64e5b0 --- /dev/null +++ b/fsquad.glsl @@ -0,0 +1,12 @@ +#version 450 core + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main( void ) +{ + gl_Position = vec4( + vec2( gl_VertexID >> 1 , gl_VertexID & 1 ) * 2 - 1 , + 0 , 1 ); +} diff --git a/main.cc b/main.cc index 6926527..6ec1b77 100644 --- a/main.cc +++ b/main.cc @@ -4,8 +4,10 @@ #include "utilities.hh" #include "texture.hh" #include "rendertarget.hh" -#include "bloom.hh" #include "raymarcher.hh" +#include "dof.hh" +#include "bloom.hh" +#include "combine.hh" #include "profiling.hh" @@ -32,7 +34,9 @@ struct T_Main std::unique_ptr< T_ShaderProgram > spCopy; std::unique_ptr< T_Raymarcher > raymarcher; + std::unique_ptr< T_DoFPass > dofPass; std::unique_ptr< T_BloomPass > bloomPass; + std::unique_ptr< T_CombinePass > combinePass; void startIteration( ); void handleCapture( ); @@ -66,8 +70,12 @@ T_Main::T_Main( ) initProgram( ); raymarcher = std::make_unique< T_Raymarcher >( watcher , 1280 , 720 ); + dofPass = std::make_unique< T_DoFPass >( watcher , + raymarcher->output( ) , raymarcher->depth( ) ); bloomPass = std::make_unique< T_BloomPass >( watcher , raymarcher->output( ) ); + combinePass = std::make_unique< T_CombinePass >( watcher , + dofPass->output( ) , bloomPass->output( ) ); } void T_Main::mainLoop( ) @@ -166,7 +174,9 @@ void T_Main::makeUI( ) ImGui::Checkbox( "Profiler" , &T_Profiler::Profiler.uiEnabled( ) ); raymarcher->makeUI( ); + dofPass->makeUI( ); bloomPass->makeUI( ); + combinePass->makeUI( ); ImGui::End( ); @@ -177,7 +187,9 @@ void T_Main::render( ) { T_Profiler::Profiler.start( "Render" ); raymarcher->render( ); + dofPass->render( ); bloomPass->render( ); + combinePass->render( ); glFinish( ); T_Profiler::Profiler.end( "Render" ); glUseProgram( 0 ); diff --git a/map.glsl b/map.glsl index 3681bbe..38058e2 100644 --- a/map.glsl +++ b/map.glsl @@ -1,6 +1,6 @@ vec2 map( vec3 pos ) { vec3 q = pos; - q.xy = mod( q.xy + 2. , 4. ) - 2.; + q.xy = mod( q.xy + 4. , 8. ) - 4.; return vec2( length( q ) - 1.8 , step( 0. , 1.9 - length( pos.xy ) ) ); } diff --git a/raymarch-header.glsl b/raymarch-header.glsl index 2821952..0ccd569 100644 --- a/raymarch-header.glsl +++ b/raymarch-header.glsl @@ -12,7 +12,8 @@ layout( location = 7 ) uniform vec4 u_Render; vec3 camPos , lookAt , camUp; float nearPlane; -layout( location = 0 ) out vec4 color; +layout( location = 0 ) out vec3 o_Color; +layout( location = 1 ) out float o_Z; void setCamFromUniforms( ) { camPos = u_CamPos; diff --git a/raymarcher.cc b/raymarcher.cc index 0ab310d..1c84af9 100644 --- a/raymarcher.cc +++ b/raymarcher.cc @@ -18,24 +18,36 @@ T_Raymarcher::T_Raymarcher( __rd__ const uint32_t height ) : camera_( ) , program_( GL_FRAGMENT_SHADER , watcher ) , txOutput_( width , height , E_TexType::RGB16F ) , - rtOutput_( T_RendertargetSetup( ).add( txOutput_ ).create( ) ) + txDepth_( width , height , E_TexType::R16F ) , + rtOutput_( T_RendertargetSetup( ) + .add( txOutput_ ) + .add( txDepth_ ) + .create( ) ) { + glGenProgramPipelines( 1 , &pipeline_ ); + program_.addFile( "raymarch-header.glsl" ); program_.addFile( "map.glsl" ); program_.addFile( "raymarcher.glsl" ); program_.load( ); + + auto& fsq( T_ShaderProgram::FullscreenQuad( watcher ) ); + glUseProgramStages( pipeline_ , GL_VERTEX_SHADER_BIT , fsq.id( ) ); + glUseProgramStages( pipeline_ , GL_FRAGMENT_SHADER_BIT , program_.id( ) ); + assert( glGetError( ) == GL_NO_ERROR ); } void T_Raymarcher::render( ) { PSTART( ); - if ( !( program_.activate( ) && rtOutput_.activate( ) ) ) { + if ( ! rtOutput_.activate( ) ) { PEND( ); return; } - glClearColor( 0 , 1 , 1 , 1 ); + glBindProgramPipeline( pipeline_ ); + glClearColor( 0 , 0 , 0 , 1 ); glClear( GL_COLOR_BUFFER_BIT ); enum { U_TIME = 0 , @@ -48,20 +60,21 @@ void T_Raymarcher::render( ) U_RAYMARCHER = 7 , }; - glUniform1f( U_TIME , 0 ); - glUniform2f( U_RESOLUTION , rtOutput_.width( ) , rtOutput_.height( ) ); + glProgramUniform1f( program_.id( ) , U_TIME , 0 ); + glProgramUniform2f( program_.id( ) , U_RESOLUTION , rtOutput_.width( ) , rtOutput_.height( ) ); - glUniform3fv( U_CAM_POS , 1 , &camera_.pos.x ); - glUniform3fv( U_LOOK_AT , 1 , &camera_.lookAt.x ); - glUniform3fv( U_CAM_UP , 1 , &camera_.up.x ); - glUniform1f( U_NEAR_PLANE , camera_.np ); + glProgramUniform3fv( program_.id( ) , U_CAM_POS , 1 , &camera_.pos.x ); + glProgramUniform3fv( program_.id( ) , U_LOOK_AT , 1 , &camera_.lookAt.x ); + glProgramUniform3fv( program_.id( ) , U_CAM_UP , 1 , &camera_.up.x ); + glProgramUniform1f( program_.id( ) , U_NEAR_PLANE , camera_.np ); - glUniform3f( U_LIGHT_DIR , 0 , 1 , 1 ); + glProgramUniform3f( program_.id( ) , U_LIGHT_DIR , 0 , 1 , 1 ); - glUniform4f( U_RAYMARCHER , rmIterations , rmStep , + glProgramUniform4f( program_.id( ) , U_RAYMARCHER , rmIterations , rmStep , rmEpsilon , rmMaxDist ); - glRectf( -1, -1 , 1 , 1 ); + glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); + glBindProgramPipeline( 0 ); PEND( ); } diff --git a/raymarcher.glsl b/raymarcher.glsl index afc7e7a..0ae8d56 100644 --- a/raymarcher.glsl +++ b/raymarcher.glsl @@ -77,7 +77,8 @@ void main( ) bc = vec3( 0. ); } - color = vec4( bc , 1 ); + o_Color = bc; + o_Z = r.x; /* if ( r.y == -2 ) { diff --git a/raymarcher.hh b/raymarcher.hh index 0418501..34fa908 100644 --- a/raymarcher.hh +++ b/raymarcher.hh @@ -27,13 +27,15 @@ struct T_Raymarcher T_Camera& camera( ) noexcept { return camera_; } T_Texture& output( ) noexcept { return txOutput_; } + T_Texture& depth( ) noexcept { return txDepth_; } private: T_Camera camera_; + GLuint pipeline_; T_ShaderProgram program_; - T_Texture txOutput_; + T_Texture txOutput_ , txDepth_; T_Rendertarget rtOutput_; int rmIterations = 128; diff --git a/rendertarget.cc b/rendertarget.cc index cfd8084..4cf62f8 100644 --- a/rendertarget.cc +++ b/rendertarget.cc @@ -56,8 +56,8 @@ T_Rendertarget T_RendertargetSetup::create( ) glBindFramebuffer( GL_FRAMEBUFFER , id ); for ( auto i = 0u ; i < nca ; i ++ ) { #ifdef INTRUSIVE_TRACES - printf( "init fb %p att %d tx %p level %d\n" , - this , i , + printf( "init %p fb %d att %d tx %p level %d\n" , + this , id , i , colorAttachments_[ i ].texture , colorAttachments_[ i ].level ); #endif @@ -132,6 +132,10 @@ bool T_Rendertarget::activate( ) for ( auto i = 0u ; i < nCats_ ; i ++ ) { buffers_.push_back( GL_COLOR_ATTACHMENT0 + i ); } +#ifdef INTRUSIVE_TRACES + printf( "fb %d: created buffers (%d items)\n" , id_ , + int( buffers_.size( ) ) ); +#endif } glBindFramebuffer( GL_FRAMEBUFFER , id_ ); glViewport( 0 , 0 , width_ , height_ ); diff --git a/texture.cc b/texture.cc index 7ac3023..e27efc8 100644 --- a/texture.cc +++ b/texture.cc @@ -1,4 +1,5 @@ #include "externals.hh" +#include "utilities.hh" #include "texture.hh" @@ -62,13 +63,17 @@ T_Texture::T_Texture( uint32_t w = width , h = height; for ( auto i = 0u ; i < levels ; i ++ ) { +#ifdef INTRUSIVE_TRACES + printf( "init %p txid %d lv %d sz %dx%d\n" , this , id_ , + i , w , h ); +#endif glTexImage2D( GL_TEXTURE_2D , i , ifmt , w , h , 0 , fmt , dt , nullptr ); w >>= 1; h >>= 1; assert( w && h ); } - assert( glGetError( ) == GL_NO_ERROR ); + GL_CHECK( ); } T_Texture::~T_Texture( ) diff --git a/utilities.cc b/utilities.cc index ffd3c23..8d8c8fa 100644 --- a/utilities.cc +++ b/utilities.cc @@ -339,16 +339,46 @@ void T_ShaderProgram::load( ) } T_ShaderCode sc( n ); + printf( "LOAD PROGRAM" ); for ( auto i = 0u ; i < n ; i ++ ) { if ( chunksOrFiles_[ i ] ) { + printf( " %d:(chunk)" , i ); sc.setPart( i , parts_[ i ].c_str( ) ); - } else if ( sc.loadPart( i , parts_[ i ].c_str( ) , errors_ ) ) { - files_.watch( parts_[ i ] ); + } else { + printf( " %d:%s" , i , parts_[ i ].c_str( ) ); + if ( sc.loadPart( i , parts_[ i ].c_str( ) , errors_ ) ) { + files_.watch( parts_[ i ] ); + } } } + printf( "\n" ); if ( errors_.size( ) == 0 ) { program_ = sc.createProgram( programType_ , errors_ ); + if ( program_ != 0 ) { + GLint x; + glGetProgramInterfaceiv( program_ , GL_PROGRAM_OUTPUT , + GL_ACTIVE_RESOURCES , &x ); + printf( "-> LOADED (%d output(s)" , x ); + for ( int i = 0 ; i < x ; i ++ ) { + static const GLenum query[] = { + GL_NAME_LENGTH , GL_LOCATION + }; + int output[ 2 ]; + glGetProgramResourceiv( program_ , GL_PROGRAM_OUTPUT , + i , 2 , query , 2 , nullptr , + output ); + + char rName[ output[ 0 ] + 1 ]; + glGetProgramResourceName( program_ , + GL_PROGRAM_OUTPUT , i , + sizeof( rName ) , nullptr , + rName ); + printf( "%s %s@%d" , i == 0 ? ":" : "" , rName , + output[ 1 ] ); + } + printf( ")\n" ); + } } if ( errors_.size( ) ) { @@ -367,6 +397,22 @@ bool T_ShaderProgram::activate( ) const return program_ != 0; } +namespace { + std::unique_ptr< T_ShaderProgram > FsQuad_; +} + +T_ShaderProgram const& T_ShaderProgram::FullscreenQuad( + __rw__ T_FilesWatcher& watcher ) +{ + if ( !FsQuad_ ) { + FsQuad_ = std::make_unique< T_ShaderProgram >( + GL_VERTEX_SHADER , watcher ); + FsQuad_->addFile( "fsquad.glsl" ); + FsQuad_->load( ); + } + return *FsQuad_; +} + /*= T_Camera =================================================================*/ diff --git a/utilities.hh b/utilities.hh index 89523a6..f79fe67 100644 --- a/utilities.hh +++ b/utilities.hh @@ -15,6 +15,18 @@ inline void reenableButtons( ) /*----------------------------------------------------------------------------*/ +#define GL_CHECK( ) \ + do { \ + auto err_( glGetError( ) ); \ + if ( err_ != GL_NO_ERROR ) { \ + fprintf( stderr , "GL error %x in %s:%d\n" , \ + err_ , __FILE__ , __LINE__ ); \ + abort( ); \ + } \ + } while ( 0 ) + +/*----------------------------------------------------------------------------*/ + // Add some value to an angle, keeping it in [-180;180] void updateAngle( __rw__ float& initial , @@ -143,6 +155,11 @@ struct T_ShaderProgram void load( ); bool activate( ) const; + GLuint id( ) const { return program_; } + + static T_ShaderProgram const& FullscreenQuad( + __rw__ T_FilesWatcher& watcher ); + private: T_WatchedFiles files_;