/****************************************************************************
 * file:      survival-kit-variable-windows.c
 * status:    17-aug-2011, wlm.
 *            13-nov-2011, wlm.
 * functie:   OpenGL survival kit with variable windows.
 *            This is a simplefied version of survival-kit-extended
 ****************************************************************************/

#ifdef __APPLE__
  #include <GLUT/glut.h>
#else
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glut.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

/* Default grootte en positie van door OpenGL te maken venster.         */
int WINSIZE_X = 600;   /* grootte in X-richting in pixels               */
int WINSIZE_Y = 400;   /* grootte in Y-richting in pixels               */
int WINPOS_X = 100;    /* standaardpositie van linker                   */
int WINPOS_Y = 100;    /*                      boven  hoek              */

int WINSIZE_X_S = 600; /* standaardgrootte in X-richting in pixels      */
int WINSIZE_Y_S = 400; /* standaardgrootte in Y-richting in pixels      */
int current_size = 0;  /* current window size 0 at start of the program */

/* Default grenzen van gebruikerscoordinaten in door OpenGL te maken venster.*/
float XMIN = -3.0;     /* linksonder  */
float XMAX = 3.0;      /* rechtsboven */
float YMIN = -2.0;     /* linksonder  */
float YMAX = 2.0;      /* rechtsboven */

#define MAXPOINTS 1000 /* Globale array voor het opstaan van de te plotten x- en y-waardes */
float xwaardes[MAXPOINTS];
float ywaardes[MAXPOINTS];

/* Functie declaraties                  */
void progReshape(int w, int h);
void progInit(void);
void printText(float x, float y, char s[]);
void drawLine(float x1, float y1, float x2, float y2);
void drawPoint(float x1, float y1, float pointsize);
void progDisplay(void);
void progReshape(int w, int h);
void progKeyboard(unsigned char key, int x, int y);
/* Voor onderstaande "eigen" functie zie commentaar in main  */
void berekeningPlot(int argc, char** argv);

#define FRAME_TITLE  "Voorbeeld: OpenGL survival kit"

/****************************************************************************
 * Hoofdprogramma.
 ****************************************************************************/
int main(int argc, char** argv) {
	/*  Plaats HIER je eigen code nodig VOORDAT je naar de grafisch mode gaat
	 *  Als voorbeeld is hier gegeven de call naar berekeningPlot(argc, argv)
	 */
	berekeningPlot(argc, argv);

	/* Initialisatie van de OpenGL Utility Toolkit (glut).                */
	glutInit(&argc, argv);

	/* Initialisatie van vensterparameters.                               */
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(WINSIZE_X, WINSIZE_Y);
	glutInitWindowPosition(WINPOS_X, WINPOS_Y);

	/* Maak venster.                                                      */
	glutCreateWindow(FRAME_TITLE);

	/* Initialisatie van dit programma.                                   */
	progInit();

	/* Declaratie van functies om "events" af te handelen.                */
	glutDisplayFunc(progDisplay); /* hier wordt getekend!             */
	glutReshapeFunc(progReshape); /* na vormverandering van venster   */
	glutKeyboardFunc(progKeyboard); /* na typen van toets op toetsenbord*/

	/* Event handling loop. */
	glutMainLoop();

	return 0;
}

void berekeningPlot(int argc, char** argv) {
	/*  Plaats HIERONDER je eigen code nodig VOORDAT je naar de grafisch mode gaat */
	int i;
	float delta = 0.2;
	YMIN = 1000000.;
	YMAX = -100000.;
	for (i = 0; i < MAXPOINTS; i++) {
		xwaardes[i] = XMIN + delta + (XMAX - XMIN - 2. * delta)
				/ ((float) MAXPOINTS) * (float) i;
		ywaardes[i] = pow(xwaardes[i], 3);
		if (YMIN > ywaardes[i])
			YMIN = ywaardes[i];
		if (YMAX < ywaardes[i])
			YMAX = ywaardes[i];
	}
	YMAX = YMAX + delta;
	YMIN = YMIN - delta;
	return;
}

/****************************************************************************
 * Met de onderstaande progDisplay functie kun je je eigen plot
 * creeren.
 ****************************************************************************/
