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

// This plugin uses OpenGL to capture the current 3D view to a ppm file.
//
// To use it, give it a filename as an argument into which the PPM image
// of the current view should be written.
//
// Limitations:
//  - any parts of other X windows that are obscuring the view
//    will be captured rather than the view underneath.  This is
//    an effect of the OpenGL buffer system on SGIs.
// 
//  - colour index mode buffers cannot be read by this plugin, so
//    the view should be set to shaded mode before doing the capture.
//    It is posible to read an OpenGL colour index mode buffer, but it
//    is more complicated, and is therefore an exercise left to the
//    readers.

#include "viewCapturePPM.h"   // PPM routines

#include <maya/MSimple.h>
#include <maya/MObject.h>
#include <maya/MGlobal.h> 
#include <maya/M3dView.h> 

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

#include <stdlib.h>
#include <maya/MIOStream.h>

DeclareSimpleCommand( viewCapture, PLUGIN_COMPANY, "3.0")

MStatus viewCapture::doIt( const MArgList& args )
{
    MStatus status = MS::kSuccess;

    if ( args.length() != 1 ) {
        // Need the file name argument
        //
        return MS::kFailure;
    }

    MString fileName;
    args.get( 0, fileName );

    // Get the active 3D view
    //
    M3dView view = M3dView::active3dView();

    // Capture the current view
    //
    view.refresh();
    view.beginGL();
 
    // Set the target for our pixel read to be the front buffer.  First, the
    // current state is saved using the glPushAttrib call.  It is important
    // to leave the OpenGL in the same state that we found it.
    //
    glPushAttrib( GL_PIXEL_MODE_BIT ); 

    int width = view.portWidth();
    int height = view.portHeight(); 

    // Allocate buffers for the pixel data
    //
    GLfloat * red   = new GLfloat[width*height];
    GLfloat * green = new GLfloat[width*height];
    GLfloat * blue  = new GLfloat[width*height];

    // Read the values from the OpenGL frame buffer
    //
    glReadBuffer( GL_FRONT );
    glReadPixels( 0, 0, width, height, GL_RED, GL_FLOAT, red );
    glReadPixels( 0, 0, width, height, GL_GREEN, GL_FLOAT, green );
    glReadPixels( 0, 0, width, height, GL_BLUE, GL_FLOAT, blue );
    
    // Put the gl read target back
    //
    glPopAttrib(); 

    view.endGL();

    // Write file as a PPM
    //
    Pic_Pixel * line = PixelAlloc( width );
    int idx;

    Pic * file = PicOpen( fileName.asChar(), (short) width, (short) height );
    if ( NULL != file ) { 
        for ( int row = height - 1; row >= 0; row-- ) {
            // Covert the row of pixels into PPM format
            //
            for ( int col = 0; col < width; col++ ) {
                // Find the array elements for this pixel
                //
                idx = ( row * width ) + ( col );
                line[col].r = (Pic_byte)( red[idx]   * 255.0 );
                line[col].g = (Pic_byte)( green[idx] * 255.0 );
                line[col].b = (Pic_byte)( blue[idx] * 255.0 );
            }
            // Write the line
            //
            if ( !PicWriteLine( file, line ) ) {
                status = MS::kFailure; 
                return MS::kFailure;
            }
        }
        PicClose( file ); 
    }
 
    delete []red;
    delete []green;
    delete []blue;
    PixelFree( line );

    return status;
}