Skip to content

Commit

Permalink
Merge pull request #5355 from johnhaddon/optionQueryObject
Browse files Browse the repository at this point in the history
OptionQuery : Support ObjectPlug query type
  • Loading branch information
ericmehl authored Jun 22, 2023
2 parents bb0f157 + 1375c5a commit 45ce71a
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 53 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Improvements
- VectorWarp : Added `Bilinear` filter, for faster but lower quality warping.
- Dilate, Erode, Median, Resample, Resize, ImageTransform, Blur, VectorWarp : Improved performance significantly. For example, a Blur with a large radius is now almost 6x faster.
- RotateTool : Added the ability to rotate an axis whose plane of rotation is parallel or nearly parallel to the view.
- OptionQuery : Added support for querying generic `IECore::Object` values using an `ObjectPlug`.

Fixes
-----
Expand Down
55 changes: 54 additions & 1 deletion python/GafferSceneTest/OptionQueryTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@
import imath

import IECore
import IECoreScene

import Gaffer
import GafferScene
import GafferSceneTest


class OptionQueryTest( GafferSceneTest.SceneTestCase ):

def testDefault( self ) :
Expand Down Expand Up @@ -348,6 +349,58 @@ def testSerialisation( self ) :
self.assertEqual( str( scriptNode["target"]["options"]["b"]["value"].getInput() ), str( query["out"][1]["value"] ) )
self.assertEqual( str( scriptNode["target"]["options"]["c"]["value"].getInput() ), str( query["out"][2]["value"] ) )

def testObjectPlugQuery( self ) :

value1 = IECoreScene.ShaderNetwork(
shaders = {
"output" : IECoreScene.Shader( "test1" ),
},
output = "output"
)

value2 = IECoreScene.ShaderNetwork(
shaders = {
"output" : IECoreScene.Shader( "test2" ),
},
output = "output"
)

customOptions = GafferScene.CustomOptions()
customOptions["extraOptions"].setValue( {
"testObject" : value1,
} )

query = GafferScene.OptionQuery()
query["scene"].setInput( customOptions["out"] )
query.addQuery( Gaffer.ObjectPlug( defaultValue = IECore.NullObject.defaultNullObject() ), "testObject" )

self.assertTrue( query["out"][0]["exists"].getValue() )
self.assertEqual( query["out"][0]["value"].getValue(), value1 )

customOptions["extraOptions"].setValue( {
"testObject" : value2,
} )

self.assertTrue( query["out"][0]["exists"].getValue() )
self.assertEqual( query["out"][0]["value"].getValue(), value2 )

query["queries"][0]["name"].setValue( "blah" )
self.assertFalse( query["out"][0]["exists"].getValue() )
self.assertEqual( query["out"][0]["value"].getValue(), IECore.NullObject.defaultNullObject() )

def testMismatchedTypes( self ) :

customOptions = GafferScene.CustomOptions()
customOptions["extraOptions"].setValue( {
"test" : IECore.StringData( "i am a string" ),
} )

query = GafferScene.OptionQuery()
query["scene"].setInput( customOptions["out"] )
query.addQuery( Gaffer.FloatPlug( defaultValue = 2.0 ), "test" )

self.assertTrue( query["out"][0]["exists"].getValue() )
self.assertEqual( query["out"][0]["value"].getValue(), 2.0 )

if __name__ == "__main__":
unittest.main()
46 changes: 24 additions & 22 deletions python/GafferSceneUI/OptionQueryUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,28 +330,30 @@ def __menuDefinition( self ) :

result.append( "/FromPathsDivider", { "divider" : True } )

