From 6b8af9cf83851c075c6c9514b1deaa931c2b19a4 Mon Sep 17 00:00:00 2001 From: Thomas Guillermo Albers Raviola Date: Fri, 16 Jan 2026 23:02:32 +0100 Subject: Initial commit --- 09-september/tomcat/renderer/camera.c | 95 ++++++ 09-september/tomcat/renderer/camera.h | 32 ++ 09-september/tomcat/renderer/entity.c | 33 ++ 09-september/tomcat/renderer/mesh.c | 146 +++++++++ 09-september/tomcat/renderer/mesh.h | 22 ++ 09-september/tomcat/renderer/model.c | 314 +++++++++++++++++++ 09-september/tomcat/renderer/model.h | 21 ++ 09-september/tomcat/renderer/renderer.c | 430 ++++++++++++++++++++++++++ 09-september/tomcat/renderer/renderer.h | 86 ++++++ 09-september/tomcat/renderer/renderer_types.h | 47 +++ 09-september/tomcat/renderer/shader.c | 187 +++++++++++ 09-september/tomcat/renderer/shader.h | 59 ++++ 09-september/tomcat/renderer/texture.c | 188 +++++++++++ 09-september/tomcat/renderer/texture.h | 30 ++ 09-september/tomcat/renderer/vertex.h | 15 + 09-september/tomcat/renderer/window.c | 49 +++ 09-september/tomcat/renderer/window.h | 20 ++ 17 files changed, 1774 insertions(+) create mode 100644 09-september/tomcat/renderer/camera.c create mode 100644 09-september/tomcat/renderer/camera.h create mode 100644 09-september/tomcat/renderer/entity.c create mode 100644 09-september/tomcat/renderer/mesh.c create mode 100644 09-september/tomcat/renderer/mesh.h create mode 100644 09-september/tomcat/renderer/model.c create mode 100644 09-september/tomcat/renderer/model.h create mode 100644 09-september/tomcat/renderer/renderer.c create mode 100644 09-september/tomcat/renderer/renderer.h create mode 100644 09-september/tomcat/renderer/renderer_types.h create mode 100644 09-september/tomcat/renderer/shader.c create mode 100644 09-september/tomcat/renderer/shader.h create mode 100644 09-september/tomcat/renderer/texture.c create mode 100644 09-september/tomcat/renderer/texture.h create mode 100644 09-september/tomcat/renderer/vertex.h create mode 100644 09-september/tomcat/renderer/window.c create mode 100644 09-september/tomcat/renderer/window.h (limited to '09-september/tomcat/renderer') 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 + +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 +#include +#include + +#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 +#include +#include + +#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, + ¤t_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", ¤t_texture.x, ¤t_texture.y); + + array_append(textures, ¤t_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", ¤t_normal.x, + ¤t_normal.y, + ¤t_normal.z); + array_append(normals, ¤t_normal); + + if(count != 3) + Util_FatalError("Bad normals data on .obj file"); + } + else + { + count = sscanf(buffer, "v %f %f %f\n", ¤t_position.x, + ¤t_position.y, + ¤t_position.z); + + array_append(positions, ¤t_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, ¤t_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 + +#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, ¢er, &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 +#include + +#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 +#include +#include +#include +#include + +#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 +#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 + +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 +#include + +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 -- cgit v1.2.3