#pragma once
#include <gl\glew.h>
#include <gl\glfw3.h>
#include "Object.h"
#include <vector>


#define VERTEX_INDEX_XYZ		0
#define VERTEX_INDEX_UV			1

#define VERTEX_COMPONENTS_XYZ	3
#define VERTEX_COMPONENTS_UV	2

#define VERTEX_SIZE_XYZ			(sizeof(float) * VERTEX_COMPONENTS_XYZ)
#define VERTEX_SIZE_UV			(sizeof(float) * VERTEX_COMPONENTS_UV)

#define VERTEX_OFFSET_XYZ		0
#define VERTEX_OFFSET_UV		(VERTEX_SIZE_XYZ)

struct Vertex {
	GLfloat position[3];
	GLfloat uv[2];
};

struct textureData {
	bool alpha;
	std::uint32_t width;
	std::uint32_t height;
	std::vector<std::uint8_t>* data;
};

class OpenGLController
{
////////////////////////////////////////////////////////////////////////////////////////////
// constructor/destructor
public:
	static OpenGLController* getInstance(int oglMajor = 4, int oglMinor = 5);
	~OpenGLController();

private:
	OpenGLController() {};
	OpenGLController(int oglMajor, int oglMinor);

////////////////////////////////////////////////////////////////////////////////////////////
// member
private:
	// window
	GLFWwindow* pWindow			= NULL;
	std::string sWindowName		= "MeshViewer 2.0 pre-alpha";
	int iWidth					= 640;
	int iHeight					= 480;

	// init glfw
	int iOglMajorVersion		= 4;
	int iOglMinorVersion		= 5;
	int iAntiAliasingLevel		= 4;

// IDs ====================================
	//object data
	GLuint gluiVertexArrayID	= 0;
	GLuint gluiVertexBufferID	= 0;

	//obj color
	GLuint gluiTextureID		= 0;
	GLuint gluiShaderPrgmID		= 0;
	GLuint gluiSamplerID		= 0;

	//obj transformation
	GLuint gluiMatrixID			= 0;
// ========================================

	// data
	std::vector<Modl*>* vModels = NULL;
	std::vector<textureData*> vTextures;
	Bbox sceneBoundingBox;

// transformation =========================
	//values
	float fRotationX			= 0;
	float fRotationY			= 0;
	float fRotationZ			= 0;
	double dTranslationX		= 0;
	double dTranslationY		= 0;
	double dTranslationZ		= 3;

// ========================================

	// camera
	float fFOV					= 45.0f;
	float fMinView				= 0.1f;
	float fMaxView				= 100.0f;


////////////////////////////////////////////////////////////////////////////////////////////
// private functions
private:
	void processInit();
	void deleteVectors();

	void startGLFW();
	void createWindow();
	void startGLEW();
	void setCallbackFunctions();

	glm::mat4 getModelMatrix(unsigned int index);
	glm::mat4 getMVPMatrix(unsigned int index);


////////////////////////////////////////////////////////////////////////////////////////////
// public functions
public:

	// callback
	void resize(int width, int height);
	void addRotX(float value);
	void addRotY(float value);
	void addTransX(double value);
	void addTransY(double value);
	void addTransZ(double value);
	void resetView();

	// main routine
	GLFWwindow* getWindow() const;
	void updateScene();
	void loadMsh(const char* path);

};

