Skip to content

Commit 7a3e441

Browse files
committed
ShaderNetwork : Support InternedString attributes in substitutions
This is needed to allow USD `token` attributes to be referenced by a substitution.
1 parent 16d9ee7 commit 7a3e441

File tree

3 files changed

+52
-23
lines changed

3 files changed

+52
-23
lines changed

Changes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Improvements
55
------------
66

7+
- ShaderNetwork : Added support for InternedStringData attributes in string parameter substitutions.
78
- MurmurHash : Added specialisation for `std::hash`, among other things allowing the use of MurmurHash as a key in `unordered_map`.
89
- CompoundObject : Defaulted template argument to `Object` in `member()` methods.
910

src/IECoreScene/ShaderNetwork.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,14 @@ struct ReplaceFunctor
6666
std::string operator()( const boost::smatch & match )
6767
{
6868
// Search for attribute matching token
69-
const StringData *sourceAttribute = m_attributes->member<StringData>( match[1].str() );
70-
if( sourceAttribute )
69+
const Object *sourceAttribute = m_attributes->member( match[1].str() );
70+
if( auto stringData = runTimeCast<const StringData>( sourceAttribute ) )
7171
{
72-
return sourceAttribute->readable();
72+
return stringData->readable();
73+
}
74+
else if( auto internedStringData = runTimeCast<const InternedStringData>( sourceAttribute ) )
75+
{
76+
return internedStringData->readable().string();
7377
}
7478
else
7579
{
@@ -428,10 +432,14 @@ class ShaderNetwork::Implementation
428432
update();
429433
for( const auto &a : m_neededSubstitutions )
430434
{
431-
const StringData *sourceAttribute = attributes->member<StringData>( a );
432-
if( sourceAttribute )
435+
const Object *sourceAttribute = attributes->member( a );
436+
if( auto stringData = runTimeCast<const StringData>( sourceAttribute ) )
437+
{
438+
h.append( stringData->readable() );
439+
}
440+
else if( auto internedStringData = runTimeCast<const InternedStringData>( sourceAttribute ) )
433441
{
434-
h.append( sourceAttribute->readable() );
442+
h.append( internedStringData->readable().string() );
435443
}
436444
else
437445
{

test/IECoreScene/ShaderNetworkTest.py

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -513,23 +513,25 @@ def testUniqueHandles( self ) :
513513
{ "test" } | { "test{0}".format( x ) for x in range( 1, 20 ) }
514514
)
515515

516-
def testSubstitutions( self ):
517-
def runSubstitutionTest( shader, attributes ):
518-
n = IECoreScene.ShaderNetwork( shaders = { "s" : s } )
519-
a = IECore.CompoundObject( attributes )
520-
h = IECore.MurmurHash()
521-
n.hashSubstitutions( a, h )
522-
nSubst = n.copy()
523-
nSubst.applySubstitutions( a )
524-
return ( h, nSubst.getShader("s") )
516+
def __hashAndSubstitution( self, shader, attributes ) :
517+
518+
n = IECoreScene.ShaderNetwork( shaders = { "s" : shader } )
519+
a = IECore.CompoundObject( attributes )
520+
h = IECore.MurmurHash()
521+
n.hashSubstitutions( a, h )
522+
nSubst = n.copy()
523+
nSubst.applySubstitutions( a )
524+
return ( h, nSubst.getShader( "s" ) )
525+
526+
def testSubstitutions( self ) :
525527

526528
s = IECoreScene.Shader( "test", "surface",IECore.CompoundData( {
527529
"a" : IECore.StringData( "foo" ),
528530
"b" : IECore.FloatData( 42.42 ),
529531
"c" : IECore.StringVectorData( [ "foo", "bar" ] ),
530532
} ) )
531533

532-
( h, sSubst ) = runSubstitutionTest( s, { "unused" : IECore.StringData( "blah" ) } )
534+
( h, sSubst ) = self.__hashAndSubstitution( s, { "unused" : IECore.StringData( "blah" ) } )
533535
self.assertEqual( h, IECore.MurmurHash() )
534536
self.assertEqual( s, sSubst )
535537

@@ -538,7 +540,7 @@ def runSubstitutionTest( shader, attributes ):
538540
"b" : IECore.FloatData( 42.42 ),
539541
"c" : IECore.StringVectorData( [ "<attr:bob>", "pre<attr:carol>", "<attr:fred>post", "<attr:bob><attr:carol> <attr:fred>" ] ),
540542
} ) )
541-
( h, sSubst ) = runSubstitutionTest( s, { "unused" : IECore.StringData( "blah" ) } )
543+
( h, sSubst ) = self.__hashAndSubstitution( s, { "unused" : IECore.StringData( "blah" ) } )
542544
# Now that we've got substitutions, the hash should be non-default
543545
self.assertNotEqual( h, IECore.MurmurHash() )
544546

