///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////// "Space Rush" gra w OpenGL na zaliczenie przedimotu Grafika Komputerowa i Wizualizacja - Michał Jeleń 223B ////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define SCENE_LEVEL1 "../resources/levelone.bmp"
#define SCENE_LEVEL2 "../resources/leveltwo.bmp"
#define SCENE_LEVEL3 "../resources/levelthree.bmp"
#define SCENE_LEVEL4 "../resources/levelfour.bmp"
#define SCENE_LEVEL5 "../resources/levelfive.bmp"

#include <cstdlib>
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <list>
#include <algorithm>
#include <time.h>
#include <math.h>
#include <cstdio>
#include <vector>
#include <string> 
#include <fstream>

#include "conf.h"
#include "timer.h"
#include "objloader.h"
#include "textureloader.h"

using namespace std;


#include "util.h"
#include "gl.h"
#include "glut.h"

//int ScreenWidth = 1366;
int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
//int ScreenHeight = 768;
int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);

char *LevelsArray[5] = {SCENE_LEVEL1, SCENE_LEVEL2, SCENE_LEVEL3, SCENE_LEVEL4, SCENE_LEVEL5 };
long int ScoreTab[5][4] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0};

long long int LevelTime = 0;
long long int LevelTimeSeconds = 0;
int CurrentLevel = 1;
int PlayerLives = 5;
int PlayerPoints = 0;
int LevelCount = 5;

float MaxH = 0.0058;
//float GroundPosZ = 0.0025;
float GroundPosZ = 0.0026;
float PlayerOverBlock = 0;
float PlayerIsOnBlock = 0;

float Scale = 0;

float speed = 0.0008 / Scale;
float DeltaMoveLeftRight = 0.00015 / Scale;
float DeltaZFall = 0.00024 / Scale;
float DeltaZJump = 0.00024 / Scale;
float StarRotateAngle = 5 / Scale;

float SmoothMoveLeft = 0.1;
float SmoothMoveRight = 0.1;

float SmoothMoveUp = 1.0;
float SmoothMoveDown = 0.2;

float SmoothSpeed = 0.05;

bool GameOver = 0;
bool DefinitlyGameOver = 0;
bool LevelFinished = 0;
bool PlayerIsOnGround = 1;
bool LoadNextLevel = 0;
bool PlayerInJump = 0;
bool PlayerInFall = 0;
bool LevelChanged = 1;
bool MenuToken = 0;
bool EnableStates = 0;
bool InGame = 0;
bool ZPrzoduMam = 0;


int SummaryStars, SummaryTime,SummaryPoints;

string TotalPointsString;
string TotalPointsValueString;
int TotalPointsStringLength;
int TotalPointsValueStringLength;
string PressEscape;


GLuint SpaceShipModel;
GLuint SpaceShipLeftModel;
GLuint SpaceShipRightModel;
GLuint StarModel;
GLuint HeartModel;

GLuint BackgroundTexture;
GLuint GameOverTexture;
GLuint PlayGame;
GLuint ExitGame;

BITMAPINFOHEADER bitmapInfoHeader;

float StartX, StartY, StartZ;
float HudX, HudY, HudZ;

Timer TimeCounter;

///////////////////////////////////////// utworzenie obiektu klasy CGL
CGL cgl;

