/* Universidade Federal Fluminense
 * Programa de Pós-Graduação em Computação
 *
 * Tópicos Avançados em Computação Visual e Interfaces II (Técnicas Avançadas de Rendering)
 * Professor: Leandro Augusto Frata Fernandes
 *
 * Version: 2012.05.05-001
 */

#include "geometry.h"

QuadGeometry::QuadGeometry() {
	m_vertices.resize(4);
	m_vertices[0].vertex.set(-1.0f, -1.0f, 0.0f, 1.0f); m_vertices[0].normal.set(0.0f, 0.0f, 1.0f); m_vertices[0].texCoord0.set(0.0f, 0.0f); m_vertices[0].tangent.set(1.0f, 0.0f, 0.0f); m_vertices[0].bitangent.set(0.0f, 1.0f, 0.0f);
	m_vertices[1].vertex.set( 1.0f, -1.0f, 0.0f, 1.0f); m_vertices[1].normal.set(0.0f, 0.0f, 1.0f); m_vertices[1].texCoord0.set(1.0f, 0.0f); m_vertices[1].tangent.set(1.0f, 0.0f, 0.0f); m_vertices[1].bitangent.set(0.0f, 1.0f, 0.0f);
	m_vertices[2].vertex.set(-1.0f,  1.0f, 0.0f, 1.0f); m_vertices[2].normal.set(0.0f, 0.0f, 1.0f); m_vertices[2].texCoord0.set(0.0f, 1.0f); m_vertices[2].tangent.set(1.0f, 0.0f, 0.0f); m_vertices[2].bitangent.set(0.0f, 1.0f, 0.0f);
	m_vertices[3].vertex.set( 1.0f,  1.0f, 0.0f, 1.0f); m_vertices[3].normal.set(0.0f, 0.0f, 1.0f); m_vertices[3].texCoord0.set(1.0f, 1.0f); m_vertices[3].tangent.set(1.0f, 0.0f, 0.0f); m_vertices[3].bitangent.set(0.0f, 1.0f, 0.0f);

	m_indices.resize(6);
	m_indices[0] = 0;
	m_indices[1] = 1;
	m_indices[2] = 2;
	m_indices[3] = 2;
	m_indices[4] = 1;
	m_indices[5] = 3;
}

SphereGeometry::SphereGeometry(const GLuint& nRings_, const GLuint& nSegments_) {
	VertexData current;

	unsigned short verticeIndex = 0;
	GLfloat deltaRingAngle = (pi<GLfloat>() / nRings_);
	GLfloat deltaSegAngle = (2.0f * pi<GLfloat>() / nSegments_);
 
	for (GLuint ring=0; ring<=nRings_; ++ring) {
		GLfloat r0 = sin(ring * deltaRingAngle);
		GLfloat y0 = cos(ring * deltaRingAngle);
 
		for (GLuint seg=0; seg<=nSegments_; ++seg) {
			GLfloat x0 = r0 * sin(seg * deltaSegAngle);
			GLfloat z0 = r0 * cos(seg * deltaSegAngle);
 
			current.vertex.set(x0, y0, z0, 1.0f);
			current.normal.set(x0, y0, z0);
			current.texCoord0.set((GLfloat)seg / (GLfloat)nSegments_, (GLfloat)ring / (GLfloat)nRings_);
			m_vertices.push_back(current);
 
			if (ring != nRings_) {
				m_indices.push_back(verticeIndex + nSegments_ + 1);
				m_indices.push_back(verticeIndex);
				m_indices.push_back(verticeIndex + nSegments_);
				m_indices.push_back(verticeIndex + nSegments_ + 1);
				m_indices.push_back(verticeIndex + 1);
				m_indices.push_back(verticeIndex);
				verticeIndex++;
			}
		}
	}

	for (size_t i=0; i<m_indices.size(); i+=3) {
		VertexData& v1 = m_vertices[m_indices[i + 0]];
		VertexData& v2 = m_vertices[m_indices[i + 1]];
		VertexData& v3 = m_vertices[m_indices[i + 2]];
        
		const coord4f& deltaCoord1 = v2.vertex - v1.vertex;
		const coord4f& deltaCoord2 = v3.vertex - v1.vertex;
        
		const texcoord2f& deltaTexCoord1 = v2.texCoord0 - v1.texCoord0;
		const texcoord2f& deltaTexCoord2 = v3.texCoord0 - v1.texCoord0;
        
		const GLfloat r = 1.0f / (deltaTexCoord1.s * deltaTexCoord2.t - deltaTexCoord2.s * deltaTexCoord1.t);
		const coord4f& tangent = r * (deltaCoord1 * deltaTexCoord2.t - deltaCoord2 * deltaTexCoord1.t);
		const coord4f& bitangent = r * (deltaCoord2 * deltaTexCoord1.s - deltaCoord1 * deltaTexCoord2.s);

		v1.tangent.set(tangent.x, tangent.y, tangent.z);
		v1.bitangent.set(bitangent.x, bitangent.y, bitangent.z);

		v2.tangent.set(tangent.x, tangent.y, tangent.z);
		v2.bitangent.set(bitangent.x, bitangent.y, bitangent.z);

		v3.tangent.set(tangent.x, tangent.y, tangent.z);
		v3.bitangent.set(bitangent.x, bitangent.y, bitangent.z);
	}
}

DrawableGeometry::DrawableGeometry(const Geometry* geometry_) :
	m_geometry(geometry_) {
}

DrawableObject::DrawableObject(DrawableGeometry* drawableGeometry_) :
	m_drawableGeometry(drawableGeometry_) {
}

DrawableObject::DrawableObject(const coord3f& location_, const coord3f& forwardDirection_, const coord3f& upDirection_, DrawableGeometry* drawableGeometry_) :
	Object(location_, forwardDirection_, upDirection_),
	m_drawableGeometry(drawableGeometry_) {
}
