#include "OpenGL4.h"
#include "resource.h"

#include <cstdlib>

#include "Varia.h"

int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	POINT polozenieOkna = {100,100};
	POINT rozmiarOkna = {800,600};
	if(!okno.Init(hInstance,polozenieOkna,rozmiarOkna))
	{
		MessageBox(NULL,"Inicjacja okna nie powiodła się","Aplikacja OpenGL 3.3+",MB_OK|MB_ICONERROR);
		return EXIT_FAILURE;
	}
	else return okno.Run();
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	return okno.WndProc(hWnd,message,wParam,lParam);
}

//---------------

bool COkno::Init(HINSTANCE uchwytAplikacji,POINT polozenieOkna,POINT rozmiarOkna)
{
	char nazwaOkna[]="Aplikacja OpenGL";

	WNDCLASSEX wc;
	wc.cbSize=sizeof(wc);
	wc.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC; //styl okna
	wc.lpfnWndProc=(WNDPROC)::WndProc; //procedura okna
	wc.cbClsExtra=0; //dodatkowe bajty zarezerwowane za klasą okna
	wc.cbWndExtra=0; //dodatkowe bajty zarezerwowane za instancją okna
	wc.hInstance=uchwytAplikacji; //instancja aplikacji
	wc.hIcon=LoadIcon(uchwytAplikacji,MAKEINTRESOURCE(IDI_OPENGL4)); //uchwyt ikony
	wc.hIconSm=LoadIcon(uchwytAplikacji,MAKEINTRESOURCE(IDI_OPENGL4)); //uchwyt ikony
	wc.hCursor=LoadCursor(NULL,IDC_ARROW); //uchwyt kursora
	wc.hbrBackground=NULL; //uchwyt pędzla tła
	wc.lpszMenuName=NULL; //nazwa menu
	wc.lpszClassName=nazwaOkna; //nazwa klasy okna	

	if(RegisterClassEx(&wc)==0) return false; //rejestracja klasy okna

	bool trybPelnoekranowy=false;

	//ustawienia okna
	DWORD stylOkna = WS_OVERLAPPEDWINDOW;
	if(trybPelnoekranowy)
	{
		polozenieOkna.x=0;
		polozenieOkna.y=0;
		RECT rozmiarEkranu;
		GetWindowRect(GetDesktopWindow(),&rozmiarEkranu);
		rozmiarOkna.x=rozmiarEkranu.right-rozmiarEkranu.left;
		rozmiarOkna.y=rozmiarEkranu.bottom-rozmiarEkranu.top; //zamiast pobierać, można wymusić okresloną rozdzielczość
		//rozmiarOkna.x=1024;
		//rozmiarOkna.y=768;
		stylOkna=WS_POPUP;
		if(!ZmianaRozdzielczosciEkranu(rozmiarOkna.x,rozmiarOkna.y)) return false; //w takiej konstrukcji to tylko wymusza glebię kolorów w trybie pełnoekranowym
	}

	//tworzenie okna
	uchwytOkna=CreateWindow(
		nazwaOkna, //nazwa klasy okna
		nazwaOkna, //nazwa okna
		stylOkna,
		polozenieOkna.x,polozenieOkna.y, //położenie okna (x, y)
		rozmiarOkna.x,rozmiarOkna.y, //rozmiar okna (szerokość, wysokość)
		NULL, //uchwyt okna nadrzędnego (parent)
		NULL, //uchwyt menu
		uchwytAplikacji, //uchwyt instancji aplikacji
		NULL); //parametr komunikatu informujacego o utworzeniu okna

	if(uchwytOkna==NULL) return false;

	ShowWindow(uchwytOkna,SW_SHOW); //pokazanie i aktualizacja okna
	UpdateWindow(uchwytOkna);

	return true;
}