void SetScale()
{
	std::ifstream plik;
	plik.open("scale.txt");
	plik >> Scale;
};
///////////////////////////////////////// inicjalizacja srodowiska graficznego oraz zmiennych 
void CGL::init(void) {


	//if (EnableStates == 1)TimeCounter.start();   // timer start
	PlayerPoints = 0;  // reset punktow
	//cout << "Timer Started";

	SpaceShipModel = LoadObj("../resources/spaceship.obj");
	SpaceShipLeftModel = LoadObj("../resources/spaceshipleft.obj");
	SpaceShipRightModel = LoadObj("../resources/spaceshipright.obj");

	StarModel = LoadObj("../resources/star.obj");
	HeartModel = LoadObj("../resources/heart.obj");


	if (ScreenWidth == 1366 && ScreenHeight == 768)
	{
	BackgroundTexture = LoadTexture("../resources/1366x768/background.bmp", ScreenWidth, ScreenHeight);
	GameOverTexture = LoadTexture("../resources/1366x768/gameover.bmp", ScreenWidth, ScreenHeight);
	PlayGame = LoadTexture("../resources/1366x768/playgame.bmp", ScreenWidth, ScreenHeight);
	ExitGame = LoadTexture("../resources/1366x768/exitgame.bmp", ScreenWidth, ScreenHeight);
}

	if (ScreenWidth == 1920 && ScreenHeight == 1200)
	{
		BackgroundTexture = LoadTexture("../resources/1920x1200/background.bmp", ScreenWidth, ScreenHeight);
		GameOverTexture = LoadTexture("../resources/1920x1200/gameover.bmp", ScreenWidth, ScreenHeight);
		PlayGame = LoadTexture("../resources/1920x1200/playgame.bmp", ScreenWidth, ScreenHeight);
		ExitGame = LoadTexture("../resources/1920x1200/exitgame.bmp", ScreenWidth, ScreenHeight);
	}

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	////////////////////////////////////////////////////////////////// Ustawienia kamery

	//gluPerspective( 20, 1, 0.01, 100 );

	//gluPerspective(30, ScreenWidth / ScreenHeight, 0.01, 1);

	//gluPerspective(30, ScreenWidth / ScreenHeight, 0.01, 1);
	gluPerspective(30, ScreenWidth / ScreenHeight, 0.01, 1);
	gluLookAt(0, -0.06, 0.006, 0, 0, 0, 0, 1, 0); /// z plecow

	//gluLookAt(posX, posY, posZ+0.1, posX, posY, posZ, 0, 1, 0); /// z plecow
	//gluLookAt( 0, -3, 0.2, 0, 0, 0, 0, 1,0 );
	//gluLookAt(0, -0.04, 0.003, 0, 0, 0, 0, 1, 0); /// z plecow
	//gluLookAt(0, -0.025, 0.000000000001, 0, 0, 0, 0, 1, 0); // z tyu
	//gluLookAt(0, 0, 0.1 , 0, 0, 0, 0, 1, 0); //  z goryu

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	// ustawienie parametrow zrodla swiatla, wlaczenie oswietlenia
	// Swiatlo 0
	float vec[4];
	SET_VEC4(vec, 0.7f, 0.7f, 0.4f, 1.0f);
	glLightfv(GL_LIGHT0, GL_POSITION, vec);
	SET_VEC4(vec, 1.0f, 1.0f, 1.0f, 1.0f);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, vec);
	glLightfv(GL_LIGHT0, GL_AMBIENT, vec);
	glLightfv(GL_LIGHT0, GL_EMISSION, vec);
	glLightfv(GL_LIGHT0, GL_SPECULAR, vec);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
	
	// Swiatlo 1
	float vec1[4];
	SET_VEC4(vec1, 0.7f, 0.7f, 0.4f, 1.0f);
	glLightfv(GL_LIGHT1, GL_POSITION, vec1);
	SET_VEC4(vec1, 1.0f, 1.0f, 1.0f, 1.0f);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, vec);
	glLightfv(GL_LIGHT1, GL_AMBIENT, vec);
	glLightfv(GL_LIGHT1, GL_EMISSION, vec);
	glLightfv(GL_LIGHT1, GL_SPECULAR, vec);
	glEnable(GL_LIGHT1);

	glEnable(GL_LIGHTING);
	
	// wlaczenie cieniowania Gouraud'a (smooth shading)
	glShadeModel(GL_SMOOTH);

	// ustawienie koloru tla
	//glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); 

	// skasowanie bufora klawiatury
	for (int i = 0; i < 256; i++)cgl.keyStates[i] = false;

	// poczatkowe polozenie obiektu

	posX = 0.01175;
	posY = 0.00175;
	posZ = 0.00348;

	StartX = posX;
	StartY = posY;
	StartZ = posZ;

	rotation = 90;

	posXOld = posX;
	posYOld = posY;
	posZOld = posZ;
	rotationOld = rotation;

	// odczytanie i wyswietlenie wersji OpenGL
	char* version = (char*)glGetString(GL_VERSION);
	printf("OpenGL version: %s\n", version);

	// odczytanie struktury sceny z zewnetrznego pliku (!!! dane bitmapy odczytane sa w formacie BGR888)
	//BITMAPINFOHEADER bitmapInfoHeader;

	mscene = CUTIL::LoadBitmapFile(SCENE_LEVEL1, &bitmapInfoHeader);

	if (mscene == NULL) {
		printf("ERROR: cannot open input file with the scene data\n");
		exit(1);
	}

	mscene_width = (int)bitmapInfoHeader.biWidth;
	mscene_height = (int)bitmapInfoHeader.biHeight;
	mscene_line_length = (int)(bitmapInfoHeader.biSizeImage / mscene_height);
	printf("Bitmap size: %d,%d (line length:%d, size:%d (%d))\n", mscene_width, mscene_height, mscene_line_length, bitmapInfoHeader.biSizeImage, (mscene_width*mscene_height * 3));

	/*
	for( int c = 0; c < mscene_height; c++ ) {
	for( int w = 0; w < mscene_width; w++ ) {

	int idx = xy2idx( w, c );

	printf("(%d,%d,%d)",mscene[idx],mscene[idx+1],mscene[idx+2] );
	}
	printf("\n");
	}

	*/
	// poczatkowe stany gry (! wazna jest kolejnosc stanow na liscie)
	if (EnableStates == 0)state_list.push_back(STATE_DRAW_MENU);
	if (EnableStates == 1)
	{
	state_list.push_back(STATE_DRAW_HUD);
	//state_list.push_back(STATE_DRAW_GAMEOVER_TEXTURE);

	state_list.push_back(STATE_DRAW_BACKGROUND);
	state_list.push_back(STATE_DRAW_SCENE);
	state_list.push_back(STATE_DRAW_OBJECT);
	state_list.push_back(STATE_NEW_LIGHT);
	state_list.push_back(STATE_COLLISIONS_SCENE);
	}
}


///////////////////////////////////////// glowna procedura przerysowania ekranu
bool is_first = true;

// Wywołanie tak utworzonej display listy w celu jej narysowania
ofstream plik;
void SaveScores()
{
	plik.open("player.s", std::ofstream::out | std::ofstream::trunc); 
	for (int i = 0; i < 5; i++)plik << ScoreTab[i][0] << " " << ScoreTab[i][1] << " " << ScoreTab[i][2] << " " << ScoreTab[i][3] << endl;
	plik.close();
};

void CalculatePoints()
{
	/*
	for (int i = 0; i < 5; i++)
	{
		for (int j= 0; j < 4; j++)
		{
			cout << ScoreTab[i][j];
		}
		cout << endl;
	}
	*/
	for (int i = 0; i < 5; i++)
	{
		SummaryStars += ScoreTab[i][1];
		SummaryTime += ScoreTab[i][2];
	}

	//cout << SummaryStars << endl;
	//cout << SummaryTime << endl;
	//cout << CurrentLevel << endl;
	//cout << PlayerLives << endl;
}

