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