#include "externals.hh" #include "common.hh" #include "ui.hh" #include "ui-colorgrading.hh" #include "ui-overrides.hh" #include "ui-sync.hh" #include "ui-utilities.hh" #include namespace sov { namespace { char const* BuildLabel_( uint32_t& counter , T_StringBuilder& sb ) noexcept { sb.clear( ) << "##temp label " << counter << '\0'; counter ++; return sb.data( ); } } // namespace A_SyncData::~A_SyncData( ) { } /*= FLOAT OVERRIDES ==========================================================*/ M_DECL_SOVUI( Float ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Float& >( ovp ) }; char const* const label( BuildLabel_( counter , sb ) ); float v{ data[ 0 ] }; const bool changed( ov.slider( ) ? SliderFloat( label , &v , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) : DragFloat( label , &v , ov.step( ) , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) ); if ( changed ) { data.set( 0 , v ); } return changed; } M_DECL_SOVUI( Float2 ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Float2& >( ovp ) }; float v[ 2 ]; for ( auto i = 0 ; i < 2 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderFloat2( label , v , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) : DragFloat2( label , v , ov.step( ) , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 2 ; i ++ ) { data.set( i , v[ i ] ); } } return changed; } M_DECL_SOVUI( Float3 ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Float3& >( ovp ) }; float v[ 3 ]; for ( auto i = 0 ; i < 3 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderFloat3( label , v , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) : DragFloat3( label , v , ov.step( ) , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 3 ; i ++ ) { data.set( i ,v[ i ]); } } return changed; } M_DECL_SOVUI( Float4 ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Float4& >( ovp ) }; float v[ 4 ]; for ( auto i = 0 ; i < 4 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderFloat4( label , v , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) : DragFloat4( label , v , ov.step( ) , ov.min( ) , ov.max( ) , ov.decimals( ) , ov.power( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 4 ; i ++ ) { data.set( i ,v[ i ]); } } return changed; } /*= INTEGER OVERRIDES ========================================================*/ M_DECL_SOVUI( Integer ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Integer& >( ovp ) }; int32_t v = int32_t( data[ 0 ] ); char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderInt( label , &v , ov.min( ) , ov.max( ) ) : DragInt( label , &v , ov.step( ) , ov.min( ) , ov.max( ) ) ); if ( changed ) { data.set( 0 ,v); } return changed; } M_DECL_SOVUI( Integer2 ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Integer2& >( ovp ) }; int32_t v[ 2 ]; for ( auto i = 0 ; i < 2 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderInt2( label , v , ov.min( ) , ov.max( ) ) : DragInt2( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 2 ; i ++ ) { data.set( i ,v[ i ]); } } return changed; } M_DECL_SOVUI( Integer3 ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Integer3& >( ovp ) }; int32_t v[ 3 ]; for ( auto i = 0 ; i < 3 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderInt3( label , v , ov.min( ) , ov.max( ) ) : DragInt3( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 3 ; i ++ ) { data.set( i ,v[ i ]); } } return changed; } M_DECL_SOVUI( Integer4 ) { using namespace ImGui; auto& ov{ dynamic_cast< T_Integer4& >( ovp ) }; int32_t v[ 4 ]; for ( auto i = 0 ; i < 4 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label( BuildLabel_( counter , sb ) ); const bool changed( ov.slider( ) ? SliderInt4( label , v , ov.min( ) , ov.max( ) ) : DragInt4( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); if ( changed ) { for ( auto i = 0 ; i < 4 ; i ++ ) { data.set( i ,v[ i ]); } } return changed; } /*= COLOR GRADING OVERRIDES ==================================================*/ M_DECL_SOVUI( ColorGrading ) { using namespace ImGui; auto& ov{ dynamic_cast< T_ColorGrading& >( ovp ) }; float v[ 3 ]; for ( auto i = 0 ; i < 3 ; i ++ ) { v[ i ] = data[ i ]; } char const* const label{ BuildLabel_( counter , sb ) }; const bool changed{ ColorGradingControls( label , &v[ 0 ] , &v[ 1 ] , &v[ 2 ] , ov.base( ) , ov.unit( ) ) }; if ( changed ) { for ( auto i = 0 ; i < 3 ; i ++ ) { data.set( i ,v[ i ]); } } return changed; } /*= CAMERA OVERRIDES =========================================================*/ namespace { glm::vec3 VectorFromInputs_( T_CamOverride::T_VectorConfig const& vc , A_SyncData const& data ) noexcept { return glm::vec3{ data[ vc.x ] , data[ vc.y ] , data[ vc.z ] }; } void InputsFromVector_( T_CamOverride::T_VectorConfig const& vc , A_SyncData& data , glm::vec3 const& v ) noexcept { data.set( vc.x ,v.x); data.set( vc.y ,v.y); data.set( vc.z ,v.z); } /*------------------------------------------------------------------------------*/ struct T_MouseCam_ : public virtual A_MouseCtrl { T_CameraMouseControl camera; T_CamOverride& ov; T_OwnPtr< A_SyncData > data; T_MouseCam_( T_Camera& cam , T_CamOverride& ov , A_SyncData const& data ) noexcept : camera( cam ) , ov( ov ) , data( data.clone( ) ) { } void handleDragAndDrop( ImVec2 const& move , T_KbdMods modifiers , T_MouseButtons buttons ) noexcept override; void handleWheel( float wheel , T_KbdMods modifiers , T_MouseButtons buttons ) noexcept override; }; /*------------------------------------------------------------------------------*/ void T_MouseCam_::handleDragAndDrop( ImVec2 const& move , T_KbdMods modifiers , T_MouseButtons buttons ) noexcept { if ( !ov.enabled( ) ) { UI::Sync( ).clearMouseDelegate( ); return; } camera.handleDragAndDrop( move , modifiers , buttons ); auto& cam{ camera.camera }; InputsFromVector_( ov.target( ) , *data , cam.lookAt( ) ); if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { InputsFromVector_( ov.angles( ) , *data , cam.angles( ) ); data->set( ov.distance( ) ,cam.distance( )); } else { InputsFromVector_( ov.position( ) , *data , cam.position( ) ); InputsFromVector_( ov.up( ) , *data , cam.upVector( ) ); } } void T_MouseCam_::handleWheel( const float wheel , T_KbdMods modifiers , T_MouseButtons buttons ) noexcept { if ( !ov.enabled( ) ) { UI::Sync( ).clearMouseDelegate( ); return; } camera.handleWheel( wheel , modifiers , buttons ); auto& cam{ camera.camera }; if ( modifiers & E_KbdMod::SHIFT ) { auto const& fc( ov.fovConfig( ) ); if ( fc.mode == T_CamOverride::FM_FOV ) { data->set( fc.inputIndex ,cam.fieldOfView( )); } else { data->set( fc.inputIndex ,cam.nearPlane( )); } } else { InputsFromVector_( ov.target( ) , *data , cam.lookAt( ) ); if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { InputsFromVector_( ov.angles( ) , *data , cam.angles( ) ); data->set( ov.distance( ) ,cam.distance( )); } else { InputsFromVector_( ov.position( ) , *data , cam.position( ) ); InputsFromVector_( ov.up( ) , *data , cam.upVector( ) ); } } } } // namespace M_DECL_SOVUI( Camera ) { auto& ov{ dynamic_cast< T_CamOverride& >( ovp ) }; auto& camera{ ov.camData( ) }; auto const& fc{ ov.fovConfig( ) }; if ( !ov.enabled( ) || !ov.prevEnabled( ) ) { // Set field of view / near plane if ( fc.mode == T_CamOverride::FM_FOV ) { camera.fieldOfView( data[ fc.inputIndex ] ); } else { camera.nearPlane( data[ fc.inputIndex ] ); } // Set camera parameters const glm::vec3 lookAt{ VectorFromInputs_( ov.target( ) , data ) }; if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { const glm::vec3 angles{ VectorFromInputs_( ov.angles( ) , data ) }; const float distance{ data[ ov.distance( ) ] }; camera.camera( lookAt , angles , distance ); } else { const glm::vec3 position{ VectorFromInputs_( ov.position( ) , data ) }; const glm::vec3 up{ VectorFromInputs_( ov.up( ) , data ) }; camera.camera( lookAt , position , up ); } } ov.prevEnabled( ) = ov.enabled( ); // Draw UI char const* const name( BuildLabel_( counter , sb ) ); auto& sui{ UI::Sync( ) }; bool mouseHandler{ sui.isCurrentDelegate( ov.id( ) ) }; using namespace ImGui; PushItemWidth( 0 ); // Compensate for -1 PushID( GetCurrentWindow( )->GetID( name ) ); const bool handlerChanged{ Checkbox( "Mouse control" , &mouseHandler ) }; Separator( ); const auto changes{ CameraUI( camera ) }; PopID( ); PopItemWidth( ); if ( handlerChanged ) { if ( mouseHandler ) { sui.delegateMouse( ov.id( ) , NewOwned< T_MouseCam_ >( camera , ov , data ) ); } else { sui.clearMouseDelegate( ); } } // Update values if ( changes & E_CameraChange::FOV ) { if ( fc.mode == T_CamOverride::FM_FOV ) { data.set( fc.inputIndex ,camera.fieldOfView( )); } else { data.set( fc.inputIndex ,camera.nearPlane( )); } } if ( changes & E_CameraChange::MATRIX ) { InputsFromVector_( ov.target( ) , data , camera.lookAt( ) ); if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { InputsFromVector_( ov.angles( ) , data , camera.angles( ) ); data.set( ov.distance( ) ,camera.distance( )); } else { InputsFromVector_( ov.position( ) , data , camera.position( ) ); InputsFromVector_( ov.up( ) , data , camera.upVector( ) ); } } return changes; } } // namespace sov