From 8be3c508a34ac4eb333e6118ff875595b4e158f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Tue, 3 Oct 2017 16:41:00 +0200 Subject: [PATCH] Moved shader code builder to separate internal struct --- shaders.cc | 213 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 135 insertions(+), 78 deletions(-) diff --git a/shaders.cc b/shaders.cc index 076f300..26980b7 100644 --- a/shaders.cc +++ b/shaders.cc @@ -16,6 +16,7 @@ const std::map< std::string , E_ShaderInput > InputTypes_( ([] { return t; })()); + /*============================================================================*/ // Input reader state and functions, used when loading a source file @@ -163,106 +164,162 @@ bool T_ShaderInput::load( /*============================================================================*/ -bool T_ShaderCodeLoader::load( - __rd__ std::string const& name , - __wr__ T_Frankenshader& code ) +namespace { + +// Code builder, state and functions +struct T_CodeBuilder_ { - code = T_Frankenshader{ }; - - T_ShaderInput const* const main( getInput( name ) ); - if ( !main ) { - code.files.emplace( name , false ); - return false; - } - if ( main->type == E_ShaderInput::LIBRARY - || main->type == E_ShaderInput::CHUNK ) { - code.errors.push_back( T_ShaderError{ name , 0 , - "incorrect file type" } ); - } else { - code.type = E_ShaderType( int( main->type ) - 2 ); - } - struct T_StackEntry_ { std::string name; T_ShaderInput const* input; uint32_t pos; }; + + T_ShaderCodeLoader& loader; + const std::string name; + T_Frankenshader& code; + + T_ShaderInput const* main; std::map< std::string , uint32_t > pos; std::vector< T_StackEntry_ > stack; std::set< std::string > libraries; - T_ShaderInput const* current( main ); + T_ShaderInput const* current; uint32_t cpos{ 0 }; - std::string cname( name ); - pos[ cname ] = 1; + std::string cname; + + T_CodeBuilder_( __rw__ T_ShaderCodeLoader& loader , + __rd__ std::string const& name , + __rw__ T_Frankenshader& code ) + : loader( loader ) , name( name ) , code( code ) , + main( loader.getInput( name ) ) + { } + + bool buildCode( ); + void appendChunk( __rd__ T_ShaderInputChunk const& chunk ); + void include( __rd__ std::string const& name , + __rd__ const uint32_t lines ); + void next( ); +}; + +/*----------------------------------------------------------------------------*/ + +bool T_CodeBuilder_::buildCode( ) +{ + code = T_Frankenshader{ }; + code.files.emplace( name , main != nullptr ); + if ( !main ) { + return false; + } + cname = name; + current = main; while ( cpos < current->chunks.size( ) ) { auto& chunk( current->chunks[ cpos ] ); if ( chunk.type == E_ShaderInputChunk::CODE ) { - // Chunk of code; just append it. - code.sources.push_back( cname ); - code.counts.push_back( chunk.lines ); - code.starts.push_back( pos[ cname ] ); - code.code += chunk.text; - pos[ cname ] += chunk.lines; + appendChunk( chunk ); } else { - // Include. Make sure we're not recursing. - const auto prevPos( pos[ cname ] ); - pos[ cname ] += chunk.lines; - auto& nname( chunk.text ); - if ( cname == nname || 0 != count_if( stack.begin( ) , stack.end( ) , - [nname] ( T_StackEntry_ const& e ) { - return nname == e.name; - } ) ) { - code.errors.push_back( T_ShaderError{ cname , prevPos , - "recursive inclusion of '" + nname + "'" } ); - - } else if ( libraries.find( nname ) == libraries.end( ) ) { - // Load it unless it's a library that's already included - T_ShaderInput const* const isi( getInput( nname ) ); - code.files.emplace( nname , isi != nullptr ); - if ( isi && ( isi->type == E_ShaderInput::CHUNK - || isi->type == E_ShaderInput::LIBRARY ) ) { - // Ok, let's do this - if ( libraries.find( nname ) == libraries.end( ) ) { - for ( auto const& errs : isi->errors ) { - code.errors.push_back( T_ShaderError{ - nname , errs.line , errs.error } ); - } - } - libraries.insert( nname ); - stack.push_back( T_StackEntry_{ - cname , current , cpos } ); - cname = nname; - current = isi; - cpos = UINT32_MAX; - pos[ cname ] = 1; - - } else if ( isi ) { - // Trying to load a top-level shader - code.errors.push_back( T_ShaderError{ cname , prevPos , - "trying to include a top-level file" } ); - } else { - // Not found - code.errors.push_back( T_ShaderError{ cname , prevPos , - "file not found" } ); - } - } + include( chunk.text , chunk.lines ); } - cpos ++; - while ( cpos == current->chunks.size( ) && !stack.empty( ) ) { - T_StackEntry_ const& se( stack[ stack.size( ) - 1 ] ); - pos.erase( cname ); - cpos = se.pos + 1; - current = se.input; - cname = se.name; - stack.pop_back( ); - } + next( ); } return true; } +void T_CodeBuilder_::appendChunk( + __rd__ T_ShaderInputChunk const& chunk ) +{ + code.sources.push_back( cname ); + code.counts.push_back( chunk.lines ); + code.starts.push_back( pos[ cname ] ); + code.code += chunk.text; + pos[ cname ] += chunk.lines; +} + +void T_CodeBuilder_::include( + __rd__ std::string const& nname , + __rd__ const uint32_t lines ) +{ + const auto prevPos( pos[ cname ] ); + pos[ cname ] += lines; + + // Avoid recursion + if ( cname == nname || 0 != count_if( stack.begin( ) , stack.end( ) , + [nname] ( T_StackEntry_ const& e ) { + return nname == e.name; + } ) ) { + code.errors.push_back( T_ShaderError{ cname , prevPos , + "recursive inclusion of '" + nname + "'" } ); + return; + } + + // Avoid including libraries more than once + if ( libraries.find( nname ) != libraries.end( ) ) { + return; + } + + T_ShaderInput const* const isi( loader.getInput( nname ) ); + code.files.emplace( nname , isi != nullptr ); + + // Check for problems + if ( !isi ) { + // Not found + code.errors.push_back( T_ShaderError{ cname , prevPos , + "file not found" } ); + return; + } + if ( isi->type != E_ShaderInput::CHUNK && isi->type != E_ShaderInput::LIBRARY ) { + // Trying to load a top-level shader + code.errors.push_back( T_ShaderError{ cname , prevPos , + "trying to include a top-level file" } ); + return; + } + + // Add input loader errors + if ( libraries.find( nname ) == libraries.end( ) ) { + for ( auto const& errs : isi->errors ) { + code.errors.push_back( T_ShaderError{ + nname , errs.line , errs.error } ); + } + } + libraries.insert( nname ); + + // Enter the new file + stack.push_back( T_StackEntry_{ cname , current , cpos } ); + cname = nname; + current = isi; + cpos = UINT32_MAX; + pos[ cname ] = 1; +} + +void T_CodeBuilder_::next( ) +{ + cpos ++; + while ( cpos == current->chunks.size( ) && !stack.empty( ) ) { + T_StackEntry_ const& se( stack[ stack.size( ) - 1 ] ); + pos.erase( cname ); + cpos = se.pos + 1; + current = se.input; + cname = se.name; + stack.pop_back( ); + } +} + + +} // namespace + + +/*============================================================================*/ + +bool T_ShaderCodeLoader::load( + __rd__ std::string const& name , + __wr__ T_Frankenshader& code ) +{ + T_CodeBuilder_ cb( *this , name , code ); + return cb.buildCode( ); +} + T_ShaderInput const* T_ShaderCodeLoader::getInput( __rd__ std::string const& name ) {