66 import maya.OpenMaya 
as OpenMaya
 
   67 import maya.OpenMayaMPx 
as OpenMayaMPx
 
   68 import maya.OpenMayaRender 
as OpenMayaRender
 
   69 import maya.OpenMayaUI 
as OpenMayaUI
 
   75 kPluginNodeTypeName = 
"spBasicShape" 
   78 glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
 
   79 glFT = glRenderer.glFunctionTable()
 
   83 kActiveAffectedColor    = 8  
 
   98     radius = kDefaultRadius
 
   99     height = kDefaultHeight
 
  100     width = kDefaultWidth
 
  101     shapeType = kDefaultShapeType
 
  108 class basicShape(OpenMayaMPx.MPxSurfaceShape):
 
  110         OpenMayaMPx.MPxSurfaceShape.__init__(self)
 
  119         self.__myGeometry = basicGeom()
 
  123     def postConstructor(self):
 
  125          When instances of this node are created internally, the MObject associated 
  126          with the instance is not created until after the constructor of this class 
  127          is called. This means that no member functions of MPxSurfaceShape can 
  128          be called in the constructor. 
  129          The postConstructor solves this problem. Maya will call this function 
  130          after the internal object has been created. 
  131          As a general rule do all of your initialization in the postConstructor. 
  133         self.setRenderable(
True)
 
  137     def compute(self, plug, dataBlock):
 
  139          Since there are no output attributes this is not necessary but 
  140          if we wanted to compute an output mesh for rendering it would 
  141          be done here base on the inputs. 
  143         return OpenMaya.kUnknownParameter
 
  147     def getInternalValue(self, plug, datahandle):
 
  149          Handle internal attributes. 
  150          In order to impose limits on our attribute values we 
  151          mark them internal and use the values in fGeometry intead. 
  153         if (plug == basicShape.aRadius):
 
  154             datahandle.setDouble(self.__myGeometry.radius)
 
  156         elif (plug == basicShape.aHeight):
 
  157             datahandle.setDouble(self.__myGeometry.height)
 
  159         elif (plug == basicShape.aWidth):
 
  160             datahandle.setDouble(self.__myGeometry.width)
 
  163             return OpenMayaMPx.MPxSurfaceShape.getInternalValue(self, plug, datahandle)
 
  169     def setInternalValue(self, plug, datahandle):
 
  171          Handle internal attributes. 
  172          In order to impose limits on our attribute values we 
  173          mark them internal and use the values in fGeometry intead. 
  178         if (plug == basicShape.aRadius):
 
  179             radius = datahandle.asDouble()
 
  184             self.__myGeometry.radius = radius
 
  186         elif (plug == basicShape.aHeight):
 
  187             val = datahandle.asDouble()
 
  190             self.__myGeometry.height = val
 
  192         elif (plug == basicShape.aWidth):
 
  193             val = datahandle.asDouble()
 
  196             self.__myGeometry.width = val
 
  199             return OpenMayaMPx.MPxSurfaceShape.setInternalValue(self, plug, datahandle)
 
  210     def boundingBox(self):
 
  212          Returns the bounding box for the shape. 
  213          In this case just use the radius and height attributes 
  214          to determine the bounding box. 
  218         geom = self.geometry()
 
  237          This function gets the values of all the attributes and 
  238          assigns them to the fGeometry. Calling MPlug::getValue 
  239          will ensure that the values are up-to-date. 
  243         this_object = self.thisMObject()
 
  246         self.__myGeometry.radius = plug.asDouble()
 
  248         plug.setAttribute(basicShape.aHeight)
 
  249         self.__myGeometry.height = plug.asDouble()
 
  251         plug.setAttribute(basicShape.aWidth)
 
  252         self.__myGeometry.width = plug.asDouble()
 
  254         plug.setAttribute(basicShape.aShapeType)
 
  255         self.__myGeometry.shapeType = plug.asShort() 
 
  257         return self.__myGeometry
 
  261     stream=OpenMaya.MStreamUtils.stdOutStream()
 
  262     OpenMaya.MStreamUtils.writeCharBuffer(stream,msg)
 
  268 class basicShapeUI(OpenMayaMPx.MPxSurfaceShapeUI):
 
  270     __kDrawRectangle, __kDrawCircle, __kDrawTriangle = range(3)
 
  271     __kDrawWireframe, __kDrawWireframeOnShaded, __kDrawSmoothShaded, __kDrawFlatShaded, __kLastToken = range(5)
 
  274         OpenMayaMPx.MPxSurfaceShapeUI.__init__(self)
 
  278     def getDrawRequests(self, info, objectAndActiveOnly, queue):
 
  280          The draw data is used to pass geometry through the  
  281          draw queue. The data should hold all the information 
  282          needed to draw the shape. 
  286         request = info.getPrototype(self)
 
  288         shapeNode = self.surfaceShape()
 
  289         geom = shapeNode.geometry()
 
  290         self.getDrawData(geom, data)
 
  291         request.setDrawData(data)
 
  294         if (
not info.objectDisplayStatus(OpenMayaUI.M3dView.kDisplayMeshes)):
 
  298         if (info.displayStyle() == OpenMayaUI.M3dView.kWireFrame):
 
  299             self.getDrawRequestsWireframe(request, info)
 
  302         elif (info.displayStyle() == OpenMayaUI.M3dView.kGouraudShaded):
 
  303             request.setToken(basicShapeUI.__kDrawSmoothShaded)
 
  304             self.getDrawRequestsShaded(request, info, queue, data)
 
  307         elif (info.displayStyle() == OpenMayaUI.M3dView.kFlatShaded):
 
  308             request.setToken(basicShapeUI.__kDrawFlatShaded)
 
  309             self.getDrawRequestsShaded(request, info, queue, data)
 
  315     def draw(self, request, view):
 
  317          From the given draw request, get the draw data and determine 
  318          which basic to draw and with what values. 
  321         data = request.drawData()
 
  322         shapeNode = self.surfaceShape()
 
  323         geom = shapeNode.geometry()
 
  324         token = request.token()
 
  328         if ((token == basicShapeUI.__kDrawSmoothShaded) 
or 
  329                     (token == basicShapeUI.__kDrawFlatShaded)):
 
  331             material = request.material()
 
  332             material.setMaterial(request.multiPath(), request.isTransparent())
 
  340             drawTexture = material.materialIsTextured() 
