diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 385d7b8cb6e..4d4e7c0de0d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -29,21 +29,20 @@ jobs:
# and then use `include` to define their settings.
name: [
- linux,
- linux-debug,
+ linux-python2,
+ linux-python2-debug,
linux-python3,
- macos,
+ macos-python2,
]
include:
- - name: linux
+ - name: linux-python2
os: ubuntu-16.04
buildType: RELEASE
- variant: linux-python2
publish: true
containerImage: gafferhq/build:1.2.0
- dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/2.3.0/gafferDependencies-2.3.0-Python2-linux.tar.gz
+ dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/3.0.0/gafferDependencies-3.0.0-Python2-linux.tar.gz
# GitHub container builds run as root. This causes failures for tests that
# assert that filesystem permissions are respected, because root doesn't
# respect permissions. So we run the final test suite as a dedicated
@@ -51,13 +50,12 @@ jobs:
testRunner: su testUser -c
sconsCacheMegabytes: 400
- - name: linux-debug
+ - name: linux-python2-debug
os: ubuntu-16.04
buildType: DEBUG
- variant: linux-python2
publish: false
containerImage: gafferhq/build:1.2.0
- dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/2.3.0/gafferDependencies-2.3.0-Python2-linux.tar.gz
+ dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/3.0.0/gafferDependencies-3.0.0-Python2-linux.tar.gz
testRunner: su testUser -c
# Debug builds are ludicrously big, so we must use a larger cache
# limit. In practice this compresses down to 4-500Mb.
@@ -66,20 +64,18 @@ jobs:
- name: linux-python3
os: ubuntu-16.04
buildType: RELEASE
- variant: linux-python3
publish: true
containerImage: gafferhq/build:1.2.0
- dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/2.3.0/gafferDependencies-2.3.0-Python3-linux.tar.gz
+ dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/3.0.0/gafferDependencies-3.0.0-Python3-linux.tar.gz
testRunner: su testUser -c
sconsCacheMegabytes: 400
- - name: macos
+ - name: macos-python2
os: macos-10.15
buildType: RELEASE
- variant: macos-python2
publish: true
containerImage:
- dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/2.3.0/gafferDependencies-2.3.0-Python2-osx.tar.gz
+ dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/3.0.0/gafferDependencies-3.0.0-Python2-osx.tar.gz
testRunner: bash -c
sconsCacheMegabytes: 400
@@ -129,7 +125,7 @@ jobs:
echo GAFFER_SPHINX=`which sphinx-build` >> $GITHUB_ENV
env:
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GAFFER_BUILD_VARIANT: ${{ matrix.variant }}
+ GAFFER_BUILD_VARIANT: ${{ matrix.name }}
- name: Disable macOS PR Docs
run: |
@@ -161,6 +157,10 @@ jobs:
scons -j 2 build BUILD_TYPE=${{ matrix.buildType }} OPTIONS=.github/workflows/main/sconsOptions
- name: Test
+ # Tests should complete in well under an hour. If they don't it's most likely because
+ # of a hang, in which case we'd like to know more quickly than the default 6hr timeout
+ # allows.
+ timeout-minutes: 60
run: |
echo "::add-matcher::./.github/workflows/main/problemMatchers/unittest.json"
${{ matrix.testRunner }} "${{ env.GAFFER_BUILD_DIR }}/bin/gaffer test"
diff --git a/.github/workflows/main/installDependencies.py b/.github/workflows/main/installDependencies.py
old mode 100644
new mode 100755
index e24a8459f9c..72f3dfa7d0a
--- a/.github/workflows/main/installDependencies.py
+++ b/.github/workflows/main/installDependencies.py
@@ -37,13 +37,17 @@
import os
import sys
import argparse
-import urllib
import hashlib
+if sys.version_info[0] < 3 :
+ from urllib import urlretrieve
+else :
+ from urllib.request import urlretrieve
+
# Determine default archive URL.
platform = "osx" if sys.platform == "darwin" else "linux"
-defaultURL = "https://github.com/GafferHQ/dependencies/releases/download/2.1.1/gafferDependencies-2.1.1-Python2-" + platform + ".tar.gz"
+defaultURL = "https://github.com/ImageEngine/cortex/releases/download/10.2.0.0-a2/cortex-10.2.0.0-a2-" + platform + "-python2.tar.gz"
# Parse command line arguments.
@@ -74,7 +78,7 @@
# Download and unpack the archive.
sys.stderr.write( "Downloading dependencies \"%s\"\n" % args.archiveURL )
-archiveFileName, headers = urllib.urlretrieve( args.archiveURL )
+archiveFileName, headers = urlretrieve( args.archiveURL )
os.makedirs( args.dependenciesDir )
os.system( "tar xf %s -C %s --strip-components=1" % ( archiveFileName, args.dependenciesDir ) )
diff --git a/.github/workflows/main/setBuildVars.py b/.github/workflows/main/setBuildVars.py
index 0e5e0d126dd..7d61d5a5b3b 100755
--- a/.github/workflows/main/setBuildVars.py
+++ b/.github/workflows/main/setBuildVars.py
@@ -118,7 +118,6 @@
# We have a couple of naming conventions for builds, depending on the nature of the trigger.
formatVars = {
- "buildTypeSuffix" : "-debug" if os.environ.get( "BUILD_TYPE", "" ) == "DEBUG" else "",
"variant" : os.environ["GAFFER_BUILD_VARIANT"],
"timestamp" : datetime.datetime.now().strftime( "%Y_%m_%d_%H%M" ),
"pullRequest" : pullRequest,
@@ -128,9 +127,9 @@
}
nameFormats = {
- "default" : "gaffer-{timestamp}-{shortCommit}-{variant}{buildTypeSuffix}",
- "pull_request" : "gaffer-pr{pullRequest}-{branch}-{timestamp}-{shortCommit}-{variant}{buildTypeSuffix}",
- "release" : "gaffer-{tag}-{variant}{buildTypeSuffix}"
+ "default" : "gaffer-{timestamp}-{shortCommit}-{variant}",
+ "pull_request" : "gaffer-pr{pullRequest}-{branch}-{timestamp}-{shortCommit}-{variant}",
+ "release" : "gaffer-{tag}-{variant}"
}
trigger = os.environ.get( 'GITHUB_EVENT_NAME', '' )
diff --git a/.github/workflows/whitespaceCheck.yml b/.github/workflows/whitespaceCheck.yml
new file mode 100644
index 00000000000..a06236305e6
--- /dev/null
+++ b/.github/workflows/whitespaceCheck.yml
@@ -0,0 +1,13 @@
+name: Whitespace check
+on: [ pull_request ]
+jobs:
+ check:
+ runs-on: ubuntu-16.04
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ # So that we get the branch for `base_ref`.
+ fetch-depth: 0
+ - name: Check whitespace
+ run: |
+ git -c core.whitespace=indent-with-non-tab,tabwidth=1 diff --check refs/remotes/origin/${{ github.base_ref }} include src python
diff --git a/.gitignore b/.gitignore
index 0aa120ce601..5d677bba9fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,8 @@
*.swp
*.so
*.tmp
+*.desktop
+*.code-workspace
.gafferBackups
.idea
.sconf_temp
diff --git a/Changes.md b/Changes.md
index 05b0190b4d3..9e1ccf0bacb 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,3 +1,299 @@
+0.60.0.0
+========
+
+> Note : This version is built against Arnold 6.2.0.1, and is not compatible with earlier Arnold versions.
+
+Features
+--------
+
+- Spreadsheet : Added drag and drop reordering of rows.
+- InteractiveRender : Added support for motion blur.
+- Profiling : Added "Tools/Profiling" menu to annotate nodes with performance metrics.
+
+Improvements
+------------
+
+- Serialisation : Reduced script save times by around 50%.
+- Cancellation : Improved responsiveness by supporting cancellation of long computes in the following nodes :
+ - SceneReader
+ - LevelSetOffset
+ - MeshToLevelSet
+ - Plane
+ - Sphere
+ - DeleteFaces
+ - MeshDistortion
+ - MeshTangents
+ - MeshType
+ - PrimitiveSampler
+ - ResamplePrimitiveVariables
+ - ReverseWinding
+ - Seeds
+- Expression :
+ - Improved performance of Python expression evaluation when the same result is required in multiple threads. Specific expression benchmarks have shown a 10x speedup and some production scenes show an overall 15-30% improvement. Caution : This can expose pre-existing bugs in other nodes - see Breaking Changes for details.
+ - Improved error message when Python expression assigns an invalid value.
+- Numeric Bookmarks : Changed the Editor 1-9 hotkeys to follow the bookmark rather than pinning it (#4074).
+- Editors : Simplified the Editor Focus Menu, removing some seldom used (but potentially ambiguous) modes (#4074).
+- Timeline :
+ - Added support for sub-frame dragging with a Ctrl modifier, and fixed snapping of the frame indicator for regular drag operations.
+ - The current frame is now drawn next to the playhead.
+- Increased image processing tile size from 64 pixels to 128 pixels. This reduces per-tile overhead on large images, dramatically increasing effective image performance in many cases.
+- SceneNode/SceneProcessor : Enforced that the value of the `enabled` plug may not be varied using the `scene:path` context variable. Attempts to do so could result in the generation of invalid scenes. Filters are the appropriate way to enable or disable a node on a per-location basis, and should be used instead. This change yielded a 5-10% performance improvement for a moderately complex scene.
+- OSLImage : Avoided some unnecessary computes and hashing when calculating channel names or passing through channel data unaltered.
+- Context : Optimized `hash()` method, and reduced overhead in `EditableScope`.
+- NameSwitch/Spreadsheet : Rows with an empty name are now treated as if they were disabled. See Breaking Changes for further details.
+- ContextVariables : Improved performance by around 50%.
+- FilterResults : Improved performance.
+- SceneAlgo : Reduced threading overhead for `parallelProcessLocations()`, `parallelTraverse()` and `filteredParallelTraverse()`. This is particularly noticeable when visiting locations with many children.
+- Set : Added wildcard support to the `name` plug.
+- GraphEditor : Added tool menu with options to control visibility of annotations.
+- Render : Improved scene generation times for renders that use `dispatcher.batchSize` to
+ render multiple frames at once. Previously Gaffer's cache was cleared after scene generation
+ on each frame, but this is now only done for single-frame batches.
+
+Fixes
+-----
+
+- Instancer : Fixed variation of prototype root attributes using context variables.
+- ScriptNode : Fixed bugs that allowed global variables to remain in the context after they had been disabled, renamed or deleted.
+- SceneReader :
+ - Fixed crash when reading Alembic caches with non-scalar `userProperties`.
+ - Fixed crash when reading Alembic caches with invalid primitive variables.
+- UDIMQuery and OSLImage : Fixed incorrectly isolated TBB which could cause hang when other nodes use Standard cache policy. Now uses TaskCollaboration to improve performance.
+- Wrapper : Removed the `PYTHONHOME` environment variable. This fixes problems running Gaffer in python-enabled versions of `gdb`.
+- CompoundNumericPlug : Fixed serialisation of dynamic plugs with non-default interpretations.
+
+API
+---
+
+- Context :
+ - Refactored to allow EditableScope to avoid memory allocation where possible.
+ - Added fast non-allocating `EditableScope::set( name, const T * )` overload. This should be used in preference to the old `set( name, const T & )` method.
+ - Added `EditableScope::setAllocated()` method to replace the old `set()` method in the rare circumstance where allocation is required.
+ - Added `variableHash()` method, which returns the hash for an individual variable.
+ - Added `getIfExists()` method, which returns `nullptr` if a variable doesn't exist.
+ - Added `getAsData()` method, which returns a copy of a variable as `IECore::Data`.
+ - Added `TypeDescription` registration class, which must be used to register any custom data types used in context variables.
+- GraphComponent : Added `reorderChildren()` and `childrenReorderedSignal()` methods.
+- Serialisation : Added `addModule()` method, for adding imports to the serialisation.
+- Slider :
+ - Added optional value snapping for drag and button press operations. This is controlled via the `setSnapIncrement()` and `getSnapIncrement()` methods.
+ - Added `setHoverPositionVisible()` and `getHoverPositionVisible()` accessors to control an optional position indicator drawn under the pointer.
+- Expression : Added `Engine::executeCachePolicy()` method which must be implemented by subclasses.
+- ImageAlgo : Added constants for the default channel names - `channelNameR` etc.
+- SceneAlgo : Added optional `root` argument to `filteredParallelTraverse( scene, pathMatcher )`.
+- MetadataAlgo :
+ - Added optional `user` argument to `addAnnotationTemplate()`.
+ - Added optional `userOnly` argument to `annotationTemplates()`.
+- AnnotationsGadget : Added `setVisibleAnnotations()` and `getVisibleAnnotations()` methods to allow filtering of annotations.
+- MonitorAlgo : Added `removePerformanceAnnotations()` and `removeContextAnnotations()` methods.
+- Deformer : Added `affectsProcessedObjectBound()`, `hashProcessedObjectBound()` and `computeProcessedObjectBound()` virtual
+ methods. These can optionally be overridden by derived classes to compute faster approximate bounds where possible.
+
+Breaking Changes
+----------------
+
+- NameSwitch/Spreadsheet : Rows with an empty name are now treated as if they were disabled. Previously they would cause confusion by being matched against empty selectors. Use the default row for empty selectors instead, or alternatively use a catch-all `*` row.
+- Context :
+ - Removed `Ownership` enum. The copy constructor now always performs a full copy.
+ - Removed `changed()` method.
+ - Removed `_copy` argument from `get()` Python binding.
+- Slider/NumericSlider :
+ - Refactored Slider to provide all the functionality of NumericSlider, and removed NumericSlider.
+ - Renamed initial constructor argument from `value` to `values`.
+ - Removed `setPositions()/getPositions()` and `setPosition()/getPosition()` methods from `Slider`. Use `setValues()/getValues()` and `setValue()/getValue()` instead.
+ - Removed `positionChangedSignal()` from `Slider`. Use `valueChangedSignal()` instead.
+ - Removed `PositionChangedReason` from `Slider`. Use `ValueChangedReason` instead.
+ - Removed `setPositionIncrement()/getPositionIncrement()` from `Slider`. Use `setIncrement()/getIncrement()` instead.
+ - Replaced `_drawPosition()` method with `_drawValue()`.
+- StandardOptions : Removed `cameraBlur` plug. This never functioned as advertised, as the regular `transformBlur` and `deformationBlur` blur settings were applied to cameras instead. As before, a StandardAttributes node may be used to customise blur for individual cameras.
+- SceneAlgo :
+ - Changed signature of the following methods to use `GafferScene::FilterPlug` : `matchingPaths`, `filteredParallelTraverse`, `Detail::ThreadableFilteredFunctor`.
+ - Removed `filteredParallelTraverse()` overload which accepted a `Filter *`. Pass `filter->outPlug()` instead.
+- DeleteFaces / DeletePoints / DeleteCurves : The PrimitiveVariable name is now taken verbatim, rather than stripping whitespace.
+- Serialisation :
+ - Disabled copy construction.
+ - The following methods now take a `const object &` where they used to take `object &` :
+ - `modulePath()`
+ - `classPath()`
+ - The following methods now take a `Serialisation &` argument where they used to take `const Serialisation &` :
+ - `constructor()`
+ - `postConstructor()`
+ - `postHierarchy()`
+ - `postScript()`
+- ValuePlugBinding :
+ - `repr()` now takes a `Serialisation *` where it used to take a `const Serialisation *`.
+ - `valueRepr()` now has an optional `serialisation` argument.
+- Metadata : Renamed signal types :
+ - `NodeValueChangedSignal` -> `LegacyNodeValueChangedSignal`
+ - `PlugValueChangedSignal` -> `LegacyPlugValueChangedSignal`
+ - `NodeValueChangedSignal2` -> `NodeValueChangedSignal`
+ - `PlugValueChangedSignal2` -> `PlugValueChangedSignal`
+- MetadataBinding :
+ - Added `serialisation` required argument to `metadataSerialisation()`.
+ - Removed `metadataModuleDependencies()` method. Module dependencies are now declared automatically by `metadataSerialisation()`.
+- Editors : Removed the 'Follow Scene Selection' mode from the Node Editor Focus menu (#4074).
+- GafferSceneUI : Removed `SourceSet`.
+- ScriptNode : Added private member data.
+- Expression : Changed the Python expression cache policy to `Standard`. This executes expressions behind a lock, and can cause hangs if buggy upstream nodes perform TBB tasks without an appropriate `TaskIsolation` or `TaskCollaboration` policy. In this case, the `GAFFER_PYTHONEXPRESSION_CACHEPOLICY` environment variable may be set to `Legacy` or `TaskIsolation` while the bugs are fixed.
+- Node : Removed `plugFlagsChangedSignal()`. We aim to phase flags out completely in future, and none of the current flags are expected to be changed after construction.
+- ContextProcessor : Added `storage` argument to `processContext()` method.
+- FilteredChildIterator/FilteredRecursiveChildIterator : Annotated all namespace-level typedefs with `[[deprecated]]`. These were already documented as deprecated in Gaffer 0.59.0.0, but their use will now trigger compiler warnings. Please use the class-level typedefs instead, for example `Plug::Iterator` in place of `PlugIterator`.
+- RendererAlgo : Removed from the API. The render adaptor registry and `applyCameraGlobals()` are still available, but have been moved to SceneAlgo.
+- MonitorAlgo : Removed deprecated `annotate()` overloads. Source compatibility is retained.
+- Instancer : Attributes from the prototype root are now placed at the instance root, rather than on the instance group. This allows context variation to potentially vary these attributes. Usually attribute inheritance will mean that this behaves the same, but scenes which explicitly override attributes at specific locations in the hierarchy after an instancer could see modified behaviour.
+- PointsGridToPoints : Changed default value of `filter` input, so that a filter must now be connected to specify the objects to modify.
+- GafferVDB : Changed base class of the following nodes :
+ - LevelSetToMesh
+ - MeshToLevelSet
+ - LevelSetOffset
+ - PointsGridToPoints
+- LevelSetToMesh : Changed default value for `adjustBounds` plug.
+
+Build
+-----
+
+- Moved minimum required C++ standard to C++14.
+- Moved minimum required TBB version to 2018 Update 3.
+- Dependencies : Updated to GafferHQ/dependencies 3.0.0 :
+ - USD 21.05.
+ - OpenImageIO 2.2.15.1.
+ - OpenShadingLanguage 1.11.14.1.
+ - LibTIFF 4.1.0.
+ - LLVM 10.0.1.
+ - OpenVDB 7.2.2.
+ - Cortex 10.2.0.0.
+
+0.59.9.0 (relative to 0.59.8.0)
+========
+
+Features
+--------
+
+- TransformQuery : Added a new node to query the transform for a scene location.
+- BoundQuery : Added a new node to query the bound for a scene location.
+- ExistenceQuery : Added a new node to query whether a scene location exists.
+
+Improvements
+------------
+
+- OSLShader : Reduced loading times where many nodes reference the same shader.
+- Spreadsheet : Added `activeRowNames` plug to the Node Editor UI, in the Advanced tab.
+
+Fixes
+-----
+
+- ArnoldMeshLight : Fixed label for `cameraVisibility` plug.
+
+Documentation
+-------------
+
+- Fixed code samples in "Tutorials : Querying a Scene".
+
+0.59.8.0 (relative to 0.59.7.0)
+========
+
+Features
+--------
+
+- Viewer : Added multiple color inspectors. Ctrl+click on an image
+ to create a pixel inspector, or Ctrl+drag to create an area
+ inspector. The image footer now shows the results from all your inspectors,
+ and allows you to add or delete them.
+- FilterQuery : Added a new node for querying the results of a filter at a specific location.
+- GraphEditor : Added "Annotate..." item to the node context menu. This can be configured with
+ multiple annotation templates using the `MetadataAlgo` API.
+
+Improvements
+------------
+
+- Set : Added `setVariable` plug to allow the input filter to be varied depending on the set name.
+- TabbedContainer : Added menu button to allow selection of tabs that are not
+ visible due to a lack of horizontal space.
+
+Fixes
+-----
+
+- Arnold : Fixed rendering of encapsulated objects for which automatic instancing
+ is not possible. Examples include curves with non-zero `ai:curves:min_pixel_width`
+ and meshes with non-zero `ai:polymesh:subdiv_adaptive_error`.
+- PlugValueWidget : Fixed bug that tried to update the widget before all graph edits were complete.
+- GraphEditor : Fixed framing of nodes dropped into the editor. This was incorrect when the editor was
+ not at the default zoom.
+- OSL Constant : Fixed usage as a surface shader in Arnold.
+
+API
+---
+
+- Context :
+ - Added forwards compatibility for methods added to provide enhanced
+ performance in Gaffer 0.60. This allows the same code to be compiled for
+ both Gaffer 0.60 and Gaffer 0.59 (but with only the Gaffer 0.60 build
+ benefiting from improved performance).
+ - Added support for `IECore::InternedString` variables in `substitute()`.
+- MetadataAlgo : Added functions for managing annotations on nodes.
+- MonitorAlgo : Added `persistent` argument to `annotate()` functions.
+
+0.59.7.0 (relative to 0.59.6.0)
+========
+
+Improvements
+------------
+
+- Parent :
+ - Added `parentVariable` plug, to create a context variable that passes the
+ parent location to nodes upstream of the `children` plug. This allows the children
+ to be varied procedurally according to what they are parented to.
+ - Added `destination` plug, to allow children to be placed elsewhere in the scene
+ while still inheriting the transform of the "parent". This is particularly useful
+ when parenting lights to geometry.
+- Seeds : Added `destination` plug, to control where the points are placed in the scene
+ relative to the meshes they are generated from.
+- Duplicate :
+ - Added `filter` input, allowing multiple objects to be duplicated at once.
+ - Added `destination` plug, to control where the copies are placed relative to the
+ original.
+ - Improved performance for large numbers of copies.
+ - Deprecated the `target` plug. Please use filters instead.
+- Outputs : Reduced the time taken to show the NodeEditor by around 90%.
+- NodeEditor : The "Node Name" label is now draggable. For instance, it can be dragged to the PythonEditor to get a reference to the node or to the GraphEditor to find the node in the graph.
+- GraphEditor : Improved framing of nodes dragged and dropped onto the GraphEditor :
+ - Changed pointer to indicate that framing will take place.
+ - Nodes are framed directly under the pointer instead of at the centre of the widget.
+ - Fixed framing of nodes not currently in the GraphEditor.
+ - Removed framing of _plugs_ dragged to the GraphEditor. This was unintuitive and interacted poorly with the dragging of plugs to make
+ connections. The NodeEditor's "Node Name" label can be dragged instead to locate a node from the NodeEditor.
+- SceneInspector : Improved history view :
+ - Added the full path to nodes so that nodes nested in Boxes can be identified.
+ - Added edit button to open a NodeEditor for nodes in the history.
+ - Fixed gap in between sections.
+- FilterResults : Added `root` plug. This can be used to limit the results to `root` and its descendants.
+- CollectScenes : Added tab completion and a scene browser to the UI for the `sourceRoot` plug.
+- BackgroundTaskDialogue :
+ - Removed focus from "Cancel" button to make it harder to cancel accidentally.
+ - Added Esc cancellation shortcut.
+
+Fixes
+-----
+
+- Widget : Fixed drag handling bug that could cause `dragEnterSignal()` to be emitted again on a widget that had already accepted the drag.
+- FilterResults : Fixed bug handling matches at the root location.
+- NodeEditor : Fixed activator and summary updates which were skipped if the layout was not visible when the node was edited.
+- Dispatcher : Fixed dispatching when `dispatcher.batchSize` or `dispatcher.immediate` are driven by context variables.
+- SceneNode : Fixed bug hashing the transform for the root location.
+
+API
+---
+
+- SceneAlgo :
+ - Added overloads with `root` argument for `parallelTraverse()`, `filteredParallelTraverse()`, `matchingPaths()` and `matchingPathsHash()`.
+ - Deprecated `matchingPaths()` overloads taking `Filter *`. Pass a `Filter.out` plug instead.
+ - Added Python bindings for `matchingPathsHash()`.
+- ScenePlug :
+ - Added support for `..` in `stringToPath()`.
+ - Added `stringToPath()` and `pathToString()` overloads that return a result rather than passing it by reference.
+- GafferUI.FileMenu : Added `dialogueParentWindow` argument to `addScript()`.
+- Spreadsheet : Added support for per-plug `ui:spreadsheet:selectorValue` metadata. This defines the initial value for `selector` when the UI is used to create a spreadsheet for the plug.
+
0.59.6.0 (relative to 0.59.5.0)
========
@@ -401,6 +697,24 @@ Build
- OpenSSL 1.1.1h
- See https://github.com/GafferHQ/dependencies/releases/tag/2.1.1 for full details.
+0.58.6.7 (relative to 0.58.6.6)
+========
+
+Fixes
+-----
+
+- ArnoldMeshLight : Fixed label for `cameraVisibility` plug.
+
+0.58.6.6 (relative to 0.58.6.5)
+========
+
+Fixes
+-----
+
+- Arnold : Fixed rendering of encapsulated objects for which automatic instancing
+ is not possible. Examples include curves with non-zero `ai:curves:min_pixel_width`
+ and meshes with non-zero `ai:polymesh:subdiv_adaptive_error`.
+
0.58.6.5 (relative to 0.58.6.4)
========
diff --git a/SConstruct b/SConstruct
index fc6ec6a3b27..6d860f04172 100644
--- a/SConstruct
+++ b/SConstruct
@@ -51,8 +51,8 @@ import subprocess
###############################################################################################
gafferMilestoneVersion = 0 # for announcing major milestones - may contain all of the below
-gafferMajorVersion = 59 # backwards-incompatible changes
-gafferMinorVersion = 6 # new backwards-compatible features
+gafferMajorVersion = 60 # backwards-incompatible changes
+gafferMinorVersion = 0 # new backwards-compatible features
gafferPatchVersion = 0 # bug fixes
# All of the following must be considered when determining
@@ -100,8 +100,8 @@ options.Add(
options.Add(
"CXXSTD",
- "The C++ standard to build against. A minimum of C++11 is required.",
- "c++11",
+ "The C++ standard to build against. A minimum of C++14 is required.",
+ "c++14",
)
options.Add(
@@ -398,7 +398,12 @@ elif env["PLATFORM"] == "posix" :
if "g++" in os.path.basename( env["CXX"] ) :
+ # Get GCC version.
gccVersion = subprocess.check_output( [ env["CXX"], "-dumpversion" ], env=env["ENV"] ).decode().strip()
+ if "." not in gccVersion :
+ # GCC 7 onwards requires `-dumpfullversion` to get minor/patch, but this
+ # flag does not exist on earlier GCCs, where minor/patch was provided by `-dumpversion`.
+ gccVersion = subprocess.check_output( [ env["CXX"], "-dumpfullversion" ], env=env["ENV"] ).decode().strip()
gccVersion = [ int( v ) for v in gccVersion.split( "." ) ]
# GCC 4.1.2 in conjunction with boost::flat_map produces crashes when
@@ -421,6 +426,9 @@ elif env["PLATFORM"] == "posix" :
if gccVersion >= [ 5, 1 ] :
env.Append( CXXFLAGS = [ "-D_GLIBCXX_USE_CXX11_ABI=0" ] )
+ if gccVersion >= [ 9, 2 ] :
+ env.Append( CXXFLAGS = [ "-Wsuggest-override" ] )
+
env["GAFFER_PLATFORM"] = "linux"
env.Append( CXXFLAGS = [ "-std=$CXXSTD", "-fvisibility=hidden" ] )
@@ -818,7 +826,7 @@ libraries = {
"GafferImageUI" : {
"envAppends" : {
- "LIBS" : [ "IECoreGL$CORTEX_LIB_SUFFIX", "Gaffer", "GafferImage", "GafferUI", "OpenColorIO$OCIO_LIB_SUFFIX" ],
+ "LIBS" : [ "IECoreGL$CORTEX_LIB_SUFFIX", "Gaffer", "GafferImage", "GafferUI", "OpenColorIO$OCIO_LIB_SUFFIX", "IECoreScene$CORTEX_LIB_SUFFIX" ],
},
"pythonEnvAppends" : {
"LIBS" : [ "GafferBindings", "GafferUI", "GafferImage", "GafferImageUI" ],
diff --git a/bin/gaffer b/bin/gaffer
index 968ece40efc..cb04311a654 100755
--- a/bin/gaffer
+++ b/bin/gaffer
@@ -155,19 +155,12 @@ fi
# Get python set up properly
##########################################################################
-# Make sure PYTHONHOME is pointing to our internal python build.
-# We only do this if Gaffer has been built with an internal version
-# of python - otherwise we assume the existing environment is providing
-# the right value.
-
+# Unset PYTHONHOME to make sure our internal Python build is used in preference
+# to anything in the external environment. We only do this if Gaffer has been
+# built with an internal version of Python - otherwise we assume the existing
+# environment is providing the right value.
if [[ -e $GAFFER_ROOT/bin/python ]] ; then
-
- if [[ `uname` = "Linux" ]] ; then
- export PYTHONHOME="$GAFFER_ROOT"
- else
- export PYTHONHOME="$GAFFER_ROOT/lib/Python.framework/Versions/Current"
- fi
-
+ unset PYTHONHOME
fi
# Get python module path set up
diff --git a/config/installArnold.sh b/config/installArnold.sh
index 40f2e6a1f3f..98bff50c1e1 100755
--- a/config/installArnold.sh
+++ b/config/installArnold.sh
@@ -37,7 +37,7 @@
set -e
-arnoldVersion=6.0.1.0
+arnoldVersion=6.2.0.1
if [[ `uname` = "Linux" ]] ; then
arnoldPlatform=linux
diff --git a/config/installDependencies.sh b/config/installDependencies.sh
index 69fc9301d42..c61266b3373 100755
--- a/config/installDependencies.sh
+++ b/config/installDependencies.sh
@@ -55,14 +55,4 @@ buildDir=${1:-"build/gaffer-$gafferMilestoneVersion.$gafferMajorVersion.$gafferM
# Get the prebuilt dependencies package and unpack it into the build directory
-dependenciesVersion="2.1.1"
-dependenciesVersionSuffix=""
-dependenciesPythonVersion="2"
-dependenciesFileName="gafferDependencies-$dependenciesVersion-Python$dependenciesPythonVersion-$platform.tar.gz"
-downloadURL="https://github.com/GafferHQ/dependencies/releases/download/$dependenciesVersion$dependenciesVersionSuffix/$dependenciesFileName"
-
-echo "Downloading dependencies \"$downloadURL\""
-curl -L $downloadURL > $dependenciesFileName
-
-mkdir -p $buildDir
-tar xf $dependenciesFileName -C $buildDir --strip-components=1
+.github/workflows/main/installDependencies.py --dependenciesDir "$buildDir"
diff --git a/contrib/scripts/buildCompileCommands.py b/contrib/scripts/buildCompileCommands.py
index 936d1db5828..86c78bcac03 100644
--- a/contrib/scripts/buildCompileCommands.py
+++ b/contrib/scripts/buildCompileCommands.py
@@ -16,7 +16,7 @@
# Make SCons tell us everything it would do to build Gaffer
subprocess.check_call( [ "scons", "--clean" ] )
-sconsOutput = subprocess.check_output( [ "scons", "build", "--dry-run", "--no-cache" ] )
+sconsOutput = subprocess.check_output( [ "scons", "build", "--dry-run", "--no-cache" ], universal_newlines = True )
# Write that into a "compile_commands.json" file
@@ -31,7 +31,7 @@
file = line.split()[-1]
data.append(
{
- "directory" : "/Users/john/dev/gaffer",
+ "directory" : os.getcwd(),
"command" : line,
"file" : file,
}
diff --git a/doc/source/GettingStarted/TutorialAssemblingTheGafferBot/index.md b/doc/source/GettingStarted/TutorialAssemblingTheGafferBot/index.md
index c1960366d83..a08139d69e6 100644
--- a/doc/source/GettingStarted/TutorialAssemblingTheGafferBot/index.md
+++ b/doc/source/GettingStarted/TutorialAssemblingTheGafferBot/index.md
@@ -309,7 +309,7 @@ To make switching between viewing Gaffy's geometry and the render easier, you ca
1. Select the InteractiveAppleseedRender node.
-2. From the editor focus menu ![](images/editorFocusMenuNodeSelectionLinked.png "The editor focus menu") at the top-right of the top panel, choose _Node Selection_ in the _Pin_ group. The menu's icon will change to the pinned icon (![](images/nodeSetStandardSet.png "highlighted pin")) to show it is now locked to a specific node, and the Viewer's title in the tab bar will now include _[InteractiveAppleseedRender]_ to help you keep track of which node(s) are pinned in which editors.
+2. From the editor focus menu ![](images/editorFocusMenuNodeSelectionLinked.png "The editor focus menu") at the top-right of the top panel, choose _Pin InteractiveAppleseedRender_. The menu's icon will change to the pinned icon (![](images/nodeSetStandardSet.png "highlighted pin")) to show it is now locked to a specific node, and the Viewer's title in the tab bar will now include _[InteractiveAppleseedRender]_ to help you keep track of which node(s) are pinned in which editors.
![](images/viewerPinnedMaster.png "The Viewer's tab bar and editor focus menu when pinned to a specific node")
@@ -394,7 +394,7 @@ For lights to take effect, they need to be combined with the main scene. For sim
- Set the Sun Phi Angle plug to `100`.
- Set the Luminance plug to `2.5`.
-4. Connect the node's out plug to the Group node's in3 plug.
+4. Connect the node's out plug to the Group node's in2 plug.
![](images/graphEditorEnvironmentLightNode.png "A new environment light node")
diff --git a/doc/source/WorkingWithThePythonScriptingAPI/TutorialQueryingAScene/index.md b/doc/source/WorkingWithThePythonScriptingAPI/TutorialQueryingAScene/index.md
index 6874d5a9d5b..36528a2f034 100644
--- a/doc/source/WorkingWithThePythonScriptingAPI/TutorialQueryingAScene/index.md
+++ b/doc/source/WorkingWithThePythonScriptingAPI/TutorialQueryingAScene/index.md
@@ -11,181 +11,75 @@ First off, we'll create a simple scene using a network of basic nodes. Cut and p
import Gaffer
import GafferScene
import IECore
+import imath
__children = {}
__children["Sphere"] = GafferScene.Sphere( "Sphere" )
-root.addChild( __children["Sphere"] )
-__children["Sphere"]["enabled"].setValue( True )
-__children["Sphere"]["name"].setValue( 'sphere' )
-__children["Sphere"]["transform"]["translate"]["x"].setValue( 0.0 )
-__children["Sphere"]["transform"]["translate"]["y"].setValue( 1.0 )
-__children["Sphere"]["transform"]["translate"]["z"].setValue( 0.0 )
-__children["Sphere"]["transform"]["rotate"]["x"].setValue( 0.0 )
-__children["Sphere"]["transform"]["rotate"]["y"].setValue( 0.0 )
-__children["Sphere"]["transform"]["rotate"]["z"].setValue( 0.0 )
-__children["Sphere"]["transform"]["scale"]["x"].setValue( 1.0 )
-__children["Sphere"]["transform"]["scale"]["y"].setValue( 1.0 )
-__children["Sphere"]["transform"]["scale"]["z"].setValue( 1.0 )
-__children["Sphere"]["type"].setValue( 1 )
-__children["Sphere"]["radius"].setValue( 1.0 )
-__children["Sphere"]["zMin"].setValue( -1.0 )
-__children["Sphere"]["zMax"].setValue( 1.0 )
-__children["Sphere"]["thetaMax"].setValue( 360.0 )
-__children["Sphere"]["divisions"]["x"].setValue( 20 )
-__children["Sphere"]["divisions"]["y"].setValue( 40 )
-__children["Sphere"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Sphere"]["__uiPosition"]["x"].setValue( -9.311037063598633 )
-__children["Sphere"]["__uiPosition"]["y"].setValue( 13.027215003967285 )
-__children["Sphere"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Sphere"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["Sphere"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["Sphere"] )
+__children["Sphere"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Sphere"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Plane"] = GafferScene.Plane( "Plane" )
-root.addChild( __children["Plane"] )
-__children["Plane"]["enabled"].setValue( True )
-__children["Plane"]["name"].setValue( 'plane' )
-__children["Plane"]["transform"]["translate"]["x"].setValue( 0.0 )
-__children["Plane"]["transform"]["translate"]["y"].setValue( 0.0 )
-__children["Plane"]["transform"]["translate"]["z"].setValue( 0.0 )
-__children["Plane"]["transform"]["rotate"]["x"].setValue( 90.0 )
-__children["Plane"]["transform"]["rotate"]["y"].setValue( 0.0 )
-__children["Plane"]["transform"]["rotate"]["z"].setValue( 0.0 )
-__children["Plane"]["transform"]["scale"]["x"].setValue( 1.0 )
-__children["Plane"]["transform"]["scale"]["y"].setValue( 1.0 )
-__children["Plane"]["transform"]["scale"]["z"].setValue( 1.0 )
-__children["Plane"]["dimensions"]["x"].setValue( 10.0 )
-__children["Plane"]["dimensions"]["y"].setValue( 10.0 )
-__children["Plane"]["divisions"]["x"].setValue( 2 )
-__children["Plane"]["divisions"]["y"].setValue( 2 )
-__children["Plane"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Plane"]["__uiPosition"]["x"].setValue( -21.662202835083008 )
-__children["Plane"]["__uiPosition"]["y"].setValue( 13.181886672973633 )
-__children["Plane"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Plane"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["Plane"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["Plane"] )
+__children["Plane"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Plane"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Group"] = GafferScene.Group( "Group" )
-root.addChild( __children["Group"] )
-__children["Group"]["enabled"].setValue( True )
-__children["Group"]["name"].setValue( 'geometry' )
-__children["Group"]["transform"]["translate"]["x"].setValue( 0.0 )
-__children["Group"]["transform"]["translate"]["y"].setValue( 0.0 )
-__children["Group"]["transform"]["translate"]["z"].setValue( 0.0 )
-__children["Group"]["transform"]["rotate"]["x"].setValue( 0.0 )
-__children["Group"]["transform"]["rotate"]["y"].setValue( 0.0 )
-__children["Group"]["transform"]["rotate"]["z"].setValue( 0.0 )
-__children["Group"]["transform"]["scale"]["x"].setValue( 1.0 )
-__children["Group"]["transform"]["scale"]["y"].setValue( 1.0 )
-__children["Group"]["transform"]["scale"]["z"].setValue( 1.0 )
-__children["Group"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Group"]["__uiPosition"]["x"].setValue( -15.069395065307617 )
-__children["Group"]["__uiPosition"]["y"].setValue( 1.615199089050293 )
-__children["Group"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Group"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["Group"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["Group"] )
+__children["Group"]["in"].addChild( GafferScene.ScenePlug( "in1", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Group"]["in"].addChild( GafferScene.ScenePlug( "in2", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Group"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Group"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Camera"] = GafferScene.Camera( "Camera" )
-root.addChild( __children["Camera"] )
-__children["Camera"]["enabled"].setValue( True )
-__children["Camera"]["name"].setValue( 'camera' )
-__children["Camera"]["transform"]["translate"]["x"].setValue( 0.0 )
-__children["Camera"]["transform"]["translate"]["y"].setValue( 1.100000023841858 )
-__children["Camera"]["transform"]["translate"]["z"].setValue( 5.300000190734863 )
-__children["Camera"]["transform"]["rotate"]["x"].setValue( 0.0 )
-__children["Camera"]["transform"]["rotate"]["y"].setValue( 0.0 )
-__children["Camera"]["transform"]["rotate"]["z"].setValue( 0.0 )
-__children["Camera"]["transform"]["scale"]["x"].setValue( 1.0 )
-__children["Camera"]["transform"]["scale"]["y"].setValue( 1.0 )
-__children["Camera"]["transform"]["scale"]["z"].setValue( 1.0 )
-__children["Camera"]["projection"].setValue( 'perspective' )
-__children["Camera"]["fieldOfView"].setValue( 50.0 )
-__children["Camera"]["clippingPlanes"]["x"].setValue( 0.009999999776482582 )
-__children["Camera"]["clippingPlanes"]["y"].setValue( 100000.0 )
-__children["Camera"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Camera"]["__uiPosition"]["x"].setValue( 3.1233882904052734 )
-__children["Camera"]["__uiPosition"]["y"].setValue( 13.14145278930664 )
-__children["Camera"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Camera"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["Camera"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["Camera"] )
+__children["Camera"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Camera"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Group1"] = GafferScene.Group( "Group1" )
-root.addChild( __children["Group1"] )
-__children["Group1"]["enabled"].setValue( True )
-__children["Group1"]["name"].setValue( 'world' )
-__children["Group1"]["transform"]["translate"]["x"].setValue( 0.0 )
-__children["Group1"]["transform"]["translate"]["y"].setValue( 0.0 )
-__children["Group1"]["transform"]["translate"]["z"].setValue( 0.0 )
-__children["Group1"]["transform"]["rotate"]["x"].setValue( 0.0 )
-__children["Group1"]["transform"]["rotate"]["y"].setValue( 0.0 )
-__children["Group1"]["transform"]["rotate"]["z"].setValue( 0.0 )
-__children["Group1"]["transform"]["scale"]["x"].setValue( 1.0 )
-__children["Group1"]["transform"]["scale"]["y"].setValue( 1.0 )
-__children["Group1"]["transform"]["scale"]["z"].setValue( 1.0 )
-__children["Group1"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Group1"]["__uiPosition"]["x"].setValue( -8.414341926574707 )
-__children["Group1"]["__uiPosition"]["y"].setValue( -9.591415405273438 )
-__children["Group1"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["Group1"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["Group1"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["Group1"] )
+__children["Group1"]["in"].addChild( GafferScene.ScenePlug( "in1", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Group1"]["in"].addChild( GafferScene.ScenePlug( "in2", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Group1"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Group1"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["StandardOptions"] = GafferScene.StandardOptions( "StandardOptions" )
-root.addChild( __children["StandardOptions"] )
-__children["StandardOptions"]["enabled"].setValue( True )
-__children["StandardOptions"]["options"]["renderCamera"]["name"].setValue( 'render:camera' )
-__children["StandardOptions"]["options"]["renderCamera"]["value"].setValue( '/world/camera' )
-__children["StandardOptions"]["options"]["renderCamera"]["enabled"].setValue( True )
-__children["StandardOptions"]["options"]["renderResolution"]["name"].setValue( 'render:resolution' )
-__children["StandardOptions"]["options"]["renderResolution"]["value"]["x"].setValue( 1024 )
-__children["StandardOptions"]["options"]["renderResolution"]["value"]["y"].setValue( 778 )
-__children["StandardOptions"]["options"]["renderResolution"]["enabled"].setValue( True )
-__children["StandardOptions"]["options"]["cameraBlur"]["name"].setValue( 'render:cameraBlur' )
-__children["StandardOptions"]["options"]["cameraBlur"]["value"].setValue( False )
-__children["StandardOptions"]["options"]["cameraBlur"]["enabled"].setValue( False )
-__children["StandardOptions"]["options"]["transformBlur"]["name"].setValue( 'render:transformBlur' )
-__children["StandardOptions"]["options"]["transformBlur"]["value"].setValue( False )
-__children["StandardOptions"]["options"]["transformBlur"]["enabled"].setValue( False )
-__children["StandardOptions"]["options"]["deformationBlur"]["name"].setValue( 'render:deformationBlur' )
-__children["StandardOptions"]["options"]["deformationBlur"]["value"].setValue( False )
-__children["StandardOptions"]["options"]["deformationBlur"]["enabled"].setValue( False )
-__children["StandardOptions"]["options"]["shutter"]["name"].setValue( 'render:shutter' )
-__children["StandardOptions"]["options"]["shutter"]["value"]["x"].setValue( -0.25 )
-__children["StandardOptions"]["options"]["shutter"]["value"]["y"].setValue( 0.25 )
-__children["StandardOptions"]["options"]["shutter"]["enabled"].setValue( False )
-__children["StandardOptions"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["StandardOptions"]["__uiPosition"]["x"].setValue( -6.914341926574707 )
-__children["StandardOptions"]["__uiPosition"]["y"].setValue( -26.473411560058594 )
-__children["StandardOptions"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["StandardOptions"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["StandardOptions"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["StandardOptions"] )
+__children["StandardOptions"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["StandardOptions"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CustomAttributes"] = GafferScene.CustomAttributes( "CustomAttributes" )
-root.addChild( __children["CustomAttributes"] )
-__children["CustomAttributes"]["enabled"].setValue( True )
-__children["CustomAttributes"]["attributes"].addChild( Gaffer.CompoundDataPlug.MemberPlug( "member1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["CustomAttributes"]["attributes"]["member1"].addChild( Gaffer.StringPlug( "name", defaultValue = '', flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["CustomAttributes"]["attributes"]["member1"]["name"].setValue( 'myString' )
-__children["CustomAttributes"]["attributes"]["member1"].addChild( Gaffer.StringPlug( "value", defaultValue = '', flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["CustomAttributes"]["attributes"]["member1"]["value"].setValue( 'aaa' )
-__children["CustomAttributes"]["attributes"]["member1"].addChild( Gaffer.BoolPlug( "enabled", defaultValue = True, flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["CustomAttributes"]["attributes"]["member1"]["enabled"].setValue( True )
-__children["CustomAttributes"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["CustomAttributes"]["__uiPosition"]["x"].setValue( -6.914341926574707 )
-__children["CustomAttributes"]["__uiPosition"]["y"].setValue( -18.878076553344727 )
-__children["CustomAttributes"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["CustomAttributes"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["CustomAttributes"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["CustomAttributes"] )
+__children["CustomAttributes"]["attributes"].addChild( Gaffer.NameValuePlug( "", Gaffer.StringPlug( "value", defaultValue = '', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), True, "member1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
+__children["CustomAttributes"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["CustomAttributes"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["PathFilter"] = GafferScene.PathFilter( "PathFilter" )
-root.addChild( __children["PathFilter"] )
-__children["PathFilter"]["paths"].setValue( IECore.StringVectorData( [ "/world/geometry/sphere" ] ) )
-__children["PathFilter"].addChild( Gaffer.V2fPlug( "__uiPosition", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["PathFilter"]["__uiPosition"]["x"].setValue( 3.9433956146240234 )
-__children["PathFilter"]["__uiPosition"]["y"].setValue( -9.495070457458496 )
-__children["PathFilter"].addChild( Gaffer.V2fPlug( "__uiPosition1", flags = Gaffer.Plug.Flags.Dynamic | Gaffer.Plug.Flags.Serialisable | Gaffer.Plug.Flags.AcceptsInputs | Gaffer.Plug.Flags.PerformsSubstitutions | Gaffer.Plug.Flags.Cacheable, ) )
-__children["PathFilter"]["__uiPosition1"]["x"].setValue( 0.0 )
-__children["PathFilter"]["__uiPosition1"]["y"].setValue( 0.0 )
+parent.addChild( __children["PathFilter"] )
+__children["PathFilter"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["PathFilter"].addChild( Gaffer.V2fPlug( "__uiPosition1", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
+__children["Sphere"]["transform"]["translate"].setValue( imath.V3f( 0, 1, 0 ) )
+__children["Sphere"]["__uiPosition"].setValue( imath.V2f( 8.01966095, 9.80717945 ) )
+__children["Plane"]["transform"]["rotate"].setValue( imath.V3f( 90, 0, 0 ) )
+__children["Plane"]["dimensions"].setValue( imath.V2f( 10, 10 ) )
+__children["Plane"]["divisions"].setValue( imath.V2i( 2, 2 ) )
+__children["Plane"]["__uiPosition"].setValue( imath.V2f( -4.33150482, 9.96185112 ) )
__children["Group"]["in"][0].setInput( __children["Plane"]["out"] )
__children["Group"]["in"][1].setInput( __children["Sphere"]["out"] )
+__children["Group"]["name"].setValue( 'geometry' )
+__children["Group"]["__uiPosition"].setValue( imath.V2f( 2.26130295, -1.60483646 ) )
+__children["Camera"]["transform"]["translate"].setValue( imath.V3f( 0, 1.10000002, 5.30000019 ) )
+__children["Camera"]["__uiPosition"].setValue( imath.V2f( 20.4540863, 9.92141724 ) )
__children["Group1"]["in"][0].setInput( __children["Group"]["out"] )
__children["Group1"]["in"][1].setInput( __children["Camera"]["out"] )
+__children["Group1"]["name"].setValue( 'world' )
+__children["Group1"]["__uiPosition"].setValue( imath.V2f( 8.91635609, -12.811451 ) )
__children["StandardOptions"]["in"].setInput( __children["CustomAttributes"]["out"] )
+__children["StandardOptions"]["options"]["renderCamera"]["value"].setValue( '/world/camera' )
+__children["StandardOptions"]["options"]["renderCamera"]["enabled"].setValue( True )
+__children["StandardOptions"]["options"]["renderResolution"]["enabled"].setValue( True )
+__children["StandardOptions"]["__uiPosition"].setValue( imath.V2f( 10.4163561, -29.6934471 ) )
__children["CustomAttributes"]["in"].setInput( __children["Group1"]["out"] )
__children["CustomAttributes"]["filter"].setInput( __children["PathFilter"]["out"] )
-
+__children["CustomAttributes"]["attributes"]["member1"]["name"].setValue( 'myString' )
+__children["CustomAttributes"]["attributes"]["member1"]["value"].setValue( 'aaa' )
+__children["CustomAttributes"]["__uiPosition"].setValue( imath.V2f( 10.4163561, -22.0981121 ) )
+__children["PathFilter"]["paths"].setValue( IECore.StringVectorData( [ '/world/geometry/sphere' ] ) )
+__children["PathFilter"]["__uiPosition"].setValue( imath.V2f( 21.2740936, -12.715106 ) )
del __children
```
@@ -203,10 +97,10 @@ Note that we're just using Python dictionary syntax to access a node by name and
```
g = root["StandardOptions"]["out"]["globals"].getValue()
-print type( g )
-print g.keys()
-print g["option:render:camera"].value
-print g["option:render:resolution"].value
+print( type( g ) )
+print( g.keys() )
+print( g["option:render:camera"].value )
+print( g["option:render:resolution"].value )
```
There are a couple of things to note here. Firstly, although the out plug appears as a single plug in the Graph Editor, it actually has several child plugs, which allow different aspects of the scene to be queried. We accessed the `globals` plug using dictionary syntax, and then retrieved its value using the `getValue()` method. The result was an `IECore::CompoundObject` which we can pretty much treat like a dictionary, with the minor annoyance that we need to use `.value` to actually retrieve the final value we want.
@@ -215,7 +109,7 @@ The `option:render:camera` globals entry tells us that the user wants to render
```
g = root["StandardOptions"]["out"]["object"].getValue()
-RuntimeError : line 1 : Exception : Context has no entry named "scene:path"
+Gaffer.ProcessException : line 1 : Group1.out.object : Context has no variable named "scene:path"
```
That didn't work out so well did it? The problem is that whereas the globals are **global**, different objects are potentially available at each point in the scene hierarchy - we need to say which part of the hierarchy we want the object from. We do that as follows :
@@ -224,7 +118,7 @@ That didn't work out so well did it? The problem is that whereas the globals are
with Gaffer.Context( root.context() ) as context :
context["scene:path"] = IECore.InternedStringVectorData( [ 'world', 'camera' ] )
camera = root["StandardOptions"]["out"]["object"].getValue()
- print camera
+ print( camera )
```
The `Context` class is central to the way Gaffer works - a single plug can output entirely different values depending on the [Context](../../WorkingWithTheNodeGraph/Contexts/index.md) in which `getValue()` is called. Here we provided a Context as a path within the scene, but for an image node we'd provide a Context with a tile location and channel name. Contexts allow Gaffer to multithread efficiently - each thread uses it's own Context so each thread can be querying a different part of the scene or a different location in an image. That was a bit wordy though wasn't it? For now let's pretend we didn't even take this detour and let's use a utility method that does the same thing instead :
@@ -236,10 +130,10 @@ camera = root["StandardOptions"]["out"].object( "/world/camera" )
Much better. Let's take a look at what we got :
```
-print camera.parameters().keys()
-print camera.parameters()["projection"].value
-print camera.parameters()["projection:fov"].value
-print camera.parameters()["clippingPlanes"].value
+print( camera.parameters().keys() )
+print( camera.parameters()["projection"].value )
+print( camera.parameters()["focalLength"].value )
+print( camera.parameters()["clippingPlanes"].value )
```
Again, the camera looks a lot like a dictionary, so queries aren't too hard.
@@ -251,7 +145,7 @@ Having our camera is all well and good, but we don't know where it is located sp
```
transform = root["StandardOptions"]["out"].transform( "/world/camera" )
-print transform
+print( transform )
```
That gave us the local transform for the camera in the form of a matrix - we could also use the `fullTransform()` method if we wanted the global transform.
@@ -267,8 +161,8 @@ But what about the CustomAttributes node that was applied to the sphere? How can
```
a = root["StandardOptions"]["out"].attributes( "/world/geometry/sphere" )
-print a.keys()
-print a["myString"].value
+print( a.keys() )
+print( a["myString"].value )
```
If the sphere had a shader assigned to it, that would appear as `a["shader"]`, but we've deliberately left that out for now to keep this tutorial renderer agnostic.
@@ -279,8 +173,8 @@ Traversing the hierarchy
One of the key features of the queries above was that they were random access - we could query any location in the scene at any time, without needing to query the parent locations first. That's all well and good, but until now we've been using prior knowledge of the scene structure to decide what to query. In a real situation, our code doesn't know that `/world/geometry/sphere` even exists. We need a means of querying the structure of the scene first, so that we can then query the contents at each location. Oddly enough, the structure is just communicated with another plug alongside the others - this time one called `childNames`. And oddly enough, there's a utility method to help us get its value within the proper Context. Let's start at the root and see what we can find :
```
-print root["StandardOptions"]["out"].childNames( "/" )
-print root["StandardOptions"]["out"].childNames( "/world" )
+print( root["StandardOptions"]["out"].childNames( "/" ) )
+print( root["StandardOptions"]["out"].childNames( "/world" ) )
```
Rather than continue this manual exploration, let's write a simple recursive function to traverse the scene and print what it finds :
@@ -290,11 +184,11 @@ import os
def visit( scene, path ) :
- print path
- print "\tTransform : " + str( scene.transform( path ) )
- print "\tObject : " + scene.object( path ).typeName()
- print "\tAttributes : " + " ".join( scene.attributes( path ).keys() )
- print "\tBound : " + str( scene.bound( path ) ) + "\n"
+ print( path )
+ print( "\tTransform : " + str( scene.transform( path ) ) )
+ print( "\tObject : " + scene.object( path ).typeName() )
+ print( "\tAttributes : " + " ".join( scene.attributes( path ).keys() ) )
+ print( "\tBound : " + str( scene.bound( path ) ) + "\n" )
for childName in scene.childNames( path ) :
visit( scene, os.path.join( path, str( childName ) ) )
diff --git a/include/Gaffer/ArrayPlug.h b/include/Gaffer/ArrayPlug.h
index ddf0063c632..1aa7c6be416 100644
--- a/include/Gaffer/ArrayPlug.h
+++ b/include/Gaffer/ArrayPlug.h
@@ -105,12 +105,17 @@ class GAFFER_API ArrayPlug : public Plug
IE_CORE_DECLAREPTR( ArrayPlug );
-/// \deprecated Use ArrayPlug::Iterator etc instead
+[[deprecated("Use `ArrayPlug::Iterator` instead")]]
typedef FilteredChildIterator > ArrayPlugIterator;
+[[deprecated("Use `ArrayPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputArrayPlugIterator;
+[[deprecated("Use `ArrayPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputArrayPlugIterator;
+[[deprecated("Use `ArrayPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveArrayPlugIterator;
+[[deprecated("Use `ArrayPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputArrayPlugIterator;
+[[deprecated("Use `ArrayPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputArrayPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Backdrop.h b/include/Gaffer/Backdrop.h
index f43a276d453..f37e75c4656 100644
--- a/include/Gaffer/Backdrop.h
+++ b/include/Gaffer/Backdrop.h
@@ -74,8 +74,9 @@ class GAFFER_API Backdrop : public Node
IE_CORE_DECLAREPTR( Backdrop )
-/// \deprecated Use Backdrop::Iterator etc instead.
+[[deprecated("Use `Backdrop::Iterator` instead")]]
typedef FilteredChildIterator > BackdropIterator;
+[[deprecated("Use `Backdrop::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveBackdropIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/BoxIO.h b/include/Gaffer/BoxIO.h
index 22baba852a5..5099b3abf0e 100644
--- a/include/Gaffer/BoxIO.h
+++ b/include/Gaffer/BoxIO.h
@@ -188,8 +188,9 @@ class GAFFER_API BoxIO : public Node
IE_CORE_DECLAREPTR( BoxIO )
-/// \deprecated Use BoxIO::Iterator etc instead.
+[[deprecated("Use `BoxIO::Iterator` instead")]]
typedef FilteredChildIterator > BoxIOIterator;
+[[deprecated("Use `BoxIO::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveBoxIOIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/BoxIn.h b/include/Gaffer/BoxIn.h
index 29d9fbe9f80..2504a26f413 100644
--- a/include/Gaffer/BoxIn.h
+++ b/include/Gaffer/BoxIn.h
@@ -56,8 +56,9 @@ class GAFFER_API BoxIn : public BoxIO
IE_CORE_DECLAREPTR( BoxIn )
-/// \deprecated Use BoxIn::Iterator etc instead.
+[[deprecated("Use `BoxIn::Iterator` instead")]]
typedef FilteredChildIterator > BoxInIterator;
+[[deprecated("Use `BoxIn::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveBoxInIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/BoxOut.h b/include/Gaffer/BoxOut.h
index 33924978786..05b9a9ea005 100644
--- a/include/Gaffer/BoxOut.h
+++ b/include/Gaffer/BoxOut.h
@@ -71,8 +71,9 @@ class GAFFER_API BoxOut : public BoxIO
IE_CORE_DECLAREPTR( BoxOut )
-/// \deprecated Use BoxOut::Iterator etc instead.
+[[deprecated("Use `BoxOut::Iterator` instead")]]
typedef FilteredChildIterator > BoxOutIterator;
+[[deprecated("Use `BoxOut::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveBoxOutIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/BoxPlug.h b/include/Gaffer/BoxPlug.h
index 818079ce572..b07de52ad3a 100644
--- a/include/Gaffer/BoxPlug.h
+++ b/include/Gaffer/BoxPlug.h
@@ -120,30 +120,53 @@ IE_CORE_DECLAREPTR( Box3iPlug );
IE_CORE_DECLAREPTR( Box2fPlug );
IE_CORE_DECLAREPTR( Box3fPlug );
-/// \deprecated Use Box2iPlug::Iterator etc instead
+[[deprecated("Use `Box2iPlug::Iterator` instead")]]
typedef FilteredChildIterator > Box2iPlugIterator;
+[[deprecated("Use `Box2iPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputBox2iPlugIterator;
+[[deprecated("Use `Box2iPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputBox2iPlugIterator;
+[[deprecated("Use `Box3iPlug::Iterator` instead")]]
typedef FilteredChildIterator > Box3iPlugIterator;
+[[deprecated("Use `Box3iPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputBox3iPlugIterator;
+[[deprecated("Use `Box3iPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputBox3iPlugIterator;
+[[deprecated("Use `Box2fPlug::Iterator` instead")]]
typedef FilteredChildIterator > Box2fPlugIterator;
+[[deprecated("Use `Box2fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputBox2fPlugIterator;
+[[deprecated("Use `Box2fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputBox2fPlugIterator;
+[[deprecated("Use `Box3fPlug::Iterator` instead")]]
typedef FilteredChildIterator > Box3fPlugIterator;
+[[deprecated("Use `Box3fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputBox3fPlugIterator;
+[[deprecated("Use `Box3fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputBox3fPlugIterator;
+[[deprecated("Use `Box2iPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveBox2iPlugIterator;
+[[deprecated("Use `Box2iPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputBox2iPlugIterator;
+[[deprecated("Use `Box2iPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputBox2iPlugIterator;
+[[deprecated("Use `Box3iPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveBox3iPlugIterator;
+[[deprecated("Use `Box3iPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputBox3iPlugIterator;
+[[deprecated("Use `Box3iPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputBox3iPlugIterator;
+[[deprecated("Use `Box2fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveBox2fPlugIterator;
+[[deprecated("Use `Box2fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputBox2fPlugIterator;
+[[deprecated("Use `Box2fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputBox2fPlugIterator;
+[[deprecated("Use `Box3fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveBox3fPlugIterator;
+[[deprecated("Use `Box3fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputBox3fPlugIterator;
+[[deprecated("Use `Box3fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputBox3fPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/CompoundDataPlug.h b/include/Gaffer/CompoundDataPlug.h
index aae213ac0c0..1607ef21c3f 100644
--- a/include/Gaffer/CompoundDataPlug.h
+++ b/include/Gaffer/CompoundDataPlug.h
@@ -90,12 +90,18 @@ class GAFFER_API CompoundDataPlug : public Gaffer::ValuePlug
IE_CORE_DECLAREPTR( CompoundDataPlug );
+[[deprecated("Use `CompoundDataPlug::Iterator` instead")]]
typedef Gaffer::FilteredChildIterator > CompoundDataPlugIterator;
+[[deprecated("Use `CompoundDataPlug::InputIterator` instead")]]
typedef Gaffer::FilteredChildIterator > InputCompoundDataPlugIterator;
+[[deprecated("Use `CompoundDataPlug::OutputIterator` instead")]]
typedef Gaffer::FilteredChildIterator > OutputCompoundDataPlugIterator;
+[[deprecated("Use `CompoundDataPlug::RecursiveIterator` instead")]]
typedef Gaffer::FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveCompoundDataPlugIterator;
+[[deprecated("Use `CompoundDataPlug::RecursiveInputIterator` instead")]]
typedef Gaffer::FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputCompoundDataPlugIterator;
+[[deprecated("Use `CompoundDataPlug::RecursiveOutputIterator` instead")]]
typedef Gaffer::FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputCompoundDataPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/CompoundNumericPlug.h b/include/Gaffer/CompoundNumericPlug.h
index a0a695bc088..1fc8335d7ad 100644
--- a/include/Gaffer/CompoundNumericPlug.h
+++ b/include/Gaffer/CompoundNumericPlug.h
@@ -143,42 +143,77 @@ IE_CORE_DECLAREPTR( V3iPlug );
IE_CORE_DECLAREPTR( Color3fPlug );
IE_CORE_DECLAREPTR( Color4fPlug );
-/// \deprecated Use V2fPlug::Iterator etc instead
+[[deprecated("Use `V2fPlug::Iterator` instead")]]
typedef FilteredChildIterator > V2fPlugIterator;
+[[deprecated("Use `V2fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputV2fPlugIterator;
+[[deprecated("Use `V2fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputV2fPlugIterator;
+[[deprecated("Use `V3fPlug::Iterator` instead")]]
typedef FilteredChildIterator > V3fPlugIterator;
+[[deprecated("Use `V3fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputV3fPlugIterator;
+[[deprecated("Use `V3fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputV3fPlugIterator;
+[[deprecated("Use `V2iPlug::Iterator` instead")]]
typedef FilteredChildIterator > V2iPlugIterator;
+[[deprecated("Use `V2iPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputV2iPlugIterator;
+[[deprecated("Use `V2iPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputV2iPlugIterator;
+[[deprecated("Use `V3iPlug::Iterator` instead")]]
typedef FilteredChildIterator > V3iPlugIterator;
+[[deprecated("Use `V3iPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputV3iPlugIterator;
+[[deprecated("Use `V3iPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputV3iPlugIterator;
+[[deprecated("Use `Color3fPlug::Iterator` instead")]]
typedef FilteredChildIterator > Color3fPlugIterator;
+[[deprecated("Use `Color3fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputColor3fPlugIterator;
+[[deprecated("Use `Color3fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputColor3fPlugIterator;
+[[deprecated("Use `Color4fPlug::Iterator` instead")]]
typedef FilteredChildIterator > Color4fPlugIterator;
+[[deprecated("Use `Color4fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputColor4fPlugIterator;
+[[deprecated("Use `Color4fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputColor4fPlugIterator;
+[[deprecated("Use `V2fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveV2fPlugIterator;
+[[deprecated("Use `V2fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputV2fPlugIterator;
+[[deprecated("Use `V2fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputV2fPlugIterator;
+[[deprecated("Use `V3fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveV3fPlugIterator;
+[[deprecated("Use `V3fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputV3fPlugIterator;
+[[deprecated("Use `V3fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputV3fPlugIterator;
+[[deprecated("Use `V2iPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveV2iPlugIterator;
+[[deprecated("Use `V2iPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputV2iPlugIterator;
+[[deprecated("Use `V2iPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputV2iPlugIterator;
+[[deprecated("Use `V3iPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveV3iPlugIterator;
+[[deprecated("Use `V3iPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputV3iPlugIterator;
+[[deprecated("Use `V3iPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputV3iPlugIterator;
+[[deprecated("Use `Color3fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveColor3fPlugIterator;
+[[deprecated("Use `Color3fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputColor3fPlugIterator;
+[[deprecated("Use `Color3fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputColor3fPlugIterator;
+[[deprecated("Use `Color4fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveColor4fPlugIterator;
+[[deprecated("Use `Color4fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputColor4fPlugIterator;
+[[deprecated("Use `Color4fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputColor4fPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/ComputeNode.h b/include/Gaffer/ComputeNode.h
index b43aeded2be..bb84469c2ce 100644
--- a/include/Gaffer/ComputeNode.h
+++ b/include/Gaffer/ComputeNode.h
@@ -91,8 +91,9 @@ class GAFFER_API ComputeNode : public DependencyNode
};
-/// \deprecated Use ComputeNode::Iterator etc instead.
+[[deprecated("Use `ComputeNode::Iterator` instead")]]
typedef FilteredChildIterator > ComputeNodeIterator;
+[[deprecated("Use `ComputeNode::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveComputeNodeIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Context.h b/include/Gaffer/Context.h
index a0e0f6554e8..8e674d91461 100644
--- a/include/Gaffer/Context.h
+++ b/include/Gaffer/Context.h
@@ -52,9 +52,9 @@
namespace Gaffer
{
-/// This class provides a dictionary of IECore::Data objects to define the context in which a
-/// computation is performed. The most basic entry common to all Contexts is the frame number,
-/// but a context may also hold entirely arbitrary entries useful to specific types of
+/// This class provides a dictionary of variables to define the context in which a
+/// computation is performed. The most basic variable common to all Contexts is the frame number,
+/// but a context may also hold entirely arbitrary variables useful to specific types of
/// computation.
///
/// Contexts are made current using the nested Scope class - any computation triggered by
@@ -77,39 +77,10 @@ class GAFFER_API Context : public IECore::RefCounted
public :
- /// Since there are costs associated with constructing,
- /// copying and reference counting the Data values that make
- /// up a Context, various ownership options are provided which
- /// trade performance for additional constraints on client code.
- enum Ownership
- {
- /// The Context takes its own copy of a value to be held
- /// internally. This requires no additional constraints on the
- /// part of client code, but has the worst performance.
- Copied,
- /// The Context shares the value with others, incrementing
- /// the reference count to ensure it remains alive for as
- /// long as the Context needs it. Because the Context
- /// doesn't have sole ownership of the value, other code
- /// could change the value without its knowledge. It is the
- /// responsibility of client code to either ensure that this does
- /// not happen, or to manually call Context::changed() as
- /// necessary when it does. This avoids the overhead of copying
- /// values when setting them.
- Shared,
- /// The Context simply references an existing value, and doesn't
- /// even increment its reference count. In addition to the constraints
- /// for shared ownership, it is also the responsibility
- /// of client code to ensure that the value remains alive for the
- /// lifetime of the Context. This is significantly faster than
- /// either of the previous options.
- Borrowed
- };
Context();
- /// Copy constructor. The ownership argument is deprecated - use
- /// an EditableScope instead of Borrowed ownership.
- Context( const Context &other, Ownership ownership = Copied );
+ /// Copy constructor
+ Context( const Context &other );
/// Copy constructor for creating a cancellable context.
/// The canceller is referenced, not copied, and must remain
/// alive for as long as the context is in use.
@@ -123,36 +94,43 @@ class GAFFER_API Context : public IECore::RefCounted
typedef boost::signal ChangedSignal;
- template
- struct Accessor;
+ /// Sets a variable to the specified value. A copy is taken so that
+ /// subsequent changes to `value` do not affect the context.
+ template::value>>
+ void set( const IECore::InternedString &name, const T &value );
+ /// As above, but providing the value as a `Data *`.
+ void set( const IECore::InternedString &name, const IECore::Data *value );
- /// Calling with simple types (e.g float) will automatically
- /// create a TypedData to store the value.
+ /// Returns a reference to the value of a variable, throwing if it doesn't exist or
+ /// has the wrong type : `float f = context->get( "myFloat" )`.
template
- void set( const IECore::InternedString &name, const T &value );
- /// Can be used to retrieve simple types :
- /// float f = context->get( "myFloat" )
- /// And also IECore::Data types :
- /// const FloatData *f = context->get( "myFloat" )
+ const T &get( const IECore::InternedString &name ) const;
+ /// As above, but returns `defaultValue` if the variable doesn't exist.
+ /// Note that if you pass in a temporary as the `defaultValue`, you must
+ /// copy the return value (if you stored it as a reference, you would be
+ /// referencing the temporary after it was destroyed).
template
- typename Accessor::ResultType get( const IECore::InternedString &name ) const;
- /// As above but returns defaultValue when an entry is not found, rather than throwing
- /// an Exception.
+ const T &get( const IECore::InternedString &name, const T& defaultValue ) const;
+ /// Returns a pointer to the value for the variable if it exists and has
+ /// the requested type. Returns `nullptr` if the variable doesn't exist,
+ /// and throws if it exists but has the wrong type.
template
- typename Accessor::ResultType get( const IECore::InternedString &name, typename Accessor::ResultType defaultValue ) const;
-
- /// Removes an entry from the context if it exists
- void remove( const IECore::InternedString& name );
-
- /// Removes any entries whose names match the space separated patterns
+ const T *getIfExists( const IECore::InternedString &name ) const;
+
+ /// Returns a copy of the variable if it exists, throwing if it doesn't. This
+ /// can be used when the type of the variable is unknown, but it is much more
+ /// expensive than the `get()` methods above because it allocates memory.
+ IECore::DataPtr getAsData( const IECore::InternedString &name ) const;
+ /// As above but returns `defaultValue` if the variable does not exist.
+ IECore::DataPtr getAsData( const IECore::InternedString &name, const IECore::DataPtr &defaultValue ) const;
+
+ /// Removes a variable from the context, if it exists.
+ void remove( const IECore::InternedString &name );
+ /// Removes any variables whose names match the space separated patterns
/// provided. Matching is performed using `StringAlgo::matchMultiple()`.
void removeMatching( const IECore::StringAlgo::MatchPattern &pattern );
- /// When a Shared or Borrowed value is changed behind the scenes, this method
- /// must be called to notify the Context of the change.
- void changed( const IECore::InternedString &name );
-
- /// Fills the specified vector with the names of all items in the Context.
+ /// Fills the specified vector with the names of all variables in the Context.
void names( std::vector &names ) const;
/// @name Time
@@ -189,6 +167,10 @@ class GAFFER_API Context : public IECore::RefCounted
IECore::MurmurHash hash() const;
+ /// Return the hash of a particular variable ( or a default MurmurHash() if not present )
+ /// Note that this hash includes the name of the variable
+ inline IECore::MurmurHash variableHash( const IECore::InternedString &name ) const;
+
bool operator == ( const Context &other ) const;
bool operator != ( const Context &other ) const;
@@ -242,13 +224,35 @@ class GAFFER_API Context : public IECore::RefCounted
EditableScope( const ThreadState &threadState );
~EditableScope();
+ /// Sets a variable with a pointer to a typed value. It is the
+ /// caller's responsibility to ensure that the pointer remains
+ /// valid for the lifetime of the EditableScope. This is much
+ /// faster than `Context::set()` because it doesn't allocating
+ /// memory, and should be used in all performance-critical code.
template
+ void set( const IECore::InternedString &name, const T *value );
+
+ template::value > >
+ [[deprecated("Use faster pointer version, or use the more explicit setAllocated if you actually need to allocate ")]]
void set( const IECore::InternedString &name, const T &value );
+ /// Sets a variable from a copy of `value`. This is more expensive than the
+ /// pointer version above, and should be avoided where possible.
+ template::value > >
+ void setAllocated( const IECore::InternedString &name, const T &value );
+ /// As above, but providing the value as a `Data *`.
+ void setAllocated( const IECore::InternedString &name, const IECore::Data *value );
+
+ /// These are fast even though they don't take a pointer,
+ /// because the EditableScope has dedicated internal storage for
+ /// the frame.
void setFrame( float frame );
- void setFramesPerSecond( float framesPerSecond );
void setTime( float timeInSeconds );
+ [[deprecated("Use faster pointer version")]]
+ void setFramesPerSecond( float framesPerSecond );
+ void setFramesPerSecond( const float *framesPerSecond );
+
void remove( const IECore::InternedString &name );
void removeMatching( const IECore::StringAlgo::MatchPattern &pattern );
@@ -257,27 +261,114 @@ class GAFFER_API Context : public IECore::RefCounted
private :
Ptr m_context;
+ // Provides storage for `setFrame()` and `setTime()` to use
+ // (There is no easy way to provide external storage for
+ // setTime, because it multiplies the input value).
+ float m_frameStorage;
};
/// Returns the current context for the calling thread.
static const Context *current();
+ /// Used to register a data type for use in variable values.
+ /// See `GafferImage::FormatData` for an example.
+ template
+ struct TypeDescription
+ {
+ TypeDescription();
+ };
+
private :
- // Storage for each entry.
- struct Storage
+ // Determines the operation of the private copy constructor.
+ enum class CopyMode
{
- Storage() : data( nullptr ), ownership( Copied ) {}
- // We reference the data with a raw pointer to avoid the compulsory
- // overhead of an intrusive pointer.
- const IECore::Data *data;
- // And use this ownership flag to tell us when we need to do explicit
- // reference count management.
- Ownership ownership;
+ // Shares ownership with the source context where possible,
+ // allocating copies where necessary. Used by all public copy
+ // constructors.
+ Owning,
+ // References existing values without taking ownership, relying on
+ // the source context to outlive this one. Used by EditableScopes.
+ NonOwning
};
- typedef boost::container::flat_map Map;
+ Context( const Context &other, CopyMode mode );
+
+ // Type used for the value of a variable. Can refer to any type `T` for
+ // which `IECore::TypedData` is available and `registerType()` has
+ // been called. Values are stored as `const void *` pointing to `T`,
+ // along with the `IECore::TypeId` for `TypedData`, which is used to
+ // validate type-safe access. Does not manage memory or ownership in any
+ // way : this is the responsibility of calling code.
+ struct Value
+ {
+
+ inline Value();
+ template
+ Value( const IECore::InternedString &name, const T *value );
+ Value( const IECore::InternedString &name, const IECore::Data *value );
+ Value( const Value &other ) = default;
+
+ Value &operator = ( const Value &other ) = default;
+
+ template
+ inline const T &value() const;
+ IECore::TypeId typeId() const { return m_typeId; }
+ const void *rawValue() const { return m_value; }
+ // Note : This includes the hash of the name passed
+ // to the constructor.
+ const IECore::MurmurHash &hash() const { return m_hash; }
+
+ bool operator == ( const Value &rhs ) const;
+ bool operator != ( const Value &rhs ) const;
+ bool references( const IECore::Data *data ) const;
+
+ IECore::DataPtr makeData() const;
+ Value copy( IECore::ConstDataPtr &owner ) const;
+
+ // Throws if the `hash()` no longer corresponds to `value()`.
+ // This can occur if the pointee is modified after calling
+ // `EditableScope::set( name, const T * )`.
+ void validate( const IECore::InternedString &name ) const;
+
+ template
+ static void registerType();
+
+ private :
+
+ Value( IECore::TypeId typeId, const void *value, const IECore::MurmurHash &hash );
+
+ IECore::TypeId m_typeId;
+ const void *m_value;
+ IECore::MurmurHash m_hash;
+
+ struct TypeFunctions
+ {
+ IECore::DataPtr (*makeData)( const Value &value, const void **dataValue );
+ bool (*isEqual)( const Value &a, const Value &b );
+ Value (*constructor)( const IECore::InternedString &name, const IECore::Data *data );
+ const void *(*valueFromData)( const IECore::Data *data );
+ void (*validate)( const IECore::InternedString &name, const Value &v );
+ };
+
+ using TypeMap = boost::container::flat_map;
+ static TypeMap &typeMap();
+ static const TypeFunctions &typeFunctions( IECore::TypeId typeId );
+
+ };
+
+ // Sets a variable and emits `changedSignal()` as appropriate. Does not
+ // manage ownership in any way. Returns true if the value was assigned,
+ // and false if the value was not (due to it being equal to the
+ // previously stored value).
+ inline bool internalSet( const IECore::InternedString &name, const Value &value );
+ // Throws if variable doesn't exist.
+ inline const Value &internalGet( const IECore::InternedString &name ) const;
+ // Returns nullptr if variable doesn't exist.
+ inline const Value *internalGetIfExists( const IECore::InternedString &name ) const;
+
+ typedef boost::container::flat_map Map;
Map m_map;
ChangedSignal *m_changedSignal;
@@ -285,6 +376,13 @@ class GAFFER_API Context : public IECore::RefCounted
mutable bool m_hashValid;
const IECore::Canceller *m_canceller;
+ // The alloc map holds a smart pointer to data that we allocate. It must keep the entries
+ // alive at least as long as the m_map used for actual accesses is using it, though it may
+ // hold data longer than it is actually in use. ( ie. a fast pointer based set through
+ // EditableScope could overwrite a variable without updating m_allocMap )
+ typedef boost::container::flat_map AllocMap;
+ AllocMap m_allocMap;
+
};
IE_CORE_DECLAREPTR( Context );
diff --git a/include/Gaffer/Context.inl b/include/Gaffer/Context.inl
index 884041b19fe..6d253c2a8d6 100644
--- a/include/Gaffer/Context.inl
+++ b/include/Gaffer/Context.inl
@@ -85,138 +85,192 @@ struct DataTraits >
} // namespace Detail
-template
-struct Context::Accessor
+Context::Value::Value()
+ : m_typeId( IECore::InvalidTypeId ), m_value( nullptr )
{
- typedef const T &ResultType;
- typedef typename Gaffer::Detail::DataTraits::DataType DataType;
+}
- /// Returns true if the value has changed
- bool set( Storage &storage, const T &value )
+template
+Context::Value::Value( const IECore::InternedString &name, const T *value )
+ : m_typeId( Detail::DataTraits::DataType::staticTypeId() ),
+ m_value( value )
+{
+ const std::string &nameStr = name.string();
+ if( nameStr.size() > 2 && nameStr[0] == 'u' && nameStr[1] == 'i' && nameStr[2] == ':' )
{
- const DataType *d = IECore::runTimeCast( storage.data );
- if( d )
- {
- if( d->readable() == value )
- {
- // no change so early out
- return false;
- }
- else if( storage.ownership == Copied )
- {
- // update in place to avoid allocations. the cast is ok
- // because we created the value for our own use in the first
- // place. storage.data is const to remind us not to mess
- // with values we receive as Shared or Borrowed, but since this
- // is Copied, we're free to do as we please.
- const_cast( d )->writable() = value;
- return true;
- }
- }
-
- // data wasn't of the right type or we didn't have sole ownership.
- // remove the old value and replace it with a new one.
- if( storage.data && storage.ownership != Borrowed )
- {
- storage.data->removeRef();
- }
-
- storage.data = new DataType( value );
- storage.data->addRef();
- storage.ownership = Copied;
-
- return true;
+ m_hash = IECore::MurmurHash( 0, 0 );
}
-
- ResultType get( const IECore::Data *data )
+ else
{
- if( !data->isInstanceOf( DataType::staticTypeId() ) )
- {
- throw IECore::Exception( boost::str( boost::format( "Context entry is not of type \"%s\"" ) % DataType::staticTypeName() ) );
- }
- return static_cast( data )->readable();
+ m_hash.append( *value );
+ m_hash.append( m_typeId );
+ m_hash.append( (uint64_t)&nameStr );
}
-};
+}
template
-struct Context::Accessor::type > >::type>
+inline const T &Context::Value::value() const
{
- typedef typename boost::remove_pointer::type ValueType;
- typedef const ValueType *ResultType;
-
- bool set( Storage &storage, const T &value )
+ using DataType = typename Gaffer::Detail::DataTraits::DataType;
+ if( m_typeId == DataType::staticTypeId() )
{
- const ValueType *d = IECore::runTimeCast( storage.data );
- if( d && d->isEqualTo( value ) )
+ return *static_cast( m_value );
+ }
+ throw IECore::Exception( boost::str( boost::format( "Context variable is not of type \"%s\"" ) % DataType::staticTypeName() ) );
+}
+
+template
+void Context::Value::registerType()
+{
+ using ValueType = typename T::ValueType;
+ TypeFunctions &functions = typeMap()[T::staticTypeId()];
+ functions.makeData = []( const Value &value, const void **dataValue ) -> IECore::DataPtr {
+ typename T::Ptr result = new T( *static_cast( value.rawValue() ) );
+ if( dataValue )
{
- return false;
+ *dataValue = &result->readable();
}
-
- if( storage.data && storage.ownership != Borrowed )
+ return result;
+ };
+ functions.isEqual = [] ( const Value &a, const Value &b ) {
+ // Type of both `a` and `b` has been checked already in `operator ==`.
+ return (*static_cast( a.rawValue() )) == (*static_cast( b.rawValue() ));
+ };
+ functions.constructor = [] ( const IECore::InternedString &name, const IECore::Data *data ) {
+ return Value( name, &static_cast( data )->readable() );
+ };
+ functions.valueFromData = [] ( const IECore::Data *data ) -> const void * {
+ return &static_cast( data )->readable();
+ };
+ functions.validate = [] ( const IECore::InternedString &name, const Value &v ) {
+ const Value rehashed( name, static_cast( v.rawValue() ) );
+ if( v.hash() != rehashed.hash() )
{
- storage.data->removeRef();
+ throw IECore::Exception( boost::str(
+ boost::format( "Context variable \"%1%\" has an invalid hash" ) % name
+ ) );
}
+ };
+}
- IECore::DataPtr valueCopy = value->copy();
- storage.data = valueCopy.get();
- storage.data->addRef();
- storage.ownership = Copied;
+template
+void Context::set( const IECore::InternedString &name, const T &value )
+{
+ // Allocate a new typed Data, store it in m_allocMap so that it won't be deallocated,
+ // and call internalSet to reference it in the main m_map
+ typedef typename Gaffer::Detail::DataTraits::DataType DataType;
+ typename DataType::Ptr d = new DataType( value );
+ if( internalSet( name, Value( name, &d->readable() ) ) )
+ {
+ m_allocMap[name] = d;
+ }
+}
+bool Context::internalSet( const IECore::InternedString &name, const Value &value )
+{
+ if( !m_changedSignal )
+ {
+ // Fast path, typically in an EditableScope, where we
+ // expect the value to have changed and don't want the
+ // expense of checking.
+ m_map[name] = value;
+ m_hashValid = false;
return true;
}
-
- ResultType get( const IECore::Data *data )
+ else
{
- if( !data->isInstanceOf( T::staticTypeId() ) )
+ // Avoid emitting `changedSignal` if the value hasn't
+ // actually changed. We want to avoid expensive re-evaluations
+ // that might otherwise be triggered in the UI.
+ Value &v = m_map[name];
+ if( v != value )
{
- throw IECore::Exception( boost::str( boost::format( "Context entry is not of type \"%s\"" ) % T::staticTypeName() ) );
+ v = value;
+ m_hashValid = false;
+ (*m_changedSignal)( this, name );
+ return true;
+ }
+ else
+ {
+ return false;
}
- return static_cast( data );
}
-};
+}
-template
-void Context::set( const IECore::InternedString &name, const T &value )
+inline const Context::Value &Context::internalGet( const IECore::InternedString &name ) const
{
- Storage &s = m_map[name];
- if( Accessor().set( s, value ) )
+ const Value *result = internalGetIfExists( name );
+ if( !result )
{
- m_hashValid = false;
- if( m_changedSignal )
- {
- (*m_changedSignal)( this, name );
- }
+ throw IECore::Exception( boost::str( boost::format( "Context has no variable named \"%s\"" ) % name.value() ) );
}
+
+#ifndef NDEBUG
+ result->validate( name );
+#endif
+
+ return *result;
}
-template
-typename Context::Accessor::ResultType Context::get( const IECore::InternedString &name ) const
+inline const Context::Value *Context::internalGetIfExists( const IECore::InternedString &name ) const
{
Map::const_iterator it = m_map.find( name );
- if( it == m_map.end() )
+ return it != m_map.end() ? &it->second : nullptr;
+}
+
+template
+const T &Context::get( const IECore::InternedString &name ) const
+{
+ return internalGet( name ).value();
+}
+
+template
+const T &Context::get( const IECore::InternedString &name, const T &defaultValue ) const
+{
+ if( const Value *value = internalGetIfExists( name ) )
+ {
+ return internalGet( name ).value();
+ }
+ return defaultValue;
+}
+
+inline IECore::MurmurHash Context::variableHash( const IECore::InternedString &name ) const
+{
+ if( const Value *value = internalGetIfExists( name ) )
{
- throw IECore::Exception( boost::str( boost::format( "Context has no entry named \"%s\"" ) % name.value() ) );
+ return value->hash();
}
- return Accessor().get( it->second.data );
+ return IECore::MurmurHash();
}
template
-typename Context::Accessor::ResultType Context::get( const IECore::InternedString &name, typename Accessor::ResultType defaultValue ) const
+const T *Context::getIfExists( const IECore::InternedString &name ) const
{
- Map::const_iterator it = m_map.find( name );
- if( it == m_map.end() )
+ if( const Value *value = internalGetIfExists( name ) )
{
- return defaultValue;
+ return &value->value();
}
- return Accessor().get( it->second.data );
+ return nullptr;
}
template
+void Context::EditableScope::set( const IECore::InternedString &name, const T *value )
+{
+ m_context->internalSet( name, Value( name, value ) );
+}
+
+template
void Context::EditableScope::set( const IECore::InternedString &name, const T &value )
{
m_context->set( name, value );
}
+template
+void Context::EditableScope::setAllocated( const IECore::InternedString &name, const T &value )
+{
+ m_context->set( name, value );
+}
+
const IECore::Canceller *Context::canceller() const
{
return m_canceller;
@@ -239,6 +293,12 @@ class Context::SubstitutionProvider : public IECore::StringAlgo::VariableProvide
};
+template< typename T >
+Context::TypeDescription::TypeDescription()
+{
+ Context::Value::registerType();
+}
+
} // namespace Gaffer
#endif // GAFFER_CONTEXT_INL
diff --git a/include/Gaffer/ContextProcessor.h b/include/Gaffer/ContextProcessor.h
index 961a8dbe18e..20615317b09 100644
--- a/include/Gaffer/ContextProcessor.h
+++ b/include/Gaffer/ContextProcessor.h
@@ -88,7 +88,7 @@ class IECORE_EXPORT ContextProcessor : public ComputeNode
/// Must be implemented to return true if the input is used in `processContext()`.
virtual bool affectsContext( const Plug *input ) const = 0;
/// Must be implemented to modify context in place.
- virtual void processContext( Context::EditableScope &context ) const = 0;
+ virtual void processContext( Context::EditableScope &context, IECore::ConstRefCountedPtr &storage ) const = 0;
private :
diff --git a/include/Gaffer/ContextVariables.h b/include/Gaffer/ContextVariables.h
index 59a09764eb5..ba67b755653 100644
--- a/include/Gaffer/ContextVariables.h
+++ b/include/Gaffer/ContextVariables.h
@@ -60,13 +60,22 @@ class IECORE_EXPORT ContextVariables : public ContextProcessor
AtomicCompoundDataPlug *extraVariablesPlug();
const AtomicCompoundDataPlug *extraVariablesPlug() const;
+ void affects( const Plug *input, DependencyNode::AffectedPlugsContainer &outputs ) const override;
+
protected :
+ /// Implemented to compute combinedVariablesPlug
+ void hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const override;
+ void compute( ValuePlug *output, const Context *context ) const override;
+
bool affectsContext( const Plug *input ) const override;
- void processContext( Context::EditableScope &context ) const override;
+ void processContext( Context::EditableScope &context, IECore::ConstRefCountedPtr &storage ) const override;
private :
+ AtomicCompoundDataPlug *combinedVariablesPlug();
+ const AtomicCompoundDataPlug *combinedVariablesPlug() const;
+
static size_t g_firstPlugIndex;
};
diff --git a/include/Gaffer/DeleteContextVariables.h b/include/Gaffer/DeleteContextVariables.h
index 8d53f895c9c..c7f7069375f 100644
--- a/include/Gaffer/DeleteContextVariables.h
+++ b/include/Gaffer/DeleteContextVariables.h
@@ -59,7 +59,7 @@ class IECORE_EXPORT DeleteContextVariables : public ContextProcessor
protected :
bool affectsContext( const Plug *input ) const override;
- void processContext( Context::EditableScope &context ) const override;
+ void processContext( Context::EditableScope &context, IECore::ConstRefCountedPtr &storage ) const override;
private :
diff --git a/include/Gaffer/DependencyNode.h b/include/Gaffer/DependencyNode.h
index 742bafc4b6e..0d0c861e037 100644
--- a/include/Gaffer/DependencyNode.h
+++ b/include/Gaffer/DependencyNode.h
@@ -91,8 +91,9 @@ class GAFFER_API DependencyNode : public Node
};
-/// \deprecated Use DependencyNode::Iterator etc instead.
+[[deprecated("Use `DependencyNode::Iterator` instead")]]
typedef FilteredChildIterator > DependencyNodeIterator;
+[[deprecated("Use `DependencyNode::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveDependencyNodeIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Dot.h b/include/Gaffer/Dot.h
index 6c9d180af06..51669166209 100644
--- a/include/Gaffer/Dot.h
+++ b/include/Gaffer/Dot.h
@@ -105,8 +105,9 @@ class GAFFER_API Dot : public DependencyNode
IE_CORE_DECLAREPTR( Dot )
-/// \deprecated Use Dot::Iterator etc instead.
+[[deprecated("Use `Dot::Iterator` instead")]]
typedef FilteredChildIterator > DotIterator;
+[[deprecated("Use `Dot::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveDotIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Expression.h b/include/Gaffer/Expression.h
index acdaccc1e89..15c8da2c051 100644
--- a/include/Gaffer/Expression.h
+++ b/include/Gaffer/Expression.h
@@ -120,6 +120,8 @@ class GAFFER_API Expression : public ComputeNode
/// to apply them to each of the individual output plugs.
/// \threading This function may be called concurrently.
virtual IECore::ConstObjectVectorPtr execute( const Context *context, const std::vector &proxyInputs ) const = 0;
+ /// What cache policy should be used for executing the expression.
+ virtual Gaffer::ValuePlug::CachePolicy executeCachePolicy() const = 0;
//@}
/// @name Language utilities
@@ -179,6 +181,8 @@ class GAFFER_API Expression : public ComputeNode
void hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const override;
void compute( ValuePlug *output, const Context *context ) const override;
+ Gaffer::ValuePlug::CachePolicy computeCachePolicy( const Gaffer::ValuePlug *output ) const override;
+
private :
static size_t g_firstPlugIndex;
diff --git a/include/Gaffer/FilteredChildIterator.h b/include/Gaffer/FilteredChildIterator.h
index 797ae182d71..894fb84ccf5 100644
--- a/include/Gaffer/FilteredChildIterator.h
+++ b/include/Gaffer/FilteredChildIterator.h
@@ -105,7 +105,7 @@ class FilteredChildIterator : public boost::filter_iterator( BaseIterator::operator->() );
}
- FilteredChildIterator &operator++()
+ FilteredChildIterator &operator++()
{
BaseIterator::operator++();
return *this;
diff --git a/include/Gaffer/GraphComponent.h b/include/Gaffer/GraphComponent.h
index ef106a4b653..208686f57ec 100644
--- a/include/Gaffer/GraphComponent.h
+++ b/include/Gaffer/GraphComponent.h
@@ -38,6 +38,7 @@
#ifndef GAFFER_GRAPHCOMPONENT_H
#define GAFFER_GRAPHCOMPONENT_H
+#include "Gaffer/CatchingSignalCombiner.h"
#include "Gaffer/Export.h"
#include "Gaffer/TypeIds.h"
@@ -88,8 +89,9 @@ class GAFFER_API GraphComponent : public IECore::RunTimeTyped, public boost::sig
GAFFER_GRAPHCOMPONENT_DECLARE_TYPE( Gaffer::GraphComponent, GraphComponentTypeId, IECore::RunTimeTyped );
- typedef boost::signal UnarySignal;
- typedef boost::signal BinarySignal;
+ using UnarySignal = boost::signal;
+ using BinarySignal = boost::signal;
+ using ChildrenReorderedSignal = boost::signal &originalIndices ), CatchingSignalCombiner>;
/// @name Naming
/// All GraphComponents have a name, which must be unique among
@@ -127,8 +129,8 @@ class GAFFER_API GraphComponent : public IECore::RunTimeTyped, public boost::sig
////////////////////////////////////////////////////////////////////
//@{
/// The datatype used internally to store children.
- typedef std::vector ChildContainer;
- typedef ChildContainer::const_iterator ChildIterator;
+ using ChildContainer = std::vector;
+ using ChildIterator = ChildContainer::const_iterator;
/// Components can accept or reject potential children by implementing this
/// call. By default all children are accepted.
virtual bool acceptsChild( const GraphComponent *potentialChild ) const;
@@ -154,9 +156,6 @@ class GAFFER_API GraphComponent : public IECore::RunTimeTyped, public boost::sig
/// \todo Do we need acceptsRemoval()?
/// \undoable
void removeChild( GraphComponentPtr child );
- /// Removes all the children.
- /// \undoable
- void clearChildren();
/// Get an immediate child by name, performing a runTimeCast to T.
template
T *getChild( const IECore::InternedString &name );
@@ -174,6 +173,12 @@ class GAFFER_API GraphComponent : public IECore::RunTimeTyped, public boost::sig
/// Read only access to the internal container of children. This
/// is useful for iteration over children.
const ChildContainer &children() const;
+ /// Reorders the existing children.
+ /// \undoable
+ void reorderChildren( const ChildContainer &newOrder );
+ /// Removes all the children.
+ /// \undoable
+ void clearChildren();
/// Returns a descendant of this node specified by a "." separated
/// relative path, performing a runTimeCast to T.
template
@@ -221,6 +226,10 @@ class GAFFER_API GraphComponent : public IECore::RunTimeTyped, public boost::sig
/// of a child being removed from the destructor of the parent, oldParent
/// will be null as it is no longer available.
BinarySignal &parentChangedSignal();
+ /// A signal emitted when children have been reordered. The original indices
+ /// corresponding to each child are passed, to facilitate reordering of any
+ /// mirrored data structures or UI.
+ ChildrenReorderedSignal &childrenReorderedSignal();
//@}
protected :
@@ -258,6 +267,11 @@ class GAFFER_API GraphComponent : public IECore::RunTimeTyped, public boost::sig
/// to maintain a consistent state even if badly behaved observers are
/// connected to the signal.
virtual void parentChanged( Gaffer::GraphComponent *oldParent );
+ // Called by `reorderChildren()` immediately before `childrenReorderedSignal()`
+ // is emitted. This provides an opportunity to respond to reordering before
+ // outside observers are notified. Implementations should call the base class
+ // implementation before doing their own work.
+ virtual void childrenReordered( const std::vector &oldIndices );
/// It is common for derived classes to provide accessors for
/// constant-time access to specific children, as this can be
diff --git a/include/Gaffer/Metadata.h b/include/Gaffer/Metadata.h
index 2cd37988ba7..ab38570ad08 100644
--- a/include/Gaffer/Metadata.h
+++ b/include/Gaffer/Metadata.h
@@ -152,14 +152,14 @@ class GAFFER_API Metadata
};
using ValueChangedSignal = boost::signal>;
- using NodeValueChangedSignal2 = boost::signal>;
- using PlugValueChangedSignal2 = boost::signal>;
+ using NodeValueChangedSignal = boost::signal>;
+ using PlugValueChangedSignal = boost::signal>;
static ValueChangedSignal &valueChangedSignal();
/// Returns a signal that will be emitted when metadata has changed for `node`.
- static NodeValueChangedSignal2 &nodeValueChangedSignal( Node *node );
+ static NodeValueChangedSignal &nodeValueChangedSignal( Node *node );
/// Returns a signal that will be emitted when metadata has changed for any plug on `node`.
- static PlugValueChangedSignal2 &plugValueChangedSignal( Node *node );
+ static PlugValueChangedSignal &plugValueChangedSignal( Node *node );
/// Legacy signals
/// ==============
@@ -168,15 +168,15 @@ class GAFFER_API Metadata
/// plug. Their usage leads to performance bottlenecks whereby all observers
/// are triggered by all edits. They will be removed in future.
- using NodeValueChangedSignal = boost::signal>;
- using PlugValueChangedSignal = boost::signal>;
+ using LegacyNodeValueChangedSignal = boost::signal>;
+ using LegacyPlugValueChangedSignal = boost::signal>;
/// Deprecated, but currently necessary for tracking inherited
/// changes to read-only metadata.
/// \deprecated
- static NodeValueChangedSignal &nodeValueChangedSignal();
+ static LegacyNodeValueChangedSignal &nodeValueChangedSignal();
/// \deprecated
- static PlugValueChangedSignal &plugValueChangedSignal();
+ static LegacyPlugValueChangedSignal &plugValueChangedSignal();
private :
diff --git a/include/Gaffer/MetadataAlgo.h b/include/Gaffer/MetadataAlgo.h
index 65967ae555c..b9f1d3b205e 100644
--- a/include/Gaffer/MetadataAlgo.h
+++ b/include/Gaffer/MetadataAlgo.h
@@ -40,9 +40,12 @@
#include "Gaffer/Export.h"
#include "Gaffer/Node.h"
+#include "IECore/SimpleTypedData.h"
#include "IECore/StringAlgo.h"
#include "IECore/TypeIds.h"
+#include "OpenEXR/ImathColor.h"
+
#include
namespace Gaffer
@@ -135,6 +138,60 @@ GAFFER_API Node *getNumericBookmark( ScriptNode *script, int bookmark );
GAFFER_API int numericBookmark( const Node *node );
GAFFER_API bool numericBookmarkAffectedByChange( const IECore::InternedString &changedKey );
+/// Annotations
+/// ===========
+///
+/// Annotations define arbitrary text to be displayed in a coloured area
+/// next to a node. Each node can have arbitrary numbers of annotations,
+/// with different annotations being distinguished by their `name`.
+/// Templates can be used to define defaults for standard annotation types.
+/// The text from the template is used as a default when first creating
+/// an annotation via the UI, and the colour from the template provides
+/// the default colour if one is not specified explicitly by an annotation
+/// itself.
+
+struct GAFFER_API Annotation
+{
+
+ Annotation() = default;
+ Annotation( const std::string &text );
+ Annotation( const std::string &text, const Imath::Color3f &color );
+ Annotation( const IECore::ConstStringDataPtr &text, const IECore::ConstColor3fDataPtr &color = nullptr );
+ Annotation( const Annotation &other ) = default;
+ Annotation( Annotation &&other ) = default;
+
+ operator bool() const { return textData.get(); }
+
+ bool operator == ( const Annotation &rhs );
+ bool operator != ( const Annotation &rhs ) { return !(*this == rhs); };
+
+ IECore::ConstStringDataPtr textData;
+ IECore::ConstColor3fDataPtr colorData;
+
+ const std::string &text() const { return textData ? textData->readable() : g_defaultText; }
+ const Imath::Color3f &color() const { return colorData ? colorData->readable() : g_defaultColor; }
+
+ private :
+
+ static std::string g_defaultText;
+ static Imath::Color3f g_defaultColor;
+
+};
+
+GAFFER_API void addAnnotation( Node *node, const std::string &name, const Annotation &annotation, bool persistent = true );
+GAFFER_API Annotation getAnnotation( const Node *node, const std::string &name, bool inheritTemplate = false );
+GAFFER_API void removeAnnotation( Node *node, const std::string &name );
+GAFFER_API void annotations( const Node *node, std::vector &names );
+
+/// Pass `user = false` for annotations not intended for creation directly by the user.
+GAFFER_API void addAnnotationTemplate( const std::string &name, const Annotation &annotation, bool user = true );
+GAFFER_API Annotation getAnnotationTemplate( const std::string &name );
+GAFFER_API void removeAnnotationTemplate( const std::string &name );
+/// Pass `userOnly = true` to omit templates registered with `user = false`.
+GAFFER_API void annotationTemplates( std::vector &names, bool userOnly = false );
+
+GAFFER_API bool annotationsAffectedByChange( const IECore::InternedString &changedKey );
+
/// Change queries
/// ==============
diff --git a/include/Gaffer/Monitor.h b/include/Gaffer/Monitor.h
index 0e3c0b7566c..8355edacb68 100644
--- a/include/Gaffer/Monitor.h
+++ b/include/Gaffer/Monitor.h
@@ -53,7 +53,7 @@ class GAFFER_API Monitor : public IECore::RefCounted
public :
- virtual ~Monitor();
+ ~Monitor() override;
IE_CORE_DECLAREMEMBERPTR( Monitor )
diff --git a/include/Gaffer/MonitorAlgo.h b/include/Gaffer/MonitorAlgo.h
index e691672914b..920ac6a48ef 100644
--- a/include/Gaffer/MonitorAlgo.h
+++ b/include/Gaffer/MonitorAlgo.h
@@ -70,9 +70,12 @@ enum PerformanceMetric
GAFFER_API std::string formatStatistics( const PerformanceMonitor &monitor, size_t maxLinesPerMetric = 50 );
GAFFER_API std::string formatStatistics( const PerformanceMonitor &monitor, PerformanceMetric metric, size_t maxLines = 50 );
-GAFFER_API void annotate( Node &root, const PerformanceMonitor &monitor );
-GAFFER_API void annotate( Node &root, const PerformanceMonitor &monitor, PerformanceMetric metric );
-GAFFER_API void annotate( Node &root, const ContextMonitor &monitor );
+GAFFER_API void annotate( Node &root, const PerformanceMonitor &monitor, bool persistent = true );
+GAFFER_API void annotate( Node &root, const PerformanceMonitor &monitor, PerformanceMetric metric, bool persistent = true );
+GAFFER_API void annotate( Node &root, const ContextMonitor &monitor, bool persistent = true );
+
+GAFFER_API void removePerformanceAnnotations( Node &root );
+GAFFER_API void removeContextAnnotations( Node &root );
} // namespace MonitorAlgo
diff --git a/include/Gaffer/NameValuePlug.h b/include/Gaffer/NameValuePlug.h
index a8b53894f0b..2835ddb4207 100644
--- a/include/Gaffer/NameValuePlug.h
+++ b/include/Gaffer/NameValuePlug.h
@@ -134,7 +134,7 @@ class GAFFER_API NameValuePlug : public Gaffer::ValuePlug
};
-/// \deprecated Use NameValuePlug::Iterator instead
+[[deprecated("Use `NameValuePlug::Iterator` instead")]]
typedef FilteredChildIterator > NameValuePlugIterator;
IE_CORE_DECLAREPTR( NameValuePlug );
diff --git a/include/Gaffer/Node.h b/include/Gaffer/Node.h
index 8d4fd212bed..4236bf1dc4f 100644
--- a/include/Gaffer/Node.h
+++ b/include/Gaffer/Node.h
@@ -116,8 +116,6 @@ class GAFFER_API Node : public GraphComponent
/// onto an input plug of a plain Node (and potentially onwards if that plug
/// has its own output connections).
UnaryPlugSignal &plugDirtiedSignal();
- /// Emitted when the flags are changed for a plug of this node.
- UnaryPlugSignal &plugFlagsChangedSignal();
//@}
/// It's common for users to want to create their own plugs on
@@ -190,7 +188,6 @@ class GAFFER_API Node : public GraphComponent
UnaryPlugSignal m_plugSetSignal;
UnaryPlugSignal m_plugInputChangedSignal;
- UnaryPlugSignal m_plugFlagsChangedSignal;
UnaryPlugSignal m_plugDirtiedSignal;
ErrorSignal m_errorSignal;
@@ -198,8 +195,9 @@ class GAFFER_API Node : public GraphComponent
IE_CORE_DECLAREPTR( Node )
-/// \deprecated Use Node::Iterator etc instead.
+[[deprecated("Use `Node::Iterator` instead")]]
typedef FilteredChildIterator > NodeIterator;
+[[deprecated("Use `Node::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveNodeIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/NumericPlug.h b/include/Gaffer/NumericPlug.h
index d05628c1cb0..1f37374183e 100644
--- a/include/Gaffer/NumericPlug.h
+++ b/include/Gaffer/NumericPlug.h
@@ -105,18 +105,29 @@ typedef NumericPlug IntPlug;
IE_CORE_DECLAREPTR( FloatPlug );
IE_CORE_DECLAREPTR( IntPlug );
-/// \deprecated Use FloatPlug::Iterator etc instead
+[[deprecated("Use `FloatPlug::Iterator` instead")]]
typedef FilteredChildIterator > FloatPlugIterator;
+[[deprecated("Use `FloatPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputFloatPlugIterator;
+[[deprecated("Use `FloatPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputFloatPlugIterator;
+[[deprecated("Use `IntPlug::Iterator` instead")]]
typedef FilteredChildIterator > IntPlugIterator;
+[[deprecated("Use `IntPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputIntPlugIterator;
+[[deprecated("Use `IntPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputIntPlugIterator;
+[[deprecated("Use `FloatPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveFloatPlugIterator;
+[[deprecated("Use `FloatPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputFloatPlugIterator;
+[[deprecated("Use `FloatPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputFloatPlugIterator;
+[[deprecated("Use `IntPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveIntPlugIterator;
+[[deprecated("Use `IntPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputIntPlugIterator;
+[[deprecated("Use `IntPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputIntPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Plug.h b/include/Gaffer/Plug.h
index d9bbea86a14..5be9702a315 100644
--- a/include/Gaffer/Plug.h
+++ b/include/Gaffer/Plug.h
@@ -228,6 +228,7 @@ class GAFFER_API Plug : public GraphComponent
void parentChanging( Gaffer::GraphComponent *newParent ) override;
void parentChanged( Gaffer::GraphComponent *oldParent ) override;
+ void childrenReordered( const std::vector &oldIndices ) override;
/// Initiates the propagation of dirtiness from the specified
/// plug to its outputs and affected plugs (as defined by
@@ -317,12 +318,17 @@ struct PlugPredicate
}
};
-/// \deprecated Use Plug::Iterator etc instead
+[[deprecated("Use `Plug::Iterator` instead")]]
typedef FilteredChildIterator > PlugIterator;
+[[deprecated("Use `Plug::InputIterator` instead")]]
typedef FilteredChildIterator > InputPlugIterator;
+[[deprecated("Use `Plug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputPlugIterator;
+[[deprecated("Use `Plug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursivePlugIterator;
+[[deprecated("Use `Plug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputPlugIterator;
+[[deprecated("Use `Plug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Private/IECorePreview/ParallelAlgo.h b/include/Gaffer/Private/IECorePreview/ParallelAlgo.h
deleted file mode 100644
index 97a0d3ba46c..00000000000
--- a/include/Gaffer/Private/IECorePreview/ParallelAlgo.h
+++ /dev/null
@@ -1,68 +0,0 @@
-//////////////////////////////////////////////////////////////////////////
-//
-// Copyright (c) 2019, Image Engine Design Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above
-// copyright notice, this list of conditions and the following
-// disclaimer.
-//
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided with
-// the distribution.
-//
-// * Neither the name of John Haddon nor the names of
-// any other contributors to this software may be used to endorse or
-// promote products derived from this software without specific prior
-// written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-//////////////////////////////////////////////////////////////////////////
-
-#ifndef IECOREPREVIEW_PARALLELALGO_H
-#define IECOREPREVIEW_PARALLELALGO_H
-
-#include "tbb/task_arena.h"
-
-namespace IECorePreview
-{
-
-namespace ParallelAlgo
-{
-
-// Calls `f` such that any TBB tasks it spawns will run in isolation,
-// and cannot steal work from outer tasks. This is of fundamental importance
-// if you hold a lock while running any TBB code. See :
-//
-// https://software.intel.com/en-us/blogs/2018/08/16/the-work-isolation-functionality-in-intel-threading-building-blocks-intel-tbb
-template
-void isolate( const F &f )
-{
-#if TBB_INTERFACE_VERSION >= 10000
- tbb::this_task_arena::isolate( f );
-#else
- tbb::task_arena arena;
- arena.execute( f );
-#endif
-}
-
-} // namespace ParallelAlgo
-
-} // namespace IECorePreview
-
-#endif // IECOREPREVIEW_PARALLELALGO_H
diff --git a/include/Gaffer/Private/IECorePreview/TaskMutex.h b/include/Gaffer/Private/IECorePreview/TaskMutex.h
index 93778b16bc1..1d19b395dc2 100644
--- a/include/Gaffer/Private/IECorePreview/TaskMutex.h
+++ b/include/Gaffer/Private/IECorePreview/TaskMutex.h
@@ -189,30 +189,13 @@ class TaskMutex : boost::noncopyable
m_mutex->m_executionState->arena.execute(
[this, &fWrapper] {
-#if TBB_INTERFACE_VERSION >= 10003
+ // Prior to TBB 2018 Update 3, `run_and_wait()` is buggy,
+ // causing calls to `wait()` on other threads to return
+ // immediately rather than do the work we want. Use
+ // `static_assert()` to ensure we never build with a buggy
+ // version.
+ static_assert( TBB_INTERFACE_VERSION >= 10003, "Minumum of TBB 2018 Update 3 required" );
m_mutex->m_executionState->taskGroup.run_and_wait( fWrapper );
-#else
- // The `run_and_wait()` method is buggy until
- // TBB 2018 Update 3, causing calls to `wait()` on other threads to
- // return immediately rather than do the work we want.
- // So we call `run()` and `wait()` separately. This has two
- // downsides though :
- //
- // 1. It appears to trigger a TBB bug whereby it is sometimes
- // unable to destroy the internals of the `task_arena`. It
- // then spends increasing amounts of time in
- // `market::try_destroy_arena()`, doing a linear search through
- // all the zombie arenas until it finds the one it
- // wants to destroy, decides for some reason it can't destroy it,
- // and gives up. With large numbers of arenas this can add
- // huge overhead.
- // 2. It does not guarantee that `fWrapper` runs on the same thread
- // that `run()` is called on (`run_and_wait()` does provide
- // that guarantee). This forces us into nasty ThreadStateFixer
- // workarounds in Gaffer/ValuePlug.cpp.
- m_mutex->m_executionState->taskGroup.run( fWrapper );
- m_mutex->m_executionState->taskGroup.wait();
-#endif
}
);
@@ -359,7 +342,7 @@ class TaskMutex : boost::noncopyable
observe( true );
}
- ~ArenaObserver()
+ ~ArenaObserver() override
{
observe( false );
}
@@ -403,7 +386,7 @@ class TaskMutex : boost::noncopyable
}
// Work around https://bugs.llvm.org/show_bug.cgi?id=32978
- ~ExecutionState() noexcept( true )
+ ~ExecutionState() noexcept( true ) override
{
}
diff --git a/include/Gaffer/Random.h b/include/Gaffer/Random.h
index cc38be7c746..f0d34525072 100644
--- a/include/Gaffer/Random.h
+++ b/include/Gaffer/Random.h
@@ -96,6 +96,8 @@ class GAFFER_API Random : public ComputeNode
};
+IE_CORE_DECLAREPTR( Random )
+
} // namespace Gaffer
#endif // GAFFER_RANDOM_H
diff --git a/include/Gaffer/Reference.h b/include/Gaffer/Reference.h
index 209ce59e096..18c24add9f9 100644
--- a/include/Gaffer/Reference.h
+++ b/include/Gaffer/Reference.h
@@ -92,8 +92,9 @@ class GAFFER_API Reference : public SubGraph
IE_CORE_DECLAREPTR( Reference )
-/// \deprecated Use Reference::Iterator etc instead.
+[[deprecated("Use `Reference::Iterator` instead")]]
typedef FilteredChildIterator > ReferenceIterator;
+[[deprecated("Use `Reference::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator > RecursiveReferenceIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/ScriptNode.h b/include/Gaffer/ScriptNode.h
index 1fd0d6b5f10..0c644b75ba6 100644
--- a/include/Gaffer/ScriptNode.h
+++ b/include/Gaffer/ScriptNode.h
@@ -46,6 +46,8 @@
#include "Gaffer/TypedPlug.h"
#include "Gaffer/UndoScope.h"
+#include "boost/container/flat_set.hpp"
+
#include
#include
@@ -327,7 +329,11 @@ class GAFFER_API ScriptNode : public Node
// =================
ContextPtr m_context;
+ // The names of variables that we have added to `m_context`
+ // from `variablesPlug()`.
+ boost::container::flat_set m_currentVariables;
+ void updateContextVariables();
void plugSet( Plug *plug );
void contextChanged( const Context *context, const IECore::InternedString &name );
diff --git a/include/Gaffer/ShufflePlug.h b/include/Gaffer/ShufflePlug.h
index a41ca4dfc91..62f260b5243 100644
--- a/include/Gaffer/ShufflePlug.h
+++ b/include/Gaffer/ShufflePlug.h
@@ -75,7 +75,7 @@ class GAFFER_API ShufflePlug : public ValuePlug
};
-/// \deprecated Use ShufflePlug::Iterator instead
+[[deprecated("Use `ShufflePlug::Iterator` instead")]]
typedef FilteredChildIterator > ShufflePlugIterator;
IE_CORE_DECLAREPTR( ShufflePlug )
diff --git a/include/Gaffer/ShufflePlug.inl b/include/Gaffer/ShufflePlug.inl
index 120cc6ba90a..ab9abf23cdd 100644
--- a/include/Gaffer/ShufflePlug.inl
+++ b/include/Gaffer/ShufflePlug.inl
@@ -85,7 +85,9 @@ T ShufflesPlug::shuffle( const T &sourceContainer ) const
for( const auto &sourceData : sourceContainer )
{
- scope.set( g_sourceVariable, sourceData.first );
+ // Quick way to get a string from a key that could be std::string or IECore::InternedString
+ const std::string &source = sourceData.first;
+ scope.set( g_sourceVariable, &source );
i = 0;
bool deleteSource = false;
diff --git a/include/Gaffer/SplinePlug.h b/include/Gaffer/SplinePlug.h
index 4020661b2a6..8924161452b 100644
--- a/include/Gaffer/SplinePlug.h
+++ b/include/Gaffer/SplinePlug.h
@@ -190,24 +190,41 @@ IE_CORE_DECLAREPTR( SplineffPlug );
IE_CORE_DECLAREPTR( SplinefColor3fPlug );
IE_CORE_DECLAREPTR( SplinefColor4fPlug );
-/// \deprecated Use SplineffPlug::Iterator etc instead
+[[deprecated("Use `SplineffPlug::Iterator` instead")]]
typedef FilteredChildIterator > SplineffPlugIterator;
+[[deprecated("Use `SplineffPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputSplineffPlugIterator;
+[[deprecated("Use `SplineffPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputSplineffPlugIterator;
+[[deprecated("Use `SplinefColor3fPlug::Iterator` instead")]]
typedef FilteredChildIterator > SplinefColor3fPlugIterator;
+[[deprecated("Use `SplinefColor3fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputSplinefColor3fPlugIterator;
+[[deprecated("Use `SplinefColor3fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputSplinefColor3fPlugIterator;
+[[deprecated("Use `SplinefColor4fPlug::Iterator` instead")]]
typedef FilteredChildIterator > SplinefColor4fPlugIterator;
+[[deprecated("Use `SplinefColor4fPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputSplinefColor4fPlugIterator;
+[[deprecated("Use `SplinefColor4fPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputSplinefColor4fPlugIterator;
+[[deprecated("Use `SplineffPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveSplineffPlugIterator;
+[[deprecated("Use `SplineffPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputSplineffPlugIterator;
+[[deprecated("Use `SplineffPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputSplineffPlugIterator;
+[[deprecated("Use `SplinefColor3fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveSplinefColor3fPlugIterator;
+[[deprecated("Use `SplinefColor3fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputSplinefColor3fPlugIterator;
+[[deprecated("Use `SplinefColor3fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputSplinefColor3fPlugIterator;
+[[deprecated("Use `SplinefColor4fPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveSplinefColor4fPlugIterator;
+[[deprecated("Use `SplinefColor4fPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputSplinefColor4fPlugIterator;
+[[deprecated("Use `SplinefColor4fPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputSplinefColor4fPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/Spreadsheet.h b/include/Gaffer/Spreadsheet.h
index f76519d9e72..eef2156db47 100644
--- a/include/Gaffer/Spreadsheet.h
+++ b/include/Gaffer/Spreadsheet.h
@@ -76,7 +76,7 @@ class GAFFER_API Spreadsheet : public ComputeNode
public :
RowsPlug( const std::string &name = defaultName(), Direction direction = In, unsigned flags = Default );
- virtual ~RowsPlug();
+ ~RowsPlug() override;
GAFFER_PLUG_DECLARE_TYPE( Gaffer::Spreadsheet::RowsPlug, Gaffer::SpreadsheetRowsPlugTypeId, Gaffer::ValuePlug );
diff --git a/include/Gaffer/StringPlug.h b/include/Gaffer/StringPlug.h
index b9893366fd1..edbc475da04 100644
--- a/include/Gaffer/StringPlug.h
+++ b/include/Gaffer/StringPlug.h
@@ -129,12 +129,17 @@ class GAFFER_API StringPlug : public ValuePlug
IE_CORE_DECLAREPTR( StringPlug );
-/// \deprecated Use StringPlug::Iterator etc instead
+[[deprecated("Use `StringPlug::Iterator` instead")]]
typedef FilteredChildIterator > StringPlugIterator;
+[[deprecated("Use `StringPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputStringPlugIterator;
+[[deprecated("Use `StringPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputStringPlugIterator;
+[[deprecated("Use `StringPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveStringPlugIterator;
+[[deprecated("Use `StringPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputStringPlugIterator;
+[[deprecated("Use `StringPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputStringPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/TimeWarp.h b/include/Gaffer/TimeWarp.h
index a5c6e92ecbd..33eccca931c 100644
--- a/include/Gaffer/TimeWarp.h
+++ b/include/Gaffer/TimeWarp.h
@@ -62,7 +62,7 @@ class IECORE_EXPORT TimeWarp : public ContextProcessor
protected :
bool affectsContext( const Plug *input ) const override;
- void processContext( Context::EditableScope &context ) const override;
+ void processContext( Context::EditableScope &context, IECore::ConstRefCountedPtr &storage ) const override;
private :
diff --git a/include/Gaffer/Transform2DPlug.h b/include/Gaffer/Transform2DPlug.h
index a996007b905..715535971eb 100644
--- a/include/Gaffer/Transform2DPlug.h
+++ b/include/Gaffer/Transform2DPlug.h
@@ -81,12 +81,17 @@ class GAFFER_API Transform2DPlug : public ValuePlug
IE_CORE_DECLAREPTR( Transform2DPlug );
-/// \deprecated Use Transform2DPlug::Iterator etc instead
+[[deprecated("Use `Transform2DPlug::Iterator` instead")]]
typedef FilteredChildIterator > Transform2DPlugIterator;
+[[deprecated("Use `Transform2DPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputTransform2DPlugIterator;
+[[deprecated("Use `Transform2DPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputTransform2DPlugIterator;
+[[deprecated("Use `Transform2DPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveTransform2DPlugPlugIterator;
+[[deprecated("Use `Transform2DPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputTransform2DPlugPlugIterator;
+[[deprecated("Use `Transform2DPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputTransform2DPlugPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/TransformPlug.h b/include/Gaffer/TransformPlug.h
index 52f718341c2..4462678a6d7 100644
--- a/include/Gaffer/TransformPlug.h
+++ b/include/Gaffer/TransformPlug.h
@@ -83,12 +83,17 @@ class GAFFER_API TransformPlug : public ValuePlug
IE_CORE_DECLAREPTR( TransformPlug );
-/// \deprecated Use TransformPlug::Iterator etc instead
+[[deprecated("Use `TransformPlug::Iterator` instead")]]
typedef FilteredChildIterator > TransformPlugIterator;
+[[deprecated("Use `TransformPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputTransformPlugIterator;
+[[deprecated("Use `TransformPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputTransformPlugIterator;
+[[deprecated("Use `TransformPlug::RecursiveIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveTransformPlugIterator;
+[[deprecated("Use `TransformPlug::RecursiveInputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveInputTransformPlugIterator;
+[[deprecated("Use `TransformPlug::RecursiveOutputIterator` instead")]]
typedef FilteredRecursiveChildIterator, PlugPredicate<> > RecursiveOutputTransformPlugIterator;
} // namespace Gaffer
diff --git a/include/Gaffer/TypedObjectPlug.h b/include/Gaffer/TypedObjectPlug.h
index 35de5618ffc..912e3ddbcfd 100644
--- a/include/Gaffer/TypedObjectPlug.h
+++ b/include/Gaffer/TypedObjectPlug.h
@@ -172,93 +172,179 @@ IE_CORE_DECLAREPTR( CompoundObjectPlug );
IE_CORE_DECLAREPTR( AtomicCompoundDataPlug );
IE_CORE_DECLAREPTR( PathMatcherDataPlug );
-/// \deprecated Use ObjectPlug::Iterator etc instead
+[[deprecated("Use `ObjectPlug::Iterator` instead")]]
typedef FilteredChildIterator > ObjectPlugIterator;
+[[deprecated("Use `ObjectPlug::InputIterator` instead")]]
typedef FilteredChildIterator > InputObjectPlugIterator;
+[[deprecated("Use `ObjectPlug::OutputIterator` instead")]]
typedef FilteredChildIterator > OutputObjectPlugIterator;
+[[deprecated("Use `BoolVectorDataPlug::Iterator` instead")]]
typedef FilteredChildIterator > BoolVectorDataPlugIterator;
+[[deprecated("Use `BoolVectorDataPlug::InputIterator` instead")]]
typedef FilteredChildIterator