1 from __future__
import division
74 from builtins
import object
75 from builtins
import range
76 import maya.OpenMaya
as OpenMaya
77 import maya.OpenMayaMPx
as OpenMayaMPx
78 import maya.OpenMayaRender
as OpenMayaRender
79 import maya.OpenMayaUI
as OpenMayaUI
84 kPluginNodeTypeName =
"spInstanceShape"
87 glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
88 glFT = glRenderer.glFunctionTable()
92 kActiveAffectedColor = 8
104 class instanceGeom(object):
106 self.radius = kDefaultRadius
107 self.count = kDefaultCount
108 self.instanceShape =
None
109 self.drawQueueList = []
115 class instanceShape(OpenMayaMPx.MPxSurfaceShape):
122 OpenMayaMPx.MPxSurfaceShape.__init__(self)
125 self.__myGeometry = instanceGeom()
128 def postConstructor(self):
130 When instances of this node are created internally, the
131 MObject associated with the instance is not created until
132 after the constructor of this class is called. This means
133 that no member functions of MPxSurfaceShape can be called in
134 the constructor. The postConstructor solves this
135 problem. Maya will call this function after the internal
136 object has been created. As a general rule do all of your
137 initialization in the postConstructor.
139 self.setRenderable(
True)
142 def getInternalValue(self, plug, datahandle):
144 Handle internal attributes.
145 In order to impose limits on our attribute values we
146 mark them internal and use the values in fGeometry instead.
148 if (plug == instanceShape.aRadius):
149 datahandle.setDouble(self.__myGeometry.radius)
150 elif (plug == instanceShape.aCount):
151 datahandle.setInt(self.__myGeometry.count)
153 return OpenMayaMPx.MPxSurfaceShape.getInternalValue(self, plug, datahandle)
159 def setInternalValue(self, plug, datahandle):
161 Handle internal attributes.
162 In order to impose limits on our attribute values we
163 mark them internal and use the values in fGeometry instead.
168 if (plug == instanceShape.aRadius):
169 radius = datahandle.asDouble()
174 self.__myGeometry.radius = radius
176 elif (plug == instanceShape.aCount):
177 count = datahandle.asInt()
180 self.__myGeometry.count = count
182 return OpenMayaMPx.MPxSurfaceShape.setInternalValue(self, plug, datahandle)
192 def boundingBox(self):
194 Returns the bounding box for the shape.
195 In this case just use the radius and height attributes
196 to determine the bounding box.
200 geom = self.geometry()
203 if geom.instanceShape:
205 result = fnDag.boundingBox()
209 for c
in range( geom.count ):
210 percent = float(c)/float(geom.count)
211 rad = 2*math.pi * percent
212 p = (r*math.cos(rad), r*math.sin(rad),0.0)
216 trans.setTranslation( vec, OpenMaya.MSpace.kTransform )
217 mmatrix = trans.asMatrix();
218 newbbox.transformUsing( mmatrix )
219 result.expand( newbbox )
226 This function gets the values of all the attributes and
227 assigns them to the fGeometry. Calling MPlug::getValue
228 will ensure that the values are up-to-date.
232 this_object = self.thisMObject()
235 self.__myGeometry.radius = plug.asDouble()
237 self.__myGeometry.count = plug.asInt()
241 plug.connectedTo( plugArray,
True,
False )
242 if ( plugArray.length() > 0 ):
243 node = plugArray[0].node()
246 dagNode.getPath(path)
247 self.__myGeometry.instanceShape = path
249 return self.__myGeometry
255 class instanceShapeUI(OpenMayaMPx.MPxSurfaceShapeUI):
258 OpenMayaMPx.MPxSurfaceShapeUI.__init__(self)
261 def getDrawRequests(self, info, objectAndActiveOnly, queue):
263 The draw data is used to pass geometry through the
264 draw queue. The data should hold all the information
265 needed to draw the shape.
274 request = info.getPrototype(self)
275 shapeNode = self.surfaceShape()
276 path = info.multiPath()
281 geom = shapeNode.geometry()
284 if request.displayStyle() == OpenMayaUI.M3dView.kGouraudShaded:
287 if geom.instanceShape:
290 shapeUI = OpenMayaMPx.MPxSurfaceShapeUI.surfaceShapeUI(geom.instanceShape)
292 mainMaterial = shapeUI.material( geom.instanceShape )
293 mainMaterial.evaluateMaterial( view, geom.instanceShape )
295 for a
in range(geom.count):
296 myQueue = OpenMayaUI.MDrawRequestQueue()
297 percent = float(a)/float(geom.count)
298 rad = 2*math.pi * percent
299 position = (r*math.cos(rad), r*math.sin(rad),0.0)
307 myinfo.setMultiPath( geom.instanceShape )
308 shapeUI.getDrawRequests( myinfo,
309 objectAndActiveOnly, myQueue )
310 geom.drawQueueList.append( (myQueue, position) )
312 info.setMultiPath( path )
320 mainMaterial = defaultMaterial
322 request.setMaterial( mainMaterial )
324 request.setMaterial( defaultMaterial )
327 self.getDrawData(geom, data)
328 request.setDrawData(data)
334 def draw(self, request, view):
336 From the given draw request, get the draw data and determine
337 which basic shape to draw and with what values.
340 data = request.drawData()
341 shapeNode = self.surfaceShape()
343 glFT.glMatrixMode( OpenMayaRender.MGL_MODELVIEW )
344 if geom.instanceShape:
345 shapeUI = OpenMayaMPx.MPxSurfaceShapeUI.surfaceShapeUI(geom.instanceShape)
346 for (queue, pos)
in geom.drawQueueList:
348 glFT.glTranslatef( pos[0], pos[1], pos[2] )
349 while not queue.isEmpty():
350 request = queue.remove()
351 shapeUI.draw( request, view )
358 glFT.glPushAttrib( OpenMayaRender.MGL_ALL_ATTRIB_BITS )
359 glFT.glPolygonMode(OpenMayaRender.MGL_FRONT_AND_BACK,
360 OpenMayaRender.MGL_LINE)
361 glFT.glBegin(OpenMayaRender.MGL_QUADS)
362 glFT.glVertex3f(-1*(geom.radius), -1*(geom.radius), 0.0)
363 glFT.glNormal3f(0, 0, 1.0)
365 glFT.glVertex3f(-1*(geom.radius), (geom.radius), 0.0)
366 glFT.glNormal3f(0, 0, 1.0)
368 glFT.glVertex3f((geom.radius), (geom.radius), 0.0)
369 glFT.glNormal3f(0, 0, 1.0)
371 glFT.glVertex3f((geom.radius), -1*(geom.radius), 0.0)
372 glFT.glNormal3f(0, 0, 1.0)
377 def select(self, selectInfo, selectionList, worldSpaceSelectPts):
379 Select function. Gets called when the bbox for the object is
380 selected. This function just selects the object without
381 doing any intersection tests.
386 item.add(selectInfo.selectPath())
388 selectInfo.addSelection(item, xformedPt, selectionList,
389 worldSpaceSelectPts, priorityMask,
False)
398 return OpenMayaMPx.asMPxPtr( instanceShape() )
402 return OpenMayaMPx.asMPxPtr( instanceShapeUI() )
405 def nodeInitializer():
407 def setOptions(attr):
408 attr.setHidden(
False)
409 attr.setKeyable(
True)
410 attr.setInternal(
True)
415 instanceShape.aInstanceShape = messageAttr.create(
"instanceShape",
"is")
416 instanceShape.addAttribute(instanceShape.aInstanceShape)
418 instanceShape.aRadius = numericAttr.create(
"radius",
"r", OpenMaya.MFnNumericData.kDouble, kDefaultRadius)
419 setOptions(numericAttr)
420 instanceShape.addAttribute(instanceShape.aRadius)
422 instanceShape.aCount = numericAttr.create("count",
"ct", OpenMaya.MFnNumericData.kInt, kDefaultCount)
423 setOptions(numericAttr)
424 instanceShape.addAttribute(instanceShape.aCount)
427 def initializePlugin(mobject):
428 mplugin = OpenMayaMPx.MFnPlugin(mobject,
"Autodesk",
"2011",
"Any")
430 mplugin.registerShape( kPluginNodeTypeName, spInstanceShapeNodeId,
431 nodeCreator, nodeInitializer, uiCreator )
433 sys.stderr.write(
"Failed to register node: %s" % kPluginNodeTypeName )
438 def uninitializePlugin(mobject):
439 mplugin = OpenMayaMPx.MFnPlugin(mobject)
441 mplugin.deregisterNode( spInstanceShapeNodeId )
443 sys.stderr.write(
"Failed to deregister node: %s" % kPluginNodeTypeName )