Skip to content

Commit

Permalink
ValuePlugSerialiser : Fix serialisation of complex CompoundObjects
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Dec 3, 2020
1 parent 3fbb2d4 commit f02357d
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 2 deletions.
22 changes: 22 additions & 0 deletions python/GafferSceneTest/CustomAttributesTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,28 @@ def testLoadExtraAttributesFrom0_58( self ) :
} )
)

def testAssignShader( self ) :

script = Gaffer.ScriptNode()

script["sphere"] = GafferScene.Sphere()
script["sphereFilter"] = GafferScene.PathFilter()
script["sphereFilter"]["paths"].setValue( IECore.StringVectorData( [ "/sphere" ] ) )

attributes = IECore.CompoundObject( {
"ai:surface" : IECoreScene.ShaderNetwork( { "output" : IECoreScene.Shader( "flat" ) }, output = "output" )
} )

script["attributes"] = GafferScene.CustomAttributes()
script["attributes"]["in"].setInput( script["sphere"]["out"] )
script["attributes"]["filter"].setInput( script["sphereFilter"]["out"] )
script["attributes"]["extraAttributes"].setValue( attributes )
self.assertEqual( script["attributes"]["out"].attributes( "/sphere" ), attributes )

script2 = Gaffer.ScriptNode()
script2.execute( script.serialise() )
self.assertEqual( script2["attributes"]["out"].attributes( "/sphere" ), attributes )

def testDirtyPropagation( self ) :

attributes = GafferScene.CustomAttributes()
Expand Down
17 changes: 15 additions & 2 deletions python/GafferTest/TypedObjectPlugTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,30 +239,43 @@ def testSerialisationWithoutRepr( self ) :
)
)

v3 = IECore.CompoundObject( {
"a" : IECore.IntData( 10 ),
"b" : v1,
"c" : v2,
"d" : IECore.StringData( "test" ),
} )

with self.assertRaises( Exception ) :
eval( repr( v1 ) )

s = Gaffer.ScriptNode()
s["n"] = Gaffer.Node()
s["n"]["user"]["p1"] = Gaffer.ObjectPlug( defaultValue = v1, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
s["n"]["user"]["p2"] = Gaffer.ObjectPlug( defaultValue = v2, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
s["n"]["user"]["p3"] = Gaffer.ObjectPlug( defaultValue = v3, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )

s2 = Gaffer.ScriptNode()
s2.execute( s.serialise() )
self.assertEqual( s2["n"]["user"]["p1"].defaultValue(), v1 )
self.assertEqual( s2["n"]["user"]["p2"].defaultValue(), v2 )
self.assertEqual( s2["n"]["user"]["p3"].defaultValue(), v3 )
self.assertEqual( s2["n"]["user"]["p1"].getValue(), v1 )
self.assertEqual( s2["n"]["user"]["p2"].getValue(), v2 )
self.assertEqual( s2["n"]["user"]["p3"].getValue(), v3 )

s["n"]["user"]["p1"].setValue( v2 )
s["n"]["user"]["p2"].setValue( v1 )
s["n"]["user"]["p2"].setValue( v3 )
s["n"]["user"]["p3"].setValue( v1 )

s2 = Gaffer.ScriptNode()
s2.execute( s.serialise() )
self.assertEqual( s2["n"]["user"]["p1"].defaultValue(), v1 )
self.assertEqual( s2["n"]["user"]["p2"].defaultValue(), v2 )
self.assertEqual( s2["n"]["user"]["p3"].defaultValue(), v3 )
self.assertEqual( s2["n"]["user"]["p1"].getValue(), v2 )
self.assertEqual( s2["n"]["user"]["p2"].getValue(), v1 )
self.assertEqual( s2["n"]["user"]["p2"].getValue(), v3 )
self.assertEqual( s2["n"]["user"]["p3"].getValue(), v1 )

def testConnectCompoundDataToCompoundObject( self ) :

Expand Down
33 changes: 33 additions & 0 deletions src/GafferBindings/ValuePlugBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,28 @@ std::string valueSerialisationWalk( const Gaffer::ValuePlug *plug, const std::st
return identifier + ".setValue( " + ValuePlugSerialiser::valueRepr( pythonValue ) + " )\n";
}

std::string compoundObjectRepr( const IECore::CompoundObject *o )
{
std::string items;
for( const auto &e : o->members() )
{
if( items.size() )
{
items += ", ";
}
items += "'" + e.first.string() + "' : " + ValuePlugSerialiser::valueRepr( object( e.second ) );
}

if( items.empty() )
{
return "IECore.CompoundObject()";
}
else
{
return "IECore.CompoundObject( { " + items + "} )";
}
}

} // namespace

std::string ValuePlugSerialiser::repr( const Gaffer::ValuePlug *plug, const std::string &extraArguments, const Serialisation *serialisation )
Expand Down Expand Up @@ -242,6 +264,17 @@ std::string ValuePlugSerialiser::postHierarchy( const Gaffer::GraphComponent *gr

std::string ValuePlugSerialiser::valueRepr( const boost::python::object &value )
{
// CompoundObject may contain objects which can only be serialised
// via `objectToBase64()`, so we need to override the standard Cortex
// serialiser.

boost::python::extract<IECore::CompoundObjectPtr> compoundObjectExtractor( value );
if( compoundObjectExtractor.check() )
{
auto co = compoundObjectExtractor();
return compoundObjectRepr( co.get() );
}

// We use IECore.repr() because it correctly prefixes the imath
// types with the module name, and also works around problems
// when round-tripping empty Box2fs.
Expand Down

0 comments on commit f02357d

Please sign in to comment.