aboutsummaryrefslogtreecommitdiff
path: root/08-august/src/renderer/shape.c
diff options
context:
space:
mode:
Diffstat (limited to '08-august/src/renderer/shape.c')
-rw-r--r--08-august/src/renderer/shape.c335
1 files changed, 335 insertions, 0 deletions
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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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,
+ &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;
+}
+
+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, &current_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);
+ }
+}