diff options
| author | Thomas Guillermo Albers Raviola <thomas@thomaslabs.org> | 2026-01-16 23:02:32 +0100 |
|---|---|---|
| committer | Thomas Guillermo Albers Raviola <thomas@thomaslabs.org> | 2026-01-16 23:02:32 +0100 |
| commit | 6b8af9cf83851c075c6c9514b1deaa931c2b19a4 (patch) | |
| tree | 428986b49c32e21d3f7a3c2dfa41858ae0153209 /09-september/tomcat | |
Initial commit
Diffstat (limited to '09-september/tomcat')
42 files changed, 3496 insertions, 0 deletions
diff --git a/09-september/tomcat/gui/widget.c b/09-september/tomcat/gui/widget.c new file mode 100644 index 0000000..507173a --- /dev/null +++ b/09-september/tomcat/gui/widget.c @@ -0,0 +1,12 @@ +#include "widget.h" +#include <stdlib.h> + +widget_t *Widget_CreateImage(Texture *texture, int x, int y, int w, int h) +{ + return NULL; +} + +void Widget_Destroy(widget_t *widget) +{ + free(widget); +} diff --git a/09-september/tomcat/gui/widget.h b/09-september/tomcat/gui/widget.h new file mode 100644 index 0000000..1b1c62d --- /dev/null +++ b/09-september/tomcat/gui/widget.h @@ -0,0 +1,13 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include "GL/glew.h" +#include "../renderer/renderer_types.h" + +typedef struct +{ + int x, y, w, h; + Texture *texture; +} widget_t; + +#endif // WIDGET_H diff --git a/09-september/tomcat/input.c b/09-september/tomcat/input.c new file mode 100644 index 0000000..8384ceb --- /dev/null +++ b/09-september/tomcat/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/09-september/tomcat/input.h b/09-september/tomcat/input.h new file mode 100644 index 0000000..92876ca --- /dev/null +++ b/09-september/tomcat/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/09-september/tomcat/math/math_util.c b/09-september/tomcat/math/math_util.c new file mode 100644 index 0000000..1285f3d --- /dev/null +++ b/09-september/tomcat/math/math_util.c @@ -0,0 +1,10 @@ +#include "math_util.h" + +float baryCentric(Vec3 *p1, Vec3 *p2, Vec3 *p3, Vec2 *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/09-september/tomcat/math/math_util.h b/09-september/tomcat/math/math_util.h new file mode 100644 index 0000000..5582dc7 --- /dev/null +++ b/09-september/tomcat/math/math_util.h @@ -0,0 +1,8 @@ +#ifndef MATH_UTIL_H +#define MATH_UTIL_H + +#include "vector.h" + +extern float baryCentric(Vec3 *p1, Vec3 *p2, Vec3 *p3, Vec2 *pos); + +#endif // MATH_UTIL_H diff --git a/09-september/tomcat/math/matrix4x4.c b/09-september/tomcat/math/matrix4x4.c new file mode 100644 index 0000000..d4bea71 --- /dev/null +++ b/09-september/tomcat/math/matrix4x4.c @@ -0,0 +1,326 @@ +#include "matrix4x4.h" +#include "../util/util.h" +#include <SDL2/SDL.h> + +void mat4_identity(Mat4 *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 mat4_inverse(const Mat4 *a) +{ + Mat4 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 mat4_mul(const Mat4 *a, const Mat4 *b) +{ + int i, j, k; + GLfloat sum = 0.0f; + Mat4 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 mat4_translate(const Vec3 *a) +{ + Mat4 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 mat4_scale(GLfloat x, GLfloat y, GLfloat z) +{ + Mat4 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 mat4_rotate(GLfloat degrees, const Vec3 *a) +{ + Mat4 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 mat4_rotate_x(GLfloat degrees) +{ + Mat4 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 mat4_rotate_y(GLfloat degrees) +{ + Mat4 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 mat4_rotate_z(GLfloat degrees) +{ + Mat4 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 mat4_perspective(GLfloat fov, GLfloat aspect, GLfloat zNear, GLfloat zFar) +{ + Mat4 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 +mat4_orthographic(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) +{ + Mat4 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] = 2.0f / (near - far); + + a.data[0 + 3 * 4] = (left + right) / (left - right); + a.data[1 + 3 * 4] = (bottom + top) / (bottom - top); + a.data[2 + 3 * 4] = (far + near) / (far - near); + + return a; +} + +Mat4 mat4_lookAt(Vec3 *eye, Vec3 *center, Vec3 *up) +{ + Vec3 temp = vec3_sub(center, eye); + + Vec3 f = vec3_normalize(&temp); + Vec3 u = vec3_normalize(up); + temp = vec3_cross_mul(&f, &u); + Vec3 s = vec3_normalize(&temp); + u = vec3_cross_mul(&s, &f); + + Mat4 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 mat4_mul_vec3(const Mat4 *a, const Vec3 *b) +{ + Vec3 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 mat4_mul_vec4(const Mat4 *a, const Vec4 *b) +{ + Vec4 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/09-september/tomcat/math/matrix4x4.h b/09-september/tomcat/math/matrix4x4.h new file mode 100644 index 0000000..74918fe --- /dev/null +++ b/09-september/tomcat/math/matrix4x4.h @@ -0,0 +1,39 @@ +#ifndef MATRIX4X4_H +#define MATRIX4X4_H + +#include <GL/glew.h> +#include "vector.h" + +/* accesing data: row + column * width */ +typedef struct +{ + GLfloat data[16]; +} Mat4; + +extern void mat4_identity(Mat4 *a); +extern Mat4 mat4_inverse(const Mat4 *a); +extern Mat4 mat4_mul(const Mat4 *a, const Mat4 *b); + +extern Mat4 mat4_translate(const Vec3 *a); +extern Mat4 mat4_scale(GLfloat x, GLfloat y, GLfloat z); +extern Mat4 mat4_rotate_x(GLfloat degrees); +extern Mat4 mat4_rotate_y(GLfloat degrees); +extern Mat4 mat4_rotate_z(GLfloat degrees); +extern Mat4 mat4_rotate(GLfloat degrees, const Vec3 *a); + +extern Mat4 +mat4_perspective(GLfloat fov, GLfloat aspect, GLfloat zNear, GLfloat zFar); + +extern Mat4 +mat4_orthographic(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far); + +extern Mat4 +mat4_lookAt(Vec3 *eye, Vec3 *center, Vec3 *up); + +extern Vec3 +mat4_mul_vec3(const Mat4 *a, const Vec3 *b); + +extern Vec4 +mat4_mul_vec4(const Mat4 *a, const Vec4 *b); + +#endif // MATRIX4X4_H diff --git a/09-september/tomcat/math/vector.c b/09-september/tomcat/math/vector.c new file mode 100644 index 0000000..230de51 --- /dev/null +++ b/09-september/tomcat/math/vector.c @@ -0,0 +1,177 @@ +#include "vector.h" +#include <SDL2/SDL.h> + +Vec4 vec4_add(const Vec4 *a, const Vec4 *b) +{ + Vec4 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 vec4_sub(const Vec4 *a, const Vec4 *b) +{ + Vec4 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 vec4_scalar_mul(const Vec4 *a, GLfloat scalar) +{ + Vec4 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 *a, const Vec4 *b) +{ + return ( (a->x * b->x) + (a->y * b->y) + (a->z * b->z) + (a->w * b->w) ); +} + +GLfloat vec4_length(Vec4 *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) ); +} + +GLfloat vec4_length2(Vec4 *a) +{ + return ( 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 vec4_normalize(Vec4 *a) +{ + Vec4 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; +} + +Vec3 vec3_add(const Vec3 *a, const Vec3 *b) +{ + Vec3 c; + c.x = a->x + b->x; + c.y = a->y + b->y; + c.z = a->z + b->z; + return c; +} + +Vec3 vec3_sub(const Vec3 *a, const Vec3 *b) +{ + Vec3 c; + c.x = a->x - b->x; + c.y = a->y - b->y; + c.z = a->z - b->z; + return c; +} + +Vec3 vec3_scalar_mul(const Vec3 *a, GLfloat scalar) +{ + Vec3 c; + c.x = a->x * scalar; + c.y = a->y * scalar; + c.z = a->z * scalar; + return c; +} + +GLfloat vec3_dot_mul(const Vec3 *a, const Vec3 *b) +{ + return ( (a->x * b->x) + (a->y * b->y) + (a->z * b->z) ); +} + + +Vec3 vec3_cross_mul(const Vec3 *a, const Vec3 *b) +{ + Vec3 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 *a) +{ + return SDL_sqrtf(SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) + SDL_pow(a->z, 2.0f)); +} + +GLfloat vec3_length2(Vec3 *a) +{ + return ( SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) + SDL_pow(a->z, 2.0f) ); +} + +Vec3 vec3_normalize(Vec3 *a) +{ + Vec3 b; + GLfloat length = vec3_length(a); + b.x = a->x / length; + b.y = a->y / length; + b.z = a->z / length; + return b; +} + +Vec2 vec2_add(const Vec2 *a, const Vec2 *b) +{ + Vec2 c; + c.x = a->x + b->x; + c.y = a->y + b->y; + return c; +} + +Vec2 vec2_sub(const Vec2 *a, const Vec2 *b) +{ + Vec2 c; + c.x = a->x - b->x; + c.y = a->y - b->y; + return c; +} + +Vec2 vec2_scalar_mul(const Vec2 *a, GLfloat scalar) +{ + Vec2 c; + c.x = a->x * scalar; + c.y = a->y * scalar; + return c; +} + +GLfloat vec2_dot_mul(const Vec2 *a, const Vec2 *b) +{ + return ( (a->x * b->x) + (a->y * b->y) ); +} + + +Vec2 vec2_cross_mul(const Vec2 *a, const Vec2 *b) +{ + Vec2 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 *a) +{ + return SDL_sqrtf(SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) ); +} + +GLfloat vec2_length2(Vec2 *a) +{ + return ( SDL_pow(a->x, 2.0f) + SDL_pow(a->y, 2.0f) ); +} + +Vec2 vec2_normalize(Vec2 *a) +{ + Vec2 b; + GLfloat length = vec2_length(a); + b.x = a->x / length; + b.y = a->y / length; + return b; +} diff --git a/09-september/tomcat/math/vector.h b/09-september/tomcat/math/vector.h new file mode 100644 index 0000000..173fc11 --- /dev/null +++ b/09-september/tomcat/math/vector.h @@ -0,0 +1,47 @@ +#ifndef VECTOR4F_H +#define VECTOR4F_H + +#include <GL/glew.h> + +typedef struct _Vec4 +{ + GLfloat x, y, z, w; +} Vec4; + +extern Vec4 vec4_add(const Vec4 *a, const Vec4 *b); +extern Vec4 vec4_sub(const Vec4 *a, const Vec4 *b); +extern Vec4 vec4_scalar_mul(const Vec4 *a, GLfloat scalar); +extern GLfloat vec4_dot_mul(const Vec4 *a, const Vec4 *b); +extern GLfloat vec4_length(Vec4 *a); +extern GLfloat vec4_length2(Vec4 *a); +extern Vec4 vec4_normalize(Vec4 *a); + +typedef struct _Vec3 +{ + GLfloat x, y, z; +} Vec3; + +extern Vec3 vec3_add(const Vec3 *a, const Vec3 *b); +extern Vec3 vec3_sub(const Vec3 *a, const Vec3 *b); +extern Vec3 vec3_scalar_mul(const Vec3 *a, GLfloat scalar); +extern GLfloat vec3_dot_mul(const Vec3 *a, const Vec3 *b); +extern Vec3 vec3_cross_mul(const Vec3 *a, const Vec3 *b); +extern GLfloat vec3_length(Vec3 *a); +extern GLfloat vec3_length2(Vec3 *a); +extern Vec3 vec3_normalize(Vec3 *a); + +typedef struct _Vec2 +{ + GLfloat x, y; +} Vec2; + +extern Vec2 vec2_add(const Vec2 *a, const Vec2 *b); +extern Vec2 vec2_sub(const Vec2 *a, const Vec2 *b); +extern Vec2 vec2_scalar_mul(const Vec2 *a, GLfloat scalar); +extern GLfloat vec2_dot_mul(const Vec2 *a, const Vec2 *b); +extern Vec2 vec2_cross_mul(const Vec2 *a, const Vec2 *b); +extern GLfloat vec2_length(Vec2 *a); +extern GLfloat vec2_length2(Vec2 *a); +extern Vec2 vec2_normalize(Vec2 *a); + +#endif // VECTOR4F_H diff --git a/09-september/tomcat/not_in_use/fbo.c b/09-september/tomcat/not_in_use/fbo.c new file mode 100644 index 0000000..5880276 --- /dev/null +++ b/09-september/tomcat/not_in_use/fbo.c @@ -0,0 +1,108 @@ +#include "fbo.h" +#include "renderer.h" +#include "../util/util.h" + +#include <string.h> +#include <stdlib.h> + +Fbo *fbo_new(const char *name, GLint width, GLint height) +{ + Fbo *fbo; + + if(strlen(name) >= MAX_PATH_LENGTH) + Util_FatalError("Fbo name is too long: %s\n", name); + + if(render.num_fbos >= MAX_FBOS) + return NULL; + + fbo = malloc(sizeof(Fbo)); + memset(fbo, 0, sizeof(Fbo)); + + glGenFramebuffers(1, &fbo->frame_buffer); + + return fbo; +} + +void fbo_attach_buffer(Fbo *fbo, GLenum format, int index) +{ + GLenum attachment; + GLuint *buffer; + + switch(format) + { + case GL_RGB: + case GL_RGBA: + fbo->color_format = format; + buffer = &fbo->color_buffer[index]; + attachment = GL_COLOR_ATTACHMENT0 + index; + break; + + case GL_DEPTH_COMPONENT: + fbo->depth_format = format; + buffer = &fbo->depth_buffer; + attachment = GL_DEPTH_ATTACHMENT; + break; + + default: + Util_FatalError("Invalid fbo buffer format\n"); + } + + if(*buffer == 0) + { + glGenRenderbuffers(1, buffer); + glBindRenderbuffer(GL_RENDERBUFFER, *buffer); + glRenderbufferStorage(GL_RENDERBUFFER, format, fbo->width, fbo->height); + + fbo_bind(fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, *buffer); + fbo_bind(NULL); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } +} + +void fbo_attach_texture(Fbo *fbo, Texture *t, GLenum attachment) +{ + int index; + + fbo_bind(fbo); + if(attachment >= GL_COLOR_ATTACHMENT0 && attachment < GL_COLOR_ATTACHMENT0 + 8) + { + glFramebufferTexture(GL_FRAMEBUFFER, attachment, t->tex_id, 0); + glDrawBuffers(1, &attachment); + + index = attachment - GL_COLOR_ATTACHMENT0; + fbo->color_textures[index] = t; + } + + fbo_bind(NULL); +} + +void fbo_bind(Fbo *fbo) +{ + if(fbo) + { + glBindFramebuffer(GL_FRAMEBUFFER, fbo->frame_buffer); + glViewport(0, 0, fbo->width, fbo->height); + } + else + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, render.window->Width, render.window->Height); + } +} + +void fbo_purge(Fbo *fbo) +{ + int i; + + for(i = 0; i < 8; i++) + if(fbo->color_buffer[i]) + { + glDeleteRenderbuffers(1, &fbo->color_buffer[i]); + } + if(fbo->depth_buffer) + glDeleteRenderbuffers(1, &fbo->depth_buffer); + + if(fbo->frame_buffer) + glDeleteFramebuffers(1, &fbo->frame_buffer); +} diff --git a/09-september/tomcat/not_in_use/fbo.h b/09-september/tomcat/not_in_use/fbo.h new file mode 100644 index 0000000..244cb7f --- /dev/null +++ b/09-september/tomcat/not_in_use/fbo.h @@ -0,0 +1,35 @@ +#ifndef FBO_H +#define FBO_H + +#include "../shared.h" + +struct _Texture; + +typedef struct _Fbo +{ + char _name[MAX_PATH_LENGTH]; + + GLuint frame_buffer; /** Actual fbo object**/ + + /** color_texture when you want to render to a + texture and color_buffer when you want to render + to a RenderBuffer **/ + struct _Texture *color_textures[8]; + GLuint color_buffer[8]; + GLenum color_format; + + struct _Texture *depth_texture; + GLuint depth_buffer; + GLenum depth_format; + + GLint width; + GLint height; +} Fbo; + +extern Fbo *fbo_new(const char *name, GLint width, GLint height); +extern void fbo_attach_buffer(Fbo *fbo, GLenum format, int index); +extern void fbo_attach_texture(Fbo *fbo, struct _Texture *t, GLenum attachment); +extern void fbo_bind(Fbo *fbo); +extern void fbo_purge(Fbo *fbo); + +#endif // FBO_H diff --git a/09-september/tomcat/particles/particles.c b/09-september/tomcat/particles/particles.c new file mode 100644 index 0000000..5e99e06 --- /dev/null +++ b/09-september/tomcat/particles/particles.c @@ -0,0 +1,153 @@ +#include "particles.h" +#include "../util/util_time.h" +#include "../util/util.h" + +#include <string.h> +#include <stdlib.h> + +ParticleManager particles; + +static int compare_particles(const void *_a, const void *_b); + +void Particles_Init() +{ + memset( &particles, 0, sizeof(ParticleManager) ); +} + +ParticleSystem *Particles_AddSystem() +{ + if(particles.num_systems >= MAX_PARTICLES_SYSTEMS) + return NULL; + + ParticleSystem *s = malloc( sizeof(ParticleSystem) ); + particles.systems[particles.num_systems] = s; + memset( s, 0, sizeof(ParticleSystem) ); + + particles.num_systems += 1; + + return s; +} + +void Particles_RemoveSystem(ParticleSystem *system) +{ + int index = &system - particles.systems; + + if(index > MAX_PARTICLES_SYSTEMS || index < 0) + { + fprintf(stderr, "Invalid particle system!\n"); + return; + } + /* TODO: Finish this function */ +} + +void Particles_EmitParticle(ParticleSystem *system, Particle *p) +{ + if(system->num_particles >= MAX_PARTICLES_PER_SYSTEM) + return; + + Particle *dest = &system->particles[system->num_particles]; + memcpy(dest, p, sizeof(Particle)); + + system->num_particles += 1; +} + +void Particles_Update(const Vec3 *camera_position) +{ + Particle *c = NULL; /* Current particle */ + ParticleSystem *s = NULL; /* Current particle system */ + Texture *t = NULL; /* Texture of the current system */ + Vec3 d; /* Vector for calculating the distance to the camera */ + Vec3 velocity; + + int i, j; + for(i = 0; i < particles.num_systems; i++) + { + s = particles.systems[i]; + t = s->texture; + + /* We ceil it so we dont truncate the decimal part and get always 0 */ + int particles_to_emit = (int)ceil( s->emit_rate * Time_GetFrameTime() ); + + /* Emit the automatically emited particles */ + for(j = 0; j < particles_to_emit; j++) + { + velocity.x = Util_RandomF(0.0f, 50.0f); + velocity.y = Util_RandomF(0.0f, 50.0f); + velocity.z = Util_RandomF(0.0f, 50.0f); + velocity = vec3_normalize(&velocity); + + if(s->num_particles >= MAX_PARTICLES_PER_SYSTEM) + break; /* So we dont overflow */ + + c = &s->particles[s->num_particles ++]; + memset(c, 0, sizeof(Particle)); + + c->life_length = s->life_length; + c->position = s->position; + c->scale = 10.0f; + c->weight = s->weight; + c->velocity = vec3_scalar_mul(&velocity, s->speed); + } + + for(j = 0; j < s->num_particles; j++) + { + c = &s->particles[j]; + + /* Update each particle -.- */ + c->velocity.y += c->weight * Time_GetFrameTime(); + Vec3 velocity = vec3_scalar_mul(&c->velocity, Time_GetFrameTime()); + c->position = vec3_add(&c->position, &velocity); + + /* Update animations + * How far into its life the particle is */ + float life_factor = c->elapsed_time / c->life_length; + /* How many different stages there are */ + int stage_count = t->number_of_rows * t->number_of_rows; + float atlas_progression = life_factor * stage_count; + int index = floor(atlas_progression); + + int column = index % t->number_of_rows; + int row = index / t->number_of_rows; + c->tex_offset.x = (float)column / t->number_of_rows; + c->tex_offset.y = (float)row / t->number_of_rows; + /* End of animation update */ + + c->elapsed_time += Time_GetFrameTime(); + + if(c->elapsed_time > c->life_length) + { + /* "Kill" the particle by overriding it with the last particle on the array */ + memmove( c, &s->particles[s->num_particles], sizeof(Particle) ); + s->num_particles -= 1; + } + else + { + d = vec3_sub(camera_position, &c->position); + c->distance_to_camera = vec3_length2(&d); + } + } + /*Sort all particles on system by distance to camera */ + qsort(s->particles, s->num_particles, sizeof(Particle), compare_particles); + } +} + +void Particles_Shutdown() +{ + int i; + for(i = 0; i < particles.num_systems; i++) + { + if(particles.systems[i]) + free(particles.systems[i]); + } + memset(&particles, 0, sizeof(ParticleManager)); +} + +static int compare_particles(const void *_a, const void *_b) +{ + Particle *a = (Particle *)_a; + Particle *b = (Particle *)_b; + + if(a->distance_to_camera < b->distance_to_camera) return -1; + if(a->distance_to_camera > b->distance_to_camera) return 1; + return 0; +} diff --git a/09-september/tomcat/particles/particles.h b/09-september/tomcat/particles/particles.h new file mode 100644 index 0000000..8404ff4 --- /dev/null +++ b/09-september/tomcat/particles/particles.h @@ -0,0 +1,62 @@ +#ifndef PARTICLES_H +#define PARTICLES_H + +#include "../renderer/renderer_types.h" +#include "../math/vector.h" + +#define MAX_PARTICLES_PER_SYSTEM 10000 +#define MAX_PARTICLES_SYSTEMS 10 + +typedef struct _Particle +{ + Vec3 position; + Vec3 velocity; + + Vec2 tex_offset; /* Used for animating */ + + GLfloat weight; /* How does the gravity affect the particle (In theory it should be a vector)*/ + GLfloat life_length; + GLfloat rotation; + GLfloat scale; + GLfloat distance_to_camera; /* Used for sorting the systems */ + + GLfloat elapsed_time; +} Particle; + +typedef struct _ParticleSystem +{ + Vec3 position; + + GLint emit_rate; + GLfloat speed; + GLfloat weight; + GLfloat life_length; + + bool additive; /* Additive vs alpha blending */ + + Texture *texture; + Particle particles[MAX_PARTICLES_PER_SYSTEM]; + int num_particles; + +} ParticleSystem; + +typedef struct +{ + ParticleSystem *systems[MAX_PARTICLES_SYSTEMS]; + int num_systems; +} ParticleManager; + +extern ParticleManager particles; + +extern void Particles_Init(); + +extern ParticleSystem *Particles_AddSystem(); +extern void Particles_RemoveSystem(ParticleSystem *system); +/* Used for manual emission */ +extern void Particles_EmitParticle(ParticleSystem *system, Particle *p); +/* Removes a particle if it "dies" */ +extern void Particles_Update(const Vec3 *camera_position); +/* We need to delete all dynamically allocated particles that still remains */ +extern void Particles_Shutdown(); + +#endif // PARTICLES_H diff --git a/09-september/tomcat/renderer/camera.c b/09-september/tomcat/renderer/camera.c new file mode 100644 index 0000000..8a0c620 --- /dev/null +++ b/09-september/tomcat/renderer/camera.c @@ -0,0 +1,95 @@ +#include "camera.h" + +#include "../util/util_time.h" + +static const float movementSpeed = 40.0f; + +Camera *camera_new() +{ + Camera *camera; + camera = malloc( sizeof(Camera) ); + + camera->position = (Vec3){ 0.0f, 6.0f, 0.0f }; + camera->viewDirection = (Vec3){ 0.5f, 0.0f, -1.0f }; + camera->needsUpdate = true; + camera->up = (Vec3){ 0.0f, 1.0f, 0.0f }; + + return camera; +} + +void camera_move_up(Camera* camera) +{ + Vec3 temp = vec3_scalar_mul(&camera->up, movementSpeed * Time_GetFrameTime()); + camera->position = vec3_add(&camera->position, &temp); +} + +void camera_move_down(Camera* camera) +{ + Vec3 temp = vec3_scalar_mul(&camera->up, -movementSpeed * Time_GetFrameTime()); + camera->position = vec3_add(&camera->position, &temp); +} + +void camera_move_left(Camera* camera) +{ + Vec3 strafeDirection = vec3_cross_mul(&camera->viewDirection, &camera->up); + strafeDirection = vec3_scalar_mul(&strafeDirection, -movementSpeed * Time_GetFrameTime()); + camera->position = vec3_add(&camera->position, &strafeDirection); +} + +void camera_move_right(Camera* camera) +{ + Vec3 strafeDirection = vec3_cross_mul(&camera->viewDirection, &camera->up); + strafeDirection = vec3_scalar_mul(&strafeDirection, movementSpeed * Time_GetFrameTime()); + camera->position = vec3_add(&camera->position, &strafeDirection); +} + +void camera_move_foward(Camera* camera) +{ + Vec3 temp = vec3_scalar_mul(&camera->viewDirection, movementSpeed * Time_GetFrameTime()); + camera->position = vec3_add(&camera->position, &temp); +} + +void camera_move_backward(Camera* camera) +{ + Vec3 temp = vec3_scalar_mul(&camera->viewDirection, -movementSpeed * Time_GetFrameTime()); + camera->position = vec3_add(&camera->position, &temp); +} + +void camera_mouse_update(Camera *camera, const Vec2 *newMousePosition) +{ + Vec2 mouseDelta = vec2_sub(newMousePosition, &camera->mousePosition); + + /* El if evita que el mouse se teletrasporte al cambiar de posicion muy rapido */ + if(vec2_length(&mouseDelta) > 50.0f){ + camera->mousePosition = *newMousePosition; + return; + } + + Vec3 verticalRotation = vec3_cross_mul(&camera->viewDirection, &camera->up); + + Mat4 temp = mat4_rotate(mouseDelta.x * -0.5f, &camera->up); + + camera->viewDirection = mat4_mul_vec3(&temp, &camera->viewDirection); + + temp = mat4_rotate(mouseDelta.y * -0.5f, &verticalRotation); + camera->viewDirection = mat4_mul_vec3(&temp, &camera->viewDirection); + + camera->mousePosition = *newMousePosition; + + camera->needsUpdate = true; +} + +void camera_free(Camera *camera) +{ + free(camera); +} + +Mat4 camera_get_model_to_view_matrix(Camera* camera) +{ + if(camera->needsUpdate) + { + Vec3 temp = vec3_add(&camera->position, &camera->viewDirection); + camera->viewMatrix = mat4_lookAt(&camera->position, &temp, &camera->up); + } + return camera->viewMatrix; +} diff --git a/09-september/tomcat/renderer/camera.h b/09-september/tomcat/renderer/camera.h new file mode 100644 index 0000000..0c63178 --- /dev/null +++ b/09-september/tomcat/renderer/camera.h @@ -0,0 +1,32 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include "../math/matrix4x4.h" +#include "../math/vector.h" +#include <stdbool.h> + +typedef struct +{ + Vec3 position; + Vec3 viewDirection; + Vec3 up; + Mat4 projectionMatrix; + Mat4 viewMatrix; + Vec2 mousePosition; + bool needsUpdate; +} Camera; + +extern Camera *camera_new(); +extern void camera_move_up(Camera *camera); +extern void camera_move_down(Camera *camera); +extern void camera_move_left(Camera *camera); +extern void camera_move_right(Camera *camera); +extern void camera_move_foward(Camera *camera); +extern void camera_move_backward(Camera *camera); +extern void camera_mouse_update(Camera *camera, const Vec2 *newMousePosition); +extern void camera_free(Camera *camera); + +/* Consigue la viewMatrix */ +extern Mat4 camera_get_model_to_view_matrix(Camera *camera); + +#endif // CAMERA_H diff --git a/09-september/tomcat/renderer/entity.c b/09-september/tomcat/renderer/entity.c new file mode 100644 index 0000000..d5e7429 --- /dev/null +++ b/09-september/tomcat/renderer/entity.c @@ -0,0 +1,33 @@ +#include "renderer.h" + +Mat4 Entity_GetModelTransform(Entity* entity) +{ + Mat4 temp; + Mat4 rotation = mat4_rotate_x(entity->rotX); + temp = mat4_rotate_y(entity->rotY); + rotation = mat4_mul(&rotation, &temp); + temp = mat4_rotate_z(entity->rotZ); + rotation = mat4_mul(&rotation, &temp); + + temp = mat4_translate(&entity->position); + + Mat4 modelTransform = mat4_mul(&temp, &rotation); + temp = mat4_scale(entity->scale[0], entity->scale[1], entity->scale[2]); + modelTransform = mat4_mul(&modelTransform, &temp); + + return modelTransform; +} + +Vec2 Entity_GetTexOffset(Entity *entity) +{ + /* Offset inside a texture atlas should default to (0, 0)*/ + Vec2 tex_offset; + Texture *t = entity->texture; + + int column = entity->index % t->number_of_rows; + int row = entity->index / t->number_of_rows; + tex_offset.x = (float)column / t->number_of_rows; + tex_offset.y = (float)row / t->number_of_rows; + + return tex_offset; +} diff --git a/09-september/tomcat/renderer/mesh.c b/09-september/tomcat/renderer/mesh.c new file mode 100644 index 0000000..7ef27dc --- /dev/null +++ b/09-september/tomcat/renderer/mesh.c @@ -0,0 +1,146 @@ +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#include "mesh.h" +#include "renderer.h" + +#define NUM_ARRAY_ELEMENTS(a) sizeof(a) / sizeof(*a) + +Mesh *mesh_new(vertex_t* vertices, GLsizeiptr vertexBuffersize, + GLushort* indices, GLsizeiptr indexBuffersize) +{ + Mesh *mesh; + mesh = malloc( sizeof(Mesh) ); + memset(mesh, 0, sizeof(Mesh) ); + + render.meshes[render.num_meshes] = mesh; + render.num_meshes += 1; + + mesh->num_indices = ( indexBuffersize / sizeof(GLushort) ); + + glGenVertexArrays(1, &mesh->vao); + glGenBuffers(1, &mesh->vbo); + glGenBuffers(1, &mesh->ebo); + + glBindVertexArray(mesh->vao); + + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, vertexBuffersize, vertices, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffersize, indices, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, position) ); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, texCoord) ); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, normal) ); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, tangent) ); + + glBindVertexArray(0); + return mesh; +} + +Mesh *mesh_make_skybox(float size) +{ + Mesh *mesh; + mesh = malloc( sizeof(Mesh) ); + memset(mesh, 0, sizeof(Mesh) ); + + render.meshes[render.num_meshes] = mesh; + render.num_meshes += 1; + + Vec3 positions[] = + { + {-size, size, -size}, {-size, -size, -size}, {+size, -size, -size}, + {+size, -size, -size}, {+size, +size, -size}, {-size, +size, -size}, + + {-size, -size, +size}, {-size, -size, -size}, {-size, +size, -size}, + {-size, +size, -size}, {-size, +size, +size}, {-size, -size, +size}, + + {+size, -size, -size}, {+size, -size, +size}, {+size, +size, +size}, + {+size, +size, +size}, {+size, +size, -size}, {+size, -size, -size}, + + {-size, -size, +size}, {-size, +size, +size}, {+size, +size, +size}, + {+size, +size, +size}, {+size, -size, +size}, {-size, -size, +size}, + + {-size, +size, -size}, {+size, +size, -size}, {+size, +size, +size}, + {+size, +size, +size}, {-size, +size, +size}, {-size, +size, -size}, + + {-size, -size, -size}, {-size, -size, +size}, {+size, -size, -size}, + {+size, -size, -size}, {-size, -size, +size}, {+size, -size, +size} + }; + + mesh->num_indices = 0; + mesh->num_vertices = NUM_ARRAY_ELEMENTS(positions); + + glGenVertexArrays(1, &mesh->vao); + glGenBuffers(1, &mesh->vbo); + mesh->ebo = 0; + + glBindVertexArray(mesh->vao); + + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0 ); + + glBindVertexArray(0); + return mesh; +} + +Mesh *mesh_make_quad() +{ + Mesh *mesh; + mesh = malloc( sizeof(Mesh) ); + memset(mesh, 0, sizeof(Mesh) ); + + render.meshes[render.num_meshes] = mesh; + render.num_meshes += 1; + + Vec3 positions[] = + { + { -0.5f, +0.5f, +0.0f}, { -0.5f, -0.5f, +0.0f}, + { +0.5f, +0.5f, +0.0f}, { +0.5f, -0.5f, +0.0f} + }; + + mesh->num_vertices = NUM_ARRAY_ELEMENTS(positions); + mesh->num_indices = 0; + + glGenVertexArrays(1, &mesh->vao); + glGenBuffers(1, &mesh->vbo); + mesh->ebo = 0; + + glBindVertexArray(mesh->vao); + + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0 ); + + glBindVertexArray(0); + return mesh; +} + +void mesh_purge(Mesh *mesh) +{ + if(mesh) + { + if(mesh->vbo) + glDeleteBuffers(1, &mesh->vbo); + if(mesh->ebo) + glDeleteBuffers(1, &mesh->ebo); + if(mesh->vao) + glDeleteVertexArrays(1, &mesh->vao); + + memset(mesh, 0, sizeof(Mesh)); + } +} diff --git a/09-september/tomcat/renderer/mesh.h b/09-september/tomcat/renderer/mesh.h new file mode 100644 index 0000000..711a82e --- /dev/null +++ b/09-september/tomcat/renderer/mesh.h @@ -0,0 +1,22 @@ +#ifndef MESH_H +#define MESH_H + +#include "vertex.h" + +typedef struct _Mesh +{ + GLuint num_indices; + GLuint num_vertices; + GLuint vbo, ebo, vao; +} Mesh; + +/** Mesh Factory **/ +extern Mesh *mesh_new(vertex_t* vertices, GLsizeiptr vertexBuffersize, + GLushort* indices, GLsizeiptr indexBuffersize); + +extern Mesh *mesh_make_skybox(float size); +extern Mesh *mesh_make_quad(); + +extern void mesh_purge(Mesh *mesh); + +#endif // MESH_H diff --git a/09-september/tomcat/renderer/model.c b/09-september/tomcat/renderer/model.c new file mode 100644 index 0000000..3c65ad3 --- /dev/null +++ b/09-september/tomcat/renderer/model.c @@ -0,0 +1,314 @@ +#include "model.h" +#include "renderer.h" +#include "../util/array.h" +#include "../util/util.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#define MAX_HASH_MODELS 1024 +static Model *model_hash_table[MAX_HASH_MODELS]; + +static const int BUFFER_SIZE = 128; + +static Model *_model_alloc(const char *name) +{ + if(strlen(name) > MAX_PATH_LENGTH) + Util_FatalError("File following model name is too long: %s", name); + + if(render.num_models >= MAX_MODELS) + return NULL; + + Model *model; + + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_MODELS; + + model = malloc( sizeof(Model) ); + memset(model, 0, sizeof(Model) ); + + render.models[render.num_models] = model; + render.num_models += 1; + + strcpy(model->_name, name); + model->_hash_next = model_hash_table[hash_]; + model_hash_table[hash_] = model; + + model->_hash = hash_; + + return model; +} + +Model *model_get(const char *name) +{ + Model *model; + + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_MODELS; + + if(model_hash_table[hash_] != NULL) + { + for(model = model_hash_table[hash_]; model; model = model->_hash_next) + { + if( model->_hash == hash_ ) + return model; + } + } + + return NULL; +} + +typedef struct +{ + vertex_t *data; + GLushort *indices; + + Array *positions; + Array *textures; + Array *normals; + Array *tangents; + + unsigned int vertex_count, index_count; + unsigned int index_pointer; + + GLubyte hasTextCoords, hasNormals; +} OBJ_Mesh; + +static vertex_t *search_index(vertex_t *pkey, vertex_t *pelem, unsigned int vertex_count) +{ + int i; + for(i = 0; i < vertex_count; i++) + { + if(pelem[i].position.x == pkey->position.x && + pelem[i].position.y == pkey->position.y && + pelem[i].position.z == pkey->position.z && + pelem[i].texCoord.x == pkey->texCoord.x && + pelem[i].texCoord.y == pkey->texCoord.y && + pelem[i].normal.x == pkey->normal.x && + pelem[i].normal.y == pkey->normal.y && + pelem[i].normal.z == pkey->normal.z) + { + return &pelem[i]; + } + } + return NULL; +} + +static void calculate_tangents(OBJ_Mesh *mesh) +{ + int i; + for(i = 0; i < mesh->index_count; i += 3) + { + int i0 = i; + int i1 = i + 1; + int i2 = i + 2; + + Vec3 *v0 = ( (Vec3 *)mesh->positions->data) + i0; + Vec3 *v1 = ( (Vec3 *)mesh->positions->data) + i1; + Vec3 *v2 = ( (Vec3 *)mesh->positions->data) + i2; + + Vec2 *uv0 = ( (Vec2 *)mesh->textures->data) + i0; + Vec2 *uv1 = ( (Vec2 *)mesh->textures->data) + i1; + Vec2 *uv2 = ( (Vec2 *)mesh->textures->data) + i2; + + Vec3 deltaPos1 = vec3_sub(v1, v0); + Vec3 deltaPos2 = vec3_sub(v2, v0); + + Vec2 deltaUV1 = vec2_sub(uv1, uv0); + Vec2 deltaUV2 = vec2_sub(uv2, uv0); + + GLfloat r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x); + + deltaPos1 = vec3_scalar_mul(&deltaPos1, deltaUV2.y); + deltaPos2 = vec3_scalar_mul(&deltaPos2, deltaUV1.y); + + Vec3 tangent = vec3_sub(&deltaPos1, &deltaPos2); + tangent = vec3_scalar_mul(&tangent, r); + + ( (Vec3 *)mesh->tangents->data)[i2] = tangent; + ( (Vec3 *)mesh->tangents->data)[i1] = tangent; + ( (Vec3 *)mesh->tangents->data)[i0] = tangent; + } + /* + We normalize the tangents at the end of the parse_obj_index loop + for(i = 0; i < mesh.index_count; i++) + { + mesh.tangents[i] = vec3_normalize(&mesh.tangents[i]); + } + */ +} + +static void parse_obj_index(OBJ_Mesh *mesh, vertex_t *current_vertex) +{ + vertex_t *indexOnArray = search_index(current_vertex, mesh->data, mesh->vertex_count); + + /* We check if the vertex was already loaded, so the index points to the created vertex instead of repeating data*/ + if(indexOnArray == NULL) + { + mesh->data = (vertex_t*) realloc( mesh->data, sizeof(vertex_t) * (++mesh->vertex_count) ); + + /* We make the index point to the last vertex added */ + mesh->indices[mesh->index_pointer] = mesh->vertex_count - 1; + + mesh->data[mesh->vertex_count - 1] = *current_vertex; + } + else + { + GLushort index = (GLushort)(indexOnArray - mesh->data); + mesh->data[index].tangent = vec3_add( &mesh->data[index].tangent, + ¤t_vertex->tangent ); + + /* We make the index point to the previus vertex added instead of creating a new one */ + mesh->indices[mesh->index_pointer] = index; + } + + mesh->index_pointer += 1; +} + +Model *model_obj_new(const char *path) +{ + Model *model; + model = model_get(path); + + if(model) + return model; + + OBJ_Mesh obj_mesh; + memset( &obj_mesh, 0, sizeof(OBJ_Mesh) ); + + obj_mesh.positions = array_create( sizeof(Vec3) ); + obj_mesh.normals = array_create( sizeof(Vec3) ); + obj_mesh.textures = array_create( sizeof(Vec2) ); + + Array *positions = array_create( sizeof(Vec3) ); + Array *normals = array_create( sizeof(Vec3) ); + Array *textures = array_create( sizeof(Vec2) ); + + vertex_t current_vertex; + + Vec3 current_position; + Vec3 current_normal; + Vec2 current_texture; + + int count = 0, i; + int texture[3], normal[3], verts[3]; + + FILE *file = fopen(path, "r"); + if(file == NULL) + Util_FatalError("%s file could not be loaded!", path); + + char buffer[BUFFER_SIZE]; + while( !feof(file) ) + { + fgets(buffer, BUFFER_SIZE, file); + switch(buffer[0]) + { + case 'v': + if(buffer[1] == 't') + { + count = sscanf(buffer, "vt %f %f\n", ¤t_texture.x, ¤t_texture.y); + + array_append(textures, ¤t_texture); + + if(count != 2) + Util_FatalError("Bad texture coordinates on .obj file"); + } + else if(buffer[1] == 'n') + { + count = sscanf(buffer, "vn %f %f %f\n", ¤t_normal.x, + ¤t_normal.y, + ¤t_normal.z); + array_append(normals, ¤t_normal); + + if(count != 3) + Util_FatalError("Bad normals data on .obj file"); + } + else + { + count = sscanf(buffer, "v %f %f %f\n", ¤t_position.x, + ¤t_position.y, + ¤t_position.z); + + array_append(positions, ¤t_position); + + if(count != 3) + Util_FatalError("Bad vertices data on .obj file"); + } + break; + case 'f': + obj_mesh.index_count += 3; + + count = sscanf(buffer, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", + &verts[0], &texture[0], &normal[0], + &verts[1], &texture[1], &normal[1], + &verts[2], &texture[2], &normal[2]); + + if(count != 9) + Util_FatalError("Bad face data on .obj file"); + + array_append(obj_mesh.positions, &( (Vec3 *)positions->data )[ verts[0] -1 ] ); + array_append(obj_mesh.positions, &( (Vec3 *)positions->data )[ verts[1] -1 ] ); + array_append(obj_mesh.positions, &( (Vec3 *)positions->data )[ verts[2] -1 ] ); + + array_append(obj_mesh.normals, &( (Vec3 *)normals->data )[ normal[0] - 1 ] ); + array_append(obj_mesh.normals, &( (Vec3 *)normals->data )[ normal[1] - 1 ] ); + array_append(obj_mesh.normals, &( (Vec3 *)normals->data )[ normal[2] - 1 ] ); + + array_append(obj_mesh.textures, &( (Vec2 *)textures->data )[ texture[0] - 1 ] ); + array_append(obj_mesh.textures, &( (Vec2 *)textures->data )[ texture[1] - 1 ] ); + array_append(obj_mesh.textures, &( (Vec2 *)textures->data )[ texture[2] - 1 ] ); + + break; + default: + break; + } + } + + obj_mesh.indices = malloc( obj_mesh.index_count * sizeof(GLushort) ); + obj_mesh.tangents = array_create_by_size( sizeof(Vec3), obj_mesh.index_count ); + calculate_tangents(&obj_mesh); + + for(i = 0; i < obj_mesh.index_count; i++) + { + current_vertex.position = ( (Vec3 *)obj_mesh.positions->data )[i]; + current_vertex.texCoord = ( (Vec2 *)obj_mesh.textures->data )[i]; + current_vertex.normal = ( (Vec3 *)obj_mesh.normals->data )[i]; + current_vertex.tangent = ( (Vec3 *)obj_mesh.tangents->data )[i]; + + parse_obj_index(&obj_mesh, ¤t_vertex); + } + + for(i = 0; i < obj_mesh.vertex_count; i++) + { + obj_mesh.data[i].tangent = vec3_normalize(&obj_mesh.data[i].tangent); + } + + array_free(obj_mesh.positions); + array_free(obj_mesh.normals); + array_free(obj_mesh.textures); + array_free(obj_mesh.tangents); + + array_free(positions); + array_free(textures); + array_free(normals); + + fclose(file); + + GLsizeiptr vertexBuffersize = obj_mesh.vertex_count * sizeof(vertex_t); + GLsizeiptr indexBuffersize = obj_mesh.index_count * sizeof(GLushort); + + model = _model_alloc(path); + + model->mesh = mesh_new(obj_mesh.data, vertexBuffersize, obj_mesh.indices, indexBuffersize); + + free(obj_mesh.data); + free(obj_mesh.indices); + + return model; +} + +void model_purge(Model *model) +{ + mesh_purge(model->mesh); +} diff --git a/09-september/tomcat/renderer/model.h b/09-september/tomcat/renderer/model.h new file mode 100644 index 0000000..6b514dd --- /dev/null +++ b/09-september/tomcat/renderer/model.h @@ -0,0 +1,21 @@ +#ifndef MODEL_H +#define MODEL_H + +#include "../shared.h" +#include "mesh.h" + +typedef struct _Model +{ + Mesh *mesh; + /* Material? */ + + char _name[MAX_PATH_LENGTH]; + struct _Model *_hash_next; + unsigned int _hash; +} Model; + +extern Model *model_obj_new(const char *path); +extern Model *model_get(const char *name); +extern void model_purge(Model *model); + +#endif // MODEL_H diff --git a/09-september/tomcat/renderer/renderer.c b/09-september/tomcat/renderer/renderer.c new file mode 100644 index 0000000..307c543 --- /dev/null +++ b/09-september/tomcat/renderer/renderer.c @@ -0,0 +1,430 @@ +#include "renderer.h" +#include "../util/util_time.h" +#include "../util/util.h" + +#include <string.h> + +#define MAX_LIGHTS 4 + +Renderer render; + +void Render_Init(Window *window) +{ + memset( &render, 0, sizeof(Renderer) ); + + if(glewInit() != GLEW_OK) + Util_FatalError("Glew could no be started!"); + + strcpy( render.info.version, (const char *) glGetString(GL_VERSION) ); + strcpy( render.info.vendor, (const char *) glGetString(GL_VENDOR) ); + strcpy( render.info.shading_version, (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION) ); + + fprintf(stderr, "%s\n", render.info.version); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glClearColor(0.0f, 0.0f, 0.39f, 1.0f); + + //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + + render.default_quad = mesh_make_quad(); + + render.default_shader = shader_new("pass_shader", "resources/shaders/passShader.vert", + "resources/shaders/passShader.frag"); + render.default_shader->totalTransform = shader_get_uniform_location(render.default_shader, "M_MVP"); + render.default_shader->Texture = shader_get_uniform_location(render.default_shader, "Texture"); + + + glBindVertexArray(render.default_quad->vao); + glCreateBuffers(1, &render.instance_vbo); + + glBindBuffer(GL_ARRAY_BUFFER, render.instance_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 18 * 10000, NULL, GL_STREAM_DRAW); + + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 0)); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 2) ); + glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 6) ); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 10) ); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 14) ); + + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + glEnableVertexAttribArray(4); + glEnableVertexAttribArray(5); + + glVertexAttribDivisor(1, 1); + glVertexAttribDivisor(2, 1); + glVertexAttribDivisor(3, 1); + glVertexAttribDivisor(4, 1); + glVertexAttribDivisor(5, 1); + + glBindVertexArray(0); + + render.window = window; + render.shadow_width = 1024; + render.shadow_height = 1024; + + /** TEMP **/ + + Vec3 center = {0.0f, 0.0f, 0.0f}; + Vec3 up = {0.0f, 1.0f, 0.0f}; + render.inv_light_dir = (Vec3){11.54f, 66.74f, 9.93f}; + Mat4 shadow_ortho_mat = mat4_orthographic(-100.0f, 100.0f, -100.0f, 100.0f, -100.0f, 200.0f); + Mat4 shadow_view_mat = mat4_lookAt(&render.inv_light_dir, ¢er, &up); + Mat4 shadow_model; + mat4_identity(&shadow_model); + + render.shadow_mvp = mat4_mul(&shadow_ortho_mat, &shadow_view_mat); + render.shadow_mvp = mat4_mul(&render.shadow_mvp, &shadow_model); + + render.shadow_shader = shader_new("s_shader", "resources/shaders/shadow_shader.vert", + "resources/shaders/shadow_shader.frag"); + render.shadow_shader->totalTransform = shader_get_uniform_location(render.shadow_shader, "M_MVP"); + + /** TEMP **/ + + glGenFramebuffers(1, &render.shadow_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, render.shadow_fbo); + + + glGenTextures(1, &render.shadow_map); + glBindTexture(GL_TEXTURE_2D, render.shadow_map); + + + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, render.shadow_width, + render.shadow_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glGenTextures(1, &render.shadow_color); + glBindTexture(GL_TEXTURE_2D, render.shadow_color); + + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, render.shadow_width, + render.shadow_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, render.shadow_map, 0); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, render.shadow_color, 0); + + //glDrawBuffer(GL_NONE); + GLenum draw_buffer = GL_COLOR_ATTACHMENT0; + glDrawBuffers(1, &draw_buffer); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + Util_FatalError("Could not create a frame buffer object\n"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, render.window->Width, render.window->Height); + + Util_CheckGLError(); +} + +void Render_BeginFrame() +{ + glClearColor(0.0f, 0.0f, 0.39f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + glBindFramebuffer(GL_FRAMEBUFFER, render.shadow_fbo); + glViewport(0, 0, render.shadow_width, render.shadow_height); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +} + +void Render_LoadLights(Shader *s, const Light *lights, int n) +{ + Vec3 light_positions[MAX_LIGHTS]; + Vec4 light_colors[MAX_LIGHTS]; + Vec3 attenuation[MAX_LIGHTS]; + int i; + + /* Default light in case we are not given enough lights (n < 4) */ + static const Light defaultLight = + { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f } + }; + + for(i = 0; i < MAX_LIGHTS; i++) + { + if(i < n) + { + light_positions[i] = lights[i].position; + light_colors[i] = lights[i].color; + attenuation[i] = lights[i].attenuation; + } + else + { + light_positions[i] = defaultLight.position; + light_colors[i] = defaultLight.color; + attenuation[i] = defaultLight.attenuation; + } + + } + + glUniform3fv(s->lightPosition, MAX_LIGHTS, (float *)light_positions); + glUniform4fv(s->lightColor, MAX_LIGHTS, (float *)light_colors); + glUniform3fv(s->lightAttenuation, MAX_LIGHTS, (float *)attenuation); +} + +/****************************************************************************** +* * +* Function Name: Render_DrawEntity * +* * +* Specific shader layout * +* -> extra0 texture atlas number of rows * +* -> extra1 texture atlas xy offset * +* * +*******************************************************************************/ + +void Render_DrawEntity(Shader *s, Mat4 *projectedViewMatrix, Entity *entity) +{ + Mesh *mesh = entity->model->mesh; + /*We need the model to world matrix in our shader in order to rotate the normals*/ + Mat4 modelTransform = Entity_GetModelTransform(entity); + Mat4 totalMatrix; + + /** TEMP **/ + + /** TEMP**/ + + glUniformMatrix4fv(s->modelToWorld, 1, GL_FALSE, modelTransform.data); + + totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform); + glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalMatrix.data); + + glUniform1i(s->Texture, 0); + texture_bind(entity->texture, 0); + + glUniform1f(s->extra0, entity->texture->number_of_rows); + Vec2 tex_offset = Entity_GetTexOffset(entity); + glUniform2fv(s->extra1, 1, (float *)&tex_offset); + + glBindVertexArray(mesh->vao); + glDrawElements(GL_TRIANGLES, mesh->num_indices, GL_UNSIGNED_SHORT, NULL); + glBindVertexArray(0); +} + +/****************************************************************************** +* * +* Function Name: Render_DrawTerrain * +* * +* Specific shader layout * +* -> extra0 Texture_Background * +* -> extra1 Texture_R * +* -> extra2 Texture_G * +* -> extra3 Texture_B * +* -> extra4 Texture_BlendMap * +* * +*******************************************************************************/ + +void Render_DrawTerrain(Shader *s, Mat4 *projectedViewMatrix, Terrain *terrain) +{ + Mat4 totalMatrix; + Mat4 modelTransform; + + /* We need the model to world matrix in our shader in order to rotate the normals */ + modelTransform = mat4_translate(&terrain->position); + glUniformMatrix4fv(s->modelToWorld, 1, GL_FALSE, modelTransform.data); + + totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform); + glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalMatrix.data); + + /** Set textures for the terrain **/ + + glUniform1i(s->extra0, 0); + glUniform1i(s->extra1, 1); + glUniform1i(s->extra2, 2); + glUniform1i(s->extra3, 3); + glUniform1i(s->extra4, 4); + + texture_bind(terrain->textures.texture[0], 0); + texture_bind(terrain->textures.texture[1], 1); + texture_bind(terrain->textures.texture[2], 2); + texture_bind(terrain->textures.texture[3], 3); + texture_bind(terrain->blendmap, 4); + + /**********************************/ + + glBindVertexArray(terrain->mesh->vao); + glDrawElements(GL_TRIANGLES, terrain->mesh->num_indices, GL_UNSIGNED_SHORT, NULL); + glBindVertexArray(0); +} + +void Render_DrawSky(Shader *s, Mat4 *viewMatrix, Mat4 *projectionMatrix, Skybox *sky) +{ + Mat4 myViewMatrix = *viewMatrix; + Mat4 totalTransform; + Mat4 rotateMatrix = mat4_rotate_y(sky->rotation); + + sky->rotation += SKYBOX_ROTATION_SPEED * Time_GetFrameTime(); + + /* We don't want to move the skybox around (We want it to stay with the camera in the midle), + just rotate it with the camera so we remove the translations components of the matrix */ + + myViewMatrix.data[0 + 3 * 4] = 0.0f; + myViewMatrix.data[1 + 3 * 4] = 0.0f; + myViewMatrix.data[2 + 3 * 4] = 0.0f; + + myViewMatrix = mat4_mul(&myViewMatrix, &rotateMatrix); + totalTransform = mat4_mul(projectionMatrix, &myViewMatrix); + + glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalTransform.data ); + + texture_bind(sky->texture, 0); + glUniform1i(s->Texture, 0); + + glBindVertexArray(sky->cube->vao); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); +} + +/****************************************************************************** +* * +* Function Name: Render_DrawParticles * +* * +* Specific shader layout * +* -> extra0 texture atlas number of rows * +* -> extra1 texture atlas xy offset * +* * +*******************************************************************************/ + +void Render_DrawParticles(Shader *s, Mat4 *viewMatrix, Mat4 *projectionMatrix) +{ + Mat4 modelTransform, modelViewMatrix, totalTransform, scale; + Particle *c = NULL; + ParticleSystem *sys = NULL; + + int num_particles = 0; + int i, j; + + + glEnable(GL_BLEND); + glDepthMask(GL_FALSE); + glUniform1i(s->Texture, 0); + + for(i = 0; i < particles.num_systems; i++) + { + sys = particles.systems[i]; + + texture_bind(sys->texture, 0); + glUniform1f(s->extra0, sys->texture->number_of_rows); + + /* Orphane the buffer */ + glBindBuffer(GL_ARRAY_BUFFER, render.instance_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 18 * MAX_PARTICLES_PER_SYSTEM, NULL, GL_STREAM_DRAW); + + if(sys->additive) + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + else + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + for(j = 0; j < sys->num_particles; j++) + { + c = &sys->particles[j]; + + modelTransform = mat4_translate(&c->position); + scale = mat4_scale(c->scale, c->scale, c->scale); + modelTransform = mat4_mul(&modelTransform, &scale); + /* + We eliminate the rotation from the view matrix so the particle is always facing the camera, + for this we add the transposed matrix from the rotation part of the viewmatrx and put it + on the model transform matrix + */ + modelTransform.data[0] = viewMatrix->data[0]; + modelTransform.data[4] = viewMatrix->data[1]; + modelTransform.data[8] = viewMatrix->data[2]; + modelTransform.data[1] = viewMatrix->data[4]; + modelTransform.data[5] = viewMatrix->data[5]; + modelTransform.data[9] = viewMatrix->data[6]; + modelTransform.data[2] = viewMatrix->data[8]; + modelTransform.data[6] = viewMatrix->data[9]; + modelTransform.data[10] = viewMatrix->data[10]; + + modelViewMatrix = mat4_mul(viewMatrix, &modelTransform); + totalTransform = mat4_mul(projectionMatrix, &modelViewMatrix); + + /* Load the texture atlas coods and MVP matrix */ + glBufferSubData(GL_ARRAY_BUFFER, num_particles * sizeof(GLfloat), sizeof(Vec2), &c->tex_offset); + glBufferSubData(GL_ARRAY_BUFFER, (num_particles + 2) * sizeof(GLfloat), sizeof(Mat4), totalTransform.data); + + num_particles += 18; + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindVertexArray(render.default_quad->vao); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, num_particles / 18); + } + + glBindVertexArray(0); + + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); +} + +void Render_EndFrame() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, render.window->Width, render.window->Height); +} + +void Render_Shutdown() +{ + int i; + + glDeleteTextures(1, &render.shadow_map); + glDeleteFramebuffers(1, &render.shadow_fbo); + + glDeleteBuffers(1, &render.instance_vbo); + + /* Destroy all created textures */ + for(i = 0; i < render.num_textures; i++) + { + texture_purge( render.textures[i] ); + free(render.textures[i]); + } + + /* Destroy all created models */ + for(i = 0; i < render.num_models; i++) + { + model_purge(render.models[i]); + free(render.models[i]); + } + + for(i = 0; i < render.num_meshes; i++) + { + mesh_purge(render.meshes[i]); + free(render.meshes[i]); + } + + /* Destroy all created shaders */ + for(i = 0; i < render.num_shaders; i++) + { + shader_purge(render.shaders[i]); + free(render.shaders[i]); + } + + /* Just for checking */ + printf("%d textures were deleted!\n", render.num_textures); + printf("%d models were deleted!\n", render.num_models); + printf("%d shaders were deleted!\n", render.num_shaders); + printf("%d meshes were deleted!\n", render.num_meshes); + + /* Clear everything */ + memset( &render, 0, sizeof(Renderer) ); +} diff --git a/09-september/tomcat/renderer/renderer.h b/09-september/tomcat/renderer/renderer.h new file mode 100644 index 0000000..791d65d --- /dev/null +++ b/09-september/tomcat/renderer/renderer.h @@ -0,0 +1,86 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include "../terrain.h" +#include "../util/array.h" +#include "vertex.h" +#include "../particles/particles.h" +#include "renderer_types.h" +#include "stdint.h" +#include "window.h" + +#define MAX_STRING_LENGTH 128 + +#define MAX_TEXTURES 2048 +#define MAX_MODELS 2048 +#define MAX_MESHES 2048 +#define MAX_SHADERS 32 + +/** Beginning of rendering functions **/ + +typedef struct _GlInfo +{ + char version[MAX_STRING_LENGTH]; + char shading_version[MAX_STRING_LENGTH]; + char vendor[MAX_STRING_LENGTH]; +} GlInfo; + +typedef struct _Renderer +{ + GlInfo info; + + Mesh *default_quad; + Shader *default_shader; + GLuint instance_vbo; + + Texture *textures[MAX_TEXTURES]; /* All loaded textures */ + int num_textures; + + Shader *shaders[MAX_SHADERS]; /* All loaded shaders */ + int num_shaders; + + Model *models[MAX_MODELS]; /* All created shapes */ + int num_models; + + Mesh *meshes[MAX_MESHES]; + int num_meshes; + + Window *window; + + GLuint shadow_fbo; /* Frame buffer for shadow mapping */ + GLuint shadow_map; /* Texture for rendering the shadow map (shadow mapping) */ + GLuint shadow_color; + GLint shadow_width; + GLint shadow_height; + + /** TEMP **/ + Mat4 shadow_mvp; + Vec3 inv_light_dir; + Shader *shadow_shader; + + /** TEMP **/ +} Renderer; +extern Renderer render; + +extern void Render_Init(Window *window); + +extern void Render_BeginFrame(); + +/* Load lights into the current shader program */ +extern void Render_LoadLights(Shader *shader, const Light *lights, int n); + +extern void Render_DrawEntity(Shader *shader, Mat4 *projectedViewMatrix, Entity *entity); +extern void Render_DrawTerrain(Shader *shader, Mat4 *projectedViewMatrix, Terrain *terrain); +extern void Render_DrawSky(Shader *shader, Mat4 *viewMatrix, Mat4 *projectionMatrix, Skybox *sky); +extern void Render_DrawParticles(Shader *shader, Mat4 *viewMatrix, Mat4 *projectionMatrix); + +extern void Render_EndFrame(); + +extern void Render_Shutdown(); + +extern Mat4 Entity_GetModelTransform(Entity* entity); +extern Vec2 Entity_GetTexOffset(Entity *entity); + +/** End of rendering functions **/ + +#endif // RENDERER_H diff --git a/09-september/tomcat/renderer/renderer_types.h b/09-september/tomcat/renderer/renderer_types.h new file mode 100644 index 0000000..cd07a20 --- /dev/null +++ b/09-september/tomcat/renderer/renderer_types.h @@ -0,0 +1,47 @@ +#ifndef RENDERER_TYPES_H +#define RENDERER_TYPES_H + +#define SKYBOX_ROTATION_SPEED 1.0f + +#include "../util/str.h" +#include "../util/array.h" + +#include "../math/vector.h" +#include "../math/matrix4x4.h" + +#include "shader.h" +#include "texture.h" +#include "model.h" + +typedef struct _Material +{ + Texture *normal_map; + GLfloat shine_damper; + GLfloat reflectivity; +} Material; + +typedef struct +{ + Texture *texture; + Mesh *cube; + GLfloat rotation; +} Skybox; + +typedef struct _Entity +{ + Model *model; + Texture *texture; + Vec3 position; + float rotX, rotY, rotZ; + int index; /* Index inside a texture atlas should default to 0 */ + float scale[3]; +} Entity; + +typedef struct +{ + Vec3 position; + Vec4 color; + Vec3 attenuation; +} Light; + +#endif // RENDERER_TYPES_H diff --git a/09-september/tomcat/renderer/shader.c b/09-september/tomcat/renderer/shader.c new file mode 100644 index 0000000..3f6a5d7 --- /dev/null +++ b/09-september/tomcat/renderer/shader.c @@ -0,0 +1,187 @@ +#include "renderer.h" +#include "../util/util.h" + +#include <stdlib.h> +#include <string.h> + +#define MAX_HASH_SHADER 16 +static Shader *shader_hash_table[MAX_HASH_SHADER]; + +static void CompileShader(const char *source, GLuint shaderID) +{ + glShaderSource(shaderID, 1, &source, 0); + glCompileShader(shaderID); + GLint error; + glGetShaderiv(shaderID, GL_COMPILE_STATUS, &error); + if(error != GL_TRUE) + { + GLint logLenth; + glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLenth); + GLchar buffer[logLenth]; + glGetShaderInfoLog(shaderID, logLenth, &logLenth, buffer); + glDeleteShader(shaderID); + Util_FatalError("Some shader failed to compile:\n%s", buffer); + } +} + +Shader *shader_new(const char *name, const char *vertexShaderPath, const char *fragShaderPath) +{ + if(strlen(name) >= MAX_PATH_LENGTH) + Util_FatalError("File following shader name is too long: %s", name); + + Shader *s; + s = shader_get(name); + if(s != NULL) + return s; + + char *vertexShaderSource = Util_LoadFile(vertexShaderPath); + char *fragmentShaderSource = Util_LoadFile(fragShaderPath); + + GLuint vs = 0, fs = 0, program; + vs = glCreateShader(GL_VERTEX_SHADER); + fs = glCreateShader(GL_FRAGMENT_SHADER); + + if(vs == 0 || fs == 0) + Util_FatalError("Shaders could not be created\n"); + + program = glCreateProgram(); + + CompileShader(vertexShaderSource, vs); + CompileShader(fragmentShaderSource, fs); + + glAttachShader(program, vs); + glAttachShader(program, fs); + + glLinkProgram(program); + + GLint error; + glGetProgramiv(program, GL_LINK_STATUS, &error); + + if(error != GL_TRUE) + { + GLint logLength; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + + GLchar buffer[logLength]; + glGetProgramInfoLog(program, logLength, &logLength, buffer); + + glDeleteProgram(program); + glDeleteShader(vs); + glDeleteShader(fs); + + Util_FatalError("Shader program failed to link!:\n%s", buffer); + } + /** Free some usless resources **/ + glDetachShader(program, vs); + glDetachShader(program, fs); + glDeleteShader(vs); + glDeleteShader(fs); + + free(vertexShaderSource); + free(fragmentShaderSource); + + /** Alloc the new texture **/ + s = malloc( sizeof(Shader) ); + memset(s, 0, sizeof(Shader) ); + s->id = program; + + /** Register inside the resource manager **/ + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_SHADER; + + render.shaders[render.num_shaders] = s; + render.num_shaders += 1; + + strcpy(s->name, name); + s->_hash_next = shader_hash_table[hash_]; + shader_hash_table[hash_] = s; + + s->_hash = hash_; + + /** Return the final result **/ + return s; +} + +Shader *shader_get(const char *name) +{ + Shader *s; + + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_SHADER; + + if(shader_hash_table[hash_] != NULL) + { + for(s = shader_hash_table[hash_]; s; s = s->_hash_next) + { + if( s->_hash == hash_ ) + return s; + } + } + return NULL; +} + +void shader_purge(Shader *shader) +{ + /** Purge the opengl data **/ + if(shader->id != 0) + { + glUseProgram(0); + glDeleteProgram(shader->id); + shader->id = 0; + } +} + +GLint shader_get_uniform_location( Shader *s, const char *uniformName ) +{ + GLint u = glGetUniformLocation(s->id, uniformName); + if(u == GL_INVALID_INDEX) + Util_FatalError("Uniform \"%s\" could not be found!", uniformName); + else + return u; + + return 0; +} + +GLint shader_get_attrib_location( Shader *s, const char *attributeName ) +{ + GLint attrLocation = glGetAttribLocation(s->id, attributeName); + if(attrLocation < 0) + Util_FatalError("Attribute \"%s\" could not be found!\n", attributeName); + return attrLocation; +} + +void shader_set_uniform_mat4( Shader *s, const char *name, const float matrix[16] ) +{ + GLint location = shader_get_uniform_location(s, name); + glUniformMatrix4fv(location, 1, GL_FALSE, matrix); +} + +void shader_set_uniform_float( Shader *s, const char *name, const float val ) +{ + GLint location = shader_get_uniform_location(s, name); + glUniform1f(location, val); +} + +void shader_set_uniform_vec2( Shader *s, const char *name, const float vec[2] ) +{ + GLint location = shader_get_uniform_location(s, name); + glUniform2fv(location, 1, vec); +} + +void shader_set_uniform_vec3( Shader *s, const char *name, const float vec[3] ) +{ + GLint location = shader_get_uniform_location(s, name); + glUniform3fv(location, 1, vec); +} + +void shader_set_uniform_vec4( Shader *s, const char *name, const float vec[4] ) +{ + GLint location = shader_get_uniform_location(s, name); + glUniform4fv(location, 1, vec); +} + +void shader_set_uniform_int( Shader *s, const char *name, const int val ) +{ + GLint location = shader_get_uniform_location(s, name); + glUniform1i(location, val); +} diff --git a/09-september/tomcat/renderer/shader.h b/09-september/tomcat/renderer/shader.h new file mode 100644 index 0000000..e4889f3 --- /dev/null +++ b/09-september/tomcat/renderer/shader.h @@ -0,0 +1,59 @@ +#ifndef SHADER_H +#define SHADER_H + +#include "../shared.h" + +typedef struct _Shader +{ + GLuint id; + char name[MAX_PATH_LENGTH]; + + /* Layout */ + + /* Program Attributes */ + GLint position; + GLint uv; + GLint normal; + GLint tangent; + + /* Program Uniforms */ + GLint totalTransform; + GLint modelToWorld; + GLint lightPosition; + GLint ambientLight; + GLint lightColor; + GLint lightAttenuation; + GLint World_eyePosition; + GLint Texture; + GLint Normal_Map; + + /* Program Multi Purpose Uniforms */ + GLint extra0; + GLint extra1; + GLint extra2; + GLint extra3; + GLint extra4; + GLint extra5; + + struct _Shader *_hash_next; + unsigned int _hash; +} Shader; + +/** Shaders **/ +extern Shader *shader_new(const char *name, const char *vertexShaderPath, const char *fragShaderPath); +extern Shader *shader_get(const char *name); +extern void shader_purge(Shader *shader); +/** **/ + +/** Shader functions **/ +extern GLint shader_get_uniform_location( Shader *s, const char *uniformName ); +extern GLint shader_get_attrib_location( Shader *s, const char *attributeName ); +extern void shader_set_uniform_mat4( Shader *s, const char *name, const float matrix[16] ); +extern void shader_set_uniform_float( Shader *s, const char *name, const float val ); +extern void shader_set_uniform_vec2( Shader *s, const char *name, const float vec[2] ); +extern void shader_set_uniform_vec3( Shader *s, const char *name, const float vec[3] ); +extern void shader_set_uniform_vec4( Shader *s, const char *name, const float vec[4] ); +extern void shader_set_uniform_int( Shader *s, const char *name, const int val ); +/** **/ + +#endif // SHADER_H diff --git a/09-september/tomcat/renderer/texture.c b/09-september/tomcat/renderer/texture.c new file mode 100644 index 0000000..e653c5a --- /dev/null +++ b/09-september/tomcat/renderer/texture.c @@ -0,0 +1,188 @@ +#include "../util/util.h" +#include "renderer.h" +#include "texture.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <SDL2/SDL.h> +#include <SDL2/SDL_image.h> + +#define MAX_HASH_TEXTURES 1024 +static Texture *texture_hash_table[MAX_HASH_TEXTURES]; + +Texture *texture_new(const char *path) +{ + return texture_with_name_new(path, path); +} + +Texture *texture_with_name_new(const char *name, const char *path) +{ + if(strlen(name) > MAX_PATH_LENGTH) + Util_FatalError("File following texture name is too long: %s", name); + + Texture *tex; + tex = texture_get(name); + + if(tex != NULL) + return tex; + + if(render.num_textures >= MAX_TEXTURES) + return NULL; + + /** Alloc the new texture **/ + tex = malloc( sizeof(Texture) ); + memset(tex, 0, sizeof(Texture) ); + tex->number_of_rows = 1; + tex->type = GL_TEXTURE_2D; + + SDL_Surface *data = IMG_Load(path); + + if(data == NULL) + Util_FatalError("Texture %s could not be found!\n", path); + + glGenTextures(1, &tex->tex_id); + glBindTexture(GL_TEXTURE_2D, tex->tex_id); + + SDL_LockSurface(data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->w, data->h, GL_FALSE, GL_RGBA, GL_UNSIGNED_BYTE, data->pixels); + SDL_UnlockSurface(data); + SDL_FreeSurface(data); + + /** Configure the texture **/ + glGenerateMipmap(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.4); + + glBindTexture(GL_TEXTURE_2D, 0); + + /** Register inside the resource manager **/ + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_TEXTURES; + + render.textures[render.num_textures] = tex; + render.num_textures += 1; + + strcpy(tex->_name, name); + tex->_hash_next = texture_hash_table[hash_]; + texture_hash_table[hash_] = tex; + + tex->hash_ = hash_; + + /** Return the final result **/ + return tex; +} + +Texture *texture_cubemap_new(const char *paths[6]) +{ + return texture_cubemap_with_name_new(paths[0], paths); +} + +Texture *texture_cubemap_with_name_new(const char *name, const char *paths[6]) +{ + Texture *tex; + tex = texture_get(name); + + if(tex != NULL) + { + puts("s"); + return tex; + } + + if(render.num_textures >= MAX_TEXTURES) + return NULL; + + /** Alloc the new texture **/ + tex = malloc( sizeof(Texture) ); + memset(tex, 0, sizeof(Texture) ); + tex->number_of_rows = 1; + tex->type = GL_TEXTURE_CUBE_MAP; + + glGenTextures(1, &tex->tex_id); + glBindTexture(GL_TEXTURE_CUBE_MAP, tex->tex_id); + + SDL_Surface *data; + + int i; + for(i = 0; i < 6; i++) + { + data = IMG_Load(paths[i]); + + if(data == NULL) + Util_FatalError("Texture %s could not be found!\n", paths[i]); + + SDL_LockSurface(data); + /** All the textures sides are linearly stored so we just add "i" **/ + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, + data->w, data->h, GL_FALSE, GL_RGBA, GL_UNSIGNED_BYTE, data->pixels); + + SDL_UnlockSurface(data); + SDL_FreeSurface(data); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + /** Register inside the resource manager **/ + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_TEXTURES; + + render.textures[render.num_textures] = tex; + render.num_textures += 1; + + strcpy(tex->_name, name); + tex->_hash_next = texture_hash_table[hash_]; + texture_hash_table[hash_] = tex; + + tex->hash_ = hash_; + + /** Return the final result **/ + return tex; +} + +Texture *texture_get(const char *name) +{ + Texture *tex; + + unsigned int hash_ = Util_Hash( name ); + hash_ %= MAX_HASH_TEXTURES; + + if(texture_hash_table[hash_] != NULL) + { + for(tex = texture_hash_table[hash_]; tex; tex = tex->_hash_next) + { + if( tex->hash_ == hash_ ) + return tex; + } + } + return NULL; +} + +void texture_bind(Texture *tex, int slot) +{ + glActiveTexture(GL_TEXTURE0 + slot); + + if(tex->type != GL_TEXTURE_2D && tex->type != GL_TEXTURE_CUBE_MAP) + return; + + + glBindTexture(tex->type, tex->tex_id); +} + +void texture_purge(Texture *tex) +{ + /** Purge the opengl data **/ + if(tex->tex_id != 0) + { + glDeleteTextures(1, &tex->tex_id); + tex->tex_id = 0; + } +} diff --git a/09-september/tomcat/renderer/texture.h b/09-september/tomcat/renderer/texture.h new file mode 100644 index 0000000..8288c72 --- /dev/null +++ b/09-september/tomcat/renderer/texture.h @@ -0,0 +1,30 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include "../shared.h" + +typedef struct _Texture +{ + GLuint tex_id; + GLenum type; + + int number_of_rows; /* used for texture atlases */ + + char _name[MAX_PATH_LENGTH]; + unsigned int hash_; + struct _Texture *_hash_next; /* linked list for storing on hash table */ + +} Texture; + +extern Texture *texture_new(const char *name); +extern Texture *texture_with_name_new(const char *name, const char *path); + +extern Texture *texture_cubemap_new(const char *paths[6]); +extern Texture *texture_cubemap_with_name_new(const char *name, const char *paths[6]); + +extern Texture *texture_get(const char *name); +extern void texture_bind(Texture *tex, int slot); + +extern void texture_purge(Texture *tex); /* Clean the texture without freeing the container */ + +#endif // TEXTURE_H diff --git a/09-september/tomcat/renderer/vertex.h b/09-september/tomcat/renderer/vertex.h new file mode 100644 index 0000000..6a79dde --- /dev/null +++ b/09-september/tomcat/renderer/vertex.h @@ -0,0 +1,15 @@ +#ifndef VERTEX_H +#define VERTEX_H + +#include <GL/glew.h> +#include "../math/vector.h" + +typedef struct +{ + Vec3 position; + Vec2 texCoord; + Vec3 normal; + Vec3 tangent; +} vertex_t; + +#endif // VERTEX_H diff --git a/09-september/tomcat/renderer/window.c b/09-september/tomcat/renderer/window.c new file mode 100644 index 0000000..d5db1eb --- /dev/null +++ b/09-september/tomcat/renderer/window.c @@ -0,0 +1,49 @@ +#include "window.h" +#include "../util/util.h" +#include <stdlib.h> + +Window* window_new(const char* title, Uint32 width, Uint32 height) +{ + Window* window = malloc(sizeof(Window)); + window->title = title; + window->Width = width; + window->Height = height; + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + + window->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + width, height, SDL_WINDOW_OPENGL); + if(window->window == NULL) + Util_FatalError( "The window could not be created:\n%s", SDL_GetError() ); + + window->context = SDL_GL_CreateContext(window->window); + + if(window->context == NULL) + Util_FatalError( "Context could not be created:\n%s", SDL_GetError() ); + + glViewport(0, 0, width, height); + + return window; +} + +void window_resize(Window* window, Uint32 width, Uint32 height) +{ + window->Width = width; + window->Height = height; + SDL_SetWindowSize(window->window, width, height); + glViewport(0, 0, width, height); +} + +void window_update(Window* window) +{ + SDL_GL_SwapWindow(window->window); +} + +void window_destroy(Window* window) +{ + SDL_GL_DeleteContext(window->context); + SDL_DestroyWindow(window->window); + free(window); +} diff --git a/09-september/tomcat/renderer/window.h b/09-september/tomcat/renderer/window.h new file mode 100644 index 0000000..608937a --- /dev/null +++ b/09-september/tomcat/renderer/window.h @@ -0,0 +1,20 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include <SDL2/SDL.h> +#include <GL/glew.h> + +typedef struct +{ + SDL_Window* window; + SDL_GLContext context; + Uint32 Width, Height; + const char* title; +} Window; + +extern Window* window_new(const char* title, Uint32 width, Uint32 height); +extern void window_resize(Window* window, Uint32 width, Uint32 height); +extern void window_update(Window* window); +extern void window_destroy(Window* window); + +#endif // WINDOW_H diff --git a/09-september/tomcat/shared.h b/09-september/tomcat/shared.h new file mode 100644 index 0000000..35fd471 --- /dev/null +++ b/09-september/tomcat/shared.h @@ -0,0 +1,13 @@ +#ifndef SHARED_H +#define SHARED_H + +#include "GL/glew.h" +#define MAX_PATH_LENGTH 64 + +typedef enum +{ + FALSE, + TRUE +} boolean; + +#endif // SHARED_H diff --git a/09-september/tomcat/terrain.c b/09-september/tomcat/terrain.c new file mode 100644 index 0000000..f23d057 --- /dev/null +++ b/09-september/tomcat/terrain.c @@ -0,0 +1,155 @@ +#include "terrain.h" +#include "math/math_util.h" +#include "math/vector.h" +#include "util/util.h" +#include "renderer/renderer.h" + +#include <SDL2/SDL.h> +#include <SDL2/SDL_image.h> +#include <math.h> + +#define PLANE_SIZE 128 +#define PLANE_MAX_HEIGHT 10 + +#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 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 normal = { hLeft - hRight, 2.0f, hDown - hUp}; + return vec3_normalize(&normal); +} + +GLfloat Terrain_GetHeightOfTerrain(Terrain *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 p1 = { 0, terrain->height[ gridX * PLANE_SIZE + gridZ ], 0 }; + /* 1, heights[gridX + 1][gridZ], 0) */ + Vec3 p2 = { 1, terrain->height[ (gridX + 1) * PLANE_SIZE + gridZ ], 0}; + /* 0, heights[gridX][gridZ + 1], 1) */ + Vec3 p3 = { 0, terrain->height[ gridX * PLANE_SIZE + (gridZ + 1) ], 1}; + + Vec2 pos = {xCoord, zCoord}; + + answer = baryCentric(&p1, &p2, &p3, &pos); + } else { + /* (1, heights[gridX + 1][gridZ], 0) */ + Vec3 p1 = { 1, terrain->height[ (gridX + 1) * PLANE_SIZE + gridZ ], 0 }; + /* (1, heights[gridX + 1][gridZ + 1], 1) */ + Vec3 p2 = { 1, terrain->height[ (gridX + 1) * PLANE_SIZE + (gridZ + 1) ], 1}; + /* (0, heights[gridX][gridZ + 1], 1) */ + Vec3 p3 = { 0, terrain->height[ gridX * PLANE_SIZE + (gridZ + 1) ], 1}; + Vec2 pos = {xCoord, zCoord}; + + answer = baryCentric(&p1, &p2, &p3, &pos); + } + + return answer; +} + +Terrain *Terrain_Create( int w, int l, const char* heightmap_path, Texture *blendmap, TerrainTexturePack *textures ) +{ + Terrain *terrain = malloc( sizeof(Terrain) ); + 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){ (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){ 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->mesh = mesh_new(data, vertexBufferSize, indices, indexBufferSize); + return terrain; +} + +void Terrain_Destroy( Terrain *terrain ) +{ + if(terrain->height) + free(terrain->height); + + free(terrain); +} + diff --git a/09-september/tomcat/terrain.h b/09-september/tomcat/terrain.h new file mode 100644 index 0000000..b321e5f --- /dev/null +++ b/09-september/tomcat/terrain.h @@ -0,0 +1,27 @@ +#ifndef TERRAIN_H +#define TERRAIN_H + +#include "renderer/renderer_types.h" +#include "math/vector.h" + +typedef struct +{ + Texture *texture[4]; +} TerrainTexturePack; + +typedef struct +{ + Mesh *mesh; + Texture *blendmap; + TerrainTexturePack textures; + + GLfloat *height; + int w, l; + Vec3 position; +} Terrain; + +extern Terrain *Terrain_Create( int w, int l, const char* heightmap_path, Texture *blendmap, TerrainTexturePack *textures); +extern GLfloat Terrain_GetHeightOfTerrain(Terrain *terrain, GLfloat x, GLfloat z); +extern void Terrain_Destroy( Terrain *terrain ); + +#endif // TERRAIN_H diff --git a/09-september/tomcat/util/array.c b/09-september/tomcat/util/array.c new file mode 100644 index 0000000..13660e0 --- /dev/null +++ b/09-september/tomcat/util/array.c @@ -0,0 +1,102 @@ +#include "array.h" + +#include <stdlib.h> +#include <string.h> + +#define ARRAY_GROWTH_FACTOR 2 +#define MAX(x, y) ( (x > y) ? x : y ) + +typedef struct _RealArray +{ + char *data; + unsigned int length; /* Number of elements */ + + unsigned int type_size; + unsigned int capacity; /* Array capacity in elements number */ + bool clear; +} RealArray; + +static void array_check_for_expand(RealArray *arr, unsigned int length); + +Array *array_create(unsigned int type_size) +{ + return array_create_by_size(type_size, 0); +} + +Array *array_create_by_size(unsigned int type_size, unsigned int reserved_size) +{ + RealArray *arr = malloc( sizeof(RealArray) ); + arr->capacity = 0; + arr->data = NULL; + arr->length = 0; + arr->type_size = type_size; + + if(reserved_size != 0) + { + array_check_for_expand(arr, reserved_size); + } + + return (Array *)arr; +} + +void array_append(Array *arr, void *data) +{ + RealArray *r_arr = (RealArray *)arr; + array_check_for_expand(r_arr, 1); + + memcpy(r_arr->data + r_arr->length * r_arr->type_size, data, r_arr->type_size); + r_arr->length += 1; +} + +void array_insert(Array *arr, int index, void *data) +{ + RealArray *r_arr = (RealArray *)arr; + array_check_for_expand(r_arr, 1); + + /* Shift everything one place */ + memmove(r_arr->data + (index + 1) * r_arr->type_size, + r_arr->data + index * r_arr->type_size, + r_arr->length * r_arr->type_size - index * r_arr->type_size); + + /* Insert the new data */ + memcpy(r_arr->data + index * r_arr->type_size, data, r_arr->type_size); + + r_arr->length += 1; +} + +void array_remove(Array *arr, int index) +{ + +} + +void array_reserve(Array *arr, unsigned int length) +{ + +} + +unsigned int array_get_type_size(Array *arr) +{ + RealArray *r_arr = (RealArray *)arr; + return r_arr->type_size; +} + +void array_free(Array *arr) +{ + RealArray *r_arr = (RealArray *)arr; + + free(r_arr->data); + free(r_arr); +} + +static void array_check_for_expand(RealArray *arr, unsigned int length) +{ + RealArray *r_arr = (RealArray *)arr; + + unsigned int expected_size = r_arr->length + length; + + if(r_arr->capacity < expected_size) + { + r_arr->capacity = MAX(ARRAY_GROWTH_FACTOR * r_arr->capacity, expected_size); + r_arr->data = realloc(r_arr->data, r_arr->capacity * r_arr->type_size); + } +} diff --git a/09-september/tomcat/util/array.h b/09-september/tomcat/util/array.h new file mode 100644 index 0000000..1444a74 --- /dev/null +++ b/09-september/tomcat/util/array.h @@ -0,0 +1,23 @@ +#ifndef ARRAY_H +#define ARRAY_H + +#include <stdbool.h> + +typedef struct +{ + char *data; + unsigned int length; +} Array; + +extern Array *array_create(unsigned int type_size); +extern Array *array_create_by_size(unsigned int type_size, unsigned int reserved_size); + +extern void array_append(Array *arr, void *data); +extern void array_insert(Array *arr, int index, void *data); +extern void array_remove(Array *arr, int index); +extern void array_reserve(Array *arr, unsigned int length); +extern unsigned int array_get_type_size(Array *arr); + +extern void array_free(Array *arr); + +#endif // ARRAY_H diff --git a/09-september/tomcat/util/str.c b/09-september/tomcat/util/str.c new file mode 100644 index 0000000..295b390 --- /dev/null +++ b/09-september/tomcat/util/str.c @@ -0,0 +1,121 @@ +#include "str.h" + +#include <string.h> +#include <stdlib.h> + +/* Note, we add always 1 to length for the \0 character */ + +static void string_check_for_expand( String *string_, unsigned int length ) +{ + if(string_->length + length >= string_->allocated_length) + { + string_->allocated_length = string_->length + length + 1; + string_->data = realloc(string_->data, string_->allocated_length * sizeof(char) ); + } +} + +String *string_create( const char *init ) +{ + String *str; + + if(init == NULL || *init == '\0') + { + str = string_create_by_size(1); + } + else + { + unsigned int len = strlen(init); + str = string_create_by_size(len + 1); + string_append(str, init); + } + + return str; +} + +String *string_create_by_size( unsigned int reserved_size) +{ + String *str = malloc( sizeof(String) ); + + str->data = NULL; + str->length = 0; + str->allocated_length = 0; + + string_check_for_expand(str, reserved_size); + + str->data[0] = 0; + return str; +} + +void string_assign( String *string_, const char *val ) +{ + +} + +void string_append( String *string_, const char *val ) +{ + string_insert(string_, string_->length, val); +} + +void string_append_char( String *string_, char c ) +{ + string_insert(string_, string_->length, &c); +} + +void string_insert( String *string_, int index, const char *val) +{ + if(index > string_->length) + return; + + unsigned int length = strlen(val); + string_check_for_expand(string_, length); + + if(index == string_->length - 1) + { + strcpy(string_->data + string_->length, val); + } + else + { + memmove(string_->data + index + length, + string_->data + index, + (string_->length - index) * sizeof(char) ); + + memcpy(string_->data + index, val, length * sizeof(char) ); + } + + string_->length += length; + string_->data[string_->length] = '\0'; +} + +void string_insert_char( String *string_, int index, char val) +{ + string_insert(string_, index, &val); +} + +void string_free( String *string_ ) +{ + if(string_) + { + free(string_->data); + free(string_); + } +} + +unsigned int string_hash( String *string_ ) +{ + unsigned int hash, i; + for(hash = i = 0; i < string_->length; ++i) + { + hash += string_->data[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +bool string_equal( String *a, String *b ) +{ + return !strcmp(a->data, b->data); +} diff --git a/09-september/tomcat/util/str.h b/09-september/tomcat/util/str.h new file mode 100644 index 0000000..d8182e1 --- /dev/null +++ b/09-september/tomcat/util/str.h @@ -0,0 +1,29 @@ +#ifndef STR_H +#define STR_H + +#include <stdbool.h> + +typedef struct _String +{ + char *data; + unsigned int length; + unsigned int allocated_length; +} String; + +extern String *string_create( const char *init ); +extern String *string_create_by_size( unsigned int reserved_size); + +extern void string_assign( String *string_, const char *val ); + +extern void string_append( String *string_, const char *val ); +extern void string_append_char( String *string_, char c ); + +extern void string_insert( String *string_, int index, const char *val); +extern void string_insert_char( String *string_, int index, char val); + +extern void string_free( String *string_ ); + +extern unsigned int string_hash( String *string_ ); +extern bool string_equal( String *a, String *b ); + +#endif // STR_H diff --git a/09-september/tomcat/util/util.c b/09-september/tomcat/util/util.c new file mode 100644 index 0000000..22eb0fc --- /dev/null +++ b/09-september/tomcat/util/util.c @@ -0,0 +1,138 @@ +#include "util.h" + +#include <SDL2/SDL.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +unsigned int Util_Hash( const char *str ) +{ + unsigned int hash, i, length; + length = strlen(str); + + for(hash = i = 0; i < length; ++i) + { + hash += str[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} + +void Util_FatalError( const char *fmt, ... ) +{ + fprintf(stderr, "Fatal Error:\n"); + + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + SDL_Quit(); + exit(1); +} + +void Util_CheckGLError() +{ + GLenum error = glGetError(); + switch(error) + { + case GL_INVALID_ENUM: + fprintf(stderr, "WARNING: GL_INVALID_ENUM\n"); + break; + case GL_INVALID_VALUE: + fprintf(stderr, "WARNING: GL_INVALID_VALUE\n"); + break; + case GL_INVALID_OPERATION: + fprintf(stderr, "WARNING: GL_INVALID_OPERATION\n"); + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + fprintf(stderr, "WARNING: GL_INVALID_FRAMEBUFFER_OPERATION\n"); + break; + case GL_OUT_OF_MEMORY: + fprintf(stderr, "WARNING: GL_OUT_OF_MEMORY\n"); + break; + case GL_STACK_UNDERFLOW: + fprintf(stderr, "WARNING: GL_STACK_UNDERFLOW\n"); + break; + case GL_STACK_OVERFLOW: + fprintf(stderr, "WARNING: GL_STACK_OVERFLOW\n"); + break; + + default: + break; + } +} + +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 = 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 +Util_GetMouseRay(int screenWidth, int screenHeigth, Mat4 *viewMatrix, Mat4 *projectionMatrix, + int mouseX, int mouseY) +{ + Vec4 eyeCoords; + Vec3 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 clipCoords = { normalX, normalY, -1.0f, 1.0f }; + + /* Remove perpective */ + { + Mat4 invertedProjection = mat4_inverse(projectionMatrix); + eyeCoords = mat4_mul_vec4(&invertedProjection, &clipCoords); + eyeCoords.z = -1.0f; + eyeCoords.w = 0.0f; + } + + /* Remove view matrix*/ + { + Mat4 invertedViewMatrix = mat4_inverse(viewMatrix); + Vec4 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/09-september/tomcat/util/util.h b/09-september/tomcat/util/util.h new file mode 100644 index 0000000..f09f7cb --- /dev/null +++ b/09-september/tomcat/util/util.h @@ -0,0 +1,27 @@ +#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 unsigned int Util_Hash( const char *str ); +extern void Util_FatalError( const char* fmt, ... ); +extern void Util_CheckGLError(); +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 +Util_GetMouseRay(int screenWidth, int screenHeigth, Mat4 *viewMatrix, Mat4 *projectionMatrix, + int mouseX, int mouseY); + +#endif // UTIL_H diff --git a/09-september/tomcat/util/util_time.c b/09-september/tomcat/util/util_time.c new file mode 100644 index 0000000..e56d997 --- /dev/null +++ b/09-september/tomcat/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 = (float)TIME.counted_frames / ( (float)(SDL_GetTicks() - TIME.beg_ticks) / 1000.0f ); + + 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/09-september/tomcat/util/util_time.h b/09-september/tomcat/util/util_time.h new file mode 100644 index 0000000..3c3e470 --- /dev/null +++ b/09-september/tomcat/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 |
