/*
 * This code was created by Jeff Molofee '99 
 * (ported to Linux/SDL by Ti Leggett '01)
 *
 * If you've found this code useful, please let me know.
 *
 * Visit Jeff at http://nehe.gamedev.net/
 * 
 * or for port-specific comments, questions, bugreports etc. 
 * email to leggett@eecs.tulane.edu
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>

#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP     16

SDL_Surface *surface;

// function to release/destroy our resources and restoring the old desktop
void quit(int returnCode)
{
	SDL_Quit();

	// exit the program
	exit(returnCode);
}

// function to reset our viewport after a window resize
int resizeWindow(int width, int height)
{
	// height / width ration
	GLfloat ratio;

	// protect against a divide by zero
	if (height == 0)
		height = 1;

	ratio = (GLfloat)width / (GLfloat)height;

	// setup our viewport
	glViewport(0, 0, (GLint)width, (GLint)height);

	// change to the projection matrix and set our viewing volume.
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// set our perspective
	gluPerspective(45.0f, ratio, 0.1f, 100.0f);

	// make sure we're chaning the model view and not the projection
	glMatrixMode(GL_MODELVIEW);

	// reset the view
	glLoadIdentity();

	return true;
}

// function to handle key press events
void handleKeyPress(SDL_keysym *keysym)
{
	switch (keysym->sym) {
	case SDLK_ESCAPE:
		// ESC key was pressed
		quit(0);
		break;
		
	case SDLK_F1:
		// F1 key was pressed; this toggles fullscreen mode
		SDL_WM_ToggleFullScreen(surface);
		break;
		
	default:
		break;
	}
}

// general OpenGL initialization function
int initGL(GLvoid)
{
	// enable smooth shading
	glShadeModel(GL_SMOOTH);

	// set the background black
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

	// depth buffer setup
	glClearDepth(1.0f);

	// enables depth testing
	glEnable(GL_DEPTH_TEST);

	// the type of depth test to do
	glDepthFunc(GL_LEQUAL);

	// really nice perspective calculations
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	return true;
}

/* Here goes our drawing code */
int drawGLScene(GLvoid)
{
	// these are to calculate our fps
	static GLint T0     = 0;
	static GLint Frames = 0;

	// clear the screen and the depth buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glLoadIdentity();
	
	glTranslatef(-1.5f, 0.0f, -6.0f);
	
	glBegin(GL_TRIANGLES);
		glVertex3f(0.0f, 1.0f, 0.0f);
		glVertex3f(-1.0f, -1.0f, 0.0f);
		glVertex3f(1.0f, -1.0f, 0.0f);
	glEnd();
	
	glTranslatef(3.0f, 0.0f, 0.0f);

	glBegin(GL_QUADS);
		glVertex3f(-1.0f, 1.0f, 0.0f);
		glVertex3f(1.0f, 1.0f, 0.0f);
		glVertex3f(1.0f, -1.0f, 0.0f);
		glVertex3f(-1.0f, -1.0f, 0.0f);
	glEnd();
	
	// Draw it to the screen
	SDL_GL_SwapBuffers( );
	
	return true;
	
	/*

	// Gather our frames per second
	Frames++;
	GLint t = SDL_GetTicks();
	if (t - T0 >= 5000) {
		GLfloat seconds = (t - T0) / 1000.0;
		GLfloat fps = Frames / seconds;
		printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
		T0 = t;
		Frames = 0;
	}

	return true;
	*/
}

int main(int argc, char **argv)
{
	// flags to pass to SDL_SetVideoMode
	int videoFlags;
	// main loop variable
	bool done = false;
	// used to collect events
	SDL_Event event;
	// this holds some info about our display
	const SDL_VideoInfo *videoInfo;
	// whether or not the window is active
	bool isActive = true;

	// initialize SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
		fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError());
		quit(1);
	}

	// fetch the video info
	videoInfo = SDL_GetVideoInfo();
	if (!videoInfo) {
		fprintf(stderr, "Video query failed: %s\n", SDL_GetError());
		quit(1);
	}

	// the flags to pass to SDL_SetVideoMode
	videoFlags  = SDL_OPENGL;          // Enable OpenGL in SDL
	videoFlags |= SDL_GL_DOUBLEBUFFER; // Enable double buffering
	videoFlags |= SDL_HWPALETTE;       // Store the palette in hardware
	videoFlags |= SDL_RESIZABLE;       // Enable window resizing

	// this checks to see if surfaces can be stored in memory
	videoFlags |= (videoInfo->hw_available ? SDL_HWSURFACE : SDL_SWSURFACE);

	// this checks if hardware blits can be done
	if (videoInfo->blit_hw)
		videoFlags |= SDL_HWACCEL;

	// sets up OpenGL double buffering
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	// get a SDL surface
	surface = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags);
	if (!surface) {
		fprintf(stderr, "Video mode set failed: %s\n", SDL_GetError());
		quit(1);
	}

	if (!initGL()) {
		fprintf(stderr, "Could not initialize OpenGL.\n");
		quit(1);
	}

	resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT);

	while (!done) {
		while (SDL_PollEvent(&event)) {
			switch (event.type) {
			case SDL_ACTIVEEVENT:
				/* Something's happend with our focus
				 * If we lost focus or we are iconified, we
				 * shouldn't draw the screen
				 */
				isActive = (event.active.gain == 0 ? false : true);
				break;
				
			case SDL_VIDEORESIZE:
				/* handle resize event */
				surface = SDL_SetVideoMode(event.resize.w, event.resize.h, 16,
					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;
				
			case SDL_KEYDOWN:
				handleKeyPress(&event.key.keysym);
				break;
				
			case SDL_QUIT:
				done = true;
				break;
				
			default:
				break;
			}
		}

		if (isActive)
			drawGLScene();
		
		// don't use all the CPU time
		if (!SDL_PollEvent(NULL))
			SDL_Delay(10);
	}

	quit(0);

	// should never get here
	return 0;
}


