#include "MojeOkno.h"
#include "Varia.h" //JednostkowyWektorNormalny3fv
#include "Modele.h" //Rysuj...
//#include "glext.h"
#include "resource.h"

#include "Testy.cpp"
#include "Wektor.h"
#include <time.h>

CMojeOknoGL::CMojeOknoGL()
	:aktor(kostkaZTeksturami),program(NULL)
{	
}

void CMojeOknoGL::RysujAktorow()
{	
	static bool shaderyZainicjowane=false;
	if (!shaderyZainicjowane)
	{
		shaderyZainicjowane=true;
		if(CzyShaderyDostepne()) program=PrzygotujShadery();		
		if(program==NULL) MessageBox(NULL,"Błąd inicjacji shaderów. Próby ich inicjacji nie będą ponawiane","OpenGL GLSL",MB_OK);
	}

	static float czas=0.0f;
	czas+=0.01f;
	ZmienStalaCzas(program,czas);

	static bool teksturyZainicjowane=false;
	if (!teksturyZainicjowane)
	{
		PrzygotujTekstury();
		teksturyZainicjowane=true;
	}	

	const float x0=1.0; 
	const float y0=1.0; 
	const float z0=1.0; 		
	
	switch(aktor)
	{
	case trojkat:
		RysujTrojkat(x0,y0,0);
		break;

	case bialaKostka:
		glColor3f(1.0f,1.0f,1.0f);
		Modele::RysujSzescian(2*x0,false,false,NULL);
		break;

	case kolorowaKostka:
		Modele::RysujSzescian(2*x0,true,false,NULL);
		break;

	case kostkaZTeksturami:
		glColor3f(1.0f,1.0f,1.0f);
		glEnable(GL_TEXTURE_2D);
		WiazDwieTekstury(program,indeksTekstury);
		Modele::RysujSzescian(2*x0,false,false,NULL);
		ZwolnijDwieTekstury();
		glDisable(GL_TEXTURE_2D);
		break;

	case sfera:		
		glColor3f(1.0f,1.0f,1.0f);
		Modele::RysujSfere_Shadery(program,2*x0,indeksTekstury);
		break;

	case latarnia:
		{
		float poziomMorza=-1.75f*y0;

		//przygotowanie szablonu
		glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); //wylaczenie rysowania do bufora pikseli
		glDisable(GL_DEPTH_TEST); //wyłaczenie testu głebokości
		glEnable(GL_STENCIL_TEST); //właczenie testu szablonu	
		glStencilFunc(GL_ALWAYS,1,~0); //funkcja testu szablonu: tworzenie szablonu
		glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
		glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); //ukrywanie w szablonie dolnej powierzchni lustra	
		Modele::RysujOcean(x0,poziomMorza,z0); //rysowanie powierzchni lustra do szablonu
		glDisable(GL_CULL_FACE); //wylaczenie ukrywania powierzchni
		glDisable(GL_STENCIL_TEST); //wylaczenie testu szablonu
		glEnable(GL_DEPTH_TEST); //przywrocenie bufora glebii	
		glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); //przywrocenie rysowania do bufora pikseli
	
		//przygotowanie bufora szablonowego do korzystania z szablonu
		glStencilFunc(GL_EQUAL,1,~0); //funkcja testu szablonu: uzycie szablonu
		glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); //szablon pozostawiany bez zmian

		//plaszczyzny obcinajace
		double rownanie_plaszczyzny_obcinajacej_odbicie[4]={0.0,-1,0.0,poziomMorza};
		glClipPlane(GL_CLIP_PLANE0,rownanie_plaszczyzny_obcinajacej_odbicie);
		double rownanie_plaszczyzny_obcinajacej_latarnie[4]={0.0,1,0.0,-poziomMorza};
		glClipPlane(GL_CLIP_PLANE1,rownanie_plaszczyzny_obcinajacej_latarnie);

		//odbicie		
		glEnable(GL_STENCIL_TEST);
		glEnable(GL_CLIP_PLANE0);
		glPushMatrix();
		glTranslatef(-0.25f*x0,poziomMorza-2*x0,0);
		glScalef(1,-1,1);	
		Modele::RysujLatarnie(2.5f*x0);
		glPopMatrix();
		glDisable(GL_CLIP_PLANE0);
		glDisable(GL_STENCIL_TEST);
	
		//ocean
		Modele::RysujOcean(x0,poziomMorza,z0);

		//latarnia	
		glEnable(GL_CLIP_PLANE1);
		glPushMatrix();
		glTranslatef(-0.25f*x0,poziomMorza+2*x0,0);
		Modele::RysujLatarnie(2.5f*x0);
		glPopMatrix();
		glDisable(GL_CLIP_PLANE1);	
		}
		break;
	}
}

