#include "stdafx.h"
#include "SnakeMesh.h"
#include <glm/gtx/rotate_vector.hpp>

graphics::SnakeMesh::SnakeMesh(unsigned int numIterations)
{
	yMax = -999999;
	m_numIterations = numIterations;
	numIndices = 6;
	numVertices = 4;
	VERTICES[0] = glm::vec3(0, 0, 0);
	VERTICES[1] = glm::vec3(0.5, 0, 0);
	VERTICES[2] = glm::vec3(0.5, 0.5, 0);
	VERTICES[3] = glm::vec3(0.0, 0.5, 0);
	xAxis = glm::vec3(1.0f, 0.0f, 0.0f);
	yAxis = glm::vec3(0.0f, 1.0f, 0.0f);
	INDICES[0] = 0;
	INDICES[1] = 1;
	INDICES[2] = 2;
	INDICES[3] = 0;
	INDICES[4] = 2;
	INDICES[5] = 3;
	
	glGenVertexArrays(1, &m_VAO);
	glBindVertexArray(m_VAO);
	glGenBuffers(2, &m_buffers[0]);
	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES), NULL, GL_STATIC_DRAW);
	glBufferSubData(GL_ARRAY_BUFFER, 0, 12 * sizeof(float), VERTICES);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[1]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(INDICES), NULL, GL_STATIC_DRAW);
	glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numIndices * sizeof(unsigned int), INDICES);

	glBindVertexArray(0);
}

void graphics::SnakeMesh::grow() {
	if (numVertices > m_numIterations) return;
	int A = numVertices - 4;
	int B = numVertices - 3;
	int C = numVertices - 2;
	int D = numVertices - 1;
	int E = numVertices;
	int F = numVertices + 1;
	int G = numVertices + 2;
	int H = numVertices + 3;
	/*for (int i = 0; i < 4; ++i) {
		VERTICES[numVertices + i] = VERTICES[numVertices + i - 4] + glm::vec3(0, 0, 0.25f);
	}*/
	static const float STEP = 0.25f;
	glm::vec3 randomPoints[4];
	 
	float angleY = 0.001f;
	float angleX = 2.1f;
	VERTICES[E] = VERTICES[A] + getRandomPoint(0.15);
	VERTICES[E] = rotate(VERTICES[E], glm::radians(angleX), yAxis);
	VERTICES[E] = rotate(VERTICES[E], glm::radians(angleY), xAxis);
	VERTICES[E].y += angleY;
	if (VERTICES[E].y > yMax) yMax = VERTICES[E].y;

	VERTICES[F] = VERTICES[B] + getRandomPoint(0.15);
	VERTICES[F] = rotate(VERTICES[F], glm::radians(angleX), yAxis);
	VERTICES[F] = rotate(VERTICES[F], glm::radians(angleY), xAxis);
	VERTICES[F].y += angleY;
	if (VERTICES[F].y > yMax) yMax = VERTICES[F].y;

	VERTICES[G] = VERTICES[C] + getRandomPoint(0.15);
	VERTICES[G] = rotate(VERTICES[G], glm::radians(angleX), yAxis);
	VERTICES[G] = rotate(VERTICES[G], glm::radians(angleY), xAxis);
	VERTICES[G].y += angleY;
	if (VERTICES[G].y > yMax) yMax = VERTICES[G].y;

	VERTICES[H] = VERTICES[D] + getRandomPoint(0.15);
	VERTICES[H] = rotate(VERTICES[H], glm::radians(angleX), yAxis);
	VERTICES[H] = rotate(VERTICES[H], glm::radians(angleY), xAxis);
	VERTICES[H].y += angleY;
	if (VERTICES[H].y > yMax) yMax = VERTICES[H].y;

	glm::vec3 tmpXAxis = xAxis;
	xAxis = rotate(xAxis, glm::radians(angleX), yAxis);
	yAxis = rotate(yAxis, glm::radians(angleY), tmpXAxis);

	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[0]);
	glBufferSubData(GL_ARRAY_BUFFER, numVertices*sizeof(float)*3, 12 * sizeof(float), VERTICES+numVertices);

	INDICES[numIndices] = A; INDICES[numIndices + 1] = B; INDICES[numIndices + 2] = E;
	INDICES[numIndices + 3] = B; INDICES[numIndices + 4] = E; INDICES[numIndices + 5] = F;

	INDICES[numIndices + 6] = B; INDICES[numIndices + 7] = C; INDICES[numIndices + 8] = F;
	INDICES[numIndices + 9] = C; INDICES[numIndices + 10] = F; INDICES[numIndices + 11] = G;

	INDICES[numIndices + 12] = A; INDICES[numIndices + 13] = D; INDICES[numIndices + 14] = E;
	INDICES[numIndices + 15] = D; INDICES[numIndices + 16] = E; INDICES[numIndices + 17] = H;

	INDICES[numIndices + 18] = D; INDICES[numIndices + 19] = C; INDICES[numIndices + 20] = G;
	INDICES[numIndices + 21] = D; INDICES[numIndices + 22] = G; INDICES[numIndices + 23] = H;

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[1]);
	glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, numIndices*sizeof(unsigned int),24 * sizeof(unsigned int), INDICES+numIndices);
	numIndices += 24;
	numVertices += 4;
}

void graphics::SnakeMesh::render() {
	glBindVertexArray(m_VAO);

	glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0);

	glBindVertexArray(0);
}

graphics::SnakeMesh::~SnakeMesh() {

}

glm::vec3 graphics::SnakeMesh::getRandomPoint(float r) {
	using namespace glm;
	r *= r;
	while (true) {
		float x = float(rand()) / float(RAND_MAX) - 0.5f;
		float y = float(rand()) / float(RAND_MAX) - 0.5f;
		if (x*x + y*y <= r) {
			return glm::vec3(x, y, 0.25f);
		}
	}
}