and not view.usingDefaultMaterial() 
 
  344                 material.applyTexture(view, data)
 
  346         glFT.glPushAttrib( OpenMayaRender.MGL_ALL_ATTRIB_BITS )
 
  348         if ((token == basicShapeUI.__kDrawSmoothShaded) 
or 
  349                     (token == basicShapeUI.__kDrawFlatShaded)):         
 
  350             glFT.glEnable(OpenMayaRender.MGL_POLYGON_OFFSET_FILL)
 
  351             glFT.glPolygonMode(OpenMayaRender.MGL_FRONT_AND_BACK, OpenMayaRender.MGL_FILL)
 
  353                 glFT.glEnable(OpenMayaRender.MGL_TEXTURE_2D)            
 
  355             glFT.glPolygonMode(OpenMayaRender.MGL_FRONT_AND_BACK, OpenMayaRender.MGL_LINE)
 
  358         if (geom.shapeType == basicShapeUI.__kDrawCircle):
 
  360             glFT.glBegin(OpenMayaRender.MGL_POLYGON)
 
  361             for i 
in range(0,360):
 
  362                 rad = (i*2*math.pi)/360;
 
  363                 glFT.glNormal3f(0.0, 0.0, 1.0)
 
  365                     glFT.glTexCoord3f(geom.radius*math.cos(0), geom.radius*math.sin(0), 0.0)
 
  366                     glFT.glVertex3f(geom.radius*math.cos(0), geom.radius*math.sin(0), 0.0)
 
  368                     glFT.glTexCoord3f(geom.radius*math.cos(rad), geom.radius*math.sin(rad), 0.0)
 
  369                     glFT.glVertex3f(geom.radius*math.cos(rad), geom.radius*math.sin(rad), 0.0)
 
  372         elif (geom.shapeType == basicShapeUI.__kDrawRectangle):
 
  374             glFT.glBegin(OpenMayaRender.MGL_QUADS)
 
  376             glFT.glTexCoord2f(-1*(geom.width/2), -1*(geom.height/2))
 
  377             glFT.glVertex3f(-1*(geom.width/2), -1*(geom.height/2), 0.0)
 
  378             glFT.glNormal3f(0, 0, 1.0)
 
  380             glFT.glTexCoord2f(-1*(geom.width/2), (geom.height/2))
 
  381             glFT.glVertex3f(-1*(geom.width/2), (geom.height/2), 0.0)
 
  382             glFT.glNormal3f(0, 0, 1.0)
 
  384             glFT.glTexCoord2f((geom.width/2), (geom.height/2))
 
  385             glFT.glVertex3f((geom.width/2), (geom.height/2), 0.0)
 
  386             glFT.glNormal3f(0, 0, 1.0)
 
  388             glFT.glTexCoord2f((geom.width/2), -1*(geom.height/2))
 
  389             glFT.glVertex3f((geom.width/2), -1*(geom.height/2), 0.0)
 
  390             glFT.glNormal3f(0, 0, 1.0)
 
  395             glFT.glBegin(OpenMayaRender.MGL_TRIANGLES)
 
  396             glFT.glTexCoord2f(-1*(geom.width/2), -1*(geom.height/2))
 
  397             glFT.glVertex3f(-1*(geom.width/2), -1*(geom.height/2), 0.0)
 
  398             glFT.glNormal3f(0.0, 0.0, 1.0)
 
  400             glFT.glTexCoord2f(0.0, (geom.height/2))
 
  401             glFT.glVertex3f(0.0, (geom.height/2), 0.0)
 
  402             glFT.glNormal3f(0.0, 0.0, 1.0)
 
  404             glFT.glTexCoord2f((geom.width/2), -1*(geom.height/2))
 
  405             glFT.glVertex3f((geom.width/2), -1*(geom.height/2), 0.0)
 
  406             glFT.glNormal3f(0.0, 0.0, 1.0)
 
  409         if ((token == basicShapeUI.__kDrawSmoothShaded) 
or 
  410                     (token == basicShapeUI.__kDrawFlatShaded)):
 
  411             glFT.glDisable(OpenMayaRender.MGL_POLYGON_OFFSET_FILL)
 
  414                 glFT.glDisable(OpenMayaRender.MGL_TEXTURE_2D)
 
  421     def select(self, selectInfo, selectionList, worldSpaceSelectPts):
 
  423          Select function. Gets called when the bbox for the object is selected. 
  424          This function just selects the object without doing any intersection tests. 
  429         item.add(selectInfo.selectPath())
 
  431         selectInfo.addSelection(item, xformedPt, selectionList,
 
  432                                  worldSpaceSelectPts, priorityMask, 
False)
 
  436     def getDrawRequestsWireframe(self, request, info):
 
  438         request.setToken(basicShapeUI.__kDrawWireframe)
 
  440         displayStatus = info.displayStatus()
 
  441         activeColorTable = OpenMayaUI.M3dView.kActiveColors
 
  442         dormantColorTable = OpenMayaUI.M3dView.kDormantColors
 
  444         if (displayStatus == OpenMayaUI.M3dView.kLead):
 
  445                 request.setColor(kLeadColor, activeColorTable)
 
  447         elif (displayStatus == OpenMayaUI.M3dView.kActive):
 
  448                 request.setColor(kActiveColor, activeColorTable)
 
  450         elif (displayStatus == OpenMayaUI.M3dView.kActiveAffected):
 
  451                 request.setColor(kActiveAffectedColor, activeColorTable)
 
  453         elif (displayStatus == OpenMayaUI.M3dView.kDormant):
 
  454                 request.setColor(kDormantColor, dormantColorTable)
 
  456         elif (displayStatus == OpenMayaUI.M3dView.kHilite):
 
  457                 request.setColor(kHiliteColor, activeColorTable)
 
  461     def getDrawRequestsShaded(self, request, info, queue, data):
 
  463         path = info.multiPath() 
 
  465         material = OpenMayaMPx.MPxSurfaceShapeUI.material(self, path)
 
  466         usingDefaultMat = view.usingDefaultMaterial()
 
  470         displayStatus = info.displayStatus()
 
  474             material.evaluateMaterial(view, path)
 
  476             print "Couldn't evaluate material" 
  479         drawTexture = 