#pragma region Aktorzy
//Wiekszosc aktorow jest w klasie Modele (Modele.h/Modele.cpp)

void CMojeOknoGL::RysujTrojkat(float x0,float y0,float z0) const
{
	//Rysowanie trojkata 
	glBegin(GL_TRIANGLES); 
	//ustalanie trzech wierzcholkow trojkata (werteksow (x,y,z)) 
	//(0,0,z) jest mniej wiecej w srodku ekranu 
	glColor3f(1.0,0.0,0.5);
	glVertex3f(-x0, -y0, 0); //dolny lewy 
	glColor3f(0.5,0.0,1.0);
	glVertex3f(x0, -y0, 0); //dolny prawy 
	glColor3f(0.0,1.0,0.5);
	glVertex3f(0, y0, 0); //gorny 
	//koniec rysowania figury 
	glEnd();
}
#pragma endregion


//lista wyswietlania
unsigned int CMojeOknoGL::TworzListyWyswietlania(float dx,float dy,float dz,bool koloruj) const
{
	GLuint listyWyswietlania=glGenLists(2);

	glNewList(listyWyswietlania,GL_COMPILE); //EXECUTE - bo mamy dowolne parametry potencjalnie nieznane w momencie kompilacji
	Modele::RysujSzescian(dx,koloruj,true,indeksTekstury);
	glEndList();

	glNewList(listyWyswietlania+1,GL_COMPILE); //EXECUTE - bo mamy dowolne parametry potencjalnie nieznane w momencie kompilacji
	Modele::RysujNiszczycielaGwiazd(3*dx,3*dy,3*dz);
	glEndList();

	return listyWyswietlania;
}

#pragma region Animacja
//timer animacji
#include <mmsystem.h>

LRESULT CMojeOknoGL::WndProc(HWND hWnd, UINT message, WPARAM wParam,LPARAM lParam)
{	
	const bool ANIMACJA=false;
	const int IDT_TIMER_ANIMACJI=1;

	long wynik=COknoGL::WndProc(hWnd,message,wParam,lParam);

	//wybor aktora
	switch(message)
	{		
		//zeby to dzialalo - wylaczylem w OknoGL::WndProc wlaczniki swiatel
		case WM_KEYDOWN:	
			switch(wParam)
			{
				case VK_F1: aktor=trojkat; break;
				case VK_F2: aktor=bialaKostka; break;
				case VK_F3: aktor=kolorowaKostka; break;
				case VK_F4: aktor=kostkaZTeksturami; break;
				case VK_F5: aktor=sfera; break;
				case VK_F6: aktor=latarnia; break;
			}
			RysujScene();
			break;
	}
	
	//dalsza czesc tylko w animacji
	if(!ANIMACJA) 
	{
		przesuniecie=10;
		return wynik;
	}	

	switch (message)
	{
		case WM_CREATE: //pole uchwyt okna nie jest zainicjowane w WM_CREATE -> uzywac hWnd
			if (SetTimer(hWnd,IDT_TIMER_ANIMACJI,50,NULL)==0)
				MessageBox(hWnd,"Nie udało się ustawić timera","",MB_OK | MB_ICONERROR);
			przesuniecie=0;
			poprzedniCzas=GetTickCount();
			PlaySound("M:\\MUZYKA\\Imperial March.wav",NULL,SND_FILENAME | SND_ASYNC);						
			break;
		case WM_TIMER:
			switch(wParam)
			{
				case IDT_TIMER_ANIMACJI:					
					long biezacyCzas=GetTickCount();
					przesuniecie+=0.0005f*(biezacyCzas-poprzedniCzas);
					poprzedniCzas=biezacyCzas;
					RysujScene();
					break;
			}
			wynik=0;
			break;
		case WM_DESTROY:
			KillTimer(uchwytOkna,IDT_TIMER_ANIMACJI);
			break;
	}
	
	return wynik;
}
#pragma endregion

