Python API 2.0 Reference
python/api1/py1FilmMoveManip.py
1 from __future__ import division
2 #-
3 # ==========================================================================
4 # Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All
5 # rights reserved.
6 #
7 # The coded instructions, statements, computer programs, and/or related
8 # material (collectively the "Data") in these files contain unpublished
9 # information proprietary to Autodesk, Inc. ("Autodesk") and/or its
10 # licensors, which is protected by U.S. and Canadian federal copyright
11 # law and by international treaties.
12 #
13 # The Data is provided for use exclusively by You. You have the right
14 # to use, modify, and incorporate this Data into other products for
15 # purposes authorized by the Autodesk software license agreement,
16 # without fee.
17 #
18 # The copyright notices in the Software and this entire statement,
19 # including the above license grant, this restriction and the
20 # following disclaimer, must be included in all copies of the
21 # Software, in whole or in part, and all derivative works of
22 # the Software, unless such copies or derivative works are solely
23 # in the form of machine-executable object code generated by a
24 # source language processor.
25 #
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
27 # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
28 # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
29 # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
30 # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
31 # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
32 # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
33 # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
34 # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
35 # OR PROBABILITY OF SUCH DAMAGES.
36 #
37 # ==========================================================================
38 #+
39 
40 #
41 # filmMoveManip.py
42 # Scripted plug-in that displays a manipulator that
43 # modifies the film translate horizontal and vertical
44 # values.
45 #
46 # To use this plug-in:
47 # 1. execute the following Python:
48 # import maya
49 # maya.cmds.loadPlugin("filmMoveManip.py")
50 # maya.cmds.spFilmMoveManipCtxCmd( 'spFilmMoveManipContext1' )
51 # maya.cmds.setParent( 'Shelf1' )
52 # maya.cmds.toolButton( 'spFilmMoveManip1', cl='toolCluster', t='spFilmMoveManipContext1', i1="filmMoveManip.xpm" )
53 # 2. Open the outliner and select a camera shape such as perspShape
54 # 3. A manipulator with a horizontal and vertical axis will be displayed.
55 # 4. Move the axis to modify the film translate
56 #
57 # A keyframing example:
58 # This plug-in uses dependentPlugsReset() and addDependentPlugs() to
59 # make the U and V translate values keyable via the manipulator. If you
60 # comment out the calls and try to set a key (e.g. by pressing the "s"
61 # key) you will get an error that no keyable values are associated with
62 # the manipulator. To demonstrate keyframing try the following:
63 #
64 # 5. Follow steps 1-4 above
65 # 6. In the Outliner, select perspShape, topShape and frontShape
66 # 7. In the Channel Control panel, make "Film Translate H" keyable
67 # 8. Drag each of the three manips horizontally in the viewport
68 # 9. Press the "s" key to set a keyframe
69 # 10.Select the three cameraShapes individually. Each should have
70 # its Film Translate H value keyed
71 #
72 
73 from builtins import object
74 from builtins import next
75 import sys
76 import manipulatorMath
77 import maya.OpenMaya as OpenMaya
78 import maya.OpenMayaUI as OpenMayaUI
79 import maya.OpenMayaMPx as OpenMayaMPx
80 import maya.OpenMayaRender as OpenMayaRender
81 
82 filmMoveManipId = OpenMaya.MTypeId(0x8104B)
83 contextCmdName = "spFilmMoveManipCtxCmd"
84 nodeName = "spFilmMoveManip"
85 
86 # class that holds geometry points
87 class manipulatorGeometry(object):
88  scale = 3
89  def horizontalStart(self):
90  p = OpenMaya.MPoint(0,0,0) * self.scale
91  # print "hstart: %g %g %g" % (p.x,p.y,p.z)
92  return p
93  def horizontalEnd(self):
94  p = OpenMaya.MPoint(1,0,0) * self.scale
95  # print "hend:%g %g %g" % (p.x,p.y,p.z)
96  return p
97  def verticalStart(self):
98  p = OpenMaya.MPoint(0,0,0) * self.scale
99  # print "vstart:%g %g %g" % (p.x,p.y,p.z)
100  return p
101  def verticalEnd(self):
102  p = OpenMaya.MPoint(0,1,0) * self.scale
103  # print "vend: %g %g %g" % (p.x,p.y,p.z)
104  return p
105 
106 # manipulator class
107 class filmMoveManip(OpenMayaMPx.MPxManipulatorNode):
108 
109  # Value indices
110  horizontalIndex = 0
111  verticalIndex = 0
112 
113  # GL names
114  glHorizontalName = 0
115  glVerticalName = 0
116 
117  # Manipulator translation
118  translation = OpenMaya.MPoint()
119 
120  # Find the GL function table for the
121  # draw method
122  glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
123  glFT = glRenderer.glFunctionTable()
124 
125  def __init__(self):
126  OpenMayaMPx.MPxManipulatorNode.__init__(self)
127 
128  def postConstructor(self):
129  try:
130  su = OpenMaya.MScriptUtil(0)
131  iptr = su.asIntPtr()
132  self.addDoubleValue( "horizontalValue", 0, iptr )
133  self.horizontalIndex = su.getInt(iptr)
134  except:
135  sys.stderr.write("Failed to add horizontal double value\n")
136  raise
137 
138  try:
139  su = OpenMaya.MScriptUtil(0)
140  iptr = su.asIntPtr()
141  self.addDoubleValue( "verticalValue", 0, iptr )
142  self.verticalIndex = su.getInt(iptr)
143  except:
144  sys.stderr.write("Failed to add vertical double value\n")
145  raise
146 
147  def draw(self,view,dagpath,displayStyle,displayStatus):
148 
149  # get the 4 points of the manipulator
150  mo = manipulatorGeometry()
151  vs = mo.verticalStart()
152  ve = mo.verticalEnd()
153  hs = mo.horizontalStart()
154  he = mo.horizontalEnd()
155 
156  # pre
157  view.beginGL()
158  self.glFT.glPushMatrix()
159  self.glFT.glTranslated(self.translation.x,self.translation.y,self.translation.z)
160 
161  # get the first handle
162  su = OpenMaya.MScriptUtil(0)
163  iptr = su.asUintPtr()
164  self.glFirstHandle( iptr )
165  startIndex = su.getUint(iptr)
166 
167  # draw the manip
168  self.glHorizontalName = startIndex
169  self.colorAndName( view, self.glHorizontalName, True, self.mainColor() )
170  self.glFT.glBegin( OpenMayaRender.MGL_LINES )
171  self.glFT.glVertex3d( hs.x, hs.y, hs.z )
172  self.glFT.glVertex3d( he.x, he.y, he.z )
173  self.glFT.glEnd()
174 
175  self.glVerticalName = self.glHorizontalName + 1
176  self.colorAndName( view, self.glVerticalName, True, self.mainColor() )
177  self.glFT.glBegin( OpenMayaRender.MGL_LINES )
178  self.glFT.glVertex3d( vs.x, vs.y, vs.z )
179  self.glFT.glVertex3d( ve.x, ve.y, ve.z )
180  self.glFT.glEnd()
181 
182  # post
183  self.glFT.glPopMatrix()
184  view.endGL()
185 
186  def doPress(self,view):
187  self.translation = OpenMaya.MPoint()
188  self.updateDragInformation(view)
189 
190  def doDrag(self,view):
191  self.updateDragInformation(view)
192 
193  def doRelease(self,view):
194  # Only update the attribute on release
195  self.updateDragInformation(view,True)
196 
197  def getPlaneForView(self,view):
198  mo = manipulatorGeometry()
199  vs = mo.verticalStart()
200  ve = mo.verticalEnd()
201  hs = mo.horizontalStart()
202  he = mo.horizontalEnd()
203  v1 = he - hs
204  v2 = vs - ve
205  normal = v1 ^ v2
206  normal.normalize()
207 
208  plane = manipulatorMath.planeMath()
209  plane.setPlane( vs, normal )
210 
211  return plane
212 
213  def updateDragInformation(self,view,updateAttribute = False):
214  # mouse point and direction
215  localMousePoint = OpenMaya.MPoint()
216  localMouseDirection = OpenMaya.MVector()
217  self.mouseRay( localMousePoint, localMouseDirection )
218 
219  # plane that mouse will move in
220  plane = self.getPlaneForView( view )
221 
222  # intersect mouse into plane
223  mouseIntersect = OpenMaya.MPoint()
224  (worked,mouseIntersect) = plane.intersect( localMousePoint, localMouseDirection )
225  if not worked:
226  print("Failed to intersect plane")
227  return
228 
229  # restrict the point movement
230  su = OpenMaya.MScriptUtil(0)
231  uintptr = su.asUintPtr()
232  self.glActiveName( uintptr )
233  active = su.getUint(uintptr)
234 
235  mo = manipulatorGeometry()
236 
237  start = None
238  end = None
239  if active == self.glHorizontalName:
240  start = mo.horizontalStart()
241  end = mo.horizontalEnd()
242  elif active == self.glVerticalName:
243  start = mo.verticalStart()
244  end = mo.verticalEnd()
245  else:
246  raise "Unknown GL active component"
247 
248  vstart_end = start - end
249  line = manipulatorMath.lineMath()
250  line.setLine( start, vstart_end )
251 
252  closestPoint = OpenMaya.MPoint()
253  (worked,closestPoint) = line.closestPoint( mouseIntersect )
254  if not worked:
255  print("Failed to find closest point to line")
256  return
257 
258  self.translation = closestPoint
259  # print "mi: %g %g %g" % (mouseIntersect.x,mouseIntersect.y,mouseIntersect.z)
260 
261  if updateAttribute:
262  m = manipulatorMath.maxOfAbsThree(closestPoint.x,closestPoint.y,closestPoint.z)
263  m = m / 10.0 # slow down operation
264  if active == self.glHorizontalName:
265  self.setDoubleValue(self.horizontalIndex,m)
266  elif active == self.glVerticalName:
267  self.setDoubleValue(self.verticalIndex,m)
268 
269  def connectToDependNode(self, node):
270  nodeFn = OpenMaya.MFnDependencyNode(node)
271 
272  try:
273  hPlug = nodeFn.findPlug("filmTranslateH")
274  vPlug = nodeFn.findPlug("filmTranslateV")
275 
276  su = OpenMaya.MScriptUtil(0)
277  iptr = su.asIntPtr()
278  self.connectPlugToValue( hPlug, self.horizontalIndex, iptr )
279  self.connectPlugToValue( vPlug, self.verticalIndex, iptr )
280 
281  # Mark the plugs keyable.
282  self.addDependentPlug(hPlug)
283  self.addDependentPlug(vPlug)
284  except:
285  sys.stderr.write( "Error finding and connecting plugs\n" )
286  raise
287 
288  try:
289  OpenMayaMPx.MPxManipulatorNode.finishAddingManips(self)
290  OpenMayaMPx.MPxManipulatorNode.connectToDependNode(self,node)
291  except:
292  sys.stderr.write( "Error when finishing node connection\n" )
293  raise
294 
295 
296 def filmMoveManipCreator():
297  return OpenMayaMPx.asMPxPtr( filmMoveManip() )
298 
299 def filmMoveManipInitialize():
300  print("Initializing film move manipulator")
301 
302 class filmMoveManipContext(OpenMayaMPx.MPxSelectionContext):
303  def __init__(self):
304  OpenMayaMPx.MPxSelectionContext.__init__(self)
305 
306  def toolOnSetup(self,event):
307  updateManipulators(self)
308  OpenMaya.MModelMessage.addCallback(OpenMaya.MModelMessage.kActiveListModified, updateManipulators, self)
309 
310 def updateManipulators(clientData):
311  clientData.deleteManipulators()
312  selectionList = OpenMaya.MSelectionList()
313 
314  # Loop through the selection list, linking the film translate
315  # plugs on each selected camera to the manipulator.
317  selectionIter = OpenMaya.MItSelectionList(selectionList, OpenMaya.MFn.kInvalid)
318  while not selectionIter.isDone():
319  dependNode = OpenMaya.MObject()
320  selectionIter.getDependNode(dependNode)
321  if dependNode.isNull() or not dependNode.hasFn(OpenMaya.MFn.kCamera):
322  print("depend node is null or not a camera")
323  next(selectionIter)
324  continue
325 
326  dependNodeFn = OpenMaya.MFnDependencyNode(dependNode)
327  hPlug = dependNodeFn.findPlug("filmTranslateH", False)
328  vPlug = dependNodeFn.findPlug("filmTranslateV", False)
329  if hPlug.isNull() or vPlug.isNull():
330  print("One of filmTranslate H,V plugs are null")
331  next(selectionIter)
332  continue
333 
334  manipObject = OpenMaya.MObject()
335  manipulator = OpenMayaMPx.MPxManipulatorNode.newManipulator(nodeName, manipObject)
336  if manipulator is not None:
337  # Clear the list of keyable plugs.
338  manipulator.dependentPlugsReset()
339 
340  clientData.addManipulator(manipObject)
341  manipulator.connectToDependNode(dependNode)
342  next(selectionIter)
343 
344 
345 class filmMoveManipCtxCmd(OpenMayaMPx.MPxContextCommand):
346  def __init__(self):
347  OpenMayaMPx.MPxContextCommand.__init__(self)
348 
349  def makeObj(self):
350  return OpenMayaMPx.asMPxPtr( filmMoveManipContext() )
351 
352 
353 def contextCmdCreator():
354  return OpenMayaMPx.asMPxPtr( filmMoveManipCtxCmd() )
355 
356 
357 # initialize the script plug-in
358 def initializePlugin(mobject):
359  mplugin = OpenMayaMPx.MFnPlugin(mobject)
360 
361  try:
362  mplugin.registerContextCommand( contextCmdName, contextCmdCreator )
363  except:
364  print("Failed to register context command: %s" % contextCmdName)
365  raise
366 
367  try:
368  mplugin.registerNode(nodeName, filmMoveManipId, filmMoveManipCreator, filmMoveManipInitialize, OpenMayaMPx.MPxNode.kManipulatorNode)
369  except:
370  print("Failed to register node: %s" % nodeName)
371  raise
372 
373 # uninitialize the script plug-in
374 def uninitializePlugin(mobject):
375  mplugin = OpenMayaMPx.MFnPlugin(mobject)
376  try:
377  mplugin.deregisterContextCommand(contextCmdName)
378  except:
379  print("Failed to deregister context command: %s" % contextCmdName)
380  raise
381 
382  try:
383  mplugin.deregisterNode(filmMoveManipId)
384  except:
385  print("Failed to deregister node: %s" % nodeName)
386  raise