void DrawOnHUDStringAndValue(string name,int value,float DeltaX,float DeltaZ,bool token)
{

	string ValueString = to_string(value);
	//if (token == 1)
	//{
	//	if (LevelFinished == 0 && to_string(TimeCounter.getTime()).length() >3 )ValueString.insert(to_string(TimeCounter.getSeconds()).length(), 1, '.');
	//	else ValueString.insert(to_string(LevelTimeSeconds).length(), 1, '.');
	//}
	int StringLength = name.length();
	int ValueStringLength = ValueString.length();


	glRasterPos3f(HudX + DeltaX, HudY, HudZ + DeltaZ);
	for (int i = 0; i < StringLength; i++)
	{
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, name[i]);
	}
	for (int i = 0; i < ValueStringLength; i++)
	{
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ValueString[i]);
	}
}
void DrawOnGameOver(string name, int value,string name2,int value2, float posX, float posY, float posZ)
{

	string ValueString = to_string(value);
	string ValueString2 = to_string(value2);

	int StringLength = name.length();
	int String2Length = name2.length();

	int ValueStringLength = ValueString.length();
	int ValueString2Length = ValueString2.length();

	glRasterPos3f(posX, posY, posZ);
	for (int i = 0; i < StringLength; i++)glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, name[i]);
	for (int i = 0; i < ValueStringLength; i++)glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ValueString[i]);
	for (int i = 0; i < String2Length; i++)glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, name2[i]);
	for (int i = 0; i < ValueString2Length; i++)glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ValueString2[i]);
	
}


