hwRenderPostEffect.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

//
// DESCRIPTION: 
//      This is an example of adding processing
//      effects to the hardware renderer.
//

#ifdef WIN32
#pragma warning( disable : 4786 )       // Disable STL warnings.
#endif

#include <maya/MIOStream.h> 
#include <maya/MString.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFnPlugin.h>


#include <maya/MDrawProcedureBase.h>
#include <maya/MHardwareRenderer.h>

#include <stdio.h>

#if defined(OSMac_MachO_)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif

class hwRenderEffect : public MDrawProcedureBase
{
public:
                    hwRenderEffect();
    virtual         ~hwRenderEffect();

    virtual bool execute();

    static void deleteEffect( hwRenderEffect * ePtr);   
    static MDrawProcedureBase *createEffect( const MString &name, 
                            hwRenderEffect *ePtr,
                            MHardwareRenderer::CallLocation location);


    MHardwareRenderer::CallLocation mLocation;
};


hwRenderEffect::hwRenderEffect()
{
}

hwRenderEffect::~hwRenderEffect()
{
    // No-op
}

void
hwRenderEffect::deleteEffect( hwRenderEffect * ePtr) 
{
    if (ePtr)
    {
        MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
        if (pRenderer)
        {
            const MString & backEndStr = pRenderer->backEndString();
            MHardwareRenderer::DrawProcedureStatusCode result = 
                pRenderer->removeDrawProcedure( backEndStr, ePtr, ePtr->mLocation );
            cout<<"Call hwRenderEffect::deleteEffect("<<ePtr->fName.asChar()
                <<") loc("<<ePtr->mLocation
                <<") = "<<result<<endl;
        }
        delete ePtr;
        ePtr = 0;
    }
}

/*static*/
MDrawProcedureBase *
hwRenderEffect::createEffect( const MString &name, 
                            hwRenderEffect *ePtr,
                            MHardwareRenderer::CallLocation location)
{
    MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
    if (pRenderer)
    {
        if (!ePtr)
        {
            ePtr = new hwRenderEffect();
            ePtr->setEnabled( true );
            ePtr->setName( name );  
            ePtr->mLocation = location;

            const MString & backEndStr = pRenderer->backEndString();
            MHardwareRenderer::DrawProcedureStatusCode result = 
                pRenderer->addDrawProcedure( backEndStr, ePtr, location );
            cout<<"Call hwRenderEffect::createEffect("<<ePtr->name().asChar()
                <<") loc("<<ePtr->mLocation
                <<") = "<<result<<endl;
        }
    }
    return (MDrawProcedureBase *)ePtr;
}

