1
2 """
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.
6 """
7 __docformat__ = "restructuredtext"
8
9 import util as mutil
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
14
15 import inspect
16
17 __all__ = [ 'Scene' ]
21 """ Implements Scene Callbacks"""
22
23 _checkCBSet = set( ( api.MSceneMessage.kBeforeNewCheck,
24 api.MSceneMessage.kBeforeSaveCheck ) )
25
26 _checkFileCBSet = set( ( api.MSceneMessage.kBeforeImportCheck,
27 api.MSceneMessage.kBeforeOpenCheck,
28 api.MSceneMessage.kBeforeExportCheck,
29 api.MSceneMessage.kBeforeReferenceCheck,
30 api.MSceneMessage.kBeforeLoadReferenceCheck ) )
31
32
33 use_weakref = False
34 remove_on_error = True
35
36 weakref_sender = True
37
38
39
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
47 return reg_method
48
49
50
51
52
53 -class Scene( util.Singleton, util.EventSender ):
54 """Singleton Class allowing access to the maya scene
55
56 You can register all events available in MSceneMessage easily usnig the following
57 syntax:
58
59 >>> scene.beforeSoftwareRender = myFunctionObject
60
61 """
62
63
64 kFileTypeMap = { "" : "mayaAscii",
65 ".ma" : "mayaAscii",
66 ".mb" : "mayaBinary" }
67
68
69 sender_as_argument = False
70
71
72
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
76
77
78
79
80
81
82 @classmethod
83 - def open( cls, scenepath=None, force=False, **kwargs ):
84 """ Open the scene at the given scenepath
85
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"""
92 if not scenepath:
93 scenepath = cls.name()
94
95
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 )
101
102 @classmethod
103 - def new( cls, force = False, **kwargs ):
104 """ Create a new scene
105
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 ) )
113
114 @classmethod
115 - def rename( cls, scenepath ):
116 """Rename the currently loaded file to be the file at scenepath
117
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)
123 try:
124 cmds.file( rename = scenepath.expandvars() )
125 cmds.file( type = cls.kFileTypeMap[ scenepath.ext() ] )
126 except KeyError:
127 raise RuntimeError( "Unsupported filetype of: " + scenepath )
128
129
130 return scenepath
131
132 @classmethod
133 - def save( cls, scenepath=None, autodeleteUnknown = False, **kwargs ):
134 """Save the currently opened scene under scenepath in the respective format
135
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( )
144
145 scenepath = make_path( scenepath )
146 curscene = cls.name()
147 try :
148 filetype = cls.kFileTypeMap[ scenepath.ext() ]
149 curscenetype = cls.kFileTypeMap[ curscene.ext() ]
150 except KeyError:
151 raise RuntimeError( "Unsupported filetype of: " + scenepath )
152
153
154 if curscene != scenepath:
155 cls.rename(scenepath)
156
157
158 parentdir = scenepath.dirname( )
159 if not parentdir.exists( ):
160 parentdir.makedirs( )
161
162
163
164 if autodeleteUnknown and curscenetype != filetype:
165 cls.deleteUnknownNodes()
166
167
168
169 kwargs.pop('save', kwargs.pop('s', None))
170 kwargs.pop('type', kwargs.pop('typ', None))
171 try:
172 return make_path( cmds.file( save=True, type=filetype, **kwargs ) )
173 except RuntimeError:
174 if curscene != cls.name():
175 cls.rename(curscene)
176
177 raise
178
179
180 @classmethod
181 - def export(cls, outputFile, nodeListOrIterable=None, **kwargs):
182 """Export the given nodes or everything into the file at path
183
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
195
196 prev_selection = None
197 if nodeListOrIterable is None:
198 kwargs['exportAll'] = True
199 else:
200
201 kwargs['exportSelected'] = True
202 prev_selection = api.MSelectionList()
203 api.MGlobal.getActiveSelectionList(prev_selection)
204
205 import nt
206 nt.select(nt.toSelectionList(nodeListOrIterable))
207
208
209 typ = kwargs.pop('type', kwargs.pop('typ', cls.kFileTypeMap.get(outputFile.ext(), None)))
210 if typ is None:
211 raise RuntimeError("Invalid type in %s" % outputFile)
212
213
214 try:
215 cmds.file(outputFile, type=typ, **kwargs)
216 return outputFile
217 finally:
218 if prev_selection is not None:
219 api.MGlobal.setActiveSelectionList(prev_selection)
220
221
222
223
224
225
226 @classmethod
228 """Deletes all unknown nodes in the scene
229
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
232 in the scene"""
233 unknownNodes = cmds.ls( type="unknown" )
234 if unknownNodes:
235 cmds.delete( unknownNodes )
236
237
238
239
240 @classmethod
242 return make_path( cmds.file( q=1, exn=1 ) )
243
244 @classmethod
246 return cmds.file( q=1, amf=True )
247
248
249
250
251