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 --- 08-august/src/renderer/entity.c | 18 ++ 08-august/src/renderer/entity.h | 20 +++ 08-august/src/renderer/renderer.c | 147 +++++++++++++++++ 08-august/src/renderer/renderer.h | 18 ++ 08-august/src/renderer/shape.c | 335 ++++++++++++++++++++++++++++++++++++++ 08-august/src/renderer/shape.h | 26 +++ 08-august/src/renderer/skybox.h | 16 ++ 7 files changed, 580 insertions(+) create mode 100644 08-august/src/renderer/entity.c create mode 100644 08-august/src/renderer/entity.h create mode 100644 08-august/src/renderer/renderer.c create mode 100644 08-august/src/renderer/renderer.h create mode 100644 08-august/src/renderer/shape.c create mode 100644 08-august/src/renderer/shape.h create mode 100644 08-august/src/renderer/skybox.h (limited to '08-august/src/renderer') diff --git a/08-august/src/renderer/entity.c b/08-august/src/renderer/entity.c new file mode 100644 index 0000000..b96491d --- /dev/null +++ b/08-august/src/renderer/entity.c @@ -0,0 +1,18 @@ +#include "entity.h" + +mat4_t Entity_GetModelTransform(entity_t* entity) +{ + mat4_t temp; + mat4_t 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_t modelTransform = mat4_mul(&temp, &rotation); + + return modelTransform; +} + diff --git a/08-august/src/renderer/entity.h b/08-august/src/renderer/entity.h new file mode 100644 index 0000000..ba33004 --- /dev/null +++ b/08-august/src/renderer/entity.h @@ -0,0 +1,20 @@ +#ifndef ENTITY_H +#define ENTITY_H + +#include "../math/vector3f.h" +#include "../math/matrix4x4.h" + +#include "shape.h" +#include "../texture.h" + +typedef struct +{ + shape_t *shape; + GLuint texture; + vec3_t position; + float rotX, rotY, rotZ; +} entity_t; + +extern mat4_t Entity_GetModelTransform(entity_t* entity); + +#endif // ENTITY_H diff --git a/08-august/src/renderer/renderer.c b/08-august/src/renderer/renderer.c new file mode 100644 index 0000000..2ea4426 --- /dev/null +++ b/08-august/src/renderer/renderer.c @@ -0,0 +1,147 @@ +#include "renderer.h" +#include "../util/util_time.h" + +#include + +#define MAX_LIGHTS 4 + +void Render_Init() +{ + +} + +void Render_LoadLights(Shader_Layout *layout, const light_t *lights, int n) +{ + vec3_t light_positions[MAX_LIGHTS]; + vec4_t light_colors[MAX_LIGHTS]; + vec3_t attenuation[MAX_LIGHTS]; + + /* Default light in case we are not given enough lights (n < 4) */ + const light_t defaultLight = { {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f} }; + + int i; + for(i = 0; i < MAX_LIGHTS; i++) + { + if(i < MAX_LIGHTS) + { + 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(layout->lightPosition, MAX_LIGHTS, (float*)light_positions); + glUniform4fv(layout->lightColor, MAX_LIGHTS, (float*)light_colors); + glUniform3fv(layout->lightAttenuation, MAX_LIGHTS, (float*)attenuation); + +} + +void Render_DrawEntity(Shader_Layout *layout, mat4_t *projectedViewMatrix, entity_t *entity) +{ + glBindVertexArray(entity->shape->vao); + + /*We need the model to world matrix in our shader in order to rotate the normals*/ + mat4_t modelTransform = Entity_GetModelTransform(entity); + glUniformMatrix4fv(layout->modelToWorld, 1, GL_FALSE, modelTransform.data); + + mat4_t totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform); + glUniformMatrix4fv(layout->totalTransform, 1, GL_FALSE, totalMatrix.data); + + glActiveTexture(GL_TEXTURE0); + glUniform1i(layout->Texture, 0); + glBindTexture(GL_TEXTURE_2D, entity->texture); + + glDrawElements(GL_TRIANGLES, entity->shape->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_Layout *layout, mat4_t *projectedViewMatrix, terrain_t *terrain) +{ + glBindVertexArray(terrain->shape->vao); + + /* We need the model to world matrix in our shader in order to rotate the normals */ + mat4_t modelTransform = mat4_translate(&terrain->position); + glUniformMatrix4fv(layout->modelToWorld, 1, GL_FALSE, modelTransform.data); + + mat4_t totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform); + glUniformMatrix4fv(layout->totalTransform, 1, GL_FALSE, totalMatrix.data); + + /** Set textures for the terrain **/ + + glUniform1i(layout->extra0, 0); + glUniform1i(layout->extra1, 1); + glUniform1i(layout->extra2, 2); + glUniform1i(layout->extra3, 3); + glUniform1i(layout->extra4, 4); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, terrain->textures.texture[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, terrain->textures.texture[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, terrain->textures.texture[2]); + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, terrain->textures.texture[3]); + glActiveTexture(GL_TEXTURE4); + glBindTexture(GL_TEXTURE_2D, terrain->blendmap); + + /************************************************************/ + + glDrawElements(GL_TRIANGLES, terrain->shape->num_indices, GL_UNSIGNED_SHORT, NULL); + + glBindVertexArray(0); +} + +void Render_DrawSky(Shader_Layout *layout, mat4_t *viewMatrix, mat4_t *projectionMatrix, skybox_t *sky) +{ + glBindVertexArray(sky->cube->vao); + + mat4_t myViewMatrix = *viewMatrix; + sky->rotation += SKYBOX_ROTATION_SPEED * Time_GetFrameTime(); + mat4_t rotateMatrix = mat4_rotate_y(sky->rotation); + + /* 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); + mat4_t totalTransform = mat4_mul(projectionMatrix, &myViewMatrix); + + glUniformMatrix4fv(layout->totalTransform, 1, GL_FALSE, totalTransform.data ); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, sky->texture); + glUniform1i(layout->Texture, 0); + + glDrawArrays(GL_TRIANGLES, 0, 36); + + glBindVertexArray(0); +} + +void Render_Quit() +{ + +} diff --git a/08-august/src/renderer/renderer.h b/08-august/src/renderer/renderer.h new file mode 100644 index 0000000..b6f4f76 --- /dev/null +++ b/08-august/src/renderer/renderer.h @@ -0,0 +1,18 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include "../graphics/shaders.h" +#include "entity.h" +#include "skybox.h" +#include "../terrain.h" +#include "../light.h" + +extern void Render_Init(); +/* Load lights into the shader program */ +extern void Render_LoadLights(Shader_Layout *layout, const light_t *lights, int n); +extern void Render_DrawEntity(Shader_Layout *layout, mat4_t *projectedViewMatrix, entity_t *entity); +extern void Render_DrawTerrain(Shader_Layout *layout, mat4_t *projectedViewMatrix, terrain_t *terrain); +extern void Render_DrawSky(Shader_Layout *layout, mat4_t *viewMatrix, mat4_t *projectionMatrix, skybox_t *sky); +extern void Render_Quit(); + +#endif // RENDERER_H diff --git a/08-august/src/renderer/shape.c b/08-august/src/renderer/shape.c new file mode 100644 index 0000000..7f274df --- /dev/null +++ b/08-august/src/renderer/shape.c @@ -0,0 +1,335 @@ +#include "shape.h" +#include +#include +#include +#include "../util/util.h" + +#define NUM_ARRAY_ELEMENTS(a) sizeof(a) / sizeof(*a) + +shape_t *Shape_CreateFromRawData(vertex_t* vertices, GLsizeiptr vertexBuffersize, + GLushort* indices, GLsizeiptr indexBuffersize) +{ + shape_t *shape = malloc( sizeof(shape_t) ); + + shape->num_indices = ( indexBuffersize / sizeof(GLushort) ); + + glGenVertexArrays(1, &shape->vao); + glGenBuffers(1, &shape->vbo); + glGenBuffers(1, &shape->ebo); + + glBindVertexArray(shape->vao); + + glBindBuffer(GL_ARRAY_BUFFER, shape->vbo); + glBufferData(GL_ARRAY_BUFFER, vertexBuffersize, vertices, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, shape->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 shape; +} + +shape_t* Shape_MakeSkyBox(float size) +{ + vec3_t 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} + }; + + shape_t *shape = malloc( sizeof(shape_t) ); + + shape->num_indices = 0; + + glGenVertexArrays(1, &shape->vao); + glGenBuffers(1, &shape->vbo); + shape->ebo = 0; + + glBindVertexArray(shape->vao); + + glBindBuffer(GL_ARRAY_BUFFER, shape->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 shape; +} + +static const int BUFFER_size = 128; + +typedef struct +{ + vertex_t *data; + GLushort *indices; + + vec3_t *positions; + vec2_t *textures; + vec3_t *normals; + vec3_t *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_t *v0 = &mesh->positions[i0]; + vec3_t *v1 = &mesh->positions[i1]; + vec3_t *v2 = &mesh->positions[i2]; + + vec2_t *uv0 = &mesh->textures[i0]; + vec2_t *uv1 = &mesh->textures[i1]; + vec2_t *uv2 = &mesh->textures[i2]; + + vec3_t deltaPos1 = vec3_sub(v1, v0); + vec3_t deltaPos2 = vec3_sub(v2, v0); + + vec2_t deltaUV1 = vec2_sub(uv1, uv0); + vec2_t 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_t tangent = vec3_sub(&deltaPos1, &deltaPos2); + tangent = vec3_scalar_mul(&tangent, r); + + mesh->tangents[i2] = tangent; + mesh->tangents[i1] = tangent; + mesh->tangents[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; +} + +shape_t* Shape_LoadOBJ(const char* path) +{ + OBJ_Mesh mesh; + memset( &mesh, 0, sizeof(OBJ_Mesh) ); + + vec3_t *positions = NULL; + vec3_t *normals = NULL; + vec2_t *textures = NULL; + + vertex_t current_vertex; + + unsigned int positions_count = 0, normals_count = 0, textures_count = 0; + + 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') + { + textures = (vec2_t*) realloc(textures, sizeof(vec2_t) * (++textures_count) ); + count = sscanf(buffer, "vt %f %f\n", &textures[textures_count - 1].x, + &textures[textures_count - 1].y); + + if(count != 2) + Util_FatalError("Bad texture coordinates on .obj file"); + } + else if(buffer[1] == 'n') + { + normals = (vec3_t*) realloc(normals, sizeof(vec3_t) * (++normals_count) ); + count = sscanf(buffer, "vn %f %f %f\n", &normals[normals_count - 1].x, + &normals[normals_count - 1].y, &normals[normals_count - 1].z); + + if(count != 3) + Util_FatalError("Bad normals data on .obj file"); + } + else + { + positions = (vec3_t*) realloc(positions, sizeof(vec3_t) * (++positions_count) ); + count = sscanf(buffer, "v %f %f %f\n", &positions[positions_count - 1].x, + &positions[positions_count - 1].y, &positions[positions_count - 1].z); + + if(count != 3) + Util_FatalError("Bad vertices data on .obj file"); + } + break; + case 'f': + mesh.index_count += 3; + + mesh.positions = realloc(mesh.positions, mesh.index_count * sizeof(vec3_t) ); + mesh.textures = realloc(mesh.textures, mesh.index_count * sizeof(vec2_t) ); + mesh.normals = realloc(mesh.normals, mesh.index_count * sizeof(vec3_t) ); + + 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"); + + mesh.positions[mesh.index_count - 3] = positions[ verts[0] - 1 ]; + mesh.textures[mesh.index_count - 3] = textures[ texture[0] - 1 ]; + mesh.normals[mesh.index_count - 3] = normals[ normal[0] - 1 ]; + + mesh.positions[mesh.index_count - 2] = positions[ verts[1] - 1 ]; + mesh.textures[mesh.index_count - 2] = textures[ texture[1] - 1 ]; + mesh.normals[mesh.index_count - 2] = normals[ normal[1] - 1 ]; + + mesh.positions[mesh.index_count - 1] = positions[ verts[2] - 1 ]; + mesh.textures[mesh.index_count - 1] = textures[ texture[2] - 1 ]; + mesh.normals[mesh.index_count - 1] = normals[ normal[2] - 1 ]; + + break; + default: + break; + } + } + + mesh.indices = malloc( mesh.index_count * sizeof(GLushort) ); + mesh.tangents = malloc( mesh.index_count * sizeof(vec3_t) ); + calculate_tangents(&mesh); + + for(i = 0; i < mesh.index_count; i++) + { + current_vertex = (vertex_t){.position = mesh.positions[i], .texCoord = mesh.textures[i], + .normal = mesh.normals[i], .tangent = mesh.tangents[i] }; + parse_obj_index(&mesh, ¤t_vertex); + } + + for(i = 0; i < mesh.vertex_count; i++) + { + mesh.data[i].tangent = vec3_normalize(&mesh.data[i].tangent); + } + + free(mesh.positions); + free(mesh.normals); + free(mesh.textures); + free(mesh.tangents); + + free(positions); + free(textures); + free(normals); + + fclose(file); + + GLsizeiptr vertexBuffersize = mesh.vertex_count * sizeof(vertex_t); + GLsizeiptr indexBuffersize = mesh.index_count * sizeof(GLushort); + + shape_t* shape = Shape_CreateFromRawData(mesh.data, vertexBuffersize, mesh.indices, indexBuffersize); + + free(mesh.data); + free(mesh.indices); + + return shape; +} + +void Shape_Free(shape_t* shape) +{ + if(shape) + { + if(shape->vbo) + glDeleteBuffers(1, &shape->vbo); + if(shape->ebo) + glDeleteBuffers(1, &shape->ebo); + if(shape->vao) + glDeleteVertexArrays(1, &shape->vao); + free(shape); + } +} diff --git a/08-august/src/renderer/shape.h b/08-august/src/renderer/shape.h new file mode 100644 index 0000000..8942548 --- /dev/null +++ b/08-august/src/renderer/shape.h @@ -0,0 +1,26 @@ +#ifndef SHAPE_H +#define SHAPE_H + +#include "../vertex.h" + +typedef struct +{ + GLuint num_indices; + GLuint vbo, ebo, vao; +} shape_t; + +extern shape_t* Shape_MakeCube(); +extern shape_t* Shape_MakeArrow(); +extern shape_t* Shape_MakeQuad(); +extern shape_t* Shape_MakeSkyBox(float size); + +extern shape_t* Shape_LoadOBJ(const char* path); + +extern shape_t* Shape_CreateFromRawData(vertex_t* vertices, GLsizeiptr vertexBufferSize, + GLushort* indices, GLsizeiptr indexBufferSize); + +extern void Shape_Free(shape_t* shape); + + + +#endif // SHAPE_H diff --git a/08-august/src/renderer/skybox.h b/08-august/src/renderer/skybox.h new file mode 100644 index 0000000..235ee1a --- /dev/null +++ b/08-august/src/renderer/skybox.h @@ -0,0 +1,16 @@ +#ifndef SKYBOX_H +#define SKYBOX_H + +#include +#include "shape.h" + +#define SKYBOX_ROTATION_SPEED 1.0f + +typedef struct +{ + GLuint texture; + shape_t *cube; + GLfloat rotation; +} skybox_t; + +#endif // SKYBOX_H -- cgit v1.2.3