diff --git a/include/IECoreMaya/MayaTypeIds.h b/include/IECoreMaya/MayaTypeIds.h index 644b777ef6..82223ab78e 100644 --- a/include/IECoreMaya/MayaTypeIds.h +++ b/include/IECoreMaya/MayaTypeIds.h @@ -67,6 +67,7 @@ enum MayaTypeId GeometryCombinerId = 0x00110DD2, SceneShapeId = 0x00110DD3, SceneShapeInterfaceId = 0x00110DD4, + SceneShapeProxyId = 0x00110DD5, /// Don't forget to update MayaTypeIdsBinding.cpp LastId = 0x00110E3F, diff --git a/include/IECoreMaya/SceneShapeProxy.h b/include/IECoreMaya/SceneShapeProxy.h new file mode 100644 index 0000000000..e56ba90812 --- /dev/null +++ b/include/IECoreMaya/SceneShapeProxy.h @@ -0,0 +1,67 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2022, 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 Image Engine Design 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 IE_COREMAYA_SCENESHAPEPROXY_H +#define IE_COREMAYA_SCENESHAPEPROXY_H + +#include "IECoreMaya/SceneShape.h" + +namespace IECoreMaya +{ + +/// A proxy derived from the SceneShape which exposes the same functionality as the base clase +/// with the exception, that we never register it as a maya SubSceneOverride. The reasoning +/// behind this is that the SubSceneOverride does not take into account the visibility state of the shape. +/// During an update loop of the SubSceneOverride, all SceneShapes will be queried for their update state, +/// regardless their visibility in the scene. This query is slow and we get a huge drop in performance +/// when having a huge amount of SceneShapes in the scene. +/// This is considered to be a bug in the ViewPort 2 API. Our attempts to rewrite the code to use +/// "MPxGeometryOverride" or "MPxDrawOverride" prove themselves as unstable or not suitable for our +/// use case, why we decided to use this "hackery" and not register a proxy of the SceneShape for +/// drawing at all +class IECOREMAYA_API SceneShapeProxy : public SceneShape +{ + public : + + SceneShapeProxy(); + virtual ~SceneShapeProxy(); + + static void *creator(); + static MStatus initialize(); + static MTypeId id; +}; + +} + +#endif // IE_COREMAYA_SCENESHAPEPROXY_H diff --git a/include/IECoreMaya/SceneShapeProxyUI.h b/include/IECoreMaya/SceneShapeProxyUI.h new file mode 100644 index 0000000000..8ed06afc05 --- /dev/null +++ b/include/IECoreMaya/SceneShapeProxyUI.h @@ -0,0 +1,59 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2022, 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 Image Engine Design 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 IECOREMAYA_SCENESHAPEPROXYUI_H +#define IECOREMAYA_SCENESHAPEPROXYUI_H + +#include "maya/MPxSurfaceShapeUI.h" +#include "maya/MTypes.h" +#include "IECoreMaya/Export.h" + +namespace IECoreMaya +{ + +/// The SceneShapeProxyUI is required for the registration of the SceneShapeProxy and we just make it a NoOp +/// TODO: It might be worth to see if the SceneShapeUI has any dependencies on the drawing capabilities of the +/// shape and if that's not the case, register SceneShapeProxy with the original implementation of SceneShapeUI +class IECOREMAYA_API SceneShapeProxyUI : public MPxSurfaceShapeUI +{ + + public : + + SceneShapeProxyUI(); + static void *creator(); +}; + +} // namespace IECoreMaya + +#endif // IECOREMAYA_SCENESHAPEPROXYUI_H diff --git a/mel/IECoreMaya/IECoreMaya.mel b/mel/IECoreMaya/IECoreMaya.mel index 0f77a7c67b..87fcf1e320 100644 --- a/mel/IECoreMaya/IECoreMaya.mel +++ b/mel/IECoreMaya/IECoreMaya.mel @@ -53,3 +53,4 @@ source "IECoreMaya/ieDrawableHolderUI.mel"; source "IECoreMaya/ieGeometryCombinerUI.mel"; source "IECoreMaya/ieCurveCombinerUI.mel"; source "IECoreMaya/ieSceneShapeUI.mel"; +source "IECoreMaya/ieSceneShapeProxyUI.mel"; diff --git a/mel/IECoreMaya/ieSceneShapeProxyUI.mel b/mel/IECoreMaya/ieSceneShapeProxyUI.mel new file mode 100644 index 0000000000..4164df0eea --- /dev/null +++ b/mel/IECoreMaya/ieSceneShapeProxyUI.mel @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2022, 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 Image Engine Design 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. +// +////////////////////////////////////////////////////////////////////////// + + +global proc AEieSceneShapeProxyTemplate( string $nodeName ) +{ + editorTemplate -beginScrollLayout; + + editorTemplate -beginLayout "Inputs"; + editorTemplate -annotation "Path to the scene interface file." -addControl "file" ; + editorTemplate -annotation "Path in the scene interface where you start reading." -addControl "root"; + editorTemplate -annotation "If on, only read the object at the root path." -addControl "objectOnly"; + editorTemplate -addControl "time"; + + editorTemplate -endLayout; + + editorTemplate -beginLayout "Queries"; + editorTemplate -addControl "querySpace"; + editorTemplate -addControl "queryPaths"; + editorTemplate -addControl "queryAttributes"; + editorTemplate -addControl "queryConvertParameters"; + + editorTemplate -endLayout; + + editorTemplate -beginLayout "All Dynamic Attributes"; + editorTemplate -beginLayout "Open With Caution - Maya May Hang"; + editorTemplate -extraControlsLabel "Too Late Now!" -addExtraControls; + editorTemplate -endLayout; + editorTemplate -endLayout; + + editorTemplate -endScrollLayout; +} diff --git a/python/IECoreMaya/FnSceneShape.py b/python/IECoreMaya/FnSceneShape.py index 9136e60b23..6057f4922f 100644 --- a/python/IECoreMaya/FnSceneShape.py +++ b/python/IECoreMaya/FnSceneShape.py @@ -42,10 +42,12 @@ import IECore import IECoreScene import IECoreMaya -import StringUtil +from . import StringUtil +import six +from six.moves import range -## A function set for operating on the IECoreMaya::SceneShape type. +## A function set for operating on the IECoreMaya::SceneShape and IECoreMaya::SceneShapeProxy types. class FnSceneShape( maya.OpenMaya.MFnDagNode ) : __MayaAttributeDataType = namedtuple('__MayaAttributeDataType', 'namespace type') @@ -72,30 +74,50 @@ class FnSceneShape( maya.OpenMaya.MFnDagNode ) : ## Initialise the function set for the given procedural object, which may # either be an MObject or a node name in string or unicode form. # Note: Most of the member functions assume that this function set is initialized with the full dag path. - def __init__( self, object ) : - if isinstance( object, basestring ) : - object = StringUtil.dagPathFromString( object ) + def __init__( self, mayaObject ) : + + if isinstance( mayaObject, six.string_types ) : + mayaObject = StringUtil.dagPathFromString( mayaObject ) + maya.OpenMaya.MFnDagNode.__init__( self, mayaObject ) + + # We use pythons metaprogramming capabilities and dynamically change the object that is created based + # on the node type type that is passed in. We do this so that we can use FnSceneShape for two different + # node types, i.e. SceneShape and its derived proxy class SceneShapeProxy, without having to change huge + # parts of the codebase. SceneShape and SceneShapeProxy both provide the same core functionality of reading + # a SceneInterface, with the difference that SceneShapeProxy can't be drawn in the ViewPort and therefore + # drawing/selecting related methods in those class have no effect. See SceneShapeProxy.h for more information. + def __new__( cls, mayaObject ): + + if isinstance( mayaObject, six.string_types ) : + mayaObject = StringUtil.dagPathFromString( mayaObject ) + else: + dagPath = maya.OpenMaya.MDagPath() + maya.OpenMaya.MDagPath.getAPathTo(mayaObject, dagPath) + mayaObject = dagPath - maya.OpenMaya.MFnDagNode.__init__( self, object ) + if maya.cmds.nodeType(mayaObject.fullPathName()) == "ieSceneShape": + return object.__new__(FnSceneShape) + if maya.cmds.nodeType(mayaObject.fullPathName()) == "ieSceneShapeProxy": + return object.__new__(_FnSceneShapeProxy) ## Creates a new node under a transform of the specified name. Returns a function set instance operating on this new node. - @staticmethod + @classmethod @IECoreMaya.UndoFlush() - def create( parentName, transformParent = None, shadingEngine = None ) : + def create( cls, parentName, transformParent = None, shadingEngine = None, shapeType=None ) : try: parentNode = maya.cmds.createNode( "transform", name=parentName, skipSelect=True, parent = transformParent ) except: # The parent name is supposed to be the children names in a sceneInterface, they could be numbers, maya doesn't like that. Use a prefix. parentNode = maya.cmds.createNode( "transform", name="sceneShape_"+parentName, skipSelect=True, parent = transformParent ) - return FnSceneShape.createShape( parentNode, shadingEngine=shadingEngine ) + return cls.createShape( parentNode, shadingEngine=shadingEngine, shapeType=shapeType ) ## Create a scene shape under the given node. Returns a function set instance operating on this shape. - @staticmethod + @classmethod @IECoreMaya.UndoFlush() - def createShape( parentNode, shadingEngine = None ) : + def createShape( cls, parentNode, shadingEngine = None, shapeType=None ) : parentShort = parentNode.rpartition( "|" )[-1] - numbersMatch = re.search( "[0-9]+$", parentShort ) + numbersMatch = re.search( r"[0-9]+$", parentShort ) if numbersMatch is not None : numbers = numbersMatch.group() shapeName = parentShort[:-len(numbers)] + "SceneShape" + numbers @@ -103,11 +125,11 @@ def createShape( parentNode, shadingEngine = None ) : shapeName = parentShort + "SceneShape" dagMod = maya.OpenMaya.MDagModifier() - shapeNode = dagMod.createNode( FnSceneShape._mayaNodeType(), IECoreMaya.StringUtil.dependencyNodeFromString( parentNode ) ) + shapeNode = dagMod.createNode( shapeType if shapeType else cls._mayaNodeType(), IECoreMaya.StringUtil.dependencyNodeFromString( parentNode ) ) dagMod.renameNode( shapeNode, shapeName ) dagMod.doIt() - fnScS = FnSceneShape( shapeNode ) + fnScS = cls( shapeNode ) maya.cmds.sets( fnScS.fullPathName(), edit=True, forceElement=shadingEngine or "initialShadingGroup" ) fnScS.findPlug( "objectOnly" ).setLocked( True ) @@ -121,13 +143,13 @@ def createShape( parentNode, shadingEngine = None ) : ## Registers a new callback triggered when a new child shape is created during geometry expansion. # Signature: `callback( dagPath )` - @staticmethod - def addChildCreatedCallback( func ): - FnSceneShape.__childCreatedCallbacks.add( func ) + @classmethod + def addChildCreatedCallback( cls, func ): + cls.__childCreatedCallbacks.add( func ) - @staticmethod - def __executeChildCreatedCallbacks( dagPath ): - for callback in FnSceneShape.__childCreatedCallbacks: + @classmethod + def __executeChildCreatedCallbacks( cls, dagPath ): + for callback in cls.__childCreatedCallbacks: try: callback( dagPath ) except Exception as exc: @@ -163,7 +185,7 @@ def selectedComponentNames( self ) : ## Selects the components specified by the passed names. def selectComponentNames( self, componentNames ) : if not isinstance( componentNames, set ) : - if isinstance( componentNames, basestring ): + if isinstance( componentNames, six.string_types ): componentNames = set( (componentNames, ) ) else: componentNames = set( componentNames ) @@ -264,11 +286,11 @@ def __createChild( self, childName, sceneFile, sceneRoot, drawGeo = False, drawC if maya.cmds.objExists(childPath): shape = maya.cmds.listRelatives( childPath, fullPath=True, type="ieSceneShape" ) if shape: - fnChild = IECoreMaya.FnSceneShape( shape[0] ) + fnChild = self.__class__( shape[0] ) else: - fnChild = IECoreMaya.FnSceneShape.createShape( childPath, shadingEngine=shadingGroup ) + fnChild = self.createShape( childPath, shadingEngine=shadingGroup ) else: - fnChild = IECoreMaya.FnSceneShape.create( childName, transformParent=parentPath, shadingEngine=shadingGroup ) + fnChild = self.create( childName, transformParent=parentPath, shadingEngine=shadingGroup ) fnChildTransform = maya.OpenMaya.MFnDagNode( fnChild.parent( 0 ) ) @@ -284,7 +306,7 @@ def __createChild( self, childName, sceneFile, sceneRoot, drawGeo = False, drawC # Set visible if I have any of the draw flags in my hierarchy, otherwise set hidden if drawTagsFilter: childTags = fnChild.sceneInterface().readTags( IECoreScene.SceneInterface.EveryTag ) - commonTags = filter( lambda x: str(x) in childTags, drawTagsFilter.split() ) + commonTags = [x for x in drawTagsFilter.split() if str(x) in childTags] if not commonTags: dgMod.newPlugValueBool( fnChildTransform.findPlug( "visibility" ), False ) else: @@ -296,24 +318,24 @@ def __createChild( self, childName, sceneFile, sceneRoot, drawGeo = False, drawC outTransform = self.findPlug( "outTransform" ).elementByLogicalIndex( index ) childTranslate = fnChildTransform.findPlug( "translate" ) - FnSceneShape.__disconnectPlug( dgMod, childTranslate ) + self.__disconnectPlug( dgMod, childTranslate ) dgMod.connect( outTransform.child( self.attribute( "outTranslate" ) ), childTranslate ) childRotate = fnChildTransform.findPlug( "rotate" ) - FnSceneShape.__disconnectPlug( dgMod, childRotate) + self.__disconnectPlug( dgMod, childRotate) dgMod.connect( outTransform.child( self.attribute( "outRotate" ) ), childRotate ) childScale = fnChildTransform.findPlug( "scale" ) - FnSceneShape.__disconnectPlug( dgMod, childScale ) + self.__disconnectPlug( dgMod, childScale ) dgMod.connect( outTransform.child( self.attribute( "outScale" ) ), childScale ) childTime = fnChild.findPlug( "time" ) - FnSceneShape.__disconnectPlug( dgMod, childTime ) + self.__disconnectPlug( dgMod, childTime ) dgMod.connect( self.findPlug( "outTime" ), childTime ) dgMod.doIt() - FnSceneShape.__executeChildCreatedCallbacks( fnChild.fullPathName() ) + self.__executeChildCreatedCallbacks( fnChild.fullPathName() ) return fnChild @@ -689,7 +711,7 @@ def __cortexTypeToMayaType( self, querySceneInterface, attributeName ): timePlug = self.findPlug( 'time', False ) time = timePlug.asMTime().asUnits( maya.OpenMaya.MTime.kSeconds ) cortexData = querySceneInterface.readAttribute( attributeName, time ) - return FnSceneShape.__cortexToMayaDataTypeMap.get( cortexData.typeId() ) + return self.__cortexToMayaDataTypeMap.get( cortexData.typeId() ) ## Returns a list of attribute names which can be promoted to maya plugs. # \param queryPath Path to the scene from which we want return attribute names. Defaults to root '/' @@ -791,3 +813,15 @@ def promoteAttribute( self, attributeName, queryPath='/', nodePath='', mayaAttri @classmethod def _mayaNodeType( cls ): return "ieSceneShape" + + +# A derived function set for operating on the IECoreMaya::SceneShapeProxy type. +# It inherits all functionality from the base clase and we only override the `_mayaNodeType` method. +# This object is used in the __new__ method of FnSceneShape to create the correct object depending +# on the passed in node type +class _FnSceneShapeProxy( FnSceneShape ) : + + # Returns the maya node type that this function set operates on + @classmethod + def _mayaNodeType( cls ): + return "ieSceneShapeProxy" diff --git a/python/IECoreMaya/__init__.py b/python/IECoreMaya/__init__.py index 7372b97d8a..c5f39ab6fc 100644 --- a/python/IECoreMaya/__init__.py +++ b/python/IECoreMaya/__init__.py @@ -34,72 +34,73 @@ __import__( "IECoreScene" ) -from _IECoreMaya import * +from ._IECoreMaya import * -from UIElement import UIElement -from ParameterUI import ParameterUI -from BoolParameterUI import BoolParameterUI -from StringParameterUI import StringParameterUI -from PathParameterUI import PathParameterUI -from FileNameParameterUI import FileNameParameterUI -from DirNameParameterUI import DirNameParameterUI -from FileSequenceParameterUI import FileSequenceParameterUI -from NumericParameterUI import NumericParameterUI -from VectorParameterUI import VectorParameterUI -from ColorParameterUI import ColorParameterUI -from BoxParameterUI import BoxParameterUI -from SplineParameterUI import SplineParameterUI -from NoteParameterUI import NoteParameterUI -from NodeParameter import NodeParameter -from DAGPathParameter import DAGPathParameter -from DAGPathVectorParameter import DAGPathVectorParameter -from mayaDo import mayaDo -from Menu import Menu -from BakeTransform import BakeTransform -from MeshOpHolderUtil import create -from MeshOpHolderUtil import createUI -from ScopedSelection import ScopedSelection -from FnParameterisedHolder import FnParameterisedHolder -from FnConverterHolder import FnConverterHolder -from StringUtil import * -from MayaTypeId import MayaTypeId -from ParameterPanel import ParameterPanel -from AttributeEditorControl import AttributeEditorControl -from OpWindow import OpWindow -from FnTransientParameterisedHolderNode import FnTransientParameterisedHolderNode -from UndoDisabled import UndoDisabled -from ModalDialogue import ModalDialogue -from Panel import Panel -from WaitCursor import WaitCursor -from FnOpHolder import FnOpHolder -from UITemplate import UITemplate -from FnParameterisedHolderSet import FnParameterisedHolderSet -from TemporaryAttributeValues import TemporaryAttributeValues -from GenericParameterUI import GenericParameterUI -from FnDagNode import FnDagNode -from CompoundParameterUI import CompoundParameterUI -from ClassParameterUI import ClassParameterUI -from ClassVectorParameterUI import ClassVectorParameterUI -from PresetsOnlyParameterUI import PresetsOnlyParameterUI -from TestCase import TestCase -from TestProgram import TestProgram -from FileBrowser import FileBrowser -from FileDialog import FileDialog -from GeometryCombinerUI import * -from PresetsUI import * -from ParameterClipboardUI import * -from NumericVectorParameterUI import NumericVectorParameterUI -from StringVectorParameterUI import StringVectorParameterUI -from ManipulatorUI import * -from TransformationMatrixParameterUI import TransformationMatrixParameterUI -from LineSegmentParameterUI import LineSegmentParameterUI -from Collapsible import Collapsible -from RefreshDisabled import RefreshDisabled -from UndoChunk import UndoChunk -from UndoFlush import UndoFlush +from .UIElement import UIElement +from .ParameterUI import ParameterUI +from .BoolParameterUI import BoolParameterUI +from .StringParameterUI import StringParameterUI +from .PathParameterUI import PathParameterUI +from .FileNameParameterUI import FileNameParameterUI +from .DirNameParameterUI import DirNameParameterUI +from .FileSequenceParameterUI import FileSequenceParameterUI +from .NumericParameterUI import NumericParameterUI +from .VectorParameterUI import VectorParameterUI +from .ColorParameterUI import ColorParameterUI +from .BoxParameterUI import BoxParameterUI +from .SplineParameterUI import SplineParameterUI +from .NoteParameterUI import NoteParameterUI +from .NodeParameter import NodeParameter +from .DAGPathParameter import DAGPathParameter +from .DAGPathVectorParameter import DAGPathVectorParameter +from .mayaDo import mayaDo +from .Menu import Menu +from .BakeTransform import BakeTransform +from .MeshOpHolderUtil import create +from .MeshOpHolderUtil import createUI +from .ScopedSelection import ScopedSelection +from .FnParameterisedHolder import FnParameterisedHolder +from .FnConverterHolder import FnConverterHolder +from .StringUtil import * +from .MayaTypeId import MayaTypeId +from .ParameterPanel import ParameterPanel +from .AttributeEditorControl import AttributeEditorControl +from .OpWindow import OpWindow +from .FnTransientParameterisedHolderNode import FnTransientParameterisedHolderNode +from .UndoDisabled import UndoDisabled +from .ModalDialogue import ModalDialogue +from .Panel import Panel +from .WaitCursor import WaitCursor +from .FnOpHolder import FnOpHolder +from .UITemplate import UITemplate +from .FnParameterisedHolderSet import FnParameterisedHolderSet +from .TemporaryAttributeValues import TemporaryAttributeValues +from .GenericParameterUI import GenericParameterUI +from .FnDagNode import FnDagNode +from .CompoundParameterUI import CompoundParameterUI +from .ClassParameterUI import ClassParameterUI +from .ClassVectorParameterUI import ClassVectorParameterUI +from .PresetsOnlyParameterUI import PresetsOnlyParameterUI +from .TestCase import TestCase +from .TestProgram import TestProgram +from .FileBrowser import FileBrowser +from .FileDialog import FileDialog +from .GeometryCombinerUI import * +from .PresetsUI import * +from .ParameterClipboardUI import * +from .NumericVectorParameterUI import NumericVectorParameterUI +from .StringVectorParameterUI import StringVectorParameterUI +from .ManipulatorUI import * +from .TransformationMatrixParameterUI import TransformationMatrixParameterUI +from .LineSegmentParameterUI import LineSegmentParameterUI +from .Collapsible import Collapsible +from .RefreshDisabled import RefreshDisabled +from .UndoChunk import UndoChunk +from .UndoFlush import UndoFlush -import Menus -import SceneShapeUI -from FnSceneShape import FnSceneShape +from . import Menus +from . import SceneShapeUI +from .FnSceneShape import FnSceneShape +from .FnSceneShape import _FnSceneShapeProxy __import__( "IECore" ).loadConfig( "CORTEX_STARTUP_PATHS", subdirectory = "IECoreMaya" ) diff --git a/src/IECoreMaya/IECoreMaya.cpp b/src/IECoreMaya/IECoreMaya.cpp index 313d6be15c..2ba03f40ad 100644 --- a/src/IECoreMaya/IECoreMaya.cpp +++ b/src/IECoreMaya/IECoreMaya.cpp @@ -71,7 +71,9 @@ #include "IECoreMaya/DrawableHolder.h" #include "IECoreMaya/DrawableHolderUI.h" #include "IECoreMaya/SceneShape.h" +#include "IECoreMaya/SceneShapeProxy.h" #include "IECoreMaya/SceneShapeUI.h" +#include "IECoreMaya/SceneShapeProxyUI.h" #include "IECoreMaya/SceneShapeInterface.h" #include "IECoreMaya/SceneShapeSubSceneOverride.h" @@ -148,6 +150,12 @@ MStatus initialize(MFnPlugin &plugin) s = MHWRender::MDrawRegistry::registerSubSceneOverrideCreator( SceneShapeSubSceneOverride::drawDbClassification(), SceneShapeSubSceneOverride::drawDbId(), SceneShapeSubSceneOverride::Creator ); assert( s ); + /// Note the missing classification for the draw DB and the "missing" call to "MHWRender::MDrawRegistry::registerSubSceneOverrideCreator" + /// after registering the Shape itself. See the documentation of the SceneShapeProxy class in SceneShapeProxy.h for the reason behind this. + s = plugin.registerShape( "ieSceneShapeProxy", SceneShapeProxy::id, + SceneShapeProxy::creator, SceneShapeProxy::initialize, SceneShapeProxyUI::creator ); + assert( s ); + s = plugin.registerNode( "ieOpHolderNode", OpHolderNode::id, OpHolderNode::creator, OpHolderNode::initialize ); assert( s ); @@ -245,6 +253,7 @@ MStatus uninitialize(MFnPlugin &plugin) s = plugin.deregisterNode( ParameterisedHolderComponentShape::id ); s = plugin.deregisterNode( SceneShapeInterface::id ); s = plugin.deregisterNode( SceneShape::id ); + s = plugin.deregisterNode( SceneShapeProxy::id ); s = plugin.deregisterNode( OpHolderNode::id ); s = plugin.deregisterNode( ConverterHolder::id ); s = plugin.deregisterNode( TransientParameterisedHolderNode::id ); diff --git a/src/IECoreMaya/SceneShape.cpp b/src/IECoreMaya/SceneShape.cpp index aa69e1d4fa..207552b6a7 100644 --- a/src/IECoreMaya/SceneShape.cpp +++ b/src/IECoreMaya/SceneShape.cpp @@ -190,7 +190,7 @@ SceneShape *SceneShape::findScene( const MDagPath &p, bool noIntermediate, MDagP MFnDagNode fnChildDag(childObject); MPxNode* userNode = fnChildDag.userNode(); - if( userNode && userNode->typeId() == SceneShapeId ) + if( userNode && ( userNode->typeId() == SceneShapeId || userNode->typeId() == SceneShapeProxyId ) ) { if ( noIntermediate && fnChildDag.isIntermediateObject() ) { diff --git a/src/IECoreMaya/SceneShapeProxy.cpp b/src/IECoreMaya/SceneShapeProxy.cpp new file mode 100644 index 0000000000..965d0f95ba --- /dev/null +++ b/src/IECoreMaya/SceneShapeProxy.cpp @@ -0,0 +1,55 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2022, 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 Image Engine Design 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. +// +////////////////////////////////////////////////////////////////////////// + +#include "IECoreMaya/SceneShapeProxy.h" +#include "IECoreMaya/MayaTypeIds.h" + +using namespace IECoreMaya; + +MTypeId SceneShapeProxy::id = SceneShapeProxyId; + +SceneShapeProxy::SceneShapeProxy() {} + +SceneShapeProxy::~SceneShapeProxy() {} + +void *SceneShapeProxy::creator() +{ + return new SceneShapeProxy; +} + +MStatus SceneShapeProxy::initialize() +{ + MStatus s = inheritAttributesFrom( "ieSceneShape" ); + return s; +} diff --git a/src/IECoreMaya/SceneShapeProxyUI.cpp b/src/IECoreMaya/SceneShapeProxyUI.cpp new file mode 100644 index 0000000000..935348cf81 --- /dev/null +++ b/src/IECoreMaya/SceneShapeProxyUI.cpp @@ -0,0 +1,46 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2022, 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 Image Engine Design 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. +// +////////////////////////////////////////////////////////////////////////// + +#include "IECoreMaya/SceneShapeProxyUI.h" + +using namespace IECoreMaya; + +SceneShapeProxyUI::SceneShapeProxyUI() +{ +} + +void *SceneShapeProxyUI::creator() +{ + return new SceneShapeProxyUI; +} diff --git a/src/IECoreMaya/bindings/MayaTypeIdBinding.cpp b/src/IECoreMaya/bindings/MayaTypeIdBinding.cpp index 806a2082f8..cbe1e9f8c4 100644 --- a/src/IECoreMaya/bindings/MayaTypeIdBinding.cpp +++ b/src/IECoreMaya/bindings/MayaTypeIdBinding.cpp @@ -69,6 +69,7 @@ void bindMayaTypeId() .value( "GeometryCombiner", GeometryCombinerId ) .value( "SceneShapeInterface", SceneShapeInterfaceId ) .value( "SceneShape", SceneShapeId ) + .value( "SceneShapeProxy", SceneShapeProxyId ) ; } diff --git a/test/IECoreMaya/All.py b/test/IECoreMaya/All.py index 071b9e2df3..4303730cc7 100644 --- a/test/IECoreMaya/All.py +++ b/test/IECoreMaya/All.py @@ -81,6 +81,7 @@ from ToMayaCameraConverterTest import ToMayaCameraConverterTest from LiveSceneTest import * from SceneShapeTest import SceneShapeTest +from SceneShapeProxyTest import SceneShapeProxyTest from FnSceneShapeTest import FnSceneShapeTest from FromMayaLocatorConverterTest import FromMayaLocatorConverterTest from ToMayaLocatorConverterTest import ToMayaLocatorConverterTest diff --git a/test/IECoreMaya/FnSceneShapeTest.py b/test/IECoreMaya/FnSceneShapeTest.py index bad6e48725..a91332a73b 100644 --- a/test/IECoreMaya/FnSceneShapeTest.py +++ b/test/IECoreMaya/FnSceneShapeTest.py @@ -113,6 +113,32 @@ def __setupTableProp( self ): mat = IECore.TransformationMatrixd( s, r, t ) tableTop_GEO.writeTransform( IECore.TransformationMatrixdData(mat), 0 ) + def testClassTypeInstantiation( self ): + + sceneShapeNode = maya.cmds.createNode( "ieSceneShape" ) + sceneShapeFn = IECoreMaya.FnSceneShape( sceneShapeNode ) + self.assertEqual( sceneShapeFn.__class__, IECoreMaya.FnSceneShape ) + + sceneShapeProxyNode = maya.cmds.createNode( "ieSceneShapeProxy" ) + sceneShapeProxyFn = IECoreMaya.FnSceneShape( sceneShapeProxyNode ) + self.assertEqual( sceneShapeProxyFn.__class__, IECoreMaya._FnSceneShapeProxy ) + + def testCreateShapeType( self ): + + sceneShapeTransform = maya.cmds.createNode( "transform" ) + sceneShapeFn = IECoreMaya.FnSceneShape.createShape( sceneShapeTransform, shapeType="ieSceneShape") + self.assertEqual( sceneShapeFn.__class__, IECoreMaya.FnSceneShape ) + + sceneShapeNode = maya.cmds.listRelatives( sceneShapeTransform, shapes=True) + self.assertTrue( maya.cmds.objectType( sceneShapeNode, isType="ieSceneShape" )) + + sceneShapeProxyTransform = maya.cmds.createNode( "transform" ) + sceneShapeProxyFn = IECoreMaya.FnSceneShape.createShape( sceneShapeProxyTransform, shapeType="ieSceneShapeProxy" ) + self.assertEqual( sceneShapeProxyFn.__class__, IECoreMaya._FnSceneShapeProxy ) + + sceneShapeProxyNode = maya.cmds.listRelatives( sceneShapeProxyTransform, shapes=True) + self.assertTrue( maya.cmds.objectType( sceneShapeProxyNode, isType="ieSceneShapeProxy" )) + def testSceneInterface( self ) : maya.cmds.file( new=True, f=True ) diff --git a/test/IECoreMaya/SceneShapeProxyTest.py b/test/IECoreMaya/SceneShapeProxyTest.py new file mode 100644 index 0000000000..67f90a1b9c --- /dev/null +++ b/test/IECoreMaya/SceneShapeProxyTest.py @@ -0,0 +1,48 @@ +########################################################################## +# +# Copyright (c) 2022, 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 Image Engine Design 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. +# +########################################################################## + + +import IECoreMaya +import maya.cmds + +import SceneShapeTest + +class SceneShapeProxyTest( SceneShapeTest.SceneShapeTest ): + + def setUp( self ): + IECoreMaya.TestCase.setUp(self) + self._node = maya.cmds.createNode( "ieSceneShapeProxy" ) + +if __name__ == "__main__": + IECoreMaya.TestProgram( plugins = [ "ieCore" ] ) diff --git a/test/IECoreMaya/SceneShapeTest.py b/test/IECoreMaya/SceneShapeTest.py index aa66d6841e..79864ef68a 100644 --- a/test/IECoreMaya/SceneShapeTest.py +++ b/test/IECoreMaya/SceneShapeTest.py @@ -48,9 +48,9 @@ class SceneShapeTest( IECoreMaya.TestCase ) : __testPlugAnimFile = "test/testPlugAnim.scc" __testPlugAttrFile = "test/testPlugAttr.scc" - def setUp( self ) : - - maya.cmds.file( new=True, f=True ) + def setUp( self ): + super( SceneShapeTest, self ).setUp() + self._node = maya.cmds.createNode( "ieSceneShape" ) def writeSCC( self, file, rotation=imath.V3d( 0, 0, 0 ), time=0 ) : @@ -136,8 +136,7 @@ def testComputePlugs( self ) : self.writeSCC( file = SceneShapeTest.__testFile ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node maya.cmds.setAttr( node+'.file', SceneShapeTest.__testFile,type='string' ) maya.cmds.setAttr( node+'.root',"/",type='string' ) @@ -179,13 +178,11 @@ def testComputePlugs( self ) : self.assertEqual( maya.cmds.getAttr( node+".outBound", mi=True ), [1]) self.assertEqual( maya.cmds.getAttr( node+".outObjects", mi=True ), [2]) - def testPlugValues( self ) : self.writeSCC( file=SceneShapeTest.__testPlugFile, rotation = imath.V3d( 0, 0, IECore.degreesToRadians( -30 ) ) ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node maya.cmds.setAttr( node+'.file', SceneShapeTest.__testPlugFile,type='string' ) maya.cmds.setAttr( node+'.root',"/",type='string' ) @@ -291,13 +288,11 @@ def testPlugValues( self ) : maya.cmds.setAttr( node+'.time', 5 ) self.assertEqual( maya.cmds.getAttr( node+".outTime" ), 5 ) - def testAnimPlugValues( self ) : self.writeAnimSCC( file=SceneShapeTest.__testPlugAnimFile ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node maya.cmds.connectAttr( "time1.outTime", node+".time" ) maya.cmds.setAttr( node+'.file', SceneShapeTest.__testPlugAnimFile,type='string' ) @@ -413,13 +408,11 @@ def testAnimPlugValues( self ) : self.assertAlmostEqual( maya.cmds.getAttr( node+".outTransform[2].outRotateZ"), 0.0 ) self.assertEqual( maya.cmds.getAttr( node+".outTransform[2].outScale"), [(1.0, 1.0, 1.0)] ) - - def testqueryAttributes( self ) : + def testQueryAttributes( self ) : self.writeAttributeSCC( file=SceneShapeTest.__testPlugAttrFile ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node maya.cmds.setAttr( node+'.file', SceneShapeTest.__testPlugAttrFile,type='string' ) maya.cmds.setAttr( node+".queryPaths[0]", "/1", type="string") @@ -458,8 +451,7 @@ def testTags( self ) : self.writeTagSCC( file=SceneShapeTest.__testFile ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node fn = IECoreMaya.FnSceneShape( node ) transform = str(maya.cmds.listRelatives( node, parent=True )[0]) maya.cmds.setAttr( node+'.file', SceneShapeTest.__testFile, type='string' ) @@ -492,8 +484,7 @@ def testLiveSceneTags( self ) : self.writeTagSCC( file=SceneShapeTest.__testFile ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node fn = IECoreMaya.FnSceneShape( node ) transform = str(maya.cmds.listRelatives( node, parent=True )[0]) maya.cmds.setAttr( node+'.file', SceneShapeTest.__testFile, type='string' ) @@ -528,8 +519,7 @@ def testLinkedLiveSceneTags( self ) : self.writeTagSCC( file=SceneShapeTest.__testFile ) - maya.cmds.file( new=True, f=True ) - node = maya.cmds.createNode( 'ieSceneShape' ) + node = self._node fn = IECoreMaya.FnSceneShape( node ) transform = str(maya.cmds.listRelatives( node, parent=True )[0]) maya.cmds.setAttr( node+'.file', SceneShapeTest.__testFile, type='string' )