#pragma region Zrodla swiatla
//zrodla swiatla
void CMojeOknoGL::ZrodlaSwiatla()
{
	natezenie_swiatla_tla=0.5f;
	MlecznaZarowka(0.5f);
	ZoltaIZielonaMleczneZarowki();
	Reflektor(1.0f,0.0f);

	/*
	//mgla
	glEnable(GL_FOG);
	const float biel[4]={1.0,1.0,1.0,1.0};
	glFogfv(GL_FOG_COLOR,biel);
	glFogf(GL_FOG_START,0.0);
	glFogf(GL_FOG_END,100.0);
	glFogf(GL_FOG_MODE,GL_LINEAR);
	*/	
}


void CMojeOknoGL::MlecznaZarowka(float jasnosc)
{	
	const float kolor[4]={jasnosc,jasnosc,jasnosc,1.0f};
	const float pozycja[4]={5.0f,0.0f,-5.0f,1.0f};	
	glLightfv(GL_LIGHT1,GL_POSITION,pozycja);
	glLightfv(GL_LIGHT1,GL_DIFFUSE,kolor);
	glEnable(GL_LIGHT1);
}

void CMojeOknoGL::ZoltaIZielonaMleczneZarowki()
{
	//zolta mleczna zarowka
	const float kolor_zolta[4]={1.0f,1.0f,0.0f,1.0f};
	const float pozycja_zolta[4]={-2.0f,0.0f,1.0f,1.0f};
	glLightfv(GL_LIGHT2,GL_POSITION,pozycja_zolta);
	glLightfv(GL_LIGHT2,GL_DIFFUSE,kolor_zolta);
	//glEnable(GL_LIGHT2);

	//zielona mleczna zarowka
	const float kolor_zielony[4]={0.0f,1.0f,0.0f,1.0f};
	const float pozycja_zielony[4]={2.0f,0.0f,1.0f,1.0f};
	glLightfv(GL_LIGHT3,GL_POSITION,pozycja_zielony);
	glLightfv(GL_LIGHT3,GL_DIFFUSE,kolor_zielony);
	//glEnable(GL_LIGHT3);
}

void CMojeOknoGL::Reflektor(float jasnoscRozblysk,float jasnoscRozproszone)
{
	const float kolor_rozproszone[4]={jasnoscRozproszone,jasnoscRozproszone,jasnoscRozproszone,1.0f};
	const float kolor_rozblysk[4]={jasnoscRozblysk,jasnoscRozblysk,jasnoscRozblysk,1.0};
	const float pozycja[4]={-10.0f,-10.0f,10.0f,1.0f};	
	const float kierunek[4]={1.0,1.0,-1.0,1.0};   
	const float szerokosc_wiazki=30.0f; //w stopniach
	const float wygaszanie=1.0f;
   
	glLightfv(GL_LIGHT4,GL_POSITION,pozycja);
	glLightfv(GL_LIGHT4,GL_DIFFUSE,kolor_rozproszone);

	glLightfv(GL_LIGHT4,GL_SPECULAR,kolor_rozblysk);
	glLightfv(GL_LIGHT4,GL_SPOT_DIRECTION,kierunek);
	glLightf(GL_LIGHT4,GL_SPOT_CUTOFF,szerokosc_wiazki);
	glLightf(GL_LIGHT4,GL_SPOT_EXPONENT,wygaszanie);
	glEnable(GL_LIGHT4);
}
#pragma endregion


