Shaders - directives for uniforms

This commit is contained in:
Emmanuel BENOîT 2017-10-08 10:13:11 +02:00
parent d53269e09e
commit 7ab196df56
2 changed files with 112 additions and 22 deletions

View file

@ -6,7 +6,7 @@
namespace { namespace {
const std::regex PreprocDirective_( "^\\s*//!\\s*([a-z]+(\\s+([^\\s]+))*)\\s*$" ); const std::regex PreprocDirective_( "^\\s*//!\\s*([a-z]+(\\s+([^\\s]+))*)\\s*$" );
const std::regex UniformName_( "^[A-Za-z][A-Za-z0-9_]*$" );
const std::regex GLSLErrorNv_( "^[0-9]*\\(([0-9]+).*$" ); const std::regex GLSLErrorNv_( "^[0-9]*\\(([0-9]+).*$" );
const std::map< std::string , E_ShaderInput > InputTypes_( ([] { const std::map< std::string , E_ShaderInput > InputTypes_( ([] {
@ -22,6 +22,20 @@ const std::map< std::string , E_ShaderInput > InputTypes_( ([] {
return t; return t;
})()); })());
const std::unordered_map< std::string , E_UniformType > UniformTypes_( ([] {
std::unordered_map< std::string , E_UniformType > t;
t.emplace( "float" , E_UniformType::F1 );
t.emplace( "vec2" , E_UniformType::F2 );
t.emplace( "vec3" , E_UniformType::F3 );
t.emplace( "vec4" , E_UniformType::F4 );
t.emplace( "int" , E_UniformType::I1 );
t.emplace( "ivec2" , E_UniformType::I2 );
t.emplace( "ivec3" , E_UniformType::I3 );
t.emplace( "ivec4" , E_UniformType::I4 );
t.emplace( "sampler2D" , E_UniformType::SAMPLER2D );
return t;
})());
const GLenum ProgramTypes_[] = { const GLenum ProgramTypes_[] = {
GL_VERTEX_SHADER , GL_VERTEX_SHADER ,
GL_FRAGMENT_SHADER , GL_FRAGMENT_SHADER ,
@ -64,11 +78,16 @@ struct T_InputReader_
~T_InputReader_( ); ~T_InputReader_( );
void read( ); void read( );
void handleDirective(
__rd__ T_Tokens_ const& tokens );
void parseInputDirective(
__rd__ T_Tokens_ const& tokens );
void error(
__rd__ std::string const& err );
void nl( ); void nl( );
void addAccumulated( ); void addAccumulated( );
void handleDirective(
__rd__ T_Tokens_ const& tokens );
void error( __rd__ std::string const& err );
}; };
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
@ -103,22 +122,7 @@ void T_InputReader_::read( )
addAccumulated( ); addAccumulated( );
} }
void T_InputReader_::nl( ) /*----------------------------------------------------------------------------*/
{
accumLines ++;
accumulator += '\n';
}
void T_InputReader_::addAccumulated( )
{
if ( accumLines ) {
auto& ck( input.chunks );
ck.emplace_back( E_ShaderInputChunk::CODE ,
std::move( accumulator ) , accumLines );
accumulator = {};
accumLines = 0;
}
}
void T_InputReader_::handleDirective( void T_InputReader_::handleDirective(
__rd__ T_Tokens_ const& tokens ) __rd__ T_Tokens_ const& tokens )
@ -148,20 +152,89 @@ void T_InputReader_::handleDirective(
input.type = pos->second; input.type = pos->second;
} }
} else if ( directive == "input" ) {
nl( );
parseInputDirective( tokens );
} else if ( directive == "uniforms" ) {
nl( );
for ( auto const& c : input.chunks ) {
if ( c.type == E_ShaderInputChunk::UNIFORMS ) {
error( "duplicate uniform generation" );
return;
}
}
input.chunks.emplace_back( E_ShaderInputChunk::UNIFORMS , "" , 1 );
} else { } else {
nl( ); nl( );
error( "unknown directive" ); error( "unknown directive" );
} }
} }
void T_InputReader_::parseInputDirective(
__rd__ T_Tokens_ const& tokens )
{
if ( tokens.size( ) != 4 ) {
error( "invalid arguments" );
return;
}
// Local/global
const bool global{ tokens[ 1 ] == "global" };
if ( !global && tokens[ 1 ] != "local" ) {
error( "second argument should be 'local' or 'global'" );
return;
}
// Name
std::string const& name{ tokens[ 2 ] };
if ( input.uniforms.find( name ) != input.uniforms.end( ) ) {
error( "duplicate uniform" );
return;
}
if ( !std::regex_match( name , UniformName_ ) ) {
error( "invalid uniform name" );
return;
}
// Type
auto tPos( UniformTypes_.find( tokens[ 3 ] ) );
if ( tPos == UniformTypes_.end( ) ) {
error( "unsupported uniform type" );
return;
}
input.uniforms.emplace( tokens[ 2 ] , T_ShaderUniform{
tokens[ 2 ] , global , tPos->second } );
}
/*----------------------------------------------------------------------------*/
void T_InputReader_::error( void T_InputReader_::error(
__rd__ std::string const& err ) __rd__ std::string const& err )
{ {
printf( "input error (%d - %s)\n" , line , err.c_str( ) );
input.errors.push_back( T_ShaderInputError{ input.errors.push_back( T_ShaderInputError{
line , err } ); line , err } );
} }
void T_InputReader_::nl( )
{
accumLines ++;
accumulator += '\n';
}
void T_InputReader_::addAccumulated( )
{
if ( accumLines ) {
auto& ck( input.chunks );
ck.emplace_back( E_ShaderInputChunk::CODE ,
std::move( accumulator ) , accumLines );
accumulator = {};
accumLines = 0;
}
}
} // namespace } // namespace

View file

@ -8,7 +8,8 @@
// Type of input chunk // Type of input chunk
enum class E_ShaderInputChunk { enum class E_ShaderInputChunk {
CODE , CODE ,
INCLUDE INCLUDE ,
UNIFORMS
}; };
// Input chunk data // Input chunk data
@ -44,12 +45,28 @@ struct T_ShaderInputError
std::string error; std::string error;
}; };
// Uniform types
enum class E_UniformType {
F1 , F2 , F3 , F4 ,
I1 , I2 , I3 , I4 ,
SAMPLER2D
};
// Uniform declarations
struct T_ShaderUniform
{
std::string name;
bool global;
E_UniformType type;
};
// Source file // Source file
struct T_ShaderInput struct T_ShaderInput
{ {
E_ShaderInput type = E_ShaderInput::CHUNK; E_ShaderInput type = E_ShaderInput::CHUNK;
std::vector< T_ShaderInputChunk > chunks; std::vector< T_ShaderInputChunk > chunks;
std::vector< T_ShaderInputError > errors; std::vector< T_ShaderInputError > errors;
std::unordered_map< std::string , T_ShaderUniform > uniforms;
bool load( __rd__ std::string const& path ); bool load( __rd__ std::string const& path );
}; };