WPARAM COkno::Run()
{
	//petla glowna - obsluga komunikatow
	MSG msg;
	while(GetMessage(&msg,0,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT COkno::WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
	case WM_DESTROY: //zamykanie okna => konczenie aplikacji
		//ChangeDisplaySettings(NULL,0); //przywrocenie domyslnej rozdzielczosci ekranu
		PostQuitMessage(0);
		break;
	case WM_SIZE: //zmiana rozmiaru okna
		RECT rect;
		GetClientRect(uchwytOkna,&rect);
		szerokoscObszaruUzytkownika=rect.right-rect.left;
		wysokoscObszaruUzytkownika=rect.bottom-rect.top;
		break;
	default: //automatyczne przetwarzanie komunikatow
		return DefWindowProc(hWnd,message,wParam,lParam);
	}
	return 0L;
}

bool COkno::ZmianaRozdzielczosciEkranu(long szerokosc,long wysokosc,long glebiaKolorow) const
{
	DEVMODE dmScreenSettings; //struktura trybu wyswietlania
	ZeroMemory(&dmScreenSettings,sizeof(dmScreenSettings)); //czyszczenie pamieci
	dmScreenSettings.dmSize=sizeof(dmScreenSettings); //rozmiar struktury
	dmScreenSettings.dmPelsWidth=szerokosc; //nowa szerokosc ekranu
	dmScreenSettings.dmPelsHeight=wysokosc; //nowa wysokosc ekranu
	dmScreenSettings.dmBitsPerPel=glebiaKolorow; //ilosc bitow opisujacych kolor piksela
	dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; //elementy podlegajace zmianom
	return ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)==DISP_CHANGE_SUCCESSFUL;
}

//-----------------------------

#include "InitApi.h"

LRESULT COknoGL::WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	long wynik=COkno::WndProc(hWnd,message,wParam,lParam);
	
	const UINT IDT_TIMER_OBROTOW_MODELU = 200;		

	switch(message)
	{
	case WM_CREATE: //utworzenie okna
		InitWGL(hWnd,true); //Uwaga! Tu zmienna uchwytOkna nie jest jeszcze zainicjowana.
		idProgramuShaderow = PrzygotujShadery("shader.vsh","shader.fsh");
		if(idProgramuShaderow == NULL) MessageBox(NULL,"Przygotowanie shaderów nie powiodło się","OpenGL - Shadery",MB_OK | MB_ICONERROR);
		InitBuforWerteksow();
		UstawienieSceny();

		//timer
		{
			const UINT okres_powtarzania = 16;
			if(SetTimer(hWnd,IDT_TIMER_OBROTOW_MODELU,okres_powtarzania,NULL)==NULL)
				MessageBox(hWnd,"Nie udało się ustawić timera","Nowoczesny OpenGL",MB_OK|MB_ICONERROR);
		}

		break;
	case WM_DESTROY: //zamkniecie okna
		UsunBuforWerteksow();
		UsunWGL();
		KillTimer(hWnd,IDT_TIMER_OBROTOW_MODELU); //timer
		break;
	case WM_SIZE: //zmiana rozmiaru okna
		UstawienieSceny();
		break;
	case WM_PAINT: //okno wymaga odswiezenia
		RysujScene();
		ValidateRect(hWnd,NULL);
		break;
	case WM_MOUSEWHEEL:
		RysujScene();
		ValidateRect(hWnd,NULL);
		break;
	case WM_TIMER:
		switch(wParam)
		{
			case IDT_TIMER_OBROTOW_MODELU:
				RysujScene();
				ValidateRect(hWnd,NULL);
				break;
		}
		break;
	}

	return wynik;
}

//WGL

