Python API 2.0 Reference
python/api2/py2FootPrintNode.py
1 #-
2 # ===========================================================================
3 # Copyright 2015 Autodesk, Inc. All rights reserved.
4 #
5 # Use of this software is subject to the terms of the Autodesk license
6 # agreement provided at the time of installation or download, or which
7 # otherwise accompanies this software in either electronic or hard copy form.
8 # ===========================================================================
9 #+
10 
11 ########################################################################
12 # DESCRIPTION:
13 #
14 # Produces the dependency graph node "footPrint_py".
15 #
16 # This example demonstrates how to create a user-defined locator. A locator
17 # is a DAG object that is drawn in 3D views, but does not render.
18 # This example plug-in defines a new locator node that draws a foot print.
19 # The foot print can be selected and moved using the regular manipulators.
20 #
21 # To use, load the plug-in and execute:
22 #
23 # maya.cmds.createNode('footPrint_py')
24 #
25 ########################################################################
26 
27 from builtins import range
28 import sys
29 import maya.api.OpenMaya as om
30 import maya.api.OpenMayaUI as omui
31 import maya.api.OpenMayaAnim as oma
32 import maya.api.OpenMayaRender as omr
33 import maya.cmds as cmds
34 
35 def maya_useNewAPI():
36  """
37  The presence of this function tells Maya that the plugin produces, and
38  expects to be passed, objects created using the Maya Python API 2.0.
39  """
40  pass
41 
42 def matrixAsArray(matrix):
43  array = []
44  for i in range(16):
45  array.append(matrix[i])
46  return array
47 
48 ## Foot Data
49 ##
50 sole = [ [ 0.00, 0.0, -0.70 ],
51  [ 0.04, 0.0, -0.69 ],
52  [ 0.09, 0.0, -0.65 ],
53  [ 0.13, 0.0, -0.61 ],
54  [ 0.16, 0.0, -0.54 ],
55  [ 0.17, 0.0, -0.46 ],
56  [ 0.17, 0.0, -0.35 ],
57  [ 0.16, 0.0, -0.25 ],
58  [ 0.15, 0.0, -0.14 ],
59  [ 0.13, 0.0, 0.00 ],
60  [ 0.00, 0.0, 0.00 ],
61  [ -0.13, 0.0, 0.00 ],
62  [ -0.15, 0.0, -0.14 ],
63  [ -0.16, 0.0, -0.25 ],
64  [ -0.17, 0.0, -0.35 ],
65  [ -0.17, 0.0, -0.46 ],
66  [ -0.16, 0.0, -0.54 ],
67  [ -0.13, 0.0, -0.61 ],
68  [ -0.09, 0.0, -0.65 ],
69  [ -0.04, 0.0, -0.69 ],
70  [ -0.00, 0.0, -0.70 ] ]
71 heel = [ [ 0.00, 0.0, 0.06 ],
72  [ 0.13, 0.0, 0.06 ],
73  [ 0.14, 0.0, 0.15 ],
74  [ 0.14, 0.0, 0.21 ],
75  [ 0.13, 0.0, 0.25 ],
76  [ 0.11, 0.0, 0.28 ],
77  [ 0.09, 0.0, 0.29 ],
78  [ 0.04, 0.0, 0.30 ],
79  [ 0.00, 0.0, 0.30 ],
80  [ -0.04, 0.0, 0.30 ],
81  [ -0.09, 0.0, 0.29 ],
82  [ -0.11, 0.0, 0.28 ],
83  [ -0.13, 0.0, 0.25 ],
84  [ -0.14, 0.0, 0.21 ],
85  [ -0.14, 0.0, 0.15 ],
86  [ -0.13, 0.0, 0.06 ],
87  [ -0.00, 0.0, 0.06 ] ]
88 soleCount = 21
89 heelCount = 17
90 
91 
92 #############################################################################
93 ##
94 ## Node implementation with standard viewport draw
95 ##
96 #############################################################################
97 class footPrint(omui.MPxLocatorNode):
98  id = om.MTypeId( 0x00080067 )
99  drawDbClassification = "drawdb/geometry/footPrint_py"
100  drawRegistrantId = "FootprintNodePlugin_py"
101 
102  size = None ## The size of the foot
103 
104  @staticmethod
105  def creator():
106  return footPrint()
107 
108  @staticmethod
109  def initialize():
110  unitFn = om.MFnUnitAttribute()
111 
112  footPrint.size = unitFn.create( "size", "sz", om.MFnUnitAttribute.kDistance )
113  unitFn.default = om.MDistance(1.0)
114 
115  om.MPxNode.addAttribute( footPrint.size )
116 
117  def __init__(self):
118  omui.MPxLocatorNode.__init__(self)
119 
120  def compute(self, plug, data):
121  return None
122 
123  def draw(self, view, path, style, status):
124  ## Get the size
125  ##
126  thisNode = self.thisMObject()
127  plug = om.MPlug( thisNode, footPrint.size )
128  sizeVal = plug.asMDistance()
129  multiplier = sizeVal.asCentimeters()
130 
131  global sole, soleCount
132  global heel, heelCount
133 
134  view.beginGL()
135 
136  ## drawing in VP1 views will be done using V1 Python APIs:
137  import maya.OpenMayaRender as v1omr
138  glRenderer = v1omr.MHardwareRenderer.theRenderer()
139  glFT = glRenderer.glFunctionTable()
140 
141  if ( style == omui.M3dView.kFlatShaded ) or ( style == omui.M3dView.kGouraudShaded ):
142  ## Push the color settings
143  ##
144  glFT.glPushAttrib( v1omr.MGL_CURRENT_BIT )
145 
146  # Show both faces
147  glFT.glDisable( v1omr.MGL_CULL_FACE )
148 
149  if status == omui.M3dView.kActive:
150  view.setDrawColor( 13, omui.M3dView.kActiveColors )
151  else:
152  view.setDrawColor( 13, omui.M3dView.kDormantColors )
153 
154  glFT.glBegin( v1omr.MGL_TRIANGLE_FAN )
155  for i in range(soleCount-1):
156  glFT.glVertex3f( sole[i][0] * multiplier, sole[i][1] * multiplier, sole[i][2] * multiplier )
157  glFT.glEnd()
158 
159  glFT.glBegin( v1omr.MGL_TRIANGLE_FAN )
160  for i in range(heelCount-1):
161  glFT.glVertex3f( heel[i][0] * multiplier, heel[i][1] * multiplier, heel[i][2] * multiplier )
162  glFT.glEnd()
163 
164  glFT.glPopAttrib()
165 
166  ## Draw the outline of the foot
167  ##
168  glFT.glBegin( v1omr.MGL_LINES )
169  for i in range(soleCount-1):
170  glFT.glVertex3f( sole[i][0] * multiplier, sole[i][1] * multiplier, sole[i][2] * multiplier )
171  glFT.glVertex3f( sole[i+1][0] * multiplier, sole[i+1][1] * multiplier, sole[i+1][2] * multiplier )
172 
173  for i in range(heelCount-1):
174  glFT.glVertex3f( heel[i][0] * multiplier, heel[i][1] * multiplier, heel[i][2] * multiplier )
175  glFT.glVertex3f( heel[i+1][0] * multiplier, heel[i+1][1] * multiplier, heel[i+1][2] * multiplier )
176  glFT.glEnd()
177 
178  view.endGL()
179 
180  ## Draw the name of the footPrint
181  view.setDrawColor( om.MColor( (0.1, 0.8, 0.8, 1.0) ) )
182  view.drawText( "Footprint", om.MPoint( 0.0, 0.0, 0.0 ), omui.M3dView.kCenter )
183 
184  def isBounded(self):
185  return True
186 
187  def boundingBox(self):
188  ## Get the size
189  ##
190  thisNode = self.thisMObject()
191  plug = om.MPlug( thisNode, footPrint.size )
192  sizeVal = plug.asMDistance()
193  multiplier = sizeVal.asCentimeters()
194 
195  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
196  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
197 
198  corner1 *= multiplier
199  corner2 *= multiplier
200 
201  return om.MBoundingBox( corner1, corner2 )
202 
203 #############################################################################
204 ##
205 ## Viewport 2.0 override implementation
206 ##
207 #############################################################################
208 class footPrintData(om.MUserData):
209  def __init__(self):
210  om.MUserData.__init__(self, False) ## don't delete after draw
211 
212  self.fColor = om.MColor()
213  self.fLineList = om.MPointArray()
214  self.fTriangleList = om.MPointArray()
215 
216 class footPrintDrawOverride(omr.MPxDrawOverride):
217  @staticmethod
218  def creator(obj):
219  return footPrintDrawOverride(obj)
220 
221  ## By setting isAlwaysDirty to false in MPxDrawOverride constructor, the
222  ## draw override will be updated (via prepareForDraw()) only when the node
223  ## is marked dirty via DG evaluation or dirty propagation. Additional
224  ## callback is also added to explicitly mark the node as being dirty (via
225  ## MRenderer::setGeometryDrawDirty()) for certain circumstances.
226  def __init__(self, obj):
227  omr.MPxDrawOverride.__init__(self, obj, None, False)
228 
229  ## We want to perform custom bounding box drawing
230  ## so return True so that the internal rendering code
231  ## will not draw it for us.
232  self.mCustomBoxDraw = True
233  self.mCurrentBoundingBox = om.MBoundingBox()
234 
235  def supportedDrawAPIs(self):
236  ## this plugin supports both GL and DX
237  return omr.MRenderer.kOpenGL | omr.MRenderer.kDirectX11 | omr.MRenderer.kOpenGLCoreProfile
238 
239  def isBounded(self, objPath, cameraPath):
240  return True
241 
242  def boundingBox(self, objPath, cameraPath):
243  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
244  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
245 
246  multiplier = self.getMultiplier(objPath)
247  corner1 *= multiplier
248  corner2 *= multiplier
249 
250  self.mCurrentBoundingBox.clear()
251  self.mCurrentBoundingBox.expand( corner1 )
252  self.mCurrentBoundingBox.expand( corner2 )
253 
254  return self.mCurrentBoundingBox
255 
256  def disableInternalBoundingBoxDraw(self):
257  return self.mCustomBoxDraw
258 
259  def prepareForDraw(self, objPath, cameraPath, frameContext, oldData):
260  ## Retrieve data cache (create if does not exist)
261  data = oldData
262  if not isinstance(data, footPrintData):
263  data = footPrintData()
264 
265  ## compute data and cache it
266  global soleCount, sole
267  global heelCount, heel
268 
269  fMultiplier = self.getMultiplier(objPath)
270 
271  data.fLineList.clear()
272 
273  for i in range(soleCount-1):
274  data.fLineList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
275  data.fLineList.append( om.MPoint(sole[i+1][0] * fMultiplier, sole[i+1][1] * fMultiplier, sole[i+1][2] * fMultiplier) )
276 
277  for i in range(heelCount-1):
278  data.fLineList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
279  data.fLineList.append( om.MPoint(heel[i+1][0] * fMultiplier, heel[i+1][1] * fMultiplier, heel[i+1][2] * fMultiplier) )
280 
281  data.fTriangleList.clear()
282 
283  for i in range(1,soleCount-1):
284  data.fTriangleList.append( om.MPoint(sole[0][0] * fMultiplier, sole[0][1] * fMultiplier, sole[0][2] * fMultiplier) )
285  data.fTriangleList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
286  data.fTriangleList.append( om.MPoint(sole[i+1][0] * fMultiplier, sole[i+1][1] * fMultiplier, sole[i+1][2] * fMultiplier) )
287 
288  for i in range(1,heelCount-1):
289  data.fTriangleList.append( om.MPoint(heel[0][0] * fMultiplier, heel[0][1] * fMultiplier, heel[0][2] * fMultiplier) )
290  data.fTriangleList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
291  data.fTriangleList.append( om.MPoint(heel[i+1][0] * fMultiplier, heel[i+1][1] * fMultiplier, heel[i+1][2] * fMultiplier) )
292 
293  data.fColor = omr.MGeometryUtilities.wireframeColor(objPath)
294 
295  return data
296 
297  def hasUIDrawables(self):
298  return True
299 
300  def addUIDrawables(self, objPath, drawManager, frameContext, data):
301  locatordata = data
302  if not isinstance(locatordata, footPrintData):
303  return
304 
305  drawManager.beginDrawable()
306 
307  ##Draw the foot print solid/wireframe
308  drawManager.setColor( locatordata.fColor )
309  drawManager.setDepthPriority(5)
310 
311  if (frameContext.getDisplayStyle() & omr.MFrameContext.kGouraudShaded):
312  drawManager.mesh(omr.MGeometry.kTriangles, locatordata.fTriangleList)
313 
314  drawManager.mesh(omr.MUIDrawManager.kLines, locatordata.fLineList)
315 
316  ## Draw a text "Foot"
317  pos = om.MPoint( 0.0, 0.0, 0.0 ) ## Position of the text
318  textColor = om.MColor( (0.1, 0.8, 0.8, 1.0) ) ## Text color
319 
320  drawManager.setColor( textColor )
321  drawManager.setFontSize( omr.MUIDrawManager.kSmallFontSize )
322  drawManager.text(pos, "Footprint", omr.MUIDrawManager.kCenter )
323 
324  drawManager.endDrawable()
325 
326  def getMultiplier(self, objPath):
327  ## Retrieve value of the size attribute from the node
328  footprintNode = objPath.node()
329  plug = om.MPlug(footprintNode, footPrint.size)
330  if not plug.isNull:
331  sizeVal = plug.asMDistance()
332  return sizeVal.asCentimeters()
333 
334  return 1.0
335 
336 def initializePlugin(obj):
337  plugin = om.MFnPlugin(obj, "Autodesk", "3.0", "Any")
338 
339  try:
340  plugin.registerNode("footPrint_py", footPrint.id, footPrint.creator, footPrint.initialize, om.MPxNode.kLocatorNode, footPrint.drawDbClassification)
341  except:
342  sys.stderr.write("Failed to register node\n")
343  raise
344 
345  try:
346  cmds.pluginDisplayFilter("footPrintFilter_py", register=True, label="Footprint (Python)", classification=footPrint.drawDbClassification)
347  except:
348  sys.stderr.write("Failed to register displayFilter\n")
349  raise
350 
351  try:
352  omr.MDrawRegistry.registerDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId, footPrintDrawOverride.creator)
353  except:
354  sys.stderr.write("Failed to register override\n")
355  raise
356 
357 def uninitializePlugin(obj):
358  plugin = om.MFnPlugin(obj)
359 
360  try:
361  plugin.deregisterNode(footPrint.id)
362  except:
363  sys.stderr.write("Failed to deregister node\n")
364  pass
365 
366  try:
367  cmds.pluginDisplayFilter("footPrintFilter_py", deregister=True)
368  except:
369  sys.stderr.write("Failed to deregister displayFilter\n")
370  pass
371 
372  try:
373  omr.MDrawRegistry.deregisterDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId)
374  except:
375  sys.stderr.write("Failed to deregister override\n")
376  pass
377