Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render Pass Menu #6177

Open
wants to merge 10 commits into
base: 1.5_maintenance
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ API
---

- PlugLayout : Activations may now depend on the presence of certain plugs, as they are now reevaluated when child plugs are added and removed.
- ScriptNodeAlgo : Added `setCurrentRenderPass()`, `getCurrentRenderPass()`, and `acquireRenderPassPlug()` methods.

1.5.1.0 (relative to 1.5.0.1)
=======
Expand Down
11 changes: 11 additions & 0 deletions include/GafferSceneUI/ScriptNodeAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

#include "GafferScene/VisibleSet.h"

#include "Gaffer/NameValuePlug.h"
#include "Gaffer/Signals.h"

#include "IECore/PathMatcher.h"
Expand Down Expand Up @@ -112,6 +113,16 @@ GAFFERSCENEUI_API std::vector<IECore::InternedString> getLastSelectedPath( const
/// Returns a signal emitted when either the selected paths or last selected path change for `script`.
GAFFERSCENEUI_API ChangedSignal &selectedPathsChangedSignal( Gaffer::ScriptNode *script );

/// Render Passes
/// =============

/// Acquires a plug used to specify the current render pass for the script.
GAFFERSCENEUI_API Gaffer::NameValuePlug *acquireRenderPassPlug( Gaffer::ScriptNode *script, bool createIfMissing = true );
/// Sets the current render pass for the script.
GAFFERSCENEUI_API void setCurrentRenderPass( Gaffer::ScriptNode *script, std::string renderPass );
/// Returns the current render pass for the script.
GAFFERSCENEUI_API std::string getCurrentRenderPass( const Gaffer::ScriptNode *script );

} // namespace ScriptNodeAlgo

} // namespace GafferSceneUI
15 changes: 4 additions & 11 deletions python/GafferSceneUI/RenderPassEditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,17 +360,10 @@ def __setActiveRenderPass( self, pathListing ) :
self.__popup.popup( parent = self )
return

