
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "./glm/ext.hpp" // perspective, translate, rotate
#include <iostream>
#include "utils.h"
using namespace std;
float cameraX, cameraY, cameraZ;
float cubeLocX, cubeLocY, cubeLocZ; 
#define numVAOs 1
#define numVBOs 1
// allocate variables used in display() function, so that they won’t need to be allocated during rendering
GLuint mvLoc, projLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvMat;
void setupVertices(void);
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];
float x = 0.0f; // location of triangle on x axis
float inc = 0.01f; // offset for moving the triangle
float theta = 0;

void init(GLFWwindow* window) {
	renderingProgram = createShaderProgram(); //load, compile, create, attach and link shader programmes done here
	cameraX = 0.0f; cameraY = 0.0f; cameraZ = 8.0f;
	cubeLocX = 0.0f; cubeLocY = -2.0f; cubeLocZ = 0.0f; // shift down Y to reveal perspective
	// build perspective matrix
	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 1.0472 radians = 60 degrees
	setupVertices();
}
void display(GLFWwindow* window, double currentTime) {
	glClear(GL_DEPTH_BUFFER_BIT); 
	glClearColor(0.8, 0.8, 0.9, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glUseProgram(renderingProgram); //specify linked program to use
	//setup MV matrices 
	// and get the uniform variables from vertex shader for the MV and projection matrices
	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");
	// build perspective matrix
	glfwGetFramebufferSize(window, &width, &height);
	
	// build view matrix, model matrix, and model-view matrix
	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
	//vMat=glm::lookAt(glm::vec3(cameraX, cameraY, cameraZ), glm::vec3(cubeLocX, cubeLocY, cubeLocZ),glm::vec3(1.0f, 1.0f, 0.0f));
	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(cubeLocX, cubeLocY, cubeLocZ));
	mMat = glm::rotate(mMat, glm::radians(45.0f), glm::vec3(0.0f, 1.0f, 0.0f));
	mvMat = vMat * mMat;
	// copy perspective and MV matrices to corresponding uniform variables
	glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));
	// adjust OpenGL settings and draw model
	
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); //three vertices of triangle 1 primitive
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);



	/*glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);*/
	//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	//  glPolygonMode(GL_BACK,GL_FILL); //uses also GL_FRONT_AND_BACK; GL_FILL, GL_POINT, GL_LINE  
	//  glPolygonMode(GL_FRONT,GL_FILL);// to spec. whether poly's. front and back are drawn filled
										// as lines or points

	//glCullFace(GL_BACK);//discards front or back facing polygons
	glCullFace(GL_FRONT);//discards front or back facing polygons
	glEnable(GL_CULL_FACE);  
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDrawArrays(GL_TRIANGLES, 0, 48);  //draw triangle primitive

	/*glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
	glDrawArrays(GL_TRIANGLES, 0, 3);*/
}
int main(void) {
	if (!glfwInit()) { exit(EXIT_FAILURE); }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(600, 600, "Triangle glfw window", NULL, NULL);
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);
	init(window);
	while (!glfwWindowShouldClose(window)) {
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}


void setupVertices(void) { 
	// 9 vertices, for first triangle
	float tri1VertexPos[144] = {
		//A House
			 0.0, 0.0, 0.0,//front 
			 0.0, -2.0, 0.0,
			 1.0, 0.0, 0.0,
			0.0, -2.0, 0.0,
			1.0, -2.0, 0.0,
			1.0, 0.0, 0.0,

			1.0, 0.0, 0.0,//right 
			1.0, -2.0, 0.0,
			1.0, -2.0, -1.0,
			1.0, 0.0, 0.0,
			1.0, -2.0, -1.0,
			1.0, 0.0, -1.0,

			0.0, 0.0, 0.0,//left 
			0.0, 0.0, -1.0,
			0.0, -2.0, -1.0,
			0.0, 0.0, 0.0,
			0.0, -2.0, -1.0,
			0.0, -2.0, 0.0,

			0.0, -2.0, 0.0, //bottom
			0.0, -2.0, -1.0,
			1.0, -2.0, -1.0,
			0.0, -2.0, 0.0,
			1.0, -2.0, -1.0,
			1.0, -2.0, 0.0,

			0.0, 0.0, -1.0,//back 
			1.0, -2.0, -1.0,
			1.0, 0.0, -1.0,
			0.0, 0.0, -1.0,
			0.0, -2.0, -1.0,
			1.0, -2.0, -1.0,
		0.0, 0.0, 0.0,//front gable 
			1.0, 0.0, 0.0,
			0.5, 1.25, 0.0,

			0.0, 0.0, -1.0,//back gable 
			0.5, 1.25, -1.0,
			1.0, 0.0, -1.0,


			0.0, 0.0, 0.0,//left roof 
			0.5, 1.25, 0.0,
			0.5, 1.25, -1.0,
			0.0, 0.0, 0.0,
			0.5, 1.25, -1.0,
			0.0, 0.0, -1.0,

			0.5, 1.25, 0.0,//right roof 
			1.0, 0.0, 0.0,
			1.0, 0.0, -1.0,
			0.5, 1.25, 0.0,
			1.0, 0.0, -1.0,
			0.5, 1.25, -1.0
	};



	//initialse VAO and VBOs
	glGenVertexArrays(numVAOs, vao); //we will use one VAO
	glBindVertexArray(vao[0]);
	glGenBuffers(numVBOs, vbo);//we have one VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);//first VBO
	glBufferData(GL_ARRAY_BUFFER, sizeof(tri1VertexPos), tri1VertexPos, GL_STATIC_DRAW);
	//glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);//first VBO
	//glBufferData(GL_ARRAY_BUFFER, sizeof(tri1VertexColor), tri1VertexColor, GL_STATIC_DRAW);
	//glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);//3nd VBO
	//glBufferData(GL_ARRAY_BUFFER, sizeof(tri2VertexPos), tri2VertexPos, GL_STATIC_DRAW);
}
