
#ifndef PROJECTIONS_H
#define PROJECTIONS_H

float ProjColors[16][3] = {
		{ 1.0, 0.0, 0.0 },
		{ 0.0, 1.0, 0.0 }, 
		{ 0.0, 0.0, 1.0 }, 
		{ 1.0, 1.0, 0.0 }, 
		{ 0.0, 1.0, 1.0 }, 
		{ 1.0, 0.0, 1.0 }, 
		{ 1.0, 0.5, 0.0 }, 
		{ 0.0, 0.5, 1.0 }, 
		{ 0.5, 1.0, 0.0 }, 
		{ 0.5, 0.0, 1.0 }, 
		{ 0.0, 1.0, 0.5 }, 
		{ 0.1, 0.0, 0.5 }, 
		{ 0.5, 0.5, 1.0 }, 
		{ 1.0, 0.5, 0.5 }, 
		{ 0.5, 1.0, 0.5 }, 
		{ 0.6, 0.3, 1.0 } };

class Projection {

public:

	float x , y , size;
	static int currentlegend;
	static int cue;

	signed char mat[512][512];
	unsigned char cuefriends[512][512];
	static int region_growing[4096][2];
	static int begin_grow;
	static int end_grow;

	Projection() {
		int i, j;
		for (i=0;i<512;i++) {
			for (j=0;j<512;j++) {
				mat[i][j] = (signed char)-1;
				cuefriends[i][j] = (unsigned char)0;
				region_growing[i][j] = 0;
			}
		}
	};