bool COknoGL::InitWGL(HWND uchwytOkna,bool uzupelnijTytulOkna)
{
	uchwytDC=GetDC(uchwytOkna);
	if(!UstalFormatPikseli(uchwytDC)) return false; 
	HGLRC tymczasowyUchwytRC=wglCreateContext(uchwytDC); //tworzenie tymczasowego kontekstu renderowania (met. tradycyjna)
	if(tymczasowyUchwytRC==NULL) return false;
	if(!wglMakeCurrent(uchwytDC,tymczasowyUchwytRC)) return false;

	//uzupelnienie tytulu
	if(uzupelnijTytulOkna)
	{
		char bufor[256]; GetWindowText(uchwytOkna,bufor,256);
		const GLubyte* wersja=glGetString(GL_VERSION);
		strcat(bufor," "); strcat(bufor,(char*)wersja);
		const GLubyte* dostawca=glGetString(GL_VENDOR);
		strcat(bufor," / "); strcat(bufor,(char*)dostawca);
		const GLubyte* kartaGraficzna=glGetString(GL_RENDERER);
		strcat(bufor," / "); strcat(bufor,(char*)kartaGraficzna);
		SetWindowText(uchwytOkna,bufor);
	}

	int major, minor; 
	glGetIntegerv(GL_MAJOR_VERSION,&major);
	glGetIntegerv(GL_MINOR_VERSION,&minor);
	if(major<3 && minor<3) return false;

	int atrybuty[]=
	{
		WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
		WGL_CONTEXT_MINOR_VERSION_ARB, 3,
		WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
		WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
		//WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
		0
	};

	InitAPI();
	uchwytRC = wglCreateContextAttribsARB(uchwytDC,0,atrybuty); //tworzenie zasadniczego kontekstu dla OpenGL 3.3+
	if(uchwytRC==NULL) return false;
	if(!wglMakeCurrent(uchwytDC,uchwytRC)) return false;

	wglDeleteContext(tymczasowyUchwytRC); //usuniecie niepotrzebnego juz tymczasowego uchwytu kontekstu renderowania

	return true;
}

void COknoGL::UsunWGL()
{
	wglMakeCurrent(0,0); //???? czy pierwszy nie powinien byc uchwytDC
	wglDeleteContext(uchwytRC);
	ReleaseDC(uchwytOkna,uchwytDC);
}

bool COknoGL::UstalFormatPikseli(HDC uchwytDC) const
{
	PIXELFORMATDESCRIPTOR opisFormatuPikseli;
	ZeroMemory(&opisFormatuPikseli,sizeof(opisFormatuPikseli));
	opisFormatuPikseli.nVersion=1;
	opisFormatuPikseli.dwFlags=PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER; //w oknie, podwojne buforowanie 
	opisFormatuPikseli.iPixelType=PFD_TYPE_RGBA; //typ koloru RGB z kanalem alfa
	opisFormatuPikseli.cColorBits=32; //jakosc kolorów 4 bajty (po bajcie na kazdy kanal)
	opisFormatuPikseli.cDepthBits=32; //glebokosc bufora Z (z-buffer) 
	opisFormatuPikseli.iLayerType=PFD_MAIN_PLANE;
	
	int formatPikseli=ChoosePixelFormat(uchwytDC,&opisFormatuPikseli);
	if(formatPikseli==0) return false;

	if(!SetPixelFormat(uchwytDC,formatPikseli,&opisFormatuPikseli)) return false;
	return true;
}

//OpenGL

void COknoGL::UstawienieSceny()
{
	glViewport(0,0,szerokoscObszaruUzytkownika,wysokoscObszaruUzytkownika);

	/*
	//ustalenie macierzy projekcji 
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	float aspectRatio=szerokoscObszaruUzytkownika/(float)wysokoscObszaruUzytkownika;
	glFrustum(-1*aspectRatio,1*aspectRatio,-1,1,1,100); //left,right,bottom,top,znear,zfar (clipping); mnozenie macierzy rzutowania przez macierz perspektywy - ustalanie frustum
	
	glMatrixMode(GL_MODELVIEW); //powrót do macierzy widoku modelu 
	glLoadIdentity();
	*/

	//glDepthFunc(GL_LEQUAL); //??????????????????????????
	//glEnable(GL_DEPTH_TEST); //bufor glebii aktywny 	

	glCullFace(GL_BACK);
	glEnable(GL_CULL_FACE);

}

//#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL+(bytes))

