Skip to content

Commit

Permalink
Shuffle : Stop wildcards matching __black and __white
Browse files Browse the repository at this point in the history
This is the sketchy approach - note the comment about undefined behaviour.
Note also that this approach would mean we don't have any current use for
`ShufflesPlug::shuffleWithDefaultSource()`.
  • Loading branch information
johnhaddon committed Dec 15, 2023
1 parent c693d67 commit 6dea107
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 18 deletions.
25 changes: 25 additions & 0 deletions python/GafferImageTest/ShuffleTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,31 @@ def testWildCards( self ) :
constant["out"].channelData( channel, imath.V2i( 0 ) ),
)

def testWildCardsDontMatchSpecialChannels( self ) :

constant = GafferImage.Constant()
constant["color"].setValue( imath.Color4f( 0, 1, 2, 3 ) )

shuffle = GafferImage.Shuffle()
shuffle["in"].setInput( constant["out"] )

self.assertImagesEqual( shuffle["out"], constant["out"] )

shuffle["shuffles"].addChild(
Gaffer.ShufflePlug( "*", "newLayer.${source}" )
)

self.assertEqual(
shuffle["out"].channelNames(),
IECore.StringVectorData( [ "R", "G", "B", "A", "newLayer.R", "newLayer.G", "newLayer.B", "newLayer.A" ] )
)

for channel in "RGBA" :
self.assertEqual(
shuffle["out"].channelData( f"newLayer.{channel}", imath.V2i( 0 ) ),
constant["out"].channelData( channel, imath.V2i( 0 ) ),
)

def testDeleteSource( self ) :

constant = GafferImage.Constant()
Expand Down
70 changes: 52 additions & 18 deletions src/GafferImage/Shuffle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,35 +50,69 @@ using namespace GafferImage;
namespace
{

struct MappingData : public IECore::Data
class SourceMap : public unordered_map<string, string>
{
public :

MappingData( const StringVectorData *inChannelNames, const ShufflesPlug *shuffles, Shuffle::MissingSourceMode mode )
{
for( const auto &channelName : inChannelNames->readable() )
SourceMap( const vector<string> &inChannelNames, Shuffle::MissingSourceMode mode )
: m_missingSourceMode( mode )
{
m_mapping[channelName] = channelName;
for( const auto &channelName : inChannelNames )
{
(*this)[channelName] = channelName;
}
m_virtualChannels["__white"] = "__white";
m_virtualChannels["__black"] = "__black";
}
m_mapping["__white"] = "__white";
m_mapping["__black"] = "__black";

if( mode == Shuffle::MissingSourceMode::Black )
{
const std::string black( "__black" );
m_mapping = shuffles->shuffleWithDefaultSource( m_mapping, black );
}
else
const_iterator find( const std::string &source ) const
{
m_mapping = shuffles->shuffle( m_mapping, mode == Shuffle::MissingSourceMode::Ignore );
auto it = unordered_map<string, string>::find( source );
if( it != end() )
{
return it;
}

// Source channel doesn't exist, see if it's a "virtual" channel. We
// can't just add these to the main map, because then they are
// available for matching by wildcards, which is not what we want.
it = m_virtualChannels.find( source );
if( it != m_virtualChannels.end() )
{
// Note : This is technically undefined behaviour,
// because ShufflePlug will compare it against `end()`
// which is from a different container.
return it;
}

if( m_missingSourceMode == Shuffle::MissingSourceMode::Black )
{
return m_virtualChannels.find( "__black" );
}

return end();
}

private :

const Shuffle::MissingSourceMode m_missingSourceMode;
unordered_map<string, string> m_virtualChannels;

};


struct MappingData : public IECore::Data
{

MappingData( const StringVectorData *inChannelNames, const ShufflesPlug *shuffles, Shuffle::MissingSourceMode mode )
{
const SourceMap sourceMap( inChannelNames->readable(), mode );
m_mapping = shuffles->shuffle( sourceMap, mode == Shuffle::MissingSourceMode::Ignore );

m_outChannelNames = new StringVectorData();
for( const auto &m : m_mapping )
{
if( m.first != "__white" && m.first != "__black" )
{
m_outChannelNames->writable().push_back( m.first );
}
m_outChannelNames->writable().push_back( m.first );
}
m_outChannelNames->writable() = ImageAlgo::sortedChannelNames( m_outChannelNames->readable() );
}
Expand Down

0 comments on commit 6dea107

Please sign in to comment.