@@ -550,12 +552,12 @@ def runSubstitutionTest( shader, attributes ):
550552
self.assertEqual( sSubst.parameters["c"][2], "post" )
551553
self.assertEqual( sSubst.parameters["c"][3], " " )
552554

553-
( h2, sSubst2 ) = runSubstitutionTest( s, { "unused" : IECore.StringData( "blah2" ) } )
555+
( h2, sSubst2 ) = self.__hashAndSubstitution( s, { "unused" : IECore.StringData( "blah2" ) } )
554556
# The attribute being changed has no impact
555557
self.assertEqual( h, h2 )
556558
self.assertEqual( sSubst, sSubst2 )
557559

558-
( h3, sSubst3 ) = runSubstitutionTest( s, { "fred" : IECore.StringData( "CAT" ) } )
560+
( h3, sSubst3 ) = self.__hashAndSubstitution( s, { "fred" : IECore.StringData( "CAT" ) } )
559561
self.assertNotEqual( h, h3 )
560562
self.assertNotEqual( s, sSubst3 )
561563
self.assertEqual( sSubst3.parameters["a"].value, "preCATpost" )
@@ -564,7 +566,7 @@ def runSubstitutionTest( shader, attributes ):
564566
self.assertEqual( sSubst3.parameters["c"][2], "CATpost" )
565567
self.assertEqual( sSubst3.parameters["c"][3], " CAT" )
566568

567-
( h4, sSubst4 ) = runSubstitutionTest( s, { "fred" : IECore.StringData( "FISH" ) } )
569+
( h4, sSubst4 ) = self.__hashAndSubstitution( s, { "fred" : IECore.StringData( "FISH" ) } )
568570
self.assertNotEqual( h3, h4 )
569571
self.assertEqual( sSubst4.parameters["c"][2], "FISHpost" )
570572

@@ -573,7 +575,7 @@ def runSubstitutionTest( shader, attributes ):
573575
"bob" : IECore.StringData( "CAT" ),
574576
"carol" : IECore.StringData( "BIRD" )
575577
}
576-
( h5, sSubst5 ) = runSubstitutionTest( s, allAttributes )
578+
( h5, sSubst5 ) = self.__hashAndSubstitution( s, allAttributes )
577579
self.assertNotEqual( h4, h5 )
578580
self.assertEqual( sSubst5.parameters["a"].value, "preFISHpost" )
579581
self.assertEqual( sSubst5.parameters["c"][0], "CAT" )
@@ -587,14 +589,32 @@ def runSubstitutionTest( shader, attributes ):
587589
"b" : IECore.FloatData( 42.42 ),
588590
"c" : IECore.StringVectorData( [ r"\<attr:bob\>", r"\<attr:carol>", r"<attr:fred\>" ] ),
589591
} ) )
590-
( h6, sSubst6 ) = runSubstitutionTest( s, {} )
591-
( h7, sSubst7 ) = runSubstitutionTest( s, allAttributes )
592+
( h6, sSubst6 ) = self.__hashAndSubstitution( s, {} )
593+
( h7, sSubst7 ) = self.__hashAndSubstitution( s, allAttributes )
592594
self.assertEqual( h6, h7 )
593595
self.assertEqual( sSubst6, sSubst7 )
594596
self.assertEqual( sSubst6.parameters["a"].value, "pre<attr:fred>post" )
595597
self.assertEqual( sSubst6.parameters["c"][0], "<attr:bob>" )
596598
self.assertEqual( sSubst6.parameters["c"][1], "<attr:carol>" )
597599
self.assertEqual( sSubst6.parameters["c"][2], "<attr:fred>" )
598600

601+
def testInternedStringSubstitutions( self ) :
602+
603+
shader = IECoreScene.Shader(
604+
"test", "surface",
605+
IECore.CompoundData( {
606+
"a" : IECore.StringData( "<attr:internedString>" ),
607+
} )
608+
)
609+
610+
hash1, substitutedShader = self.__hashAndSubstitution( shader, { "internedString" : IECore.InternedStringData( "a" ) } )
611+
self.assertNotEqual( hash1, IECore.MurmurHash() )
612+
self.assertEqual( substitutedShader.parameters["a"], IECore.StringData( "a" ) )
613+
614+
hash2, substitutedShader = self.__hashAndSubstitution( shader, { "internedString" : IECore.InternedStringData( "b" ) } )
615+
self.assertNotEqual( hash2, IECore.MurmurHash() )
616+
self.assertNotEqual( hash2, hash1 )
617+
self.assertEqual( substitutedShader.parameters["a"], IECore.StringData( "b" ) )
618+
599619
if __name__ == "__main__":
600620
unittest.main()

0 commit comments

Comments
 (0)