renderViewRenderCmd.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.
// ==========================================================================
//+

#include <maya/MSimple.h>
#include <maya/MIOStream.h>
#include <maya/MRenderView.h>
#include <maya/M3dView.h>
#include <math.h>
#include <maya/MSyntax.h>
#include <maya/MArgDatabase.h>

//
//  renderViewRender command declaration
//
class renderViewRender : public MPxCommand 
{                           
public:                 
    renderViewRender() {};
    ~renderViewRender() {};

    virtual MStatus doIt ( const MArgList& );
    
    static void*    creator();
    
    static MSyntax  newSyntax();
    MStatus parseSyntax (MArgDatabase &argData);

    static const char * cmdName;

private:
    bool doNotClearBackground;              

};                                                  

static const char * kDoNotClearBackground       = "-b";
static const char * kDoNotClearBackgroundLong   = "-background";

const char * renderViewRender::cmdName = "renderViewRender";

void* renderViewRender::creator()                   
{                                                   
    return new renderViewRender;                    
}                                                   

MSyntax renderViewRender::newSyntax()
{
    MStatus status;
    MSyntax syntax;
    syntax.addFlag( kDoNotClearBackground, kDoNotClearBackgroundLong );
    CHECK_MSTATUS_AND_RETURN(status, syntax);
    return syntax;
}

//
// Description:
//      Read the values of the additionnal flags for this command.
//
MStatus renderViewRender::parseSyntax (MArgDatabase &argData)
{
    // Get the flag values, otherwise the default values are used.
    doNotClearBackground = argData.isFlagSet( kDoNotClearBackground );
    
    return MS::kSuccess;
}

//
// Description:
//      register the command
//
MStatus initializePlugin( MObject obj )         
{                                                           
    MFnPlugin   plugin( obj, PLUGIN_COMPANY, "4.5" );   
    MStatus     stat;                                       
    stat = plugin.registerCommand(  renderViewRender::cmdName,
                                    renderViewRender::creator,
                                    renderViewRender::newSyntax);   
    if ( !stat )                                                
        stat.perror( "registerCommand" );                           
    return stat;                                                
}                                                               

//
// Description:
//      unregister the command
//
MStatus uninitializePlugin( MObject obj )                       
{                                                               
    MFnPlugin   plugin( obj );                                  
    MStatus     stat;                                           
    stat = plugin.deregisterCommand( renderViewRender::cmdName );               
    if ( !stat )                                    
        stat.perror( "deregisterCommand" );         
    return stat;                                    
}

RV_PIXEL evaluate(int x, int y)
//
//  Description:
//      Generates a simple procedural circular pattern to be sent to the 
//      Render View.
//
//  Arguments:
//      x, y - coordinates in the current tile (the pattern is centred 
//             around (0,0) ).
//
//  Return Value:
//      An RV_PIXEL structure containing the colour of pixel (x,y).
//
{
    unsigned int distance = (unsigned int) sqrt(double((x*x) + (y*y)));

    RV_PIXEL pixel;
    // Always fully red.
    pixel.r = 255.0f;       
    // Green and blue varies according to the distance.
    pixel.g = pixel.b = 155.0f + (distance % 20) * 5;
    pixel.a = 255.0f;

    return pixel;
}

