commit
b764ec95e7
@ -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"))) |
||||||
|
)) |
@ -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" |
||||||
|
|
@ -0,0 +1,133 @@ |
|||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#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); |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
#ifndef ARRAY_H |
||||||
|
#define ARRAY_H |
||||||
|
|
||||||
|
#include <stddef.h> |
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
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 |
@ -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(); |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
#ifndef game_H |
||||||
|
#define game_H |
||||||
|
|
||||||
|
void game_init(void); |
||||||
|
void game_cleanup(void); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,72 @@ |
|||||||
|
#include <assert.h> |
||||||
|
#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; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,23 @@ |
|||||||
|
#ifndef input_H |
||||||
|
#define input_H |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
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 |
@ -0,0 +1,547 @@ |
|||||||
|
#ifndef linmath_H |
||||||
|
#define linmath_H |
||||||
|
|
||||||
|
#include <math.h> |
||||||
|
|
||||||
|
#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<n; ++i) \
|
||||||
|
r[i] = a[i] + b[i]; \
|
||||||
|
} \
|
||||||
|
static inline void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
r[i] = a[i] - b[i]; \
|
||||||
|
} \
|
||||||
|
static inline void vec##n##_scale(vec##n r, vec##n const v, float const s) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
r[i] = v[i] * s; \
|
||||||
|
} \
|
||||||
|
static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \
|
||||||
|
{ \
|
||||||
|
float p = 0.; \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
p += b[i]*a[i]; \
|
||||||
|
return p; \
|
||||||
|
} \
|
||||||
|
static inline float vec##n##_len(vec##n const v) \
|
||||||
|
{ \
|
||||||
|
return sqrtf(vec##n##_mul_inner(v,v)); \
|
||||||
|
} \
|
||||||
|
static inline void vec##n##_norm(vec##n r, vec##n const v) \
|
||||||
|
{ \
|
||||||
|
float k = 1.0 / vec##n##_len(v); \
|
||||||
|
vec##n##_scale(r, v, k); \
|
||||||
|
} |
||||||
|
|
||||||
|
LINMATH_H_DEFINE_VEC(2) |
||||||
|
LINMATH_H_DEFINE_VEC(3) |
||||||
|
LINMATH_H_DEFINE_VEC(4) |
||||||
|
|
||||||
|
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b) |
||||||
|
{ |
||||||
|
r[0] = a[1]*b[2] - a[2]*b[1]; |
||||||
|
r[1] = a[2]*b[0] - a[0]*b[2]; |
||||||
|
r[2] = a[0]*b[1] - a[1]*b[0]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n) |
||||||
|
{ |
||||||
|
float p = 2.f*vec3_mul_inner(v, n); |
||||||
|
int i; |
||||||
|
for(i=0;i<3;++i) |
||||||
|
r[i] = v[i] - p*n[i]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b) |
||||||
|
{ |
||||||
|
r[0] = a[1]*b[2] - a[2]*b[1]; |
||||||
|
r[1] = a[2]*b[0] - a[0]*b[2]; |
||||||
|
r[2] = a[0]*b[1] - a[1]*b[0]; |
||||||
|
r[3] = 1.f; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n) |
||||||
|
{ |
||||||
|
float p = 2.f*vec4_mul_inner(v, n); |
||||||
|
int i; |
||||||
|
for(i=0;i<4;++i) |
||||||
|
r[i] = v[i] - p*n[i]; |
||||||
|
} |
||||||
|
|
||||||
|
typedef vec4 mat4x4[4]; |
||||||
|
|
||||||
|
static inline void mat4x4_identity(mat4x4 M) |
||||||
|
{ |
||||||
|
int i, j; |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
for(j=0; j<4; ++j) |
||||||
|
M[i][j] = i==j ? 1.f : 0.f; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_dup(mat4x4 M, mat4x4 N) |
||||||
|
{ |
||||||
|
int i, j; |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
for(j=0; j<4; ++j) |
||||||
|
M[i][j] = N[i][j]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_row(vec4 r, mat4x4 M, int i) |
||||||
|
{ |
||||||
|
int k; |
||||||
|
for(k=0; k<4; ++k) |
||||||
|
r[k] = M[k][i]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_col(vec4 r, mat4x4 M, int i) |
||||||
|
{ |
||||||
|
int k; |
||||||
|
for(k=0; k<4; ++k) |
||||||
|
r[k] = M[i][k]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) |
||||||
|
{ |
||||||
|
int i, j; |
||||||
|
for(j=0; j<4; ++j) |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
M[i][j] = N[j][i]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
vec4_add(M[i], a[i], b[i]); |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
vec4_sub(M[i], a[i], b[i]); |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
vec4_scale(M[i], a[i], k); |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
vec4_scale(M[0], a[0], x); |
||||||
|
vec4_scale(M[1], a[1], y); |
||||||
|
vec4_scale(M[2], a[2], z); |
||||||
|
for(i = 0; i < 4; ++i) { |
||||||
|
M[3][i] = a[3][i]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b) |
||||||
|
{ |
||||||
|
mat4x4 temp; |
||||||
|
int k, r, c; |
||||||
|
for(c=0; c<4; ++c) for(r=0; r<4; ++r) { |
||||||
|
temp[c][r] = 0.f; |
||||||
|
for(k=0; k<4; ++k) |
||||||
|
temp[c][r] += a[k][r] * b[c][k]; |
||||||
|
} |
||||||
|
mat4x4_dup(M, temp); |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v) |
||||||
|
{ |
||||||
|
int i, j; |
||||||
|
for(j=0; j<4; ++j) { |
||||||
|
r[j] = 0.f; |
||||||
|
for(i=0; i<4; ++i) |
||||||
|
r[j] += M[i][j] * v[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z) |
||||||
|
{ |
||||||
|
mat4x4_identity(T); |
||||||
|
T[3][0] = x; |
||||||
|
T[3][1] = y; |
||||||
|
T[3][2] = z; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) |
||||||
|
{ |
||||||
|
vec4 t = {x, y, z, 0}; |
||||||
|
vec4 r; |
||||||
|
int i; |
||||||
|
for (i = 0; i < 4; ++i) { |
||||||
|
mat4x4_row(r, M, i); |
||||||
|
M[3][i] += vec4_mul_inner(r, t); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b) |
||||||
|
{ |
||||||
|
int i, j; |
||||||
|
for(i=0; i<4; ++i) for(j=0; j<4; ++j) |
||||||
|
M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle) |
||||||
|
{ |
||||||
|
float s = sinf(angle); |
||||||
|
float c = cosf(angle); |
||||||
|
vec3 u = {x, y, z}; |
||||||
|
if(vec3_len(u) > 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 |
@ -0,0 +1,24 @@ |
|||||||
|
#include <stdarg.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#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"); |
||||||
|
} |
@ -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 |
@ -0,0 +1,54 @@ |
|||||||
|
#define GLEW_STATIC |
||||||
|
#include <GL/glew.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#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(); |
||||||
|
} |
@ -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); |
||||||
|
} |
@ -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 |
@ -0,0 +1,107 @@ |
|||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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 |
@ -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); |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
#ifndef window_system_H |
||||||
|
#define window_system_H |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
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 |
Loading…
Reference in new issue