aboutsummaryrefslogtreecommitdiff
path: root/08-august/src/renderer
diff options
context:
space:
mode:
authorThomas Guillermo Albers Raviola <thomas@thomaslabs.org>2026-01-16 23:02:32 +0100
committerThomas Guillermo Albers Raviola <thomas@thomaslabs.org>2026-01-16 23:02:32 +0100
commit6b8af9cf83851c075c6c9514b1deaa931c2b19a4 (patch)
tree428986b49c32e21d3f7a3c2dfa41858ae0153209 /08-august/src/renderer
Initial commit
Diffstat (limited to '08-august/src/renderer')
-rw-r--r--08-august/src/renderer/entity.c18
-rw-r--r--08-august/src/renderer/entity.h20
-rw-r--r--08-august/src/renderer/renderer.c147
-rw-r--r--08-august/src/renderer/renderer.h18
-rw-r--r--08-august/src/renderer/shape.c335
-rw-r--r--08-august/src/renderer/shape.h26
-rw-r--r--08-august/src/renderer/skybox.h16
7 files changed, 580 insertions, 0 deletions
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 <string.h>
+
+#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 <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);
+ }
+}
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 <GL/glew.h>
+#include "shape.h"
+
+#define SKYBOX_ROTATION_SPEED 1.0f
+
+typedef struct
+{
+ GLuint texture;
+ shape_t *cube;
+ GLfloat rotation;
+} skybox_t;
+
+#endif // SKYBOX_H