void CGL::display(void) {
	
	//cout << Scale << endl;

	SetScale();
	speed = 0.0008 / Scale;
	DeltaMoveLeftRight = 0.00015 / Scale;
	DeltaZFall = 0.00024 / Scale;
	DeltaZJump = 0.00024 / Scale;

	if (PlayerLives == 0)
	{
		LevelTime = TimeCounter.getTime();
		LevelTimeSeconds = TimeCounter.getSeconds();
		if (TimeCounter.isRunning())TimeCounter.stop();
		ScoreTab[CurrentLevel - 1][0] = CurrentLevel;
		ScoreTab[CurrentLevel - 1][1] = PlayerPoints;
		ScoreTab[CurrentLevel - 1][2] = LevelTime;
		ScoreTab[CurrentLevel - 1][3] = PlayerLives;
		SaveScores();
	}
	////if (PlayerInJump == 0){
	//if (onblock == 1)MaxH = MaxH * 2;
	//else MaxH = 0.006;
	//}
	//cout << "posX: " << posX << " posY: " << posY << " posZ: " << posZ << endl;

	if( is_first ) {
		t_old = CUTIL::getTime();
		is_first = false;
	}
	
	float t = CUTIL::getTime(); // aktualny czas
	float dt = t - t_old; // czas, ktory uplynal od poprzedniego wywolania display()
	t_old = t;

	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	// obsluga klawiatury	
	keyOperations(); 
	
	// transformacja calej sceny
	glPushMatrix();	

	// przesuniecie planszy na srodek okna
	//glTranslatef( -0.5f, -0.5f, 0.0f );

	// zmiana widoku kamery
	//glTranslatef( 0.0f, 0.0f, 0.1f ); // przesuniecie korekcyjne	
	//glRotatef( -30, 1, 0, 0 ); // pochylenie kamery (3PP)
	glRotatef( -rotation+90, 0, 0, 1 ); // obrot planszy zgodnie z obrotem gracza
	glTranslatef( -posX, -posY, -posZ );	// przesuniecie planszy do polozenia gracza

	HudX = posX;
	HudY = posY;
	HudZ = posZ;
	//cout << "posX: " << posX << "posY: " << posY << endl;


	// glowna petla obslugujaca stany gry
	int idx;
	bool bb;
	list<CMissle*>::iterator it;
	list<int> states = state_list;
	list<int>::iterator state;
	for (state = states.begin(); state != states.end(); ++state) {
		switch (*state) {

			//////////////////////// dodatkowe zrodlo swiatla
		case STATE_NEW_LIGHT:

			if (LevelChanged == 1)
			{
				LevelChanged = 0;
				TimeCounter.start();   // timer start
				PlayerPoints = 0;
			}

			// polozenie zrodla swiatla (LIGHT1)
			//glMaterialfv( GL_FRONT, GL_DIFFUSE, colorGray );
			//glMaterialfv( GL_FRONT, GL_AMBIENT, colorGray );
			//glMaterialfv(GL_FRONT, GL_EMISSION, colorWhite);
			//glPushMatrix();
			//glTranslatef(posX, posY, posZ+0.01f);
			//glScalef(0.001f, 0.001f, 0.001f);
			//glutSolidSphere(1, 20, 20);
			//glPopMatrix();

			float vec[4];
			SET_VEC4(vec, posX, posY, posZ + 0.01f, 1.0f);
			glLightfv(GL_LIGHT0, GL_POSITION, vec);
			glMaterialfv(GL_FRONT, GL_EMISSION, colorDim);
			break;

			float vec1[4];
			SET_VEC4(vec1, posX, posY-0.01, posZ + 0.02f, 1.0f);
			glLightfv(GL_LIGHT0, GL_POSITION, vec1);
			glMaterialfv(GL_FRONT, GL_EMISSION, colorDim);
			break;

			/////////////////// ruch obiektu do przodu
		case STATE_MOVE_OBJECT_FORWARD:

			if (LevelFinished == 1)
			{

				posXOld = posX;
				if (posY < (posYOld + 0.005))posY = posY + 0.00005;
				else { posZ = posZ + 0.00005;/* cout << posZ << endl; */}

				if (posZ > 0.01 && DefinitlyGameOver == 0){ LoadNextLevel = 1; _sleep(2500);}

				if (LoadNextLevel == 1 && CurrentLevel < 5){
					LoadNextLevel = 0;
					LevelFinished = 0;
					idx = 0;
					PlayerInJump = 0;
					CurrentLevel++;
					mscene = CUTIL::LoadBitmapFile(LevelsArray[CurrentLevel-1], &bitmapInfoHeader);

					posX = 0.01175;
					posY = 0.00175;
					posZ = 0.00348;
					LevelChanged = 1;
		
					//cout << "posX: " << posX << " posY: " << posY << " posZ: " << posZ << endl;
				}

			}

			if (findState(STATE_COLLISIONS_SCENE)) {

				if ((mscene[idx] == 0 && mscene[idx + 1] == 255 && mscene[idx + 2] == 255) && posZ < 0.0045) {
					PlayerPoints++;
					mscene[idx] = 255;
					mscene[idx + 1] = 0;
					mscene[idx + 2] = 0;
				}

				else if ((mscene[idx] == 0 && mscene[idx + 1] == 0 && mscene[idx + 2] == 255) && posZ < 0.0045) {
					PlayerLives++;
					mscene[idx] = 255;
					mscene[idx + 1] = 0;
					mscene[idx + 2] = 0;
				}
			}

			if (posZ == MaxH)PlayerInJump = 0;
			if (GameOver == 0 && LevelFinished == 0){
				posXOld = posX;
				posYOld = posY;

				//posX = posX + dt * 0.0005f * cos(rotation * 3.14f / 180.0f);
				//posY = posY + dt * 0.0005f * sin(rotation * 3.14f / 180.0f);
				posY = posY + speed;

				// wykrywanie kolizji z elementami sceny zdefiniowanymi w tablicy
				if (findState(STATE_COLLISIONS_SCENE)) {
					//bb = xy2mscene(posX, posY, idx);

					if ((mscene[idx] == 0 && mscene[idx + 1] == SCENE_COLLISION && mscene[idx + 2] == 0)) {
						LevelFinished = 1;
						//cout << "Koniec poziomu" << endl;
						LevelTime = TimeCounter.getTime();
						LevelTimeSeconds = TimeCounter.getSeconds();
						ScoreTab[CurrentLevel - 1][0] = CurrentLevel;
						ScoreTab[CurrentLevel - 1][1] = PlayerPoints;
						ScoreTab[CurrentLevel - 1][2] = LevelTime;
						ScoreTab[CurrentLevel - 1][3] = PlayerLives;
						TimeCounter.reset();

						if (CurrentLevel == 5)SaveScores();
						if (TimeCounter.isRunning())TimeCounter.stop();
					}

					bb = xy2mscene(posX, posY + 0.001, idx);
					if (posZ < GroundPosZ + 0.003 || bb )
					if ((mscene[idx] == 128 && mscene[idx + 1] == 0 && mscene[idx + 2] == 0)) {
							posY = posYOld;
							ZPrzoduMam = 1;
						}
					else ZPrzoduMam=0;
				}

				state_list.remove(STATE_MOVE_OBJECT_FORWARD);
			}
			break;


			///////////////////	ruch obiektu w lewo
		case STATE_MOVE_OBJECT_LEFT:
			posXOld = posX;

				//cout << posX << " " << posY << " " << posZ << endl;
				//cout << PlayerInFall << PlayerInJump << PlayerIsOnBlock<< PlayerOverBlock << PlayerIsOnGround << endl;
				if ((GameOver == 0 && LevelFinished == 0))
				{
					posX = posX - (DeltaMoveLeftRight*SmoothMoveLeft);
				}
			

			state_list.remove(STATE_MOVE_OBJECT_LEFT);
			break;


			///////////////////	ruch obiektu w prawo
		case STATE_MOVE_OBJECT_RIGHT:
			posXOld = posX;

				if (GameOver == 0 && LevelFinished == 0)
				{
					posX = posX + (DeltaMoveLeftRight*SmoothMoveRight);
				}
			
			state_list.remove(STATE_MOVE_OBJECT_RIGHT);
			break;

		/////////////////// skok obiektu

		case STATE_OBJECT_JUMP:

			if (GameOver == 0 && LevelFinished == 0){
				if (posZ < MaxH)
				{
					if (posZ > MaxH - 0.0014 && SmoothMoveUp > 0.1f)SmoothMoveUp -= SmoothSpeed;
					//cout << SmoothMoveUp << endl;

					posZ = posZ + (DeltaZJump*SmoothMoveUp);
				}
				else {
					 PlayerInJump = 0;	PlayerInFall = 1; SmoothMoveUp = 1.0;
				}


				//if (posZ == 0.0067)
				//{

				//DeltaZJump = DeltaZJump * 1.0005;
				//}
			}
			state_list.remove(STATE_OBJECT_JUMP);

			break;

		///////////////// spadek obiektu
		case STATE_OBJECT_FALL:
			posZOld = posZ;
			//DeltaZFall = DeltaZFall * 1.005;
			//posZ = posZ - DeltaZFall;
			bb = xy2mscene(posX, posY, idx);

			if ((mscene[idx] == 128 && mscene[idx + 1] == 0 && mscene[idx + 2] == 0) && posZ>0.0055)PlayerOverBlock = 1;
			else PlayerOverBlock = 0;
			if (PlayerInJump == 0 && LevelFinished == 0)
			{
				if (findState(STATE_COLLISIONS_SCENE)) {

					if ((mscene[idx] == 255 && mscene[idx + 1] == 0 && mscene[idx + 2] == 0) || (mscene[idx] == 0 && mscene[idx + 1] == 255 && mscene[idx + 2] == 0) || (mscene[idx] == 128 && mscene[idx + 1] == 0 && mscene[idx + 2] == 0) || (mscene[idx] == 0 && mscene[idx + 1] == 255 && mscene[idx + 2] == 255) || (mscene[idx] == 0 && mscene[idx + 1] == 0 && mscene[idx + 2] == 255)) {
						posZ = posZOld;
						if (SmoothMoveDown < 1.0f)SmoothMoveDown += SmoothSpeed;
						//cout << "SmoothDown : " << SmoothMoveDown << endl;
						//cout << "COLLISION" << endl;
						if (posZ > GroundPosZ && PlayerOverBlock == 0)
						{
							//DeltaZFall = DeltaZFall * 1.005;
							posZ = posZ - (DeltaZFall*SmoothMoveDown);
						}
						else if (posZ > GroundPosZ + 0.0033)
						{
							//DeltaZFall = DeltaZFall * 1.005;
							posZ = posZ - (DeltaZFall*SmoothMoveDown);
						}
						//DeltaZFall = 0.001;
						if (posZ > GroundPosZ - 0.0001 + 0.0033 && posZ < GroundPosZ + 0.0001 + 0.0033 && PlayerOverBlock == 1){ PlayerIsOnBlock = 1; SmoothMoveDown = 0.2; }
						else { PlayerIsOnBlock = 0; PlayerInFall = 0; }
						if (posZ > GroundPosZ - 0.0001 && posZ < GroundPosZ + 0.0001){ PlayerIsOnGround = 1; SmoothMoveDown = 0.2; }
						else { PlayerIsOnGround = 0; PlayerInFall = 0; }
					}

					else

					{
						//DeltaZFall = DeltaZFall * 1.05;
						posZ = posZ - DeltaZFall;
						if (posZ < GroundPosZ){ GameOver = 1; DeltaZFall = 0.0003; }
						if (posZ < -0.025){ GameOver = 0, PlayerLives--; DeltaZFall = 0.00024; posX = StartX; posY = StartY; posZ = StartZ; }
					}
				}
			}
			if (PlayerInJump == 0 && PlayerInFall == 0)MaxH = 0.0058;
			state_list.remove(STATE_OBJECT_FALL);
			break;
		
			/////////////////// kolizje
			/*case STATE_COLLISIONS:
				if (detectCollision(collisionTarget))
				pmaterial = MATERIAL_PLAYER_BLUE;
				else
				pmaterial = MATERIAL_PLAYER_RED;
				state_list.remove(STATE_COLLISIONS);
				break;
				*/

			///////////////////	rysowanie obiektu
		case STATE_DRAW_OBJECT:
			if(LevelChanged!=1)drawObject();
			InGame = 1;
			break;

			///////////////////	rysowanie obiektu
		case STATE_DRAW_SCENE:
			if (LevelChanged != 1)drawScene();
			break;

			/*////////////////// ruch, kolizje i kasowanie pociskow
			case STATE_MISSLE:
			for( it = missle_list.begin(); it != missle_list.end(); it++) {

			(*it)->x = (*it)->x + dt * 0.0005f * cos( (*it)->dir * 3.14f / 180.0f );
			(*it)->y = (*it)->y + dt * 0.0005f * sin( (*it)->dir * 3.14f / 180.0f );

			// kolizje pocisku ze scianami planszy
			bb = xy2mscene( (*it)->x, (*it)->y, idx );
			if( bb || (mscene[idx] == SCENE_COLLISION && mscene[idx+1] == SCENE_COLLISION && mscene[idx+2] == SCENE_COLLISION) ) {
			mscene[idx] = 0;
			mscene[idx+1] = 0;
			mscene[idx+2] = 0;
			delete (*it);
			missle_list.erase( it );
			break;
			}

			// skasowanie pocisku po przekroczeniu granic planszy
			if( (*it)->x < 0 || (*it)->x > 1 || (*it)->y < 0 || (*it)->y > 1 ) {
			delete (*it);
			missle_list.erase( it );
			break;
			}
			else
			drawMissle( *it );
			}
			break;
			*/
			////////////////// ruch pociskow
		case STATE_WAIT:
			t_wait = t_wait + dt;
			break;

		case STATE_DRAW_BACKGROUND:

		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glLoadIdentity();
		glOrtho(0.0f, ScreenWidth, 0.0f, ScreenHeight, -100.0f, 1.0f);

		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();

		glLoadIdentity();
		glDisable(GL_LIGHTING);

		//glColor3f(1, 1, 1);

		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, BackgroundTexture);

		// Draw a textured quad
		glBegin(GL_QUADS);
		//glRotatef(-30 .0f,0.0f, 0.0f,1.0f);
		glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
		glTexCoord2f(0, 1); glVertex3f(0, ScreenHeight, 0);
		glTexCoord2f(1, 1); glVertex3f(ScreenWidth, ScreenHeight, 0);
		glTexCoord2f(1, 0); glVertex3f(ScreenWidth, 0, 0);
		glEnd();
		glDisable(GL_TEXTURE_2D);

		glPopMatrix();
		glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);

		glEnable(GL_LIGHTING);
		break;
		
		case STATE_DRAW_GAMEOVER:

			if (keyStates[27])exit(0);

			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();
			glOrtho(0.0f, ScreenWidth, 0.0f, ScreenHeight, -5.0f, 1.0f);

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();

			glLoadIdentity();
			glDisable(GL_LIGHTING);

			glColor3f(1, 1, 1);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, GameOverTexture);

			// Draw a textured quad
			glBegin(GL_QUADS);
			glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
			glTexCoord2f(0, 1); glVertex3f(0, ScreenHeight, 0);
			glTexCoord2f(1, 1); glVertex3f(ScreenWidth, ScreenHeight, 0);
			glTexCoord2f(1, 0); glVertex3f(ScreenWidth, 0, 0);
			glEnd();

			glDisable(GL_TEXTURE_2D);
			glPopMatrix();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
			glMatrixMode(GL_MODELVIEW);

			glPushMatrix();
			glDisable(GL_LIGHTING);

			glColor3f(1.0f, 1.0f, 1.0f);
			///////////////////////////////////////////////////////////////////////////////////////////////////////////
			if (CurrentLevel == LevelCount)SummaryPoints = ((CurrentLevel)* 1000) + (1000 - (SummaryTime*0.002)) + (SummaryStars)+(PlayerLives * 20);
			else SummaryPoints = ((CurrentLevel-1)* 1000) + (1000 - (SummaryTime*0.002)) + (SummaryStars)+(PlayerLives * 20);
			if (CurrentLevel == LevelCount)DrawOnGameOver("Levels Completed : ", CurrentLevel , " x 1000 = ", (CurrentLevel) * 1000, HudX - 0.003, HudY - 0.01, HudZ+0.001);
			else DrawOnGameOver("Levels Completed : ", CurrentLevel - 1, " x 1000 = ", (CurrentLevel - 1) * 1000, HudX - 0.003, HudY - 0.01, HudZ + 0.001);
			DrawOnGameOver("Total Time : 1000 - (", SummaryTime, "ms x 0.002) = ", 1000 - (SummaryTime*0.002), HudX - 0.003, HudY - 0.01, HudZ);
			DrawOnGameOver("Total Stars : ", SummaryStars, " x 1 = ", SummaryStars, HudX - 0.003, HudY - 0.01, HudZ - 0.001);
			DrawOnGameOver("Live Points : ", PlayerLives, " x 20 = ", PlayerLives*20, HudX - 0.003, HudY - 0.01, HudZ - 0.002);

			TotalPointsString = "Total Points : ";
			TotalPointsValueString = to_string(SummaryPoints);
			TotalPointsStringLength = TotalPointsString.length();
			TotalPointsValueStringLength = TotalPointsValueString.length();


			glRasterPos3f(HudX - 0.0013, HudY - 0.01, HudZ - 0.0040);
			for (int i = 0; i < TotalPointsStringLength; i++)
			{
				glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, TotalPointsString[i]);
			}
			for (int i = 0; i < TotalPointsValueStringLength; i++)
			{
				glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, TotalPointsValueString[i]);
			}


			PressEscape = "PRESS ESC KEY TO EXIT";
			glRasterPos3f(HudX - 0.0023, HudY - 0.01, HudZ - 0.01);
			for (int i = 0; i < PressEscape.length(); i++)
			{
				glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, PressEscape[i]);
			}

			glEnable(GL_LIGHTING);

			glPopMatrix();

			state_list.remove(STATE_DRAW_GAMEOVER);
			break;
			

		case STATE_DRAW_MENU:
			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();
			glOrtho(0.0f, ScreenWidth, 0.0f, ScreenHeight, -5.0f, 1.0f);

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();

			glLoadIdentity();
			glDisable(GL_LIGHTING);

			glColor3f(1, 1, 1);
			glEnable(GL_TEXTURE_2D);

			if(MenuToken == 0)glBindTexture(GL_TEXTURE_2D, PlayGame);
			if(MenuToken == 1)glBindTexture(GL_TEXTURE_2D, ExitGame);
			// Draw a textured quad
			glBegin(GL_QUADS);
			glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
			glTexCoord2f(0, 1); glVertex3f(0, ScreenHeight, 0);
			glTexCoord2f(1, 1); glVertex3f(ScreenWidth, ScreenHeight, 0);
			glTexCoord2f(1, 0); glVertex3f(ScreenWidth, 0, 0);
			glEnd();

			glDisable(GL_TEXTURE_2D);
			glPopMatrix();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
			glMatrixMode(GL_MODELVIEW);

			glPushMatrix();
			glDisable(GL_LIGHTING);

			glColor3f(1.0f, 1.0f, 1.0f);

			///////////////////////////////////////////////////////////////////////////////////////////////////////////

			glEnable(GL_LIGHTING);

			glPopMatrix();
			break;

		case STATE_DRAW_HUD:

			glPushMatrix();
			glDisable(GL_LIGHTING);

			glColor3f(1.0f, 1.0f, 1.0f);

			///////////////////////////////////////////////////////////////////////////////////////////////////////////
	
			DrawOnHUDStringAndValue("Collected Stars: ", PlayerPoints,0.008,0.012,0);
			if(LevelFinished==0)DrawOnHUDStringAndValue("Time: ", TimeCounter.getSeconds(), -0.011, 0.012,1);
			else DrawOnHUDStringAndValue("Time: ", LevelTimeSeconds, -0.011, 0.012, 1);
			//glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, int('m'));
			glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, int('s'));
			DrawOnHUDStringAndValue("Level ", CurrentLevel,-0.0007, 0.014, 0);
			DrawOnHUDStringAndValue("Lives: ", PlayerLives, +0.008, 0.011, 0);

			glEnable(GL_LIGHTING);

			glPopMatrix();
			break;
			}
	}
	glPopMatrix();

	// wyswietlenie tylniego ekranu
	glutSwapBuffers(); 
	
	// wymuszenie przerysowania podczas następnej synchronizacji ekranu
	glutPostRedisplay(); 
}


