/* first mark the polygon by clicking (left). once done, 
use right click to finish marking polygon. 
left click on any pixel to fill that area. */
/* do not resize the screen..... do not change the world coordinates either */
/* This program fills a white area with green, considering the bounds if any */

#include <GL/glut.h>
#include <stdio.h>

GLfloat displayBuffer[400][400][3] = {};
int pointsSpecified = 0;
GLint currentPoint[2];
GLint firstPoint[2];
GLint fillPixel[2];

void myInit () {
	
	int i, j;
	glClearColor (1.0, 1.0, 1.0, 1.0);
	glColor3f (0.0, 0.0, 0.0);
	
	glPointSize (2);
	glLineWidth (2);
	
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity();
	glOrtho (0.0, 400.0, 0.0, 400.0, 0.0, 400.0);
	glMatrixMode (GL_MODELVIEW);
	
	for (i = 0; i < 400; i++)
		for (j = 0; j < 400; j++)
			displayBuffer[i][j][0] = displayBuffer[i][j][1] = displayBuffer[i][j][2] = 1.0;
}

void display () {

	glClear (GL_COLOR_BUFFER_BIT);
	glDrawPixels (400, 400, GL_RGB, GL_FLOAT, displayBuffer);
	
	glFlush();
}

void fillArea (int x, int y) {
	
	/* fill white area with green*/
	
	/* Using a recursive function, i.e a stack (syllabus specifies that we
	use "appropriate data structures... */
	/* This is not a line based filling, just fills the area pixel by pixel. */
	
	/* NOTE: array access is made as array[y][x] and not array[x][y]. 
	Here is what the manual says:
	"glReadPixels() returns values from each pixel with lower left cornet at 
	(x+i, y+j) for 0 <= j < height. This pixel is said to be the ith pixel 
	in the jth row. Pixels are returned in row order from the lowest to the
	highest row, left to right in each row."
	the 'x' and 'y' in the above manual lines are the first two arguments of 
	glReadPixels(), not the arguments to this function.
	*/
	if (displayBuffer[y][x][0] == 1.0 && displayBuffer[y][x][1] == 1.0
		&& displayBuffer[y][x][2] == 1.0) {
		
		displayBuffer[y][x][0] = 0, displayBuffer[y][x][1] = 1, displayBuffer[y][x][2] = 0;
		if (x+1 < 400)
			fillArea (x+1, y);
		if (y+1 < 400)
			fillArea (x, y+1);
		if (x-1 >= 0)
			fillArea (x-1, y);
		if (y-1 >= 0)
			fillArea (x, y-1);
	}
}

void mouseReact (int button, int state, int x, int y) {
	
	glColor3f (0.0, 0.0, 0.0);
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && pointsSpecified != -1) {
		if (pointsSpecified == 0) {
			pointsSpecified++;
			currentPoint[0] = x;
			currentPoint[1] = 400-y;
			firstPoint[0] = x;
			firstPoint[1] = 400-y;
			glBegin (GL_POINTS);
			glVertex2i (x, 400-y);
			glEnd();
			glFlush();
		}
		else if (pointsSpecified > 0) {
			glBegin (GL_LINES);
				glVertex2i (currentPoint[0], currentPoint[1]);
				currentPoint[0] = x;
				currentPoint[1] = 400-y;
				glVertex2i (currentPoint[0], currentPoint[1]);
			glEnd();
			glFlush();
		}
	}
	
	/* to select the pixel for filling the area */
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && pointsSpecified == -1) {
		fillPixel[0] = x;
		fillPixel[1] = 400-y;
		fillArea (fillPixel[0], fillPixel[1]);
		pointsSpecified = -2;
		glutPostRedisplay();
	}

	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
		/* close the polygon. */
		if (pointsSpecified != -2)
			pointsSpecified = -1;
		glBegin (GL_LINES);
			glVertex2i (currentPoint[0], currentPoint[1]);
			glVertex2i (firstPoint[0], firstPoint[1]);
		glEnd();
		glFlush();
		
		/* Now read the display buffer to displayBuffer[] for further
		processing. */
		glReadPixels (0, 0, 400, 400, GL_RGB, GL_FLOAT, displayBuffer);
	}
}


int main (int argc, char *argv[]) {

	glutInit (&argc, argv);
	glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
	glutCreateWindow ("Fill:");
	glutInitWindowSize (400, 400);
	glutInitWindowPosition (0, 0);
	glutDisplayFunc (display);
	glutMouseFunc (mouseReact);
	glutReshapeWindow (400, 400);
	myInit ();
	glutMainLoop();
	
	return 0;
}