## \todo Perhaps we should add `ScriptNodeAlgo.set/getCurrentRenderPass()`
# to wrap this up for general consumption?
if "renderPass" not in script["variables"] :
renderPassPlug = Gaffer.NameValuePlug( "renderPass", "", "renderPass", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
script["variables"].addChild( renderPassPlug )
Gaffer.MetadataAlgo.setReadOnly( renderPassPlug["name"], True )
else :
renderPassPlug = script["variables"]["renderPass"]

currentRenderPass = renderPassPlug["value"].getValue()
renderPassPlug["value"].setValue( selectedPassNames[0] if selectedPassNames[0] != currentRenderPass else "" )
GafferSceneUI.ScriptNodeAlgo.setCurrentRenderPass(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be wrapped in an UndoScope? It wasn't before, and it does kindof feel like "UI state" that you wouldn't expect to be undoable, but it is actually editing a plug in the script, which generally speaking should be undoable.

script,
selectedPassNames[0] if selectedPassNames[0] != GafferSceneUI.ScriptNodeAlgo.getCurrentRenderPass( script ) else ""
)

def __columnContextMenuSignal( self, column, pathListing, menuDefinition ) :

Expand Down
59 changes: 58 additions & 1 deletion python/GafferSceneUITest/ScriptNodeAlgoTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#
# * Neither the name of John Haddon nor the names of
# any other contributors to this software may be used to endorse or
# promote products derived from this software without specifiscript prior
# promote products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
Expand Down Expand Up @@ -204,5 +204,62 @@ def testVisibleSetExpansionUtilities( self ) :
self.assertEqual( GafferSceneUI.ScriptNodeAlgo.getVisibleSet( script ).expansions, IECore.PathMatcher( [ "/", "/A", "/A/C" ] ) )
self.assertEqual( newLeafs, IECore.PathMatcher( [ "/A/C/G", "/A/C/F" ] ) )

def testAcquireRenderPassPlug( self ) :

s1 = Gaffer.ScriptNode()
s2 = Gaffer.ScriptNode()

self.assertIsNone( GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug( s1, createIfMissing = False ) )

p1A = GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug( s1 )
p1B = GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug( s1 )

p2A = GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug( s2 )
p2B = GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug( s2 )

self.assertIsNotNone( p1A )
self.assertIsNotNone( p2A )

self.assertTrue( p1A.isSame( p1B ) )
self.assertTrue( p2A.isSame( p2B ) )
self.assertFalse( p1A.isSame( p2A ) )

def testAcquireManuallyCreatedRenderPassPlug( self ) :

s = Gaffer.ScriptNode()
s["variables"]["renderPass"] = Gaffer.NameValuePlug( "renderPass", "", "renderPass" )

self.assertTrue( GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug( s ).isSame( s["variables"]["renderPass"] ) )

s1 = Gaffer.ScriptNode()
s1["variables"]["renderPass"] = Gaffer.NameValuePlug( "renderPass", IECore.IntData( 0 ), "renderPass" )

self.assertRaises( IECore.Exception, GafferSceneUI.ScriptNodeAlgo.acquireRenderPassPlug, s1 )

def testSetCurrentRenderPass( self ) :

script = Gaffer.ScriptNode()
self.assertNotIn( "renderPass", script["variables"] )

GafferSceneUI.ScriptNodeAlgo.setCurrentRenderPass( script, "testA" )
self.assertIn( "renderPass", script["variables"] )
self.assertEqual( "testA", script["variables"]["renderPass"]["value"].getValue() )

script2 = Gaffer.ScriptNode()
script2["variables"]["renderPass"] = Gaffer.NameValuePlug( "renderPass", 123.0, "renderPass" )
self.assertRaises( IECore.Exception, GafferSceneUI.ScriptNodeAlgo.setCurrentRenderPass, script2, "testB" )

def testGetCurrentRenderPass( self ) :

script = Gaffer.ScriptNode()
self.assertEqual( "", GafferSceneUI.ScriptNodeAlgo.getCurrentRenderPass( script ) )

GafferSceneUI.ScriptNodeAlgo.setCurrentRenderPass( script, "testA" )
self.assertEqual( "testA", GafferSceneUI.ScriptNodeAlgo.getCurrentRenderPass( script ) )

script2 = Gaffer.ScriptNode()
script2["variables"]["renderPass"] = Gaffer.NameValuePlug( "renderPass", 123.0, "renderPass" )
self.assertRaises( IECore.Exception, GafferSceneUI.ScriptNodeAlgo.getCurrentRenderPass, script2 )

if __name__ == "__main__":
unittest.main()
49 changes: 49 additions & 0 deletions src/GafferSceneUI/ScriptNodeAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@

#include "Gaffer/Context.h"
#include "Gaffer/ScriptNode.h"
#include "Gaffer/NameValuePlug.h"
#include "Gaffer/CompoundDataPlug.h"
#include "Gaffer/MetadataAlgo.h"

#include "boost/bind/bind.hpp"

Expand Down Expand Up @@ -146,5 +149,51 @@ std::vector<IECore::InternedString> ScriptNodeAlgo::getLastSelectedPath( const G
ScriptNodeAlgo::ChangedSignal &ScriptNodeAlgo::selectedPathsChangedSignal( Gaffer::ScriptNode *script )
{
return changedSignals( script ).selectedPathsChangedSignal;
}

NameValuePlug *ScriptNodeAlgo::acquireRenderPassPlug( Gaffer::ScriptNode *script, bool createIfMissing )
{
for( NameValuePlug::Iterator it( script->variablesPlug() ); !it.done(); ++it )
{
if( (*it)->getName() == "renderPass" )
Comment on lines +156 to +158
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just use script->variablesPlug()->getChild<NameValuePlug>( "renderPass" ) here instead of doing our own search?

{
if( (*it)->valuePlug<StringPlug>() )
{
return it->get();
}
else
{
throw IECore::Exception( fmt::format( "Plug type of {} is {}, but must be StringPlug", (*it)->valuePlug()->fullName(), (*it)->valuePlug()->typeName() ) );
}
}
}

if( createIfMissing )
{
auto renderPassPlug = new NameValuePlug( "renderPass", new StringPlug(), "renderPass", Gaffer::Plug::Flags::Default | Gaffer::Plug::Flags::Dynamic );
MetadataAlgo::setReadOnly( renderPassPlug->namePlug(), true );
script->variablesPlug()->addChild( renderPassPlug );

return renderPassPlug;
}

return nullptr;
}

void ScriptNodeAlgo::setCurrentRenderPass( Gaffer::ScriptNode *script, std::string renderPass )
{
if( auto renderPassPlug = acquireRenderPassPlug( script ) )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this check redundant? Doesn't acquireRenderPassPlug() always return non-null when createIfMissing = true?

{
renderPassPlug->valuePlug<StringPlug>()->setValue( renderPass );
}
}

std::string ScriptNodeAlgo::getCurrentRenderPass( const Gaffer::ScriptNode *script )
{
if( const auto renderPassPlug = acquireRenderPassPlug( const_cast<ScriptNode *>( script ), /* createIfMissing = */ false ) )
{
return renderPassPlug->valuePlug<StringPlug>()->getValue();
}

return "";
}
20 changes: 20 additions & 0 deletions src/GafferSceneUIModule/ScriptNodeAlgoBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ std::string getLastSelectedPathWrapper( const ScriptNode &script )
return result;
}

NameValuePlugPtr acquireRenderPassPlugWrapper( Gaffer::ScriptNode &script, bool createIfMissing )
{
IECorePython::ScopedGILRelease gilRelease;
return acquireRenderPassPlug( &script, createIfMissing );
}

void setCurrentRenderPassWrapper( ScriptNode &script, const std::string &renderPass )
{
IECorePython::ScopedGILRelease gilRelease;
setCurrentRenderPass( &script, renderPass );
}

std::string getCurrentRenderPassWrapper( ScriptNode &script )
{
return getCurrentRenderPass( &script );
}

} // namespace

void GafferSceneUIModule::bindScriptNodeAlgo()
Expand All @@ -117,4 +134,7 @@ void GafferSceneUIModule::bindScriptNodeAlgo()
def( "setLastSelectedPath", &setLastSelectedPathWrapper );
def( "getLastSelectedPath", &getLastSelectedPathWrapper );
def( "selectedPathsChangedSignal", &selectedPathsChangedSignal, return_value_policy<reference_existing_object>() );
def( "acquireRenderPassPlug", &acquireRenderPassPlugWrapper, ( arg( "script" ), arg( "createIfMissing" ) = true ) );
def( "setCurrentRenderPass", &setCurrentRenderPassWrapper );
def( "getCurrentRenderPass", &getCurrentRenderPassWrapper );
}