73 import maya.OpenMaya
as OpenMaya
74 import maya.OpenMayaMPx
as OpenMayaMPx
75 import maya.OpenMayaRender
as OpenMayaRender
76 import maya.OpenMayaUI
as OpenMayaUI
81 kPluginNodeTypeName =
"spInstanceShape"
84 glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
85 glFT = glRenderer.glFunctionTable()
89 kActiveAffectedColor = 8
103 self.radius = kDefaultRadius
104 self.count = kDefaultCount
105 self.instanceShape =
None
106 self.drawQueueList = []
112 class instanceShape(OpenMayaMPx.MPxSurfaceShape):
119 OpenMayaMPx.MPxSurfaceShape.__init__(self)
122 self.__myGeometry = instanceGeom()
125 def postConstructor(self):
127 When instances of this node are created internally, the
128 MObject associated with the instance is not created until
129 after the constructor of this class is called. This means
130 that no member functions of MPxSurfaceShape can be called in
131 the constructor. The postConstructor solves this
132 problem. Maya will call this function after the internal
133 object has been created. As a general rule do all of your
134 initialization in the postConstructor.
136 self.setRenderable(
True)
139 def getInternalValue(self, plug, datahandle):
141 Handle internal attributes.
142 In order to impose limits on our attribute values we
143 mark them internal and use the values in fGeometry instead.
145 if (plug == instanceShape.aRadius):
146 datahandle.setDouble(self.__myGeometry.radius)
147 elif (plug == instanceShape.aCount):
148 datahandle.setInt(self.__myGeometry.count)
150 return OpenMayaMPx.MPxSurfaceShape.getInternalValue(self, plug, datahandle)
156 def setInternalValue(self, plug, datahandle):
158 Handle internal attributes.
159 In order to impose limits on our attribute values we
160 mark them internal and use the values in fGeometry instead.
165 if (plug == instanceShape.aRadius):
166 radius = datahandle.asDouble()
171 self.__myGeometry.radius = radius
173 elif (plug == instanceShape.aCount):
174 count = datahandle.asInt()
177 self.__myGeometry.count = count
179 return OpenMayaMPx.MPxSurfaceShape.setInternalValue(self, plug, datahandle)
189 def boundingBox(self):
191 Returns the bounding box for the shape.
192 In this case just use the radius and height attributes
193 to determine the bounding box.
197 geom = self.geometry()
200 if geom.instanceShape:
202 result = fnDag.boundingBox()
206 for c
in range( geom.count ):
207 percent = float(c)/float(geom.count)
208 rad = 2*math.pi * percent
209 p = (r*math.cos(rad), r*math.sin(rad),0.0)
213 trans.setTranslation( vec, OpenMaya.MSpace.kTransform )
214 mmatrix = trans.asMatrix();
215 newbbox.transformUsing( mmatrix )
216 result.expand( newbbox )
223 This function gets the values of all the attributes and
224 assigns them to the fGeometry. Calling MPlug::getValue
225 will ensure that the values are up-to-date.
229 this_object = self.thisMObject()
232 self.__myGeometry.radius = plug.asDouble()
234 self.__myGeometry.count = plug.asInt()
238 plug.connectedTo( plugArray,
True,
False )
239 if ( plugArray.length() > 0 ):
240 node = plugArray[0].node()
243 dagNode.getPath(path)
244 self.__myGeometry.instanceShape = path
246 return self.__myGeometry
252 class instanceShapeUI(OpenMayaMPx.MPxSurfaceShapeUI):
255 OpenMayaMPx.MPxSurfaceShapeUI.__init__(self)
258 def getDrawRequests(self, info, objectAndActiveOnly, queue):
260 The draw data is used to pass geometry through the
261 draw queue. The data should hold all the information
262 needed to draw the shape.
271 request = info.getPrototype(self)
272 shapeNode = self.surfaceShape()
273 path = info.multiPath()
278 geom = shapeNode.geometry()
281 if request.displayStyle() == OpenMayaUI.M3dView.kGouraudShaded:
284 if geom.instanceShape:
287 shapeUI = OpenMayaMPx.MPxSurfaceShapeUI.surfaceShapeUI(geom.instanceShape)
289 mainMaterial = shapeUI.material( geom.instanceShape )
290 mainMaterial.evaluateMaterial( view, geom.instanceShape )
292 for a
in range(geom.count):
293 myQueue = OpenMayaUI.MDrawRequestQueue()
294 percent = float(a)/float(geom.count)
295 rad = 2*math.pi * percent
296 position = (r*math.cos(rad), r*math.sin(rad),0.0)
304 myinfo.setMultiPath( geom.instanceShape )
305 shapeUI.getDrawRequests( myinfo,
306 objectAndActiveOnly, myQueue )
307 geom.drawQueueList.append( (myQueue, position) )
309 info.setMultiPath( path )
317 mainMaterial = defaultMaterial
319 request.setMaterial( mainMaterial )
321 request.setMaterial( defaultMaterial )
324 self.getDrawData(geom, data)
325 request.setDrawData(data)
331 def draw(self, request, view):
333 From the given draw request, get the draw data and determine
334 which basic shape to draw and with what values.
337 data = request.drawData()
338 shapeNode = self.surfaceShape()
340 glFT.glMatrixMode( OpenMayaRender.MGL_MODELVIEW )
341 if geom.instanceShape:
342 shapeUI = OpenMayaMPx.MPxSurfaceShapeUI.surfaceShapeUI(geom.instanceShape)
343 for (queue, pos)
in geom.drawQueueList:
345 glFT.glTranslatef( pos[0], pos[1], pos[2] )
346 while not queue.isEmpty():
347 request = queue.remove()
348 shapeUI.draw( request, view )
355 glFT.glPushAttrib( OpenMayaRender.MGL_ALL_ATTRIB_BITS )
356 glFT.glPolygonMode(OpenMayaRender.MGL_FRONT_AND_BACK,
357 OpenMayaRender.MGL_LINE)
358 glFT.glBegin(OpenMayaRender.MGL_QUADS)
359 glFT.glVertex3f(-1*(geom.radius), -1*(geom.radius), 0.0)
360 glFT.glNormal3f(0, 0, 1.0)
362 glFT.glVertex3f(-1*(geom.radius), (geom.radius), 0.0)
363 glFT.glNormal3f(0, 0, 1.0)
365 glFT.glVertex3f((geom.radius), (geom.radius), 0.0)
366 glFT.glNormal3f(0, 0, 1.0)
368 glFT.glVertex3f((geom.radius), -1*(geom.radius), 0.0)
369 glFT.glNormal3f(0, 0, 1.0)
374 def select(self, selectInfo, selectionList, worldSpaceSelectPts):
376 Select function. Gets called when the bbox for the object is
377 selected. This function just selects the object without
378 doing any intersection tests.
383 item.add(selectInfo.selectPath())
385 selectInfo.addSelection(item, xformedPt, selectionList,
386 worldSpaceSelectPts, priorityMask,
False)
395 return OpenMayaMPx.asMPxPtr( instanceShape() )
399 return OpenMayaMPx.asMPxPtr( instanceShapeUI() )
402 def nodeInitializer():
404 def setOptions(attr):
405 attr.setHidden(
False)
406 attr.setKeyable(
True)
407 attr.setInternal(
True)
412 instanceShape.aInstanceShape = messageAttr.create(
"instanceShape",
"is")
413 instanceShape.addAttribute(instanceShape.aInstanceShape)
415 instanceShape.aRadius = numericAttr.create(
"radius",
"r", OpenMaya.MFnNumericData.kDouble, kDefaultRadius)
416 setOptions(numericAttr)
417 instanceShape.addAttribute(instanceShape.aRadius)
419 instanceShape.aCount = numericAttr.create("count",
"ct", OpenMaya.MFnNumericData.kInt, kDefaultCount)
420 setOptions(numericAttr)
421 instanceShape.addAttribute(instanceShape.aCount)
424 def initializePlugin(mobject):
425 mplugin = OpenMayaMPx.MFnPlugin(mobject,
"Autodesk",
"2011",
"Any")
427 mplugin.registerShape( kPluginNodeTypeName, spInstanceShapeNodeId,
428 nodeCreator, nodeInitializer, uiCreator )
430 sys.stderr.write(
"Failed to register node: %s" % kPluginNodeTypeName )
435 def uninitializePlugin(mobject):
436 mplugin = OpenMayaMPx.MFnPlugin(mobject)
438 mplugin.deregisterNode( spInstanceShapeNodeId )
440 sys.stderr.write(
"Failed to deregister node: %s" % kPluginNodeTypeName )