#pragma region Teksturowanie
//aktywna moze byc tylko jedna z ponizszych definicji
//#define TeksturaDlaSfery //Ziemia
#define TeksturaDlaNiszczycielaGwiazd
//#define TekstuaCzytanaZPliku //Nefryt
//#define TeksturyGenerowaneZeWzoru

#ifdef TeksturaDlaSfery
void CMojeOknoGL::PrzygotujTekstury()
{
	const int ILOSC_TEKSTUR=1;
	glGenTextures(ILOSC_TEKSTUR,indeksTekstury); //generowanie identyfikatora do tekstur (uchwytow, name to mylna nazwa)

	char* nazwyTekstur[ILOSC_TEKSTUR]={"tekstura.bmp"};

	int teksturaSzer;
	int teksturaWys;
	for(int it=0;it<ILOSC_TEKSTUR;it++)
	{
		//wczytanie tekstury
		unsigned long* tekstura=WczytajTeksture(uchwytOkna,nazwyTekstur[it],teksturaSzer,teksturaWys,false,255);

		glBindTexture(GL_TEXTURE_2D,indeksTekstury[it]); //kolejne polecenia beda dotyczyc tej tekstury
	
		//tworzenie tekstury z tablicy bitow
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		//glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

		gluBuild2DMipmaps(GL_TEXTURE_2D,3,teksturaSzer,teksturaWys,GL_RGBA,GL_UNSIGNED_BYTE,tekstura);			
		//glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,teksturaSzer,teksturaWys, 0, GL_RGBA, GL_UNSIGNED_BYTE, tekstura);
	
		delete[] tekstura; //oryginalne dane sa usuwane	
	}
}
#endif
#ifdef TeksturaDlaNiszczycielaGwiazd
void CMojeOknoGL::PrzygotujTekstury()
{
	const int ILOSC_TEKSTUR=2;
	glGenTextures(ILOSC_TEKSTUR,indeksTekstury); //generowanie identyfikatora do tekstur (uchwytow, name to mylna nazwa)

	char* nazwyTekstur[ILOSC_TEKSTUR]={"tekstura1.bmp","tekstura2.bmp"};

	int teksturaSzer;
	int teksturaWys;
	for(int it=0;it<ILOSC_TEKSTUR;it++)
	{
		//wczytanie tekstury
		unsigned long* tekstura=WczytajTeksture(uchwytOkna,nazwyTekstur[it],teksturaSzer,teksturaWys,false,255);
		//unsigned long* tekstura=WczytajTeksture(uchwytOkna,MAKEINTRESOURCE(IDB_DEATHSTAR),teksturaSzer,teksturaWys,true,255);

		glBindTexture(GL_TEXTURE_2D,indeksTekstury[it]); //kolejne polecenia beda dotyczyc tej tekstury
	
		//tworzenie tekstury z tablicy bitow
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
		glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

		gluBuild2DMipmaps(GL_TEXTURE_2D,4,teksturaSzer,teksturaWys,GL_RGBA,GL_UNSIGNED_BYTE,tekstura);	
	
		delete[] tekstura; //oryginalne dane sa usuwane	
	}
}
#endif