	void DisplayLegend() {
		int i;
		char buffer[32];

		// display label
		strcpy(buffer,"regions");
		glColor3f(0.0,0.0,0.0);
		for (i=0;i<strlen(buffer);i++) {
			glRasterPos2f(0.1+0.2*(float)i,1.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}

		// display region colors
		glBegin(GL_QUADS);
		for (i=0;i<8;i++) {
			glColor3f(ProjColors[i][0],ProjColors[i][1],ProjColors[i][2]);
			glVertex3f(0.1,2.1+(float)i,0.0);
			glVertex3f(0.1,1.9+(float)(i+1),0.0);
			glVertex3f(0.9,1.9+(float)(i+1),0.0);
			glVertex3f(0.9,2.1+(float)i,0.0);
		}
		glEnd();

		// edit axes mode

		glLineWidth(2);

		glColor3f(0.5,0.5,0.5);
		glBegin(GL_LINES);
		glVertex2f(0.1,10.1); glVertex2f(0.1,10.9);
		glVertex2f(0.9,10.1); glVertex2f(0.9,10.9);
		glVertex2f(0.1,10.1); glVertex2f(0.9,10.1);
		glVertex2f(0.1,10.9); glVertex2f(0.9,10.9);
		glVertex2f(0.5,10.5); glVertex2f(0.8,10.8);
		glVertex2f(0.5,10.5); glVertex2f(0.2,10.2);
		glVertex2f(0.5,10.5); glVertex2f(0.2,10.8);
		glVertex2f(0.5,10.5); glVertex2f(0.8,10.2);
		glEnd();
		
		strcpy(buffer,"axes");
		glColor3f(0.0,0.0,0.0);
		for (i=0;i<strlen(buffer);i++) {
			glRasterPos2f(1.1+0.2*(float)i,10.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
	
		// edit endpoint mode
		glColor3f(0.5,0.5,0.5);
		glBegin(GL_LINES);
		glVertex2f(0.1,11.1); glVertex2f(0.1,11.9);
		glVertex2f(0.9,11.1); glVertex2f(0.9,11.9);
		glVertex2f(0.1,11.1); glVertex2f(0.9,11.1);
		glVertex2f(0.1,11.9); glVertex2f(0.9,11.9);
		glVertex2f(0.3,11.3); glVertex2f(0.8,11.8);
		glEnd();
		glPointSize(3);
		glBegin(GL_POINTS);
		glVertex2f(0.3,11.3);
		glEnd();

		strcpy(buffer,"tree");
		glColor3f(0.0,0.0,0.0);
		for (i=0;i<strlen(buffer);i++) {
			glRasterPos2f(1.1+0.2*(float)i,11.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}

		// blank region mode
		glColor3f(0.5,0.5,0.5);
		glBegin(GL_LINES);
		glVertex2f(0.1,12.1); glVertex2f(0.1,12.9);
		glVertex2f(0.9,12.1); glVertex2f(0.9,12.9);
		glVertex2f(0.1,12.1); glVertex2f(0.9,12.1);
		glVertex2f(0.1,12.9); glVertex2f(0.9,12.9);
		glEnd();

		strcpy(buffer,"blank");
		glColor3f(0.0,0.0,0.0);
		for (i=0;i<strlen(buffer);i++) {
			glRasterPos2f(1.1+0.2*(float)i,12.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
		
		// select friends mode
		glBegin(GL_QUADS);
		glColor3f(0.5,0.5,0.5);
		glVertex3f(0.1,13.1,0.0);
		glVertex3f(0.1,13.9,0.0);
		glVertex3f(0.9,13.9,0.0);
		glVertex3f(0.9,13.1,0.0);
		glEnd();

		strcpy(buffer,"cues");
		glColor3f(0.0,0.0,0.0);
		for (i=0;i<strlen(buffer);i++) {
			glRasterPos2f(1.1+0.2*(float)i,13.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}

		if (cue > 0) {
			glColor3f(0.0,0.0,0.2);
			glBegin(GL_LINES);
			glVertex2i(0,13); glVertex2i(1,13);
			glVertex2i(1,14); glVertex2i(0,14);
			glVertex2i(1,13); glVertex2i(1,14);
			glVertex2i(0,13); glVertex2i(0,14);
			glEnd();
		}

		// label zoom window
		strcpy(buffer,"zoom / parallel");
		if (zoomparmode==0) {
			glColor3f(1.0,0.0,0.0);
		} else {
			glColor3f(0.0,0.0,0.0);
		}
		for (i=0;i<4;i++) {
			glRasterPos2f(2.5+0.2*(float)i,13.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
		glColor3f(0.0,0.0,0.0);
		for (i=4;i<6;i++) {
			glRasterPos2f(2.5+0.2*(float)i,13.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
		if (zoomparmode==1) {
			glColor3f(1.0,0.0,0.0);
		} else {
			glColor3f(0.0,0.0,0.0);
		}
		for (i=6;i<16;i++) {
			glRasterPos2f(2.5+0.2*(float)i,13.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
/*
		glColor3f(0.0,0.0,0.0);
		for (i=16;i<18;i++) {
			glRasterPos2f(2.5+0.2*(float)i,13.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
		if (zoomparmode==2) {
			glColor3f(1.0,0.0,0.0);
		} else {
			glColor3f(0.0,0.0,0.0);
		}
		for (i=18;i<strlen(buffer);i++) {
			glRasterPos2f(2.5+0.2*(float)i,13.3);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,buffer[i]);
		}
*/
		// display current mode
		glColor3f(0.0,0.0,0.5);
		glBegin(GL_LINES);
		glVertex2i(0,currentlegend+2); glVertex2i(1,currentlegend+2);
		glVertex2i(1,currentlegend+3); glVertex2i(0,currentlegend+3);
		glVertex2i(1,currentlegend+2); glVertex2i(1,currentlegend+3);
		glVertex2i(0,currentlegend+2); glVertex2i(0,currentlegend+3);
		glEnd();



	};

	void check_and_add(int i, int j, int r) {
		if ((i>=0) && (j>=0) && (i<512) && (j<512)) {
			if (mat[i][j] < (signed char)0) {
				mat[i][j] = (signed char)r;
				region_growing[end_grow][0] = i;
				region_growing[end_grow][1] = j;
				if (end_grow < 4095) {
					end_grow++;
				} else {
					end_grow = 0;
				}
			}
		}
	};

	void GrowRegion(int x, int y, int r) {
		int i, j;
		region_growing[0][0] = x;
		region_growing[0][1] = y;
		mat[x][y] = (signed char)r;
		while ((end_grow != begin_grow + 1) && ((end_grow!=0)||(begin_grow!=4095))) {
			i = region_growing[begin_grow][0];
			j = region_growing[begin_grow][1];
			check_and_add(i+1,j,r);
			check_and_add(i,j+1,r);
			check_and_add(i-1,j,r);
			check_and_add(i,j-1,r);
			if (begin_grow < 4095) {
				begin_grow++;
			} else {
				begin_grow = 0;
			}
		}
	};

	void MarkAndDisplay(int fromx, int fromy, int tox, int toy, int size, int region) {
		int top, bottom;
		int i, j, left, right;
		int diffto, difffrom;
		int temp;
		// find top and bottom
		if (fromy>toy) {
			top = fromy+size;
			bottom = toy-size;
		} else {
			top = toy+size;
			bottom = fromy-size;
		}
		// from bottom to top, find the leftmost and rightmost
		for (i=bottom;i<=top;i++) {
			// ******************** candidate leftmost **************************************
			left = 512;
			// 1. left edge of to-box
			if ((i>=toy-size)&&(i<=toy+size)) left = tox-size;
			// 2. left edge of from-box
			if ((i>=fromy-size)&&(i<=fromy+size)&&(fromx-size<left)) left = fromx-size;
			// 3. linear interpolation of bottom-left corners
			if (i<top-size-size) {
				diffto = i-(toy-size);
				if (diffto<0) diffto = -diffto;
				difffrom = i-(fromy-size);
				if (difffrom<0) difffrom = -difffrom;
				temp = (diffto * (fromx-size) + difffrom * (tox-size)) / (diffto + difffrom);
				if (temp<left) left = temp;
			}
			// 4. linear interpolation of top-left corners
			if (i>bottom+size+size) {
				diffto = i-(toy+size);
				if (diffto<0) diffto = -diffto;
				difffrom = i-(fromy+size);
				if (difffrom<0) difffrom = -difffrom;
				temp = (diffto * (fromx-size) + difffrom * (tox-size)) / (diffto + difffrom);
				if (temp<left) left = temp;
			}
			// ******************** candidate rightmost *************************************
			right = 0;
			// 1. right edge of to-box
			if ((i>=toy-size)&&(i<=toy+size)) right = tox+size;
			// 2. right edge of from-box
			if ((i>=fromy-size)&&(i<=fromy+size)&&(fromx+size>right)) left = fromx+size;
			// 3. linear interpolation of bottom-right corners
			if (i<top-size-size) {
				diffto = i-(toy-size);
				if (diffto<0) diffto = -diffto;
				difffrom = i-(fromy-size);
				if (difffrom<0) difffrom = -difffrom;
				temp = (diffto * (fromx+size) + difffrom * (tox+size)) / (diffto + difffrom);
				if (temp>right) right = temp;
			}
			// 4. linear interpolation of top-right corners
			if (i>bottom+size+size) {
				diffto = i-(toy+size);
				if (diffto<0) diffto = -diffto;
				difffrom = i-(fromy+size);
				if (difffrom<0) difffrom = -difffrom;
				temp = (diffto * (fromx+size) + difffrom * (tox+size)) / (diffto + difffrom);
				if (temp>right) right = temp;
			}
			// ******************** mark all the pixels **************************************		
			glPointSize(1);
			for (j=left;j<=right;j++) {
				if ((i>=0)&&(i<512)&&(j>=0)&&(j<512)) {
					if (cue > 0) {
						if (region>0) {
							if (mat[j][i] != (signed char)region) cuefriends[j][i] |= (1 << region);
							glColor4f(0.5,0.5,0.5,0.6);
							glBegin(GL_POINTS);
							glVertex3f((float)j,(float)i,0.3);
							glEnd();
						} else { // erase mode
							cuefriends[j][i] &= (0 << region);
							glColor4f(0.0,0.0,0.0,0.6);
						}

					} else {
						if (region>0) {
							mat[j][i] = (signed char)region;
							glColor4f(ProjColors[region][0],ProjColors[region][1],ProjColors[region][2],0.5);
						} else { // erase mode
							mat[j][i] = (signed char)-1;
							glColor4f(0.0,0.0,0.0,0.6);
						}
						glBegin(GL_POINTS);
						glVertex3f((float)j,(float)i,0.3);
						glEnd();
					}
				}
			}
		}
	};

		
	void Display(int pointsize) {
		int i, j;
		int localregion;
		unsigned char localfriend;
		glPointSize(pointsize);
		for (i=0;i<512;i++) {
			for (j=0;j<512;j++) {
				localregion = mat[i][j];
				localfriend = cuefriends[i][j];
				if (cue > 0) { // if setting cue, then display only one region
					if (localregion==region) { // display the region
						glColor4f(ProjColors[localregion][0],ProjColors[localregion][1],ProjColors[localregion][2],0.5);
						glBegin(GL_POINTS);
						glVertex3f((float)i,(float)j,-0.2);
						glEnd();
					} else if (((localfriend >> region) & 1) > 0) { // display the cue region in grey
						glColor4f(0.5,0.5,0.5,0.5);
						glBegin(GL_POINTS);
						glVertex3f((float)i,(float)j,-0.2);
						glEnd();
					}
				} else if (localregion>=0) {
					glColor4f(ProjColors[localregion][0],ProjColors[localregion][1],ProjColors[localregion][2],0.5);
					glBegin(GL_POINTS);
					glVertex3f((float)i,(float)j,-0.2);
					glEnd();
				}
			}
		}
	};

};

#endif

