/*
	An example based on the per-particle code.  In this example a 2D array is loaded
	with a figure, and the figure is then rotated in screen space by showing each
	point by choosing the point a given number of pixels to the right -- except that
	those points within a given space are gotten by choosing a point that many pixels
	to the left.  This gives the impression of two sets of points that move in opposite
	directions.  This technique should allow the viewer to identify the space.
   
	Example to show the importance of motion in perception.

	Source file to be used with
	Cunningham, Computer Graphics: Programming in OpenGL for Visual Communication, Prentice-Hall, 2007

	Intended for class use only
*/
#include <GLUT/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

// function prototypes
void myinit(void);
void fillSourceArray(void);
int isInside(int,int);
void display( void );
void reshape(int w,int h);
void keyboard(unsigned char key, int x, int y);
void animate(void);

#define SIZE 500

float myColor[3];
int sourceArray[SIZE][SIZE];
int step;
int stepsize = 1;

void myinit(void)
{ 
	fillSourceArray();
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	gluOrtho2D(0.,(float)SIZE,0.,(float)SIZE);	
}

/*
	function to fill the source array for the base to be shifted.
	This version is simplistic and fills an integer array with 0|1
	whereas more sophisticated (e.g. color) arrays could easily be
	used instead.
*/
void fillSourceArray(void)
{
	int i, j;
	
	for (i=0; i<SIZE; i++) {
		for (j=0; j<SIZE; j++) {
			sourceArray[i][j] = random()%2;
		}
	}
}

/*
	Function to determine the region to be shown with contrasting motion.  The
	original version is a simple circle, but this can be replaced by many kinds
	of regions and tests.
*/
int isInside(int i, int j)
{
	if ( (i-SIZE/2)*(i-SIZE/2) + (j-SIZE/2)*(j-SIZE/2) < SIZE*SIZE/6 ) return 1;
	else return 0;
}

void display( void )
{
	int i, j;
	float c[3];
	
	glBegin(GL_POINTS);
		for (i=0; i<SIZE; i++) {
			for (j=0; j<SIZE; j++) {
				if (isInside(i,j))
					c[0] = c[1] = c[2] = (float)sourceArray[i][(j+step)%SIZE];
				else
					c[0] = c[1] = c[2] = (float)sourceArray[i][(j-step)%SIZE];
				glColor3f(c[0], c[1], c[2]);
				glVertex2f( (float)(j), (float)(i) );
			}
		}
	glEnd();
    glutSwapBuffers();
 }

void reshape(int w,int h)
{
        glViewport(0,0,(GLsizei)w,(GLsizei)h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
		gluOrtho2D(0.,(float)SIZE,0.,(float)SIZE);
}

void keyboard(unsigned char key, int x, int y)
{
	stepsize = 1 - stepsize;
	glutPostRedisplay();
}

void animate(void)
{ 
	step += stepsize;
	step %= SIZE;
	//printf("%i\n", step);
	glutPostRedisplay();
}

int main(int argc, char** argv)
{
/* Standard GLUT initialization */
	glutInit(&argc,argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(SIZE,SIZE);
	glutInitWindowPosition(70,70);
	glutCreateWindow("Find the shape from the motion");
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutIdleFunc(animate);
	glutKeyboardFunc(keyboard);

	myinit();

	glutMainLoop();
}
