Depth of field!!!

This commit is contained in:
Emmanuel BENOîT 2017-10-01 18:51:02 +02:00
parent 96122a6487
commit b2be3dcb8c
23 changed files with 441 additions and 48 deletions

View file

@ -15,6 +15,8 @@ DEMO = \
rendertarget.o \
raymarcher.o \
bloom.o \
dof.o \
combine.o \
profiling.o
DEMO_DEPS = $(DEMO:%.o=.%.d)

2
TODO
View file

@ -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

View file

@ -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 );
}

View file

@ -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_;
};

59
combine.cc Normal file
View file

@ -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 );
}

34
combine.hh Normal file
View file

@ -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_;
};

61
dof-common.glsl Normal file
View file

@ -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;
}

8
dof-pass1.glsl Normal file
View file

@ -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 );
}

15
dof-pass2.glsl Normal file
View file

@ -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 );
}

81
dof.cc Normal file
View file

@ -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( )
{
}

41
dof.hh Normal file
View file

@ -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_;
};

12
fsquad.glsl Normal file
View file

@ -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 );
}

14
main.cc
View file

@ -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 );

View file

@ -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 ) ) );
}

View file

@ -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;

View file

@ -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( );
}

View file

@ -77,7 +77,8 @@ void main( )
bc = vec3( 0. );
}
color = vec4( bc , 1 );
o_Color = bc;
o_Z = r.x;
/*
if ( r.y == -2 ) {

View file

@ -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;

View file

@ -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_ );

View file

@ -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( )

View file

@ -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 =================================================================*/

View file

@ -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_;