void COknoGL::InitBuforWerteksow() //ważna funkcja
{
	//Vertex Array Object (VAO)
	glGenVertexArrays(1,&vao);
	glBindVertexArray(vao);

	const float x0=1.0f;
	const float y0=1.0f;
	const float z0=1.0f;

	static const CWerteks werteksy[]=
	{
		//tylnia
		CWerteks(x0,-y0,-z0,  1,0,0,  0,0,-1,  0,0),
		CWerteks(-x0,-y0,-z0,  1,0,0,  0,0,-1,  1,0),
		CWerteks(x0,y0,-z0,  1,0,0,  0,0,-1,  0,1),
		CWerteks(-x0,y0,-z0,  1,0,0,  0,0,-1,  1,1),
		//przednia
		CWerteks(-x0,-y0,z0,  1,0,0,  0,0,1,  0,0),
		CWerteks(x0,-y0,z0,  1,0,0,  0,0,1,  3,0),
		CWerteks(-x0,y0,z0,  1,0,0,  0,0,1,  0,3),
		CWerteks(x0,y0,z0,  1,0,0,  0,0,1,  3,3),

		//prawa
		CWerteks(x0,-y0,z0,  0,1,0,  1,0,0,  0,0),
		CWerteks(x0,-y0,-z0,  0,1,0,  1,0,0,  1,0),
		CWerteks(x0,y0,z0,  0,1,0,  1,0,0,  0,1),
		CWerteks(x0,y0,-z0,  0,1,0,  1,0,0,  1,1),
		//lewa
		CWerteks(-x0,-y0,-z0,  0,1,0,  -1,0,0,  0,0),
		CWerteks(-x0,-y0,z0,  0,1,0,  -1,0,0,  1,0),
		CWerteks(-x0,y0,-z0,  0,1,0,  -1,0,0,  0,1),
		CWerteks(-x0,y0,z0,  0,1,0,  -1,0,0,  1,1),
		
		//gorna
		CWerteks(-x0,y0,z0,  0,0,1,  0,1,0,  0,0),
		CWerteks(x0,y0,z0,  0,0,1,  0,1,0,  1,0),
		CWerteks(-x0,y0,-z0,  0,0,1,  0,1,0,  0,1),
		CWerteks(x0,y0,-z0,  0,0,1,  0,1,0,  1,1),
		//dolna
		CWerteks(-x0,-y0,-z0,  0,0,1,  0,-1,0,  0,0), //tu cos zle!!!!!!!
		CWerteks(x0,-y0,-z0,  0,0,1,  0,-1,0,  1,0),
		CWerteks(-x0,-y0,z0,  0,0,1,  0,-1,0,  1,1),
		CWerteks(x0,-y0,z0,  0,0,1,  0,-1,0,  0,1),
	};

	//Vertex Buffer Object (VBO)
	glGenBuffers(1,&vbo); //tworz tylko jeden bufor

	GLuint atrybutPolozenie = glGetAttribLocation(idProgramuShaderow,"pozycja_in");
	GLuint atrybutKolor = glGetAttribLocation(idProgramuShaderow,"kolor_in");
	GLuint atrybutNormalna = glGetAttribLocation(idProgramuShaderow,"normalna_in");
	GLuint atrybutWspTeksturowania = glGetAttribLocation(idProgramuShaderow,"wspTeksturowania_in");	

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(werteksy), werteksy, GL_STATIC_DRAW);
	
	glVertexAttribPointer(atrybutPolozenie,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),0);
	//glVertexAttribPointer(atrybutPolozenie,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),BUFFER_OFFSET(0));
	glVertexAttribPointer(atrybutPolozenie,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),(const void*)offsetof(CWerteks,x));
	glEnableVertexAttribArray(atrybutPolozenie);		

	//glVertexAttribPointer(atrybutKolor,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),BUFFER_OFFSET(3*sizeof(GLfloat)));
	glVertexAttribPointer(atrybutKolor,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),(const void*)offsetof(CWerteks,r));
	glEnableVertexAttribArray(atrybutKolor);

	glVertexAttribPointer(atrybutNormalna,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),(const void*)offsetof(CWerteks,nx));
	glEnableVertexAttribArray(atrybutNormalna);

	glVertexAttribPointer(atrybutWspTeksturowania,3,GL_FLOAT,GL_FALSE,sizeof(CWerteks),(const void*)offsetof(CWerteks,t));
	glEnableVertexAttribArray(atrybutWspTeksturowania);
}

