#include <maya/MIOStream.h>
#include <maya/MPxSurfaceShape.h>
#include <maya/MPxSurfaceShapeUI.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnEnumAttribute.h>
#include <maya/MPoint.h>
#include <maya/MPlug.h>
#include <maya/MDrawData.h>
#include <maya/MDrawRequest.h>
#include <maya/MSelectionMask.h>
#include <maya/MSelectionList.h>
#include <maya/MDagPath.h>
#include <maya/MMaterial.h>
#if defined(OSMac_MachO_)
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#define MCHECKERROR(STAT,MSG)       \
    if ( MS::kSuccess != STAT ) {   \
        cerr << MSG << endl;        \
        return MS::kFailure;        \
    }
#define MAKE_NUMERIC_ATTR( NAME, SHORTNAME, TYPE, DEFAULT, KEYABLE ) \
    MStatus NAME##_stat;                                             \
    MFnNumericAttribute NAME##_fn;                                   \
    NAME = NAME##_fn.create( #NAME, SHORTNAME, TYPE, DEFAULT );      \
    MCHECKERROR(NAME##_stat, "numeric attr create error");           \
    NAME##_fn.setHidden( !KEYABLE );                                 \
    NAME##_fn.setKeyable( KEYABLE );                                 \
    NAME##_fn.setInternal( true );                                   \
    NAME##_stat = addAttribute( NAME );                              \
    MCHECKERROR(NAME##_stat, "addAttribute error");
#define LEAD_COLOR              18  // green
#define ACTIVE_COLOR            15  // white
#define ACTIVE_AFFECTED_COLOR   8   // purple
#define DORMANT_COLOR           4   // blue
#define HILITE_COLOR            17  // pale blue
class quadricGeom 
{
public:
    double radius1;
    double radius2;
    double height;
    double startAngle;
    double sweepAngle;
    short slices;
    short loops;
    short stacks;
    short shapeType;
};
{
public:
    quadricShape();
    virtual ~quadricShape(); 
                      
    static  void *      creator();
    quadricGeom*        geometry();
private:
    quadricGeom*        fGeometry;
    
    
 
public:
    
    
};
{
public:
    quadricShapeUI();
    virtual ~quadricShapeUI(); 
                                     bool objectAndActiveOnly,
    static  void *  creator();
private:
    enum {
        kDrawCylinder,
        kDrawDisk,
        kDrawPartialDisk,
        kDrawSphere
    };
    
    
    enum {
        kDrawWireframe,
        kDrawWireframeOnShaded,
        kDrawSmoothShaded,
        kDrawFlatShaded,
        kLastToken
    };
};
MTypeId quadricShape::id( 0x80111 );
 
quadricShape::quadricShape()
{
    fGeometry = new quadricGeom;
    fGeometry->radius1      = 1.0;
    fGeometry->radius2      = 1.0;
    fGeometry->height       = 2.0;
    fGeometry->startAngle   = 0.0;
    fGeometry->sweepAngle   = 90.0;
    fGeometry->slices       = 8;
    fGeometry->loops        = 6;
    fGeometry->stacks       = 4;
    fGeometry->shapeType    = 0;
}
quadricShape::~quadricShape()
{
    delete fGeometry;
}
void quadricShape::postConstructor()
{ 
    
    
    setRenderable( true );
}
{ 
}
bool quadricShape::getInternalValue( 
const MPlug& plug,
 
{
    bool isOk = true;
    if ( plug == radius1 ) {
        datahandle.
set( fGeometry->radius1 );
        isOk = true;
    }
    else if ( plug == radius2 ) {
        datahandle.
set( fGeometry->radius2 );
        isOk = true;
    }
    else if ( plug == height ) {
        datahandle.
set( fGeometry->height );
        isOk = true;
    }
    else if ( plug == startAngle ) {
        datahandle.
set( fGeometry->startAngle );
        isOk = true;
    }
    else if ( plug == sweepAngle ) {
        datahandle.
set( fGeometry->sweepAngle );
        isOk = true;
    }
    else if ( plug == slices ) {
        datahandle.
set( fGeometry->slices );
        isOk = true;
    }
    else if ( plug == loops ) {
        datahandle.
set( fGeometry->loops );
        isOk = true;
    }
    else if ( plug == stacks ) {
        datahandle.
set( fGeometry->stacks );
        isOk = true;
    }
    else {
    }
    return isOk;
}
bool quadricShape::setInternalValue( 
const MPlug& plug,
 
{
    bool isOk = true;
    
    
    
    if ( plug == radius1 ) {
        double innerRadius = datahandle.
asDouble();
 
        double outerRadius = fGeometry->radius2;
        if ( innerRadius > outerRadius ) {
            outerRadius = innerRadius;
        }
        if ( innerRadius < 0 ) {
            innerRadius = 0;
        }
        fGeometry->radius1 = innerRadius;
        fGeometry->radius2 = outerRadius;
        isOk = true;
    }
    else if ( plug == radius2 ) {
        double outerRadius = datahandle.
asDouble();
 
        double innerRadius = fGeometry->radius1;
        if ( outerRadius <= 0 ) {
            outerRadius = 0.1;
        }
        if ( innerRadius > outerRadius ) {
            innerRadius = outerRadius;
        }
        if ( innerRadius < 0 ) {
            innerRadius = 0;
        }
        fGeometry->radius1 = innerRadius;
        fGeometry->radius2 = outerRadius;
        isOk = true;
    }
    else if ( plug == height ) {
        if ( val <= 0 ) {
            val = 0.1;
        }
        fGeometry->height = val;
    }
    else if ( plug == startAngle ) {
        fGeometry->startAngle = val;
    }
    else if ( plug == sweepAngle ) {
        fGeometry->sweepAngle = val;
    }
    else if ( plug == slices ) {
        if ( val < 3 ) {
            val = 3;
        }
        fGeometry->slices = val;
    }
    else if ( plug == loops ) {
        if ( val < 3 ) {
            val = 3;
        }
        fGeometry->loops = val;
    }
    else if ( plug == stacks ) {
        if ( val < 2 ) {
            val = 2;
        }
        fGeometry->stacks = val;
    }
    else {
    }
    return isOk;
}
bool quadricShape::isBounded() const { return true; }
{
    quadricShape* nonConstThis = const_cast <quadricShape*> (this);
    quadricGeom* geom = nonConstThis->geometry();
    double r = geom->radius1;
    r = geom->radius2;
    r = geom->height;
    return result;
}
void* quadricShape::creator()
{
    return new quadricShape();
}
{ 
    
    
    shapeType = enumAttr.
create( 
"shapeType", 
"st", 0, &stat );
    MCHECKERROR( stat, "create shapeType attribute" );
    stat = addAttribute( shapeType );
    MCHECKERROR( stat, "Error adding shapeType attribute." );
    
    
    
    return stat;
}
quadricGeom* quadricShape::geometry()
{
    MObject this_object = thisMObject();
 
    MPlug plug( this_object, radius1 ); plug.
getValue( fGeometry->radius1 );
 
    return fGeometry;
}
quadricShapeUI::quadricShapeUI() {}
quadricShapeUI::~quadricShapeUI() {}
void* quadricShapeUI::creator()
{
    return new quadricShapeUI();
}
void quadricShapeUI::getDrawRequests( 
const MDrawInfo & info,
 
                             bool ,
{
    
    
    
    
    quadricShape* shapeNode = (quadricShape*)surfaceShape();
    quadricGeom* geom = shapeNode->geometry();
    getDrawData( geom, data );
    
        return;
    
    
    {        
            getDrawRequestsWireframe( request, info );
            break;
        
            getDrawRequestsShaded( request, info, queue, data );
            break;
        
            getDrawRequestsShaded( request, info, queue, data );
            break;
        default:    
            break;
    }
}
{   
    quadricGeom * geom = (quadricGeom*)data.
geometry();
    int token = request.
token();
 
    bool drawTexture = false;
    view.beginGL(); 
    if ( (token == kDrawSmoothShaded) || (token == kDrawFlatShaded) )
    {
#if     defined(SGI) || defined(MESA)
        glEnable( GL_POLYGON_OFFSET_EXT );
#else
        glEnable( GL_POLYGON_OFFSET_FILL );
#endif
        
        
        
        
        if ( drawTexture ) glEnable(GL_TEXTURE_2D);
        
        
        if ( drawTexture ) {
        }
    }
    GLUquadricObj* qobj = gluNewQuadric();
    switch( token )
    {
        case kDrawWireframe :
        case kDrawWireframeOnShaded :
            gluQuadricDrawStyle( qobj, GLU_LINE );
            break;
        case kDrawSmoothShaded :
            gluQuadricNormals( qobj, GLU_SMOOTH );
            gluQuadricTexture( qobj, true );
            gluQuadricDrawStyle( qobj, GLU_FILL );
            break;
        case kDrawFlatShaded :
            gluQuadricNormals( qobj, GLU_FLAT );
            gluQuadricTexture( qobj, true );
            gluQuadricDrawStyle( qobj, GLU_FILL );
            break;
    }
    switch ( geom->shapeType )
    {
    case kDrawCylinder :
        gluCylinder( qobj, geom->radius1, geom->radius2, geom->height,
                     geom->slices, geom->stacks );
        break;
    case kDrawDisk :
        gluDisk( qobj, geom->radius1, geom->radius2, geom->slices, geom->loops );
        break;
    case kDrawPartialDisk :
        gluPartialDisk( qobj, geom->radius1, geom->radius2, geom->slices,
                        geom->loops, geom->startAngle, geom->sweepAngle );
        break;
    case kDrawSphere : 
    default :
        gluSphere( qobj, geom->radius1, geom->slices, geom->stacks );
        break;
    }
    
    
    if ( drawTexture ) glDisable(GL_TEXTURE_2D);
    view.endGL(); 
}
{
    item.
add( selectInfo.selectPath() );
    selectInfo.addSelection( item, xformedPt, selectionList,
                             worldSpaceSelectPts, priorityMask, false );
    return true;
}
void quadricShapeUI::getDrawRequestsWireframe( 
MDrawRequest& request,
 
{
    switch ( displayStatus )
    {
            request.
setColor( LEAD_COLOR, activeColorTable );
            break;
            request.
setColor( ACTIVE_COLOR, activeColorTable );
            break;
            request.
setColor( ACTIVE_AFFECTED_COLOR, activeColorTable );
            break;
            request.
setColor( DORMANT_COLOR, dormantColorTable );
            break;
            request.
setColor( HILITE_COLOR, activeColorTable );
            break;
        default:    
            break;
    }
}
void quadricShapeUI::getDrawRequestsShaded( 
MDrawRequest& request,
 
{
    
    
    
    
        cerr << "Couldnt evaluate\n";
    }
    bool drawTexture = true;
    }
    bool materialTransparent = false;
    if ( materialTransparent ) {
    }
    
    
    
    
    {
        getDrawRequestsWireframe( wireRequest, info );
        wireRequest.
setToken( kDrawWireframeOnShaded );
        queue.
add( wireRequest );
    }
}
{ 
    MFnPlugin plugin( obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    return plugin.registerShape( "quadricShape", quadricShape::id,
                                   &quadricShape::creator,
                                   &quadricShape::initialize,
                                   &quadricShapeUI::creator  );
}
{
    return plugin.deregisterNode( quadricShape::id );
}