///////////////////////////////////////// rysowanie obiektu
/*
void CGL::drawMissle( CMissle* cm ) {

	setMaterial( MATERIAL_WALL_RED );

	glPushMatrix();
	glTranslatef( cm->x, cm->y, 0.05f );
	glScalef( 0.01f, 0.01f, 0.01f );	

	//if( findState( STATE_COLLISIONS ) ) {
		//glGetFloatv( GL_MODELVIEW_MATRIX, collisionTarget.m );
		//collisionTarget.r = 0.025f;
	//}

	glutSolidSphere( 0.4, 20, 20 );
	glPopMatrix();

}
*/
///////////////////////////////////////// rysowanie obiektu	

void CGL::drawObject( void ) {

	setMaterial(MATERIAL_PLAYER_GRAY);

	glPushMatrix();
	glTranslatef( posX, posY, posZ);
	glRotatef( rotation, 0.0f, 0.0f, 1.0f );
	glRotatef( 90.0f, 1.0f, 0.0f, 0.0f );
	glScalef( 0.05f, 0.05f, 0.05f );	

	/*
	if( findState( STATE_COLLISIONS ) ) {
		glGetFloatv( GL_MODELVIEW_MATRIX, collisionTarget.m );
		collisionTarget.r = 0.025f;
	}
	*/

	//glutSolidTeapot(0.5 / (mscene_height/10));
	if (keyStates['d'] && LevelFinished == 0 && GameOver == 0)glCallList(SpaceShipRightModel);
	else if (keyStates['a'] && LevelFinished == 0 && GameOver == 0)glCallList(SpaceShipLeftModel);
	else glCallList(SpaceShipModel);
	glPopMatrix();
	
}

