/*
trajectory.c
Jeffrey Grafton <jgrafton at tjhsst dot edu>
9/19/2002

This program is released under the GNU General Public License.
A copy of this license is available online at
http://www.gnu.org/copyleft/gpl.html.
*/

#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define MINX -10.0
#define MINY -10.0
#define MAXX 200
#define MAXY 200
#define WINDOW_WIDTH 600
#define WINDOW_HEIGHT 600

#define GRAVITY 9.80

void display_init(void);
void display(void);
void draw_axes(void);
void draw_projectile(void);
void keyboard(unsigned char, int, int);
void print_string (int, int, void*, char*);
void explosion(GLdouble, GLdouble);

GLdouble angle = 30.0, velocity = 20.0, t = 0.0, wind = 10.0;
int status = 0;
char message[32]="";

int
main (int argc, char **argv)
{
	time_t time_var;
/*	printf("Angle (in degrees): ");
	scanf("%lf", &angle);
	printf("Velocity (in meters/second): ");
	scanf("%lf", &velocity);
*/	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
	glutCreateWindow("trajectory");
	display_init();
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	
	time(&time_var);
	srand(time_var); /* seed the random number generator */
	
	wind = (rand() % 101 - 50) / 10.0; /* set the wind velocity */
	
	glutMainLoop();
	return 0;
}

/* initialization routines */
void
display_init (void)
{
	glClearColor(0.0, 0.0, 0.2, 0.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(MINX, MAXX, MINY, MAXY, -1.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);
}

/* main display function */
void
display (void)
{
	draw_axes();
	if (status)
		draw_projectile();
	glutSwapBuffers();
}

/* draws axes and other things of that nature */
void
draw_axes (void)
{
	char buffer[32];
	if(status < 2)
	{
		glClear(GL_COLOR_BUFFER_BIT); 
	}
	
	glLineWidth(3);
	glColor3d(1.0, 1.0, 1.0);
	
	snprintf(buffer, 32, "Angle: %.1f degrees", angle);
	print_string(5.0, MAXY - 5.0, GLUT_BITMAP_HELVETICA_12, buffer);

	snprintf(buffer, 32, "Velocity: %.1f m/s", velocity);
	print_string(5.0, MAXY - 10.0, GLUT_BITMAP_HELVETICA_12, buffer);

	snprintf(buffer, 32, "Wind: %.2f m/s", wind);
	print_string(5.0, MAXY - 15.0, GLUT_BITMAP_HELVETICA_12, buffer);

	print_string(10.0, MAXY - 30.0, GLUT_BITMAP_HELVETICA_18, message);
	
	glBegin(GL_LINES);
		glVertex2d(MINX, 0.0);
		glVertex2d(MAXX, 0.0);
		glVertex2d(0.0, MINY);
		glVertex2d(0.0, MAXY);
	
		glColor3d(0.0, 0.0, 1.0);
		glVertex2d(0.0, 0.0);
		glVertex2d(10.0 * cos(M_PI * angle / 180), 10.0 * sin(M_PI * angle / 180));
	
		glColor3d(1.0, 1.0 - 1.0 / (fabs(velocity) / 20.0 + 0.0001), 0.0); /* make the color correspond to the velocity */
		glVertex2d(5.0, -3.0);
		glVertex2d(5.0 + velocity, -3.0);
	glEnd();
	
	glColor3d(0.0, 1.0, 1.0 - 1.0 / (fabs(wind) * 2.0 + 0.0001)); /* make the color correspond to the wind velocity */
	glBegin(GL_TRIANGLES);
		glVertex2d(100.0, MAXY - 5.0);
		glVertex2d(100.0 + wind * 2.0, MAXY - 7.5);
		glVertex2d(100.0, MAXY - 10.0);
	glEnd();
	
	glColor3d(0.0, 1.0, 0.0);
	glRectd(100.0, 0.5, 110.0, 2.0);
}

/* draws the projectile in motion */
void
draw_projectile (void)
{
	GLdouble x = 1.0, y = 1.0, lastx = 0.0, lasty = 0.0, xv, yv, x0, y0, hitx = 0.0, hity = 0.0;
	
	xv = velocity * cos(M_PI * angle / 180);
	yv = velocity * sin(M_PI * angle / 180);
	x0 = 10.0 * cos(M_PI * angle / 180);
	y0 = 10.0 * sin(M_PI * angle / 180);

	if (status == 1)
	{
		t = 0.0;
		status = 2;
	}
	
	glColor3d(1.0, 0.0, 0.0);
	
	glBegin(GL_LINE_STRIP);
		for(t = 0.0; y > 0.0; t += 0.1)
		{
			x = x0 + xv * t + 0.5 * wind * t * t;
			y = y0 + yv * t - 0.5 * GRAVITY * t * t;

			
			/* check to see if we've hit the ground yet */
			if (y < 0.0 && (y - lasty) != 0.0)
			{
				GLdouble slope = (y - lasty) / (x - lastx);
				GLdouble yintercept = (y) - (slope * (x));
				hitx = -yintercept / slope;
	
				glColor3d(1.0, 1.0, 1.0);
				if (hitx >= 100.0 && hitx <= 110.0)
				{
					strncpy(message, "TARGET HIT!", 32);
				}
				else
				{
					strncpy(message, "TARGET MISSED.", 32);
				}
				glVertex2d(hitx, 0.0);
			}
			else
				glVertex2d(x, y);
			lastx = x;
			lasty = y;
			glutSwapBuffers();
		}

	glEnd();
	glFlush();
	draw_axes();
	explosion(hitx, hity);
	status = 0;
	wind += (rand() % 21 - 11) / 10.0; /* modify our wind */
}

/* make the nice pretty explosiony thing. */
void
explosion(GLdouble x, GLdouble y)
{
	GLdouble i, j;
	
	glColor3d(1.0, 0.8, 0.3);
	glBegin(GL_POINTS);
		for (i = 0.0; i <= 20.0; i += 0.5)
		{
			for (j = 0; j < 50; j += 1.0)
			{
				glVertex2d(x + i * cos(j * M_PI / 25), y + i * sin(j * M_PI / 25));
			}
		glutSwapBuffers();
		}
	glEnd();
		
}

/* keyboard callback function */
void
keyboard (unsigned char key, int x, int y)
{
/*	printf ("key = %d\n", key); */
	if (key == 'a' || key == 'A')
		angle++;
	if (key == 'd' || key == 'D')
		angle--;
	if (key == 'w' || key == 'W')
		velocity++;
	if (key == 's' || key == 'S')
		velocity--;
	if (key == 13 || key == 32)
		status = 1;
	
	strncpy(message, "", 32);
 	glutPostRedisplay();
}

/* draw a string to the screen */
void
print_string (int x, int y, void *font, char *string)
{
	int i;
	glPushMatrix();
	glTranslatef(x, y, 0);
	glRasterPos2d(0, 0);
	for (i = 0; i < strlen(string); i++)
		glutBitmapCharacter(font, string[i]);
	glPopMatrix();
}

