// 
// Torbert, 8.26.2009
// 
// MPI and OpenGL Integration Demo, Version 1.0
// 
// Four Workers tell the Manager how to color each quadrant of the window.
// 

#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
#include <GL/glut.h>

double xmin,ymin,xmax,ymax;
int w=400,h=300;

// MPI
int rank,size,tag=0;
MPI_Status status;

// colors
double red[5]  ={0.0,1.0,0.0,0.0,1.0};
double green[5]={0.0,0.0,1.0,0.0,1.0};
double blue[5] ={0.0,0.0,0.0,1.0,1.0};

void display(void)
{
	int j;
	double r,g,b,x,y,dx,dy;
	
	dx=(xmin+xmax)/2.0;
	dy=(ymin+ymax)/2.0;
	for(j=1;j<=4;j++) // loop over Workers
	{
		MPI_Recv(&r,1,MPI_DOUBLE,j,tag,MPI_COMM_WORLD,&status);
		MPI_Recv(&g,1,MPI_DOUBLE,j,tag,MPI_COMM_WORLD,&status);
		MPI_Recv(&b,1,MPI_DOUBLE,j,tag,MPI_COMM_WORLD,&status);
		glColor3f(r,g,b);

		x=xmin+dx*((j-1)%2);
		y=ymax-dy*((j-1)/2);
		glBegin(GL_POLYGON);
		glVertex2f(x   ,y   );
		glVertex2f(x+dx,y   );
		glVertex2f(x+dx,y-dy);
		glVertex2f(x   ,y-dy);
		glEnd();
	}
   glutSwapBuffers();
}
void keyfunc(unsigned char key,int xscr,int yscr)
{
	if(key=='q')
	{
		MPI_Finalize();
		exit(0);
	}
}
void reshape(int wscr,int hscr)
{
	w=wscr; h=hscr;
   glViewport(0,0,(GLsizei)w,(GLsizei)h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

	xmin=ymin=0.0; xmax=ymax=1.0;
	if(w<=h)
	   ymax=1.0*(GLfloat)h/(GLfloat)w;
	else
		xmax=1.0*(GLfloat)w/(GLfloat)h;

	gluOrtho2D(xmin,xmax,ymin,ymax);
   glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char* argv[])
{
	MPI_Init(&argc,&argv);
	MPI_Comm_size(MPI_COMM_WORLD,&size);
	MPI_Comm_rank(MPI_COMM_WORLD,&rank);

	if(rank==0) // Only the Manager calls OpenGL commands.
	{
	   glutInit(&argc,argv);
	   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	   glutInitWindowSize(w,h);
	   glutInitWindowPosition(100,50);
	   glutCreateWindow("MPI and OpenGL");
	
	   glutDisplayFunc(display);
		glutIdleFunc(NULL);
		glutKeyboardFunc(keyfunc);
		glutReshapeFunc(reshape);
	
   	glutMainLoop();
	}
	else        // Workers do not call any OpenGL commands.
	{
		MPI_Send(  red+rank,1,MPI_DOUBLE,0,tag,MPI_COMM_WORLD);
		MPI_Send(green+rank,1,MPI_DOUBLE,0,tag,MPI_COMM_WORLD);
		MPI_Send( blue+rank,1,MPI_DOUBLE,0,tag,MPI_COMM_WORLD);
		MPI_Finalize();
	}

	return 0;
}

// 
// Notes
// -----
// chmod 755 Mgcc
// ./Mgcc mpi_opengl_0
// mpirun -np 5 -machinefile hosts.txt mpi_opengl_0
//
// Leave off machinefile option to use automatic file:
//    mpirun -np 5 mpi_opengl_0
// 
