diff --git a/camera.hh b/camera.hh index 0c85e89..eb1ae52 100644 --- a/camera.hh +++ b/camera.hh @@ -63,7 +63,7 @@ struct T_Camera glm::vec3 const& angles , float distance ) noexcept; void camera( glm::vec3 const& position , - glm::vec3 const& directionOrTarget , + glm::vec3 const& target , glm::vec3 const& up ) noexcept; private: diff --git a/demo.srd b/demo.srd index 07c7682..358f820 100644 --- a/demo.srd +++ b/demo.srd @@ -86,6 +86,11 @@ (int "Correction steps" raymarcher-correction (min 0) (max 100) (slider)) ) + (camera "Camera" + (near-plane camera-nearplane) + (position camera-pos-x camera-pos-y camera-pos-z) + (up camera-up-x camera-up-y camera-up-z) + (look-at camera-lookat-x camera-lookat-y camera-lookat-z)) (float "Fog" fog (min 0) (max 1) (step .000005) (decimals 5)) ) diff --git a/syncoverrides.cc b/syncoverrides.cc index 6d301b6..6223754 100644 --- a/syncoverrides.cc +++ b/syncoverrides.cc @@ -328,6 +328,135 @@ bool CgSetUnit_( T_SRDParserData const& data ) 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 /*------------------------------------------------------------------------------*/ @@ -398,6 +527,10 @@ ebcl::T_SRDParserConfig sov::GetParserConfig( ) << EnterContext( "color-grading" ) << OnEnter( EnterColorGrading_ ) << OnExit( AddColorGrading_ ) ) + // Camera controls + << ( Rule() << "camera" << Text( ) << EnterContext( "camera" ) + << OnEnter( EnterCam_ ) + << OnExit( ExitCam_ ) ) ; // Floating point control parameters @@ -424,6 +557,22 @@ ebcl::T_SRDParserConfig sov::GetParserConfig( ) << ( 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 }; } @@ -838,3 +987,142 @@ bool T_ColorGrading::setUnit( assert( v != 0 ); M_SETOPT_( unit_ , v ); } + + +/*= T_CamOverride ==============================================================*/ + +T_CamOverride::T_CamOverride( + T_String const& title ) noexcept + : A_SyncOverride( "cam" , title ) , + camMode_( CM_INVALID ) +{} + +/*------------------------------------------------------------------------------*/ + +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 +{ +#warning implement the fuck +} diff --git a/syncoverrides.hh b/syncoverrides.hh index da23bf6..6dc3897 100644 --- a/syncoverrides.hh +++ b/syncoverrides.hh @@ -1,5 +1,6 @@ #pragma once #include "sync.hh" +#include "camera.hh" namespace sov { @@ -211,6 +212,115 @@ class T_ColorGrading : public A_SyncOverride }; +/*= CAMERA CONTROLS ============================================================*/ + +class T_CamOverride : public A_SyncOverride +{ + public: + enum E_SetState { + S_OK , // Inputs were set + S_DEF , // Duplicate definition + S_INPUTS , // Duplicate inputs + }; + + private: + enum E_CamMode_ { + CM_INVALID , + CM_ANGLES , + CM_VECTORS + }; + + enum E_FovMode_ { + FM_INVALID , + FM_FOV , + FM_NEARPLANE , + }; + + struct T_FovConfig_ + { + E_FovMode_ mode; + uint32_t inputIndex; + + T_FovConfig_( E_FovMode_ mode , uint32_t idx ) noexcept + : mode( mode ) , inputIndex( idx ) + { assert( mode != FM_INVALID ); } + }; + + struct T_VectorConfig_ + { + uint32_t x , y , z; + + T_VectorConfig_( uint32_t x , uint32_t y , uint32_t z ) noexcept + : x(x),y(y),z(z) + {} + }; + + T_Optional< T_FovConfig_ > fovConfig_; + T_Optional< T_VectorConfig_ > target_; + + T_Optional< T_VectorConfig_ > upVector_; + T_Optional< T_VectorConfig_ > position_; + + T_Optional< T_VectorConfig_ > angles_; + T_Optional< uint32_t > distance_; + + E_CamMode_ camMode_; + T_Camera camera_; + + public: + T_CamOverride( T_String const& title ) noexcept; + + E_SetState setFieldOfView( + T_String const& input ) noexcept; + E_SetState setNearPlane( + T_String const& input ) noexcept; + + E_SetState setTarget( + T_String const& inX , + T_String const& inY , + T_String const& inZ ) noexcept; + + E_SetState setUpVector( + T_String const& inX , + T_String const& inY , + T_String const& inZ ) noexcept; + E_SetState setPositionVector( + T_String const& inX , + T_String const& inY , + T_String const& inZ ) noexcept; + + E_SetState setAngles( + T_String const& in1 , + T_String const& in2 , + T_String const& in3 ) noexcept; + E_SetState setDistance( + T_String const& input ) noexcept; + + bool isFovConfigured( ) const noexcept + { return fovConfig_; } + bool isTargetConfigured( ) const noexcept + { return target_; } + bool checkValidConfig( ) noexcept; + + T_Camera& camData( ) noexcept + { return camera_; } + T_Camera const& camData( ) const noexcept + { return camera_; } + + private: + E_SetState setVector( + T_Optional< T_VectorConfig_ >& vector , + T_String const& inX , + T_String const& inY , + T_String const& inZ ) noexcept; + + protected: + void makeEditWidgets( + uint32_t& counter , + T_StringBuilder& sb ) noexcept override; +}; + + /*= PARSER CONFIGURATION =======================================================*/ // Get a parser configuration that will be able to parse UI override definitions.