not usingDefaultMat
 
  480         if (drawTexture 
and material.materialIsTextured()):
 
  481             material.evaluateTexture(data)
 
  483         request.setMaterial(material)
 
  491         if ((displayStatus == OpenMayaUI.M3dView.kActive) 
or 
  492                  (displayStatus == OpenMayaUI.M3dView.kLead) 
or 
  493                  (displayStatus == OpenMayaUI.M3dView.kHilite)):
 
  494             wireRequest = info.getPrototype(self)
 
  495             wireRequest.setDrawData(data)
 
  496             self.getDrawRequestsWireframe(wireRequest, info)
 
  497             wireRequest.setToken(basicShapeUI.__kDrawWireframeOnShaded)
 
  498             wireRequest.setDisplayStyle(OpenMayaUI.M3dView.kWireFrame)
 
  499             queue.add(wireRequest)
 
  504     return OpenMayaMPx.asMPxPtr( basicShape() )
 
  508     return OpenMayaMPx.asMPxPtr( basicShapeUI() )
 
  511 def nodeInitializer():
 
  514     basicShape.aShapeType = enumAttr.create(
"shapeType", 
"st", kDefaultShapeType)
 
  515     enumAttr.addField(
"rectangle", 0)
 
  516     enumAttr.addField(
"circle", 1)
 
  517     enumAttr.addField(
"triangle", 2)
 
  518     enumAttr.setHidden(
False)
 
  519     enumAttr.setKeyable(
True)
 
  520     basicShape.addAttribute(basicShape.aShapeType)
 
  524     def setOptions(attr):
 
  525         attr.setHidden(
False)
 
  526         attr.setKeyable(
True)
 
  527         attr.setInternal(
True)
 
  531     basicShape.aRadius = numericAttr.create(
"radius", 
"r", OpenMaya.MFnNumericData.kDouble, kDefaultRadius) 
  532     setOptions(numericAttr) 
  533     basicShape.addAttribute(basicShape.aRadius) 
  535     basicShape.aHeight = numericAttr.create("height", 
"ht", OpenMaya.MFnNumericData.kDouble, kDefaultHeight)
 
  536     setOptions(numericAttr)
 
  537     basicShape.addAttribute(basicShape.aHeight)
 
  539     basicShape.aWidth = numericAttr.create(
"width2", 
"wt2", OpenMaya.MFnNumericData.kDouble, kDefaultWidth)
 
  540     setOptions(numericAttr)
 
  541     basicShape.addAttribute(basicShape.aWidth)
 
  544 def initializePlugin(mobject):
 
  545     mplugin = OpenMayaMPx.MFnPlugin(mobject, 
"Autodesk", 
"8.5", 
"Any")
 
  547         mplugin.registerShape( kPluginNodeTypeName, spBasicShapeNodeId,
 
  548                                 nodeCreator, nodeInitializer, uiCreator )
 
  550         sys.stderr.write( 
"Failed to register node: %s" % kPluginNodeTypeName )
 
  555 def uninitializePlugin(mobject):
 
  556     mplugin = OpenMayaMPx.MFnPlugin(mobject)
 
  558         mplugin.deregisterNode( spBasicShapeNodeId )
 
  560         sys.stderr.write( 
"Failed to deregister node: %s" % kPluginNodeTypeName )