#ifdef TekstuaCzytanaZPliku
void CMojeOknoGL::PrzygotujTekstury()
{
	glGenTextures(1,indeksTekstury); //generowanie identyfikatora do tekstur (uchwytow, name to mylna nazwa)

	int teksturaSzer;
	int teksturaWys;
	//wczytanie tekstury
	//unsigned long* tekstura=WczytajTeksture(uchwytOkna,"Nefryt.bmp",teksturaSzer,teksturaWys,false,255);	
	unsigned long* tekstura=WczytajTeksture(uchwytOkna,MAKEINTRESOURCE(IDB_NEFRYT),teksturaSzer,teksturaWys,true,255);
	//unsigned long* tekstura=WczytajTeksture(uchwytOkna,"tekstura_24bit.bmp",teksturaSzer,teksturaWys,128);
	//unsigned long* tekstura=WczytajTeksture(uchwytOkna,"tekstura_1bit.bmp",teksturaSzer,teksturaWys,128);
	//unsigned long* tekstura=WczytajTeksture(uchwytOkna,"tekstura_8bit.bmp",teksturaSzer,teksturaWys,128);
	//unsigned long* tekstura=WczytajTeksture(uchwytOkna,"tekstura_4bit.bmp",teksturaSzer,teksturaWys,128);

	glBindTexture(GL_TEXTURE_2D,indeksTekstury[0]); //kolejne polecenia beda dotyczyc tej tekstury
	
	//tworzenie tekstury z tablicy bitow
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
	//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
	//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

	gluBuild2DMipmaps(GL_TEXTURE_2D,4,teksturaSzer,teksturaWys,GL_RGBA,GL_UNSIGNED_BYTE,tekstura);
	
	delete[] tekstura; //oryginalne dane sa usuwane	
}
#endif

#ifdef TeksturyGenerowaneZeWzoru
//Trzy tekstury dla szescianu
void CMojeOknoGL::PrzygotujTekstury()
{
	const int ILOSC_TEKSTUR=3;
	glGenTextures(ILOSC_TEKSTUR,indeksTekstury); //generowanie identyfikatora do tekstur (uchwytow, name to mylna nazwa)

	int teksturaSzer=4;
	int teksturaWys=4;

	unsigned long* tekstura[ILOSC_TEKSTUR];
	for(int it=0;it<ILOSC_TEKSTUR;it++)
	{
		//przygotowanie trzech tablicy pikseli
		tekstura[it]=new unsigned long[teksturaSzer*teksturaWys]; //32-bity na piksel
		for(int ih=0;ih<teksturaWys;ih++)
			for(int iw=0;iw<teksturaSzer;iw++)
			{
				bool ciemniejsza=((iw+ih)%2)?true:false;
				unsigned char R=0,G=0,B=0,A=128;
				switch(it)
				{
					case 0:
						R=0; 
						G=(ciemniejsza)?0:255;
						B=255;
						break;
					case 1:
						R=255; 
						G=0;
						B=(ciemniejsza)?0:255;;
						break;
					case 2:
						R=(ciemniejsza)?0:255; 
						G=255;
						B=0;
						break;
				}
				tekstura[it][iw+(ih*teksturaSzer)]=(A << 24) + (B << 16) + (G << 8) + (R);
			}	
	}
	
	for(int it=0;it<ILOSC_TEKSTUR;it++)
	{
		glBindTexture(GL_TEXTURE_2D,indeksTekstury[it]); //kolejne polecenia beda dotyczyc tej tekstury

		//tworzenie tekstury z tablicy bitow
		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		//float kolorPodkladu[4]={0.0f,1.0f,0.0f,1.0f};
		//glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,kolorPodkladu);
		glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

		glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,teksturaSzer,teksturaWys, 0, GL_RGBA, GL_UNSIGNED_BYTE, tekstura[it]);
		//gluBuild2DMipmaps(GL_TEXTURE_2D,4,teksturaSzer,teksturaWys,GL_RGBA, GL_UNSIGNED_BYTE, tekstura[it]);

		delete[] tekstura[it]; //oryginalne dane sa usuwane
	}
}
#endif
#pragma endregion

#pragma region Shadery
/* Shadery */
//Do shaderow - wyswietlanie informacji
void ShowMessage(char* tekst)
{
    MessageBoxA(NULL,tekst,"OpenGL - shadery",MB_OK);
}