for item in [
Gaffer.BoolPlug,
Gaffer.FloatPlug,
Gaffer.IntPlug,
"NumericDivider",
Gaffer.StringPlug,
"StringDivider",
Gaffer.V2iPlug,
Gaffer.V3iPlug,
Gaffer.V2fPlug,
Gaffer.V3fPlug,
"VectorDivider",
Gaffer.Color3fPlug,
Gaffer.Color4fPlug,
for label, plugCreator in [
( "Bool", Gaffer.BoolPlug ),
( "Float", Gaffer.FloatPlug ),
( "Int", Gaffer.IntPlug ),
( "NumericDivider", None ),
( "String", Gaffer.StringPlug ),
( "StringDivider", None ),
( "V2i", Gaffer.V2iPlug ),
( "V3i", Gaffer.V3iPlug ),
( "V2f", Gaffer.V2fPlug ),
( "V3f", Gaffer.V3fPlug ),
( "VectorDivider", None ),
( "Color3f", Gaffer.Color3fPlug ),
( "Color4f", Gaffer.Color4fPlug ),
( "ObjectDivider", None ),
( "Object", functools.partial( Gaffer.ObjectPlug, defaultValue = IECore.NullObject.defaultNullObject() ) ),
] :
if isinstance( item, str ) :
result.append( "/" + item, { "divider": True } )
if plugCreator is None :
result.append( f"/{label}", { "divider": True } )
else :
result.append(
"/" + item.__name__.replace( "Plug", "" ),
f"/{label}",
{
"command" : functools.partial( Gaffer.WeakMethod( self.__addQuery ), "", "", item ),
"command" : functools.partial( Gaffer.WeakMethod( self.__addQuery ), "", "", plugCreator ),
}
)

Expand Down Expand Up @@ -393,22 +395,22 @@ def __addFromGlobalsMenuDefinition( self ) :

return result

def __addQuery( self, plugName, optionName, plugTypeOrValue ) :
def __addQuery( self, plugName, optionName, plugCreatorOrValue ) :

with Gaffer.UndoScope( self.getPlug().ancestor( Gaffer.ScriptNode ) ) :

node = self.getPlug().node()

if isinstance( plugTypeOrValue, IECore.Data ) :
if isinstance( plugCreatorOrValue, IECore.Data ) :
dummyPlug = Gaffer.PlugAlgo.createPlugFromData(
plugName,
Gaffer.Plug.Direction.In,
Gaffer.Plug.Flags.Default,
plugTypeOrValue
plugCreatorOrValue
)
node.addQuery( dummyPlug, optionName )
else:
node.addQuery( plugTypeOrValue(), optionName )
node.addQuery( plugCreatorOrValue(), optionName )

def __updateQueryMetadata( self, plug ) :

Expand Down
49 changes: 19 additions & 30 deletions src/GafferScene/OptionQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,60 +291,49 @@ void OptionQuery::compute( Gaffer::ValuePlug *output, const Gaffer::Context *con

if( output == oPlug->getChild( g_existsPlugIndex ) )
{
const NameValuePlug *childQueryPlug = queryPlug( output );

const std::string optionName = childQueryPlug->namePlug()->getValue();

const std::string optionName = queryPlug( output )->namePlug()->getValue();
bool exists = false;
if( optionName.size() )
{
ConstCompoundObjectPtr globals = scenePlug()->globalsPlug()->getValue();
const Data *resultData = globals->member<const Data>( g_namePrefix + optionName );

static_cast<BoolPlug *>( output )->setValue( resultData != nullptr );

return;
exists = globals->members().count( g_namePrefix + optionName );
}

static_cast<BoolPlug *>( output )->setValue( false );

static_cast<BoolPlug *>( output )->setValue( exists );
return;
}

else if(
oPlug->getChild( g_valuePlugIndex )->isAncestorOf( output ) ||
output == oPlug->getChild( g_valuePlugIndex )
)
const ValuePlug *valuePlug = oPlug->getChild<ValuePlug>( g_valuePlugIndex );
if( output == valuePlug || valuePlug->isAncestorOf( output ) )
{
const NameValuePlug *childQueryPlug = queryPlug( output );

const std::string optionName = childQueryPlug->namePlug()->getValue();

const ValuePlug *vPlug = valuePlugFromQuery( childQueryPlug );

ConstObjectPtr object;
if( optionName.size() )
{
ConstCompoundObjectPtr globals = scenePlug()->globalsPlug()->getValue();
const Data *resultData = globals->member<const Data>( g_namePrefix + optionName );
object = globals->member<Object>( g_namePrefix + optionName );
}

if( resultData != nullptr )
if( object )
{
if( auto objectPlug = runTimeCast<ObjectPlug>( output ) )
{
objectPlug->setValue( object );
return;
}
else if( auto data = runTimeCast<const Data>( object.get() ) )
{
if( PlugAlgo::setValueFromData( vPlug, output, resultData ) )
if( PlugAlgo::setValueFromData( valuePlug, output, data ) )
{
return;
}
}
}

output->setFrom(
static_cast<const Gaffer::ValuePlug *>(
correspondingPlug(
vPlug,
output,
static_cast<const ValuePlug *>( childQueryPlug->valuePlug() )
)
)
correspondingPlug( valuePlug, output, childQueryPlug->valuePlug<ValuePlug>() )
);

return;
}
}
Expand Down

0 comments on commit 45ce71a

Please sign in to comment.