///////////////////////////////////////// rysowanie obiektow na scenie w oparciu o dane bitmapy
void CGL::drawScene( void ) {
	if (StarRotateAngle<360)StarRotateAngle = StarRotateAngle + (5/Scale);
	else StarRotateAngle = 0;

	if( findState( STATE_COLLISIONS ) )
		collision_list.clear(); // skasowanie listy kolizji

//#define CompleteFill 0.00170f
#define CompleteFill 0.0016f
	glPushMatrix();

	for( int c = 0; c < mscene_height; c++ ) {
		for( int w = 0; w < mscene_width; w++ ) {

			int idx = xy2idx( w, c );

			if (mscene[idx] == 255 && mscene[idx + 1] == 0 && mscene[idx + 2] == 0) { // czarne elementy - szesciany ( 255,0,0 BMP)
				// kolor obiektu
			setMaterial(MATERIAL_WALL_BLACK);

				glPushMatrix();

				glTranslatef(
					(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
					(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
					0.0f);
		
				glScalef(
					1.0f / (float)mscene_height - CompleteFill,
					1.0f / (float)mscene_height - CompleteFill,
					1.0f / (float)mscene_height - CompleteFill);

				CUTIL::drawBox();
				glPopMatrix();
			}
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

				if (mscene[idx] == 0 && mscene[idx + 1] == 255 && mscene[idx + 2] == 0) { // zielone elementy meta ( 0,255,0 BMP)

					// kolor obiektu
					setMaterial(MATERIAL_WALL_GREEN);

					glPushMatrix();

					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						0.0f);


					glScalef(
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill);

				CUTIL::drawBox();
				glPopMatrix();
				
				
			}

				if (mscene[idx] == 128 && mscene[idx + 1] == 0 && mscene[idx + 2] == 0) { // czarne elementy - sciany ( 128,0,0 BMP)

					// kolor obiektu
					setMaterial(MATERIAL_WALL_BLACK);

					glPushMatrix();

					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						0.003f);


					glScalef(
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill);


					CUTIL::drawBox();
					glPopMatrix();

					glPushMatrix();

					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						0.0f);


					glScalef(
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill);


					CUTIL::drawBox();
					glPopMatrix();
				}

				
				if (mscene[idx] == 0 && mscene[idx + 1] == 255 && mscene[idx + 2] == 255) { // zolter elementy - gwiazdki ( 0,255,255 BMP )

					// kolor obiektu
					setMaterial(MATERIAL_WALL_YELLOW);
					glPushMatrix();

					/////////////////////////////////////////////////////////////////////////////////////////////////////
					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						 0.0033);

					//glScalef(
					//	1.0f / (float)mscene_height - CompleteFill,
					//	1.0f / (float)mscene_height - CompleteFill,
					//	3 * (1.0f / (float)mscene_height - CompleteFill));
					
					glRotatef(StarRotateAngle, 0, 0, 1);
					glCallList(StarModel);
					//glRotatef(0.5f, 0, 1, 0);
					glPopMatrix();


					setMaterial(MATERIAL_WALL_BLACK);

					glPushMatrix();

					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						0.0f);


					glScalef(
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill);

					CUTIL::drawBox();
					glPopMatrix();
				}


				if (mscene[idx] == 0 && mscene[idx + 1] == 0 && mscene[idx + 2] == 255) { // czerwone elementy - zycia ( 0,0,255 BMP )

					// kolor obiektu
					setMaterial(MATERIAL_WALL_RED);
					glPushMatrix();

					/////////////////////////////////////////////////////////////////////////////////////////////////////
					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						0.0033);

					//glScalef(
					//	1.0f / (float)mscene_height - CompleteFill,
					//	1.0f / (float)mscene_height - CompleteFill,
					//	3 * (1.0f / (float)mscene_height - CompleteFill));

					glRotatef(StarRotateAngle, 0, 0, 1);
					glCallList(HeartModel);
					//glRotatef(0.5f, 0, 1, 0);
					glPopMatrix();


					setMaterial(MATERIAL_WALL_BLACK);

					glPushMatrix();

					glTranslatef(
						(float)w / (float)mscene_height + 0.5f / (float)mscene_height,
						(float)c / (float)mscene_height + 0.5f / (float)mscene_height,
						0.0f);


					glScalef(
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill,
						1.0f / (float)mscene_height - CompleteFill);

					CUTIL::drawBox();
					glPopMatrix();
				}
		}
	}
	glPopMatrix();
}