void COknoGL::PrzygotujTeksturyZPliku()
{
	const int LICZBA_TEKSTUR = 2;
	glGenTextures(LICZBA_TEKSTUR,indeksyTekstur); //generowanie indeksow dla tekstur (uchwyt)

	char* nazwyPlikowTekstur[LICZBA_TEKSTUR] = {"tekstura1.bmp","tekstura3.bmp"};

	int teksturaSzer;
	int teksturaWys;
	for(int it=0;it<LICZBA_TEKSTUR;++it)
	{		
		glBindTexture(GL_TEXTURE_2D,indeksyTekstur[it]); //kolejne polecenia beda dotyczyc tej tekstury
		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_T,GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
		//glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
		glGenerateMipmap(GL_TEXTURE_2D);

		//wczytywanie tekstury z pliku
		unsigned long* tekstura = WczytajTeksture(uchwytOkna,nazwyPlikowTekstur[it],teksturaSzer,teksturaWys,false,255);
		glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,teksturaSzer,teksturaWys,0,GL_RGBA,GL_UNSIGNED_BYTE,tekstura);
		delete [] tekstura;
	}
}

void COknoGL::WiazTekstury(unsigned int program, const unsigned int* indeksyTekstur)
{
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,indeksyTekstur[0]);
	GLint lokalizacjaProbnikaTekstury = glGetUniformLocation(program,"samplerTekstury");
	glUniform1i(lokalizacjaProbnikaTekstury,0);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D,indeksyTekstur[1]);
	GLint lokalizacjaDodatkowegoProbnikaTekstury = glGetUniformLocation(program,"samplerDodatkowejTekstury");
	glUniform1i(lokalizacjaDodatkowegoProbnikaTekstury,1);
}

void ZwolnijDwieTekstury()
{
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,NULL);

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

void COknoGL::UsunBuforWerteksow()
{
	glDeleteVertexArrays(1,&vao);
	glDeleteBuffers(1,&vbo);
}

#include <math.h>

float* RzutowaniePerspektywiczne(float* M,float l,float r,float b,float t,float n,float f) //f,n>0
{
	for(int i=0;i<16;++i) M[i]=0;
	M[0]=2*n/(r-l);
	M[2]=(r+l)/(r-l);
	M[5]=2*n/(t-b);
	M[6]=(t+b)/(t-b);
	M[10]=(f+n)/(f-n);
	M[11]=2*f*n/(f-n);
	M[14]=-1;
	return M;
};

float* Mnozenie(float* M1,float* M2,float* bufor,int rozmiar = 4)
{
	for(int i=0;i<rozmiar*rozmiar;++i) bufor[i]=0;
	for(int kolumna=0;kolumna<rozmiar;++kolumna)
		for(int wiersz=0;wiersz<rozmiar;++wiersz)
			for(int i=0;i<rozmiar;++i)
				bufor[wiersz+rozmiar*kolumna]+=M1[wiersz+rozmiar*i]*M2[i+rozmiar*kolumna];
	return bufor;
}

#include "Matrix.h"

