From b764ec95e7d08c693910378a73a1cffb026208c0 Mon Sep 17 00:00:00 2001 From: Shariq Shah Date: Tue, 30 Jun 2015 13:12:33 +0500 Subject: [PATCH] First commit --- .dir-locals.el | 4 + premake4.lua | 29 +++ src/array.c | 133 +++++++++++ src/array.h | 41 ++++ src/game.c | 50 ++++ src/game.h | 7 + src/input.c | 72 ++++++ src/input.h | 23 ++ src/linmath.h | 547 ++++++++++++++++++++++++++++++++++++++++++++ src/log.c | 24 ++ src/log.h | 7 + src/main.c | 54 +++++ src/renderer.c | 25 ++ src/renderer.h | 10 + src/string_utils.c | 107 +++++++++ src/string_utils.h | 12 + src/window_system.c | 94 ++++++++ src/window_system.h | 22 ++ 18 files changed, 1261 insertions(+) create mode 100644 .dir-locals.el create mode 100644 premake4.lua create mode 100644 src/array.c create mode 100644 src/array.h create mode 100644 src/game.c create mode 100644 src/game.h create mode 100644 src/input.c create mode 100644 src/input.h create mode 100644 src/linmath.h create mode 100644 src/log.c create mode 100644 src/log.h create mode 100644 src/main.c create mode 100644 src/renderer.c create mode 100644 src/renderer.h create mode 100644 src/string_utils.c create mode 100644 src/string_utils.h create mode 100644 src/window_system.c create mode 100644 src/window_system.h diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..32407fd --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,4 @@ +((c-mode . + ((company-clang-arguments . ("-I/mnt/Dev/Projects/Symmetry/include/GLFW")) + (flycheck-clang-include-path . ("/mnt/Dev/Projects/Symmetry/include/GLFW"))) + )) diff --git a/premake4.lua b/premake4.lua new file mode 100644 index 0000000..1fee653 --- /dev/null +++ b/premake4.lua @@ -0,0 +1,29 @@ +solution "Symmetry" +configurations {"Debug", "Release"} +location "build" +language "C" +includedirs {"include/**"} +buildoptions {"-Wall", "-std=c11"} +linkoptions { "`pkg-config --libs --static glfw3`" } +links {"GLEW"} + +-- local cmd_stream = assert(io.popen("pkg-config --libs --static glfw3", r)) +-- local libs_to_link = assert(cmd_stream:read("*all")) +-- cmd_stream:close() +-- libs_to_link = string.gsub(libs_to_link, "-lglfw", "") +-- libs_to_link = string.gsub(libs_to_link, "\n", "") +-- linkoptions {libs_to_link} + +project "Symmetry" +kind "ConsoleApp" +files { "src/*.h", "src/*.c"} + +configuration "Debug" +flags {"Symbols"} +targetdir "bin/debug" + +configuration "Release" +defines {"NDEBUG"} +flags {"Optimize"} +targetdir "bin/release" + diff --git a/src/array.c b/src/array.c new file mode 100644 index 0000000..3a15425 --- /dev/null +++ b/src/array.c @@ -0,0 +1,133 @@ +#include +#include + +#include "array.h" + +#define ARRAY_MIN_CAPACITY 2 + +static bool array_reallocate(Array* array); + +Array* array_new_(size_t object_size) +{ + Array* newArray = malloc(sizeof(Array)); + + newArray->object_size = object_size; + newArray->length = 0; + newArray->capacity = ARRAY_MIN_CAPACITY; + newArray->data = malloc(newArray->object_size * newArray->capacity); + + return newArray; +} + +void array_free(Array* array) +{ + free(array->data); + free(array); +} + +void* array_get(Array* array, unsigned int index) +{ + return array->data + (array->object_size * index); +} + +void* array_top(Array* array) +{ + return array->data + (array->object_size * (array->length - 1)); +} + +void* array_add(Array* array) +{ + /* if capacity is full, double size */ + if(++array->length > array->capacity) + { + array->capacity = array->capacity << 1; /* LShift by 1 means (number * number) */ + char* new_data = realloc(array->data, array->object_size * array->capacity); + if(new_data) + { + array->data = new_data; + } + else + { + array->length--; + array->capacity = array->capacity >> 1; + /* TODO: Error handling here! */ + } + } + + /* return new location added */ + return array->data + (array->object_size * (array->length - 1)); +} + +void array_reset(Array* array, unsigned int length) +{ + free(array->data); + array->length = length; + array->capacity = length < ARRAY_MIN_CAPACITY ? ARRAY_MIN_CAPACITY : length; + array->data = malloc(array->object_size * array->capacity); +} + +bool array_pop(Array* array) +{ + bool success = false; + if(array->length > 0) + { + array->length--; + success = array_reallocate(array); + } + return success; +} + +bool array_reallocate(Array* array) +{ + bool success = true; + /* If capacity is too big i.e. 4 times larger than length, halve it */ + if((array->length << 2) < array->capacity && array->capacity > ARRAY_MIN_CAPACITY) + { + array->capacity = array->capacity >> 1; + char* new_data = realloc(array->data, array->object_size * array->capacity); + if(new_data) + array->data = new_data; + else + success = false; + } + return success; +} + +bool array_remove_at(Array* array, unsigned int index) +{ + bool success = false; + if(array->length > 0) + { + unsigned int next_index = index++; + if(next_index < array->length) + { + array->length--; + char* current_location = array->data + (array->object_size * index); + char* location_after_obj = current_location + array->object_size; + memmove(current_location, + location_after_obj, + array->object_size * ((array->length - 1) - next_index)); + success = array_reallocate(array); + } + else + { + success = array_pop(array); + } + } + return success; +} + +void* array_begin(Array* array) +{ + return array->data; +} + +void* array_end(Array* array) +{ + return array->data + (array->object_size * array->length); +} + +void array_sort(Array* array, int (*compar)(const void*, const void*)) +{ + qsort(array->data, array->length, array->object_size, compar); +} diff --git a/src/array.h b/src/array.h new file mode 100644 index 0000000..cd30f4e --- /dev/null +++ b/src/array.h @@ -0,0 +1,41 @@ +#ifndef ARRAY_H +#define ARRAY_H + +#include +#include + +typedef struct +{ + char* data; // actual data + unsigned int capacity; // current capacity i.e memory allocated + unsigned int length; // current length of array + size_t object_size; // size per element +} Array; + +Array* array_new_(size_t object_size); +#define array_new(type) array_new_(sizeof(type)); // Use this for array creation +void array_free(Array* array); + +// All the macros with _val return by value while the function returns pointer +void* array_get(Array* array, unsigned int index); +#define array_get_val(array, type, index) (*((type*) array_get(array, index))) + +void* array_top(Array* array); +#define array_top_val(array, type) (*((type*) array_top(array))) + +void* array_add(Array* array); +#define array_add_val(array, type) (*((type*) array_add(array))) + +void array_reset(Array* array, unsigned int length); // Resize to length objects whose data is unspecified +#define array_clear(array) array_reset(array, 0) + +bool array_pop(Array* array); // Remove object with highest index +bool array_remove_at(Array* array, unsigned int index); + +void* array_begin(Array* array); +void* array_end(Array* array); + +void array_sort(Array* array, int (*compar)(const void*, const void*)); // Sort array by providing a comparator function + + +#endif diff --git a/src/game.c b/src/game.c new file mode 100644 index 0000000..d63b914 --- /dev/null +++ b/src/game.c @@ -0,0 +1,50 @@ +#include "game.h" +#include "GLFW/glfw3.h" + +#include "window_system.h" +#include "input.h" +#include "renderer.h" +#include "log.h" + +void run(void); +void update(void); +void render(void); + +void game_init(void) +{ + GLFWwindow* window = window_get_active(); + input_init(window); + renderer_init(window); + run(); +} + +void run(void) +{ + while(!window_should_close()) + { + update(); + render(); + window_swap_buffers(); + window_poll_events(); + } +} + +void update(void) +{ + if(input_get_key_state(GLFW_KEY_A, GLFW_REPEAT)) + log_message("A released"); + + if(input_get_mousebutton_state(GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS)) + log_message("Left mouse released"); +} + +void render(void) +{ + renderer_draw(); +} + +void game_cleanup(void) +{ + input_cleanup(); + renderer_cleanup(); +} diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..534f5c2 --- /dev/null +++ b/src/game.h @@ -0,0 +1,7 @@ +#ifndef game_H +#define game_H + +void game_init(void); +void game_cleanup(void); + +#endif diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..5f46f59 --- /dev/null +++ b/src/input.c @@ -0,0 +1,72 @@ +#include +#include "input.h" +#include "GLFW/glfw3.h" + +#include "window_system.h" +#include "log.h" + +void input_on_key(GLFWwindow* window, int key, int scancode, int action, int mods); +void input_on_mousebutton(GLFWwindow* window, int button, int action, int mods); +void input_on_cursor_move(GLFWwindow* window, double xpos, double ypos); + +void input_init(GLFWwindow* window) +{ + glfwSetMouseButtonCallback(window, input_on_mousebutton); + glfwSetKeyCallback(window, input_on_key); + glfwSetCursorPosCallback(window, input_on_cursor_move); + glfwSetInputMode(window, GLFW_STICKY_KEYS, 1); +} + +void input_cleanup(void) +{ + +} + +void input_on_cursor_move(GLFWwindow* window, double xpos, double ypos) +{ + +} + +void input_get_cursor_pos(double* xpos, double* ypos) +{ + assert(xpos && ypos); + GLFWwindow* window = window_get_active(); + glfwGetCursorPos(window, xpos, ypos); +} + +void input_on_key(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + +} + +void input_on_mousebutton(GLFWwindow* window, int button, int action, int mods) +{ + +} + +void input_set_cursor_mode(Cursor_Mode mode) +{ + GLFWwindow* window = window_get_active(); + int cursor_mode = GLFW_CURSOR_NORMAL; + if(mode == CM_HIDDEN) + cursor_mode = GLFW_CURSOR_HIDDEN; + else if(mode == CM_HIDDEN) + cursor_mode = GLFW_CURSOR_DISABLED; + + glfwSetInputMode(window, GLFW_CURSOR, cursor_mode); +} + +bool input_get_key_state(int key, int state_type) +{ + GLFWwindow* window = window_get_active(); + int current_state = glfwGetKey(window, key); + return current_state == state_type ? true : false; +} + +bool input_get_mousebutton_state(int button, int state_type) +{ + GLFWwindow* window = window_get_active(); + int current_state = glfwGetMouseButton(window, button); + return current_state == state_type ? true : false; +} + diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..a31de4a --- /dev/null +++ b/src/input.h @@ -0,0 +1,23 @@ +#ifndef input_H +#define input_H + +#include + +struct GLFWwindow; +typedef struct GLFWwindow GLFWwindow; + +typedef enum +{ + CM_NORMAL = 0, + CM_LOCKED, + CM_HIDDEN +} Cursor_Mode; + +void input_init(GLFWwindow* window); +void input_cleanup(void); +bool input_get_mousebutton_state(int button, int state_type); +bool input_get_key_state(int key, int state_type); +void input_get_cursor_pos(double* xpos, double* ypos); +void input_set_cursor_mode(Cursor_Mode mode); + +#endif diff --git a/src/linmath.h b/src/linmath.h new file mode 100644 index 0000000..3216cd8 --- /dev/null +++ b/src/linmath.h @@ -0,0 +1,547 @@ +#ifndef linmath_H +#define linmath_H + +#include + +#define LINMATH_H_DEFINE_VEC(n) \ + typedef float vec##n[n]; \ + static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ + { \ + int i; \ + for(i=0; i 1e-4) { + vec3_norm(u, u); + mat4x4 T; + mat4x4_from_vec3_mul_outer(T, u, u); + mat4x4 S = { + { 0, u[2], -u[1], 0}, + {-u[2], 0, u[0], 0}, + { u[1], -u[0], 0, 0}, + { 0, 0, 0, 0} + }; + mat4x4_scale(S, S, s); + mat4x4 C; + mat4x4_identity(C); + mat4x4_sub(C, C, T); + mat4x4_scale(C, C, c); + mat4x4_add(T, T, C); + mat4x4_add(T, T, S); + T[3][3] = 1.; + mat4x4_mul(R, M, T); + } else { + mat4x4_dup(R, M); + } +} + +static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + {1.f, 0.f, 0.f, 0.f}, + {0.f, c, s, 0.f}, + {0.f, -s, c, 0.f}, + {0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} + +static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + { c, 0.f, s, 0.f}, + { 0.f, 1.f, 0.f, 0.f}, + { -s, 0.f, c, 0.f}, + { 0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} + +static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + { c, s, 0.f, 0.f}, + { -s, c, 0.f, 0.f}, + { 0.f, 0.f, 1.f, 0.f}, + { 0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} + +static inline void mat4x4_invert(mat4x4 T, mat4x4 M) +{ + float s[6]; + float c[6]; + s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; + s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; + s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; + s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; + s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; + s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; + c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; + c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; + c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; + c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; + c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; + c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; +/* Assumes it is invertible */ + float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); + T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; + T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; + T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; + T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; + T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; + T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; + T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; + T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; + T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; + T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; + T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; + T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; + T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; + T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; + T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; + T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; +} + +static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) +{ + mat4x4_dup(R, M); + float s = 1.; + vec3 h; + vec3_norm(R[2], R[2]); + s = vec3_mul_inner(R[1], R[2]); + vec3_scale(h, R[2], s); + vec3_sub(R[1], R[1], h); + vec3_norm(R[2], R[2]); + s = vec3_mul_inner(R[1], R[2]); + vec3_scale(h, R[2], s); + vec3_sub(R[1], R[1], h); + vec3_norm(R[1], R[1]); + s = vec3_mul_inner(R[0], R[1]); + vec3_scale(h, R[1], s); + vec3_sub(R[0], R[0], h); + vec3_norm(R[0], R[0]); +} + +static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ + M[0][0] = 2.f*n/(r-l); + M[0][1] = M[0][2] = M[0][3] = 0.f; + M[1][1] = 2.*n/(t-b); + M[1][0] = M[1][2] = M[1][3] = 0.f; + M[2][0] = (r+l)/(r-l); + M[2][1] = (t+b)/(t-b); + M[2][2] = -(f+n)/(f-n); + M[2][3] = -1.f; + M[3][2] = -2.f*(f*n)/(f-n); + M[3][0] = M[3][1] = M[3][3] = 0.f; +} + +static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ + M[0][0] = 2.f/(r-l); + M[0][1] = M[0][2] = M[0][3] = 0.f; + M[1][1] = 2.f/(t-b); + M[1][0] = M[1][2] = M[1][3] = 0.f; + M[2][2] = -2.f/(f-n); + M[2][0] = M[2][1] = M[2][3] = 0.f; + M[3][0] = -(r+l)/(r-l); + M[3][1] = -(t+b)/(t-b); + M[3][2] = -(f+n)/(f-n); + M[3][3] = 1.f; +} + +static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) +{ +/* NOTE: Degrees are an unhandy unit to work with. + * linmath.h uses radians for everything! */ + float const a = 1.f / tan(y_fov / 2.f); + m[0][0] = a / aspect; + m[0][1] = 0.f; + m[0][2] = 0.f; + m[0][3] = 0.f; + m[1][0] = 0.f; + m[1][1] = a; + m[1][2] = 0.f; + m[1][3] = 0.f; + m[2][0] = 0.f; + m[2][1] = 0.f; + m[2][2] = -((f + n) / (f - n)); + m[2][3] = -1.f; + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = -((2.f * f * n) / (f - n)); + m[3][3] = 0.f; +} + +static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) +{ +/* Adapted from Android's OpenGL Matrix.java. */ +/* See the OpenGL GLUT documentation for gluLookAt for a description */ +/* of the algorithm. We implement it in a straightforward way: */ +/* TODO: The negation of of can be spared by swapping the order of + * operands in the following cross products in the right way. */ + vec3 f; + vec3_sub(f, center, eye); + vec3_norm(f, f); + vec3 s; + vec3_mul_cross(s, f, up); + vec3_norm(s, s); + vec3 t; + vec3_mul_cross(t, s, f); + m[0][0] = s[0]; + m[0][1] = t[0]; + m[0][2] = -f[0]; + m[0][3] = 0.f; + m[1][0] = s[1]; + m[1][1] = t[1]; + m[1][2] = -f[1]; + m[1][3] = 0.f; + m[2][0] = s[2]; + m[2][1] = t[2]; + m[2][2] = -f[2]; + m[2][3] = 0.f; + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = 0.f; + m[3][3] = 1.f; + mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); +} + +typedef float quat[4]; + +static inline void quat_identity(quat q) +{ + q[0] = q[1] = q[2] = 0.f; + q[3] = 1.f; +} + +static inline void quat_add(quat r, quat a, quat b) +{ + int i; + for(i=0; i<4; ++i) + r[i] = a[i] + b[i]; +} + +static inline void quat_sub(quat r, quat a, quat b) +{ + int i; + for(i=0; i<4; ++i) + r[i] = a[i] - b[i]; +} + +static inline void quat_mul(quat r, quat p, quat q) +{ + vec3 w; + vec3_mul_cross(r, p, q); + vec3_scale(w, p, q[3]); + vec3_add(r, r, w); + vec3_scale(w, q, p[3]); + vec3_add(r, r, w); + r[3] = p[3]*q[3] - vec3_mul_inner(p, q); +} + +static inline void quat_scale(quat r, quat v, float s) +{ + int i; + for(i=0; i<4; ++i) + r[i] = v[i] * s; +} + +static inline float quat_inner_product(quat a, quat b) +{ + float p = 0.f; + int i; + for(i=0; i<4; ++i) + p += b[i]*a[i]; + return p; +} + +static inline void quat_conj(quat r, quat q) +{ + int i; + for(i=0; i<3; ++i) + r[i] = -q[i]; + r[3] = q[3]; +} + +static inline void quat_rotate(quat r, float angle, vec3 axis) { + vec3 v; + vec3_scale(v, axis, sinf(angle / 2)); + int i; + for(i=0; i<3; ++i) + r[i] = v[i]; + r[3] = cosf(angle / 2); +} + +#define quat_norm vec4_norm + +static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) +{ + quat v_ = {v[0], v[1], v[2], 0.f}; + quat_conj(r, q); + quat_norm(r, r); + quat_mul(r, v_, r); + quat_mul(r, q, r); +} + +static inline void mat4x4_from_quat(mat4x4 M, quat q) +{ + float a = q[3]; + float b = q[0]; + float c = q[1]; + float d = q[2]; + float a2 = a*a; + float b2 = b*b; + float c2 = c*c; + float d2 = d*d; + M[0][0] = a2 + b2 - c2 - d2; + M[0][1] = 2.f*(b*c + a*d); + M[0][2] = 2.f*(b*d - a*c); + M[0][3] = 0.f; + M[1][0] = 2*(b*c - a*d); + M[1][1] = a2 - b2 + c2 - d2; + M[1][2] = 2.f*(c*d + a*b); + M[1][3] = 0.f; + M[2][0] = 2.f*(b*d + a*c); + M[2][1] = 2.f*(c*d - a*b); + M[2][2] = a2 - b2 - c2 + d2; + M[2][3] = 0.f; + M[3][0] = M[3][1] = M[3][2] = 0.f; + M[3][3] = 1.f; +} + +static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) +{ +/* XXX: The way this is written only works for othogonal matrices. */ +/* TODO: Take care of non-orthogonal case. */ + quat_mul_vec3(R[0], q, M[0]); + quat_mul_vec3(R[1], q, M[1]); + quat_mul_vec3(R[2], q, M[2]); + R[3][0] = R[3][1] = R[3][2] = 0.f; + R[3][3] = 1.f; +} + +static inline void quat_from_mat4x4(quat q, mat4x4 M) +{ + float r=0.f; + int i; + int perm[] = { 0, 1, 2, 0, 1 }; + int *p = perm; + for(i = 0; i<3; i++) { + float m = M[i][i]; + if( m < r ) + continue; + m = r; + p = &perm[i]; + } + r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); + if(r < 1e-6) { + q[0] = 1.f; + q[1] = q[2] = q[3] = 0.f; + return; + } + q[0] = r/2.f; + q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); + q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); + q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); +} + +#endif diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..012bb21 --- /dev/null +++ b/src/log.c @@ -0,0 +1,24 @@ +#include +#include + +#include "log.h" + +void log_message(const char* message, ...) +{ + printf("MSG : "); + va_list list; + va_start(list, message); + vprintf(message, list); + va_end(list); + printf("\n"); +} + +void log_error(const char* context, const char* error, ...) +{ + printf("ERR (%s) : ", context); + va_list list; + va_start(list, error); + vprintf(error, list); + va_end(list); + printf("\n"); +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..d9f939a --- /dev/null +++ b/src/log.h @@ -0,0 +1,7 @@ +#ifndef log_H +#define log_H + +void log_message(const char* message, ...); +void log_error(const char* context, const char* error, ...); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6e38eea --- /dev/null +++ b/src/main.c @@ -0,0 +1,54 @@ +#define GLEW_STATIC +#include +#include + +#include "log.h" +#include "window_system.h" +#include "game.h" + + +const int WIN_WIDTH = 800; +const int WIN_HEIGHT = 600; + +int init(); +void cleanup(); + +int main(int argc, char** args) +{ + //Initialize window system and Glew + if(!init()) + log_error("Main:main", "Could not initialize"); + else + game_init(); + + cleanup(); + log_message("Program exiting!"); + return 0; +} + +int init(void) +{ + bool success = true; + if(window_init("Symmetry", WIN_WIDTH, WIN_HEIGHT)) + { + //Initialize GLEW + glewExperimental = GL_TRUE; + GLenum glewError = glewInit(); + if(glewError != GLEW_OK) + { + log_error("Main:init", "GLEW : %s", glewGetErrorString(glewError)); + success = false; + } + } + else + { + success = false; + } + return success; +} + +void cleanup() +{ + game_cleanup(); + window_cleanup(); +} diff --git a/src/renderer.c b/src/renderer.c new file mode 100644 index 0000000..443dbd1 --- /dev/null +++ b/src/renderer.c @@ -0,0 +1,25 @@ +#include "renderer.h" +#include "GLFW/glfw3.h" + +void on_framebuffer_size_change(GLFWwindow* window, int width, int height); + +void renderer_init(GLFWwindow* window) +{ + glClearColor(0.3f, 0.6f, 0.9f, 1.0f); + glfwSetFramebufferSizeCallback(window, on_framebuffer_size_change); +} + +void renderer_draw(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void renderer_cleanup(void) +{ + +} + +void on_framebuffer_size_change(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..d8d3646 --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,10 @@ +#ifndef renderer_H +#define renderer_H + +typedef struct GLFWwindow GLFWwindow; + +void renderer_init(GLFWwindow* window); +void renderer_draw(void); +void renderer_cleanup(void); + +#endif diff --git a/src/string_utils.c b/src/string_utils.c new file mode 100644 index 0000000..41ee8ae --- /dev/null +++ b/src/string_utils.c @@ -0,0 +1,107 @@ +#include +#include + +#include "string_utils.h" +#include "array.h" + +char* str_new(const char* string) +{ + size_t length = strlen(string); + char* new_string = malloc(length + 1); + strcpy(new_string, string); + return new_string; +} + +char* str_concat(char* string, const char* str_to_concat) +{ + size_t length = strlen(str_to_concat); + size_t length_orig = strlen(string); + + char* temp = realloc(string, length + length_orig + 1); /* +1 at the end to cope for null byte */ + if(temp) + { + string = temp; + strcat(string + length_orig, str_to_concat); + } + return string; +} + +char* str_replace(char* string, const char* pattern, const char* replacement) +{ + Array* indices = array_new(unsigned int); + size_t string_len = strlen(string); + + /* Calculate size of new string and allocate new memory */ + size_t pattern_len = strlen(pattern); + size_t replacement_len = strlen(replacement); + + bool done = false; + char* remaining_string = string; + while(!done) + { + char* location = strstr(remaining_string, pattern); + if(location) + { + unsigned int index = location - string; + unsigned int* new_index = array_add(indices); + *new_index = index; + remaining_string = location + pattern_len; /* Find the next occurance in the remaining string */ + } + else + { + done = true; + } + } + + if(indices->length > 0) + { + size_t string_len_without_pattern = string_len - (pattern_len * indices->length); + size_t new_string_len = string_len_without_pattern + (replacement_len * indices->length); + char* new_string = malloc(new_string_len); + + if(new_string) + { + done = false; + unsigned int count = 0; + unsigned int index = array_get_val(indices, unsigned int, count); + unsigned int prev_index = 0; + while(!done) + { + char* source_beg = string + prev_index; + char* source_end = string + index; + + strncat(new_string, source_beg, (source_end - source_beg)); + strcat(new_string, replacement); + + count++; + prev_index = index + pattern_len; + + if(count == indices->length) + { + done = true; + source_beg = string + prev_index; + strcat(new_string, source_beg); + } + else + { + index = array_get_val(indices, unsigned int, count); + } + } + free(string); + } + + array_free(indices); + return new_string; + } + else + { + return NULL; + } +} + + + + + + + diff --git a/src/string_utils.h b/src/string_utils.h new file mode 100644 index 0000000..270d914 --- /dev/null +++ b/src/string_utils.h @@ -0,0 +1,12 @@ +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +/* +Convenience methods for handling strings + */ + +char* str_new(const char* string); +char* str_concat(char* string, const char* str_to_concat); +char* str_replace(char* string, const char* pattern, const char* replacement); + +#endif diff --git a/src/window_system.c b/src/window_system.c new file mode 100644 index 0000000..2111cff --- /dev/null +++ b/src/window_system.c @@ -0,0 +1,94 @@ +#include "window_system.h" +#include "GLFW/glfw3.h" + +#include "log.h" + +static GLFWwindow* active_window = NULL; +static on_window_close window_close_custom = NULL; +static on_window_resize window_resize_custom = NULL; + +void window_error_callback(int error, const char* description); +void window_resize(GLFWwindow* window, int width, int height); +void window_close_callback(GLFWwindow* window); + +bool window_init(const char* title, int width, int height) +{ + bool success = true; + glfwSetErrorCallback(window_error_callback); + if(!glfwInit()) + { + log_error("window_create", "Initializing glfw failed"); + success = false; + } + else + { + const char* version = glfwGetVersionString(); + log_message("Initialized with %s", version); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + active_window = glfwCreateWindow(width, height, title, NULL, NULL); + if(!active_window) + { + log_error("window_create", "Failed to create window"); + success = false; + } + else + { + glfwMakeContextCurrent(active_window); + glfwSwapInterval(1); + glfwSetWindowSizeCallback(active_window, window_resize); + glfwSetWindowCloseCallback(active_window, window_close_callback); + } + } + return success; +} + +void window_error_callback(int error, const char* description) +{ + log_error("GLFW", "(%d) %s", error, description); +} + +void window_close_callback(GLFWwindow* window) +{ + if(!window_close_custom) + glfwSetWindowShouldClose(window, GL_TRUE); + else + window_close_custom(); +} + +void window_cleanup(void) +{ + if(active_window) glfwDestroyWindow(active_window); + glfwTerminate(); +} + +void window_poll_events(void) +{ + glfwPollEvents(); +} + +void window_swap_buffers(void) +{ + glfwSwapBuffers(active_window); +} + +void window_set_size(int width, int height) +{ + glfwSetWindowSize(active_window, width, height); +} + +void window_resize(GLFWwindow* window, int width, int height) +{ + /* Maybe resize main frame buffer here? */ + if(window_resize_custom) window_resize_custom(width, height); +} + +GLFWwindow* window_get_active(void) +{ + return active_window; +} + +bool window_should_close(void) +{ + return glfwWindowShouldClose(active_window); +} diff --git a/src/window_system.h b/src/window_system.h new file mode 100644 index 0000000..a547de3 --- /dev/null +++ b/src/window_system.h @@ -0,0 +1,22 @@ +#ifndef window_system_H +#define window_system_H + +#include + +struct GLFWwindow; +typedef struct GLFWwindow GLFWwindow; + +typedef void (*on_window_close) (void); // Callback for window close +typedef void (*on_window_resize) (int, int); // Callback that recieves window resize event +typedef void (*on_key) (int, int , int, int); // Callback for keyboard events +typedef void (*on_mouse_pos) (double, double); // Callback for mouse position + +bool window_init(const char* title, int width, int height); +void window_cleanup(void); +void window_set_size(int width, int height); +void window_poll_events(void); +void window_swap_buffers(void); +bool window_should_close(void); +GLFWwindow* window_get_active(void); + +#endif