bool ShowDebug=true;
void ShowDebugInfo(char* tekst)
{
    if (ShowDebug) MessageBoxA(NULL,tekst,"Komunikat debugowania",MB_OK);
}

bool CMojeOknoGL::CzyShaderyDostepne()
{
	if(__argc>1 && (strcmp(__argv[1],"-d")==0 || strcmp(__argv[1],"/d")==0)) 
	{
		ShowDebug=true;
		ShowMessage("Komunikaty będą pokazywane");
	}
	else ShowDebug=false;

	//biezacy katalog
	if(ShowDebug)
	{
		char komunikat[1024]="Ścieżka programu: ";		
		strcat(komunikat,__argv[0]);
		strcat(komunikat,"\nKatalog roboczy: ");
		char katalog[MAX_PATH];
		GetCurrentDirectory(MAX_PATH,katalog);
		strcat(komunikat,katalog);
		ShowDebugInfo(komunikat);
	}

	//sprawdzanie rozszerzen
	char* rozszerzenia=(char*)malloc(strlen((char *)glGetString(GL_EXTENSIONS))+1);
	strcpy (rozszerzenia,(char *)glGetString(GL_EXTENSIONS));

	const int GL_SHADING_LANGUAGE_VERSION = 0x8B8C;

	//sprawdzenie czy rozszerzenie shaderów jest dostepne
	bool isShaderAvailable=strstr(rozszerzenia,"GL_ARB_shader_objects")>0;

	if(isShaderAvailable)
	{
		char komunikat[256]="Shadery są obsługiwane\nShading Language: ";
		strcat(komunikat,(char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
		ShowDebugInfo(komunikat);
	}
	else
	{
		ShowMessage("Shadery nie są obsługiwane");
	}
	return isShaderAvailable;
}

#include <fstream>
char* CzytajPlikTxt(char* nazwaPliku,int rozmiarBufora,char* bufor)
{
    strcpy(bufor,"");
    int dlugosc_tekstu=0;
    char linia[1024]="";
    std::ifstream plik_we(nazwaPliku);
    if (plik_we==NULL) return NULL;
    while (plik_we)
  	{
        plik_we.getline(linia,1024);
        int dlugosc_linii=strlen(linia);
        if (rozmiarBufora>(dlugosc_tekstu+dlugosc_linii))
        {
            strcat(bufor,linia);
            strcat(bufor,"\n");
            dlugosc_tekstu+=dlugosc_linii;
        }
        else break;
    }
    plik_we.close();
    return bufor;
}

unsigned int CMojeOknoGL::PrzygotujShadery()
{
	//zamiast glext.h
	#ifndef APIENTRY
	#define APIENTRY
	#endif
	#ifndef APIENTRYP
	#define APIENTRYP APIENTRY *
	#endif 
	//typy
	typedef char GLchar;
	typedef char GLcharARB;
	typedef unsigned int GLhandleARB;
	//deklaracje funkcji
	typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
	typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
	typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
	typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
	typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
	typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
	typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
	typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
	typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
	typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
	typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);

	#define GL_VERTEX_SHADER                  0x8B31
	#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81
	#define GL_FRAGMENT_SHADER                0x8B30
	#define GL_OBJECT_LINK_STATUS_ARB         0x8B82
	#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83

    //Pobieranie adresow funkcji
    //funkcje obiektow shaderow
    PFNGLCREATESHADERPROC glCreateShader=(PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
    PFNGLDELETESHADERPROC glDeleteShader=(PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
    PFNGLSHADERSOURCEPROC glShaderSource=(PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
    PFNGLCOMPILESHADERPROC glCompileShader=(PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
    //obiekty programow
    PFNGLCREATEPROGRAMPROC glCreateProgram=(PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
    PFNGLLINKPROGRAMPROC glLinkProgram=(PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
    PFNGLUSEPROGRAMPROC glUseProgram=(PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
    //funkcje obiektow (niektore ARB)
    PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB=(PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
    PFNGLGETINFOLOGARBPROC glGetInfoLogARB=(PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
    PFNGLDELETEOBJECTARBPROC glDeleteObjectARB=(PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
    PFNGLATTACHOBJECTARBPROC glAttachObjectARB=(PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
    //sprawdzanie czy pobrane adresy
    if (glCreateShader==NULL || glDeleteShader==NULL || glShaderSource==NULL || glCompileShader==NULL ||
        glCreateProgram==NULL || glLinkProgram==NULL || glUseProgram==NULL ||
        glGetObjectParameterivARB==NULL || glGetInfoLogARB==NULL || glDeleteObjectARB==NULL || glAttachObjectARB==NULL)
    {
        ShowMessage("Uwaga! Pobranie adresów funkcji shaderów nie powiodło się");
        return NULL;
    }
    else ShowDebugInfo("Pobranie adresów funkcji shaderów powiodło się");

    /* Vertex shader */
	//Czytanie kodu shadera z pliku
	char kodShadera[65535]="";
    if (CzytajPlikTxt("shader.vsh",65535,kodShadera)==NULL) 
	{
		ShowMessage("Uwaga! Wczytanie kodu shadera z pliku nie powiodło się");
		return NULL;
	}

    ShowDebugInfo(kodShadera);
    //Tworzenie obiektu shadera
    GLhandleARB vsh=glCreateShader(GL_VERTEX_SHADER);
    if(vsh!=NULL) ShowDebugInfo("Utworzenie obiektu shadera powiodło się");
    else
    {
        ShowMessage("Uwaga! Utworzenie obiektu shadera nie powiodło się");
        return NULL;
    }    
    
    //Dostarczanie zrodla do obiektu shadera
    const GLchar* zrodlo[1];
    zrodlo[0]=kodShadera;
    glShaderSource(vsh,1,zrodlo,NULL);

    //Kompilacja kodu shadera
    glCompileShader(vsh);

    //Weryfikacja kompilacji
    GLint powodzenie;
    glGetObjectParameterivARB(vsh,GL_OBJECT_COMPILE_STATUS_ARB,&powodzenie);
    if (powodzenie) ShowDebugInfo("Kompilacja vertex shadera powiodła się");
    else
    {
        const int maxInfoLogSize=2048;
        GLchar infoLog[maxInfoLogSize];
        glGetInfoLogARB(vsh,maxInfoLogSize,NULL,infoLog);
		char komunikat[1024]="Uwaga! Kompilacja vertex shadera nie powiodła się:\n";
		strcat(komunikat,(char*)infoLog);
        ShowMessage(komunikat);
		//return NULL;
    }

	/* Pixel/Fragment Shader */
    GLhandleARB psh=glCreateShader(GL_FRAGMENT_SHADER);
	strcpy(kodShadera,"");
	if (CzytajPlikTxt("shader.psh",65535,kodShadera)==NULL) ShowMessage("Uwaga! Wczytanie kodu shadera z pliku nie powiodło się");
    ShowDebugInfo(kodShadera);
    zrodlo[0]=kodShadera;
    glShaderSource(psh,1,zrodlo,NULL);
    glCompileShader(psh);
    glGetObjectParameterivARB(psh,GL_OBJECT_COMPILE_STATUS_ARB,&powodzenie);
    if (powodzenie) ShowDebugInfo("Kompilacja pixel shadera powiodła się");
    //else ShowMessage("Uwaga! Kompilacja pixel nie shadera powiodła się");
	else
    {
        const int maxInfoLogSize=2048;
        GLchar infoLog[maxInfoLogSize];
        glGetInfoLogARB(psh,maxInfoLogSize,NULL,infoLog);
		char komunikat[1024]="Uwaga! Kompilacja pixel shadera nie powiodła się:\n";
		strcat(komunikat,(char*)infoLog);
        ShowMessage(komunikat);
		//return NULL;
    }

    /* Obiekt programu */
    //tworzenie obiektu programu
    GLhandleARB program=glCreateProgram();
    //przylaczanie shaderow
    glAttachObjectARB(program,vsh); //odlaczanie: glDetachObjectARB
    glAttachObjectARB(program,psh);
    //linkowanie (konsolidacja) programu
    glLinkProgram(program);
    glGetObjectParameterivARB(program,GL_OBJECT_LINK_STATUS_ARB,&powodzenie);
    if (powodzenie) ShowDebugInfo("Linkowanie programu powiodło się");
    else
    {
        const int maxInfoLogSize=2048;
        GLchar infoLog[maxInfoLogSize];
        glGetInfoLogARB(program,maxInfoLogSize,NULL,infoLog);
		char komunikat[1024]="Uwaga! Linkowanie programu nie powiodło się:\n";
		strcat(komunikat,(char*)infoLog);
		ShowMessage(komunikat);
		//return NULL;
    }
    //walidacja programu z uwglednieniem aktualnego stanu aplikacji i biblioteki OpenGL
    glGetObjectParameterivARB(program,GL_OBJECT_VALIDATE_STATUS_ARB,&powodzenie);
    if (powodzenie) ShowDebugInfo("Walidacja programu powiodła się");
    else
    {
        const int maxInfoLogSize=2048;
        GLcharARB infoLog[maxInfoLogSize];
        glGetInfoLogARB(program,maxInfoLogSize,NULL,infoLog);
		char komunikat[1024]="Uwaga! Walidacja programu nie powiodła się:\n";
        strcat(komunikat,(char*)infoLog);
		ShowMessage(komunikat);
		//return NULL;
    }
    //uzycie programu
    glUseProgram(program);

    //Usuwanie obiektow
    //usuniecie obiektu shadera nie zwolni wiazania, obiekt zostanie usuniety gdy przestanie byc uzywany
    glDeleteShader(vsh);
    glDeleteShader(psh);
    glDeleteObjectARB(program);

	return program;
}

void CMojeOknoGL::ZmienStalaCzas(unsigned int program,float czas)
{
	#ifndef APIENTRY
	#define APIENTRY
	#endif

	//typy
	typedef char GLchar;	

	typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
	typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);

	PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation=(PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
	PFNGLUNIFORM1FPROC glUniform1f=(PFNGLUNIFORM1FPROC)wglGetProcAddress("glUniform1f");

	if(program!=NULL && !oknoJestZamykane) glUniform1f(glGetUniformLocation(program,"czas"),czas);
}

void CMojeOknoGL::WiazDwieTekstury(unsigned int program,const unsigned int* indeksTekstury)
{
	#ifndef APIENTRY
	#define APIENTRY
	#endif
	#ifndef APIENTRYP
	#define APIENTRYP APIENTRY *
	#endif 
	
	typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
	
	PFNGLACTIVETEXTUREPROC glActiveTexture=(PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
	
	#define GL_TEXTURE0                       0x84C0
	#define GL_TEXTURE1                       0x84C1

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,indeksTekstury[0]);	
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D,indeksTekstury[1]);	

	//typy
	typedef char GLchar;	

	typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
	typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);

	PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation=(PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
	PFNGLUNIFORM1IPROC glUniform1i=(PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");

	glUniform1i(glGetUniformLocation(program, "samplerDodatkowejTekstury"), indeksTekstury[0]);
}

void CMojeOknoGL::ZwolnijDwieTekstury()
{
	#ifndef APIENTRY
	#define APIENTRY
	#endif
	#ifndef APIENTRYP
	#define APIENTRYP APIENTRY *
	#endif 
	
	typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
	
	PFNGLACTIVETEXTUREPROC glActiveTexture=(PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
	
	#define GL_TEXTURE0                       0x84C0
	#define GL_TEXTURE1                       0x84C1

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,NULL);	
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D,NULL);	
}

#pragma endregion