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