aboutsummaryrefslogtreecommitdiff
path: root/09-september/tomcat/renderer
diff options
context:
space:
mode:
Diffstat (limited to '09-september/tomcat/renderer')
-rw-r--r--09-september/tomcat/renderer/camera.c95
-rw-r--r--09-september/tomcat/renderer/camera.h32
-rw-r--r--09-september/tomcat/renderer/entity.c33
-rw-r--r--09-september/tomcat/renderer/mesh.c146
-rw-r--r--09-september/tomcat/renderer/mesh.h22
-rw-r--r--09-september/tomcat/renderer/model.c314
-rw-r--r--09-september/tomcat/renderer/model.h21
-rw-r--r--09-september/tomcat/renderer/renderer.c430
-rw-r--r--09-september/tomcat/renderer/renderer.h86
-rw-r--r--09-september/tomcat/renderer/renderer_types.h47
-rw-r--r--09-september/tomcat/renderer/shader.c187
-rw-r--r--09-september/tomcat/renderer/shader.h59
-rw-r--r--09-september/tomcat/renderer/texture.c188
-rw-r--r--09-september/tomcat/renderer/texture.h30
-rw-r--r--09-september/tomcat/renderer/vertex.h15
-rw-r--r--09-september/tomcat/renderer/window.c49
-rw-r--r--09-september/tomcat/renderer/window.h20
17 files changed, 1774 insertions, 0 deletions
diff --git a/09-september/tomcat/renderer/camera.c b/09-september/tomcat/renderer/camera.c
new file mode 100644
index 0000000..8a0c620
--- /dev/null
+++ b/09-september/tomcat/renderer/camera.c
@@ -0,0 +1,95 @@
+#include "camera.h"
+
+#include "../util/util_time.h"
+
+static const float movementSpeed = 40.0f;
+
+Camera *camera_new()
+{
+ Camera *camera;
+ camera = malloc( sizeof(Camera) );
+
+ camera->position = (Vec3){ 0.0f, 6.0f, 0.0f };
+ camera->viewDirection = (Vec3){ 0.5f, 0.0f, -1.0f };
+ camera->needsUpdate = true;
+ camera->up = (Vec3){ 0.0f, 1.0f, 0.0f };
+
+ return camera;
+}
+
+void camera_move_up(Camera* camera)
+{
+ Vec3 temp = vec3_scalar_mul(&camera->up, movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void camera_move_down(Camera* camera)
+{
+ Vec3 temp = vec3_scalar_mul(&camera->up, -movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void camera_move_left(Camera* camera)
+{
+ Vec3 strafeDirection = vec3_cross_mul(&camera->viewDirection, &camera->up);
+ strafeDirection = vec3_scalar_mul(&strafeDirection, -movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &strafeDirection);
+}
+
+void camera_move_right(Camera* camera)
+{
+ Vec3 strafeDirection = vec3_cross_mul(&camera->viewDirection, &camera->up);
+ strafeDirection = vec3_scalar_mul(&strafeDirection, movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &strafeDirection);
+}
+
+void camera_move_foward(Camera* camera)
+{
+ Vec3 temp = vec3_scalar_mul(&camera->viewDirection, movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void camera_move_backward(Camera* camera)
+{
+ Vec3 temp = vec3_scalar_mul(&camera->viewDirection, -movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void camera_mouse_update(Camera *camera, const Vec2 *newMousePosition)
+{
+ Vec2 mouseDelta = vec2_sub(newMousePosition, &camera->mousePosition);
+
+ /* El if evita que el mouse se teletrasporte al cambiar de posicion muy rapido */
+ if(vec2_length(&mouseDelta) > 50.0f){
+ camera->mousePosition = *newMousePosition;
+ return;
+ }
+
+ Vec3 verticalRotation = vec3_cross_mul(&camera->viewDirection, &camera->up);
+
+ Mat4 temp = mat4_rotate(mouseDelta.x * -0.5f, &camera->up);
+
+ camera->viewDirection = mat4_mul_vec3(&temp, &camera->viewDirection);
+
+ temp = mat4_rotate(mouseDelta.y * -0.5f, &verticalRotation);
+ camera->viewDirection = mat4_mul_vec3(&temp, &camera->viewDirection);
+
+ camera->mousePosition = *newMousePosition;
+
+ camera->needsUpdate = true;
+}
+
+void camera_free(Camera *camera)
+{
+ free(camera);
+}
+
+Mat4 camera_get_model_to_view_matrix(Camera* camera)
+{
+ if(camera->needsUpdate)
+ {
+ Vec3 temp = vec3_add(&camera->position, &camera->viewDirection);
+ camera->viewMatrix = mat4_lookAt(&camera->position, &temp, &camera->up);
+ }
+ return camera->viewMatrix;
+}
diff --git a/09-september/tomcat/renderer/camera.h b/09-september/tomcat/renderer/camera.h
new file mode 100644
index 0000000..0c63178
--- /dev/null
+++ b/09-september/tomcat/renderer/camera.h
@@ -0,0 +1,32 @@
+#ifndef CAMERA_H
+#define CAMERA_H
+
+#include "../math/matrix4x4.h"
+#include "../math/vector.h"
+#include <stdbool.h>
+
+typedef struct
+{
+ Vec3 position;
+ Vec3 viewDirection;
+ Vec3 up;
+ Mat4 projectionMatrix;
+ Mat4 viewMatrix;
+ Vec2 mousePosition;
+ bool needsUpdate;
+} Camera;
+
+extern Camera *camera_new();
+extern void camera_move_up(Camera *camera);
+extern void camera_move_down(Camera *camera);
+extern void camera_move_left(Camera *camera);
+extern void camera_move_right(Camera *camera);
+extern void camera_move_foward(Camera *camera);
+extern void camera_move_backward(Camera *camera);
+extern void camera_mouse_update(Camera *camera, const Vec2 *newMousePosition);
+extern void camera_free(Camera *camera);
+
+/* Consigue la viewMatrix */
+extern Mat4 camera_get_model_to_view_matrix(Camera *camera);
+
+#endif // CAMERA_H
diff --git a/09-september/tomcat/renderer/entity.c b/09-september/tomcat/renderer/entity.c
new file mode 100644
index 0000000..d5e7429
--- /dev/null
+++ b/09-september/tomcat/renderer/entity.c
@@ -0,0 +1,33 @@
+#include "renderer.h"
+
+Mat4 Entity_GetModelTransform(Entity* entity)
+{
+ Mat4 temp;
+ Mat4 rotation = mat4_rotate_x(entity->rotX);
+ temp = mat4_rotate_y(entity->rotY);
+ rotation = mat4_mul(&rotation, &temp);
+ temp = mat4_rotate_z(entity->rotZ);
+ rotation = mat4_mul(&rotation, &temp);
+
+ temp = mat4_translate(&entity->position);
+
+ Mat4 modelTransform = mat4_mul(&temp, &rotation);
+ temp = mat4_scale(entity->scale[0], entity->scale[1], entity->scale[2]);
+ modelTransform = mat4_mul(&modelTransform, &temp);
+
+ return modelTransform;
+}
+
+Vec2 Entity_GetTexOffset(Entity *entity)
+{
+ /* Offset inside a texture atlas should default to (0, 0)*/
+ Vec2 tex_offset;
+ Texture *t = entity->texture;
+
+ int column = entity->index % t->number_of_rows;
+ int row = entity->index / t->number_of_rows;
+ tex_offset.x = (float)column / t->number_of_rows;
+ tex_offset.y = (float)row / t->number_of_rows;
+
+ return tex_offset;
+}
diff --git a/09-september/tomcat/renderer/mesh.c b/09-september/tomcat/renderer/mesh.c
new file mode 100644
index 0000000..7ef27dc
--- /dev/null
+++ b/09-september/tomcat/renderer/mesh.c
@@ -0,0 +1,146 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "mesh.h"
+#include "renderer.h"
+
+#define NUM_ARRAY_ELEMENTS(a) sizeof(a) / sizeof(*a)
+
+Mesh *mesh_new(vertex_t* vertices, GLsizeiptr vertexBuffersize,
+ GLushort* indices, GLsizeiptr indexBuffersize)
+{
+ Mesh *mesh;
+ mesh = malloc( sizeof(Mesh) );
+ memset(mesh, 0, sizeof(Mesh) );
+
+ render.meshes[render.num_meshes] = mesh;
+ render.num_meshes += 1;
+
+ mesh->num_indices = ( indexBuffersize / sizeof(GLushort) );
+
+ glGenVertexArrays(1, &mesh->vao);
+ glGenBuffers(1, &mesh->vbo);
+ glGenBuffers(1, &mesh->ebo);
+
+ glBindVertexArray(mesh->vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
+ glBufferData(GL_ARRAY_BUFFER, vertexBuffersize, vertices, GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ebo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffersize, indices, GL_STATIC_DRAW);
+
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+ glEnableVertexAttribArray(3);
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, position) );
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, texCoord) );
+ glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, normal) );
+ glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, tangent) );
+
+ glBindVertexArray(0);
+ return mesh;
+}
+
+Mesh *mesh_make_skybox(float size)
+{
+ Mesh *mesh;
+ mesh = malloc( sizeof(Mesh) );
+ memset(mesh, 0, sizeof(Mesh) );
+
+ render.meshes[render.num_meshes] = mesh;
+ render.num_meshes += 1;
+
+ Vec3 positions[] =
+ {
+ {-size, size, -size}, {-size, -size, -size}, {+size, -size, -size},
+ {+size, -size, -size}, {+size, +size, -size}, {-size, +size, -size},
+
+ {-size, -size, +size}, {-size, -size, -size}, {-size, +size, -size},
+ {-size, +size, -size}, {-size, +size, +size}, {-size, -size, +size},
+
+ {+size, -size, -size}, {+size, -size, +size}, {+size, +size, +size},
+ {+size, +size, +size}, {+size, +size, -size}, {+size, -size, -size},
+
+ {-size, -size, +size}, {-size, +size, +size}, {+size, +size, +size},
+ {+size, +size, +size}, {+size, -size, +size}, {-size, -size, +size},
+
+ {-size, +size, -size}, {+size, +size, -size}, {+size, +size, +size},
+ {+size, +size, +size}, {-size, +size, +size}, {-size, +size, -size},
+
+ {-size, -size, -size}, {-size, -size, +size}, {+size, -size, -size},
+ {+size, -size, -size}, {-size, -size, +size}, {+size, -size, +size}
+ };
+
+ mesh->num_indices = 0;
+ mesh->num_vertices = NUM_ARRAY_ELEMENTS(positions);
+
+ glGenVertexArrays(1, &mesh->vao);
+ glGenBuffers(1, &mesh->vbo);
+ mesh->ebo = 0;
+
+ glBindVertexArray(mesh->vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
+
+ glEnableVertexAttribArray(0);
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
+
+ glBindVertexArray(0);
+ return mesh;
+}
+
+Mesh *mesh_make_quad()
+{
+ Mesh *mesh;
+ mesh = malloc( sizeof(Mesh) );
+ memset(mesh, 0, sizeof(Mesh) );
+
+ render.meshes[render.num_meshes] = mesh;
+ render.num_meshes += 1;
+
+ Vec3 positions[] =
+ {
+ { -0.5f, +0.5f, +0.0f}, { -0.5f, -0.5f, +0.0f},
+ { +0.5f, +0.5f, +0.0f}, { +0.5f, -0.5f, +0.0f}
+ };
+
+ mesh->num_vertices = NUM_ARRAY_ELEMENTS(positions);
+ mesh->num_indices = 0;
+
+ glGenVertexArrays(1, &mesh->vao);
+ glGenBuffers(1, &mesh->vbo);
+ mesh->ebo = 0;
+
+ glBindVertexArray(mesh->vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
+
+ glEnableVertexAttribArray(0);
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
+
+ glBindVertexArray(0);
+ return mesh;
+}
+
+void mesh_purge(Mesh *mesh)
+{
+ if(mesh)
+ {
+ if(mesh->vbo)
+ glDeleteBuffers(1, &mesh->vbo);
+ if(mesh->ebo)
+ glDeleteBuffers(1, &mesh->ebo);
+ if(mesh->vao)
+ glDeleteVertexArrays(1, &mesh->vao);
+
+ memset(mesh, 0, sizeof(Mesh));
+ }
+}
diff --git a/09-september/tomcat/renderer/mesh.h b/09-september/tomcat/renderer/mesh.h
new file mode 100644
index 0000000..711a82e
--- /dev/null
+++ b/09-september/tomcat/renderer/mesh.h
@@ -0,0 +1,22 @@
+#ifndef MESH_H
+#define MESH_H
+
+#include "vertex.h"
+
+typedef struct _Mesh
+{
+ GLuint num_indices;
+ GLuint num_vertices;
+ GLuint vbo, ebo, vao;
+} Mesh;
+
+/** Mesh Factory **/
+extern Mesh *mesh_new(vertex_t* vertices, GLsizeiptr vertexBuffersize,
+ GLushort* indices, GLsizeiptr indexBuffersize);
+
+extern Mesh *mesh_make_skybox(float size);
+extern Mesh *mesh_make_quad();
+
+extern void mesh_purge(Mesh *mesh);
+
+#endif // MESH_H
diff --git a/09-september/tomcat/renderer/model.c b/09-september/tomcat/renderer/model.c
new file mode 100644
index 0000000..3c65ad3
--- /dev/null
+++ b/09-september/tomcat/renderer/model.c
@@ -0,0 +1,314 @@
+#include "model.h"
+#include "renderer.h"
+#include "../util/array.h"
+#include "../util/util.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define MAX_HASH_MODELS 1024
+static Model *model_hash_table[MAX_HASH_MODELS];
+
+static const int BUFFER_SIZE = 128;
+
+static Model *_model_alloc(const char *name)
+{
+ if(strlen(name) > MAX_PATH_LENGTH)
+ Util_FatalError("File following model name is too long: %s", name);
+
+ if(render.num_models >= MAX_MODELS)
+ return NULL;
+
+ Model *model;
+
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_MODELS;
+
+ model = malloc( sizeof(Model) );
+ memset(model, 0, sizeof(Model) );
+
+ render.models[render.num_models] = model;
+ render.num_models += 1;
+
+ strcpy(model->_name, name);
+ model->_hash_next = model_hash_table[hash_];
+ model_hash_table[hash_] = model;
+
+ model->_hash = hash_;
+
+ return model;
+}
+
+Model *model_get(const char *name)
+{
+ Model *model;
+
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_MODELS;
+
+ if(model_hash_table[hash_] != NULL)
+ {
+ for(model = model_hash_table[hash_]; model; model = model->_hash_next)
+ {
+ if( model->_hash == hash_ )
+ return model;
+ }
+ }
+
+ return NULL;
+}
+
+typedef struct
+{
+ vertex_t *data;
+ GLushort *indices;
+
+ Array *positions;
+ Array *textures;
+ Array *normals;
+ Array *tangents;
+
+ unsigned int vertex_count, index_count;
+ unsigned int index_pointer;
+
+ GLubyte hasTextCoords, hasNormals;
+} OBJ_Mesh;
+
+static vertex_t *search_index(vertex_t *pkey, vertex_t *pelem, unsigned int vertex_count)
+{
+ int i;
+ for(i = 0; i < vertex_count; i++)
+ {
+ if(pelem[i].position.x == pkey->position.x &&
+ pelem[i].position.y == pkey->position.y &&
+ pelem[i].position.z == pkey->position.z &&
+ pelem[i].texCoord.x == pkey->texCoord.x &&
+ pelem[i].texCoord.y == pkey->texCoord.y &&
+ pelem[i].normal.x == pkey->normal.x &&
+ pelem[i].normal.y == pkey->normal.y &&
+ pelem[i].normal.z == pkey->normal.z)
+ {
+ return &pelem[i];
+ }
+ }
+ return NULL;
+}
+
+static void calculate_tangents(OBJ_Mesh *mesh)
+{
+ int i;
+ for(i = 0; i < mesh->index_count; i += 3)
+ {
+ int i0 = i;
+ int i1 = i + 1;
+ int i2 = i + 2;
+
+ Vec3 *v0 = ( (Vec3 *)mesh->positions->data) + i0;
+ Vec3 *v1 = ( (Vec3 *)mesh->positions->data) + i1;
+ Vec3 *v2 = ( (Vec3 *)mesh->positions->data) + i2;
+
+ Vec2 *uv0 = ( (Vec2 *)mesh->textures->data) + i0;
+ Vec2 *uv1 = ( (Vec2 *)mesh->textures->data) + i1;
+ Vec2 *uv2 = ( (Vec2 *)mesh->textures->data) + i2;
+
+ Vec3 deltaPos1 = vec3_sub(v1, v0);
+ Vec3 deltaPos2 = vec3_sub(v2, v0);
+
+ Vec2 deltaUV1 = vec2_sub(uv1, uv0);
+ Vec2 deltaUV2 = vec2_sub(uv2, uv0);
+
+ GLfloat r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
+
+ deltaPos1 = vec3_scalar_mul(&deltaPos1, deltaUV2.y);
+ deltaPos2 = vec3_scalar_mul(&deltaPos2, deltaUV1.y);
+
+ Vec3 tangent = vec3_sub(&deltaPos1, &deltaPos2);
+ tangent = vec3_scalar_mul(&tangent, r);
+
+ ( (Vec3 *)mesh->tangents->data)[i2] = tangent;
+ ( (Vec3 *)mesh->tangents->data)[i1] = tangent;
+ ( (Vec3 *)mesh->tangents->data)[i0] = tangent;
+ }
+ /*
+ We normalize the tangents at the end of the parse_obj_index loop
+ for(i = 0; i < mesh.index_count; i++)
+ {
+ mesh.tangents[i] = vec3_normalize(&mesh.tangents[i]);
+ }
+ */
+}
+
+static void parse_obj_index(OBJ_Mesh *mesh, vertex_t *current_vertex)
+{
+ vertex_t *indexOnArray = search_index(current_vertex, mesh->data, mesh->vertex_count);
+
+ /* We check if the vertex was already loaded, so the index points to the created vertex instead of repeating data*/
+ if(indexOnArray == NULL)
+ {
+ mesh->data = (vertex_t*) realloc( mesh->data, sizeof(vertex_t) * (++mesh->vertex_count) );
+
+ /* We make the index point to the last vertex added */
+ mesh->indices[mesh->index_pointer] = mesh->vertex_count - 1;
+
+ mesh->data[mesh->vertex_count - 1] = *current_vertex;
+ }
+ else
+ {
+ GLushort index = (GLushort)(indexOnArray - mesh->data);
+ mesh->data[index].tangent = vec3_add( &mesh->data[index].tangent,
+ &current_vertex->tangent );
+
+ /* We make the index point to the previus vertex added instead of creating a new one */
+ mesh->indices[mesh->index_pointer] = index;
+ }
+
+ mesh->index_pointer += 1;
+}
+
+Model *model_obj_new(const char *path)
+{
+ Model *model;
+ model = model_get(path);
+
+ if(model)
+ return model;
+
+ OBJ_Mesh obj_mesh;
+ memset( &obj_mesh, 0, sizeof(OBJ_Mesh) );
+
+ obj_mesh.positions = array_create( sizeof(Vec3) );
+ obj_mesh.normals = array_create( sizeof(Vec3) );
+ obj_mesh.textures = array_create( sizeof(Vec2) );
+
+ Array *positions = array_create( sizeof(Vec3) );
+ Array *normals = array_create( sizeof(Vec3) );
+ Array *textures = array_create( sizeof(Vec2) );
+
+ vertex_t current_vertex;
+
+ Vec3 current_position;
+ Vec3 current_normal;
+ Vec2 current_texture;
+
+ int count = 0, i;
+ int texture[3], normal[3], verts[3];
+
+ FILE *file = fopen(path, "r");
+ if(file == NULL)
+ Util_FatalError("%s file could not be loaded!", path);
+
+ char buffer[BUFFER_SIZE];
+ while( !feof(file) )
+ {
+ fgets(buffer, BUFFER_SIZE, file);
+ switch(buffer[0])
+ {
+ case 'v':
+ if(buffer[1] == 't')
+ {
+ count = sscanf(buffer, "vt %f %f\n", &current_texture.x, &current_texture.y);
+
+ array_append(textures, &current_texture);
+
+ if(count != 2)
+ Util_FatalError("Bad texture coordinates on .obj file");
+ }
+ else if(buffer[1] == 'n')
+ {
+ count = sscanf(buffer, "vn %f %f %f\n", &current_normal.x,
+ &current_normal.y,
+ &current_normal.z);
+ array_append(normals, &current_normal);
+
+ if(count != 3)
+ Util_FatalError("Bad normals data on .obj file");
+ }
+ else
+ {
+ count = sscanf(buffer, "v %f %f %f\n", &current_position.x,
+ &current_position.y,
+ &current_position.z);
+
+ array_append(positions, &current_position);
+
+ if(count != 3)
+ Util_FatalError("Bad vertices data on .obj file");
+ }
+ break;
+ case 'f':
+ obj_mesh.index_count += 3;
+
+ count = sscanf(buffer, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
+ &verts[0], &texture[0], &normal[0],
+ &verts[1], &texture[1], &normal[1],
+ &verts[2], &texture[2], &normal[2]);
+
+ if(count != 9)
+ Util_FatalError("Bad face data on .obj file");
+
+ array_append(obj_mesh.positions, &( (Vec3 *)positions->data )[ verts[0] -1 ] );
+ array_append(obj_mesh.positions, &( (Vec3 *)positions->data )[ verts[1] -1 ] );
+ array_append(obj_mesh.positions, &( (Vec3 *)positions->data )[ verts[2] -1 ] );
+
+ array_append(obj_mesh.normals, &( (Vec3 *)normals->data )[ normal[0] - 1 ] );
+ array_append(obj_mesh.normals, &( (Vec3 *)normals->data )[ normal[1] - 1 ] );
+ array_append(obj_mesh.normals, &( (Vec3 *)normals->data )[ normal[2] - 1 ] );
+
+ array_append(obj_mesh.textures, &( (Vec2 *)textures->data )[ texture[0] - 1 ] );
+ array_append(obj_mesh.textures, &( (Vec2 *)textures->data )[ texture[1] - 1 ] );
+ array_append(obj_mesh.textures, &( (Vec2 *)textures->data )[ texture[2] - 1 ] );
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ obj_mesh.indices = malloc( obj_mesh.index_count * sizeof(GLushort) );
+ obj_mesh.tangents = array_create_by_size( sizeof(Vec3), obj_mesh.index_count );
+ calculate_tangents(&obj_mesh);
+
+ for(i = 0; i < obj_mesh.index_count; i++)
+ {
+ current_vertex.position = ( (Vec3 *)obj_mesh.positions->data )[i];
+ current_vertex.texCoord = ( (Vec2 *)obj_mesh.textures->data )[i];
+ current_vertex.normal = ( (Vec3 *)obj_mesh.normals->data )[i];
+ current_vertex.tangent = ( (Vec3 *)obj_mesh.tangents->data )[i];
+
+ parse_obj_index(&obj_mesh, &current_vertex);
+ }
+
+ for(i = 0; i < obj_mesh.vertex_count; i++)
+ {
+ obj_mesh.data[i].tangent = vec3_normalize(&obj_mesh.data[i].tangent);
+ }
+
+ array_free(obj_mesh.positions);
+ array_free(obj_mesh.normals);
+ array_free(obj_mesh.textures);
+ array_free(obj_mesh.tangents);
+
+ array_free(positions);
+ array_free(textures);
+ array_free(normals);
+
+ fclose(file);
+
+ GLsizeiptr vertexBuffersize = obj_mesh.vertex_count * sizeof(vertex_t);
+ GLsizeiptr indexBuffersize = obj_mesh.index_count * sizeof(GLushort);
+
+ model = _model_alloc(path);
+
+ model->mesh = mesh_new(obj_mesh.data, vertexBuffersize, obj_mesh.indices, indexBuffersize);
+
+ free(obj_mesh.data);
+ free(obj_mesh.indices);
+
+ return model;
+}
+
+void model_purge(Model *model)
+{
+ mesh_purge(model->mesh);
+}
diff --git a/09-september/tomcat/renderer/model.h b/09-september/tomcat/renderer/model.h
new file mode 100644
index 0000000..6b514dd
--- /dev/null
+++ b/09-september/tomcat/renderer/model.h
@@ -0,0 +1,21 @@
+#ifndef MODEL_H
+#define MODEL_H
+
+#include "../shared.h"
+#include "mesh.h"
+
+typedef struct _Model
+{
+ Mesh *mesh;
+ /* Material? */
+
+ char _name[MAX_PATH_LENGTH];
+ struct _Model *_hash_next;
+ unsigned int _hash;
+} Model;
+
+extern Model *model_obj_new(const char *path);
+extern Model *model_get(const char *name);
+extern void model_purge(Model *model);
+
+#endif // MODEL_H
diff --git a/09-september/tomcat/renderer/renderer.c b/09-september/tomcat/renderer/renderer.c
new file mode 100644
index 0000000..307c543
--- /dev/null
+++ b/09-september/tomcat/renderer/renderer.c
@@ -0,0 +1,430 @@
+#include "renderer.h"
+#include "../util/util_time.h"
+#include "../util/util.h"
+
+#include <string.h>
+
+#define MAX_LIGHTS 4
+
+Renderer render;
+
+void Render_Init(Window *window)
+{
+ memset( &render, 0, sizeof(Renderer) );
+
+ if(glewInit() != GLEW_OK)
+ Util_FatalError("Glew could no be started!");
+
+ strcpy( render.info.version, (const char *) glGetString(GL_VERSION) );
+ strcpy( render.info.vendor, (const char *) glGetString(GL_VENDOR) );
+ strcpy( render.info.shading_version, (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION) );
+
+ fprintf(stderr, "%s\n", render.info.version);
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glClearColor(0.0f, 0.0f, 0.39f, 1.0f);
+
+ //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+
+ render.default_quad = mesh_make_quad();
+
+ render.default_shader = shader_new("pass_shader", "resources/shaders/passShader.vert",
+ "resources/shaders/passShader.frag");
+ render.default_shader->totalTransform = shader_get_uniform_location(render.default_shader, "M_MVP");
+ render.default_shader->Texture = shader_get_uniform_location(render.default_shader, "Texture");
+
+
+ glBindVertexArray(render.default_quad->vao);
+ glCreateBuffers(1, &render.instance_vbo);
+
+ glBindBuffer(GL_ARRAY_BUFFER, render.instance_vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 18 * 10000, NULL, GL_STREAM_DRAW);
+
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 0));
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 2) );
+ glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 6) );
+ glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 10) );
+ glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 14) );
+
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+ glEnableVertexAttribArray(3);
+ glEnableVertexAttribArray(4);
+ glEnableVertexAttribArray(5);
+
+ glVertexAttribDivisor(1, 1);
+ glVertexAttribDivisor(2, 1);
+ glVertexAttribDivisor(3, 1);
+ glVertexAttribDivisor(4, 1);
+ glVertexAttribDivisor(5, 1);
+
+ glBindVertexArray(0);
+
+ render.window = window;
+ render.shadow_width = 1024;
+ render.shadow_height = 1024;
+
+ /** TEMP **/
+
+ Vec3 center = {0.0f, 0.0f, 0.0f};
+ Vec3 up = {0.0f, 1.0f, 0.0f};
+ render.inv_light_dir = (Vec3){11.54f, 66.74f, 9.93f};
+ Mat4 shadow_ortho_mat = mat4_orthographic(-100.0f, 100.0f, -100.0f, 100.0f, -100.0f, 200.0f);
+ Mat4 shadow_view_mat = mat4_lookAt(&render.inv_light_dir, &center, &up);
+ Mat4 shadow_model;
+ mat4_identity(&shadow_model);
+
+ render.shadow_mvp = mat4_mul(&shadow_ortho_mat, &shadow_view_mat);
+ render.shadow_mvp = mat4_mul(&render.shadow_mvp, &shadow_model);
+
+ render.shadow_shader = shader_new("s_shader", "resources/shaders/shadow_shader.vert",
+ "resources/shaders/shadow_shader.frag");
+ render.shadow_shader->totalTransform = shader_get_uniform_location(render.shadow_shader, "M_MVP");
+
+ /** TEMP **/
+
+ glGenFramebuffers(1, &render.shadow_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, render.shadow_fbo);
+
+
+ glGenTextures(1, &render.shadow_map);
+ glBindTexture(GL_TEXTURE_2D, render.shadow_map);
+
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, render.shadow_width,
+ render.shadow_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenTextures(1, &render.shadow_color);
+ glBindTexture(GL_TEXTURE_2D, render.shadow_color);
+
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, render.shadow_width,
+ render.shadow_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, render.shadow_map, 0);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, render.shadow_color, 0);
+
+ //glDrawBuffer(GL_NONE);
+ GLenum draw_buffer = GL_COLOR_ATTACHMENT0;
+ glDrawBuffers(1, &draw_buffer);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ Util_FatalError("Could not create a frame buffer object\n");
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glViewport(0, 0, render.window->Width, render.window->Height);
+
+ Util_CheckGLError();
+}
+
+void Render_BeginFrame()
+{
+ glClearColor(0.0f, 0.0f, 0.39f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+ glBindFramebuffer(GL_FRAMEBUFFER, render.shadow_fbo);
+ glViewport(0, 0, render.shadow_width, render.shadow_height);
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+}
+
+void Render_LoadLights(Shader *s, const Light *lights, int n)
+{
+ Vec3 light_positions[MAX_LIGHTS];
+ Vec4 light_colors[MAX_LIGHTS];
+ Vec3 attenuation[MAX_LIGHTS];
+ int i;
+
+ /* Default light in case we are not given enough lights (n < 4) */
+ static const Light defaultLight =
+ {
+ { 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 1.0f, 0.0f, 0.0f }
+ };
+
+ for(i = 0; i < MAX_LIGHTS; i++)
+ {
+ if(i < n)
+ {
+ light_positions[i] = lights[i].position;
+ light_colors[i] = lights[i].color;
+ attenuation[i] = lights[i].attenuation;
+ }
+ else
+ {
+ light_positions[i] = defaultLight.position;
+ light_colors[i] = defaultLight.color;
+ attenuation[i] = defaultLight.attenuation;
+ }
+
+ }
+
+ glUniform3fv(s->lightPosition, MAX_LIGHTS, (float *)light_positions);
+ glUniform4fv(s->lightColor, MAX_LIGHTS, (float *)light_colors);
+ glUniform3fv(s->lightAttenuation, MAX_LIGHTS, (float *)attenuation);
+}
+
+/******************************************************************************
+* *
+* Function Name: Render_DrawEntity *
+* *
+* Specific shader layout *
+* -> extra0 texture atlas number of rows *
+* -> extra1 texture atlas xy offset *
+* *
+*******************************************************************************/
+
+void Render_DrawEntity(Shader *s, Mat4 *projectedViewMatrix, Entity *entity)
+{
+ Mesh *mesh = entity->model->mesh;
+ /*We need the model to world matrix in our shader in order to rotate the normals*/
+ Mat4 modelTransform = Entity_GetModelTransform(entity);
+ Mat4 totalMatrix;
+
+ /** TEMP **/
+
+ /** TEMP**/
+
+ glUniformMatrix4fv(s->modelToWorld, 1, GL_FALSE, modelTransform.data);
+
+ totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform);
+ glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalMatrix.data);
+
+ glUniform1i(s->Texture, 0);
+ texture_bind(entity->texture, 0);
+
+ glUniform1f(s->extra0, entity->texture->number_of_rows);
+ Vec2 tex_offset = Entity_GetTexOffset(entity);
+ glUniform2fv(s->extra1, 1, (float *)&tex_offset);
+
+ glBindVertexArray(mesh->vao);
+ glDrawElements(GL_TRIANGLES, mesh->num_indices, GL_UNSIGNED_SHORT, NULL);
+ glBindVertexArray(0);
+}
+
+/******************************************************************************
+* *
+* Function Name: Render_DrawTerrain *
+* *
+* Specific shader layout *
+* -> extra0 Texture_Background *
+* -> extra1 Texture_R *
+* -> extra2 Texture_G *
+* -> extra3 Texture_B *
+* -> extra4 Texture_BlendMap *
+* *
+*******************************************************************************/
+
+void Render_DrawTerrain(Shader *s, Mat4 *projectedViewMatrix, Terrain *terrain)
+{
+ Mat4 totalMatrix;
+ Mat4 modelTransform;
+
+ /* We need the model to world matrix in our shader in order to rotate the normals */
+ modelTransform = mat4_translate(&terrain->position);
+ glUniformMatrix4fv(s->modelToWorld, 1, GL_FALSE, modelTransform.data);
+
+ totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform);
+ glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalMatrix.data);
+
+ /** Set textures for the terrain **/
+
+ glUniform1i(s->extra0, 0);
+ glUniform1i(s->extra1, 1);
+ glUniform1i(s->extra2, 2);
+ glUniform1i(s->extra3, 3);
+ glUniform1i(s->extra4, 4);
+
+ texture_bind(terrain->textures.texture[0], 0);
+ texture_bind(terrain->textures.texture[1], 1);
+ texture_bind(terrain->textures.texture[2], 2);
+ texture_bind(terrain->textures.texture[3], 3);
+ texture_bind(terrain->blendmap, 4);
+
+ /**********************************/
+
+ glBindVertexArray(terrain->mesh->vao);
+ glDrawElements(GL_TRIANGLES, terrain->mesh->num_indices, GL_UNSIGNED_SHORT, NULL);
+ glBindVertexArray(0);
+}
+
+void Render_DrawSky(Shader *s, Mat4 *viewMatrix, Mat4 *projectionMatrix, Skybox *sky)
+{
+ Mat4 myViewMatrix = *viewMatrix;
+ Mat4 totalTransform;
+ Mat4 rotateMatrix = mat4_rotate_y(sky->rotation);
+
+ sky->rotation += SKYBOX_ROTATION_SPEED * Time_GetFrameTime();
+
+ /* We don't want to move the skybox around (We want it to stay with the camera in the midle),
+ just rotate it with the camera so we remove the translations components of the matrix */
+
+ myViewMatrix.data[0 + 3 * 4] = 0.0f;
+ myViewMatrix.data[1 + 3 * 4] = 0.0f;
+ myViewMatrix.data[2 + 3 * 4] = 0.0f;
+
+ myViewMatrix = mat4_mul(&myViewMatrix, &rotateMatrix);
+ totalTransform = mat4_mul(projectionMatrix, &myViewMatrix);
+
+ glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalTransform.data );
+
+ texture_bind(sky->texture, 0);
+ glUniform1i(s->Texture, 0);
+
+ glBindVertexArray(sky->cube->vao);
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+ glBindVertexArray(0);
+}
+
+/******************************************************************************
+* *
+* Function Name: Render_DrawParticles *
+* *
+* Specific shader layout *
+* -> extra0 texture atlas number of rows *
+* -> extra1 texture atlas xy offset *
+* *
+*******************************************************************************/
+
+void Render_DrawParticles(Shader *s, Mat4 *viewMatrix, Mat4 *projectionMatrix)
+{
+ Mat4 modelTransform, modelViewMatrix, totalTransform, scale;
+ Particle *c = NULL;
+ ParticleSystem *sys = NULL;
+
+ int num_particles = 0;
+ int i, j;
+
+
+ glEnable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+ glUniform1i(s->Texture, 0);
+
+ for(i = 0; i < particles.num_systems; i++)
+ {
+ sys = particles.systems[i];
+
+ texture_bind(sys->texture, 0);
+ glUniform1f(s->extra0, sys->texture->number_of_rows);
+
+ /* Orphane the buffer */
+ glBindBuffer(GL_ARRAY_BUFFER, render.instance_vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 18 * MAX_PARTICLES_PER_SYSTEM, NULL, GL_STREAM_DRAW);
+
+ if(sys->additive)
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ else
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ for(j = 0; j < sys->num_particles; j++)
+ {
+ c = &sys->particles[j];
+
+ modelTransform = mat4_translate(&c->position);
+ scale = mat4_scale(c->scale, c->scale, c->scale);
+ modelTransform = mat4_mul(&modelTransform, &scale);
+ /*
+ We eliminate the rotation from the view matrix so the particle is always facing the camera,
+ for this we add the transposed matrix from the rotation part of the viewmatrx and put it
+ on the model transform matrix
+ */
+ modelTransform.data[0] = viewMatrix->data[0];
+ modelTransform.data[4] = viewMatrix->data[1];
+ modelTransform.data[8] = viewMatrix->data[2];
+ modelTransform.data[1] = viewMatrix->data[4];
+ modelTransform.data[5] = viewMatrix->data[5];
+ modelTransform.data[9] = viewMatrix->data[6];
+ modelTransform.data[2] = viewMatrix->data[8];
+ modelTransform.data[6] = viewMatrix->data[9];
+ modelTransform.data[10] = viewMatrix->data[10];
+
+ modelViewMatrix = mat4_mul(viewMatrix, &modelTransform);
+ totalTransform = mat4_mul(projectionMatrix, &modelViewMatrix);
+
+ /* Load the texture atlas coods and MVP matrix */
+ glBufferSubData(GL_ARRAY_BUFFER, num_particles * sizeof(GLfloat), sizeof(Vec2), &c->tex_offset);
+ glBufferSubData(GL_ARRAY_BUFFER, (num_particles + 2) * sizeof(GLfloat), sizeof(Mat4), totalTransform.data);
+
+ num_particles += 18;
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glBindVertexArray(render.default_quad->vao);
+ glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, num_particles / 18);
+ }
+
+ glBindVertexArray(0);
+
+ glDepthMask(GL_TRUE);
+ glDisable(GL_BLEND);
+}
+
+void Render_EndFrame()
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glViewport(0, 0, render.window->Width, render.window->Height);
+}
+
+void Render_Shutdown()
+{
+ int i;
+
+ glDeleteTextures(1, &render.shadow_map);
+ glDeleteFramebuffers(1, &render.shadow_fbo);
+
+ glDeleteBuffers(1, &render.instance_vbo);
+
+ /* Destroy all created textures */
+ for(i = 0; i < render.num_textures; i++)
+ {
+ texture_purge( render.textures[i] );
+ free(render.textures[i]);
+ }
+
+ /* Destroy all created models */
+ for(i = 0; i < render.num_models; i++)
+ {
+ model_purge(render.models[i]);
+ free(render.models[i]);
+ }
+
+ for(i = 0; i < render.num_meshes; i++)
+ {
+ mesh_purge(render.meshes[i]);
+ free(render.meshes[i]);
+ }
+
+ /* Destroy all created shaders */
+ for(i = 0; i < render.num_shaders; i++)
+ {
+ shader_purge(render.shaders[i]);
+ free(render.shaders[i]);
+ }
+
+ /* Just for checking */
+ printf("%d textures were deleted!\n", render.num_textures);
+ printf("%d models were deleted!\n", render.num_models);
+ printf("%d shaders were deleted!\n", render.num_shaders);
+ printf("%d meshes were deleted!\n", render.num_meshes);
+
+ /* Clear everything */
+ memset( &render, 0, sizeof(Renderer) );
+}
diff --git a/09-september/tomcat/renderer/renderer.h b/09-september/tomcat/renderer/renderer.h
new file mode 100644
index 0000000..791d65d
--- /dev/null
+++ b/09-september/tomcat/renderer/renderer.h
@@ -0,0 +1,86 @@
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include "../terrain.h"
+#include "../util/array.h"
+#include "vertex.h"
+#include "../particles/particles.h"
+#include "renderer_types.h"
+#include "stdint.h"
+#include "window.h"
+
+#define MAX_STRING_LENGTH 128
+
+#define MAX_TEXTURES 2048
+#define MAX_MODELS 2048
+#define MAX_MESHES 2048
+#define MAX_SHADERS 32
+
+/** Beginning of rendering functions **/
+
+typedef struct _GlInfo
+{
+ char version[MAX_STRING_LENGTH];
+ char shading_version[MAX_STRING_LENGTH];
+ char vendor[MAX_STRING_LENGTH];
+} GlInfo;
+
+typedef struct _Renderer
+{
+ GlInfo info;
+
+ Mesh *default_quad;
+ Shader *default_shader;
+ GLuint instance_vbo;
+
+ Texture *textures[MAX_TEXTURES]; /* All loaded textures */
+ int num_textures;
+
+ Shader *shaders[MAX_SHADERS]; /* All loaded shaders */
+ int num_shaders;
+
+ Model *models[MAX_MODELS]; /* All created shapes */
+ int num_models;
+
+ Mesh *meshes[MAX_MESHES];
+ int num_meshes;
+
+ Window *window;
+
+ GLuint shadow_fbo; /* Frame buffer for shadow mapping */
+ GLuint shadow_map; /* Texture for rendering the shadow map (shadow mapping) */
+ GLuint shadow_color;
+ GLint shadow_width;
+ GLint shadow_height;
+
+ /** TEMP **/
+ Mat4 shadow_mvp;
+ Vec3 inv_light_dir;
+ Shader *shadow_shader;
+
+ /** TEMP **/
+} Renderer;
+extern Renderer render;
+
+extern void Render_Init(Window *window);
+
+extern void Render_BeginFrame();
+
+/* Load lights into the current shader program */
+extern void Render_LoadLights(Shader *shader, const Light *lights, int n);
+
+extern void Render_DrawEntity(Shader *shader, Mat4 *projectedViewMatrix, Entity *entity);
+extern void Render_DrawTerrain(Shader *shader, Mat4 *projectedViewMatrix, Terrain *terrain);
+extern void Render_DrawSky(Shader *shader, Mat4 *viewMatrix, Mat4 *projectionMatrix, Skybox *sky);
+extern void Render_DrawParticles(Shader *shader, Mat4 *viewMatrix, Mat4 *projectionMatrix);
+
+extern void Render_EndFrame();
+
+extern void Render_Shutdown();
+
+extern Mat4 Entity_GetModelTransform(Entity* entity);
+extern Vec2 Entity_GetTexOffset(Entity *entity);
+
+/** End of rendering functions **/
+
+#endif // RENDERER_H
diff --git a/09-september/tomcat/renderer/renderer_types.h b/09-september/tomcat/renderer/renderer_types.h
new file mode 100644
index 0000000..cd07a20
--- /dev/null
+++ b/09-september/tomcat/renderer/renderer_types.h
@@ -0,0 +1,47 @@
+#ifndef RENDERER_TYPES_H
+#define RENDERER_TYPES_H
+
+#define SKYBOX_ROTATION_SPEED 1.0f
+
+#include "../util/str.h"
+#include "../util/array.h"
+
+#include "../math/vector.h"
+#include "../math/matrix4x4.h"
+
+#include "shader.h"
+#include "texture.h"
+#include "model.h"
+
+typedef struct _Material
+{
+ Texture *normal_map;
+ GLfloat shine_damper;
+ GLfloat reflectivity;
+} Material;
+
+typedef struct
+{
+ Texture *texture;
+ Mesh *cube;
+ GLfloat rotation;
+} Skybox;
+
+typedef struct _Entity
+{
+ Model *model;
+ Texture *texture;
+ Vec3 position;
+ float rotX, rotY, rotZ;
+ int index; /* Index inside a texture atlas should default to 0 */
+ float scale[3];
+} Entity;
+
+typedef struct
+{
+ Vec3 position;
+ Vec4 color;
+ Vec3 attenuation;
+} Light;
+
+#endif // RENDERER_TYPES_H
diff --git a/09-september/tomcat/renderer/shader.c b/09-september/tomcat/renderer/shader.c
new file mode 100644
index 0000000..3f6a5d7
--- /dev/null
+++ b/09-september/tomcat/renderer/shader.c
@@ -0,0 +1,187 @@
+#include "renderer.h"
+#include "../util/util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_HASH_SHADER 16
+static Shader *shader_hash_table[MAX_HASH_SHADER];
+
+static void CompileShader(const char *source, GLuint shaderID)
+{
+ glShaderSource(shaderID, 1, &source, 0);
+ glCompileShader(shaderID);
+ GLint error;
+ glGetShaderiv(shaderID, GL_COMPILE_STATUS, &error);
+ if(error != GL_TRUE)
+ {
+ GLint logLenth;
+ glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLenth);
+ GLchar buffer[logLenth];
+ glGetShaderInfoLog(shaderID, logLenth, &logLenth, buffer);
+ glDeleteShader(shaderID);
+ Util_FatalError("Some shader failed to compile:\n%s", buffer);
+ }
+}
+
+Shader *shader_new(const char *name, const char *vertexShaderPath, const char *fragShaderPath)
+{
+ if(strlen(name) >= MAX_PATH_LENGTH)
+ Util_FatalError("File following shader name is too long: %s", name);
+
+ Shader *s;
+ s = shader_get(name);
+ if(s != NULL)
+ return s;
+
+ char *vertexShaderSource = Util_LoadFile(vertexShaderPath);
+ char *fragmentShaderSource = Util_LoadFile(fragShaderPath);
+
+ GLuint vs = 0, fs = 0, program;
+ vs = glCreateShader(GL_VERTEX_SHADER);
+ fs = glCreateShader(GL_FRAGMENT_SHADER);
+
+ if(vs == 0 || fs == 0)
+ Util_FatalError("Shaders could not be created\n");
+
+ program = glCreateProgram();
+
+ CompileShader(vertexShaderSource, vs);
+ CompileShader(fragmentShaderSource, fs);
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+
+ glLinkProgram(program);
+
+ GLint error;
+ glGetProgramiv(program, GL_LINK_STATUS, &error);
+
+ if(error != GL_TRUE)
+ {
+ GLint logLength;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
+
+ GLchar buffer[logLength];
+ glGetProgramInfoLog(program, logLength, &logLength, buffer);
+
+ glDeleteProgram(program);
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+
+ Util_FatalError("Shader program failed to link!:\n%s", buffer);
+ }
+ /** Free some usless resources **/
+ glDetachShader(program, vs);
+ glDetachShader(program, fs);
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+
+ free(vertexShaderSource);
+ free(fragmentShaderSource);
+
+ /** Alloc the new texture **/
+ s = malloc( sizeof(Shader) );
+ memset(s, 0, sizeof(Shader) );
+ s->id = program;
+
+ /** Register inside the resource manager **/
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_SHADER;
+
+ render.shaders[render.num_shaders] = s;
+ render.num_shaders += 1;
+
+ strcpy(s->name, name);
+ s->_hash_next = shader_hash_table[hash_];
+ shader_hash_table[hash_] = s;
+
+ s->_hash = hash_;
+
+ /** Return the final result **/
+ return s;
+}
+
+Shader *shader_get(const char *name)
+{
+ Shader *s;
+
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_SHADER;
+
+ if(shader_hash_table[hash_] != NULL)
+ {
+ for(s = shader_hash_table[hash_]; s; s = s->_hash_next)
+ {
+ if( s->_hash == hash_ )
+ return s;
+ }
+ }
+ return NULL;
+}
+
+void shader_purge(Shader *shader)
+{
+ /** Purge the opengl data **/
+ if(shader->id != 0)
+ {
+ glUseProgram(0);
+ glDeleteProgram(shader->id);
+ shader->id = 0;
+ }
+}
+
+GLint shader_get_uniform_location( Shader *s, const char *uniformName )
+{
+ GLint u = glGetUniformLocation(s->id, uniformName);
+ if(u == GL_INVALID_INDEX)
+ Util_FatalError("Uniform \"%s\" could not be found!", uniformName);
+ else
+ return u;
+
+ return 0;
+}
+
+GLint shader_get_attrib_location( Shader *s, const char *attributeName )
+{
+ GLint attrLocation = glGetAttribLocation(s->id, attributeName);
+ if(attrLocation < 0)
+ Util_FatalError("Attribute \"%s\" could not be found!\n", attributeName);
+ return attrLocation;
+}
+
+void shader_set_uniform_mat4( Shader *s, const char *name, const float matrix[16] )
+{
+ GLint location = shader_get_uniform_location(s, name);
+ glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
+}
+
+void shader_set_uniform_float( Shader *s, const char *name, const float val )
+{
+ GLint location = shader_get_uniform_location(s, name);
+ glUniform1f(location, val);
+}
+
+void shader_set_uniform_vec2( Shader *s, const char *name, const float vec[2] )
+{
+ GLint location = shader_get_uniform_location(s, name);
+ glUniform2fv(location, 1, vec);
+}
+
+void shader_set_uniform_vec3( Shader *s, const char *name, const float vec[3] )
+{
+ GLint location = shader_get_uniform_location(s, name);
+ glUniform3fv(location, 1, vec);
+}
+
+void shader_set_uniform_vec4( Shader *s, const char *name, const float vec[4] )
+{
+ GLint location = shader_get_uniform_location(s, name);
+ glUniform4fv(location, 1, vec);
+}
+
+void shader_set_uniform_int( Shader *s, const char *name, const int val )
+{
+ GLint location = shader_get_uniform_location(s, name);
+ glUniform1i(location, val);
+}
diff --git a/09-september/tomcat/renderer/shader.h b/09-september/tomcat/renderer/shader.h
new file mode 100644
index 0000000..e4889f3
--- /dev/null
+++ b/09-september/tomcat/renderer/shader.h
@@ -0,0 +1,59 @@
+#ifndef SHADER_H
+#define SHADER_H
+
+#include "../shared.h"
+
+typedef struct _Shader
+{
+ GLuint id;
+ char name[MAX_PATH_LENGTH];
+
+ /* Layout */
+
+ /* Program Attributes */
+ GLint position;
+ GLint uv;
+ GLint normal;
+ GLint tangent;
+
+ /* Program Uniforms */
+ GLint totalTransform;
+ GLint modelToWorld;
+ GLint lightPosition;
+ GLint ambientLight;
+ GLint lightColor;
+ GLint lightAttenuation;
+ GLint World_eyePosition;
+ GLint Texture;
+ GLint Normal_Map;
+
+ /* Program Multi Purpose Uniforms */
+ GLint extra0;
+ GLint extra1;
+ GLint extra2;
+ GLint extra3;
+ GLint extra4;
+ GLint extra5;
+
+ struct _Shader *_hash_next;
+ unsigned int _hash;
+} Shader;
+
+/** Shaders **/
+extern Shader *shader_new(const char *name, const char *vertexShaderPath, const char *fragShaderPath);
+extern Shader *shader_get(const char *name);
+extern void shader_purge(Shader *shader);
+/** **/
+
+/** Shader functions **/
+extern GLint shader_get_uniform_location( Shader *s, const char *uniformName );
+extern GLint shader_get_attrib_location( Shader *s, const char *attributeName );
+extern void shader_set_uniform_mat4( Shader *s, const char *name, const float matrix[16] );
+extern void shader_set_uniform_float( Shader *s, const char *name, const float val );
+extern void shader_set_uniform_vec2( Shader *s, const char *name, const float vec[2] );
+extern void shader_set_uniform_vec3( Shader *s, const char *name, const float vec[3] );
+extern void shader_set_uniform_vec4( Shader *s, const char *name, const float vec[4] );
+extern void shader_set_uniform_int( Shader *s, const char *name, const int val );
+/** **/
+
+#endif // SHADER_H
diff --git a/09-september/tomcat/renderer/texture.c b/09-september/tomcat/renderer/texture.c
new file mode 100644
index 0000000..e653c5a
--- /dev/null
+++ b/09-september/tomcat/renderer/texture.c
@@ -0,0 +1,188 @@
+#include "../util/util.h"
+#include "renderer.h"
+#include "texture.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+
+#define MAX_HASH_TEXTURES 1024
+static Texture *texture_hash_table[MAX_HASH_TEXTURES];
+
+Texture *texture_new(const char *path)
+{
+ return texture_with_name_new(path, path);
+}
+
+Texture *texture_with_name_new(const char *name, const char *path)
+{
+ if(strlen(name) > MAX_PATH_LENGTH)
+ Util_FatalError("File following texture name is too long: %s", name);
+
+ Texture *tex;
+ tex = texture_get(name);
+
+ if(tex != NULL)
+ return tex;
+
+ if(render.num_textures >= MAX_TEXTURES)
+ return NULL;
+
+ /** Alloc the new texture **/
+ tex = malloc( sizeof(Texture) );
+ memset(tex, 0, sizeof(Texture) );
+ tex->number_of_rows = 1;
+ tex->type = GL_TEXTURE_2D;
+
+ SDL_Surface *data = IMG_Load(path);
+
+ if(data == NULL)
+ Util_FatalError("Texture %s could not be found!\n", path);
+
+ glGenTextures(1, &tex->tex_id);
+ glBindTexture(GL_TEXTURE_2D, tex->tex_id);
+
+ SDL_LockSurface(data);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->w, data->h, GL_FALSE, GL_RGBA, GL_UNSIGNED_BYTE, data->pixels);
+ SDL_UnlockSurface(data);
+ SDL_FreeSurface(data);
+
+ /** Configure the texture **/
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.4);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ /** Register inside the resource manager **/
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_TEXTURES;
+
+ render.textures[render.num_textures] = tex;
+ render.num_textures += 1;
+
+ strcpy(tex->_name, name);
+ tex->_hash_next = texture_hash_table[hash_];
+ texture_hash_table[hash_] = tex;
+
+ tex->hash_ = hash_;
+
+ /** Return the final result **/
+ return tex;
+}
+
+Texture *texture_cubemap_new(const char *paths[6])
+{
+ return texture_cubemap_with_name_new(paths[0], paths);
+}
+
+Texture *texture_cubemap_with_name_new(const char *name, const char *paths[6])
+{
+ Texture *tex;
+ tex = texture_get(name);
+
+ if(tex != NULL)
+ {
+ puts("s");
+ return tex;
+ }
+
+ if(render.num_textures >= MAX_TEXTURES)
+ return NULL;
+
+ /** Alloc the new texture **/
+ tex = malloc( sizeof(Texture) );
+ memset(tex, 0, sizeof(Texture) );
+ tex->number_of_rows = 1;
+ tex->type = GL_TEXTURE_CUBE_MAP;
+
+ glGenTextures(1, &tex->tex_id);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, tex->tex_id);
+
+ SDL_Surface *data;
+
+ int i;
+ for(i = 0; i < 6; i++)
+ {
+ data = IMG_Load(paths[i]);
+
+ if(data == NULL)
+ Util_FatalError("Texture %s could not be found!\n", paths[i]);
+
+ SDL_LockSurface(data);
+ /** All the textures sides are linearly stored so we just add "i" **/
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA,
+ data->w, data->h, GL_FALSE, GL_RGBA, GL_UNSIGNED_BYTE, data->pixels);
+
+ SDL_UnlockSurface(data);
+ SDL_FreeSurface(data);
+ }
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+
+ /** Register inside the resource manager **/
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_TEXTURES;
+
+ render.textures[render.num_textures] = tex;
+ render.num_textures += 1;
+
+ strcpy(tex->_name, name);
+ tex->_hash_next = texture_hash_table[hash_];
+ texture_hash_table[hash_] = tex;
+
+ tex->hash_ = hash_;
+
+ /** Return the final result **/
+ return tex;
+}
+
+Texture *texture_get(const char *name)
+{
+ Texture *tex;
+
+ unsigned int hash_ = Util_Hash( name );
+ hash_ %= MAX_HASH_TEXTURES;
+
+ if(texture_hash_table[hash_] != NULL)
+ {
+ for(tex = texture_hash_table[hash_]; tex; tex = tex->_hash_next)
+ {
+ if( tex->hash_ == hash_ )
+ return tex;
+ }
+ }
+ return NULL;
+}
+
+void texture_bind(Texture *tex, int slot)
+{
+ glActiveTexture(GL_TEXTURE0 + slot);
+
+ if(tex->type != GL_TEXTURE_2D && tex->type != GL_TEXTURE_CUBE_MAP)
+ return;
+
+
+ glBindTexture(tex->type, tex->tex_id);
+}
+
+void texture_purge(Texture *tex)
+{
+ /** Purge the opengl data **/
+ if(tex->tex_id != 0)
+ {
+ glDeleteTextures(1, &tex->tex_id);
+ tex->tex_id = 0;
+ }
+}
diff --git a/09-september/tomcat/renderer/texture.h b/09-september/tomcat/renderer/texture.h
new file mode 100644
index 0000000..8288c72
--- /dev/null
+++ b/09-september/tomcat/renderer/texture.h
@@ -0,0 +1,30 @@
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+#include "../shared.h"
+
+typedef struct _Texture
+{
+ GLuint tex_id;
+ GLenum type;
+
+ int number_of_rows; /* used for texture atlases */
+
+ char _name[MAX_PATH_LENGTH];
+ unsigned int hash_;
+ struct _Texture *_hash_next; /* linked list for storing on hash table */
+
+} Texture;
+
+extern Texture *texture_new(const char *name);
+extern Texture *texture_with_name_new(const char *name, const char *path);
+
+extern Texture *texture_cubemap_new(const char *paths[6]);
+extern Texture *texture_cubemap_with_name_new(const char *name, const char *paths[6]);
+
+extern Texture *texture_get(const char *name);
+extern void texture_bind(Texture *tex, int slot);
+
+extern void texture_purge(Texture *tex); /* Clean the texture without freeing the container */
+
+#endif // TEXTURE_H
diff --git a/09-september/tomcat/renderer/vertex.h b/09-september/tomcat/renderer/vertex.h
new file mode 100644
index 0000000..6a79dde
--- /dev/null
+++ b/09-september/tomcat/renderer/vertex.h
@@ -0,0 +1,15 @@
+#ifndef VERTEX_H
+#define VERTEX_H
+
+#include <GL/glew.h>
+#include "../math/vector.h"
+
+typedef struct
+{
+ Vec3 position;
+ Vec2 texCoord;
+ Vec3 normal;
+ Vec3 tangent;
+} vertex_t;
+
+#endif // VERTEX_H
diff --git a/09-september/tomcat/renderer/window.c b/09-september/tomcat/renderer/window.c
new file mode 100644
index 0000000..d5db1eb
--- /dev/null
+++ b/09-september/tomcat/renderer/window.c
@@ -0,0 +1,49 @@
+#include "window.h"
+#include "../util/util.h"
+#include <stdlib.h>
+
+Window* window_new(const char* title, Uint32 width, Uint32 height)
+{
+ Window* window = malloc(sizeof(Window));
+ window->title = title;
+ window->Width = width;
+ window->Height = height;
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+
+ window->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ width, height, SDL_WINDOW_OPENGL);
+ if(window->window == NULL)
+ Util_FatalError( "The window could not be created:\n%s", SDL_GetError() );
+
+ window->context = SDL_GL_CreateContext(window->window);
+
+ if(window->context == NULL)
+ Util_FatalError( "Context could not be created:\n%s", SDL_GetError() );
+
+ glViewport(0, 0, width, height);
+
+ return window;
+}
+
+void window_resize(Window* window, Uint32 width, Uint32 height)
+{
+ window->Width = width;
+ window->Height = height;
+ SDL_SetWindowSize(window->window, width, height);
+ glViewport(0, 0, width, height);
+}
+
+void window_update(Window* window)
+{
+ SDL_GL_SwapWindow(window->window);
+}
+
+void window_destroy(Window* window)
+{
+ SDL_GL_DeleteContext(window->context);
+ SDL_DestroyWindow(window->window);
+ free(window);
+}
diff --git a/09-september/tomcat/renderer/window.h b/09-september/tomcat/renderer/window.h
new file mode 100644
index 0000000..608937a
--- /dev/null
+++ b/09-september/tomcat/renderer/window.h
@@ -0,0 +1,20 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <SDL2/SDL.h>
+#include <GL/glew.h>
+
+typedef struct
+{
+ SDL_Window* window;
+ SDL_GLContext context;
+ Uint32 Width, Height;
+ const char* title;
+} Window;
+
+extern Window* window_new(const char* title, Uint32 width, Uint32 height);
+extern void window_resize(Window* window, Uint32 width, Uint32 height);
+extern void window_update(Window* window);
+extern void window_destroy(Window* window);
+
+#endif // WINDOW_H