/* virtual */
bool
hwRenderEffect::execute()
{
    MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
    if (!pRenderer)
        return false;

    const MString & backEndStr = pRenderer->backEndString();
    unsigned int width = 0, height = 0;

    MStatus stat = 
        pRenderer->getBufferSize( backEndStr, width, height );
    if (width <= 0 || height <= 0)
        return false;

    unsigned int exposureNum;
    unsigned int totalExposureCount;
    pRenderer->getCurrentExposureNumber( backEndStr, exposureNum );
    pRenderer->getTotalExposureCount( backEndStr, totalExposureCount );

    // Perform some post-rendering. Invert the image.
    bool xxxx = true;
    if ( xxxx && mLocation == MHardwareRenderer::kPostRendering )
    {
        cout<<"Call EXP["<<exposureNum<<"/"<<totalExposureCount
            <<"] hwRenderEffect::execute("<<width<<", "<<height
            <<") -- "<<fName.asChar()<<endl;

        MHardwareRenderer::BufferPixelFormat colFmt;
        stat = pRenderer->getColorBufferPixelFormat( backEndStr, colFmt );
        void *pixels = 0;
        unsigned int data_type = GL_UNSIGNED_BYTE; 
        unsigned int format = GL_RGBA;

        unsigned int totalSize = width*height*4;

        if (totalSize == 0)
            return false;

        if (colFmt == MHardwareRenderer::kRGBA_Fix8)
        {
            data_type = GL_UNSIGNED_BYTE; 
            format = GL_RGBA;
            pixels = new unsigned char[totalSize];
        }
#ifdef _SUPPORT_16_FLOAT_
        else if (MHardwareRenderer::kRGBA_Float16)
        {       
            data_type = GL_HALF_FLOAT; 
            format = GL_RGBA;
            pixels = new half[totalSize];
        }
#endif
        glPushAttrib(GL_ALL_ATTRIB_BITS); 

        glMatrixMode(GL_PROJECTION);    
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glPixelZoom( 1.0f, 1.0f );
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
        glReadPixels(0, 0, width, height, format, data_type, pixels);

        unsigned char *pixelPtr = (unsigned char*)pixels;
        if (pixelPtr)
        {
            unsigned int numPixels = width * height;
            for (unsigned int i=0; i < numPixels; i++)
            {
                *pixelPtr = (255 - *pixelPtr);  
                pixelPtr++;
                *pixelPtr = (255 - *pixelPtr);  
                pixelPtr++;         
                *pixelPtr = (255 - *pixelPtr);  
                pixelPtr++;
                *pixelPtr = 255;    
                pixelPtr++;
            }
        }

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glRasterPos2i( -1, -1 );

        // We only want to clobber RGB. Leave alpha as is.
        glColorMask( 1, 1, 1, 0 );

        // For orthographic views, we need to make sure that depth
        // test is disabled, otherwise the pixels will not draw.
        glDisable(GL_DEPTH_TEST);

        glDrawPixels(width, height, format, data_type, pixels); 

        if (pixels)
        {
            if (colFmt == MHardwareRenderer::kRGBA_Fix8)
            {
                unsigned char *pixelPtr2 = (unsigned char*)pixels;
                delete[] pixelPtr2;
            }
#ifdef _SUPPORT_16_FLOAT_
            else
            {
                half pixelPtr2 = (half*)pixels;
                delete[] pixelPtr2;
            }
#endif
        }


        glPopAttrib();
    }
    else
    {
        // Perform some pre-rendering, pre-exposure. Draw coloured
        // triangles.
        if ( (mLocation == MHardwareRenderer::kPreRendering ) ||
             ( mLocation == MHardwareRenderer::kPreExposure) )
        {
            cout<<"Call EXP["<<exposureNum<<"/"<<totalExposureCount
                <<"] hwRenderEffect::execute("<<width<<", "<<height
                <<") -- "<<fName.asChar()<<endl;

            glPushAttrib(GL_ALL_ATTRIB_BITS); 

            glMatrixMode(GL_PROJECTION);    
            glLoadIdentity();
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();

            glShadeModel(GL_SMOOTH);
            glDisable(GL_DEPTH_TEST);
            glEnable(GL_BLEND);
            glBlendFunc(GL_ONE, GL_ZERO);

            glColorMask( 1, 1, 1, 0 );
            glBegin(GL_QUADS);
            glColor4f(1.0f,1.0f,1.0f,0.5f);
            glVertex3f( -1.0f, 1.0f, 0.0f);
            glColor4f(0.0f,1.0f,1.0f,0.5f);
            glVertex3f( 0.0f, 1.0f, 0.0f);
            glColor4f(0.0f,1.0f,1.0f,0.5f);
            glVertex3f(-1.0f,-1.0f, 0.0f);
            glColor4f(1.0f,0.0f,1.0f,0.5f);
            glVertex3f( 1.0f,-1.0f, 0.0f);
            glEnd();

            glEnable(GL_DEPTH_TEST);
            glDisable(GL_BLEND);

            glPopAttrib();

        }

        // Do some post exposure. Nothing for now...
        else if ( mLocation == MHardwareRenderer::kPostExposure )
        {
            cout<<"Call EXP["<<exposureNum<<"/"<<totalExposureCount
                <<"] hwRenderEffect::execute("<<width<<", "<<height<<") -- POST-EXPOSURE"<<endl;
        }
    }

    return true;
}

// Four callback classes.
static hwRenderEffect *fsPreRender = 0;
static hwRenderEffect *fsPreExposure = 0;
static hwRenderEffect *fsPostExposure = 0;
static hwRenderEffect *fsPostRender = 0;

MStatus initializePlugin( MObject obj )
{ 
    MStatus   status = MS::kSuccess;
    
    MFnPlugin plugin( obj, PLUGIN_COMPANY, "7.0", "Any");

    // Register the callbacks.
    fsPreRender = (hwRenderEffect *)hwRenderEffect::createEffect(MString("PRE-RENDER"), fsPreRender, MHardwareRenderer::kPreRendering );
    fsPreExposure = (hwRenderEffect *)hwRenderEffect::createEffect(MString("PRE-EXPOSURE"), fsPreExposure, MHardwareRenderer::kPreExposure );
    fsPostExposure = (hwRenderEffect *)hwRenderEffect::createEffect(MString("POST-EXPOSURE"), fsPostExposure, MHardwareRenderer::kPostExposure );
    fsPostRender = (hwRenderEffect *)hwRenderEffect::createEffect(MString("POST-RENDER"), fsPostRender, MHardwareRenderer::kPostRendering );
    return status;
}

MStatus uninitializePlugin( MObject obj )
{
    MStatus   status = MS::kSuccess;
    
    // Unregister the callbacks.
    hwRenderEffect::deleteEffect(fsPreRender);
    fsPreRender = 0;
    hwRenderEffect::deleteEffect(fsPreExposure);
    fsPreExposure = 0;
    hwRenderEffect::deleteEffect(fsPostExposure);
    fsPostExposure = 0;
    hwRenderEffect::deleteEffect(fsPostRender);
    fsPostRender = 0;

    MFnPlugin plugin( obj );

    return status;
}