diff --git a/demo.srd b/demo.srd index 5e787a0..f62b065 100644 --- a/demo.srd +++ b/demo.srd @@ -152,19 +152,23 @@ (input dof-samples 16) # Input overrides - { NOT IMPLEMENTED - (ui-overrides - (section "Post-processing" - (section "Depth of Field" - (float dof-sharp-distance (min 0) (max 1000) (step .1)) - (float dof-sharp-range (min 0) (max 500) (step .1)) - (float dof-falloff (min 0) (max 500) (step .1)) - (float dof-max-blur (min 1) (max 64) (step .1)) + (ui-overrides + (section "Post-processing" + (section "Depth of Field" + (float "Sharp distance" dof-sharp-distance + (min 0) (max 50000) (step .1)) + (float "Sharp range" dof-sharp-range + (min 0) (max 50000) (step .1)) + (float "Falloff" dof-falloff + (min 0) (max 50000) (step .1)) + (float "Maximum blur" dof-max-blur + (min 1) (max 64) (slider)) + { NOT IMPLEMENTED (int dof-samples (min 1) (max 64) (step .1)) - ) + } ) ) - } + ) ) (fn dof-set-uniforms (prog) diff --git a/opparser.cc b/opparser.cc index c548209..7a83a4c 100644 --- a/opparser.cc +++ b/opparser.cc @@ -2,7 +2,9 @@ #include "opast.hh" #include "ops.hh" #include "opcomp.hh" +#include "syncoverrides.hh" #include +#include using namespace ebcl; using namespace opast; @@ -24,6 +26,7 @@ struct T_ParserImpl_ LOCALS , MAINOUT , ODBG , + OVERRIDES , PIPELINE , PROFILE , PROGRAM , @@ -60,6 +63,7 @@ struct T_ParserImpl_ add( "sampler" , E_InstrType::SAMPLER ); add( "set" , E_InstrType::SET ); add( "texture" , E_InstrType::TEXTURE ); + add( "ui-overrides" , E_InstrType::OVERRIDES ); add( "uniforms" , E_InstrType::UNIFORMS_FLT ); add( "uniforms-i" , E_InstrType::UNIFORMS_INT ); add( "use-framebuffer" , E_InstrType::USE_FRAMEBUFFER ); @@ -153,6 +157,8 @@ struct T_ParserImpl_ T_Array< T_SRDError >& errors; T_MultiArray< uint32_t > calls; T_Array< T_InstrRestriction > callInfo; + T_SRDParserConfig ovParserConfig; + T_SRDParser ovParser; T_Visitor< A_Node > visitor{ opast::ASTVisitorBrowser }; T_Visitor< uint32_t , uint32_t > callGraphVisitor{ @@ -231,6 +237,7 @@ struct T_ParserImpl_ M_DPARSER_( Input ); M_DPARSER_( Locals ); M_DPARSER_( ODebug ); + M_DPARSER_( Overrides ); M_DPARSER_( Pipeline ); M_DPARSER_( Profile ); M_DPARSER_( Program ); @@ -295,7 +302,9 @@ struct T_ParserImpl_ inline T_ParserImpl_::T_ParserImpl_( T_Array< T_SRDError >* const errors , T_OwnPtr< T_OpsParserOutput >* const output ) noexcept - : output( *output ) , errors( *errors ) + : output( *output ) , errors( *errors ) , + ovParserConfig( sov::GetParserConfig( ) ) , + ovParser( ovParserConfig ) { } void T_ParserImpl_::main( @@ -1008,6 +1017,7 @@ void T_ParserImpl_::parseInstructions( M_CASE_( INPUT , Input ); M_CASE_( LOCALS , Locals ); M_CASE_( ODBG , ODebug ); + M_CASE_( OVERRIDES , Overrides ); M_CASE_( PIPELINE , Pipeline ); M_CASE_( PROFILE , Profile ); M_CASE_( PROGRAM , Program ); @@ -1323,6 +1333,72 @@ M_INSTR_( ODebug ) /*----------------------------------------------------------------------------*/ +M_INSTR_( Overrides ) +{ + if ( input.size( ) == 1 ) { + errors.addNew( "not enough arguments" , input[ 0 ].location( ) ); + return; + } + + struct T_StackEntry_ { + T_SRDList const* list; + uint32_t pos; + + T_StackEntry_( T_SRDList const* list , + const uint32_t pos ) noexcept + : list( list ) , pos( pos ) + {} + }; + T_AutoArray< T_StackEntry_ , 16 > stack; + T_StackEntry_ current{ &input , 1 }; + T_SRDErrors ovParserErrors; + bool hadException{ false }; + try { + ovParser.start( ovParserErrors ); + while ( current.pos < current.list->size( ) || !stack.empty( ) ) { + if ( current.pos == current.list->size( ) ) { + current = stack.last( ); + stack.removeLast( ); + + T_SRDToken ls{ T_SRDToken::ListEnd( ) }; + ls.location( (*current.list)[ current.pos ].location( ) ); + ovParser.push( ovParserErrors , std::move( ls ) ); + + current.pos ++; + continue; + } + + auto const& src( (*current.list)[ current.pos ] ); + if ( src.type( ) == E_SRDTokenType::LIST ) { + T_SRDToken ls{ T_SRDToken::ListStart( ) }; + ls.location( src.location( ) ); + ovParser.push( ovParserErrors , std::move( ls ) ); + stack.add( current ); + current = T_StackEntry_{ &src.list( ) , 0 }; + } else { + ovParser.push( ovParserErrors , T_SRDToken{ src } ); + current.pos ++; + } + } + ovParser.end( ovParserErrors ); + } catch ( X_SRDErrors const& e ) { + hadException = true; + } + + const auto n{ ovParserErrors.size( ) - ( hadException ? 1 : 0 ) }; + if ( n != 0 ) { + for ( auto i = 0u ; i < n ; i ++ ) { + errors.add( ovParserErrors[ i ] ); + } + if ( hadException ) { + errors.addNew( "too many errors in UI overrides list" , + input[ 0 ].location( ) ); + } + } +} + +/*----------------------------------------------------------------------------*/ + M_INSTR_( Pipeline ) { if ( input.size( ) < 3 ) { diff --git a/syncoverrides.cc b/syncoverrides.cc index 6bceb92..c90c72c 100644 --- a/syncoverrides.cc +++ b/syncoverrides.cc @@ -2,6 +2,8 @@ #include "globals.hh" #include "syncoverrides.hh" +#include + using namespace sov; #define M_SETOPT_( FIELD , VAR ) \ @@ -10,6 +12,211 @@ using namespace sov; return true +/*= PARSER DEFINITIONS =========================================================*/ + +namespace { + +using namespace ebcl; +using SP_Section = T_SharedPtr< T_SyncOverrideSection >; + +bool EnterSection_( T_SRDParserData const& data ) +{ + *( data.targetData ) = NewShared< T_SyncOverrideSection >( (*data.input)[ 1 ].stringValue( ) ); + return true; +} + +bool ExitSection_( T_SRDParserData const& data ) +{ + auto& section( data.currentData->value< SP_Section >( ) ); + auto& parent( data.targetData->value< SP_Section >( ) ); + + if ( section->overrides.empty( ) && section->subsections.empty( ) ) { + T_StringBuilder sb; + sb << "empty section '" << section->title << "'"; + data.errors.add( std::move( sb ) , (*data.input)[ 0 ] ); + } else { + parent->subsections.add( section.makeOwned( ) ); + } + + return true; +} + +/*------------------------------------------------------------------------------*/ + +using SP_Float = T_SharedPtr< A_Float >; + +bool EnterFloat1_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + SP_Float ptr{ NewShared< T_Float >( + input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) ) }; + *( data.targetData ) = std::move( ptr ); + return true; +} + +bool EnterFloat2_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + SP_Float ptr{ NewShared< T_Float2 >( + input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , + input[ 3 ].stringValue( ) ) }; + *( data.targetData ) = std::move( ptr ); + return true; +} + +bool EnterFloat3_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + SP_Float ptr{ NewShared< T_Float3 >( + input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , + input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) ) }; + *( data.targetData ) = std::move( ptr ); + return true; +} + +bool EnterFloat4_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + SP_Float ptr{ NewShared< T_Float4 >( + input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , + input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) , + input[ 5 ].stringValue( ) ) }; + *( data.targetData ) = std::move( ptr ); + return true; +} + +bool AddFloat_( T_SRDParserData const& data ) +{ + auto& fl( data.currentData->value< SP_Float >( ) ); + auto& parent( data.targetData->value< SP_Section >( ) ); + + if ( fl->min( ) > fl->max( ) ) { + data.errors.add( "invalid bounds" , (*data.input)[ 0 ] ); + } + parent->overrides.add( fl.makeOwned( ) ); + return true; +} + +/*------------------------------------------------------------------------------*/ + +bool FloatSetSlider_( T_SRDParserData const& data ) +{ + data.currentData->value< SP_Float >( )->setSlider( ); + return true; +} + +bool FloatSetMin_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + if ( !data.currentData->value< SP_Float >( )->setMin( input[ 1 ].floatValue( ) ) ) { + data.errors.add( "duplicate minimal value" , (*data.input)[ 0 ] ); + } + return true; +} + +bool FloatSetMax_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + if ( !data.currentData->value< SP_Float >( )->setMax( input[ 1 ].floatValue( ) ) ) { + data.errors.add( "duplicate maximal value" , (*data.input)[ 0 ] ); + } + return true; +} + +bool FloatSetStep_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + const auto v( input[ 1 ].floatValue( ) ); + if ( v <= 0 ) { + data.errors.add( "invalid step value" , (*data.input)[ 1 ] ); + } else if ( !data.currentData->value< SP_Float >( )->setStep( v ) ) { + data.errors.add( "duplicate step value" , (*data.input)[ 0 ] ); + } + return true; +} + +bool FloatSetPower_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + const auto v( input[ 1 ].floatValue( ) ); + if ( v <= 0 ) { + data.errors.add( "invalid power value" , (*data.input)[ 1 ] ); + } else if ( !data.currentData->value< SP_Float >( )->setPower( v ) ) { + data.errors.add( "duplicate power value" , (*data.input)[ 0 ] ); + } + return true; +} + +bool FloatSetDecimals_( T_SRDParserData const& data ) +{ + auto const& input( *( data.input ) ); + const auto v( input[ 1 ].longValue( ) ); + if ( v < 0 || v > 10 ) { + data.errors.add( "invalid decimals value" , (*data.input)[ 1 ] ); + } else if ( !data.currentData->value< SP_Float >( )->setDecimals( v ) ) { + data.errors.add( "duplicate decimals value" , (*data.input)[ 0 ] ); + } + return true; +} + +} // namespace + +/*------------------------------------------------------------------------------*/ + +ebcl::T_SRDParserConfig sov::GetParserConfig( ) +{ + using namespace ebcl; + using namespace ebcl::SRD; + T_SRDParserDefs defs( "root" ); + + defs << OnStart( []( T_SRDParserData const& data ) -> bool { + *( data.currentData ) = NewShared< T_SyncOverrideSection >( "*" ); + return true; + } ); + + defs.context( "root" ) + << ( Rule() << "section" << Text( ) << EnterContext( "section" ) + << OnEnter( EnterSection_ ) + << OnExit( ExitSection_ ) ) + ; + defs.context( "section" ) + << ( Rule() << "section" << Text( ) << EnterContext( "section" ) ) + // Floating point controls + << ( Rule() << "float" << Text( ) << Word( ) + << EnterContext( "float" ) + << OnEnter( EnterFloat1_ ) + << OnExit( AddFloat_ ) ) + << ( Rule() << "float2" << Text( ) + << ( SRD::Times( 2 ) << Word( ) ) + << EnterContext( "float" ) + << OnEnter( EnterFloat2_ ) + << OnExit( AddFloat_ ) ) + << ( Rule() << "float3" << Text( ) + << ( SRD::Times( 3 ) << Word( ) ) + << EnterContext( "float" ) + << OnEnter( EnterFloat3_ ) + << OnExit( AddFloat_ ) ) + << ( Rule() << "float4" << Text( ) + << ( SRD::Times( 4 ) << Word( ) ) + << EnterContext( "float" ) + << OnEnter( EnterFloat4_ ) + << OnExit( AddFloat_ ) ) + ; + + // Floating point control parameters + defs.context( "float" ) + << ( Rule() << "slider" << FloatSetSlider_ ) + << ( Rule() << "min" << Numeric() << FloatSetMin_ ) + << ( Rule() << "max" << Numeric() << FloatSetMax_ ) + << ( Rule() << "step" << Numeric() << FloatSetStep_ ) + << ( Rule() << "power" << Numeric() << FloatSetPower_ ) + << ( Rule() << "decimals" << Integer() << FloatSetDecimals_ ) + ; + + return T_SRDParserConfig{ defs }; +} + + /*= A_Float ====================================================================*/ bool A_Float::setMin( diff --git a/syncoverrides.hh b/syncoverrides.hh index 0cf134e..b977e7d 100644 --- a/syncoverrides.hh +++ b/syncoverrides.hh @@ -88,5 +88,10 @@ class T_Float4 : public A_Float }; +/*= PARSER CONFIGURATION =======================================================*/ + +// Get a parser configuration that will be able to parse UI override definitions. +ebcl::T_SRDParserConfig GetParserConfig( ); + } // namespace