MStatus renderViewRender::doIt( const MArgList& args )
//
//  Description:
//      Implements the MEL renderViewRender command.  This command
//      Draws a 640x480 tiled pattern of red and white circles into Maya's
//      Render View window.  
//
//  Arguments:
//      args - The argument list that was passed to the command from MEL.
//              -background/-b renders the pattern without clearing the Render View
//
//  Return Value:
//      MS::kSuccess - command succeeded
//      MS::kFailure - command failed (returning this value will cause the 
//                     MEL script that is being run to terminate unless the
//                     error is caught using a "catch" statement.
//
{
    MStatus stat = MS::kSuccess;

    // Check if the render view exists. It should always exist, unless
    // Maya is running in batch mode.
    //
    if (!MRenderView::doesRenderEditorExist())
    {
        setResult( "Cannot renderViewRender in batch render mode. "
                   "Please run in interactive mode, "
                   "so that the render editor exists." );
        return MS::kFailure;
    }
    else
    {
        cout<<"Past doesRenderEditorExist()"<<endl;
    }
    
    // get optional flags
    MArgDatabase    argData( syntax(), args );
    parseSyntax( argData );

    // Pick a camera, and tell the Render View that we will be rendering
    // from its point of view.  Just use the camera for the active 
    // modelling view.  
    //
    M3dView curView = M3dView::active3dView();
    MDagPath camDagPath;
    curView.getCamera( camDagPath );
    cout<<"Rendering camera"<<camDagPath.fullPathName().asChar()<<endl;
    
    if( MRenderView::setCurrentCamera( camDagPath ) != MS::kSuccess )
    {
        setResult( "renderViewRender: error occurred in setCurrentCamera." );
        return MS::kFailure;
    }

    // We'll render a 640x480 image.  Tell the Render View to get ready
    // to receive 640x480 pixels of data.
    //
    unsigned int image_width = 640, image_height = 480;
    if (MRenderView::startRender( image_width, image_height, doNotClearBackground) != MS::kSuccess)
    {
        setResult( "renderViewRender: error occured in startRender." );
        return MS::kFailure;
    }

    // The image will be composed of tiles consisting of circular red and
    // white patterns.
    //
    unsigned int num_side_tiles = 8;
    unsigned int average_tiles_width = image_width / num_side_tiles;
    unsigned int average_tiles_height = image_height / num_side_tiles;
    
    // Draw each tile
    //
    for (unsigned int tile_y = 0; tile_y < num_side_tiles; tile_y++)
    {
        for (unsigned int tile_x = 0; tile_x < num_side_tiles; tile_x++)
        {
            // Find the min/max width/height.
            int min_x = tile_x * average_tiles_width;
            int max_x;

            // If this is the last tile in width, adjust the max position 
            // so that the entire width is covered.
            //
            if ((tile_x+1) == num_side_tiles)
                max_x = image_width-1;
            else
                max_x = (tile_x + 1) * average_tiles_width - 1;
                    
            int min_y = tile_y * average_tiles_height;
            int max_y;

            // If this is the last tile in height, adjust the max position 
            // so that the entire height is covered.
            //
            if ((tile_y+1) == num_side_tiles)
                max_y = image_height-1;
            else
                max_y = (tile_y + 1) * average_tiles_height - 1;
            
            unsigned int tile_width = max_x - min_x + 1; 
            unsigned int tile_height = max_y - min_y + 1;

            // Fill up the pixel array with some the pattern, which is 
            // generated by the 'evaluate' function.  The Render View
            // accepts floating point pixel values only.
            //
            RV_PIXEL* pixels = new RV_PIXEL[tile_width * tile_height];
            unsigned int index = 0;
            for (unsigned int j = 0; j < tile_height; j++ )
            {
                for (unsigned int i = 0; i < tile_width; i++)
                {
                    pixels[index] = evaluate(i - (tile_width / 2), 
                                             j - (tile_height / 2));
                    index++;
                }
            }

            // Send the data to the render view.
            //
            if (MRenderView::updatePixels(min_x, max_x, min_y, max_y, pixels) != MS::kSuccess)
            {
                setResult( "renderViewRender: error occured in updatePixels." );
                delete [] pixels;
                return MS::kFailure;
            }

            delete [] pixels;

            // Force the Render View to refresh the display of the affected 
            // region.
            //
            if (MRenderView::refresh(min_x, max_x, min_y, max_y) != MS::kSuccess)
            {
                setResult( "renderViewRender: error occured in refresh." );
                return MS::kFailure;
            }
        }
    }

    // Inform the Render View that we have completed rendering the entire image.
    //
    if (MRenderView::endRender() != MS::kSuccess)
    {
        setResult( "renderViewRender: error occured in endRender." );
        return MS::kFailure;
    }

    setResult( "renderViewRender completed." );
    return stat;
}