ImageEngine/gaffer — pull request #686 by johnhaddon (2013-12-05 19:29:19+00:00)
Title: Switch node

This implements a generic Gaffer::Switch node which can be used to instantiate switch nodes of all types. It uses this to create a SceneSwitch, ImageSwitch and ShaderSwitch. I also threw in ImageTimeWarp and ImageContextVariables for good measure, since it was trivial given the ImageMixinBase.

Switching works in different ways depending on the type of the node. ComputeNode derived types operate using hash() and compute(), passing through a perfect copy (shared in the cache) of the appropriate input - this means that they fully support expressions and other Context-varying inputs to the index plug. DependencyNode switching is a little different, and operates by making internal connections from the input branches to the output (since there is no such thing as hash() and compute() for DependencyNodes). This means the branch choice cannot be Context-varying so the index plug cannot be connected to the output of a ComputeNode.

I know one of Daniel's use cases is to use a ShaderSwitch and promote the index plug to a Box - this is something that currently doesn't work, but we have some options for achieving that. The DependencyNodeSwitch (that ShaderSwitch uses) uses plugSetSignal() for the index plug to trigger the reconnection and implement the switch. The problem is that when the plug is promoted, the plugSetSignal() is emitted for the promoted plug and not for the index directly - only plugDirtiedSignal() is emitted for the internal one, and it's illegal to perform rewiring from that signal. So we have two options that I can see :

- Modify ValuePlug so that plugSetSignal() is emitted for not only the plug on which setValue() is called, but its direct outputs too. This is my preferred option. Conceptually the value of the output plug is also set when the input is set - internally things are slightly different at the moment in that the value isn't transferred until getValue() is called on the output plug, but that's an internal detail irrelevant to the external observer.

or :

- Modify DependencyNodeSwitch to track the source of the connection whenever it's input is changed in some way, and maintain a connection to the plugSetSignal() for the eventual input. This would work, but would be kindof tricksy and wouldn't help out any other nodes with similar requirements in the future.

Hopefully the first option makes sense to everyone? I should be able to add it to this pull request tomorrow or it can become a next-time thing dependency on the priorities at your end....