diff --git a/Makefile b/Makefile index 34b6db7..02ffc37 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,18 @@ IMGUI = imgui.o imgui_demo.o imgui_draw.o DEMO = \ main.o \ imgui_impl_sdl.o \ + \ utilities.o \ texture.o \ rendertarget.o \ + programs.o \ + \ raymarcher.o \ + \ bloom.o \ dof.o \ combine.o \ + \ profiling.o DEMO_DEPS = $(DEMO:%.o=.%.d) diff --git a/bloom.cc b/bloom.cc index 9e69415..e4db3e5 100644 --- a/bloom.cc +++ b/bloom.cc @@ -2,6 +2,7 @@ #include "utilities.hh" #include "texture.hh" #include "rendertarget.hh" +#include "programs.hh" #include "bloom.hh" #include "profiling.hh" diff --git a/combine.cc b/combine.cc index 95aafc3..b990849 100644 --- a/combine.cc +++ b/combine.cc @@ -2,6 +2,7 @@ #include "utilities.hh" #include "texture.hh" #include "rendertarget.hh" +#include "programs.hh" #include "combine.hh" #include "bloom.hh" #include "profiling.hh" diff --git a/combine.hh b/combine.hh index 0e431cf..86eada4 100644 --- a/combine.hh +++ b/combine.hh @@ -5,6 +5,7 @@ # include "texture.hh" # include "rendertarget.hh" # include "utilities.hh" +# include "programs.hh" # undef REAL_BUILD #endif diff --git a/dof.cc b/dof.cc index 54b4f51..30df9d9 100644 --- a/dof.cc +++ b/dof.cc @@ -1,6 +1,7 @@ #include "externals.hh" -#include "utilities.hh" #include "texture.hh" +#include "utilities.hh" +#include "programs.hh" #include "rendertarget.hh" #include "dof.hh" #include "profiling.hh" @@ -29,6 +30,8 @@ T_DoFPass::T_DoFPass( filterParams_{ 10 , 2 , 5 , 16 } , nSamples_( 16 ) { + txPass1_.wrap( E_TexWrap::CLAMP_EDGE ); + spPass1_.addFile( "dof-common.glsl" ); spPass1_.addFile( "dof-pass1.glsl" ); spPass1_.load( ); diff --git a/dof.hh b/dof.hh index dcf0630..dc758d8 100644 --- a/dof.hh +++ b/dof.hh @@ -4,7 +4,7 @@ # include "externals.hh" # include "texture.hh" # include "rendertarget.hh" -# include "utilities.hh" +# include "programs.hh" # undef REAL_BUILD #endif diff --git a/main.cc b/main.cc index 6ec1b77..f58eba0 100644 --- a/main.cc +++ b/main.cc @@ -2,6 +2,7 @@ #include "imgui_impl_sdl.h" #include "utilities.hh" +#include "programs.hh" #include "texture.hh" #include "rendertarget.hh" #include "raymarcher.hh" diff --git a/programs.cc b/programs.cc new file mode 100644 index 0000000..48f3b14 --- /dev/null +++ b/programs.cc @@ -0,0 +1,260 @@ +#include "externals.hh" +#include "utilities.hh" +#include "programs.hh" + + +/*= T_ShaderCode =============================================================*/ + +T_ShaderCode::T_ShaderCode( + __rd__ const int nparts ) + : code( nparts , nullptr ) +{ } + +T_ShaderCode::~T_ShaderCode( ) +{ + for ( char* str : code ) { + delete[] str; + } +} + +/*----------------------------------------------------------------------------*/ + +void T_ShaderCode::setPart( + __rd__ const int index , + __rd__ char const* const string ) +{ + assert( code[ index ] == nullptr ); + + const int len( strlen( string ) + 1 ); + char buffer[ 32 ]; + const int extraLen( index == 0 ? 0 + : snprintf( buffer , sizeof( buffer ) , + "\n#line 0 %d\n" , index ) ); + + char* const output( new char[ extraLen + len ] ); + if ( index != 0 ) { + memcpy( output , buffer , extraLen ); + } + strcpy( output + extraLen , string ); + code[ index ] = output; +} + +void T_ShaderCode::setPart( + __rd__ const int index , + __rd__ void const* const data , + __rd__ const int size ) +{ + assert( code[ index ] == nullptr ); + + char buffer[ 32 ]; + const int extraLen( index == 0 ? 0 + : snprintf( buffer , sizeof( buffer ) , + "\n#line 0 %d\n" , index ) ); + + char* const output( new char[ extraLen + size + 1 ] ); + if ( index != 0 ) { + memcpy( output , buffer , extraLen ); + } + memcpy( output + extraLen , data , size ); + output[ extraLen + size ] = 0; + code[ index ] = output; +} + +bool T_ShaderCode::loadPart( + __rd__ const int index , + __rd__ std::string const& source , + __rw__ std::vector< std::string >& errors ) +{ + assert( code[ index ] == nullptr ); + + FILE * f = fopen( source.c_str( ) , "r" ); + if ( !f ) { + std::string error( "File not found: " ); + error += source; + errors.push_back( error ); + return false; + } + + char buffer[ 32 ]; + const int extraLen( index == 0 ? 0 + : snprintf( buffer , sizeof( buffer ) , + "\n#line 0 %d\n" , index ) ); + + fseek( f , 0 , SEEK_END ); + const size_t size( ftell( f ) ); + fseek( f , 0 , SEEK_SET ); + + char* const output( new char[ extraLen + size + 1 ] ); + if ( index != 0 ) { + memcpy( output , buffer , extraLen ); + } + if ( fread( output + extraLen , 1 , size , f ) != size ) { + fclose( f ); + delete[] output; + std::string error( "Could not read file: " ); + error += source; + errors.push_back( error ); + return false; + } + output[ extraLen + size ] = 0; + fclose( f ); + code[ index ] = output; + return true; +} + +/*----------------------------------------------------------------------------*/ + +GLuint T_ShaderCode::createProgram( + __rd__ GLenum type , + __rw__ std::vector< std::string >& errors ) const +{ + GLenum sid = glCreateShaderProgramv( type , code.size( ) , &code[ 0 ] ); + if ( sid == 0 ) { + errors.push_back( "Failed to create GL program" ); + return sid; + } + + int infoLogLength; + glGetProgramiv( sid , GL_INFO_LOG_LENGTH , &infoLogLength ); + if ( infoLogLength ) { + char buffer[ infoLogLength + 1 ]; + glGetProgramInfoLog( sid , infoLogLength , nullptr , buffer ); + char* start( buffer ); + char* found( strchr( buffer , '\n' ) ); + while ( found ) { + *found = 0; + errors.push_back( start ); + start = found + 1; + found = strchr( start , '\n' ); + } + if ( start < &buffer[ infoLogLength - 1 ] ) { + errors.push_back( start ); + } + } + + int lnk; + glGetProgramiv( sid , GL_LINK_STATUS , &lnk ); + if ( !lnk ) { + glDeleteProgram( sid ); + return 0; + } + + return sid; +} + + +/*= T_ShaderProgram ==========================================================*/ + +T_ShaderProgram::T_ShaderProgram( + __rd__ const GLenum programType , + __rw__ T_FilesWatcher& watcher ) + : files_( watcher , [this] { load( ); } ) , + programType_( programType ) , program_( 0 ) +{ +} + +T_ShaderProgram::~T_ShaderProgram( ) +{ + if ( program_ != 0 ) { + glDeleteProgram( program_ ); + } +} + +void T_ShaderProgram::addChunk( + __rd__ std::string const& string ) +{ + chunksOrFiles_.push_back( true ); + parts_.push_back( string ); +} + +void T_ShaderProgram::addFile( + __rd__ std::string const& source ) +{ + chunksOrFiles_.push_back( false ); + parts_.push_back( source ); +} + +void T_ShaderProgram::load( ) +{ + const auto n( parts_.size( ) ); + errors_.clear( ); + files_.clear( ); + if ( program_ != 0 ) { + glDeleteProgram( program_ ); + program_ = 0; + } + + 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 { + 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( ) ) { + printf( "\n--------------------------------------------------------------------------------\n\n" ); + for ( auto const& str : errors_ ) { + printf( "ERR: %s\n" , str.c_str( ) ); + } + } +} + +bool T_ShaderProgram::activate( ) const +{ + if ( program_ != 0 ) { + glUseProgram( program_ ); + } + 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_; +} diff --git a/programs.hh b/programs.hh new file mode 100644 index 0000000..27e711a --- /dev/null +++ b/programs.hh @@ -0,0 +1,72 @@ +#pragma once +#ifndef REAL_BUILD +# include "externals.hh" +# include "utilities.hh" +#endif + +/*= T_ShaderCode =============================================================*/ + +struct T_ShaderCode +{ + T_ShaderCode( ) = delete; + T_ShaderCode( T_ShaderCode const& ) = delete; + T_ShaderCode( T_ShaderCode&& ) = delete; + + explicit T_ShaderCode( __rd__ const int nparts ); + ~T_ShaderCode( ); + + void setPart( + __rd__ const int index , + __rd__ char const* const string ); + void setPart( + __rd__ const int index , + __rd__ void const* const data , + __rd__ const int size ); + bool loadPart( + __rd__ const int index , + __rd__ std::string const& source , + __rw__ std::vector< std::string >& errors ); + + GLuint createProgram( + __rd__ GLenum type , + __rw__ std::vector< std::string >& errors ) const; + + private: + std::vector< char* > code; +}; + +struct T_ShaderProgram +{ + T_ShaderProgram( ) = delete; + T_ShaderProgram( T_ShaderProgram const& ) = delete; + T_ShaderProgram( T_ShaderProgram&& ) = delete; + + T_ShaderProgram( + __rd__ GLenum programType , + __rw__ T_FilesWatcher& watcher ); + ~T_ShaderProgram( ); + + void addChunk( __rd__ std::string const& string ); + void addFile( __rd__ std::string const& source ); + + void load( ); + bool activate( ) const; + + GLuint id( ) const { return program_; } + + static T_ShaderProgram const& FullscreenQuad( + __rw__ T_FilesWatcher& watcher ); + + private: + T_WatchedFiles files_; + + std::vector< bool > chunksOrFiles_; + std::vector< std::string > parts_; + + std::vector< std::string > errors_; + + GLenum programType_; + GLuint program_; +}; + + diff --git a/raymarcher.cc b/raymarcher.cc index 1c84af9..df9721c 100644 --- a/raymarcher.cc +++ b/raymarcher.cc @@ -2,6 +2,7 @@ #include "utilities.hh" #include "texture.hh" #include "rendertarget.hh" +#include "programs.hh" #include "raymarcher.hh" #include "profiling.hh" diff --git a/raymarcher.hh b/raymarcher.hh index 34fa908..2d974d6 100644 --- a/raymarcher.hh +++ b/raymarcher.hh @@ -5,6 +5,7 @@ # include "texture.hh" # include "rendertarget.hh" # include "utilities.hh" +# include "programs.hh" # undef REAL_BUILD #endif diff --git a/utilities.cc b/utilities.cc index 8d8c8fa..f4e1a16 100644 --- a/utilities.cc +++ b/utilities.cc @@ -157,263 +157,6 @@ bool T_WatchedFiles::watch( } -/*= T_ShaderCode =============================================================*/ - -T_ShaderCode::T_ShaderCode( - __rd__ const int nparts ) - : code( nparts , nullptr ) -{ } - -T_ShaderCode::~T_ShaderCode( ) -{ - for ( char* str : code ) { - delete[] str; - } -} - -/*----------------------------------------------------------------------------*/ - -void T_ShaderCode::setPart( - __rd__ const int index , - __rd__ char const* const string ) -{ - assert( code[ index ] == nullptr ); - - const int len( strlen( string ) + 1 ); - char buffer[ 32 ]; - const int extraLen( index == 0 ? 0 - : snprintf( buffer , sizeof( buffer ) , - "\n#line 0 %d\n" , index ) ); - - char* const output( new char[ extraLen + len ] ); - if ( index != 0 ) { - memcpy( output , buffer , extraLen ); - } - strcpy( output + extraLen , string ); - code[ index ] = output; -} - -void T_ShaderCode::setPart( - __rd__ const int index , - __rd__ void const* const data , - __rd__ const int size ) -{ - assert( code[ index ] == nullptr ); - - char buffer[ 32 ]; - const int extraLen( index == 0 ? 0 - : snprintf( buffer , sizeof( buffer ) , - "\n#line 0 %d\n" , index ) ); - - char* const output( new char[ extraLen + size + 1 ] ); - if ( index != 0 ) { - memcpy( output , buffer , extraLen ); - } - memcpy( output + extraLen , data , size ); - output[ extraLen + size ] = 0; - code[ index ] = output; -} - -bool T_ShaderCode::loadPart( - __rd__ const int index , - __rd__ std::string const& source , - __rw__ std::vector< std::string >& errors ) -{ - assert( code[ index ] == nullptr ); - - FILE * f = fopen( source.c_str( ) , "r" ); - if ( !f ) { - std::string error( "File not found: " ); - error += source; - errors.push_back( error ); - return false; - } - - char buffer[ 32 ]; - const int extraLen( index == 0 ? 0 - : snprintf( buffer , sizeof( buffer ) , - "\n#line 0 %d\n" , index ) ); - - fseek( f , 0 , SEEK_END ); - const size_t size( ftell( f ) ); - fseek( f , 0 , SEEK_SET ); - - char* const output( new char[ extraLen + size + 1 ] ); - if ( index != 0 ) { - memcpy( output , buffer , extraLen ); - } - if ( fread( output + extraLen , 1 , size , f ) != size ) { - fclose( f ); - delete[] output; - std::string error( "Could not read file: " ); - error += source; - errors.push_back( error ); - return false; - } - output[ extraLen + size ] = 0; - fclose( f ); - code[ index ] = output; - return true; -} - -/*----------------------------------------------------------------------------*/ - -GLuint T_ShaderCode::createProgram( - __rd__ GLenum type , - __rw__ std::vector< std::string >& errors ) const -{ - GLenum sid = glCreateShaderProgramv( type , code.size( ) , &code[ 0 ] ); - if ( sid == 0 ) { - errors.push_back( "Failed to create GL program" ); - return sid; - } - - int infoLogLength; - glGetProgramiv( sid , GL_INFO_LOG_LENGTH , &infoLogLength ); - if ( infoLogLength ) { - char buffer[ infoLogLength + 1 ]; - glGetProgramInfoLog( sid , infoLogLength , nullptr , buffer ); - char* start( buffer ); - char* found( strchr( buffer , '\n' ) ); - while ( found ) { - *found = 0; - errors.push_back( start ); - start = found + 1; - found = strchr( start , '\n' ); - } - if ( start < &buffer[ infoLogLength - 1 ] ) { - errors.push_back( start ); - } - } - - int lnk; - glGetProgramiv( sid , GL_LINK_STATUS , &lnk ); - if ( !lnk ) { - glDeleteProgram( sid ); - return 0; - } - - return sid; -} - - -/*= T_ShaderProgram ==========================================================*/ - -T_ShaderProgram::T_ShaderProgram( - __rd__ const GLenum programType , - __rw__ T_FilesWatcher& watcher ) - : files_( watcher , [this] { load( ); } ) , - programType_( programType ) , program_( 0 ) -{ -} - -T_ShaderProgram::~T_ShaderProgram( ) -{ - if ( program_ != 0 ) { - glDeleteProgram( program_ ); - } -} - -void T_ShaderProgram::addChunk( - __rd__ std::string const& string ) -{ - chunksOrFiles_.push_back( true ); - parts_.push_back( string ); -} - -void T_ShaderProgram::addFile( - __rd__ std::string const& source ) -{ - chunksOrFiles_.push_back( false ); - parts_.push_back( source ); -} - -void T_ShaderProgram::load( ) -{ - const auto n( parts_.size( ) ); - errors_.clear( ); - files_.clear( ); - if ( program_ != 0 ) { - glDeleteProgram( program_ ); - program_ = 0; - } - - 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 { - 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( ) ) { - printf( "\n--------------------------------------------------------------------------------\n\n" ); - for ( auto const& str : errors_ ) { - printf( "ERR: %s\n" , str.c_str( ) ); - } - } -} - -bool T_ShaderProgram::activate( ) const -{ - if ( program_ != 0 ) { - glUseProgram( program_ ); - } - 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 =================================================================*/ void T_Camera::handleDND( diff --git a/utilities.hh b/utilities.hh index f79fe67..4d33282 100644 --- a/utilities.hh +++ b/utilities.hh @@ -107,72 +107,6 @@ struct T_WatchedFiles }; -/*= T_ShaderCode =============================================================*/ - -struct T_ShaderCode -{ - T_ShaderCode( ) = delete; - T_ShaderCode( T_ShaderCode const& ) = delete; - T_ShaderCode( T_ShaderCode&& ) = delete; - - explicit T_ShaderCode( __rd__ const int nparts ); - ~T_ShaderCode( ); - - void setPart( - __rd__ const int index , - __rd__ char const* const string ); - void setPart( - __rd__ const int index , - __rd__ void const* const data , - __rd__ const int size ); - bool loadPart( - __rd__ const int index , - __rd__ std::string const& source , - __rw__ std::vector< std::string >& errors ); - - GLuint createProgram( - __rd__ GLenum type , - __rw__ std::vector< std::string >& errors ) const; - - private: - std::vector< char* > code; -}; - -struct T_ShaderProgram -{ - T_ShaderProgram( ) = delete; - T_ShaderProgram( T_ShaderProgram const& ) = delete; - T_ShaderProgram( T_ShaderProgram&& ) = delete; - - T_ShaderProgram( - __rd__ GLenum programType , - __rw__ T_FilesWatcher& watcher ); - ~T_ShaderProgram( ); - - void addChunk( __rd__ std::string const& string ); - void addFile( __rd__ std::string const& source ); - - void load( ); - bool activate( ) const; - - GLuint id( ) const { return program_; } - - static T_ShaderProgram const& FullscreenQuad( - __rw__ T_FilesWatcher& watcher ); - - private: - T_WatchedFiles files_; - - std::vector< bool > chunksOrFiles_; - std::vector< std::string > parts_; - - std::vector< std::string > errors_; - - GLenum programType_; - GLuint program_; -}; - - /*= T_Camera =================================================================*/ struct T_Camera