#include "mygame.h"

#include "vertextshader.h"
#include "fragmentshader.h"
#include "geometryshader.h"

#include <sstream> // for std::stringstream
#include <iomanip> // for std::setprecison

using namespace Gx;

static char logBuffer[1024];

//nowe elementy
struct vertex
{
	float x,y,z;
	float r,g,b;
	float pad[2]; //dopasowywanie do 32-bitowej granicy
};

vertex trojkat[3]=
{
	{-0.5f,0,0,  1,0,0},
	{ 0,0.5f,0,  0,1,0},
	{ 0.5f,0,0,  0,0,1},
};


GLfloat position [] =
{
	-0.5f, -0.5f,
	-0.5f,  0.5f,
	0.5f,  0.5f,
	0.5f, -0.5f,
};

/*
 *	Kontruktor: tutaj inicjalizujemy format pixeli i kontekst renderingu.
 *	Warto także pokazać okno :). To nie jest miejsce na inicjalizacje funkcji gl*.
 *	Oraz cała reszta co musi być w konstruktorze.
 */
MyGame::MyGame()
{
	TRACE();

	PixelFormat pixelFormat; // domyślne parametry, podwójne buforowanie, bez antialisingu
	getGraphicsDevice().setPixelFormat(pixelFormat);

	GraphicsContext graphicsContext; // domyślnie opengl 3.3 core forward
	getGraphicsDevice().setGraphicsContext(graphicsContext);

	//getGraphicsDevice().setVerticalSync(false); // wyłącz synchronizacje pionową

	getWindow().setDimensions(600, 600); // ustaw rozmiar okna
	getWindow().show(); // pokaż okno
	getWindow().update(); // odśwież okno
}

//VBO i VAO
GLuint vboTrojkata;
GLuint vaoTrojkata;
GLuint atrybutPozycja, atrybutKolor;

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

/*
 *	Metoda odpalana jest raz tuż po zainicjalizowaniu całej aplikacji - gotowy kontekst openGL etc.
 *	Tutaj inicjalizujemy wszystko co związane z OpenGL. Ładowanie tekstur, modeli etc.
 */
void MyGame::initialize()
{
	TRACE();

	glClearColor(0.3f, 0.5f, 0.9f, 0.0f); // ustawiamy 'kolor tła'
	glPointSize(5.0f); // rozmiar wyswietlanego punktu

	VertexShader vertexShader;
	if ( !vertexShader.loadFromFile("..\\Shaders\\vertexshader.vs") )
	{
		std::printf("Vertex Shader File Error\n");
	}
	if ( !vertexShader.compile() )
	{
		vertexShader.getLog(logBuffer, 1024);
		std::printf("Vertex Shader Compile Error: %s\n", logBuffer);
	}

	FragmentShader fragmentShader;
	if ( !fragmentShader.loadFromFile("..\\Shaders\\fragmentshader.fs") )
	{
		std::printf("Fragment Shader File Error\n");
	}

	if ( !fragmentShader.compile() )
	{
		fragmentShader.getLog(logBuffer, 1024);
		std::printf("Fragment Shader Compile Error: %s\n", logBuffer);
	}

	if ( !m_identityProgram.create() )
	{
		std::printf("Cannot create a shader program.\n");
	}

	m_identityProgram.attach(vertexShader);
	m_identityProgram.attach(fragmentShader);

	if ( !m_identityProgram.link() )
	{
		m_identityProgram.getLog(logBuffer, 1024);
		std::printf("Shader Program Linker Error: %s\n", logBuffer);
	}

	if ( !m_identityProgram.validate() )
	{
		std::printf("Shader Program Validate Error.\n");
	}

	//VBO i VAO
	atrybutPozycja = glGetAttribLocation(m_identityProgram.getHandle(),"position");
	atrybutKolor = glGetAttribLocation(m_identityProgram.getHandle(),"color");
	//lepszy sposob - korzystajac z layout
	
	glGenBuffers(1,&vboTrojkata);	
	
	glGenVertexArrays(1,&vaoTrojkata);
	glBindVertexArray(vaoTrojkata);

	glBindBuffer(GL_ARRAY_BUFFER,vboTrojkata);
	glBufferData(GL_ARRAY_BUFFER,sizeof(vertex)*3,trojkat,GL_STATIC_DRAW);

	glEnableVertexAttribArray(atrybutPozycja);
	glEnableVertexAttribArray(atrybutKolor);


	glVertexAttribPointer(atrybutPozycja,3,GL_FLOAT,GL_FALSE, sizeof(vertex),BUFFER_OFFSET(0)); //ostatnie offset
	glVertexAttribPointer(atrybutKolor,3,GL_FLOAT,GL_FALSE, sizeof(vertex),BUFFER_OFFSET(3*sizeof(float)));

	
	
	
}

/*
 *	Metoda odpalana jest raz tuż przed zamknięciem aplikacji.
 *	Tutaj zwalniamy wszystko co zainicjalizowaliśmy w MyGame::initialize().
 */
void MyGame::release()
{
	TRACE();
}

/*
 *	Metoda jest odpalana za każdym razem gdy zmieni się rozmiar okna.
 *	Każdy komunikat WM_SIZE od Windows spowoduję wywołanie tej metody.
 *	Dobre miejsce na np: glViewport, macierz projekcji (viewport.getAspectRatio() może się przydać)
 */
void MyGame::reshape( const Viewport& viewport )
{
	glViewport(0, 0, viewport.getWidth(), viewport.getHeight());
}

/*
 *	Metoda odpalana jest raz na każdą klatkę.
 *	Bardzo dobre miejsce do sprawdzania stanu myszki, klawiatury etc.
 *	Także mogą być wszystkie inne rzeczy, które nie pasują do update i render, a wymagają
 *	odświerzania co klatkę.
 *	elapsedTime - czas który upłynął od ostatniej klatki, liczony w sekundach
 */
void MyGame::input( float elapsedTime )
{
}

/*
 *	Metoda odpalana jest od jednego do kilku razy na klatkę - tzw. symulacja stałokrokowa.
 *	Tutaj jedynie fizyka aktorów - np. PhysX, Bullet etc.
 *	elapsedTime - stały czas, domyślnie 1/60 sekundy
 */
void MyGame::update( float elapsedTime )
{

}

/*
 *	Metoda odpalana jest raz na każdą klatkę.
 *	Tutaj jedynie renderowanie aktorów i innych obiektów.
 *	elapsedTime - czas który upłynął od ostatniej klatki, liczony w sekundach
 */
void MyGame::render( float elapsedTime )
{
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram( m_identityProgram.getHandle() );

	//VBO i VAO
	glBindVertexArray(vboTrojkata); //binduje sie wpierw zeby ustawic, drugi raz zeby uzyc
	glDrawArrays(GL_TRIANGLES,0,3);

	glUseProgram( 0 );

	glFlush();
}