void COknoGL::RysujScene()
{
	/*
	const float x0=1.0f;
	const float y0=1.0f;
	const float z0=1.0f;
	*/

	glClearColor(0.0f,0.0f,0.0f,1.0f); //kolor czyszczenia bufora ramki
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //czysci bufory ramki i glebii

	static bool podjetaProbaInicjacjiTekstur = false;
	if(!podjetaProbaInicjacjiTekstur)
	{
		podjetaProbaInicjacjiTekstur = true;
		PrzygotujTeksturyZPliku();
	}

	float macierzJednostkowa[16];
	mat4::Fill(macierzJednostkowa, fill::eye);

	static float phiY = 0.0f;
	phiY += 0.01f;
	float obrotY[16];
	mat4::FillRotate(obrotY, phiY, dim::y);

	static float phiX = 0.0f;
	phiX += 0.005f;
	float obrotX[16];
	mat4::FillRotate(obrotX,phiX,dim::x);
	
	float macierzModelu[16];	
	mat4::Multiply(obrotY, obrotX, macierzModelu);	

	float z0=-5.0f; //odsuniecie kamery
	float macierzWidoku[16];
	mat4::Fill(macierzWidoku, fill::eye);
	macierzWidoku[11] = z0;

	/*
	//prowizorka - prymityw!!!!
	float d = 2.5f;
	float macierzRzutowania[16] = 
	{
		1,0,0,0,
		0,1,0,0,
		0,0,0,0,
		0,0,-1/d,1
	};
	*/

	float macierzRzutowania[16];
	float aspectRatio = szerokoscObszaruUzytkownika/(float)wysokoscObszaruUzytkownika;	
	mat4::FillFrustum(macierzRzutowania,-0.5f*aspectRatio,0.5f*aspectRatio,-0.5f,0.5f,1.0f,100.0f);
	
	//ZOPTYMALIZOWAC!!!!

	GLint lokalizacjaMacierzyModelu = glGetUniformLocation(idProgramuShaderow,"macierzModelu"); //to nie powinno byc wykonywane w kazdej klatce
	glUniformMatrix4fv(lokalizacjaMacierzyModelu,1,true,macierzModelu);

	GLint lokalizacjaMacierzyWidoku = glGetUniformLocation(idProgramuShaderow,"macierzWidoku"); //to nie powinno byc wykonywane w kazdej klatce
	glUniformMatrix4fv(lokalizacjaMacierzyWidoku,1,true,macierzWidoku);

	GLint lokalizacjaMacierzyRzutowania = glGetUniformLocation(idProgramuShaderow,"macierzRzutowania"); //to nie powinno byc wykonywane w kazdej klatce
	glUniformMatrix4fv(lokalizacjaMacierzyRzutowania,1,true,macierzRzutowania);

	//glEnable(GL_TEXTURE_2D);
	WiazTekstury(idProgramuShaderow,indeksyTekstur);

	/*
	glLoadIdentity();
	glTranslatef(0,0,-2); //odsuniecie calosci o 2

	//rysowanie trojkata, ustalanie trzech wierzcholkow trojkata (werteksow (x,y,z))
	glBegin(GL_TRIANGLES);
	glVertex3f(-x0,-y0,0); //dolny lewy
	glVertex3f(x0,-y0,0); //dolny prawy
	glVertex3f(0,y0,0); //gorny
	glEnd(); //koniec rysowania ciagu figur
	*/

	//glDrawArrays(GL_TRIANGLE_STRIP,0,4);

	for(int i=0;i<6;++i)
		glDrawArrays(GL_TRIANGLE_STRIP,4*i,4);

	SwapBuffers(uchwytDC); //z bufora na ekran
}

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

#include <fstream> //czy można łatwiej?
char* CzytajPlikTxt(const char* nazwaPliku,int rozmiarBufora,char* bufor)
{
	std::ifstream plik_we(nazwaPliku);
	if(plik_we==NULL) return NULL;
	plik_we.read(bufor, rozmiarBufora);
	if (plik_we.eof())
	{
		std::streamsize odczytane = plik_we.gcount();
		plik_we.close();
		bufor[odczytane] = '\0';
		return bufor;
	}
	else
	{
		plik_we.close();
		return NULL;
	}
}

