//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ /////////////////////////////////////////////////////////////////// // // NOTE: PLEASE READ THE README.TXT FILE FOR INSTRUCTIONS ON // COMPILING AND USAGE REQUIREMENTS. // // File: pnTrianglesNode.cpp // // Dependency Graph Node: pnTriangles // // Description: // // Hardware shader plugin to perform : // 1) ATI PN triangle tessellation on geometry, if the extension // ATI_pn_triangles is supported in hardware. // 2) A simple vertex program using EXT_vertex_program, if the // extension is supported. // 3) A simple fragement program using AT_fragment_program, if the // extension is supported. // // This is an excerpt from the PN triangle extension // specification: // // "When PN Triangle generation is enabled, each triangle-based geometric // primitive is replaced with a new curved surface using the primitive // vertices as control points. The intent of PN Triangles // are to take a set of triangle-based geometry and algorithmically // tessellate it into a more organic shape with a smoother silhouette. // The new surface can either linearly or quadratically interpolate the // normals across the patch. The vertices can be either linearly or // cubically interpolated across the patch. Linear interpolation // of the points would be useful for getting more sample points for // lighting on the same geometric shape. All other vertex information // (colors, texture coordinates, fog coordinates, and vertex weights) are // interpolated linearly across the patch." // // This plugin is ATI Radeon specific. // /////////////////////////////////////////////////////////////////// #include #include #include "pnTrianglesNode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MTypeId pnTriangles::id( 0x00105448 ); #define pnDefaultMaxTessellation 0 // Default max tessellation // Attributes // MObject pnTriangles::attrSubdivisions; // Subdivision level MObject pnTriangles::attrColored; // Display colored MObject pnTriangles::attrTextured; // Display textured MObject pnTriangles::attrWireframe; // Display wireframe MObject pnTriangles::attrNormalMode; // Normal evaluation mode MObject pnTriangles::attrPointMode; // Point evaluation mode MObject pnTriangles::attrEnableVertexProgram; // Enable vertex program MObject pnTriangles::attrEnablePixelProgram; // Enable pixel program pnTriangles::pnTriangles() : fSubdivisions( 0 ), // Default 0 level of subdivision fNumTextureCoords( 0 ), // Default not-textured fNumNormals( 1 ), // Default shaded fNumColors( 0 ), // Default not-colored fPointMode( kPointCubic ), // Default cubic fNormalMode( kNormalQuadratic ), // Default quadratic fMaxTessellationLevel( pnDefaultMaxTessellation ), // 0 maximum default fWireframe( false ), // Default filled fInTexturedMode( false ), // Keep track of textured mode fTestVertexProgram( false ), fTestFragmentProgram( false ), fVertexShaderId( -1 ), fFragmentShaderId( -1 ) { fExtensionSupported[kPNTriangesEXT ] = false; fExtensionSupported[kVertexShaderEXT] = false; fExtensionSupported[kFragmentShaderEXT] = false; // Initialize required extension(s) // // Initialize PN-triangles fExtensionSupported[kPNTriangesEXT] = initialize_ATI_Extension("GL_ATI_pn_triangles"); // Get the maximum tessellation level supported by the extension // if (fExtensionSupported[kPNTriangesEXT]) { int val; glGetIntegerv( GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI, &val ); fMaxTessellationLevel = val; } fExtensionSupported[kVertexShaderEXT] = initialize_ATI_Extension("GL_EXT_vertex_shader"); fExtensionSupported[kFragmentShaderEXT] = initialize_ATI_Extension("GL_ATI_fragment_shader"); } pnTriangles::~pnTriangles() // // Description: // Destructor { // Delete any vertex shader // if (fExtensionSupported[kVertexShaderEXT]) { if (fVertexShaderId != -1) glDeleteVertexShaderEXT(fVertexShaderId); } } bool pnTriangles::getInternalValue( const MPlug &plug, MDataHandle &dh ) // // Description: // Get internally cached values when attribute is queried // { if( plug == pnTriangles::attrSubdivisions ) { dh.set( int(fSubdivisions) ); return true; } else if ( plug == pnTriangles::attrColored) { dh.set( (fNumColors > 0) ); return true; } else if ( plug == pnTriangles::attrWireframe) { dh.set( fWireframe > 0); return true; } else if ( plug == pnTriangles::attrTextured) { dh.set( (fNumTextureCoords > 0) ); return true; } else if ( plug == pnTriangles::attrNormalMode ) { if (fNormalMode == kNormalLinear) dh.set( 0 ); else dh.set( 1 ); return true; } else if ( plug == pnTriangles::attrPointMode ) { if (fPointMode == kPointLinear) dh.set( 0 ); else dh.set( 1 ); return true; } else if ( plug == pnTriangles::attrEnableVertexProgram) { dh.set( fTestVertexProgram ); return true; } else if ( plug == pnTriangles::attrEnablePixelProgram) { dh.set( fTestFragmentProgram ); return true; } return false; } bool pnTriangles::setInternalValue( const MPlug &plug, const MDataHandle &dh ) // // Description: // Set internally cached values when attribute changes // { if( plug == pnTriangles::attrSubdivisions ) { fSubdivisions = dh.asInt(); // Make sure we don't go above the maximum allowed by // the extension if (fSubdivisions > fMaxTessellationLevel) fSubdivisions = fMaxTessellationLevel; return true; } else if ( plug == pnTriangles::attrColored) { if (dh.asBool() == true) fNumColors = 1; else fNumColors = 0; return true; } else if ( plug == pnTriangles::attrWireframe) { if (dh.asBool() == true) fWireframe = 1; else fWireframe = 0; return true; } else if ( plug == pnTriangles::attrTextured) { if (dh.asBool() == true) fNumTextureCoords = 1; else fNumTextureCoords = 0; return true; } else if ( plug == pnTriangles::attrNormalMode ) { if (dh.asInt() == 0) fNormalMode = kNormalLinear; else fNormalMode = kNormalQuadratic; return true; } else if ( plug == pnTriangles::attrPointMode ) { if (dh.asInt() == 0) fPointMode = kPointLinear; else fPointMode = kPointCubic; return true; } else if ( plug == pnTriangles::attrEnableVertexProgram ) { if (dh.asBool() == true) { if (fExtensionSupported[kVertexShaderEXT]) fTestVertexProgram = 1; else fTestVertexProgram = 0; } else fTestVertexProgram = 0; return true; } else if ( plug == pnTriangles::attrEnablePixelProgram ) { #ifdef _FRAGMENT_PROGRAM_READY_ if (dh.asBool() == true) if (fExtensionSupported[kFragmentShaderEXT]) fTestFragmentProgram = 1; else fTestFragmentProgram = 0; else fTestFragmentProgram = 0; #else fTestFragmentProgram = 0; #endif return true; } return false; } void* pnTriangles::creator() // // Description: // Create new pnTriangles class // // Return Value: // a new object of this type // { return new pnTriangles(); } MStatus pnTriangles::initialize() // // Description: // Initialize class // Return Values: // MS::kSuccess // MS::kFailure // { MFnNumericAttribute nAttr; MStatus stat; // Subivision attribute attrSubdivisions = nAttr.create( "subdivisions", "sd", MFnNumericData::kInt, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setMin(0); nAttr.setMax(10); nAttr.setDefault(1); nAttr.setKeyable(true); attrColored = nAttr.create( "colored", "cl", MFnNumericData::kBoolean, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setDefault( false ); nAttr.setKeyable(true); attrTextured = nAttr.create( "textured", "tx", MFnNumericData::kBoolean, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setDefault( false ); nAttr.setKeyable(true); attrWireframe = nAttr.create( "wireframe", "wf", MFnNumericData::kBoolean, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setDefault( false ); nAttr.setKeyable(true); // Normal mode attribute attrNormalMode = nAttr.create( "quadraticNormals", "qn", MFnNumericData::kInt, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setMin(0); // Linear nAttr.setMax(1); // Quadratic nAttr.setDefault(1); nAttr.setKeyable(true); // Point mode attribute attrPointMode= nAttr.create( "cubicPoints", "cp", MFnNumericData::kInt, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setMin(0); // Linear nAttr.setMax(1); // Cubic nAttr.setDefault(1); nAttr.setKeyable(true); // Enable vertex program attrEnableVertexProgram = nAttr.create( "vertexProgram", "vp", MFnNumericData::kBoolean, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setDefault( false ); nAttr.setKeyable(true); // Enable pixel program attrEnablePixelProgram = nAttr.create( "pixelProgram", "pp", MFnNumericData::kBoolean, 1 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setDefault( false ); nAttr.setKeyable(true); // Add the attributes we have created to the node // stat = addAttribute( attrSubdivisions ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrColored ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrWireframe ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrTextured ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrNormalMode ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrPointMode ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrEnableVertexProgram ); if (!stat) { stat.perror("addAttribute"); return stat;} stat = addAttribute( attrEnablePixelProgram ); if (!stat) { stat.perror("addAttribute"); return stat;} return MS::kSuccess; } MStatus pnTriangles::getFloat3(MObject attr, float value[3]) { MStatus status; // Get the attr to use // MPlug plug(thisMObject(), attr); MObject object; status = plug.getValue(object); if (!status) { status.perror("pnTrianglesNode::bind plug.getValue."); return status; } MFnNumericData data(object, &status); if (!status) { status.perror("pnTrianglesNode::bind construct data."); return status; } status = data.getData(value[0], value[1], value[2]); if (!status) { status.perror("pnTrianglesNode::bind get values."); return status; } return MS::kSuccess; } #define DEG_TO_RAD(_x_) (3.14159265358979323846264338327950F / 180.0F * (_x_)) ////////////////////// void pnTriangles::bindVertexProgram(const MColor diffuse, const MColor specular, const MColor emission, const MColor ambient) // // Description: // Sample vertex program which sets up a yellow diffuse // shader. // { // See if extension is supported // if (!fExtensionSupported[kVertexShaderEXT]) return; // Enable vertex shaders glEnable(GL_VERTEX_SHADER_EXT); // Generate a new vertex shader id, if none has been created. if (fVertexShaderId != -1) { glBindVertexShaderEXT (fVertexShaderId); return; } fVertexShaderId = glGenVertexShadersEXT (1); //Initialize global parameter bindings GLuint Modelview = glBindParameterEXT (GL_MODELVIEW_MATRIX); GLuint Projection = glBindParameterEXT (GL_PROJECTION_MATRIX); // Q: does this read properly from vertex arrays or // do I need to define a variant pointer via glVariantPointerEXT ? // GLuint Vertex = glBindParameterEXT (GL_CURRENT_VERTEX_EXT); // GL_CURRENT_NORMAL comes from the glGetPointerTarget enums GLuint Normal = glBindParameterEXT (GL_CURRENT_NORMAL); //GLuint lightPos = glBindLightParameterEXT( 0, GL_POSITION ); // Bind a diffuse shader glBindVertexShaderEXT (fVertexShaderId); glBeginVertexShaderEXT (); { float direction[4] = { 0.57735f, 0.57735f, 0.57735f, 0.0f}; //direction vector (1,1,1) normalized GLuint lightDirection; GLuint diffMaterial; GLuint sceneAmbient; GLuint eyeVertex; GLuint clipVertex; GLuint eyeNormal; GLuint intensity; // generate local values eyeVertex = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1); clipVertex = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1); eyeNormal = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1); intensity = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1); // generate constant values lightDirection = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_CONSTANT_EXT, GL_FULL_RANGE_EXT, 1); diffMaterial = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_CONSTANT_EXT, GL_FULL_RANGE_EXT, 1); sceneAmbient = glGenSymbolsEXT (GL_VECTOR_EXT, GL_LOCAL_CONSTANT_EXT, GL_FULL_RANGE_EXT, 1); glSetLocalConstantEXT (lightDirection, GL_FLOAT, direction); glSetLocalConstantEXT (diffMaterial, GL_FLOAT, (void *)&(diffuse.r)); glSetLocalConstantEXT (sceneAmbient, GL_FLOAT, (void *)&(ambient.r)); glShaderOp2EXT (GL_OP_MULTIPLY_MATRIX_EXT, eyeVertex, Modelview, Vertex); glShaderOp2EXT (GL_OP_MULTIPLY_MATRIX_EXT, GL_OUTPUT_VERTEX_EXT, Projection, eyeVertex); // assumes no scaling/shearing in modelview matrix glShaderOp2EXT (GL_OP_MULTIPLY_MATRIX_EXT, eyeNormal, Modelview, Normal); glShaderOp2EXT (GL_OP_DOT3_EXT, intensity, lightDirection, eyeNormal); glShaderOp2EXT (GL_OP_ADD_EXT, intensity, sceneAmbient, intensity); glShaderOp2EXT (GL_OP_MUL_EXT, GL_OUTPUT_COLOR0_EXT, diffMaterial, intensity); } glEndVertexShaderEXT (); } void pnTriangles::bindFragmentProgram() // // Description: // // THIS IS JUST SAMPLE CODE, MORE NEEDS TO BE DONE TO ACTUALLY USE // INCORPORATE A FRAGMENT SHADER. // { // See if extension is supported // if (!fExtensionSupported[kFragmentShaderEXT]) return; // Enable vertex shaders glEnable(GL_FRAGMENT_SHADER_ATI); // Generate a new fragment shader id, if none has been created. if (fFragmentShaderId != -1) { glBindFragmentShaderATI (fFragmentShaderId); return; } fFragmentShaderId = glGenFragmentShadersATI(1); glBindFragmentShaderATI (fFragmentShaderId); glBeginFragmentShaderATI(); // Place sample fragment shader code here .... glEndFragmentShaderATI(); } /* virtual */ MStatus pnTriangles::bind(const MDrawRequest& request, M3dView& view) // // Description: // This bind demonstrates the usage of internal material // and texture properties. This shader must be connected // to the "hardwareShader" attribute of a lambert derived // shader. // { // Setup the view view.beginGL(); glPushAttrib( GL_ALL_ATTRIB_BITS ); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); MColor diffuse(1.0F, 1.0F, 0.0F, 1.0F); MColor specular(1.0F, 1.0F, 1.0F, 1.0F); MColor emission(0.0F, 0.0F, 0.0F, 1.0F); MColor ambient(0.2F, 0.2F, 0.2F, 1.0F); // Get the diffuse and specular colors // float shininess; bool hasTransparency = false; MMaterial material = request.material(); fInTexturedMode = material.materialIsTextured(); // Setting this to true will get the default "green" material back // since it will try and evaluate this shader, which internally // Maya does not understand -> thus giving the "green" material back bool useInternalMaterialSetting = false; if (!useInternalMaterialSetting) { material.getEmission( emission ); material.getSpecular( specular ); shininess = 13.0; } material.getHasTransparency( hasTransparency ); if (!fInTexturedMode) { if (!fTestVertexProgram && !useInternalMaterialSetting) material.getDiffuse( diffuse ); } // In textured mode. Diffuse material is always white // for texture blends else { if (!useInternalMaterialSetting) diffuse.r = diffuse.g = diffuse.b = diffuse.a = 1.0; } // Use a vertex program to set up shading // if (fTestVertexProgram) { bindVertexProgram(diffuse, specular, emission, ambient); } else if (fTestFragmentProgram) { bindFragmentProgram(); } // Don't use a vertex program to set up shading // else { // Set up the material state // glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); glColor4fv(&ambient.r); if (fInTexturedMode) { glEnable( GL_TEXTURE_2D ); MDrawData drawData = request.drawData(); material.applyTexture( view, drawData ); float scaleS, scaleT, translateS, translateT, rotate; material.getTextureTransformation(scaleS, scaleT, translateS, translateT, rotate); rotate = DEG_TO_RAD(-rotate); float c = cosf(rotate); float s = sinf(rotate); translateS += ((c+s)/2.0F); translateT += ((c-s)/2.0F); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); if(scaleS != 1.0f || scaleT != 1.0f) glScalef(1.0f/scaleS, 1.0f/scaleT, 1.0f); if(translateS != 0.0f || translateT != 0.0f) glTranslatef(0.5f-translateS, 0.5f-translateT, 0.0f); else glTranslatef(0.5f, 0.5f, 0.0f); if(rotate != 0.0f) glRotatef(-rotate, 0.0f, 0.0f, 1.0f); glMatrixMode(GL_MODELVIEW); } if (!useInternalMaterialSetting) { glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glColor4fv(&diffuse.r); glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); glColor4fv(&specular.r); glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION); glColor4fv(&emission.r); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); } else { const MDagPath dagPath = request.multiPath(); material.evaluateMaterial( view, dagPath ); material.setMaterial(dagPath, hasTransparency); } } // Do PN triangles in hardware, or do nothing // if LOD = 0 if (fExtensionSupported[kPNTriangesEXT] || (fSubdivisions == 0)) { if (fSubdivisions != 0) { glEnable( GL_PN_TRIANGLES_ATI ); // Set point mode // if (fPointMode == kPointLinear) glPNTrianglesiATI( GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI); else glPNTrianglesiATI( GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI); // Set normal mode // if (fNormalMode == kNormalLinear) glPNTrianglesiATI( GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI); else glPNTrianglesiATI( GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI); // Set tessellation level // glPNTrianglesiATI( GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, fSubdivisions ); } } view.endGL(); return MS::kSuccess; } /* virtual */ MStatus pnTriangles::unbind(const MDrawRequest& request, M3dView& view) // // Description: // // { view.beginGL(); // Disable vertex shader if (fTestVertexProgram) { glDisable(GL_VERTEX_SHADER_EXT); } // Disable fragment shader else if (fTestFragmentProgram) { glDisable(GL_FRAGMENT_SHADER_ATI); } // Disable regular material state else { glDisable( GL_TEXTURE_2D ); glDisable(GL_COLOR_MATERIAL); if (fInTexturedMode) { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } } // Disable PN triangles extension if needed // if (fExtensionSupported[kPNTriangesEXT] || (fSubdivisions == 0)) { if (fSubdivisions != 0) glDisable( GL_PN_TRIANGLES_ATI ); } glPopClientAttrib(); glPopAttrib(); view.endGL(); return MS::kSuccess; } unsigned int pnTriangles:: computePNTriangles(const float * vertexArray, const float * normalArray, const float * texCoordArray, float * pnVertexArray, float * pnNormalArray, float * pnTexCoordArray, float * pnColorArray) { unsigned int triangleCount = 0; // Software implementation left to the user... return triangleCount; } /* virtual */ MStatus pnTriangles::geometry( const MDrawRequest& request, M3dView& view, int prim, unsigned int writable, int indexCount, const unsigned int * indexArray, int vertexCount, const int * vertexIDs, const float * vertexArray, int normalCount, const float ** normalArrays, int colorCount, const float ** colorArrays, int texCoordCount, const float ** texCoordArrays) { // We assume triangles here. // if (prim != GL_TRIANGLES) return MS::kSuccess; // Should call parent class here ! view.beginGL(); if (fWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); bool needColors = (fNumColors && colorCount); bool needTexCoords = (fNumTextureCoords && texCoordCount); bool needNormals = (fNumNormals && normalCount); if (!fExtensionSupported[kPNTriangesEXT]) { // Write code here to support PN-triangles in software... } glVertexPointer(3, GL_FLOAT, 0, vertexArray); glEnableClientState(GL_VERTEX_ARRAY); if (needNormals) { glNormalPointer(GL_FLOAT, 0, normalArrays[0]); glEnableClientState(GL_NORMAL_ARRAY); } if (needTexCoords) { glTexCoordPointer(2, GL_FLOAT, 0, texCoordArrays[0]); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } if (needColors) { // Override material color glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glColorPointer(4, GL_FLOAT, 0, colorArrays[0]); glEnableClientState(GL_COLOR_ARRAY); } glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray); if (fWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); view.endGL(); return MS::kSuccess; } /* virtual */ int pnTriangles::normalsPerVertex() { return fNumNormals; } /* virtual */ int pnTriangles::texCoordsPerVertex() { if (fInTexturedMode) return fNumTextureCoords; else return 0; } /* virtual */ int pnTriangles::colorsPerVertex() { return fNumColors; } ////////////////////////////////////////////////////////////////////////////////////////////// // Main plugin interface ////////////////////////////////////////////////////////////////////////////////////////////// MStatus initializePlugin( MObject obj ) // // Description: // Initialize plugin // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; const MString UserClassify( "shader/surface/utility" ); MFnPlugin plugin( obj, "Alias", "4.5", "Any"); status = plugin.registerNode( "pnTriangles", pnTriangles::id, pnTriangles::creator, pnTriangles::initialize, MPxNode::kHwShaderNode, &UserClassify ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // Deregister node // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( pnTriangles::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; }