a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

commit cf9499da4a0512a2c0de111c9d584c5001bee60e
parent c616c3d7deb7b976ab893b8b7455fd034fea0d93
Author: amin <dev@aminmesbah.com>
Date:   Wed, 16 May 2018 06:46:12 +0000

Add math and shader libs

FossilOrigin-Name: 713a9f02e95d0203ccc69eb63f67829a2d57dc0112b8dd8db7a7031575a72c1e
Diffstat:
Asrc/glmth.h | 503+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shader.h | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 706 insertions(+), 0 deletions(-)

diff --git a/src/glmth.h b/src/glmth.h @@ -0,0 +1,503 @@ +#ifndef GLMTH_H +#define GLMTH_H + +#include <assert.h> +#include <math.h> +#include <stdbool.h> +#include <stdint.h> + +#ifndef M_PI +#define M_PI 3.14159265359f +#endif + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef float f32; +typedef double r64; + +typedef union +{ + struct + { + f32 x, y; + } + E[2]; +} v2; + +typedef union +{ + struct + { + f32 x, y, z; + }; + struct + { + v2 xy; + f32 ignored_z; + }; + struct + { + f32 ignored_x; + v2 yz; + }; + f32 E[3]; +} v3; + +typedef union +{ + struct + { + union + { + v3 xyz; + struct + { + f32 x, y, z; + }; + }; + f32 w; + }; + struct + { + v2 xy; + f32 ignored_z_xy; + f32 ignored_w_xy; + }; + struct + { + f32 ignored_x_yz; + v2 yz; + f32 ignored_w_yz; + }; + struct + { + f32 ignored_x_zw; + f32 ignored_y_zw; + v2 zw; + }; + f32 E[4]; +} v4; + +typedef struct +{ + // row-major, so you probably want to transpose before passing to opengl, + // which uses column-major matrices + f32 E[4][4]; // E[row][column] +} m4; + + +m4 glmth_m4_init_id() +{ + m4 m = { 0 }; + m.E[0][0] = 1.0f; + m.E[1][1] = 1.0f; + m.E[2][2] = 1.0f; + m.E[3][3] = 1.0f; + return m; +} + + +void glmth_m4_print(m4 m) +{ + printf("[\n"); + printf(" %f, %f, %f, %f\n", m.E[0][0], m.E[0][1], m.E[0][2], m.E[0][3]); + printf(" %f, %f, %f, %f\n", m.E[1][0], m.E[1][1], m.E[1][2], m.E[1][3]); + printf(" %f, %f, %f, %f\n", m.E[2][0], m.E[2][1], m.E[2][2], m.E[2][3]); + printf(" %f, %f, %f, %f\n", m.E[3][0], m.E[3][1], m.E[3][2], m.E[3][3]); + printf("]\n"); +} + + +f32 *glmth_m4_valueptr(m4 m) +{ + f32 *values = malloc(sizeof(m4)); + for (u8 v = 0; v < 16; ++v) + { + u8 row = v / 4; + u8 col = v % 4; + values[v] = m.E[row][col]; + } + return values; +} + + +bool glmth_m4m4_eq(m4 mat1, m4 mat2) +{ + for (u8 i = 0; i < 4; ++i) + { + for (u8 j = 0; j < 4; ++j) + { + if (mat1.E[i][j] != mat2.E[i][j]) + { + return false; + } + } + } + return true; +} + + +m4 glmth_m4m4_m(m4 mat1, m4 mat2) +{ + m4 r = { + .E[0][0] = (mat1.E[0][0] * mat2.E[0][0]) + (mat1.E[0][1] * mat2.E[1][0]) + (mat1.E[0][2] * mat2.E[2][0]) + (mat1.E[0][3] * mat2.E[3][0]), + .E[0][1] = (mat1.E[0][0] * mat2.E[0][1]) + (mat1.E[0][1] * mat2.E[1][1]) + (mat1.E[0][2] * mat2.E[2][1]) + (mat1.E[0][3] * mat2.E[3][1]), + .E[0][2] = (mat1.E[0][0] * mat2.E[0][2]) + (mat1.E[0][1] * mat2.E[1][2]) + (mat1.E[0][2] * mat2.E[2][2]) + (mat1.E[0][3] * mat2.E[3][2]), + .E[0][3] = (mat1.E[0][0] * mat2.E[0][3]) + (mat1.E[0][1] * mat2.E[1][3]) + (mat1.E[0][2] * mat2.E[2][3]) + (mat1.E[0][3] * mat2.E[3][3]), + + .E[1][0] = (mat1.E[1][0] * mat2.E[0][0]) + (mat1.E[1][1] * mat2.E[1][0]) + (mat1.E[1][2] * mat2.E[2][0]) + (mat1.E[1][3] * mat2.E[3][0]), + .E[1][1] = (mat1.E[1][0] * mat2.E[0][1]) + (mat1.E[1][1] * mat2.E[1][1]) + (mat1.E[1][2] * mat2.E[2][1]) + (mat1.E[1][3] * mat2.E[3][1]), + .E[1][2] = (mat1.E[1][0] * mat2.E[0][2]) + (mat1.E[1][1] * mat2.E[1][2]) + (mat1.E[1][2] * mat2.E[2][2]) + (mat1.E[1][3] * mat2.E[3][2]), + .E[1][3] = (mat1.E[1][0] * mat2.E[0][3]) + (mat1.E[1][1] * mat2.E[1][3]) + (mat1.E[1][2] * mat2.E[2][3]) + (mat1.E[1][3] * mat2.E[3][3]), + + .E[2][0] = (mat1.E[2][0] * mat2.E[0][0]) + (mat1.E[2][1] * mat2.E[1][0]) + (mat1.E[2][2] * mat2.E[2][0]) + (mat1.E[2][3] * mat2.E[3][0]), + .E[2][1] = (mat1.E[2][0] * mat2.E[0][1]) + (mat1.E[2][1] * mat2.E[1][1]) + (mat1.E[2][2] * mat2.E[2][1]) + (mat1.E[2][3] * mat2.E[3][1]), + .E[2][2] = (mat1.E[2][0] * mat2.E[0][2]) + (mat1.E[2][1] * mat2.E[1][2]) + (mat1.E[2][2] * mat2.E[2][2]) + (mat1.E[2][3] * mat2.E[3][2]), + .E[2][3] = (mat1.E[2][0] * mat2.E[0][3]) + (mat1.E[2][1] * mat2.E[1][3]) + (mat1.E[2][2] * mat2.E[2][3]) + (mat1.E[2][3] * mat2.E[3][3]), + + .E[3][0] = (mat1.E[3][0] * mat2.E[0][0]) + (mat1.E[3][1] * mat2.E[1][0]) + (mat1.E[3][2] * mat2.E[2][0]) + (mat1.E[3][3] * mat2.E[3][0]), + .E[3][1] = (mat1.E[3][0] * mat2.E[0][1]) + (mat1.E[3][1] * mat2.E[1][1]) + (mat1.E[3][2] * mat2.E[2][1]) + (mat1.E[3][3] * mat2.E[3][1]), + .E[3][2] = (mat1.E[3][0] * mat2.E[0][2]) + (mat1.E[3][1] * mat2.E[1][2]) + (mat1.E[3][2] * mat2.E[2][2]) + (mat1.E[3][3] * mat2.E[3][2]), + .E[3][3] = (mat1.E[3][0] * mat2.E[0][3]) + (mat1.E[3][1] * mat2.E[1][3]) + (mat1.E[3][2] * mat2.E[2][3]) + (mat1.E[3][3] * mat2.E[3][3]), + }; + return r; +} + + +v4 glmth_m4v4_m(m4 m, v4 v) +{ + v4 r = { + .x = (m.E[0][0] * v.x) + (m.E[0][1] * v.y) + (m.E[0][2] * v.z) + (m.E[0][3] * v.w), + .y = (m.E[1][0] * v.x) + (m.E[1][1] * v.y) + (m.E[1][2] * v.z) + (m.E[1][3] * v.w), + .z = (m.E[2][0] * v.x) + (m.E[2][1] * v.y) + (m.E[2][2] * v.z) + (m.E[2][3] * v.w), + .w = (m.E[3][0] * v.x) + (m.E[3][1] * v.y) + (m.E[3][2] * v.z) + (m.E[3][3] * v.w), + }; + return r; +} + + +v3 glmth_v3_cross(v3 vec1, v3 vec2) +{ + v3 r = { + .x = (vec1.y * vec2.z) - (vec1.z * vec2.y), + .y = (vec1.z * vec2.x) - (vec1.x * vec2.z), + .z = (vec1.x * vec2.y) - (vec1.y * vec2.x), + }; + return r; +} + + +v3 glmth_v3_init(f32 x, f32 y, f32 z) +{ + v3 v = { .x = x, .y = y, .z = z }; + return v; +} + +v3 glmth_v3_init_f(f32 f) +{ + return glmth_v3_init(f, f, f); +} + +f32 glmth_v3_length(v3 v) +{ + return sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z)); +} + +v3 glmth_v3f_m(v3 v, f32 s) +{ + v3 r = { .x = v.x * s, .y = v.y * s, .z = v.z * s }; + return r; +} + +v3 glmth_v3_negate(v3 v) +{ + v3 r = { .x = -v.x, .y = -v.y, .z = -v.z }; + return r; +} + + +v3 glmth_v3_normalize(v3 v) +{ + f32 l = glmth_v3_length(v); + v3 r = glmth_v3_init(v.x / l, v.y / l, v.z / l); + return r; +} + + +void glmth_v3_print(v3 v) +{ + printf("( %f, %f, %f )\n", v.x, v.y, v.z); +} + + +v3 glmth_v3_a(v3 vec1, v3 vec2) +{ + v3 r = { + .x = vec1.x + vec2.x, + .y = vec1.y + vec2.y, + .z = vec1.z + vec2.z + }; + return r; +} + + +v3 glmth_v3_s(v3 vec1, v3 vec2) +{ + return glmth_v3_a(vec1, glmth_v3_negate(vec2)); +} + + +void glmth_v4_print(v4 v) +{ + printf("( %f, %f, %f, %f )\n", v.x, v.y, v.z, v.w); +} + + +bool glmth_v4v4_eq(v4 vec1, v4 vec2) +{ + for (u8 i = 0; i < 4; ++i) + { + if (vec1.E[i] != vec2.E[i]) + { + return false; + } + } + return true; +} + + +void glmth_clampf(float *f, float min, float max) +{ + if (*f < min) + { + *f = min; + } + else if (*f > max) + { + *f = max; + } +} + + +f32 glmth_deg(f32 rad) +{ + return rad * (180.0f / M_PI); +} + + +float glmth_lerpf(float f, float min, float max) +{ + assert(f >= 0.0f && f <= 1.0f); + return (1.0f - f) * min + f * max; +} + + +f32 glmth_rad(f32 deg) +{ + return deg * (M_PI / 180.0f); +} + + +m4 glmth_rotate_x(m4 m, f32 rad) +{ + f32 c = cosf(rad); + f32 s = sinf(rad); + + m4 r = glmth_m4_init_id(); + + r.E[1][1] = c; + r.E[1][2] = -s; + + r.E[2][1] = s; + r.E[2][2] = c; + + return glmth_m4m4_m(m, r); +} + + +m4 glmth_rotate_y(m4 m, f32 rad) +{ + f32 c = cosf(rad); + f32 s = sinf(rad); + + m4 r = glmth_m4_init_id(); + + r.E[0][0] = c; + r.E[0][2] = s; + + r.E[2][0] = -s; + r.E[2][2] = c; + + return glmth_m4m4_m(m, r); +} + + +m4 glmth_rotate_z(m4 m, f32 rad) +{ + f32 c = cosf(rad); + f32 s = sinf(rad); + + m4 r = glmth_m4_init_id(); + + r.E[0][0] = c; + r.E[0][1] = -s; + + r.E[1][0] = s; + r.E[1][1] = c; + + return glmth_m4m4_m(m, r); +} + + +m4 glmth_rotate(m4 m, f32 rad, v3 axis) +{ + axis = glmth_v3_normalize(axis); + + f32 c = cosf(rad); + f32 s = sinf(rad); + + m4 r = glmth_m4_init_id(); + + r.E[0][0] = c + (powf(axis.x, 2.0f) * (1 - c)); + r.E[0][1] = (axis.x * axis.y * (1 - c)) - (axis.z * s); + r.E[0][2] = (axis.x * axis.z * (1 - c)) + (axis.y * s); + + r.E[1][0] = (axis.y * axis.x * (1 - c)) + (axis.z * s); + r.E[1][1] = c + (powf(axis.y, 2.0f) * (1 - c)); + r.E[1][2] = (axis.y * axis.z * (1 - c)) - (axis.x * s); + + r.E[2][0] = (axis.z * axis.x * (1 - c)) - (axis.y * s); + r.E[2][1] = (axis.z * axis.y * (1 - c)) + (axis.x * s); + r.E[2][2] = c + (powf(axis.z, 2.0f) * (1 - c)); + + return glmth_m4m4_m(m, r); +} + + +m4 glmth_scale(m4 m, v3 v) +{ + m4 r = glmth_m4_init_id(); + r.E[0][0] = v.x; + r.E[1][1] = v.y; + r.E[2][2] = v.z; + return glmth_m4m4_m(m, r); +} + + +m4 glmth_translate(m4 m, v3 v) +{ + m4 r = glmth_m4_init_id(); + r.E[0][3] = v.x; + r.E[1][3] = v.y; + r.E[2][3] = v.z; + return glmth_m4m4_m(m, r); +} + + +m4 glmth_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) +{ + assert(left != right); + assert(bottom != top); + assert(near != far); + + m4 r = glmth_m4_init_id(); + + r.E[0][0] = 2.0f / (right - left); + r.E[0][1] = 0.0f; + r.E[0][2] = 0.0f; + r.E[0][3] = -(right + left) / (right - left); + + r.E[1][0] = 0.0f; + r.E[1][1] = 2.0f / (top - bottom); + r.E[1][2] = 0.0f; + r.E[1][3] = -(top + bottom) / (top - bottom); + + r.E[2][0] = 0.0f; + r.E[2][1] = 0.0f; + r.E[2][2] = -2.0f / (far - near); + r.E[2][3] = -(far + near) / (far - near); + + r.E[3][0] = 0.0f; + r.E[3][1] = 0.0f; + r.E[3][2] = 0.0f; + r.E[3][3] = 1.0f; + + return r; +} + + +m4 glmth_projection_perspective(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) +{ + assert(left != right); + assert(bottom != top); + assert(near != far); + + m4 r = glmth_m4_init_id(); + + r.E[0][0] = (2.0f * near) / (right - left); + r.E[0][1] = 0.0f; + r.E[0][2] = (right + left) / (right - left); + r.E[0][3] = 0.0f; + + r.E[1][0] = 0.0f; + r.E[1][1] = (2.0f * near) / (top - bottom); + r.E[1][2] = (top + bottom) / (top - bottom); + r.E[1][3] = 0.0f; + + r.E[2][0] = 0.0f; + r.E[2][1] = 0.0f; + r.E[2][2] = -(far + near) / (far - near); + r.E[2][3] = (-2.0f * far * near) / (far - near); + + r.E[3][0] = 0.0f; + r.E[3][1] = 0.0f; + r.E[3][2] = -1.0f; + r.E[3][3] = 0.0f; + + return r; +} + + +m4 glmth_projection_perspective_fov(f32 fovy, f32 aspect, f32 near, f32 far) +{ + f32 half_height = tanf(fovy / 2.0f) * near; + f32 half_width = half_height * aspect; + f32 left = -half_width; + f32 right = half_width; + f32 bottom = -half_height; + f32 top = half_height; + + return glmth_projection_perspective(left, right, bottom, top, near, far); +} + + +m4 glmth_camera_look_at(v3 camera_pos, v3 camera_target, v3 up) +{ + v3 camera_direction = glmth_v3_normalize(glmth_v3_s(camera_pos, camera_target)); + v3 camera_right = glmth_v3_normalize(glmth_v3_cross(up, camera_direction)); + v3 camera_up = glmth_v3_cross(camera_direction, camera_right); + + m4 look = glmth_m4_init_id(); + look.E[0][0] = camera_right.x; + look.E[0][1] = camera_right.y; + look.E[0][2] = camera_right.z; + + look.E[1][0] = camera_up.x; + look.E[1][1] = camera_up.y; + look.E[1][2] = camera_up.z; + + look.E[2][0] = camera_direction.x; + look.E[2][1] = camera_direction.y; + look.E[2][2] = camera_direction.z; + + return glmth_m4m4_m(look, glmth_translate(glmth_m4_init_id(), glmth_v3_negate(camera_pos))); +} + + +#endif diff --git a/src/shader.h b/src/shader.h @@ -0,0 +1,203 @@ +#ifndef SHADER_H +#define SHADER_H + +#include <glad/glad.h> // get opengl headers +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include "glmth.h" + +struct Shader +{ + uint32_t program; +}; + + +char *read_file(char *file_path) +{ + FILE *handle = fopen(file_path, "r"); + char *buffer = NULL; + + if (handle) + { + // get file size + fseek(handle, 0, SEEK_END); + uint32_t num_bytes_in_file = ftell(handle); + rewind(handle); + + buffer = (char*) malloc(sizeof(char) * (num_bytes_in_file + 1) ); + + uint32_t bytes_read = fread(buffer, sizeof(char), num_bytes_in_file, handle); + // IMPORTANT! fread() doesn't add the '\0' + buffer[num_bytes_in_file] = '\0'; + + if (num_bytes_in_file != bytes_read) + { + free(buffer); + buffer = NULL; + } + + fclose(handle); + } + else + { + printf("Error: Couldn't open file at path: %s", file_path); + } + + return buffer; +} + + +struct Shader shader_compile(GLchar *vertex_path, GLchar *fragment_path) +{ + const GLchar *vertex_shader_source = read_file(vertex_path); + const GLchar *fragment_shader_source = read_file(fragment_path); + + GLint success; + GLchar info_log[512]; + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); + glCompileShader(vertex_shader); + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertex_shader, 512, NULL, info_log); + printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n %s\n", info_log); + } + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); + glCompileShader(fragment_shader); + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragment_shader, 512, NULL, info_log); + printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n %s\n", info_log); + } + + struct Shader s; + s.program = glCreateProgram(); + glAttachShader(s.program, vertex_shader); + glAttachShader(s.program, fragment_shader); + glLinkProgram(s.program); + glGetProgramiv(s.program, GL_LINK_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(s.program, 512, NULL, info_log); + printf("ERROR::SHADER::LINKING_FAILED\n %s\n", info_log); + } + + glDeleteShader(fragment_shader); + glDeleteShader(vertex_shader); + + return s; +} + + +void shader_use(struct Shader *s) +{ + if (s) + { + glUseProgram(s->program); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_setb(struct Shader *s, char *name, bool value) +{ + if (s) + { + glUniform1i(glGetUniformLocation(s->program, name), (int)value); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_seti(struct Shader *s, char *name, int value) +{ + if (s) + { + glUniform1i(glGetUniformLocation(s->program, name), value); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_setf(struct Shader *s, char *name, f32 value) +{ + if (s) + { + glUniform1f(glGetUniformLocation(s->program, name), value); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_setm4(struct Shader *s, char *name, m4 *mat) +{ + if (s) + { + glUniformMatrix4fv(glGetUniformLocation(s->program, name), 1, GL_TRUE, glmth_m4_valueptr(*mat)); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_setf3(struct Shader *s, char *name, f32 x, f32 y, f32 z) +{ + if (s) + { + glUniform3f(glGetUniformLocation(s->program, name), x, y, z); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_setf3_1(struct Shader *s, char *name, f32 f) +{ + if (s) + { + shader_setf3(s, name, f, f, f); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +void shader_setv3(struct Shader *s, char *name, v3 *v) +{ + if (s) + { + shader_setf3(s, name, v->x, v->y, v->z); + } + else + { + printf("Error: invalid Shader pointer\n"); + } +} + + +#endif