GLuint COknoGL::PrzygotujShadery(const char* vsNazwaPliku, const char* fsNazwaPliku)
{
	const int maksymalnaWielkoscKodu = 65535;

	/* Vertex shader */
	char kodShadera[maksymalnaWielkoscKodu] = "";
	if(CzytajPlikTxt(vsNazwaPliku,maksymalnaWielkoscKodu,kodShadera) == NULL) return NULL;
	//ShowMessage(kodShadera);

	//Tworzenie obiektu shadera
	GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
	if(vsh==NULL) return NULL;

	//Dostarczanie zrodla do obiektu shadera
	const GLchar* zrodlo[1];
	zrodlo[0] = kodShadera;
	glShaderSource(vsh,1,zrodlo,NULL);

	//Kompilacja shadera
	glCompileShader(vsh);

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

	/* Fragment shader */
	strcpy(kodShadera,"");
	if(CzytajPlikTxt(fsNazwaPliku,maksymalnaWielkoscKodu,kodShadera) == NULL) return NULL;
	//ShowMessage(kodShadera);

	//Tworzenie obiektu shadera
	GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
	if(fsh==NULL) return NULL;

	//Dostarczanie zrodla do obiektu shadera
	zrodlo[0] = kodShadera;
	glShaderSource(fsh,1,zrodlo,NULL); //sprawdzic czy bez opakowywania da rade

	//Kompilacja shadera
	glCompileShader(fsh);

	//Weryfikacje kompilacji
	glGetShaderiv(fsh,GL_COMPILE_STATUS, &powodzenie);
	//glGetObjectParameterivARB(fsh,GL_OBJECT_COMPILE_STATUS_ARB,&powodzenie);
	if(!powodzenie)
	{
		const int maxInfoLogSize = 2048;
		GLchar infoLog[maxInfoLogSize];
		glGetShaderInfoLog(fsh,maxInfoLogSize,NULL,infoLog);
		//glGetInfoLogARB(fsh,maxInfoLogSize,NULL,infoLog); //glGetShaderInfoLogARB
		char komunikat[maxInfoLogSize+64]="Uwaga! Kompilacja fragment shadera nie powiodła się:\n";
		strcat(komunikat,(char*)infoLog);
		ShowMessage(komunikat);
		return NULL;
	}
	//else ShowMessage("Kompilacja fragment shadera powiodła się");

	/* Obiekt programu shaderow */

	//Tworzenie obiektu programu
	GLuint program = glCreateProgram();

	//Przylaczanie shaderow
	glAttachShader(program,vsh);
	glAttachShader(program,fsh);
	//glAttachObjectARB(program,vsh); //lepiej byloby glAttachShader
	//glAttachObjectARB(program,fsh);

	//Linkowanie
	glLinkProgram(program);

	//Weryfikacja linkowania
	glGetProgramiv(program,GL_LINK_STATUS, &powodzenie);
	//glGetObjectParameterivARB(program,GL_OBJECT_LINK_STATUS_ARB,&powodzenie);
	if(!powodzenie)
	{
		const int maxInfoLogSize = 2048;
		GLchar infoLog[maxInfoLogSize];
		glGetProgramInfoLog(program,maxInfoLogSize,NULL,infoLog);
		//glGetInfoLogARB(program,maxInfoLogSize,NULL,infoLog); //glGetProgramInfoLogARB		
		char komunikat[maxInfoLogSize+64]="Uwaga! Linkowanie programu shaderów nie powiodło się:\n";
		strcat(komunikat,(char*)infoLog);
		ShowMessage(komunikat);
		return NULL;
	}
	//else ShowMessage("Linkowanie programu shaderów powiodło się");

	//Walidacja programu
	glGetProgramiv(program,GL_VALIDATE_STATUS, &powodzenie);
	//glGetObjectParameterivARB(program,GL_OBJECT_VALIDATE_STATUS_ARB,&powodzenie);
	if(!powodzenie)
	{
		const int maxInfoLogSize = 2048;
		GLchar infoLog[maxInfoLogSize];
		glGetProgramInfoLog(program,maxInfoLogSize,NULL,infoLog);
		//glGetInfoLogARB(program,maxInfoLogSize,NULL,infoLog); //glGetProgramInfoLogARB		
		char komunikat[maxInfoLogSize+64]="Uwaga! Walidacja programu shaderów nie powiodła się:\n";
		strcat(komunikat,(char*)infoLog);
		ShowMessage(komunikat);
		return NULL;
	}
	//else ShowMessage("Walidacja programu shaderów powiodła się");

	//Uzycie programu
	glUseProgram(program);

	//Usuwanie niepotrzebnych obiektow shadera
	glDeleteShader(vsh);
	glDeleteShader(fsh);

	//glDeleteObjectARB(vsh); //glDeleteShader
	//glDeleteObjectARB(fsh);

	return program;
}

#pragma endregion