#include "externals.hh" #include "globals.hh" #include "syncoverrides.hh" #include "colorgrading.hh" #include #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; } /*------------------------------------------------------------------------------*/ using SP_Cg = T_SharedPtr< T_ColorGrading >; bool EnterColorGrading_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); SP_Cg ptr{ NewShared< T_ColorGrading >( input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) , input[ 4 ].stringValue( ) , input[ 1 ].stringValue( ) ) }; ptr->location( ) = input[ 0 ].location( ); *( data.targetData ) = std::move( ptr ); return true; } bool AddColorGrading_( T_SRDParserData const& data ) { auto& fl( data.currentData->value< SP_Cg >( ) ); auto& parent( data.targetData->value< SP_Section >( ) ); parent->overrides.add( fl.makeOwned( ) ); return true; } bool CgSetBase_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); if ( !data.currentData->value< SP_Cg >( )->setBase( input[ 1 ].floatValue( ) ) ) { data.errors.add( "duplicate base value" , (*data.input)[ 0 ] ); } return true; } bool CgSetUnit_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); const float v( input[ 1 ].floatValue( ) ); if ( v == 0 ) { data.errors.add( "invalid unit value" , (*data.input)[ 1 ] ); } else if ( !data.currentData->value< SP_Cg >( )->setUnit( v ) ) { data.errors.add( "duplicate unit value" , (*data.input)[ 0 ] ); } return true; } /*------------------------------------------------------------------------------*/ using SP_Cam = T_SharedPtr< T_CamOverride >; bool EnterCam_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); SP_Cam ptr{ NewShared< T_CamOverride >( input[ 1 ].stringValue( ) ) }; ptr->location( ) = input[ 0 ].location( ); *( data.targetData ) = std::move( ptr ); return true; } bool ExitCam_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); auto& parent( data.targetData->value< SP_Section >( ) ); if ( !ov->isFovConfigured( ) ) { data.errors.add( "field of view or near plane missing" , input[ 0 ] ); } if ( !ov->isTargetConfigured( ) ) { data.errors.add( "target vector missing" , input[ 0 ] ); } if ( !ov->checkValidConfig( ) ) { data.errors.add( "invalid camera configuration" , input[ 0 ] ); } parent->overrides.add( ov.makeOwned( ) ); return true; } bool CamSetFov_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setFieldOfView( input[ 1 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "field of view or near plane already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "input already in use" , input[ 1 ] ); } return true; } bool CamSetNP_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setNearPlane( input[ 1 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "field of view or near plane already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "input already in use" , input[ 1 ] ); } return true; } bool CamSetTarget_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setTarget( input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "camera target already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "inputs already in use" , input[ 1 ] ); } return true; } bool CamSetPosition_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setPositionVector( input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "camera position already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "inputs already in use" , input[ 1 ] ); } return true; } bool CamSetUpVector_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setUpVector( input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "'up' vector already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "inputs already in use" , input[ 1 ] ); } return true; } bool CamSetAngles_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setAngles( input[ 1 ].stringValue( ) , input[ 2 ].stringValue( ) , input[ 3 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "camera angles already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "inputs already in use" , input[ 1 ] ); } return true; } bool CamSetDistance_( T_SRDParserData const& data ) { auto const& input( *( data.input ) ); auto& ov( data.currentData->value< SP_Cam >( ) ); const auto s{ ov->setDistance( input[ 1 ].stringValue( ) ) }; if ( s == T_CamOverride::S_DEF ) { data.errors.add( "camera distance already set" , input[ 0 ] ); } else if ( s == T_CamOverride::S_INPUTS ) { data.errors.add( "input already in use" , input[ 1 ] ); } 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_ ) ) // Color grading controls << ( Rule() << "color-grading" << Text( ) << ( SRD::Times( 3 ) << Word( ) ) << EnterContext( "color-grading" ) << OnEnter( EnterColorGrading_ ) << OnExit( AddColorGrading_ ) ) // Camera controls << ( Rule() << "camera" << Text( ) << EnterContext( "camera" ) << OnEnter( EnterCam_ ) << OnExit( ExitCam_ ) ) ; // 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_ ) ; // Color grading controls defs.context( "color-grading" ) << ( Rule() << "base" << Numeric( ) << CgSetBase_ ) << ( Rule() << "unit" << Numeric( ) << CgSetUnit_ ) ; // Camera controls defs.context( "camera" ) << ( Rule() << "fov" << Word() << CamSetFov_ ) << ( Rule() << "near-plane" << Word() << CamSetNP_ ) // << ( Rule() << ( Alt() << "target" << "look-at" ) << ( SRD::Times( 3 ) << Word() ) << CamSetTarget_ ) // << ( Rule() << "position" << ( SRD::Times( 3 ) << Word() ) << CamSetPosition_ ) << ( Rule() << "up" << ( SRD::Times( 3 ) << Word() ) << CamSetUpVector_ ) // << ( Rule() << "angles" << ( SRD::Times( 3 ) << Word() ) << CamSetAngles_ ) << ( Rule() << "distance" << Word() << CamSetDistance_ ) ; 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 ]; } } P_SyncOverride T_Float::clone( ) const noexcept { auto c{ NewOwned< T_Float >( inputs_[ 0 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } } P_SyncOverride T_Float2::clone( ) const noexcept { auto c{ NewOwned< T_Float2 >( inputs_[ 0 ] , inputs_[ 1 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } } P_SyncOverride T_Float3::clone( ) const noexcept { auto c{ NewOwned< T_Float3 >( inputs_[ 0 ] , inputs_[ 1 ] , inputs_[ 2 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } } P_SyncOverride T_Float4::clone( ) const noexcept { auto c{ NewOwned< T_Float4 >( inputs_[ 0 ] , inputs_[ 1 ] , inputs_[ 2 ] , inputs_[ 3 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } P_SyncOverride T_Integer::clone( ) const noexcept { auto c{ NewOwned< T_Integer >( inputs_[ 0 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } } P_SyncOverride T_Integer2::clone( ) const noexcept { auto c{ NewOwned< T_Integer2 >( inputs_[ 0 ] , inputs_[ 1 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } } P_SyncOverride T_Integer3::clone( ) const noexcept { auto c{ NewOwned< T_Integer3 >( inputs_[ 0 ] , inputs_[ 1 ] , inputs_[ 2 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= 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 ]; } } } P_SyncOverride T_Integer4::clone( ) const noexcept { auto c{ NewOwned< T_Integer4 >( inputs_[ 0 ] , inputs_[ 1 ] , inputs_[ 2 ] , inputs_[ 3 ] , &title_[ 0 ] ) }; copyTo( *c ); return c; } /*= T_ColorGrading =============================================================*/ T_ColorGrading::T_ColorGrading( T_String const& iRed , T_String const& iGreen , T_String const& iBlue , T_String const& title ) noexcept : A_SyncOverride( "cg" , title ) { inputs_.add( iRed ); inputs_.add( iGreen ); inputs_.add( iBlue ); } void T_ColorGrading::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{ ColorGradingControls( label , &v[ 0 ] , &v[ 1 ] , &v[ 2 ] , base( ) , unit( ) ) }; if ( changed ) { for ( auto i = 0 ; i < 3 ; i ++ ) { sinp[ inputPos_[ i ] ] = v[ i ]; } } } bool T_ColorGrading::setBase( const float v ) noexcept { M_SETOPT_( base_ , v ); } bool T_ColorGrading::setUnit( const float v ) noexcept { assert( v != 0 ); M_SETOPT_( unit_ , v ); } P_SyncOverride T_ColorGrading::clone( ) const noexcept { auto c{ NewOwned< T_ColorGrading >( inputs_[ 0 ] , inputs_[ 1 ] , inputs_[ 2 ] , &title_[ 0 ] ) }; c->location( ) = location( ); c->base_ = base_; c->unit_ = unit_; return c; } /*= T_CamOverride ==============================================================*/ T_CamOverride::T_CamOverride( T_String const& title ) noexcept : A_SyncOverride( "cam" , title ) , camMode_( CM_INVALID ) {} P_SyncOverride T_CamOverride::clone( ) const noexcept { auto c{ NewOwned< T_CamOverride >( &title_[ 0 ] ) }; c->location( ) = location( ); const auto n{ inputs_.size( ) }; for ( auto i = 0u ; i < n ; i ++ ) { c->inputs_.add( inputs_[ i ] ); } c->fovConfig_ = fovConfig_; c->target_ = target_; c->upVector_ = upVector_; c->position_ = position_; c->angles_ = angles_; c->distance_ = distance_; c->camMode_ = camMode_; return c; } /*------------------------------------------------------------------------------*/ T_CamOverride::E_SetState T_CamOverride::setFieldOfView( T_String const& input ) noexcept { if ( fovConfig_ ) { return S_DEF; } if ( inputs_.contains( input ) ) { return S_INPUTS; } fovConfig_.setNew( FM_FOV , inputs_.size( ) ); inputs_.add( input ); return S_OK; } T_CamOverride::E_SetState T_CamOverride::setNearPlane( T_String const& input ) noexcept { if ( fovConfig_ ) { return S_DEF; } if ( inputs_.contains( input ) ) { return S_INPUTS; } fovConfig_.setNew( FM_NEARPLANE , inputs_.size( ) ); inputs_.add( input ); return S_OK; } /*------------------------------------------------------------------------------*/ T_CamOverride::E_SetState T_CamOverride::setTarget( T_String const& inX , T_String const& inY , T_String const& inZ ) noexcept { return setVector( target_ , inX , inY , inZ ); } /*------------------------------------------------------------------------------*/ T_CamOverride::E_SetState T_CamOverride::setUpVector( T_String const& inX , T_String const& inY , T_String const& inZ ) noexcept { return setVector( upVector_ , inX , inY , inZ ); } T_CamOverride::E_SetState T_CamOverride::setPositionVector( T_String const& inX , T_String const& inY , T_String const& inZ ) noexcept { return setVector( position_ , inX , inY , inZ ); } /*------------------------------------------------------------------------------*/ T_CamOverride::E_SetState T_CamOverride::setAngles( T_String const& in1 , T_String const& in2 , T_String const& in3 ) noexcept { return setVector( angles_ , in1 , in2 , in3 ); } T_CamOverride::E_SetState T_CamOverride::setDistance( T_String const& input ) noexcept { if ( distance_ ) { return S_DEF; } if ( inputs_.contains( input ) ) { return S_INPUTS; } distance_ = inputs_.size( ); inputs_.add( input ); return S_OK; } /*------------------------------------------------------------------------------*/ bool T_CamOverride::checkValidConfig( ) noexcept { if ( camMode_ != CM_INVALID ) { return true; } if ( angles_ && distance_ && !( position_ || upVector_ ) ) { camMode_ = CM_ANGLES; } else if ( position_ && upVector_ && !( angles_ || distance_ ) ) { camMode_ = CM_VECTORS; } return ( camMode_ != CM_INVALID ); } /*------------------------------------------------------------------------------*/ T_CamOverride::E_SetState T_CamOverride::setVector( T_Optional< T_VectorConfig_ >& vector , T_String const& inX , T_String const& inY , T_String const& inZ ) noexcept { if ( vector ) { return S_DEF; } if ( inputs_.contains( inX ) || inputs_.contains( inY ) || inputs_.contains( inZ ) ) { return S_INPUTS; } const uint32_t s( inputs_.size( ) ); vector.setNew( s , s+1 , s+2 ); inputs_.add( inX ); inputs_.add( inY ); inputs_.add( inZ ); return S_OK; } /*------------------------------------------------------------------------------*/ void T_CamOverride::makeEditWidgets( uint32_t& counter , T_StringBuilder& sb ) noexcept { auto& sync( Globals::Sync( ) ); auto& sinp( sync.inputs( ) ); auto const& fc( *fovConfig_ ); if ( !enabled( ) || !prevEnabled_ ) { // Set field of view / near plane if ( fc.mode == FM_FOV ) { camera_.fieldOfView( sinp[ inputPos_[ fc.inputIndex ] ] ); } else { camera_.nearPlane( sinp[ inputPos_[ fc.inputIndex ] ] ); } // Set camera parameters const glm::vec3 lookAt{ vectorFromInputs( *target_ ) }; if ( camMode_ == CM_ANGLES ) { const glm::vec3 angles{ vectorFromInputs( *angles_ ) }; const float distance{ sinp[ inputPos_[ *distance_ ] ] }; camera_.camera( lookAt , angles , distance ); } else { const glm::vec3 position{ vectorFromInputs( *position_ ) }; const glm::vec3 up{ vectorFromInputs( *upVector_ ) }; camera_.camera( lookAt , position , up ); } } prevEnabled_ = enabled( ); // Draw UI char const* const name( buildLabel( counter , sb ) ); bool mouseHandler{ sync.isCurrentDelegate( *this ) }; using namespace ImGui; PushItemWidth( 0 ); // Compensate for -1 PushID( GetCurrentWindow( )->GetID( name ) ); const bool handlerChanged{ Checkbox( "Mouse control" , &mouseHandler ) }; Separator( ); const auto changes{ camera_.makeUI( ) }; PopID( ); PopItemWidth( ); if ( handlerChanged ) { if ( mouseHandler ) { sync.delegateMouse( *this ); } else { sync.clearMouseDelegate( ); } } if ( changes & T_Camera::E_Changes::FOV ) { if ( fc.mode == FM_FOV ) { sinp[ inputPos_[ fc.inputIndex ] ] = camera_.fieldOfView( ); } else { sinp[ inputPos_[ fc.inputIndex ] ] = camera_.nearPlane( ); } } if ( changes & T_Camera::E_Changes::MATRIX ) { inputsFromVector( *target_ , camera_.lookAt( ) ); if ( camMode_ == CM_ANGLES ) { inputsFromVector( *angles_ , camera_.angles( ) ); sinp[ inputPos_[ *distance_ ] ] = camera_.distance( ); } else { inputsFromVector( *position_ , camera_.position( ) ); inputsFromVector( *upVector_ , camera_.upVector( ) ); } } } glm::vec3 T_CamOverride::vectorFromInputs( T_VectorConfig_ const& vc ) noexcept { auto& sinp( Globals::Sync( ).inputs( ) ); return glm::vec3{ sinp[ inputPos_[ vc.x ] ] , sinp[ inputPos_[ vc.y ] ] , sinp[ inputPos_[ vc.z ] ] }; } void T_CamOverride::inputsFromVector( T_VectorConfig_ const& vc , glm::vec3 const& v ) noexcept { auto& sinp( Globals::Sync( ).inputs( ) ); sinp[ inputPos_[ vc.x ] ] = v.x; sinp[ inputPos_[ vc.y ] ] = v.y; sinp[ inputPos_[ vc.z ] ] = v.z; } /*------------------------------------------------------------------------------*/ void T_CamOverride::handleDragAndDrop( ImVec2 const& move , T_KeyboardModifiers modifiers , T_MouseButtons buttons ) noexcept { auto& sync( Globals::Sync( ) ); if ( !enabled( ) ) { sync.clearMouseDelegate( ); return; } camera_.handleDragAndDrop( move , modifiers , buttons ); auto& sinp( sync.inputs( ) ); inputsFromVector( *target_ , camera_.lookAt( ) ); if ( camMode_ == CM_ANGLES ) { inputsFromVector( *angles_ , camera_.angles( ) ); sinp[ inputPos_[ *distance_ ] ] = camera_.distance( ); } else { inputsFromVector( *position_ , camera_.position( ) ); inputsFromVector( *upVector_ , camera_.upVector( ) ); } } void T_CamOverride::handleWheel( const float wheel , T_KeyboardModifiers modifiers , T_MouseButtons buttons ) noexcept { auto& sync( Globals::Sync( ) ); if ( !enabled( ) ) { sync.clearMouseDelegate( ); return; } camera_.handleWheel( wheel , modifiers , buttons ); auto& sinp( sync.inputs( ) ); if ( modifiers & E_KeyboardModifier::SHIFT ) { auto const& fc( *fovConfig_ ); if ( fc.mode == FM_FOV ) { sinp[ inputPos_[ fc.inputIndex ] ] = camera_.fieldOfView( ); } else { sinp[ inputPos_[ fc.inputIndex ] ] = camera_.nearPlane( ); } } else { inputsFromVector( *target_ , camera_.lookAt( ) ); if ( camMode_ == CM_ANGLES ) { inputsFromVector( *angles_ , camera_.angles( ) ); sinp[ inputPos_[ *distance_ ] ] = camera_.distance( ); } else { inputsFromVector( *position_ , camera_.position( ) ); inputsFromVector( *upVector_ , camera_.upVector( ) ); } } }