Skip to content

Commit

Permalink
Merge branch '1.3_maintenance' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Nov 28, 2023
2 parents 04bab6c + 6007e4e commit ae1eafa
Show file tree
Hide file tree
Showing 14 changed files with 808 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main/installDependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

# Determine default archive URL.

defaultURL = "https://github.com/ImageEngine/cortex/releases/download/10.5.4.0/cortex-10.5.4.0-{platform}-python3.{extension}".format(
defaultURL = "https://github.com/ImageEngine/cortex/releases/download/10.5.4.2/cortex-10.5.4.2-{platform}-python3.{extension}".format(
platform = { "darwin" : "osx", "win32" : "windows" }.get( sys.platform, "linux" ),
extension = "tar.gz" if sys.platform != "win32" else "zip"
)
Expand Down
20 changes: 19 additions & 1 deletion Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ Breaking Changes
- Windows launch script : Removed the hardcoded `/debugexe` switch used when `GAFFER_DEBUG` is enabled, making it possible to use debuggers other than Visual Studio. Debug switches can be added to the `GAFFER_DEBUGGER` environment variable instead.
- Enums : Replaced `IECore.Enum` types with standard Python types from the `enum` module.

1.3.x.x (relative to 1.3.7.0)
1.3.x.x (relative to 1.3.8.0)
=======



1.3.8.0 (relative to 1.3.7.0)
=======

Features
Expand All @@ -37,6 +42,7 @@ Features
Improvements
------------

- GraphEditor : Added drag & drop of files into the graph editor, automatically creating a SceneReader, ImageReader or Reference node as appropriate.
- ImageTransform, Resample : Improved performance for non-separable filters without scaling, with 2-6x speedups in some benchmark cases.
- Outputs : Included `renderPass` in the filename for newly created Arnold, Cycles and 3Delight outputs. Allowing rendered images to be written to a specific directory based on the name of the current render pass.
- GUI Config : Included `renderPass` in the default filename when writing ass files from an ArnoldRender node.
Expand All @@ -47,16 +53,28 @@ Fixes

- InteractiveRender : Fixed unnecessary updates to encapsulated locations when deforming an unrelated object.
- InteractiveArnoldRender : Fixed creation of new Catalogue image when editing output metadata or pixel filter.
- GraphEditor : Fixed error caused by additional connections to `dragEnterSignal()`.
- Windows `Scene/OpenGL/Shader` Menu : Removed `\` at the beginning of menu items.
- Arnold :
- Fixed translation of `UsdPreviewSurface` normal maps.
- Fixed translation of `UsdPreviewSurface` `specularColor` fallback value.
- Scene History : Fixed error caused by `Alt+E` keypress on panels other than the Viewer, HierarchyView, LightEditor or NodeEditor.
- ImageReader : Fixed crashes caused by null `ustring` metadata values.
- Exception handling : Fixed memory leak caused by translation of `IECore::Exception` from C++ to Python and back again.

API
---

- SceneGadget : Added `snapshotToFile()` method.
- SceneAlgo :
- Added `history()` overload for returning computation history independent of a scene location, this is useful when generating history from the globals.
- Added `optionHistory()` method which returns a computation history for one specific option.
- Widget : Added handling for drag & drop from an external application via the existing `dragEnterSignal()`, `dragMoveSignal()`, `dragLeaveSignal()` and `dropSignal()` signals.

Build
-----

- Cortex : Updated to version 10.5.4.2.
- Instancer : Fixed ambiguous reference compilation errors when building with Boost 1.70.

1.3.7.0 (relative to 1.3.6.1)
Expand Down
19 changes: 19 additions & 0 deletions include/GafferScene/SceneAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ struct History : public IECore::RefCounted
};

GAFFERSCENE_API History::Ptr history( const Gaffer::ValuePlug *scenePlugChild, const ScenePlug::ScenePath &path );
GAFFERSCENE_API History::Ptr history( const Gaffer::ValuePlug *scenePlugChild );

/// Extends History to provide information on the history of a specific attribute.
/// Attributes may be renamed by ShuffleAttributes nodes and this is reflected
Expand All @@ -221,6 +222,24 @@ struct AttributeHistory : public History
/// null is returned.
GAFFERSCENE_API AttributeHistory::Ptr attributeHistory( const History *attributesHistory, const IECore::InternedString &attribute );

/// Extends History to provide information on the history of a specific option.
struct OptionHistory : public History
{
IE_CORE_DECLAREMEMBERPTR( OptionHistory )
OptionHistory(
const ScenePlugPtr &scene, const Gaffer::ContextPtr &context,
const IECore::InternedString &optionName, const IECore::ConstObjectPtr &optionValue
) : History( scene, context ), optionName( optionName ), optionValue( optionValue ) {}
IECore::InternedString optionName;
IECore::ConstObjectPtr optionValue;
};

/// Filters `globalsHistory` and returns a history for the specific `option`.
/// `globalsHistory` should have been obtained from a previous call to
/// `history( scene->globalsPlug() )`. If the option doesn't exist then
/// null is returned.
GAFFERSCENE_API OptionHistory::Ptr optionHistory( const History *globalsHistory, const IECore::InternedString &option );

/// Returns the upstream scene originally responsible for generating the specified location.
GAFFERSCENE_API ScenePlug *source( const ScenePlug *scene, const ScenePlug::ScenePath &path );

Expand Down
237 changes: 237 additions & 0 deletions python/GafferSceneTest/SceneAlgoTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,17 @@ def __assertParameterHistory( self, attributeHistory, predecessorIndices, scene,
self.assertEqual( ah.attributeValue.shaders()[shaderName].parameters[parameterName].value, parameterValue )
self.assertEqual( len( ah.predecessors ), numPredecessors )

def __assertOptionHistory( self, optionHistory, predecessorIndices, scene, optionName, optionValue, numPredecessors ) :

oh = self.__predecessor( optionHistory, predecessorIndices )

self.assertIsInstance( oh, GafferScene.SceneAlgo.OptionHistory )
self.assertEqual( oh.scene, scene )
self.assertNotIn( "scene:path", oh.context )
self.assertEqual( oh.optionName, optionName )
self.assertEqual( oh.optionValue.value, optionValue )
self.assertEqual( len( oh.predecessors ), numPredecessors )

def testAttributeHistory( self ) :

# Build network
Expand Down Expand Up @@ -1566,6 +1577,232 @@ def testAttributeHistoryWithMissingAttribute( self ) :
attributesHistory = GafferScene.SceneAlgo.history( plane["out"]["attributes"], "/plane" )
self.assertIsNone( GafferScene.SceneAlgo.attributeHistory( attributesHistory, "test" ) )

def testOptionHistory( self ) :

# Build network
# -------------
#
# standardOptions
# |
# optionTweaks customOptions
# \ /
# \ /
# \ /
# copyOptions

options = GafferScene.StandardOptions()
options["options"]["renderCamera"]["enabled"].setValue( True )
options["options"]["renderCamera"]["value"].setValue( "/renderCamera" )
options["options"]["resolutionMultiplier"]["enabled"].setValue( True )
options["options"]["resolutionMultiplier"]["value"].setValue( 2.0 )

tweaks = GafferScene.OptionTweaks()
tweaks["in"].setInput( options["out"] )

tweak = Gaffer.TweakPlug( "render:camera", "/tweakCamera" )
tweaks["tweaks"].addChild( tweak )

customOptions = GafferScene.CustomOptions()
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:camera", "/customCamera" ) )
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:resolutionMultiplier", 4.0 ) )

copyOptions = GafferScene.CopyOptions()
copyOptions["in"].setInput( tweaks["out"] )
copyOptions["source"].setInput( customOptions["out"] )

def assertResolutionMultiplierFromStandardOptions() :

history = GafferScene.SceneAlgo.history( copyOptions["out"]["globals"] )
optionHistory = GafferScene.SceneAlgo.optionHistory( history, "render:resolutionMultiplier" )

self.__assertOptionHistory( optionHistory, [], copyOptions["out"], "render:resolutionMultiplier", 2.0, 1 )
self.__assertOptionHistory( optionHistory, [ 0 ], copyOptions["in"], "render:resolutionMultiplier", 2.0, 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0 ], tweaks["out"], "render:resolutionMultiplier", 2.0, 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0, 0 ], tweaks["in"], "render:resolutionMultiplier", 2.0, 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0, 0, 0 ], options["out"], "render:resolutionMultiplier", 2.0, 0 )

def assertResolutionMultiplierFromCustomOptions() :

history = GafferScene.SceneAlgo.history( copyOptions["out"]["globals"] )
optionHistory = GafferScene.SceneAlgo.optionHistory( history, "render:resolutionMultiplier" )

self.__assertOptionHistory( optionHistory, [], copyOptions["out"], "render:resolutionMultiplier", 4.0, 1 )
self.__assertOptionHistory( optionHistory, [ 0 ], copyOptions["source"], "render:resolutionMultiplier", 4.0, 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0 ], customOptions["out"], "render:resolutionMultiplier", 4.0, 0 )

def assertRenderCameraFromStandardOptions() :

history = GafferScene.SceneAlgo.history( copyOptions["out"]["globals"] )
optionHistory = GafferScene.SceneAlgo.optionHistory( history, "render:camera" )

self.__assertOptionHistory( optionHistory, [], copyOptions["out"], "render:camera", "/tweakCamera", 1 )
self.__assertOptionHistory( optionHistory, [ 0 ], copyOptions["in"], "render:camera", "/tweakCamera", 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0 ], tweaks["out"], "render:camera", "/tweakCamera", 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0, 0 ], tweaks["in"], "render:camera", "/renderCamera", 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0, 0, 0 ], options["out"], "render:camera", "/renderCamera", 0 )


def assertRenderCameraFromCustomOptions() :

history = GafferScene.SceneAlgo.history( copyOptions["out"]["globals"] )
optionHistory = GafferScene.SceneAlgo.optionHistory( history, "render:camera" )

self.__assertOptionHistory( optionHistory, [], copyOptions["out"], "render:camera", "/customCamera", 1 )
self.__assertOptionHistory( optionHistory, [ 0 ], copyOptions["source"], "render:camera", "/customCamera", 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0 ], customOptions["out"], "render:camera", "/customCamera", 0 )

# Test `optionHistory()` with "render:camera" copied

copyOptions["options"].setValue( "render:ca*" )
assertRenderCameraFromCustomOptions()
assertResolutionMultiplierFromStandardOptions()

# Test `optionHistory()` with all "render:" options copied

copyOptions["options"].setValue( "render:*" )
assertRenderCameraFromCustomOptions()
assertResolutionMultiplierFromCustomOptions()

# Test `optionHistory()` with no options copied

copyOptions["options"].setValue( "" )
assertRenderCameraFromStandardOptions()
assertResolutionMultiplierFromStandardOptions()

# Test `optionHistory()` with an invalid option copied

copyOptions["options"].setValue( "not:an:option" )
assertRenderCameraFromStandardOptions()
assertResolutionMultiplierFromStandardOptions()

# Test `optionHistory()` with `copyOptions` disabled

copyOptions["enabled"].setValue( False )
assertRenderCameraFromStandardOptions()
assertResolutionMultiplierFromStandardOptions()

def testOptionHistoryWithMergeScenes( self ) :

# Build network
# -------------
#
# standardOptions customOptions
# \ /
# \ /
# \ /
# mergeScenes

options = GafferScene.StandardOptions()
options["options"]["renderCamera"]["enabled"].setValue( True )
options["options"]["renderCamera"]["value"].setValue( "/renderCamera" )
options["options"]["resolutionMultiplier"]["enabled"].setValue( True )
options["options"]["resolutionMultiplier"]["value"].setValue( 2.0 )

customOptions = GafferScene.CustomOptions()
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:camera", "/altCamera" ) )
customOptions["options"].addChild( Gaffer.NameValuePlug( "custom:camera", "/customCamera" ) )

mergeScenes = GafferScene.MergeScenes()
mergeScenes["in"][0].setInput( options["out"] )
mergeScenes["in"][1].setInput( customOptions["out"] )

def assertOptionHistory( optionName, mergeScenesInput, value ) :

history = GafferScene.SceneAlgo.history( mergeScenes["out"]["globals"] )
optionHistory = GafferScene.SceneAlgo.optionHistory( history, optionName )

if value is None :
self.assertIsNone( optionHistory )
return

self.__assertOptionHistory( optionHistory, [], mergeScenes["out"], optionName, value, 1 )
self.__assertOptionHistory( optionHistory, [ 0 ], mergeScenesInput, optionName, value, 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0 ], mergeScenesInput.getInput(), optionName, value, 0 )

# Test Keep mode

mergeScenes["globalsMode"].setValue( mergeScenes.Mode.Keep )

assertOptionHistory( "render:camera", mergeScenes["in"][0], "/renderCamera" )
assertOptionHistory( "custom:camera", None, None )
assertOptionHistory( "render:resolutionMultiplier", mergeScenes["in"][0], 2.0 )

# Test Merge mode

mergeScenes["globalsMode"].setValue( mergeScenes.Mode.Merge )

assertOptionHistory( "render:camera", mergeScenes["in"][1], "/altCamera" )
assertOptionHistory( "custom:camera", mergeScenes["in"][1], "/customCamera" )
assertOptionHistory( "render:resolutionMultiplier", mergeScenes["in"][0], 2.0 )

# Test Replace mode

mergeScenes["globalsMode"].setValue( mergeScenes.Mode.Replace )

assertOptionHistory( "render:camera", mergeScenes["in"][1], "/altCamera" )
assertOptionHistory( "custom:camera", mergeScenes["in"][1], "/customCamera" )
assertOptionHistory( "render:resolutionMultiplier", None, None )

def testOptionHistoryWithMissingOption( self ) :

# Option doesn't exist, so we return None.

plane = GafferScene.Plane()
globalsHistory = GafferScene.SceneAlgo.history( plane["out"]["globals"] )
self.assertIsNone( GafferScene.SceneAlgo.optionHistory( globalsHistory, "test" ) )

def testOptionHistoryWithContext( self ) :

# Build network
# -------------
#
# standardOptions standardOptions
# \ /
# \ /
# \ /
# nameSwitch

options = GafferScene.StandardOptions()
options["options"]["renderCamera"]["enabled"].setValue( True )
options["options"]["renderCamera"]["value"].setValue( "/010" )

options2 = GafferScene.StandardOptions()
options2["options"]["renderCamera"]["enabled"].setValue( True )
options2["options"]["renderCamera"]["value"].setValue( "/020" )

nameSwitch = Gaffer.NameSwitch()
nameSwitch.setup( GafferScene.ScenePlug() )
nameSwitch["selector"].setValue( "${shot}" )
nameSwitch["in"][0]["name"].setValue( "010" )
nameSwitch["in"][0]["value"].setInput( options["out"] )
nameSwitch["in"][1]["name"].setValue( "020" )
nameSwitch["in"][1]["value"].setInput( options2["out"] )

def assertOptionHistory( optionName, nameSwitchInput, value ) :

history = GafferScene.SceneAlgo.history( nameSwitch["out"]["value"]["globals"] )
optionHistory = GafferScene.SceneAlgo.optionHistory( history, optionName )

if value is None :
self.assertIsNone( optionHistory )
return

self.__assertOptionHistory( optionHistory, [], nameSwitch["out"]["value"], optionName, value, 1 )
self.__assertOptionHistory( optionHistory, [ 0 ], nameSwitchInput, optionName, value, 1 )
self.__assertOptionHistory( optionHistory, [ 0, 0 ], nameSwitchInput.getInput(), optionName, value, 0 )

with Gaffer.Context() as context :
context["shot"] = "010"
assertOptionHistory( "render:camera", nameSwitch["in"][0]["value"], "/010" )

context["shot"] = "020"
assertOptionHistory( "render:camera", nameSwitch["in"][1]["value"], "/020" )

# Use SceneTestCase's ContextSanitiser to indirectly test that `scene:path`
# isn't leaked into the context used to evaluate the globals.
context["scene:path"] = IECore.InternedStringVectorData( [ "plane" ] )
assertOptionHistory( "render:camera", nameSwitch["in"][1]["value"], "/020" )

def testHistoryWithCanceller( self ) :

plane = GafferScene.Plane()
Expand Down
2 changes: 1 addition & 1 deletion python/GafferSceneUI/SceneHistoryUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def connectToEditor( editor ) :
editor.keyPressSignal().connect( __viewerKeyPress, scoped = False )
elif isinstance( editor, GafferSceneUI.HierarchyView ) or isinstance( editor, GafferSceneUI.LightEditor ) :
editor.keyPressSignal().connect( __hierarchyViewKeyPress, scoped = False )
elif isinstance( editor, GafferUI.Editor ) :
elif isinstance( editor, GafferUI.NodeEditor ) :
editor.keyPressSignal().connect( __nodeEditorKeyPress, scoped = False )

##########################################################################
Expand Down
10 changes: 8 additions & 2 deletions python/GafferUI/GraphEditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__( self, scriptNode, **kw ) :
self.dragEnterSignal().connect( Gaffer.WeakMethod( self.__dragEnter ), scoped = False )
self.dragLeaveSignal().connect( Gaffer.WeakMethod( self.__dragLeave ), scoped = False )
self.dropSignal().connect( Gaffer.WeakMethod( self.__drop ), scoped = False )
self.__dragEnterPointer = None
self.__gadgetWidget.getViewportGadget().preRenderSignal().connect( Gaffer.WeakMethod( self.__preRender ), scoped = False )

with GafferUI.ListContainer( borderWidth = 8, spacing = 0 ) as overlay :
Expand Down Expand Up @@ -511,8 +512,12 @@ def __dragEnter( self, widget, event ) :

def __dragLeave( self, widget, event ) :

GafferUI.Pointer.setCurrent( self.__dragEnterPointer )
return True
if self.__dragEnterPointer is not None :
GafferUI.Pointer.setCurrent( self.__dragEnterPointer )
self.__dragEnterPointer = None
return True

return False

def __drop( self, widget, event ) :

Expand All @@ -523,6 +528,7 @@ def __drop( self, widget, event ) :
if dropNodes :
self.graphGadget().setRoot( dropNodes[0].parent() )
self.__frame( dropNodes, at = imath.V2f( event.line.p0.x, event.line.p0.y ) )
self.__dragEnterPointer = None
return True

return False
Expand Down
1 change: 1 addition & 0 deletions python/GafferUI/MultiLineTextWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ def __dragLeave( self, widget, event ) :
def __drop( self, widget, event ) :

self.insertText( self.__dropText( event.data ) )
return True

class _PlainTextEdit( QtWidgets.QPlainTextEdit ) :

Expand Down
Loading

0 comments on commit ae1eafa

Please sign in to comment.