diff --git a/include/Gaffer/DependencyNode.h b/include/Gaffer/DependencyNode.h index dc7a36b4a59..f067f98fac5 100644 --- a/include/Gaffer/DependencyNode.h +++ b/include/Gaffer/DependencyNode.h @@ -67,6 +67,9 @@ class DependencyNode : public Node /// for input or to place one in outputs as computations are always performed on the /// leaf level plugs only. Implementations of this method should call the base class /// implementation first. + /// \todo Make this protected, and add an accessor on the Plug class instead. + /// The general principle in effect elsewhere in Gaffer is that plugs provide + /// the public interface to the work done by nodes. virtual void affects( const Plug *input, AffectedPlugsContainer &outputs ) const = 0; /// @name Enable/Disable Behaviour diff --git a/include/GafferArnold/ArnoldDisplacement.h b/include/GafferArnold/ArnoldDisplacement.h index b5c3201e704..9efc2909a97 100644 --- a/include/GafferArnold/ArnoldDisplacement.h +++ b/include/GafferArnold/ArnoldDisplacement.h @@ -79,6 +79,8 @@ class ArnoldDisplacement : public GafferScene::Shader Gaffer::Plug *outPlug(); const Gaffer::Plug *outPlug() const; + virtual void affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const; + virtual void attributesHash( IECore::MurmurHash &h ) const; virtual IECore::ConstCompoundObjectPtr attributes() const; diff --git a/python/GafferArnoldTest/ArnoldDisplacementTest.py b/python/GafferArnoldTest/ArnoldDisplacementTest.py index d88ebcbcf15..f6afc025cf7 100644 --- a/python/GafferArnoldTest/ArnoldDisplacementTest.py +++ b/python/GafferArnoldTest/ArnoldDisplacementTest.py @@ -38,7 +38,9 @@ import IECore +import GafferTest import GafferSceneTest +import GafferOSL import GafferArnold class ArnoldDisplacementTest( GafferSceneTest.SceneTestCase ) : @@ -72,6 +74,45 @@ def test( self ) : d["enabled"].setValue( False ) self.assertEqual( d.attributes(), IECore.CompoundObject() ) + def testDirtyPropagation( self ) : + + n = GafferArnold.ArnoldShader() + n.loadShader( "noise" ) + + d = GafferArnold.ArnoldDisplacement() + cs = GafferTest.CapturingSlot( d.plugDirtiedSignal() ) + + d["height"].setValue( 10 ) + self.assertTrue( d["out"] in [ x[0] for x in cs ] ) + + del cs[:] + d["map"].setInput( n["out"] ) + self.assertTrue( d["out"] in [ x[0] for x in cs ] ) + + def testOSLShaderInput( self ) : + + n = GafferOSL.OSLShader() + n.loadShader( "Pattern/Noise" ) + + d = GafferArnold.ArnoldDisplacement() + + d["map"].setInput( n["out"] ) + self.assertTrue( d["map"].getInput().isSame( n["out"] ) ) + + na = n.attributes() + da = d.attributes() + + self.assertEqual( + da, + IECore.CompoundObject( { + "ai:disp_map" : na["osl:shader"], + "ai:disp_height" : IECore.FloatData( 1 ), + "ai:disp_padding" : IECore.FloatData( 0 ), + "ai:disp_zero_value" : IECore.FloatData( 0 ), + "ai:disp_autobump" : IECore.BoolData( False ), + } ) + ) + def testNoInput( self ) : d = GafferArnold.ArnoldDisplacement() diff --git a/src/GafferArnold/ArnoldDisplacement.cpp b/src/GafferArnold/ArnoldDisplacement.cpp index fc868130feb..6ac878e8517 100644 --- a/src/GafferArnold/ArnoldDisplacement.cpp +++ b/src/GafferArnold/ArnoldDisplacement.cpp @@ -45,12 +45,12 @@ using namespace GafferArnold; IE_CORE_DEFINERUNTIMETYPED( ArnoldDisplacement ); size_t ArnoldDisplacement::g_firstPlugIndex = 0; -static IECore::InternedString g_surfaceAttributeName = "ai:surface"; static IECore::InternedString g_mapAttributeName = "ai:disp_map"; static IECore::InternedString g_paddingAttributeName = "ai:disp_padding"; static IECore::InternedString g_heightAttributeName = "ai:disp_height"; static IECore::InternedString g_zeroValueAttributeName = "ai:disp_zero_value"; static IECore::InternedString g_autoBumpAttributeName = "ai:disp_autobump"; +static IECore::InternedString g_mapInputAttributeNames[] = { "ai:surface", "osl:shader", "" } ; ArnoldDisplacement::ArnoldDisplacement( const std::string &name ) : Shader( name ) @@ -128,6 +128,22 @@ const Gaffer::Plug *ArnoldDisplacement::outPlug() const return getChild( g_firstPlugIndex + 5 ); } +void ArnoldDisplacement::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const +{ + Shader::affects( input, outputs ); + + if( + input == mapPlug() || + input == heightPlug() || + input == paddingPlug() || + input == zeroValuePlug() || + input == autoBumpPlug() + ) + { + outputs.push_back( outPlug() ); + } +} + void ArnoldDisplacement::attributesHash( IECore::MurmurHash &h ) const { h.append( typeId() ); @@ -153,11 +169,16 @@ IECore::ConstCompoundObjectPtr ArnoldDisplacement::attributes() const CompoundObject::ObjectMap &m = result->members(); m = mapPlug()->attributes()->members(); - CompoundObject::ObjectMap::iterator it = m.find( g_surfaceAttributeName ); - if( it != m.end() ) + + for( InternedString *n = g_mapInputAttributeNames; *n != InternedString(); ++n ) { - m[g_mapAttributeName] = it->second; - m.erase( it ); + CompoundObject::ObjectMap::iterator it = m.find( *n ); + if( it != m.end() ) + { + m[g_mapAttributeName] = it->second; + m.erase( it ); + break; + } } m[g_heightAttributeName] = new FloatData( heightPlug()->getValue() ); @@ -184,7 +205,7 @@ bool ArnoldDisplacement::acceptsInput( const Gaffer::Plug *plug, const Gaffer::P { if( const GafferScene::Shader *shader = runTimeCast( inputPlug->source()->node() ) ) { - return runTimeCast( shader ); + return runTimeCast( shader ) || shader->isInstanceOf( "GafferOSL::OSLShader" ); } }