text: #include "Laborator6.h"
  
  #include <vector>
  #include <string>
  #include <iostream>
  
  #include <Core/Engine.h>
  
  using namespace std;
  
  Laborator6::Laborator6()
  {
  }
  
  Laborator6::~Laborator6()
  {
  }
  
  void Laborator6::Init()
  {
  	{
  		Mesh* mesh = new Mesh("box");
  		mesh->LoadMesh(RESOURCE_PATH::MODELS + "Primitives", "box.obj");
  		meshes[mesh->GetMeshID()] = mesh;
  	}
  
  	// Create a simple cube
  	{
  		vector<VertexFormat> vertices
  		{
  			VertexFormat(glm::vec3(-1, -1,  1), glm::vec3(0, 1, 1), glm::vec3(0.2, 0.8, 0.2)),
  			VertexFormat(glm::vec3( 1, -1,  1), glm::vec3(1, 0, 1), glm::vec3(0.9, 0.4, 0.2)),
  			VertexFormat(glm::vec3(-1,  1,  1), glm::vec3(1, 0, 0), glm::vec3(0.7, 0.7, 0.1)),
  			VertexFormat(glm::vec3( 1,  1,  1), glm::vec3(0, 1, 0), glm::vec3(0.7, 0.3, 0.7)),
  			VertexFormat(glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1), glm::vec3(0.3, 0.5, 0.4)),
  			VertexFormat(glm::vec3( 1, -1, -1), glm::vec3(0, 1, 1), glm::vec3(0.5, 0.2, 0.9)),
  			VertexFormat(glm::vec3(-1,  1, -1), glm::vec3(1, 1, 0), glm::vec3(0.7, 0.0, 0.7)),
  			VertexFormat(glm::vec3( 1,  1, -1), glm::vec3(0, 0, 1), glm::vec3(0.1, 0.5, 0.8)),
  		};
  
  		vector<unsigned short> indices =
  		{
  			0, 1, 2,		1, 3, 2,
  			2, 3, 7,		2, 7, 6,
  			1, 7, 3,		1, 5, 7,
  			6, 7, 4,		7, 5, 4,
  			0, 4, 1,		1, 4, 5,
  			2, 6, 4,		0, 2, 4,
  		};
  
  		CreateMesh("cube", vertices, indices);
  	}
  
  	// Create a shader program for drawing face polygon with the color of the normal
  	{
  		Shader *shader = new Shader("ShaderLab6");
  		shader->AddShader("Source/Laboratoare/Laborator6/Shaders/VertexShader.glsl", GL_VERTEX_SHADER);
  		shader->AddShader("Source/Laboratoare/Laborator6/Shaders/FragmentShader.glsl", GL_FRAGMENT_SHADER);
  		shader->CreateAndLink();
  		shaders[shader->GetName()] = shader;
  	}
  }
  
  Mesh* Laborator6::CreateMesh(const char *name, const std::vector<VertexFormat> &vertices, const std::vector<unsigned short> &indices)
  {
  	unsigned int VAO = 0;
  	// TODO: Create the VAO and bind it
  	glGenVertexArrays(1, &VAO);
  	glBindVertexArray(VAO);
  
  	// TODO: Create the VBO and bind it
  	unsigned int VBO;
  	glGenBuffers(1, &VBO);
  	glBindBuffer(GL_ARRAY_BUFFER, VBO);
  
  	// TODO: Send vertices data into the VBO buffer
  	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
  
  	// TODO: Crete the IBO and bind it
  	unsigned int IBO;
  	glGenBuffers(1, &IBO);
  	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
  
  	// TODO: Send indices data into the IBO buffer
  	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), &indices[0], GL_STATIC_DRAW);
  
  	// ========================================================================
  	// This section describes how the GPU Shader Vertex Shader program receives data
  
  	// set vertex position attribute
  	glEnableVertexAttribArray(0);
  	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), 0);
  
  	// set vertex normal attribute
  	glEnableVertexAttribArray(1);
  	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(sizeof(glm::vec3)));
  
  	// set texture coordinate attribute
  	glEnableVertexAttribArray(2);
  	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(2 * sizeof(glm::vec3)));
  
  	// set vertex color attribute
  	glEnableVertexAttribArray(3);
  	glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(2 * sizeof(glm::vec3) + sizeof(glm::vec2)));
  	// ========================================================================
  
  	// Unbind the VAO
  	glBindVertexArray(0);
  
  	// Check for OpenGL errors
  	CheckOpenGLError();
  
  	// Mesh information is saved into a Mesh object
  	meshes[name] = new Mesh(name);
  	meshes[name]->InitFromBuffer(VAO, static_cast<unsigned short>(indices.size()));
  	meshes[name]->vertices = vertices;
  	meshes[name]->indices = indices;
  	return meshes[name];
  }
  
  
  void Laborator6::FrameStart()
  {
  	// clears the color buffer (using the previously set color) and depth buffer
  	glClearColor(0, 0, 0, 1);
  	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  	glm::ivec2 resolution = window->GetResolution();
  	// sets the screen area where to draw
  	glViewport(0, 0, resolution.x, resolution.y);
  }
  
  void Laborator6::Update(float deltaTimeSeconds)
  {
  	/*{
  		glm::mat4 modelMatrix = glm::mat4(1);
  		modelMatrix = glm::translate(modelMatrix, glm::vec3(0, 1, 0));
  		modelMatrix = glm::rotate(modelMatrix, RADIANS(45.0f), glm::vec3(0, 1, 0));
  		modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f));
  		RenderSimpleMesh(meshes["cube"], shaders["VertexNormal"], modelMatrix);
  	}
  
  	{
  		glm::mat4 modelMatrix = glm::mat4(1);
  		modelMatrix = glm::translate(modelMatrix, glm::vec3(2, 0.5f, 0));
  		modelMatrix = glm::rotate(modelMatrix, RADIANS(60.0f), glm::vec3(1, 0, 0));
  		modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f));
  		RenderSimpleMesh(meshes["cube"], shaders["ShaderLab6"], modelMatrix);
  	}
  
  	{
  		glm::mat4 modelMatrix = glm::mat4(1);
  		modelMatrix = glm::translate(modelMatrix, glm::vec3(-2, 0.5f, 0));
  		modelMatrix = glm::rotate(modelMatrix, RADIANS(60.0f), glm::vec3(1, 1, 0));
  		RenderMesh(meshes["box"], shaders["ShaderLab6"], modelMatrix);
  	}*/
  
  	// corp avion
  	{
  		glm::mat4 modelMatrix = glm::mat4(1);
  		RenderMesh(meshes["corp_avion"], shaders["VertexNormal"], modelMatrix);
  	}
  }
  
  void Laborator6::FrameEnd()
  {
  	DrawCoordinatSystem();
  }
  
  void Laborator6::RenderSimpleMesh(Mesh *mesh, Shader *shader, const glm::mat4 & modelMatrix)
  {
  	if (!mesh || !shader || !shader->GetProgramID())
  		return;
  
  	// render an object using the specified shader and the specified position
  	glUseProgram(shader->program);
  
  	// TODO : get shader location for uniform mat4 "Model"
  	int modelLocation = glGetUniformLocation(shader->program, "Model");
  
  	// TODO : set shader uniform "Model" to modelMatrix
  	glUniformMatrix4fv(modelLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));
  
  	// TODO : get shader location for uniform mat4 "View"
  	int viewLocation = glGetUniformLocation(shader->program, "View");
  
  	// TODO : set shader uniform "View" to viewMatrix
  	glm::mat4 viewMatrix = GetSceneCamera()->GetViewMatrix();
  	glUniformMatrix4fv(viewLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
  
  	// TODO : get shader location for uniform mat4 "Projection"
  	int projectLocation = glGetUniformLocation(shader->program, "Projection");
  
  	// TODO : set shader uniform "Projection" to projectionMatrix
  	glm::mat4 projectionMatrix = GetSceneCamera()->GetProjectionMatrix();
  	glUniformMatrix4fv(projectLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
  
  	float time = Engine::GetElapsedTime();
  	int timeLocation = glGetUniformLocation(shader->program, "time");
  	glUniform1f(timeLocation, time);
  
  
  	// Draw the object
  	glBindVertexArray(mesh->GetBuffers()->VAO);
  	glDrawElements(mesh->GetDrawMode(), static_cast<int>(mesh->indices.size()), GL_UNSIGNED_SHORT, 0);
  }
  
  // Documentation for the input functions can be found in: "/Source/Core/Window/InputController.h" or
  // https://github.com/UPB-Graphics/Framework-EGC/blob/master/Source/Core/Window/InputController.h
  
  void Laborator6::OnInputUpdate(float deltaTime, int mods)
  {
  	// add key press event
  }
  
  void Laborator6::OnKeyPress(int key, int mods)
  {
  	// add key press event
  }
  
  void Laborator6::OnKeyRelease(int key, int mods)
  {
  	// add key release event
  }
  
  void Laborator6::OnMouseMove(int mouseX, int mouseY, int deltaX, int deltaY)
  {
  	// add mouse move event
  }
  
  void Laborator6::OnMouseBtnPress(int mouseX, int mouseY, int button, int mods)
  {
  	// add mouse button press event
  }
  
  void Laborator6::OnMouseBtnRelease(int mouseX, int mouseY, int button, int mods)
  {
  	// add mouse button release event
  }
  
  void Laborator6::OnMouseScroll(int mouseX, int mouseY, int offsetX, int offsetY)
  {
  }
  
  void Laborator6::OnWindowResize(int width, int height)
  {
  }
  