///////////////////////////////////////// obsluga klawiatury

void CGL::keyUp( unsigned char key,int a,int b ) {
	
	keyStates[key] = false;	
}

void CGL::keyPress( unsigned char key,int a,int b ) {

	keyStates[key] = true;
}
	
void CGL::keyOperations( void ) {	
	
	if (keyStates[27]) {
		exit(0);
	}

	// ruch obiektu w lewo
	if (keyStates['a']) {
		SmoothMoveRight = 0.1f;
		if (SmoothMoveLeft < 1.0f)SmoothMoveLeft += SmoothSpeed;
		if (!findState(STATE_MOVE_OBJECT_LEFT)) {
			state_list.remove( STATE_MOVE_OBJECT_RIGHT );
			state_list.push_front( STATE_MOVE_OBJECT_LEFT );	
		}
	}

	if (!keyStates['a'] && SmoothMoveLeft > 0.1f) {
		SmoothMoveLeft -= SmoothSpeed;
		if (!findState(STATE_MOVE_OBJECT_LEFT)) {
			state_list.remove(STATE_MOVE_OBJECT_RIGHT);
			state_list.push_front(STATE_MOVE_OBJECT_LEFT);
		}
	}

	// ruch obiektu w prawo
	if (keyStates['d']) {
		SmoothMoveLeft = 0.1f;
		if (SmoothMoveRight < 1.0f)SmoothMoveRight += SmoothSpeed;

		if (!findState(STATE_MOVE_OBJECT_RIGHT)) {
			state_list.remove(STATE_MOVE_OBJECT_LEFT);
			state_list.push_front(STATE_MOVE_OBJECT_RIGHT);
		}
	}

	if (!keyStates['d'] && SmoothMoveRight > 0.1f) {
		SmoothMoveRight -= SmoothSpeed;
		if (!findState(STATE_MOVE_OBJECT_RIGHT)) {
			state_list.remove(STATE_MOVE_OBJECT_LEFT);
			state_list.push_front(STATE_MOVE_OBJECT_RIGHT);
		}
	}

	// ruch obiektu do przodu
	if (/*keyStates['w']*/ 1 ) {
		if (!findState(STATE_MOVE_OBJECT_FORWARD)) {
			state_list.push_front( STATE_MOVE_OBJECT_FORWARD );	
		}
	}

	// skok obiektu
	if (keyStates[' '] && GameOver == 0 && PlayerIsOnBlock == 0 && PlayerIsOnGround == 1 && PlayerInJump == 0 && PlayerInFall == 0){ PlayerInJump = 1; }
	if (keyStates[' '] && GameOver == 0 && PlayerIsOnGround == 0 && PlayerIsOnBlock == 1 && PlayerInJump == 0 && PlayerInFall == 0){ PlayerInJump = 1; MaxH = 1.5 * MaxH; }
	if (!findState(STATE_OBJECT_JUMP && PlayerInJump == 1)){
		state_list.push_front(STATE_OBJECT_JUMP);
	}


	/*
	// strzelanie
	if ( keyStates['f'] ) {

		if (findState(STATE_WAIT)) { 
			if( t_wait > t_wait_time )
				state_list.remove( STATE_WAIT );
		}
		else {
			CMissle* cm = new CMissle();
			cm->x = posX;
			cm->y = posY;
			cm->dir = rotation;
			missle_list.push_back( cm );

			// kolejny pocisk bedzie mozna utworzyc po 100 [msec]
			t_wait = 0;
			t_wait_time = 100;
			state_list.push_front( STATE_WAIT );
		}

	}
	*/

	// spadek obiektu
	if (!findState(STATE_OBJECT_FALL)) {
		state_list.push_front(STATE_OBJECT_FALL);
	}


	//if(PlayerLives==0)state_list.push_front(STATE_DRAW_GameOver);
	/*
	if (posZ > 0.037)
	{
		DeltaZFall = DeltaZFall * 1.005;
		posZ = posZ - DeltaZFall;
	}
	*/

	if (PlayerLives == 0 || (CurrentLevel ==5 && LoadNextLevel==1))
	{

		if(DefinitlyGameOver==0)CalculatePoints();
		DefinitlyGameOver = 1;
		//PlayerLives = -1;
		//CurrentLevel = -1;
		//state_list.remove(STATE_COLLISIONS);
		state_list.remove(STATE_DRAW_SCENE);
		state_list.remove(STATE_DRAW_OBJECT);
		state_list.remove(STATE_DRAW_HUD);
		state_list.remove(STATE_DRAW_BACKGROUND);
		state_list.remove(STATE_NEW_LIGHT);
		state_list.remove(STATE_COLLISIONS_SCENE);
		state_list.push_front(STATE_DRAW_GAMEOVER);
	}

	if (keyStates['w'])MenuToken = 0;
	if (keyStates['s'])MenuToken = 1;
	if (MenuToken == 1 && keyStates[13] && InGame==0)exit(0);
	if (MenuToken == 0 && keyStates[13]){
		EnableStates = 1; state_list.remove(STATE_DRAW_MENU); CGL::init();
	}
}
