diff --git a/Changes.md b/Changes.md index 894cc9ab84c..501f1eba0c7 100644 --- a/Changes.md +++ b/Changes.md @@ -4,6 +4,7 @@ Improvements ------------ +- Added support for camera guides (action safe, title safe and rule of thirds). - Instancer : - Added `inactiveIds` plug for selecting primitive variables to disable some instances. - Added support for 64 bit integer ids (matching what is loaded from USD). diff --git a/python/GafferSceneUI/SceneViewUI.py b/python/GafferSceneUI/SceneViewUI.py index 93d365ce54c..0e152ae1412 100644 --- a/python/GafferSceneUI/SceneViewUI.py +++ b/python/GafferSceneUI/SceneViewUI.py @@ -801,6 +801,36 @@ def __menuDefinition( self ) : } ) + # BHGC START + + m.append( "/GuidesDivider", { "divider" : True } ) + + # might be possible to have a list of all guides and iterate over that, doing one by one for now: + + m.append( + "/Guides/Action Safe", + { + "checkBox" : self.getPlug()["actionSafeEnabled"].getValue(), + "command" : self.getPlug()["actionSafeEnabled"].setValue, + } + ) + m.append( + "/Guides/Title Safe", + { + "checkBox" : self.getPlug()["titleSafeEnabled"].getValue(), + "command" : self.getPlug()["titleSafeEnabled"].setValue, + } + ) + m.append( + "/Guides/Rule of Thirds", + { + "checkBox" : self.getPlug()["customGridEnabled"].getValue(), + "command" : self.getPlug()["customGridEnabled"].setValue, + } + ) + + # BHGC END + m.append( "/BrowseDivider", { "divider" : True } ) m.append( diff --git a/src/GafferSceneUI/SceneView.cpp b/src/GafferSceneUI/SceneView.cpp index 6d9a57e112e..ba020d7b7ef 100644 --- a/src/GafferSceneUI/SceneView.cpp +++ b/src/GafferSceneUI/SceneView.cpp @@ -1081,6 +1081,43 @@ class CameraOverlay : public GafferUI::Gadget dirty( DirtyType::Render ); } + // BHGC START + + // separate functions/variables for each guide, should probably combine all this + // i just copied the resolution/aperture gate syntax, not sure if this is ideal + + void actionSafeEnabled( const bool &actionSafeEnabled ) + { + if( actionSafeEnabled == m_actionSafeEnabled ) + { + return; + } + m_actionSafeEnabled = actionSafeEnabled; + dirty( DirtyType::Render ); + } + + void titleSafeEnabled( const bool &titleSafeEnabled ) + { + if( titleSafeEnabled == m_titleSafeEnabled ) + { + return; + } + m_titleSafeEnabled = titleSafeEnabled; + dirty( DirtyType::Render ); + } + + void customGridEnabled( const bool &customGridEnabled ) + { + if( customGridEnabled == m_customGridEnabled ) + { + return; + } + m_customGridEnabled = customGridEnabled; + dirty( DirtyType::Render ); + } + + // BHGC END + const std::string &getIcon() const { return m_icon; @@ -1140,8 +1177,66 @@ class CameraOverlay : public GafferUI::Gadget { glEnable( GL_LINE_SMOOTH ); glLineWidth( 1.5f ); + glColor4f( 0, 0.25, 0, 1.0f ); + + // BHGC START + + // stipple looks good, but it doesn't work becuase the customGrid edges overlap + + // glEnable( GL_LINE_STIPPLE ); + // glLineStipple(1, 0x00FF); + + V2f gateDiff = V2f( m_resolutionGate.max - m_resolutionGate.min ); + + V2f titlePercent = gateDiff * V2f( std::sqrt( 0.8 ) ); + V2f actionPercent = gateDiff * V2f( std::sqrt( 0.9 ) ); + + titlePercent = ( gateDiff - titlePercent ) / 2; + actionPercent = ( gateDiff - actionPercent ) / 2; + + if( m_titleSafeEnabled ) + { + Box2f titleSafe = Box2f( ( m_resolutionGate.min + titlePercent ), ( m_resolutionGate.max - titlePercent ) ); + + style->renderRectangle( titleSafe ); + } + + if( m_actionSafeEnabled ) + { + Box2f actionSafe = Box2f( ( m_resolutionGate.min + actionPercent ), ( m_resolutionGate.max - actionPercent ) ); + + style->renderRectangle( actionSafe ); + } + + // custom grid divisions, 3x3 is rule of thirds + + int div_h = 3; + int div_v = 3; + + if( m_customGridEnabled ) + { + V2f fraction = V2f( gateDiff / V2f( div_h, div_v ) ); + vector customGrid; + customGrid.reserve( div_h * div_v ); // I read that this is galaxy brain C++, maybe not needed, haha + + for( int v = 0; v < div_v; v++ ) + { + for( int h = 0; h < div_h; h++ ) + { + customGrid.push_back( Box2f( m_resolutionGate.min + ( fraction * V2f( h, v ) ), m_resolutionGate.min + ( fraction * V2f( h, v ) ) + fraction ) ); + } + } + + for( const auto &i : customGrid ) + { + style->renderRectangle( i ); + } + } + + // glDisable( GL_LINE_STIPPLE ); + + // BHGC END - glColor4f( 0.5, 0.5, 0.5, 0.5 ); style->renderRectangle( Box2f( V2f( lerp( m_resolutionGate.min.x, m_resolutionGate.max.x, m_cropWindow.min.x ), @@ -1153,7 +1248,7 @@ class CameraOverlay : public GafferUI::Gadget ) ) ); - glColor4f( 0, 0.25, 0, 1.0f ); + //glColor4f( 0, 0.25, 0, 1.0f ); style->renderRectangle( m_resolutionGate ); if( m_overscan[0] != 0.0f || m_overscan[1] != 0.0f || m_overscan[2] != 0.0f || m_overscan[3] != 0.0f ) @@ -1228,6 +1323,14 @@ class CameraOverlay : public GafferUI::Gadget std::string m_caption; std::string m_icon; + // BHGC START + + bool m_actionSafeEnabled; + bool m_titleSafeEnabled; + bool m_customGridEnabled; + + // BHGC END + }; IE_CORE_DECLAREPTR( CameraOverlay ) @@ -1382,6 +1485,16 @@ class SceneView::Camera : public Signals::Trackable ) ); + // BHGC START + + // create plugs for each guide, combine these three into one? + + plug->addChild( new BoolPlug( "actionSafeEnabled", Plug::In, false, Plug::Default & ~Plug::AcceptsInputs ) ); + plug->addChild( new BoolPlug( "titleSafeEnabled", Plug::In, false, Plug::Default & ~Plug::AcceptsInputs ) ); + plug->addChild( new BoolPlug( "customGridEnabled", Plug::In, false, Plug::Default & ~Plug::AcceptsInputs ) ); + + // BHGC END + view->addChild( plug ); // Set up our nodes. @@ -1526,6 +1639,25 @@ class SceneView::Camera : public Signals::Trackable return plug()->getChild( 6 ); } + // BHGC START + + const Gaffer::BoolPlug *titleSafeEnabledPlug() const + { + return plug()->getChild( "titleSafeEnabled" ); + } + + const Gaffer::BoolPlug *actionSafeEnabledPlug() const + { + return plug()->getChild( "actionSafeEnabled" ); + } + + const Gaffer::BoolPlug *customGridEnabledPlug() const + { + return plug()->getChild( "customGridEnabled" ); + } + + // BHGC END + SceneGadget *sceneGadget() { return static_cast( m_view->viewportGadget()->getPrimaryChild() ); @@ -1569,6 +1701,8 @@ class SceneView::Camera : public Signals::Trackable return; } + // BHGC - added the guides here, i assume that's needed in order to redraw things when they're turned on and off? + if( plug == scenePlug()->childNamesPlug() || plug == scenePlug()->globalsPlug() || @@ -1576,7 +1710,10 @@ class SceneView::Camera : public Signals::Trackable plug == scenePlug()->transformPlug() || plug == lookThroughEnabledPlug() || plug == lookThroughCameraPlug() || - plug == freeCameraPlug() + plug == freeCameraPlug() || + plug == actionSafeEnabledPlug() || // BHGC + plug == titleSafeEnabledPlug() || // BHGC + plug == customGridEnabledPlug() // BHGC ) { m_lookThroughCameraDirty = m_viewportCameraDirty = true; @@ -1867,6 +2004,17 @@ class SceneView::Camera : public Signals::Trackable ( apertureGate.min - viewportScreenWindow.min ) / viewportScreenWindow.size() * viewport, ( apertureGate.max - viewportScreenWindow.min ) / viewportScreenWindow.size() * viewport ) ); + + // BHGC START + + // draw the guides, combine these three into one? + + m_overlay->actionSafeEnabled( m_view->cameraPlug()->getChild( "actionSafeEnabled" )->getValue() ); + m_overlay->titleSafeEnabled( m_view->cameraPlug()->getChild( "titleSafeEnabled" )->getValue() ); + m_overlay->customGridEnabled( m_view->cameraPlug()->getChild( "customGridEnabled" )->getValue() ); + + // BHGC END + m_overlay->setVisible( true ); // Now set up a camera that can see all of the aperture and resolution gates.