#include "externals.hh" #include "globals.hh" #include "syncoverrides.hh" #include using namespace sov; #define M_SETOPT_( FIELD , VAR ) \ if ( FIELD ) { return false; } \ FIELD = (VAR); \ 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[ 2 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; ptr->location( ) = input[ 0 ].location( ); *( 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[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; if ( ptr->inputNames( ).size( ) != 2 ) { data.errors.add( "duplicate input names" , input[ 3 ].location( ) ); } ptr->location( ) = input[ 0 ].location( ); *( 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[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; if ( ptr->inputNames( ).size( ) != 3 ) { data.errors.add( "duplicate input names" , input[ 3 ].location( ) ); } ptr->location( ) = input[ 0 ].location( ); *( 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[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) , input[ 5 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; if ( ptr->inputNames( ).size( ) != 4 ) { data.errors.add( "duplicate input names" , input[ 3 ].location( ) ); } ptr->location( ) = input[ 0 ].location( ); *( 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 > 20 ) { 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; } /*------------------------------------------------------------------------------*/ using SP_Int = T_SharedPtr< A_Integer >; bool EnterInt1_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); SP_Int ptr{ NewShared< T_Integer >( input[ 2 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; ptr->location( ) = input[ 0 ].location( ); *( data.targetData ) = std::move( ptr ); return true; } bool EnterInt2_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); SP_Int ptr{ NewShared< T_Integer2 >( input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; if ( ptr->inputNames( ).size( ) != 2 ) { data.errors.add( "duplicate input names" , input[ 3 ].location( ) ); } ptr->location( ) = input[ 0 ].location( ); *( data.targetData ) = std::move( ptr ); return true; } bool EnterInt3_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); SP_Int ptr{ NewShared< T_Integer3 >( input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; if ( ptr->inputNames( ).size( ) != 3 ) { data.errors.add( "duplicate input names" , input[ 3 ].location( ) ); } ptr->location( ) = input[ 0 ].location( ); *( data.targetData ) = std::move( ptr ); return true; } bool EnterInt4_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); SP_Int ptr{ NewShared< T_Integer4 >( input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) , input[ 5 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; if ( ptr->inputNames( ).size( ) != 4 ) { data.errors.add( "duplicate input names" , input[ 3 ].location( ) ); } ptr->location( ) = input[ 0 ].location( ); *( data.targetData ) = std::move( ptr ); return true; } bool AddInt_( T_SRDParserData const& data ) { auto& fl( data.currentData->value< SP_Int >( ) ); 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 IntSetSlider_( T_SRDParserData const& data ) { data.currentData->value< SP_Int >( )->setSlider( ); return true; } bool IntSetMin_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); if ( !data.currentData->value< SP_Int >( )->setMin( input[ 1 ].longValue( ) ) ) { data.errors.add( "duplicate minimal value" , (*data.input)[ 0 ] ); } return true; } bool IntSetMax_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); if ( !data.currentData->value< SP_Int >( )->setMax( input[ 1 ].longValue( ) ) ) { data.errors.add( "duplicate maximal value" , (*data.input)[ 0 ] ); } return true; } bool IntSetStep_( 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_Int >( )->setStep( v ) ) { data.errors.add( "duplicate step 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" ) << OnEnter( EnterSection_ ) << OnExit( ExitSection_ ) ) // 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_ ) ) // Integer controls << ( Rule() << "int" << Text( ) << Word( ) << EnterContext( "int" ) << OnEnter( EnterInt1_ ) << OnExit( AddInt_ ) ) << ( Rule() << "int2" << Text( ) << ( SRD::Times( 2 ) << Word( ) ) << EnterContext( "int" ) << OnEnter( EnterInt2_ ) << OnExit( AddInt_ ) ) << ( Rule() << "int3" << Text( ) << ( SRD::Times( 3 ) << Word( ) ) << EnterContext( "int" ) << OnEnter( EnterInt3_ ) << OnExit( AddInt_ ) ) << ( Rule() << "int4" << Text( ) << ( SRD::Times( 4 ) << Word( ) ) << EnterContext( "int" ) << OnEnter( EnterInt4_ ) << OnExit( AddInt_ ) ) ; // 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_ ) ; // Integer control parameters defs.context( "int" ) << ( Rule() << "slider" << IntSetSlider_ ) << ( Rule() << "min" << Int32() << IntSetMin_ ) << ( Rule() << "max" << Int32() << IntSetMax_ ) << ( Rule() << "step" << Numeric() << IntSetStep_ ) ; return T_SRDParserConfig{ defs }; } /*= A_Float ====================================================================*/ bool A_Float::setMin( const float v ) noexcept { M_SETOPT_( min_ , v ); } bool A_Float::setMax( const float v ) noexcept { M_SETOPT_( max_ , v ); } bool A_Float::setStep( const float v ) noexcept { assert( v > 0 ); M_SETOPT_( step_ , v ); } bool A_Float::setDecimals( const uint32_t n ) noexcept { assert( n >= 0 && n <= 20 ); if ( decimals_ ) { return false; } T_StringBuilder sb; sb << "%." << n << 'f' << '\0'; assert( sb.size( ) < 12 ); decimals_.setNew( ); for ( auto i = 0u ; i < sb.size( ) ; i ++ ) { decimals_->add( sb.data( )[ i ] ); } return true; } bool A_Float::setPower( const float v ) noexcept { assert( v != 0 ); M_SETOPT_( power_ , v ); } void A_Float::setSlider( ) noexcept { slider_ = true; } /*= T_Float ====================================================================*/ T_Float::T_Float( T_String const& input , T_String const& title ) noexcept : A_Float( "float" , title ) { inputs_.add( input ); } void T_Float::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; float v[ 1 ] = { Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] }; char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderFloat( label , v , min( ) , max( ) , decimals( ) , power( ) ) : DragFloat( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); if ( changed ) { Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] = v[ 0 ]; } } /*= T_Float2 ===================================================================*/ T_Float2::T_Float2( T_String const& input0 , T_String const& input1 , T_String const& title ) noexcept : A_Float( "float2" , title ) { inputs_.add( input0 ); inputs_.add( input1 ); } void T_Float2::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; auto& sinp( Globals::Sync( ).inputs( ) ); float v[ 2 ]; for ( auto i = 0 ; i < 2 ; i ++ ) { v[ i ] = sinp[ inputPos_[ i ] ]; } char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderFloat2( label , v , min( ) , max( ) , decimals( ) , power( ) ) : DragFloat2( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 2 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } } /*= T_Float3 ===================================================================*/ T_Float3::T_Float3( T_String const& input0 , T_String const& input1 , T_String const& input2 , T_String const& title ) noexcept : A_Float( "float3" , title ) { inputs_.add( input0 ); inputs_.add( input1 ); inputs_.add( input2 ); } void T_Float3::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; auto& sinp( Globals::Sync( ).inputs( ) ); float v[ 3 ]; for ( auto i = 0 ; i < 3 ; i ++ ) { v[ i ] = sinp[ inputPos_[ i ] ]; } char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderFloat3( label , v , min( ) , max( ) , decimals( ) , power( ) ) : DragFloat3( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 3 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } } /*= T_Float4 ===================================================================*/ T_Float4::T_Float4( T_String const& input0 , T_String const& input1 , T_String const& input2 , T_String const& input3 , T_String const& title ) noexcept : A_Float( "float4" , title ) { inputs_.add( input0 ); inputs_.add( input1 ); inputs_.add( input2 ); inputs_.add( input3 ); } void T_Float4::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; auto& sinp( Globals::Sync( ).inputs( ) ); float v[ 4 ]; for ( auto i = 0 ; i < 4 ; i ++ ) { v[ i ] = sinp[ inputPos_[ i ] ]; } char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderFloat4( label , v , min( ) , max( ) , decimals( ) , power( ) ) : DragFloat4( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 4 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } } /*= A_Integer ==================================================================*/ bool A_Integer::setMin( const int32_t v ) noexcept { M_SETOPT_( min_ , v ); } bool A_Integer::setMax( const int32_t v ) noexcept { M_SETOPT_( max_ , v ); } bool A_Integer::setStep( const float v ) noexcept { assert( v > 0 ); M_SETOPT_( step_ , v ); } void A_Integer::setSlider( ) noexcept { slider_ = true; } /*= T_Integer ==================================================================*/ T_Integer::T_Integer( T_String const& input , T_String const& title ) noexcept : A_Integer( "int" , title ) { inputs_.add( input ); } void T_Integer::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; int32_t v[ 1 ] = { int32_t( Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] ) }; char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderInt( label , v , min( ) , max( ) ) : DragInt( label , v , step( ) , min( ) , max( ) ) ); if ( changed ) { Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] = v[ 0 ]; } } /*= T_Integer2 =================================================================*/ T_Integer2::T_Integer2( T_String const& input0 , T_String const& input1 , T_String const& title ) noexcept : A_Integer( "int2" , title ) { inputs_.add( input0 ); inputs_.add( input1 ); } void T_Integer2::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; auto& sinp( Globals::Sync( ).inputs( ) ); int32_t v[ 2 ]; for ( auto i = 0 ; i < 2 ; i ++ ) { v[ i ] = sinp[ inputPos_[ i ] ]; } char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderInt2( label , v , min( ) , max( ) ) : DragInt2( label , v , step( ) , min( ) , max( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 2 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } } /*= T_Integer3 =================================================================*/ T_Integer3::T_Integer3( T_String const& input0 , T_String const& input1 , T_String const& input2 , T_String const& title ) noexcept : A_Integer( "int3" , title ) { inputs_.add( input0 ); inputs_.add( input1 ); inputs_.add( input2 ); } void T_Integer3::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; auto& sinp( Globals::Sync( ).inputs( ) ); int32_t v[ 3 ]; for ( auto i = 0 ; i < 3 ; i ++ ) { v[ i ] = sinp[ inputPos_[ i ] ]; } char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderInt3( label , v , min( ) , max( ) ) : DragInt3( label , v , step( ) , min( ) , max( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 3 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } } /*= T_Integer4 =================================================================*/ T_Integer4::T_Integer4( T_String const& input0 , T_String const& input1 , T_String const& input2 , T_String const& input3 , T_String const& title ) noexcept : A_Integer( "int4" , title ) { inputs_.add( input0 ); inputs_.add( input1 ); inputs_.add( input2 ); inputs_.add( input3 ); } void T_Integer4::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; auto& sinp( Globals::Sync( ).inputs( ) ); int32_t v[ 4 ]; for ( auto i = 0 ; i < 4 ; i ++ ) { v[ i ] = sinp[ inputPos_[ i ] ]; } char const* const label( buildLabel( counter , sb ) ); const bool changed( slider( ) ? SliderInt4( label , v , min( ) , max( ) ) : DragInt4( label , v , step( ) , min( ) , max( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 4 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } }