#include <stdio.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "SDL.h"

#define SCREEN_BPP	16
#define TRUE		1
#define FALSE		0

int width=640, height=480;
SDL_Surface *surface;
int start, time;
double velocity = 40.0, angle = 45.0;	/* initial values, of course */
int dist = 500, range = 10;		/* reasonable target.... */
int launch = FALSE;

void display();
void myinit();
inline void KeyPressed();
inline void mouse();

void Quit(int ret) {
	SDL_Quit();
	exit(ret);
}

void ToggleFullScreen(void) {
	if(SDL_WM_ToggleFullScreen(surface) == 0) {
		fprintf(stderr, "Failed to Toggle Fullscreen mode: %s\n",
				SDL_GetError());
	}
}

/* Make everything right after a window resize */
int resizeWindow(int width, int height) {
	GLfloat ratio;				/* aspect ratio */
	if (height == 0) height = 1;	/* Protect against a divide by zero */

	ratio = (GLfloat)width / (GLfloat)height;
	glViewport(0, 0, (GLsizei)width, (GLsizei)height);
		/* Set up viewport */

	glMatrixMode(GL_PROJECTION);
		/* Change to projection matrix and set up viewing matrix*/
	glLoadIdentity();

	gluPerspective(45.0f, ratio, 0.1f, 100.0f);	/* Set perspective */

	glMatrixMode(GL_MODELVIEW);	/* Change model view (as opposed to proj)*/
	glLoadIdentity();			/* Reset the view */

	myinit();

	return(TRUE);
}

/* Declare initial window size, position, and display mode */
int main(int argc, char* argv[]) {
	int videoFlags;				/* Flags to pass to SDL_SetVideoMode */
	int done = FALSE;
	SDL_Event event;
	const SDL_VideoInfo *videoInfo;	/* Holds display info */

	printf("Creating window %d pixels wide and %d pixels high", width, height);
	printf("\nHit the F1 key to toggle between fullscreen and windowed mode");
	printf("\nPress left and right to change angle (degrees)");
	printf("\nPress up and down to change velocity (px/msec)");
	printf("\nPress left and right shift to change size of target");
	printf("\nPress left and right control to move the target");
	printf("\nClick the left mouse button to relaunch and see if you hit");
	printf("\nPress ESC to quit.\n");

	if (SDL_Init(SDL_INIT_VIDEO) < 0) {	/*initialize SDL */
		fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError());
		Quit(1);
	}
	
	videoInfo = SDL_GetVideoInfo();	/* Get some video info */
	if (!videoInfo) {
		fprintf(stderr, "Failed getting video info: %s\n", SDL_GetError());
		Quit(1);
	}
	videoFlags = SDL_OPENGL;	/* Enable OpenGL in SDL */
	videoFlags |= SDL_GL_DOUBLEBUFFER;	/* We want double buffering */
	videoFlags |= SDL_HWPALETTE;	/* Store the palette in hardware */
	videoFlags |= SDL_RESIZABLE;	/* Enable window resizing */
	if (videoInfo->hw_available) videoFlags |= SDL_HWSURFACE;
	else videoFlags |= SDL_SWSURFACE;
		/* Store surfaces in hardware if we can */
	if (videoInfo->blit_hw) videoFlags |= SDL_HWACCEL;
		/* If the hardware can do it, we want it to do our blitting */

	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
		/* Set up OpenGL double buffering */
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, SCREEN_BPP);
		/* Size of depth buffer */
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
		/* Don't need to use stencil buffer */
	SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 0);
		/* This and the next three lines set teh bpp for the accumulation
		 * buffer to 0 */
	SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 0);
	SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 0);
	SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 0);

	surface = SDL_SetVideoMode(width, height, SCREEN_BPP, videoFlags);
	if (!surface) {
		fprintf(stderr, "Video mode set failed: %s\n", SDL_GetError());
		Quit(1);
	}
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 
			SDL_DEFAULT_REPEAT_INTERVAL);	/*It gets annoying without this*/

	myinit();					/* Call my initialization routine */
	
	while (!done) { /* main event loop */
		while (SDL_PollEvent(&event)) { /* look for events */
			switch (event.type) {	/* what kind of event is it? */
				case SDL_QUIT:	/* If user wishes to quit */
					done = TRUE;
					break;
				case SDL_KEYDOWN:	/* If a key has been pressed */
					KeyPressed(&event.key.keysym);	/* Handle it */
					break;
				case SDL_MOUSEBUTTONDOWN:
				case SDL_MOUSEMOTION:
					mouse(event);
					break;
				case SDL_VIDEORESIZE:
					surface = SDL_SetVideoMode(event.resize.w, event.resize.h,
							SCREEN_BPP, videoFlags);
					if (!surface) {
						fprintf(stderr, 
								"Could not get a surface after resize:%s\n",
								SDL_GetError());
						Quit(1);
					}
					resizeWindow(event.resize.w, event.resize.h);
					break;
				default:
					break;
			}
		}
		display();				/* Call my display routine */
	}
	Quit(0);
	return 0;					/* Shouldn't get here */
}

