#ifdef WIN32
#pragma warning( disable : 4786 )               // Disable STL warnings.
#endif
#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MPlug.h>
#include <maya/MFnPlugin.h>
#include <maya/MPxHwShaderNode.h>
#include <maya/MFnMesh.h>
#if MAYA_API_VERSION >= 800
        #include <maya/MHwTextureManager.h>
        #include <maya/MImageFileInfo.h>
#endif
#if defined(OSMac_MachO_)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif
class hwManagedTextureShader : public MPxHwShaderNode
{
        public:
                    hwManagedTextureShader();
    virtual         ~hwManagedTextureShader();
        virtual void    postConstructor();
        virtual MStatus glBind(const MDagPath& shapePath);
        virtual MStatus glUnbind(const MDagPath& shapePath);
        virtual MStatus glGeometry( const MDagPath&,
                              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);
        virtual int             texCoordsPerVertex();
        virtual int             normalsPerVertex();
        virtual bool    supportsBatching() const;
    static  void *  creator();
    static  MStatus initialize();
        GLboolean lightingOn;
        bool boundTexture;
    static  MTypeId id;
};
MTypeId hwManagedTextureShader::id( 0x81033 );
void hwManagedTextureShader::postConstructor( )
{
        setMPSafe(false);
}
hwManagedTextureShader::hwManagedTextureShader()
{
}
hwManagedTextureShader::~hwManagedTextureShader()
{
}
void * hwManagedTextureShader::creator()
{
    return new hwManagedTextureShader();
}
MStatus hwManagedTextureShader::initialize()
{
    return MS::kSuccess;
}
MStatus 
hwManagedTextureShader::glBind(const MDagPath& path)
{
        
        
        glPushAttrib(GL_LIGHTING_BIT);
        lightingOn = glIsEnabled(GL_LIGHTING);
        if (lightingOn)
        {
                glEnable(GL_COLOR_MATERIAL);
                glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
        }
        
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        
#if MAYA_API_VERSION >= 800
        MObject object = path.node();
        MFnMesh mesh(object);
        MString uvSetName("map1");
        MObjectArray textures;
        boundTexture = false;
        MStatus status = mesh.getAssociatedUVSetTextures(uvSetName, textures);
        if (status == MS::kSuccess && textures.length())
        {
                MImageFileInfo::MHwTextureType hwType;
                if (MS::kSuccess == MHwTextureManager::glBind( textures[0], hwType ))
                {
                        boundTexture = true;
                }
        }
        if( !boundTexture)
        {
                glDisable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, 0);
        }
#else
        
        
        static GLuint id = 0;
        if (id == 0)
        {
                MImage fileImage;
                MStatus status = fileImage.readFromFile("<change file name here>");
                glGenTextures(1, &id);
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, id);
                GLuint width, height;
        fileImage.getSize( width, height);
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, fileImage.pixels());
        }
        else
        {
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, id);
        }
        boundTexture = true;
#endif
        if( boundTexture)
        {
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
        glEnableClientState(GL_VERTEX_ARRAY);
        return MS::kSuccess;
}
MStatus 
hwManagedTextureShader::glUnbind(const MDagPath& shapePath)
{
        
        
        glDisableClientState(GL_VERTEX_ARRAY);
        if (lightingOn)
        {
                glDisable(GL_COLOR_MATERIAL);
                glDisableClientState(GL_NORMAL_ARRAY);
        }
        if (boundTexture)
        {
                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
                glDisable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, 0);
        }
        
        
        glPopAttrib();
    return MS::kSuccess;
}
bool
hwManagedTextureShader::supportsBatching() const
{
        return true;
}
MStatus hwManagedTextureShader::glGeometry( const MDagPath& path,
                                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)
{
        glVertexPointer ( 3, GL_FLOAT, 0, &vertexArray[0] );
        if (boundTexture && texCoordCount && texCoordArrays[0] != NULL)
        {
                glEnableClientState( GL_TEXTURE_COORD_ARRAY );
                glTexCoordPointer( 2, GL_FLOAT, 0, &texCoordArrays[0][0] );
        }
        else
        {
                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
        }
        if (lightingOn && normalCount && normalArrays[0][0])
        {
                
                glEnableClientState(GL_NORMAL_ARRAY);
                glNormalPointer ( GL_FLOAT, 0, &normalArrays[0][0] );
        }
        else
        {
                glDisableClientState( GL_NORMAL_ARRAY );
        }
        glDrawElements ( prim, indexCount, GL_UNSIGNED_INT, indexArray );
        return MS::kSuccess;
}
int     hwManagedTextureShader::texCoordsPerVertex()
{
        return 1;
}
int     hwManagedTextureShader::normalsPerVertex()
{
        return 1;
}
MStatus initializePlugin( MObject obj )
{ 
        MStatus   status;
        const MString UserClassify( "shader/surface/utility/" );
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "8.0", "Any");
        status = plugin.registerNode("hwManagedTextureShader",
                                                                 hwManagedTextureShader::id, 
                                                                 hwManagedTextureShader::creator,
                                                                 hwManagedTextureShader::initialize,
                                                                 MPxNode::kHwShaderNode, &UserClassify );
        CHECK_MSTATUS(status);
        return status;
}
MStatus uninitializePlugin( MObject obj )
{
        MStatus   status;
        MFnPlugin plugin( obj );
        status = plugin.deregisterNode( hwManagedTextureShader::id );
        CHECK_MSTATUS(status);
        return status;
}