aboutsummaryrefslogtreecommitdiff
path: root/08-august/src
diff options
context:
space:
mode:
Diffstat (limited to '08-august/src')
-rw-r--r--08-august/src/camera.c85
-rw-r--r--08-august/src/camera.h32
-rw-r--r--08-august/src/game.h46
-rw-r--r--08-august/src/graphics/shaders.c135
-rw-r--r--08-august/src/graphics/shaders.h51
-rw-r--r--08-august/src/graphics/window.c44
-rw-r--r--08-august/src/graphics/window.h20
-rw-r--r--08-august/src/gui/gui_renderer.c0
-rw-r--r--08-august/src/gui/gui_renderer.h9
-rw-r--r--08-august/src/gui/widget.c17
-rw-r--r--08-august/src/gui/widget.h13
-rw-r--r--08-august/src/input.c21
-rw-r--r--08-august/src/input.h11
-rw-r--r--08-august/src/light.c1
-rw-r--r--08-august/src/light.h13
-rw-r--r--08-august/src/main.c290
-rw-r--r--08-august/src/math/math_util.c10
-rw-r--r--08-august/src/math/math_util.h9
-rw-r--r--08-august/src/math/matrix4x4.c325
-rw-r--r--08-august/src/math/matrix4x4.h40
-rw-r--r--08-august/src/math/vector2f.c54
-rw-r--r--08-august/src/math/vector2f.h19
-rw-r--r--08-august/src/math/vector3f.c59
-rw-r--r--08-august/src/math/vector3f.h19
-rw-r--r--08-august/src/math/vector4f.c53
-rw-r--r--08-august/src/math/vector4f.h18
-rw-r--r--08-august/src/player.c62
-rw-r--r--08-august/src/player.h17
-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
-rw-r--r--08-august/src/terrain.c163
-rw-r--r--08-august/src/terrain.h27
-rw-r--r--08-august/src/texture.c71
-rw-r--r--08-august/src/texture.h10
-rw-r--r--08-august/src/util/util.c87
-rw-r--r--08-august/src/util/util.h25
-rw-r--r--08-august/src/util/util_time.c52
-rw-r--r--08-august/src/util/util_time.h13
-rw-r--r--08-august/src/vertex.h17
44 files changed, 2518 insertions, 0 deletions
diff --git a/08-august/src/camera.c b/08-august/src/camera.c
new file mode 100644
index 0000000..545ac85
--- /dev/null
+++ b/08-august/src/camera.c
@@ -0,0 +1,85 @@
+#include "camera.h"
+
+#include "util/util_time.h"
+
+static const float movementSpeed = 40.0f;
+
+void Camera_Init(camera_t* camera)
+{
+ camera->position = (vec3_t){ 4.0f, 40.0f, 4.0f };
+ camera->viewDirection = (vec3_t){ -1.0f, -1.0f, 0.0f };
+ camera->needsUpdate = true;
+ camera->up = (vec3_t){ 0.0f, 1.0f, 0.0f };
+}
+
+void Camera_Move_Up(camera_t* camera)
+{
+ vec3_t temp = vec3_scalar_mul(&camera->up, movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void Camera_Move_Down(camera_t* camera)
+{
+ vec3_t temp = vec3_scalar_mul(&camera->up, -movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void Camera_Move_Left(camera_t* camera)
+{
+ vec3_t 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_t* camera)
+{
+ vec3_t 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_t* camera)
+{
+ vec3_t temp = vec3_scalar_mul(&camera->viewDirection, movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void Camera_Move_Backward(camera_t* camera)
+{
+ vec3_t temp = vec3_scalar_mul(&camera->viewDirection, -movementSpeed * Time_GetFrameTime());
+ camera->position = vec3_add(&camera->position, &temp);
+}
+
+void Camera_MouseUpdate(camera_t* camera, const vec2_t* newMousePosition)
+{
+ vec2_t 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_t verticalRotation = vec3_cross_mul(&camera->viewDirection, &camera->up);
+
+ mat4_t 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;
+}
+
+mat4_t Camera_GetModelToViewMatrix(camera_t* camera)
+{
+ if(camera->needsUpdate)
+ {
+ vec3_t temp = vec3_add(&camera->position, &camera->viewDirection);
+ camera->viewMatrix = mat4_lookAt(&camera->position, &temp, &camera->up);
+ }
+ return camera->viewMatrix;
+}
diff --git a/08-august/src/camera.h b/08-august/src/camera.h
new file mode 100644
index 0000000..384bee8
--- /dev/null
+++ b/08-august/src/camera.h
@@ -0,0 +1,32 @@
+#ifndef CAMERA_H
+#define CAMERA_H
+
+#include "math/matrix4x4.h"
+#include "math/vector3f.h"
+#include "math/vector2f.h"
+#include <stdbool.h>
+
+typedef struct
+{
+ vec3_t position;
+ vec3_t viewDirection;
+ vec3_t up;
+ mat4_t projectionMatrix;
+ mat4_t viewMatrix;
+ vec2_t mousePosition;
+ bool needsUpdate;
+} camera_t;
+
+extern void Camera_Init(camera_t* camera);
+extern void Camera_Move_Up(camera_t* camera);
+extern void Camera_Move_Down(camera_t* camera);
+extern void Camera_Move_Left(camera_t* camera);
+extern void Camera_Move_Right(camera_t* camera);
+extern void Camera_Move_Foward(camera_t* camera);
+extern void Camera_Move_Backward(camera_t* camera);
+extern void Camera_MouseUpdate(camera_t* camera, const vec2_t* newMousePosition);
+
+/* Consigue la viewMatrix */
+extern mat4_t Camera_GetModelToViewMatrix(camera_t* camera);
+
+#endif // CAMERA_H
diff --git a/08-august/src/game.h b/08-august/src/game.h
new file mode 100644
index 0000000..611bd07
--- /dev/null
+++ b/08-august/src/game.h
@@ -0,0 +1,46 @@
+#ifndef GAME_H
+#define GAME_H
+
+#include "camera.h"
+#include "graphics/window.h"
+#include "renderer/entity.h"
+#include "player.h"
+#include "terrain.h"
+#include "texture.h"
+#include "renderer/shape.h"
+#include "graphics/shaders.h"
+#include "renderer/skybox.h"
+
+typedef enum
+{
+ MENU,
+ RUNNING,
+ EXIT
+}GameState_t;
+
+#define NUM_ENTITIES 1
+
+#define WINDOW_WIDTH 1024
+#define WINDOW_HEIGHT 768
+#define WINDOW_ASPECT_RATIO ( (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT )
+
+typedef struct
+{
+ GameState_t gameState;
+ Shader_Layout shaderProgram, terrainProgram, skyboxProgram;
+
+ entity_t ents[NUM_ENTITIES];
+ shape_t *entsShape;
+ GLuint entsTexture;
+ GLuint normalMap;
+ GLuint defaultNormalMap;
+ terrain_t *terrain;
+ skybox_t sky;
+
+ player_t player;
+
+ camera_t camera;
+ window_t *window;
+} game_t;
+
+#endif // GAME_H
diff --git a/08-august/src/graphics/shaders.c b/08-august/src/graphics/shaders.c
new file mode 100644
index 0000000..c0796e1
--- /dev/null
+++ b/08-august/src/graphics/shaders.c
@@ -0,0 +1,135 @@
+#include "shaders.h"
+#include "../util/util.h"
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+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);
+ }
+}
+
+
+GLuint Shader_CompileShaders(const char* vertexShader, const char* fragmentShader)
+{
+ char* vertexShaderSource = Util_LoadFile(vertexShader);
+ char* fragmentShaderSource = Util_LoadFile(fragmentShader);
+
+ 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);
+ }
+
+ glDetachShader(program, vs);
+ glDetachShader(program, fs);
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+
+ free(vertexShaderSource);
+ free(fragmentShaderSource);
+
+ return program;
+}
+
+GLint Shader_GetUniformLocation( GLuint programID, const char* uniformName )
+{
+ GLint u = glGetUniformLocation(programID, uniformName);
+ if(u == GL_INVALID_INDEX);
+ //Util_FatalError("Uniform \"%s\" could not be found!", uniformName);
+ else
+ return u;
+
+ return 0;
+}
+
+GLint Shader_GetAttribLocation ( GLuint programID, const char* attributeName )
+{
+ GLint attrLocation = glGetAttribLocation(programID, attributeName);
+ if(attrLocation < 0)
+ Util_FatalError("Attribute \"%s\" could not be found!\n", attributeName);
+ return attrLocation;
+}
+
+void Shader_Destroy(GLuint programID)
+{
+ glUseProgram(0);
+ glDeleteProgram(programID);
+}
+
+void Shader_SetUniformMat4( GLuint programID, const char* name, const float *matrix )
+{
+ GLint location = Shader_GetUniformLocation(programID, name);
+ glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
+}
+
+void Shader_SetUniformFloat( GLuint programID, const char* name, const float val )
+{
+ GLint location = Shader_GetUniformLocation(programID, name);
+ glUniform1f(location, val);
+}
+
+void Shader_SetUniformVec2( GLuint programID, const char* name, const float vec[2] )
+{
+ GLint location = Shader_GetUniformLocation(programID, name);
+ glUniform2fv(location, 1, vec);
+}
+
+void Shader_SetUniformVec3( GLuint programID, const char* name, const float vec[3] )
+{
+ GLint location = Shader_GetUniformLocation(programID, name);
+ glUniform3fv(location, 1, vec);
+}
+
+void Shader_SetUniformVec4( GLuint programID, const char* name, const float vec[4] )
+{
+ GLint location = Shader_GetUniformLocation(programID, name);
+ glUniform4fv(location, 1, vec);
+}
+
+void Shader_SetUniformInt( GLuint programID, const char* name, const int val )
+{
+ GLint location = Shader_GetUniformLocation(programID, name);
+ glUniform1i(location, val);
+}
diff --git a/08-august/src/graphics/shaders.h b/08-august/src/graphics/shaders.h
new file mode 100644
index 0000000..db090fd
--- /dev/null
+++ b/08-august/src/graphics/shaders.h
@@ -0,0 +1,51 @@
+#ifndef SHADERS_H
+#define SHADERS_H
+
+#include <GL/glew.h>
+
+#include "../math/matrix4x4.h"
+
+typedef struct
+{
+ /* Program ID */
+ GLuint ID;
+
+ /* Program Attributes */
+ GLint position;
+ GLint color;
+ GLint uv;
+ GLint normal;
+
+ /* 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;
+} Shader_Layout;
+
+extern GLuint Shader_CompileShaders(const char* vertexShader, const char* fragmentShader);
+extern GLint Shader_GetUniformLocation( GLuint programID, const char* uniformName );
+extern GLint Shader_GetAttribLocation ( GLuint programID, const char* attributeName );
+extern void Shader_Destroy(GLuint programID);
+
+extern void Shader_SetUniformMat4( GLuint programID, const char* name, const float *matrix );
+extern void Shader_SetUniformFloat( GLuint programID, const char* name, const float val );
+extern void Shader_SetUniformVec2( GLuint programID, const char* name, const float vec[2] );
+extern void Shader_SetUniformVec3( GLuint programID, const char* name, const float vec[3] );
+extern void Shader_SetUniformVec4( GLuint programID, const char* name, const float vec[4] );
+extern void Shader_SetUniformInt( GLuint programID, const char* name, const int val );
+
+#endif // SHADERS_H
diff --git a/08-august/src/graphics/window.c b/08-august/src/graphics/window.c
new file mode 100644
index 0000000..1a942ca
--- /dev/null
+++ b/08-august/src/graphics/window.c
@@ -0,0 +1,44 @@
+#include "window.h"
+#include "../util/util.h"
+#include <stdlib.h>
+
+window_t* Window_Create(const char* title, Uint32 width, Uint32 height)
+{
+ window_t* window = (window_t*) malloc(sizeof(window_t));
+ window->title = title;
+ window->Width = width;
+ window->Height = height;
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ 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_t* 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_t* window)
+{
+ SDL_GL_SwapWindow(window->window);
+}
+
+void Window_Destroy(window_t* window)
+{
+ SDL_GL_DeleteContext(window->context);
+ SDL_DestroyWindow(window->window);
+ free(window);
+}
diff --git a/08-august/src/graphics/window.h b/08-august/src/graphics/window.h
new file mode 100644
index 0000000..1e71a83
--- /dev/null
+++ b/08-august/src/graphics/window.h
@@ -0,0 +1,20 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <SDL2/SDL.h>
+#include <GL/glew.h>
+
+typedef struct
+{
+ SDL_Window* window;
+ SDL_GLContext context;
+ Uint32 Width, Height;
+ const char* title;
+} window_t;
+
+extern window_t* Window_Create(const char* title, Uint32 width, Uint32 height);
+extern void Window_Resize(window_t* window, Uint32 width, Uint32 height);
+extern void Window_Update(window_t* window);
+extern void Window_Destroy(window_t* window);
+
+#endif // WINDOW_H
diff --git a/08-august/src/gui/gui_renderer.c b/08-august/src/gui/gui_renderer.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/08-august/src/gui/gui_renderer.c
diff --git a/08-august/src/gui/gui_renderer.h b/08-august/src/gui/gui_renderer.h
new file mode 100644
index 0000000..2c1b57f
--- /dev/null
+++ b/08-august/src/gui/gui_renderer.h
@@ -0,0 +1,9 @@
+#ifndef GUI_RENDERER_H
+#define GUI_RENDERER_H
+
+extern void gui_renderer_init();
+extern void gui_renderer_submit(widget *widget);
+extern void gui_renderer_quit();
+
+
+#endif // GUI_RENDERER_H
diff --git a/08-august/src/gui/widget.c b/08-august/src/gui/widget.c
new file mode 100644
index 0000000..9ed00f7
--- /dev/null
+++ b/08-august/src/gui/widget.c
@@ -0,0 +1,17 @@
+#include "widget.h"
+#include <stdlib.h>
+
+widget_t *Widget_CreateImage(texture_t *texture, int x, int y, int w, int h)
+{
+ widget_t *widget = (widget_t *) malloc( sizeof(widget_t) );
+ *widget = (widget_t){ x, y, w, h, 0, texture };
+
+ glGenBuffers(1, &widget->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, widget->vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, NULL, GL_DYNAMIC_DRAW);
+}
+
+void Widget_Destroy(widget_t *widget)
+{
+ free(widget);
+}
diff --git a/08-august/src/gui/widget.h b/08-august/src/gui/widget.h
new file mode 100644
index 0000000..91fc4c4
--- /dev/null
+++ b/08-august/src/gui/widget.h
@@ -0,0 +1,13 @@
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include "GL/glew.h"
+#include "../texture.h"
+
+typedef struct
+{
+ int x, y, w, h;
+ texture_t *texture;
+} widget_t;
+
+#endif // WIDGET_H
diff --git a/08-august/src/input.c b/08-august/src/input.c
new file mode 100644
index 0000000..8384ceb
--- /dev/null
+++ b/08-august/src/input.c
@@ -0,0 +1,21 @@
+#include "input.h"
+
+static bool key_buffer[MAX_KEY_BUFFER_SIZE] = { false };
+
+void Input_PressKey(unsigned int key)
+{
+ if(key > 256 || key < 0) return;
+ key_buffer[key] = true;
+}
+
+void Input_ReleaseKey(unsigned int key)
+{
+ if(key > 256 || key < 0) return;
+ key_buffer[key] = false;
+}
+
+bool Input_isKeyPressed(unsigned int key)
+{
+ if(key > 256 || key < 0) return false;
+ return key_buffer[key];
+}
diff --git a/08-august/src/input.h b/08-august/src/input.h
new file mode 100644
index 0000000..92876ca
--- /dev/null
+++ b/08-august/src/input.h
@@ -0,0 +1,11 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <stdbool.h>
+#define MAX_KEY_BUFFER_SIZE 256
+
+void Input_PressKey(unsigned int key);
+void Input_ReleaseKey(unsigned int key);
+bool Input_isKeyPressed(unsigned int key);
+
+#endif // INPUT_H
diff --git a/08-august/src/light.c b/08-august/src/light.c
new file mode 100644
index 0000000..decd182
--- /dev/null
+++ b/08-august/src/light.c
@@ -0,0 +1 @@
+#include "light.h"
diff --git a/08-august/src/light.h b/08-august/src/light.h
new file mode 100644
index 0000000..afc8eda
--- /dev/null
+++ b/08-august/src/light.h
@@ -0,0 +1,13 @@
+#ifndef LIGHT_H
+#define LIGHT_H
+
+#include "vertex.h"
+
+typedef struct
+{
+ vec3_t position;
+ vec4_t color;
+ vec3_t attenuation;
+} light_t;
+
+#endif // LIGHT_H
diff --git a/08-august/src/main.c b/08-august/src/main.c
new file mode 100644
index 0000000..41fc253
--- /dev/null
+++ b/08-august/src/main.c
@@ -0,0 +1,290 @@
+#include "game.h"
+#include "math/vector3f.h"
+#include "math/vector2f.h"
+#include "math/matrix4x4.h"
+#include "input.h"
+#include "util/util.h"
+#include "util/util_time.h"
+#include "light.h"
+#include "renderer/renderer.h"
+#include <SDL2/SDL.h>
+
+/**
+ TODO: Shadows
+ Texture Atlases
+ Memory management
+
+ +improve skybox
+ |
+ +->fog
+ +->day/night
+
+ +mouse picking (is it working perfectly?)
+
+ +add cell shading?
+
+ improve math package
+ repair gui on renderer.c
+ improve shape loading (tangent generation) (normal generation)
+ improve normal mapping
+**/
+
+void LoadResources(game_t *game);
+void Draw(game_t *game);
+void ProcessInput(game_t *game);
+void CleanUp(game_t *game);
+
+int main(int argc, char *argv[])
+{
+ SDL_Init(SDL_INIT_EVERYTHING);
+
+ game_t game;
+ game.gameState = RUNNING;
+ game.window = Window_Create("Test", WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ GLenum err = glewInit();
+ if(err != GLEW_OK) {
+ fputs(glewGetErrorString(err), stderr);
+ Util_FatalError("Glew could no be started!");
+ }
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ SDL_GL_SetSwapInterval(1);
+ // glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+
+ game.shaderProgram.ID = Shader_CompileShaders("resources/shaders/shader.vert",
+ "resources/shaders/shader.frag");
+
+ game.terrainProgram.ID = Shader_CompileShaders("resources/shaders/terrainShader.vert",
+ "resources/shaders/terrainShader.frag");
+
+ game.skyboxProgram.ID = Shader_CompileShaders("resources/shaders/skyboxShader.vert",
+ "resources/shaders/skyboxShader.frag");
+ glUseProgram(game.shaderProgram.ID);
+
+ Camera_Init(&game.camera);
+ game.camera.projectionMatrix = mat4_perspective(60.0f, WINDOW_ASPECT_RATIO, 0.1f, 900.0f);
+
+ LoadResources(&game);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ Time_Init();
+ Time_SetMaxFramesPerSecond(60);
+ while(game.gameState != EXIT)
+ {
+ Time_Begin();
+ ProcessInput(&game);
+ Player_Update(&game.player, game.terrain);
+ Draw(&game);
+
+ float FPS = Time_End();
+
+ if( !( Time_GetCountedFrames() % (int)FPS ) )
+ fprintf(stderr, "FPS: %.4f\n", FPS);
+ }
+
+ Window_Destroy(game.window);
+ CleanUp(&game);
+ SDL_Quit();
+ return 0;
+}
+
+void CleanUp(game_t *game)
+{
+ Shape_Free(game->entsShape);
+ Shape_Free(game->sky.cube);
+
+ Texture_Destroy(game->entsTexture);
+ Texture_Destroy(game->sky.texture);
+
+ Texture_Destroy(game->normalMap);
+ Texture_Destroy(game->defaultNormalMap);
+
+ Terrain_Destroy(game->terrain);
+
+ Shader_Destroy(game->shaderProgram.ID);
+ Shader_Destroy(game->terrainProgram.ID);
+ Shader_Destroy(game->skyboxProgram.ID);
+
+ Render_Quit();
+}
+
+void LoadResources(game_t *game)
+{
+ Render_Init();
+ Uint32 start = SDL_GetTicks();
+
+ game->entsShape = Shape_LoadOBJ("resources/barrel.obj");
+ game->entsTexture = Texture_Create2D("resources/textures/barrel.png");
+
+ Player_Init(&game->player);
+ game->player.entity.texture = game->entsTexture;
+ game->player.entity.shape = game->entsShape;
+
+ {
+ vec3_t position = { 0.0f, 3.0f, 0.0f };
+ float rotation[3] = { 0.0f, 0.0f, 0.0f };
+ game->ents[0].position = position;
+ game->ents[0].rotX = rotation[0];
+ game->ents[0].rotY = rotation[1];
+ game->ents[0].rotZ = rotation[2];
+ game->ents[0].shape = game->entsShape;
+ game->ents[0].texture = game->entsTexture;
+ }
+
+ {
+ vec3_t position = { -400.0f, 0.0f, -400.0f };
+ GLuint blendmap = Texture_Create2D("resources/textures/blendmap.png");
+ TerrainTexturePack pack =
+ {
+ {
+ Texture_Create2D("resources/textures/soil1.png"),
+ Texture_Create2D("resources/textures/soil2.png"),
+ Texture_Create2D("resources/textures/soil4.png"),
+ Texture_Create2D("resources/textures/soil3.png"),
+ }
+ };
+ game->terrain = Terrain_Create(800, 800, "resources/textures/heightmap.png", blendmap, &pack);
+ game->terrain->position = position;
+ }
+
+ {
+ game->sky.rotation = 0.0f;
+ game->sky.cube = Shape_MakeSkyBox(500.0f);
+ const char *paths[6] =
+ {
+ "resources/textures/right.png",
+ "resources/textures/left.png",
+ "resources/textures/top.png",
+ "resources/textures/bottom.png",
+ "resources/textures/back.png",
+ "resources/textures/front.png"
+ };
+ game->sky.texture = Texture_CreateCubeMap(paths);
+ }
+
+ /* Shader Layouts */
+
+ Shader_Layout *layout = &game->shaderProgram;
+ layout->Texture = Shader_GetUniformLocation(layout->ID, "Texture");
+ layout->modelToWorld = Shader_GetUniformLocation(layout->ID, "M_model");
+ layout->totalTransform = Shader_GetUniformLocation(layout->ID, "M_MVP");
+ layout->lightPosition = Shader_GetUniformLocation(layout->ID, "lightPosition");
+ layout->lightColor = Shader_GetUniformLocation(layout->ID, "lightColor");
+ layout->lightAttenuation = Shader_GetUniformLocation(layout->ID, "attenuation");
+ layout->Normal_Map = Shader_GetUniformLocation(layout->ID, "normalMap");
+
+ layout = &game->terrainProgram;
+ layout->modelToWorld = Shader_GetUniformLocation(layout->ID, "M_model");
+ layout->totalTransform = Shader_GetUniformLocation(layout->ID, "M_MVP");
+ layout->lightPosition = Shader_GetUniformLocation(layout->ID, "lightPosition");
+ layout->lightColor = Shader_GetUniformLocation(layout->ID, "lightColor");
+ layout->lightAttenuation = Shader_GetUniformLocation(layout->ID, "attenuation");
+
+ layout->extra0 = Shader_GetUniformLocation(layout->ID, "Texture_Background");
+ layout->extra1 = Shader_GetUniformLocation(layout->ID, "Texture_R");
+ layout->extra2 = Shader_GetUniformLocation(layout->ID, "Texture_G");
+ layout->extra3 = Shader_GetUniformLocation(layout->ID, "Texture_B");
+ layout->extra4 = Shader_GetUniformLocation(layout->ID, "Texture_BlendMap");
+
+ layout = &game->skyboxProgram;
+ layout->totalTransform = Shader_GetUniformLocation(layout->ID, "M_MVP");
+ layout->Texture = Shader_GetUniformLocation(layout->ID, "cubeMap");
+
+ game->normalMap = Texture_Create2D("resources/textures/normal_map.png");
+ game->defaultNormalMap = Texture_Create2D("resources/textures/default_normal_map.png");
+
+ fprintf(stderr, "Loading time: %u (ms)\n", SDL_GetTicks() - start);
+}
+
+void Draw(game_t *game)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /*We upload all the light vectors*/
+ static const light_t diffuseLight[1] =
+ {
+ /* Sun Light */
+ { {5.0f, 40.0f, 2.0f}, {1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f} },
+ /* Other lights
+ { {10.0f, 20.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.01f, 0.002f} },
+ { {20.0f, 20.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.01f, 0.002f} },
+ { {30.0f, 20.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 0.01f, 0.002f} },*/
+ };
+
+ Shader_SetUniformVec3(game->shaderProgram.ID, "World_eyePosition", (float*)&game->camera.position);
+ Render_LoadLights(&game->shaderProgram, diffuseLight, 1);
+
+ glActiveTexture(GL_TEXTURE13);
+ glBindTexture(GL_TEXTURE_2D, game->normalMap);
+
+ glUniform1i(game->shaderProgram.Normal_Map, 13);
+
+ mat4_t viewMatrix, projectedViewMatrix;
+
+ viewMatrix = Camera_GetModelToViewMatrix(&game->camera);
+ projectedViewMatrix = mat4_mul(&game->camera.projectionMatrix, &viewMatrix);
+
+ Render_DrawEntity(&game->shaderProgram, &projectedViewMatrix, &game->player.entity);
+ Render_DrawEntity(&game->shaderProgram, &projectedViewMatrix, &game->ents[0]);
+
+ glUseProgram(game->terrainProgram.ID);
+
+ Shader_SetUniformVec3(game->terrainProgram.ID, "World_eyePosition", (float*)&game->camera.position);
+ Render_LoadLights(&game->terrainProgram, diffuseLight, 1);
+
+ Render_DrawTerrain(&game->terrainProgram, &projectedViewMatrix, game->terrain);
+
+ glUseProgram(game->skyboxProgram.ID);
+ Render_DrawSky(&game->skyboxProgram, &viewMatrix, &game->camera.projectionMatrix, &game->sky);
+
+ glUseProgram(game->shaderProgram.ID);
+
+ Window_Update(game->window);
+}
+
+void ProcessInput(game_t *game)
+{
+ static vec2_t mousePosition;
+ SDL_Event e;
+ while(SDL_PollEvent(&e))
+ {
+ switch(e.type)
+ {
+ case SDL_QUIT:
+ game->gameState = EXIT;
+ break;
+
+ case SDL_MOUSEMOTION:
+ mousePosition.x = (GLfloat) e.motion.x;
+ mousePosition.y = (GLfloat) e.motion.y;
+ Camera_MouseUpdate(&game->camera, &mousePosition);
+ break;
+
+ case SDL_KEYDOWN:
+ Input_PressKey(e.key.keysym.scancode);
+ break;
+
+ case SDL_KEYUP:
+ Input_ReleaseKey(e.key.keysym.scancode);
+ break;
+ }
+
+ if(Input_isKeyPressed(SDL_SCANCODE_UP))
+ Camera_Move_Foward(&game->camera);
+
+ if(Input_isKeyPressed(SDL_SCANCODE_DOWN))
+ Camera_Move_Backward(&game->camera);
+
+ if(Input_isKeyPressed(SDL_SCANCODE_LEFT))
+ Camera_Move_Left(&game->camera);
+
+ if(Input_isKeyPressed(SDL_SCANCODE_RIGHT))
+ Camera_Move_Right(&game->camera);
+
+ if(Input_isKeyPressed(SDL_SCANCODE_ESCAPE))
+ game->gameState = EXIT;
+ }
+}
diff --git a/08-august/src/math/math_util.c b/08-august/src/math/math_util.c
new file mode 100644
index 0000000..f58e447
--- /dev/null
+++ b/08-august/src/math/math_util.c
@@ -0,0 +1,10 @@
+#include "math_util.h"
+
+float baryCentric(vec3_t *p1, vec3_t *p2, vec3_t *p3, vec2_t *pos)
+{
+ float det = (p2->z - p3->z) * (p1->x - p3->x) + (p3->x - p2->x) * (p1->z - p3->z);
+ float l1 = ((p2->z - p3->z) * (pos->x - p3->x) + (p3->x - p2->x) * (pos->y - p3->z)) / det;
+ float l2 = ((p3->z - p1->z) * (pos->x - p3->x) + (p1->x - p3->x) * (pos->y - p3->z)) / det;
+ float l3 = 1.0f - l1 - l2;
+ return l1 * p1->y + l2 * p2->y + l3 * p3->y;
+}
diff --git a/08-august/src/math/math_util.h b/08-august/src/math/math_util.h
new file mode 100644
index 0000000..28a5464
--- /dev/null
+++ b/08-august/src/math/math_util.h
@@ -0,0 +1,9 @@
+#ifndef MATH_UTIL_H
+#define MATH_UTIL_H
+
+#include "vector3f.h"
+#include "vector2f.h"
+
+extern float baryCentric(vec3_t *p1, vec3_t *p2, vec3_t *p3, vec2_t *pos);
+
+#endif // MATH_UTIL_H
diff --git a/08-august/src/math/matrix4x4.c b/08-august/src/math/matrix4x4.c
new file mode 100644
index 0000000..1888727
--- /dev/null
+++ b/08-august/src/math/matrix4x4.c
@@ -0,0 +1,325 @@
+#include "matrix4x4.h"
+#include "../util/util.h"
+#include <SDL2/SDL.h>
+
+void mat4_identity(mat4_t *a)
+{
+ int i;
+ for(i = 0; i < 4*4; i++)
+ {
+ a->data[i] = 0.0f;
+ }
+ a->data[0 + 0 * 4] = 1.0f;
+ a->data[1 + 1 * 4] = 1.0f;
+ a->data[2 + 2 * 4] = 1.0f;
+ a->data[3 + 3 * 4] = 1.0f;
+}
+
+/** TODO: Preprocess these operation (1 + 1 * 4) -> 5 **/
+mat4_t mat4_inverse(const mat4_t *a)
+{
+ mat4_t inv;
+ int i;
+
+ /** Remember that inverted matrix is (1/det) * cofactor(transposed) **/
+ inv.data[0 + 0 * 4] = (a->data[1 + 1 * 4] * a->data[2 + 2 * 4] * a->data[3 + 3 * 4] +
+ a->data[2 + 1 * 4] * a->data[3 + 2 * 4] * a->data[1 + 3 * 4] +
+ a->data[3 + 1 * 4] * a->data[1 + 2 * 4] * a->data[2 + 3 * 4] -
+ a->data[1 + 3 * 4] * a->data[2 + 2 * 4] * a->data[3 + 1 * 4] -
+ a->data[2 + 3 * 4] * a->data[3 + 2 * 4] * a->data[1 + 1 * 4] -
+ a->data[3 + 3 * 4] * a->data[1 + 2 * 4] * a->data[2 + 1 * 4]);
+
+ inv.data[0 + 1 * 4] = -(a->data[0 + 1 * 4] * a->data[2 + 2 * 4] * a->data[3 + 3 * 4] +
+ a->data[2 + 1 * 4] * a->data[3 + 2 * 4] * a->data[0 + 3 * 4] +
+ a->data[3 + 1 * 4] * a->data[0 + 2 * 4] * a->data[2 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[2 + 2 * 4] * a->data[3 + 1 * 4] -
+ a->data[2 + 3 * 4] * a->data[3 + 2 * 4] * a->data[0 + 1 * 4] -
+ a->data[3 + 3 * 4] * a->data[0 + 2 * 4] * a->data[2 + 1 * 4]);
+
+ inv.data[0 + 2 * 4] = (a->data[0 + 1 * 4] * a->data[1 + 2 * 4] * a->data[3 + 3 * 4] +
+ a->data[1 + 1 * 4] * a->data[3 + 2 * 4] * a->data[0 + 3 * 4] +
+ a->data[3 + 1 * 4] * a->data[0 + 2 * 4] * a->data[1 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[1 + 2 * 4] * a->data[3 + 1 * 4] -
+ a->data[1 + 3 * 4] * a->data[3 + 2 * 4] * a->data[0 + 1 * 4] -
+ a->data[3 + 3 * 4] * a->data[0 + 2 * 4] * a->data[1 + 1 * 4]);
+
+ inv.data[0 + 3 * 4] = -(a->data[0 + 1 * 4] * a->data[1 + 2 * 4] * a->data[2 + 3 * 4] +
+ a->data[1 + 1 * 4] * a->data[2 + 2 * 4] * a->data[0 + 3 * 4] +
+ a->data[2 + 1 * 4] * a->data[0 + 2 * 4] * a->data[1 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[1 + 2 * 4] * a->data[2 + 1 * 4] -
+ a->data[1 + 3 * 4] * a->data[2 + 2 * 4] * a->data[0 + 1 * 4] -
+ a->data[2 + 3 * 4] * a->data[0 + 2 * 4] * a->data[1 + 1 * 4]);
+
+ inv.data[1 + 0 * 4] = -(a->data[1 + 0 * 4] * a->data[2 + 2 * 4] * a->data[3 + 3 * 4] +
+ a->data[2 + 0 * 4] * a->data[3 + 2 * 4] * a->data[1 + 3 * 4] +
+ a->data[3 + 0 * 4] * a->data[1 + 2 * 4] * a->data[2 + 3 * 4] -
+ a->data[1 + 3 * 4] * a->data[2 + 2 * 4] * a->data[3 + 0 * 4] -
+ a->data[2 + 3 * 4] * a->data[3 + 2 * 4] * a->data[1 + 0 * 4] -
+ a->data[3 + 3 * 4] * a->data[1 + 2 * 4] * a->data[2 + 0 * 4]);
+
+ inv.data[1 + 1 * 4] = (a->data[0 + 0 * 4] * a->data[2 + 2 * 4] * a->data[3 + 3 * 4] +
+ a->data[2 + 0 * 4] * a->data[3 + 2 * 4] * a->data[0 + 3 * 4] +
+ a->data[3 + 0 * 4] * a->data[0 + 2 * 4] * a->data[2 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[2 + 2 * 4] * a->data[3 + 0 * 4] -
+ a->data[2 + 3 * 4] * a->data[3 + 2 * 4] * a->data[0 + 0 * 4] -
+ a->data[3 + 3 * 4] * a->data[0 + 2 * 4] * a->data[2 + 0 * 4]);
+
+ inv.data[1 + 2 * 4] = -(a->data[0 + 0 * 4] * a->data[1 + 2 * 4] * a->data[3 + 3 * 4] +
+ a->data[1 + 0 * 4] * a->data[3 + 2 * 4] * a->data[0 + 3 * 4] +
+ a->data[3 + 0 * 4] * a->data[0 + 2 * 4] * a->data[1 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[1 + 2 * 4] * a->data[3 + 0 * 4] -
+ a->data[1 + 3 * 4] * a->data[3 + 2 * 4] * a->data[0 + 0 * 4] -
+ a->data[3 + 3 + 4] * a->data[0 + 2 * 4] * a->data[1 + 0 * 4]);
+
+ inv.data[1 + 3 * 4] = (a->data[0 + 0 * 4] * a->data[1 + 2 * 4] * a->data[2 + 3 * 4] +
+ a->data[1 + 0 * 4] * a->data[2 + 2 * 4] * a->data[0 + 3 * 4] +
+ a->data[2 + 0 * 4] * a->data[0 + 2 * 4] * a->data[1 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[1 + 2 * 4] * a->data[2 + 0 * 4] -
+ a->data[1 + 3 * 4] * a->data[2 + 2 * 4] * a->data[0 + 0 * 4] -
+ a->data[2 + 3 * 4] * a->data[0 + 2 * 4] * a->data[1 + 0 * 4]);
+
+ inv.data[2 + 0 * 4] = (a->data[1 + 0 * 4] * a->data[2 + 1 * 4] * a->data[3 + 3 * 4] +
+ a->data[2 + 0 * 4] * a->data[3 + 1 * 4] * a->data[1 + 3 * 4] +
+ a->data[3 + 0 * 4] * a->data[1 + 1 * 4] * a->data[2 + 3 * 4] -
+ a->data[1 + 3 * 4] * a->data[2 + 1 * 4] * a->data[3 + 0 * 4] -
+ a->data[2 + 3 * 4] * a->data[3 + 1 * 4] * a->data[1 + 0 * 4] -
+ a->data[3 + 3 * 4] * a->data[1 + 1 * 4] * a->data[2 + 0 * 4]);
+
+ inv.data[2 + 1 * 4] = -(a->data[0 + 0 * 4] * a->data[2 + 1 * 4] * a->data[3 + 3 * 4] +
+ a->data[2 + 0 * 4] * a->data[3 + 1 * 4] * a->data[0 + 3 * 4] +
+ a->data[3 + 0 * 4] * a->data[0 + 1 * 4] * a->data[2 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[2 + 1 * 4] * a->data[3 + 0 * 4] -
+ a->data[2 + 3 * 4] * a->data[3 + 1 * 4] * a->data[0 + 0 * 4] -
+ a->data[3 + 3 * 4] * a->data[0 + 1 * 4] * a->data[2 + 0 * 4]);
+
+ inv.data[2 + 2 * 4] = (a->data[0 + 0 * 4] * a->data[1 + 1 * 4] * a->data[3 + 3 * 4] +
+ a->data[1 + 0 * 4] * a->data[3 + 1 * 4] * a->data[0 + 3 * 4] +
+ a->data[3 + 0 * 4] * a->data[0 + 1 * 4] * a->data[1 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[1 + 1 * 4] * a->data[3 + 0 * 4] -
+ a->data[1 + 3 * 4] * a->data[3 + 1 * 4] * a->data[0 + 0 * 4] -
+ a->data[3 + 3 * 4] * a->data[0 + 1 * 4] * a->data[1 + 0 * 4]);
+
+ inv.data[2 + 3 * 4] = -(a->data[0 + 0 * 4] * a->data[1 + 1 * 4] * a->data[2 + 3 * 4] +
+ a->data[1 + 0 * 4] * a->data[2 + 1 * 4] * a->data[0 + 3 * 4] +
+ a->data[2 + 0 * 4] * a->data[0 + 1 * 4] * a->data[1 + 3 * 4] -
+ a->data[0 + 3 * 4] * a->data[1 + 1 * 4] * a->data[2 + 0 * 4] -
+ a->data[1 + 3 * 4] * a->data[2 + 1 * 4] * a->data[0 + 0 * 4] -
+ a->data[2 + 3 * 4] * a->data[0 + 1 * 4] * a->data[1 + 0 * 4]);
+
+ inv.data[3 + 0 * 4] = -(a->data[1 + 0 * 4] * a->data[2 + 1 * 4] * a->data[3 + 2 * 4] +
+ a->data[2 + 0 * 4] * a->data[3 + 1 * 4] * a->data[1 + 2 * 4] +
+ a->data[3 + 0 * 4] * a->data[1 + 1 * 4] * a->data[2 + 2 * 4] -
+ a->data[1 + 2 * 4] * a->data[2 + 1 * 4] * a->data[3 + 0 * 4] -
+ a->data[2 + 2 * 4] * a->data[3 + 1 * 4] * a->data[1 + 0 * 4] -
+ a->data[3 + 2 * 4] * a->data[1 + 1 * 4] * a->data[2 + 0 * 4]);
+
+ inv.data[3 + 1 * 4] = (a->data[0 + 0 * 4] * a->data[2 + 1 * 4] * a->data[3 + 2 * 4] +
+ a->data[2 + 0 * 4] * a->data[3 + 1 * 4] * a->data[0 + 2 * 4] +
+ a->data[3 + 0 * 4] * a->data[0 + 1 * 4] * a->data[2 + 2 * 4] -
+ a->data[0 + 2 * 4] * a->data[2 + 1 * 4] * a->data[3 + 0 * 4] -
+ a->data[2 + 2 * 4] * a->data[3 + 1 * 4] * a->data[0 + 0 * 4] -
+ a->data[3 + 2 * 4] * a->data[0 + 1 * 4] * a->data[2 + 0 * 4]);
+
+ inv.data[3 + 2 * 4] = -(a->data[0 + 0 * 4] * a->data[1 + 1 * 4] * a->data[3 + 2 * 4] +
+ a->data[1 + 0 * 4] * a->data[3 + 1 * 4] * a->data[0 + 2 * 4] +
+ a->data[3 + 0 * 4] * a->data[0 + 1 * 4] * a->data[1 + 2 * 4] -
+ a->data[0 + 2 * 4] * a->data[1 + 1 * 4] * a->data[3 + 0 * 4] -
+ a->data[1 + 2 * 4] * a->data[3 + 1 * 4] * a->data[0 + 0 * 4] -
+ a->data[3 + 2 * 4] * a->data[0 + 1 * 4] * a->data[1 + 0 * 4]);
+
+ inv.data[3 + 3 * 4] = (a->data[0 + 0 * 4] * a->data[1 + 1 * 4] * a->data[2 + 2 * 4] +
+ a->data[1 + 0 * 4] * a->data[2 + 1 * 4] * a->data[0 + 2 * 4] +
+ a->data[2 + 0 * 4] * a->data[0 + 1 * 4] * a->data[1 + 2 * 4] -
+ a->data[0 + 2 * 4] * a->data[1 + 1 * 4] * a->data[2 + 0 * 4] -
+ a->data[1 + 2 * 4] * a->data[2 + 1 * 4] * a->data[0 + 0 * 4] -
+ a->data[2 + 2 * 4] * a->data[0 + 1 * 4] * a->data[1 + 0 * 4]);
+
+ /** Remember that our matrix is already transposed and we also got the minors(inside each "inv" entry),
+ so we just use them. We use a->data[0 + 1 * 4] * inv.data[1 + 0 * 4] becouse inv.data is transposed **/
+ float det = a->data[0 + 0 * 4] * inv.data[0 + 0 * 4] + a->data[0 + 1 * 4] * inv.data[1 + 0 * 4] +
+ a->data[0 + 2 * 4] * inv.data[2 + 0 * 4] + a->data[0 + 3 * 4] * inv.data[3 + 0 * 4];
+
+ if(det == 0.0f)
+ return *a;
+
+ det = 1.0f / det;
+
+ for(i = 0; i < 16; i++)
+ inv.data[i] *= det;
+
+ return inv;
+}
+
+mat4_t mat4_mul(const mat4_t* a, const mat4_t* b)
+{
+ int i, j, k;
+ GLfloat sum = 0.0f;
+ mat4_t c;
+ mat4_identity(&c);
+ for(i = 0; i < 4; i++)
+ for(j = 0; j < 4; j++){
+ for(k = 0; k < 4; k++){
+ sum += a->data[i + k * 4] * b->data[k + j * 4];
+ }
+ c.data[i + j * 4] = sum;
+ sum = 0.0f;
+ }
+
+ return c;
+}
+
+mat4_t mat4_translate(const vec3_t *a)
+{
+ mat4_t b;
+ mat4_identity(&b);
+ b.data[0 + 3 * 4] = a->x;
+ b.data[1 + 3 * 4] = a->y;
+ b.data[2 + 3 * 4] = a->z;
+ return b;
+}
+
+mat4_t mat4_scale(GLfloat x, GLfloat y, GLfloat z)
+{
+ mat4_t b;
+ mat4_identity(&b);
+ b.data[0 + 0 * 4] = x;
+ b.data[1 + 1 * 4] = y;
+ b.data[2 + 2 * 4] = z;
+ return b;
+}
+
+mat4_t mat4_rotate(GLfloat degrees, const vec3_t* a)
+{
+ mat4_t b;
+ mat4_identity(&b);
+ GLfloat c = SDL_cosf(toRadians(degrees)), s = SDL_sinf(toRadians(degrees)), o = 1-c;
+ b.data[0 + 0 * 4] = a->x * a->x * o + c;
+ b.data[0 + 1 * 4] = a->x * a->y * o - a->z * s;
+ b.data[0 + 2 * 4] = a->x * a->z * o + a->y * s;
+
+ b.data[1 + 0 * 4] = a->x * a->y * o + a->z * s;
+ b.data[1 + 1 * 4] = a->y * a->y * o + c;
+ b.data[1 + 2 * 4] = a->y * a->z * o - a->x * s;
+
+ b.data[2 + 0 * 4] = a->x * a->z * o - a->y * s;
+ b.data[2 + 1 * 4] = a->y * a->z * o + a->x * s;
+ b.data[2 + 2 * 4] = a->z * a->z * o + c;
+ return b;
+}
+
+mat4_t mat4_rotate_x(GLfloat degrees)
+{
+ mat4_t a;
+ mat4_identity(&a);
+ GLfloat c = SDL_cosf(toRadians(degrees)), s = SDL_sinf(toRadians(degrees));
+ a.data[1 + 1 * 4] = c;
+ a.data[2 + 1 * 4] = s;
+ a.data[1 + 2 * 4] = -s;
+ a.data[2 + 2 * 4] = c;
+ return a;
+}
+
+mat4_t mat4_rotate_y(GLfloat degrees)
+{
+ mat4_t a;
+ mat4_identity(&a);
+ GLfloat c = SDL_cosf(toRadians(degrees)), s = SDL_sinf(toRadians(degrees));
+ a.data[0 + 0 * 4] = c;
+ a.data[2 + 0 * 4] = -s;
+ a.data[0 + 2 * 4] = s;
+ a.data[2 + 2 * 4] = c;
+ return a;
+}
+
+mat4_t mat4_rotate_z(GLfloat degrees)
+{
+ mat4_t a;
+ mat4_identity(&a);
+ GLfloat c = SDL_cosf(toRadians(degrees)), s = SDL_sinf(toRadians(degrees));
+ a.data[0 + 0 * 4] = c;
+ a.data[1 + 0 * 4] = s;
+ a.data[0 + 1 * 4] = -s;
+ a.data[1 + 1 * 4] = c;
+ return a;
+}
+
+mat4_t mat4_perspective(GLfloat fov, GLfloat aspect, GLfloat zNear, GLfloat zFar)
+{
+ mat4_t a;
+ GLubyte i, j;
+ for(i = 0; i < 4; i++)
+ for(j = 0; j < 4; j++)
+ a.data[i + j * 4] = 0.0f;
+ fov = toRadians(fov); // To radians
+
+ a.data[0 + 0 * 4] = ( (1.0f / SDL_tanf( fov/2.0f )) / aspect);
+ a.data[1 + 1 * 4] = (1.0f / SDL_tanf( fov/2.0f ));
+ a.data[2 + 2 * 4] = -( (zFar + zNear) / (zFar - zNear) );
+ a.data[2 + 3 * 4] = -( ( 2.0f * zFar * zNear) / (zFar - zNear) );
+ a.data[3 + 2 * 4] = -1.0f;
+
+ return a;
+}
+
+mat4_t
+mat4_orthographic(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top)
+{
+ mat4_t a;
+ mat4_identity(&a);
+ a.data[0 + 0 * 4] = 2.0f / (right - left);
+ a.data[1 + 1 * 4] = 2.0f / (top - bottom);
+ a.data[2 + 2 * 4] = -1.0f;
+
+ a.data[0 + 3 * 4] = (left + right) / (left - right);
+ a.data[1 + 3 * 4] = (bottom + top) / (bottom - top);
+
+ return a;
+}
+
+mat4_t mat4_lookAt(vec3_t* eye, vec3_t* center, vec3_t* up)
+{
+ vec3_t temp = vec3_sub(center, eye);
+
+ vec3_t f = vec3_normalize(&temp);
+ vec3_t u = vec3_normalize(up);
+ temp = vec3_cross_mul(&f, &u);
+ vec3_t s = vec3_normalize(&temp);
+ u = vec3_cross_mul(&s, &f);
+
+ mat4_t a;
+ mat4_identity(&a);
+
+ a.data[0 + 0 * 4] = s.x;
+ a.data[0 + 1 * 4] = s.y;
+ a.data[0 + 2 * 4] = s.z;
+ a.data[1 + 0 * 4] = u.x;
+ a.data[1 + 1 * 4] = u.y;
+ a.data[1 + 2 * 4] = u.z;
+ a.data[2 + 0 * 4] =-f.x;
+ a.data[2 + 1 * 4] =-f.y;
+ a.data[2 + 2 * 4] =-f.z;
+ a.data[0 + 3 * 4] =-vec3_dot_mul(&s, eye);
+ a.data[1 + 3 * 4] =-vec3_dot_mul(&u, eye);
+ a.data[2 + 3 * 4] = vec3_dot_mul(&f, eye);
+
+ return a;
+}
+
+vec3_t mat4_mul_vec3(const mat4_t* a, const vec3_t* b)
+{
+ vec3_t c;
+ c.x = a->data[0 + 0 * 4] * b->x + a->data[0 + 1 * 4] * b->y + a->data[0 + 2 * 4] * b->z + a->data[0 + 3 * 4];
+ c.y = a->data[1 + 0 * 4] * b->x + a->data[1 + 1 * 4] * b->y + a->data[1 + 2 * 4] * b->z + a->data[1 + 3 * 4];
+ c.z = a->data[2 + 0 * 4] * b->x + a->data[2 + 1 * 4] * b->y + a->data[2 + 2 * 4] * b->z + a->data[2 + 3 * 4];
+ return c;
+}
+
+vec4_t mat4_mul_vec4(const mat4_t *a, const vec4_t *b)
+{
+ vec4_t c;
+ c.x = a->data[0 + 0 * 4] * b->x + a->data[0 + 1 * 4] * b->y + a->data[0 + 2 * 4] * b->z + a->data[0 + 3 * 4] * b->w;
+ c.y = a->data[1 + 0 * 4] * b->x + a->data[1 + 1 * 4] * b->y + a->data[1 + 2 * 4] * b->z + a->data[1 + 3 * 4] * b->w;
+ c.z = a->data[2 + 0 * 4] * b->x + a->data[2 + 1 * 4] * b->y + a->data[2 + 2 * 4] * b->z + a->data[2 + 3 * 4] * b->w;
+ c.w = a->data[3 + 0 * 4] * b->x + a->data[3 + 1 * 4] * b->y + a->data[3 + 2 * 4] * b->z + a->data[3 + 3 * 4] * b->w;
+ return c;
+}
diff --git a/08-august/src/math/matrix4x4.h b/08-august/src/math/matrix4x4.h
new file mode 100644
index 0000000..b7d54aa
--- /dev/null
+++ b/08-august/src/math/matrix4x4.h
@@ -0,0 +1,40 @@
+#ifndef MATRIX4X4_H
+#define MATRIX4X4_H
+
+#include <GL/glew.h>
+#include "vector3f.h"
+#include "vector4f.h"
+
+/* accesing data: row + column * width */
+typedef struct
+{
+ GLfloat data[16];
+} mat4_t;
+
+extern void mat4_identity(mat4_t *a);
+extern mat4_t mat4_inverse(const mat4_t *a);
+extern mat4_t mat4_mul(const mat4_t *a, const mat4_t *b);
+
+extern mat4_t mat4_translate(const vec3_t *a);
+extern mat4_t mat4_scale(GLfloat x, GLfloat y, GLfloat z);
+extern mat4_t mat4_rotate_x(GLfloat degrees);
+extern mat4_t mat4_rotate_y(GLfloat degrees);
+extern mat4_t mat4_rotate_z(GLfloat degrees);
+extern mat4_t mat4_rotate(GLfloat degrees, const vec3_t *a);
+
+extern mat4_t
+mat4_perspective(GLfloat fov, GLfloat aspect, GLfloat zNear, GLfloat zFar);
+
+extern mat4_t
+mat4_orthographic(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top);
+
+extern mat4_t
+mat4_lookAt(vec3_t *eye, vec3_t *center, vec3_t *up);
+
+extern vec3_t
+mat4_mul_vec3(const mat4_t *a, const vec3_t *b);
+
+extern vec4_t
+mat4_mul_vec4(const mat4_t *a, const vec4_t *b);
+
+#endif // MATRIX4X4_H
diff --git a/08-august/src/math/vector2f.c b/08-august/src/math/vector2f.c
new file mode 100644
index 0000000..37ffa9c
--- /dev/null
+++ b/08-august/src/math/vector2f.c
@@ -0,0 +1,54 @@
+#include "vector2f.h"
+#include <SDL2/SDL.h>
+
+vec2_t vec2_add(const vec2_t* a, const vec2_t* b)
+{
+ vec2_t c;
+ c.x = a->x + b->x;
+ c.y = a->y + b->y;
+ return c;
+}
+
+vec2_t vec2_sub(const vec2_t* a, const vec2_t* b)
+{
+ vec2_t c;
+ c.x = a->x - b->x;
+ c.y = a->y - b->y;
+ return c;
+}
+
+vec2_t vec2_scalar_mul(const vec2_t* a, GLfloat scalar)
+{
+ vec2_t c;
+ c.x = a->x * scalar;
+ c.y = a->y * scalar;
+ return c;
+}
+
+GLfloat vec2_dot_mul(const vec2_t* a, const vec2_t* b)
+{
+ return ( (a->x * b->x) + (a->y * b->y) );
+}
+
+
+vec2_t vec2_cross_mul(const vec2_t* a, const vec2_t* b)
+{
+ vec2_t c;
+ c.x = (a->x * b->y) - (a->y * b->x);
+ c.y = (a->y * b->x) - (a->x * b->y);
+ return c;
+}
+
+GLfloat vec2_length(vec2_t* a)
+{
+ return SDL_sqrtf(SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) );
+}
+
+vec2_t vec2_normalize(vec2_t* a)
+{
+ vec2_t b;
+ GLfloat length = vec2_length(a);
+ b.x = a->x / length;
+ b.y = a->y / length;
+ return b;
+}
diff --git a/08-august/src/math/vector2f.h b/08-august/src/math/vector2f.h
new file mode 100644
index 0000000..bc1d0bc
--- /dev/null
+++ b/08-august/src/math/vector2f.h
@@ -0,0 +1,19 @@
+#ifndef VECTOR2F_H
+#define VECTOR2F_H
+
+#include <GL/glew.h>
+
+typedef struct
+{
+ GLfloat x, y;
+} vec2_t;
+
+extern vec2_t vec2_add(const vec2_t* a, const vec2_t* b);
+extern vec2_t vec2_sub(const vec2_t* a, const vec2_t* b);
+extern vec2_t vec2_scalar_mul(const vec2_t* a, GLfloat scalar);
+extern GLfloat vec2_dot_mul(const vec2_t* a, const vec2_t* b);
+extern vec2_t vec2_cross_mul(const vec2_t* a, const vec2_t* b);
+extern GLfloat vec2_length(vec2_t* a);
+extern vec2_t vec2_normalize(vec2_t* a);
+
+#endif // VECTOR2F_H
diff --git a/08-august/src/math/vector3f.c b/08-august/src/math/vector3f.c
new file mode 100644
index 0000000..2c2878c
--- /dev/null
+++ b/08-august/src/math/vector3f.c
@@ -0,0 +1,59 @@
+#include "vector3f.h"
+#include <SDL2/SDL.h>
+
+vec3_t vec3_add(const vec3_t* a, const vec3_t* b)
+{
+ vec3_t c;
+ c.x = a->x + b->x;
+ c.y = a->y + b->y;
+ c.z = a->z + b->z;
+ return c;
+}
+
+vec3_t vec3_sub(const vec3_t* a, const vec3_t* b)
+{
+ vec3_t c;
+ c.x = a->x - b->x;
+ c.y = a->y - b->y;
+ c.z = a->z - b->z;
+ return c;
+}
+
+vec3_t vec3_scalar_mul(const vec3_t* a, GLfloat scalar)
+{
+ vec3_t c;
+ c.x = a->x * scalar;
+ c.y = a->y * scalar;
+ c.z = a->z * scalar;
+ return c;
+}
+
+GLfloat vec3_dot_mul(const vec3_t* a, const vec3_t* b)
+{
+ return ( (a->x * b->x) + (a->y * b->y) + (a->z * b->z) );
+}
+
+
+vec3_t vec3_cross_mul(const vec3_t* a, const vec3_t* b)
+{
+ vec3_t c;
+ c.x = (a->y * b->z) - (a->z * b->y);
+ c.y = (a->z * b->x) - (a->x * b->z);
+ c.z = (a->x * b->y) - (a->y * b->x);
+ return c;
+}
+
+GLfloat vec3_length(vec3_t* a)
+{
+ return SDL_sqrtf(SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) + SDL_pow(a->z, 2.0f));
+}
+
+vec3_t vec3_normalize(vec3_t* a)
+{
+ vec3_t b;
+ GLfloat length = vec3_length(a);
+ b.x = a->x / length;
+ b.y = a->y / length;
+ b.z = a->z / length;
+ return b;
+}
diff --git a/08-august/src/math/vector3f.h b/08-august/src/math/vector3f.h
new file mode 100644
index 0000000..ab89cb8
--- /dev/null
+++ b/08-august/src/math/vector3f.h
@@ -0,0 +1,19 @@
+#ifndef VECTOR3F_H
+#define VECTOR3F_H
+
+#include <GL/glew.h>
+
+typedef struct
+{
+ GLfloat x, y, z;
+} vec3_t;
+
+extern vec3_t vec3_add(const vec3_t* a, const vec3_t* b);
+extern vec3_t vec3_sub(const vec3_t* a, const vec3_t* b);
+extern vec3_t vec3_scalar_mul(const vec3_t* a, GLfloat scalar);
+extern GLfloat vec3_dot_mul(const vec3_t* a, const vec3_t* b);
+extern vec3_t vec3_cross_mul(const vec3_t* a, const vec3_t* b);
+extern GLfloat vec3_length(vec3_t* a);
+extern vec3_t vec3_normalize(vec3_t* a);
+
+#endif // VECTOR3F_H
diff --git a/08-august/src/math/vector4f.c b/08-august/src/math/vector4f.c
new file mode 100644
index 0000000..57e4925
--- /dev/null
+++ b/08-august/src/math/vector4f.c
@@ -0,0 +1,53 @@
+#include "vector4f.h"
+#include <SDL2/SDL.h>
+
+vec4_t vec4_add(const vec4_t* a, const vec4_t* b)
+{
+ vec4_t c;
+ c.x = a->x + b->x;
+ c.y = a->y + b->y;
+ c.z = a->z + b->z;
+ c.w = a->w + b->w;
+ return c;
+}
+
+vec4_t vec4_sub(const vec4_t* a, const vec4_t* b)
+{
+ vec4_t c;
+ c.x = a->x - b->x;
+ c.y = a->y - b->y;
+ c.z = a->z - b->z;
+ c.w = a->w - b->w;
+ return c;
+}
+
+vec4_t vec4_scalar_mul(const vec4_t* a, GLfloat scalar)
+{
+ vec4_t c;
+ c.x = a->x * scalar;
+ c.y = a->y * scalar;
+ c.z = a->z * scalar;
+ c.w = a->w * scalar;
+ return c;
+}
+
+GLfloat vec4_dot_mul(const vec4_t* a, const vec4_t* b)
+{
+ return ( (a->x * b->x) + (a->y * b->y) + (a->z * b->z) + (a->w * b->w) );
+}
+
+GLfloat vec4_length(vec4_t* a)
+{
+ return SDL_sqrtf(SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) + SDL_pow(a->z, 2.0f) + SDL_pow(a->w, 2.0f) );
+}
+
+vec4_t vec4_normalize(vec4_t* a)
+{
+ vec4_t b;
+ GLfloat length = vec4_length(a);
+ b.x = a->x / length;
+ b.y = a->y / length;
+ b.z = a->z / length;
+ b.w = a->w / length;
+ return b;
+}
diff --git a/08-august/src/math/vector4f.h b/08-august/src/math/vector4f.h
new file mode 100644
index 0000000..9a2f149
--- /dev/null
+++ b/08-august/src/math/vector4f.h
@@ -0,0 +1,18 @@
+#ifndef VECTOR4F_H
+#define VECTOR4F_H
+
+#include <GL/glew.h>
+
+typedef struct
+{
+ GLfloat x, y, z, w;
+} vec4_t;
+
+extern vec4_t vec4_add(const vec4_t *a, const vec4_t *b);
+extern vec4_t vec4_sub(const vec4_t *a, const vec4_t *b);
+extern vec4_t vec4_scalar_mul(const vec4_t *a, GLfloat scalar);
+extern GLfloat vec4_dot_mul(const vec4_t *a, const vec4_t *b);
+extern GLfloat vec4_length(vec4_t *a);
+extern vec4_t vec4_normalize(vec4_t *a);
+
+#endif // VECTOR4F_H
diff --git a/08-august/src/player.c b/08-august/src/player.c
new file mode 100644
index 0000000..47f285b
--- /dev/null
+++ b/08-august/src/player.c
@@ -0,0 +1,62 @@
+#include "player.h"
+#include "util/util_time.h"
+#include "input.h"
+#include "util/util.h"
+
+#define MAX_MOVEMENT_SPEED 10
+#define MAX_ROTATION_SPEED 100
+#define GRAVITY -15
+#define JUMP_POWER 7
+
+static void jump(player_t* player)
+{
+ player->verticalSpeed = JUMP_POWER;
+}
+
+static void check_input(player_t* player)
+{
+ if(Input_isKeyPressed(SDL_SCANCODE_W)) {
+ player->speed = MAX_MOVEMENT_SPEED;
+ } else if(Input_isKeyPressed(SDL_SCANCODE_S)) {
+ player->speed = -MAX_MOVEMENT_SPEED;
+ } else {
+ player->speed = 0.0f;
+ }
+
+ if(Input_isKeyPressed(SDL_SCANCODE_A)) {
+ player->turnSpeed = MAX_ROTATION_SPEED;
+ } else if(Input_isKeyPressed(SDL_SCANCODE_D)) {
+ player->turnSpeed = -MAX_ROTATION_SPEED;
+ } else {
+ player->turnSpeed = 0.0f;
+ }
+
+ if(Input_isKeyPressed(SDL_SCANCODE_SPACE)) {
+ jump(player);
+ }
+}
+
+void Player_Init(player_t* player)
+{
+ player->entity.position = (vec3_t){ 0.0f, 35.0f, 0.0f };
+ player->entity.rotX = player->entity.rotY = player->entity.rotZ = 0;
+ player->speed = player->turnSpeed = player->verticalSpeed = 0;
+}
+
+void Player_Update(player_t *player, terrain_t *terrain)
+{
+ check_input(player);
+ player->entity.rotY += player->turnSpeed * Time_GetFrameTime();
+ player->entity.position.x += SDL_sinf(toRadians(player->entity.rotY)) * player->speed * Time_GetFrameTime();
+ player->entity.position.z += SDL_cosf(toRadians(player->entity.rotY)) * player->speed * Time_GetFrameTime();
+
+ //player->verticalSpeed += GRAVITY * Time_GetFrameTime();
+
+ //player->entity.position.y += player->verticalSpeed * Time_GetFrameTime();
+
+ GLfloat terrainHeight = Terrain_GetHeightOfTerrain(terrain, player->entity.position.x, player->entity.position.z);
+ if(player->entity.position.y - 1.0f < terrainHeight) {
+ //player->entity.position.y = terrainHeight + 1.0f;
+ //player->verticalSpeed = 0.0f;
+ }
+}
diff --git a/08-august/src/player.h b/08-august/src/player.h
new file mode 100644
index 0000000..654dc17
--- /dev/null
+++ b/08-august/src/player.h
@@ -0,0 +1,17 @@
+#ifndef PLAYER_H
+#define PLAYER_H
+
+#include "renderer/entity.h"
+#include "math/vector3f.h"
+#include "terrain.h"
+
+typedef struct
+{
+ entity_t entity;
+ float speed, turnSpeed, verticalSpeed;
+} player_t;
+
+extern void Player_Init(player_t* player);
+extern void Player_Update(player_t* player, terrain_t *terrain);
+
+#endif // PLAYER_H
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
diff --git a/08-august/src/terrain.c b/08-august/src/terrain.c
new file mode 100644
index 0000000..c3e972a
--- /dev/null
+++ b/08-august/src/terrain.c
@@ -0,0 +1,163 @@
+#include "terrain.h"
+#include "math/math_util.h"
+#include "math/vector3f.h"
+#include "util/util.h"
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <math.h>
+
+#define PLANE_SIZE 128
+#define PLANE_MAX_HEIGHT 10
+
+#include <stdlib.h>
+
+#define NUM_ARRAY_ELEMENTS(a) sizeof(a) / sizeof(*a)
+
+static float GetHeight(int x, int y, SDL_Surface* surface)
+{
+ if(x < 0 || x >= surface->w || y < 0 || y >= surface->h)
+ return 0.0f;
+
+ Uint32 pixel = ( (Uint32*)surface->pixels )[y * surface->w + x];
+ Uint8 r, g, b;
+ SDL_GetRGB(pixel, surface->format, &r, &g, &b);
+
+ float height = (float)r / 255.0f;
+
+ return height * 40.0f;
+}
+
+static vec3_t GenerateNomal(int x, int y, SDL_Surface* surface)
+{
+ float hLeft = GetHeight(x-1, y, surface);
+ float hRight = GetHeight(x+1, y, surface);
+ float hUp = GetHeight(x, y+1, surface);
+ float hDown = GetHeight(x, y-1, surface);
+
+ vec3_t normal = { hLeft - hRight, 2.0f, hDown - hUp};
+ return vec3_normalize(&normal);
+}
+
+GLfloat Terrain_GetHeightOfTerrain(terrain_t* terrain, GLfloat x, GLfloat z)
+{
+ GLfloat terrainX = x - terrain->position.x;
+ GLfloat terrainZ = z - terrain->position.z;
+
+ GLfloat gridSquareSize = (float)terrain->l / ( (float)PLANE_SIZE - 1 );
+
+ GLint gridX = (GLint) floor(terrainX / gridSquareSize);
+ GLint gridZ = (GLint) floor(terrainZ / gridSquareSize);
+
+ if(gridX >= PLANE_SIZE - 1 || gridX < 0 || gridZ >= PLANE_SIZE - 1 || gridZ < 0)
+ {
+ printf("called\n");
+ return 0;
+ }
+
+ GLfloat xCoord = fmod(terrainX, gridSquareSize) / gridSquareSize;
+ GLfloat zCoord = fmod(terrainZ, gridSquareSize) / gridSquareSize;
+ GLfloat answer;
+
+ /* Determine in which triangle of the square are we. "Bary Centric Interpolation"*/
+ if(xCoord <= (1 - zCoord)){
+ /* 0, heights[gridX][gridZ], 0) */
+ vec3_t p1 = { 0, terrain->height[ gridX * PLANE_SIZE + gridZ ], 0 };
+ /* 1, heights[gridX + 1][gridZ], 0) */
+ vec3_t p2 = { 1, terrain->height[ (gridX + 1) * PLANE_SIZE + gridZ ], 0};
+ /* 0, heights[gridX][gridZ + 1], 1) */
+ vec3_t p3 = { 0, terrain->height[ gridX * PLANE_SIZE + (gridZ + 1) ], 1};
+
+ vec2_t pos = {xCoord, zCoord};
+
+ answer = baryCentric(&p1, &p2, &p3, &pos);
+ } else {
+ /* (1, heights[gridX + 1][gridZ], 0) */
+ vec3_t p1 = { 1, terrain->height[ (gridX + 1) * PLANE_SIZE + gridZ ], 0 };
+ /* (1, heights[gridX + 1][gridZ + 1], 1) */
+ vec3_t p2 = { 1, terrain->height[ (gridX + 1) * PLANE_SIZE + (gridZ + 1) ], 1};
+ /* (0, heights[gridX][gridZ + 1], 1) */
+ vec3_t p3 = { 0, terrain->height[ gridX * PLANE_SIZE + (gridZ + 1) ], 1};
+ vec2_t pos = {xCoord, zCoord};
+
+ answer = baryCentric(&p1, &p2, &p3, &pos);
+ }
+
+ return answer;
+}
+
+terrain_t *Terrain_Create( int w, int l, const char* heightmap_path, GLuint blendmap, TerrainTexturePack *textures )
+{
+ terrain_t *terrain = (terrain_t*) malloc( sizeof(terrain_t) );
+ terrain->height = (GLfloat*) malloc( sizeof(GLfloat) * PLANE_SIZE * PLANE_SIZE);
+
+ terrain->blendmap = blendmap;
+ terrain->w = w; terrain->l = l;
+ terrain->textures = *textures;
+
+ SDL_Surface* surface = IMG_Load(heightmap_path);
+ if(surface == NULL)
+ Util_FatalError("Heightmap file could not be loaded\n");
+
+ vertex_t data[PLANE_SIZE * PLANE_SIZE];
+ int x, y;
+ for(x = 0; x < PLANE_SIZE; x++)
+ {
+ for(y = 0; y < PLANE_SIZE; y++)
+ {
+ vertex_t* v = &data[y + x * PLANE_SIZE];
+ v->position = (vec3_t){ (float)x / (float)PLANE_SIZE, 0.0f, (float)y / (float)PLANE_SIZE };
+ /* Heightmap cordinates */
+ int image_x = v->position.x * surface->w, image_y = v->position.z * surface->h;
+
+ v->texCoord = (vec2_t){ v->position.x, v->position.z };
+ GLfloat height = GetHeight(image_x, image_y, surface);
+ terrain->height[y + x * PLANE_SIZE] = height;
+ v->position.y = height;
+ v->position.x *= w;
+ v->position.z *= l;
+
+ v->normal = GenerateNomal(image_x, image_y, surface);
+ }
+ }
+
+ int runner = 0;
+ GLushort indices[ (PLANE_SIZE-1) * (PLANE_SIZE-1) * 6 ];
+ for(x = 0; x < PLANE_SIZE-1; x++)
+ {
+ for(y = 0; y < PLANE_SIZE-1; y++)
+ {
+ indices[runner++] = PLANE_SIZE * x + y;
+ indices[runner++] = PLANE_SIZE * x + y + 1;
+ indices[runner++] = PLANE_SIZE * x + y + PLANE_SIZE;
+
+ indices[runner++] = PLANE_SIZE * x + y + 1;
+ indices[runner++] = PLANE_SIZE * x + y + PLANE_SIZE + 1;
+ indices[runner++] = PLANE_SIZE * x + y + PLANE_SIZE;
+ }
+ }
+
+ GLsizeiptr vertexBufferSize = NUM_ARRAY_ELEMENTS(data) * sizeof(vertex_t);
+ GLsizeiptr indexBufferSize = NUM_ARRAY_ELEMENTS(indices) * sizeof(GLushort);
+
+ SDL_FreeSurface(surface);
+
+ terrain->shape = Shape_CreateFromRawData(data, vertexBufferSize, indices, indexBufferSize);
+ return terrain;
+}
+
+void Terrain_Destroy( terrain_t* terrain )
+{
+ if(terrain->height)
+ free(terrain->height);
+
+ Shape_Free(terrain->shape);
+
+ int i;
+ for(i = 0; i < 4; i++)
+ Texture_Destroy(terrain->textures.texture[i]);
+
+ Texture_Destroy(terrain->blendmap);
+ free(terrain);
+}
+
diff --git a/08-august/src/terrain.h b/08-august/src/terrain.h
new file mode 100644
index 0000000..da9828b
--- /dev/null
+++ b/08-august/src/terrain.h
@@ -0,0 +1,27 @@
+#ifndef TERRAIN_H
+#define TERRAIN_H
+
+#include "renderer/shape.h"
+#include "texture.h"
+
+typedef struct
+{
+ GLuint texture[4];
+} TerrainTexturePack;
+
+typedef struct
+{
+ shape_t *shape;
+ GLuint blendmap;
+ TerrainTexturePack textures;
+
+ GLfloat *height;
+ int w, l;
+ vec3_t position;
+} terrain_t;
+
+extern terrain_t *Terrain_Create( int w, int l, const char* heightmap_path, GLuint blendmap, TerrainTexturePack *textures);
+extern GLfloat Terrain_GetHeightOfTerrain(terrain_t* terrain, GLfloat x, GLfloat z);
+extern void Terrain_Destroy( terrain_t *terrain );
+
+#endif // TERRAIN_H
diff --git a/08-august/src/texture.c b/08-august/src/texture.c
new file mode 100644
index 0000000..d1b70d9
--- /dev/null
+++ b/08-august/src/texture.c
@@ -0,0 +1,71 @@
+#include "texture.h"
+#include "util/util.h"
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+
+GLuint Texture_Create2D( const char *path )
+{
+ GLuint ID;
+ SDL_Surface *data = IMG_Load(path);
+ if(data == NULL)
+ Util_FatalError("Texture %s could not be found!\n", path);
+
+ glGenTextures(1, &ID);
+ glBindTexture(GL_TEXTURE_2D, 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);
+
+ 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);
+
+ SDL_FreeSurface(data);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ return ID;
+}
+
+GLuint Texture_CreateCubeMap( const char *paths[6] )
+{
+ GLuint ID;
+ glGenTextures(1, &ID);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 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_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ return ID;
+}
+
+void Texture_Destroy(GLuint ID)
+{
+ glDeleteTextures(1, &ID);
+}
diff --git a/08-august/src/texture.h b/08-august/src/texture.h
new file mode 100644
index 0000000..ea19124
--- /dev/null
+++ b/08-august/src/texture.h
@@ -0,0 +1,10 @@
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+#include <GL/glew.h>
+
+extern GLuint Texture_Create2D( const char *path );
+extern GLuint Texture_CreateCubeMap( const char *paths[6] );
+extern void Texture_Destroy( GLuint ID );
+
+#endif // TEXTURE_H
diff --git a/08-august/src/util/util.c b/08-august/src/util/util.c
new file mode 100644
index 0000000..ad0f1ce
--- /dev/null
+++ b/08-august/src/util/util.c
@@ -0,0 +1,87 @@
+#include "util.h"
+
+#include <SDL2/SDL.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+void Util_FatalError( const char *error, ... )
+{
+ fprintf(stderr, "Fatal Error:\n");
+
+ va_list args;
+ va_start(args, error);
+ vfprintf(stderr, error, args);
+ va_end(args);
+
+ SDL_Quit();
+ exit(1);
+}
+
+char *Util_LoadFile( const char *path )
+{
+ FILE* file = fopen( path, "r" );
+
+ if(file == NULL)
+ {
+ Util_FatalError("File %s could not be found!\n", path);
+ }
+
+ fseek( file, 0, SEEK_END );
+ size_t sizeOfFile = ftell( file );
+ fseek( file, 0, SEEK_SET );
+ char* file_data = (char *) malloc( sizeof(char) * sizeOfFile + 1 );
+ fread( file_data, sizeof(char), sizeOfFile, file );
+ file_data[sizeOfFile] = '\0';
+ fclose(file);
+ return file_data;
+}
+
+float Util_RandomF(float min, float max)
+{
+ return ( min + (float)rand() ) / ( (float)RAND_MAX / (max-min) );
+}
+
+int Util_RandomI(int min, int max)
+{
+ return ( rand() % (max-min) ) + min;
+}
+
+vec3_t
+Util_GetMouseRay(int screenWidth, int screenHeigth, mat4_t *viewMatrix, mat4_t *projectionMatrix,
+ int mouseX, int mouseY)
+{
+ vec4_t eyeCoords;
+ vec3_t mouseRay;
+ /* Normalized device coords NOTE: -y becouse for SDL y = 0 is the top of the screen */
+ GLfloat normalX = ( 2.0f * (GLfloat)mouseX ) / (GLfloat) screenWidth - 1.0f;
+ GLfloat normalY = 1.0f - (2.0f * (GLfloat)mouseY) / (GLfloat) screenHeigth;
+
+ /* clipCoords include 4th component */
+ vec4_t clipCoords = { normalX, normalY, -1.0f, 1.0f };
+
+ /* Remove perpective */
+ {
+ mat4_t invertedProjection = mat4_inverse(projectionMatrix);
+ eyeCoords = mat4_mul_vec4(&invertedProjection, &clipCoords);
+ eyeCoords.z = -1.0f;
+ eyeCoords.w = 0.0f;
+ }
+
+ /* Remove view matrix*/
+ {
+ mat4_t invertedViewMatrix = mat4_inverse(viewMatrix);
+ vec4_t temp = mat4_mul_vec4(&invertedViewMatrix, &eyeCoords);
+
+ mouseRay.x = temp.x;
+ mouseRay.y = temp.y;
+ mouseRay.z = temp.z;
+
+ mouseRay = vec3_normalize(&mouseRay);
+ }
+
+ /* Return the ray in world coordinates */
+ return mouseRay;
+}
diff --git a/08-august/src/util/util.h b/08-august/src/util/util.h
new file mode 100644
index 0000000..7227547
--- /dev/null
+++ b/08-august/src/util/util.h
@@ -0,0 +1,25 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include "../math/matrix4x4.h"
+
+#define toRadians(degrees) (degrees * 3.1415926 / 180.0f)
+#define toDegrees(radians) (radians * 180.0f / 3.1415926)
+
+#ifdef DEBUG
+#include <stdio.h>
+#define myAssert(expr) expr ? 1==1 : fprintf(stderr, "The expresion was not true\n")
+#else
+#define myAssert(expr)
+#endif // DEBUG
+
+extern void Util_FatalError( const char* error, ... );
+extern char* Util_LoadFile( const char* path );
+extern float Util_RandomF(float min, float max);
+extern int Util_RandomI(int min, int max);
+
+extern vec3_t
+Util_GetMouseRay(int screenWidth, int screenHeigth, mat4_t *viewMatrix, mat4_t *projectionMatrix,
+ int mouseX, int mouseY);
+
+#endif // UTIL_H
diff --git a/08-august/src/util/util_time.c b/08-august/src/util/util_time.c
new file mode 100644
index 0000000..b601379
--- /dev/null
+++ b/08-august/src/util/util_time.c
@@ -0,0 +1,52 @@
+#include "util_time.h"
+
+static struct
+{
+ float max_ticks_per_frame; //< cuantos ticks (tiempo demora) un frame
+ Uint32 counted_frames; //< cuantos frames han pasado
+ Uint32 start_ticks; //< ticks al iniciar la iteracion del loop
+ Uint32 beg_ticks; //< ticks desde el inicio del juego
+ Uint32 time_per_frame;
+} TIME = {
+ 1000.0f / 60.0f,
+ 0, 0, 0, 0
+};
+
+void Time_Init()
+{
+ TIME.beg_ticks = SDL_GetTicks();
+}
+
+void Time_Begin()
+{
+ TIME.start_ticks = SDL_GetTicks();
+}
+
+float Time_End()
+{
+ TIME.counted_frames += 1;
+ float FPS = TIME.counted_frames / ( (float)(SDL_GetTicks() - TIME.beg_ticks) / 1000.f );
+
+ float frameTicks = (float)(SDL_GetTicks() - TIME.start_ticks);
+ TIME.time_per_frame = frameTicks;
+ if(frameTicks < TIME.max_ticks_per_frame){
+ SDL_Delay( (Uint32)(TIME.max_ticks_per_frame - frameTicks) );
+ }
+
+ return FPS;
+}
+
+float Time_GetFrameTime()
+{
+ return (float)TIME.time_per_frame / 1000.0f;
+}
+
+void Time_SetMaxFramesPerSecond(Uint32 frames)
+{
+ TIME.max_ticks_per_frame = 1000.0f / (float)frames;
+}
+
+Uint32 Time_GetCountedFrames()
+{
+ return TIME.counted_frames;
+}
diff --git a/08-august/src/util/util_time.h b/08-august/src/util/util_time.h
new file mode 100644
index 0000000..3c3e470
--- /dev/null
+++ b/08-august/src/util/util_time.h
@@ -0,0 +1,13 @@
+#ifndef UTIL_TIME_H
+#define UTIL_TIME_H
+
+#include <SDL2/SDL.h>
+
+extern void Time_Init( void );
+extern void Time_Begin( void );
+extern float Time_End( void );
+extern void Time_SetMaxFramesPerSecond(Uint32 frames);
+extern float Time_GetFrameTime( void );
+extern Uint32 Time_GetCountedFrames( void );
+
+#endif // UTIL_TIME_H
diff --git a/08-august/src/vertex.h b/08-august/src/vertex.h
new file mode 100644
index 0000000..7ac2ec8
--- /dev/null
+++ b/08-august/src/vertex.h
@@ -0,0 +1,17 @@
+#ifndef VERTEX_H
+#define VERTEX_H
+
+#include <GL/glew.h>
+#include "math/vector2f.h"
+#include "math/vector3f.h"
+#include "math/vector4f.h"
+
+typedef struct
+{
+ vec3_t position;
+ vec2_t texCoord;
+ vec3_t normal;
+ vec3_t tangent;
+} vertex_t;
+
+#endif // VERTEX_H