3
Provides methodes to query and alter the currently loaded scene. It covers
4
most of the functionality of the 'file' command, but has been renamed to scene
5
as disambiguation to a filesystem file.
7
__docformat__ = "restructuredtext"
10
import mrv.util as util
11
import maya.OpenMaya as api
12
import maya.cmds as cmds
13
from mrv.path import make_path
20
class _SceneEvent( mutil.CallbackEventBase ):
21
""" Implements Scene Callbacks"""
23
_checkCBSet = set( ( api.MSceneMessage.kBeforeNewCheck,
24
api.MSceneMessage.kBeforeSaveCheck ) )
26
_checkFileCBSet = set( ( api.MSceneMessage.kBeforeImportCheck,
27
api.MSceneMessage.kBeforeOpenCheck,
28
api.MSceneMessage.kBeforeExportCheck,
29
api.MSceneMessage.kBeforeReferenceCheck,
30
api.MSceneMessage.kBeforeLoadReferenceCheck ) )
34
remove_on_error = True
39
# get the proper registration method
40
def _getRegisterFunction(self, eventID):
41
reg_method = api.MSceneMessage.addCallback
42
if eventID in self._checkCBSet:
43
reg_method = api.MSceneMessage.addCheckCallback
44
elif eventID in self._checkFileCBSet:
45
reg_method = api.MSceneMessage.addCheckFileCallback
46
# END find registration method
53
class Scene( util.Singleton, util.EventSender ):
54
"""Singleton Class allowing access to the maya scene
56
You can register all events available in MSceneMessage easily usnig the following
59
>>> scene.beforeSoftwareRender = myFunctionObject
64
kFileTypeMap = { "" : "mayaAscii", # treat untitled scenes as ma
66
".mb" : "mayaBinary" }
69
sender_as_argument = False
71
# create events from 'kEventName', creating a corresponding event named
73
for eidName, eid in ((n,v) for n,v in inspect.getmembers(api.MSceneMessage) if n.startswith('k')):
74
locals()[util.uncapitalize(eidName[1:])] = _SceneEvent(eid)
75
# END for each message id to create
83
def open( cls, scenepath=None, force=False, **kwargs ):
84
""" Open the scene at the given scenepath
86
:param scenepath: The path to the file to be opened
87
If None, the currently loaded file will reopened
88
:param force: if True, the new scene will be loaded although currently
89
loaded contains unsaved changes
90
:param kwargs: passed to *cmds.file*
91
:return: a Path to the loaded scene"""
93
scenepath = cls.name()
95
# NOTE: it will return the last loaded reference instead of the loaded file - lets fix this !
96
sourcePath = make_path( scenepath )
97
kwargs.pop('open', kwargs.pop('o', None))
98
kwargs.pop('force', kwargs.pop('f', None))
99
lastReference = cmds.file( sourcePath.abspath(), open=1, force=force, **kwargs )
100
return make_path( sourcePath )
103
def new( cls, force = False, **kwargs ):
104
""" Create a new scene
106
:param force: if True, the new scene will be created even though there
107
are unsaved modifications
108
:param kwargs: passed to *cmds.file*
109
:return: Path with name of the new file"""
110
kwargs.pop('new', kwargs.pop('n', None))
111
kwargs.pop('force', kwargs.pop('f', None))
112
return make_path( cmds.file( new = True, force = force, **kwargs ) )
115
def rename( cls, scenepath ):
116
"""Rename the currently loaded file to be the file at scenepath
118
:param scenepath: string or Path pointing describing the new location of the scene.
119
:return: Path to scenepath
120
:note: as opposed to the normal file -rename it will also adjust the extension
121
:raise RuntimeError: if the scene's extension is not supported."""
122
scenepath = make_path(scenepath)
124
cmds.file( rename = scenepath.expandvars() )
125
cmds.file( type = cls.kFileTypeMap[ scenepath.ext() ] )
127
raise RuntimeError( "Unsupported filetype of: " + scenepath )
128
# END exception handling
133
def save( cls, scenepath=None, autodeleteUnknown = False, **kwargs ):
134
"""Save the currently opened scene under scenepath in the respective format
136
:param scenepath: if None, the currently opened scene will be saved, otherwise
137
the name will be changed. Paths leading to the file will automatically be created.
138
:param autodeleteUnknown: if true, unknown nodes will automatically be deleted
139
before an attempt is made to change the maya file's type
140
:param kwargs: passed to cmds.file
141
:return: Path at which the scene has been saved."""
142
if scenepath is None or scenepath == "":
143
scenepath = cls.name( )
145
scenepath = make_path( scenepath )
146
curscene = cls.name()
148
filetype = cls.kFileTypeMap[ scenepath.ext() ]
149
curscenetype = cls.kFileTypeMap[ curscene.ext() ]
151
raise RuntimeError( "Unsupported filetype of: " + scenepath )
154
if curscene != scenepath:
155
cls.rename(scenepath)
158
parentdir = scenepath.dirname( )
159
if not parentdir.exists( ):
160
parentdir.makedirs( )
161
# END assure parent path exists
163
# delete unknown before changing types ( would result in an error otherwise )
164
if autodeleteUnknown and curscenetype != filetype:
165
cls.deleteUnknownNodes()
166
# END handle unkonwn nodes
169
kwargs.pop('save', kwargs.pop('s', None))
170
kwargs.pop('type', kwargs.pop('typ', None))
172
return make_path( cmds.file( save=True, type=filetype, **kwargs ) )
174
if curscene != cls.name():
176
# END restore previous name on error
178
# END exception handling
181
def export(cls, outputFile, nodeListOrIterable=None, **kwargs):
182
"""Export the given nodes or everything into the file at path
184
:param outputFile: Path object or path string to which the data should
185
be written to. Parent directories will be created as needed
186
:param nodeListOrIterable: if None, everything will be exported.
187
Otherwise it may be an MSelectionList ( recommended ), or a list of
188
Nodes, MObjects or MDagPaths
189
:param kwargs: passed to cmds.file, see the mel docs for modifying flags
190
:return: Path to which the data was exported"""
191
outputFile = make_path(outputFile)
192
if not outputFile.dirname().isdir():
193
outputFile.dirname().makedirs()
194
# END create parent dirs
196
prev_selection = None
197
if nodeListOrIterable is None:
198
kwargs['exportAll'] = True
200
# export selected mode
201
kwargs['exportSelected'] = True
202
prev_selection = api.MSelectionList()
203
api.MGlobal.getActiveSelectionList(prev_selection)
206
nt.select(nt.toSelectionList(nodeListOrIterable))
209
typ = kwargs.pop('type', kwargs.pop('typ', cls.kFileTypeMap.get(outputFile.ext(), None)))
211
raise RuntimeError("Invalid type in %s" % outputFile)
215
cmds.file(outputFile, type=typ, **kwargs)
218
if prev_selection is not None:
219
api.MGlobal.setActiveSelectionList(prev_selection)
220
# END if we have a selection to restore
221
# END handle selection
227
def deleteUnknownNodes( cls ):
228
"""Deletes all unknown nodes in the scene
230
:note: only do this if you are about to change the type of the scene during
231
save or export - otherwise the operation would fail if there are still unknown nodes
233
unknownNodes = cmds.ls( type="unknown" ) # using mel is the faatest here
235
cmds.delete( unknownNodes )
242
return make_path( cmds.file( q=1, exn=1 ) )
245
def isModified( cls ):
246
return cmds.file( q=1, amf=True )