void myinit() {
	SDL_WM_SetCaption("Trajectory 1", NULL);
	time = 0;
	start = SDL_GetTicks();
	glClearColor(0.26, 0.40, 0.58, 0.0);

	/* initialize viewing values */
	glMatrixMode(GL_PROJECTION);	/* Select Matrix Mode */
	glLoadIdentity();			/* Provide Base Matrix */
	glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);
		/* Parameters:  glOrtho(Left, Right, Bottom, Top, Front, Back) */
}

void display() {
	float i, x, y;
	glClear(GL_COLOR_BUFFER_BIT);

	glColor3f(0.0, 0.0, 0.0);
	glBegin(GL_QUADS);
		glVertex2i(dist-range, 20);
		glVertex2i(dist+range, 20);
		glVertex2i(dist+range, 0);
		glVertex2i(dist-range, 0);
	glEnd();

	if (time == 0) launch = TRUE;
	time = SDL_GetTicks() - start;
	
	glColor3f(1.0, 1.0, 0.0);
	glBegin(GL_POINTS);
	for (i = 0.0; i <= time && y >= 0.0; i+=.001) {	/* arbitrary gravity... */
		x = velocity * sin(angle) * i;
		y = velocity * cos(angle) * i - i * i;
		glVertex2f(x, y);					
	}
	glEnd();

	SDL_GL_SwapBuffers();
		/* Force writing all pending OpenGL actions to the screen*/
	glFlush();
	if (launch == TRUE && x <= dist+range && x >= dist-range && y <= 0.0) 
		printf("HIT!\n");
	if (y <= 0.0) launch = FALSE;
}

inline void KeyPressed(SDL_keysym *keysym) {
	switch (keysym->sym) {		/* which key is it? */
		case SDLK_F1:			/* F1 */
			ToggleFullScreen();	/* Toggle fullscreen/windowed mode */
			break;
		case SDLK_ESCAPE:		/* if it is ESC */
		case SDLK_q:
			Quit(0);
			break;
		case SDLK_LEFT:
			angle -= 0.01;
			break;
		case SDLK_RIGHT:
			angle += 0.01;
			break;
		case SDLK_UP:
			velocity += 0.3;
			break;
		case SDLK_DOWN:
			velocity -= 0.3;
			break;
		case SDLK_LSHIFT:
			range--;
			break;
		case SDLK_RSHIFT:
			range++;
			break;
		case SDLK_LCTRL:
			dist--;
			break;
		case SDLK_RCTRL:
			dist++;
			break;
		default:
			break;
	}
}

inline void mouse(SDL_Event event) {
	if(event.type == SDL_MOUSEBUTTONDOWN && 
		event.button.button == 1) {	/* Left button clicked */ 
		time = 0;
		start = SDL_GetTicks();
	}
}