void progDisplay(void) {
	int i;

	/* Maakt venster schoon, d.w.z. geef het de achtergrondkleur (zwart). */
	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();

	/* Hieronder vind je drie eenvoudige voorbeelden om een vierkant en text
	 met OpenGL op het scherm te plaatsen en om de in de functie
	 berekeningPlot() berekende x- en y-waardes te plotten.
	 Voor je eigen programma: VERVANG deze voorbeelden en zet je
	 eigen code er voor in de plaats
	 */

	/**********  BEGIN VOORBEELDEN  *********/

	/* Paars kader. */
	glColor3f(1.0, 0.0, 1.0);
	drawLine(XMIN + 0.1, YMIN + 0.1, XMAX - 0.1, YMIN + 0.1);
	drawLine(XMAX - 0.1, YMIN + 0.1, XMAX - 0.1, YMAX - 0.1);
	drawLine(XMAX - 0.1, YMAX - 0.1, XMIN + 0.1, YMAX - 0.1);
	drawLine(XMIN + 0.1, YMAX - 0.1, XMIN + 0.1, YMIN + 0.1);

	/* Gele tekst bovenaan. */
	glColor3f(1.0, 1.0, 0.0);
	printText(XMIN * (1 - 0.1), YMAX * (1 - 0.1),
			"Voorbeeld van het schrijven van text in OpenGL.");

	/* x- en y-waardes in groen */
	glColor3f (0.4, 1.0, 0.4);
	for (i = 0; i < MAXPOINTS - 1; i++)
		drawLine(xwaardes[i], ywaardes[i], xwaardes[i + 1], ywaardes[i + 1]);

	/**********  EINDE VOORBEELDEN  *********/

	/* Zorgt dat alles getekend wordt. */
	glutSwapBuffers();
}

/****************************************************************************
 * Afhandelen van toetsinterrupt:
 *   programma stopt als e of q in venster ingetikt is.
 *   Bij ESC wordt window gereshaped
 ****************************************************************************/
void progKeyboard(unsigned char key, int x, int y) {
	switch (key) {
	case 'e':
		exit(0);
		break;
	case 'q':
		exit(0);
		break;
	case 27:
		if (current_size == 1) {
			WINSIZE_X = WINSIZE_X_S;
			WINSIZE_Y = WINSIZE_Y_S;
			current_size = 0;
		} else {
			WINSIZE_X = (int) ((float) WINSIZE_X * 1.5);
			WINSIZE_Y = (int) ((float) WINSIZE_Y * 0.75);
			current_size = 1;
		}
		progReshape(WINSIZE_X, WINSIZE_Y);
		glutPostRedisplay();
		break;
	}
}

/****************************************************************************
 * Initialisatie voor het programma.
 ****************************************************************************/
void progInit(void) {
	/* Zet achtergrondkleur van door OpenGL te maken venster (zwart). */
	glClearColor(0.0, 0.0, 0.0, 0.0);

	/* Geef instructies voor gebruiker in commandovenster. */
	printf(
			"\n  %s\n  Type 'e' of 'q' in OpenGL venster om te stoppen; ESC om de grootte van het venster te veranderen.\n",
			FRAME_TITLE);
}

/****************************************************************************
 * Druk tekst in "s" af beginnend op positie (x,y).
 ****************************************************************************/
void printText(float x, float y, char s[]) {
	int i, length;
	char c;

	/* Ga naar gewenste beginpositie. */
	glRasterPos2f(x, y);
	length = strlen(s);
	for (i = 0; i < length; i++) {
		c = s[i];
		glutBitmapCharacter(GLUT_BITMAP_8_BY_13, c);
	}
}

/****************************************************************************
 * Teken lijn van (x1,y1) naar (x2,y2) in gebruikerscoordinaten.
 ****************************************************************************/
void drawLine(float x1, float y1, float x2, float y2) {
	glBegin(GL_LINES);
	glVertex2f(x1, y1);
	glVertex2f(x2, y2);
	glEnd();
}

/****************************************************************************
 * Tekent een punt op (x1,y1) in gebruikerscoordinaten.
 ****************************************************************************/
void drawPoint(float x1, float y1, float pointsize) {
	glEnable(GL_POINT_SMOOTH);
	glPointSize(pointsize);
	glBegin(GL_POINTS);
	glVertex2f(x1, y1);
	glEnd();
}

/****************************************************************************
 * Afhandelen van verandering van venstergrootte:
 *   w en h zijn de nieuwe breedte en hoogte van het venster in
 *   venstercoordinaten, het oude venster wordt geheel in het nieuwe
 *   afgebeeld, waardoor de X/Y-verhoudingen niet bewaard hoeven te blijven.
 *
 *   Je kunt met behulp van XMIN, XMAX, YMIN en YMAX (Globale parameters)
 *   de gebruikers assen aanpassen
 ****************************************************************************/
void progReshape(int w, int h) {
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glutReshapeWindow(w, h);
	glViewport(0, 0, w, h);
	gluOrtho2D(XMIN, XMAX, YMIN, YMAX);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
