/***************************************************************************
 *   Copyright (C) 2005 by Michal Turek - Woq                              *
 *   WOQ (zavinac) seznam.cz                                               *
 *                                                                         *
 *   Program vytvori OpenGL okno a vykresli do nej barevny trojuhelnik     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <stdio.h>
#include <SDL.h>
#include <SDL_opengl.h>


/*
 * Symbolicke konstanty
 */

#define SDL_SUBSYSTEMS SDL_INIT_VIDEO

#define WIN_FLAGS SDL_OPENGL|SDL_RESIZABLE
#define WIN_WIDTH 640
#define WIN_HEIGHT 480
#define WIN_BPP 0

#define WIN_TITLE "SDL a OpenGL"

// Predni a zadni orezavaci rovina pro gluPerspective()
#define NEAR_PLANE 1.0
#define FAR_PLANE 10.0

// Je-li definovano, pouzije se fsaa (karta musi podporovat GL_ARB_multisample)
// Zaroven take definuje pocet vzorku
// #define FSAA 2

// Definovat v Linuxu (aktualizuje vnitrni (SDL) velikost okna)
// Nedefinovat v MS Windows (ztrata OpenGL kontextu)
#define CALL_SETVIDEOMODE_WHEN_RESIZING


/*
 * Funkcni prototypy
 */

bool InitGL();				// Nastavi vlastnosti OpenGL
void ResizeGL(int width, int height);	// Nastavi OpenGL perspektivu
bool Init();				// Hlavni inicializacni funkce
void Draw();				// Rendering sceny
void Destroy();				// Deinicializace
bool ProcessEvent();			// Osetruje udalosti
int  main(int argc, char *argv[]);	// Vstup do programu


/*
 * Globalni promenne
 */

SDL_Surface *g_screen;// Surface okna


/*
 * Inicializuje vlastnosti OpenGL
 */

bool InitGL()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	return true;
}


/*
 * Nastavuje perspektivu, vola se, kdyz uzivatel roztahuje okno
 * v parametrech nova velikost
 */

void ResizeGL(int width, int height)
{
	if(height == 0)// Deleni nulou
		height = 1;

	glViewport(0, 0, width, height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(45.0, (GLdouble)width/(GLdouble)height,
			NEAR_PLANE, FAR_PLANE);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


/*
 * Hlavni inicializacni funkce
 */

bool Init()
{
	if(SDL_Init(SDL_SUBSYSTEMS) == -1)// Inicializace SDL
	{
		fprintf(stderr, "Unable to initialize SDL: %s.\n",
				SDL_GetError());
		return false;
	}

	// Atributy rendering kontextu
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 24);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);

	SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 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);

#ifdef FSAA
	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FSAA);
#endif

	// Vytvori okno s definovanymi vlastnostmi
	g_screen = SDL_SetVideoMode(WIN_WIDTH, WIN_HEIGHT, WIN_BPP, WIN_FLAGS);

	if(g_screen == NULL)
	{
		fprintf(stderr, "Unable to set %dx%d video: %s.\n",
				WIN_WIDTH, WIN_HEIGHT, SDL_GetError());
		return false;
	}

	if(!InitGL())// Inicializace OpenGL
		return false;

	ResizeGL(WIN_WIDTH, WIN_HEIGHT);// Nastavi perspektivu
	SDL_WM_SetCaption(WIN_TITLE, NULL);// Titulek okna

	return true;
}


/*
 * Rendering sceny
 */

void Draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glBegin(GL_TRIANGLES);
		glColor3ub(255, 0, 0); glVertex3f(-1.0f,-0.5f,-3.0f);
		glColor3ub(0, 255, 0); glVertex3f( 1.0f,-0.5f,-3.0f);
		glColor3ub(0, 0, 255); glVertex3f( 0.0f, 0.5f,-3.0f);
	glEnd();

	glFlush();
	SDL_GL_SwapBuffers();// Prohodi predni a zadni buffer
}


/*
 * Deinicializacni funkce
 */

void Destroy()
{
	SDL_Quit();
}


/*
 * Osetruje udalosti (bude probrano nekdy v budoucnu)
 * V tomto pripade reaguje na roztahovani okna uzivatelem a ceka na klavesu ESC,
 * ktera ukonci program
 */

bool ProcessEvent()
{
	SDL_Event event;

	while(SDL_PollEvent(&event))
	{
		switch(event.type)
		{
			// Klavesnice
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						return false;
						break;

					default:
						break;
				}
				break;

			// Zmena velikosti okna
			case SDL_VIDEORESIZE:
#ifdef CALL_SETVIDEOMODE_WHEN_RESIZING
				g_screen = SDL_SetVideoMode(event.resize.w,
					event.resize.h, WIN_BPP, WIN_FLAGS);

				if(g_screen == NULL)
				{
					fprintf(stderr,
						"Unable to resize window: %s.\n",
						SDL_GetError());
					return false;
				}
#endif
				ResizeGL(event.resize.w, event.resize.h);
				break;

			// Pozadavek na ukonceni
			case SDL_QUIT:
				return false;
				break;

			default:
				break;
		}
	}

	return true;
}


/*
 * Vstup do programu
 */

int main(int argc, char *argv[])
{
	printf(WIN_TITLE);
	printf("\nPress ESC key to quit.\n");

	if(!Init())// Inicializace
	{
		Destroy();
		return 1;
	}

	// Hlavni smycka programu
	bool done = false;
	while(!done)
	{
		done = !ProcessEvent();// Osetri udalosti

		Draw();// Rendering
	}

	// Deinicializace a konec
	Destroy();
	return 0;
}