//-
// ==========================================================================
// 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;
}




