feat: added code

main
Sara 2024-01-25 14:08:23 +01:00
parent 8957fdd9bc
commit aee9aec828
14 changed files with 959 additions and 0 deletions

9
debug.c Normal file
View File

@ -0,0 +1,9 @@
#include "debug.h"
#if NDEBUG
int g_debug_error_abort = 0;
int g_debug_log_lvl = 0;
#else
int g_debug_error_abort = 1;
int g_debug_log_lvl = 3;
#endif

69
debug.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef _fencer_debug_h
#define _fencer_debug_h
#include <stdio.h>
#include <stdlib.h>
#ifndef NDEBUG
#include <assert.h>
#endif
extern int g_debug_error_abort;
extern int g_debug_log_lvl;
#define LOG_INFO(...) do {\
if(g_debug_log_lvl < 3) break;\
printf("[%s:%d] INFO | ", __FILE__, __LINE__);\
printf(__VA_ARGS__);\
printf("\n");\
} while(0)
#define LOG_ERROR(...) do {\
if(g_debug_log_lvl >= 1) {\
printf("[%s:%d] ERROR | ", __FILE__, __LINE__);\
printf(__VA_ARGS__);\
printf("\n");\
fflush(stdout);\
}\
if(g_debug_error_abort != 0) abort();\
} while(0)
#define LOG_WARNING(...) do {\
if(g_debug_log_lvl < 2) break;\
printf("[%s:%d] WARNING | ", __FILE__, __LINE__);\
printf(__VA_ARGS__);\
printf("\n");\
} while(0)
#define RETURN_ERROR(__VALUE, ...) do {\
LOG_ERROR(__VA_ARGS__);\
return __VALUE;\
} while(0)
#define RETURN_WARNING(__VALUE, ...) do {\
LOG_WARNING(__VA_ARGS__);\
return __VALUE;\
} while(0)
#define ASSERT_RETURN(__ASSERT, __RETURN, ...) do {\
if(!(__ASSERT)) {\
LOG_ERROR(__VA_ARGS__);\
return __RETURN;\
}\
} while(0)
#define CHECK(__ASSERT, ...) do {\
if(!(__ASSERT)) {\
LOG_ERROR(__VA_ARGS__);\
}\
} while(0)
#define ASSERT_RETURN_WARN(__ASSERT, __RETURN, ...) do {\
if(!(__ASSERT)) {\
LOG_WARNING(__VA_ARGS__);\
return __RETURN;\
}\
} while(0)
#endif // !_fencer_debug_h

116
dictionary.c Normal file
View File

@ -0,0 +1,116 @@
#include "dictionary.h"
#include "strutil.h"
#include "string.h"
#include "math.h"
typedef struct Key {
char* key;
uintptr_t hash;
} Key;
Dictionary dictionary_new(size_t element_size) {
return (Dictionary) {
.element_size = element_size,
.list = list_init(sizeof(Key) + element_size)
};
}
Key* internal_dictionary_get(Dictionary* self, uintptr_t keyhash, size_t* out_index) {
if(self->list.len == 0) {
if(out_index) *out_index = 0;
return NULL;
}
Key* element;
signed long l = 0, r = self->list.len, m;
while(l <= r) {
m = floor((double)(l+r)/2.0);
if(out_index != NULL) *out_index = m;
element = list_at_unchecked(&self->list, m);
if(keyhash < element->hash)
r = m-1;
else if(keyhash > element->hash)
l = m+1;
else
return element;
}
m = m >= 0 ? (m < self->list.len ? m : self->list.len - 1) : 0;
return list_at_as(Key, &self->list, m);
}
void* dictionary_get_raw(Dictionary* self, const char* key) {
uintptr_t hash = strhash(key);
Key* keyblock = internal_dictionary_get(self, hash, NULL);
return keyblock == NULL || strcmp(key, keyblock->key) != 0
? NULL
: ((char*)keyblock) + sizeof(Key);
}
static inline
int dictionary_insert_kvp(Dictionary* self, Key key, void* value, size_t index) {
// allocate a block of memory to insert into the list
char* insert_data = malloc(self->list.element_size);
if(insert_data == NULL)
return -1; // OOM
// fill block with key and value
memcpy(insert_data, &key, sizeof(Key));
memcpy(insert_data + sizeof(Key), value, self->element_size);
// decide add or insert based on current length of list
if(self->list.len == 0 || index >= self->list.len)
list_add(&self->list, insert_data);
else
list_insert(&self->list, insert_data, index);
// free allocated key-value block
free(insert_data);
return 0;
}
int dictionary_set_raw(Dictionary* self, const char* key, void* data) {
const uintptr_t keyhash = strhash(key);
size_t closest_index;
Key* closest = internal_dictionary_get(self, keyhash, &closest_index);
// get index of closest hash
// prepare key data
Key keydata = {
.hash = keyhash,
.key = malloc(strlen(key)+1)
};
strcpy(keydata.key, key);
if(closest == NULL) {
return dictionary_insert_kvp(self, keydata, data, closest_index);
} else if(closest->hash == keyhash && strcmp(closest->key, key) == 0) {
memcpy(closest + 1, data, self->element_size);
return 0;
} else if(keyhash < closest->hash) { // insert before
return dictionary_insert_kvp(self, keydata, data, closest_index);
} else {
return dictionary_insert_kvp(self, keydata, data, closest_index + 1);
}
}
int dictionary_erase(Dictionary* self, const char* key) {
const uintptr_t keyhash = strhash(key);
size_t index;
Key* element = internal_dictionary_get(self, keyhash, &index);
if(element->hash != keyhash || strcmp(key, element->key) != 0)
return -1; // not a match
// free the key string
free(element->key);
list_erase(&self->list, index);
return 0;
}
void dictionary_empty(Dictionary* self) {
list_empty(&self->list);
}
int dictionary_has_key(Dictionary* self, const char* key) {
return dictionary_get_raw(self, key) != NULL;
}
int dictionary_try_get(Dictionary* self, const char* key, void* out) {
void* found = dictionary_get_raw(self, key);
if(found == NULL)
return 0;
memmove(out, found, self->element_size);
return 1;
}

46
dictionary.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _fencer_hash_map_h
#define _fencer_hash_map_h
#include "list.h"
typedef struct Dictionary {
List list;
size_t element_size;
} Dictionary;
// returns a newly initialized dictionary
extern Dictionary dictionary_new(size_t element_size);
// gets a voidptr to the value identified by key
extern void* dictionary_get_raw(Dictionary* self, const char* key);
// inserts or overwrites a new entry identified by key
extern int dictionary_set_raw(Dictionary* self, const char* key, void* data);
// remove entry identified by key from dictionary
extern int dictionary_erase(Dictionary* self, const char* key);
// clear the contents of the dictionary
// erases all heap-allocated memory, the dictionary can be safely freed after
extern void dictionary_empty(Dictionary* self);
// find out if the dictionary contains a value identified by this key
// returns 1 if the key was found
// returns 0 if the key was not found
extern int dictionary_has_key(Dictionary* self, const char* key);
// try to find value identified as key in the dictionary.
// return 1 if the value was found, 0 if not.
// if dictionary_try_get returns 0, memory at out will be unchanged,
// if dictionary_try_get returns 1, found value will be copied into out
extern int dictionary_try_get(Dictionary* self, const char* key, void* out);
// insert or override value identified by key from a value type (supports rvalues)
#define dictionary_set_value(Type_, Dict_, Key_, Value_)\
{ Type_ __value = (Type_)Value_; dictionary_set_raw(Dict_, Key_, &__value); }
// initialize dictionary to fit values of Type_
#define dictionary_from_type(Type_)\
dictionary_new(sizeof(Type_))
// get a pointer to value identified by Key_
#define dictionary_get_as(Type_, Dict_, Key_)\
(Type_*)dictionary_get_raw(Dict_, Key_)
// get dereferenced value identified by Key_
#define dictionary_get_value(Type_, Dict_, Key_)\
*((Type_*)dictionary_get_raw(Dict_, Key_))
#endif // !_fencer_hash_map_h

176
list.c Normal file
View File

@ -0,0 +1,176 @@
#include "list.h"
#include "stdint.h"
#include "stdlib.h"
#include "string.h"
#include "debug.h"
#ifndef LIST_DEFAULT_RESERVE
#define LIST_DEFAULT_RESERVE 4
#endif
List list_init(size_t element_size) {
List self = {
.element_size = element_size,
.cap = LIST_DEFAULT_RESERVE,
.len = 0,
.data = malloc(element_size * LIST_DEFAULT_RESERVE),
};
if(self.data == NULL) {
LOG_ERROR("Failed to allocate list with starting capacity of %d", LIST_DEFAULT_RESERVE);
self.cap = 0;
}
return self;
}
List list_copy(const List* source) {
List self = list_init(source->element_size);
list_reserve(&self, source->cap);
if(self.cap > 0) {
memcpy(self.data, source->data, source->element_size * source->len);
self.len = source->len;
} else {
LOG_ERROR("Failed to reserve space");
}
return self;
}
void list_empty(List* self) {
if(self->data == NULL || self->cap == 0)
return;
self->data = NULL;
self->cap = 0;
self->len = 0;
}
void list_reserve(List* self, size_t at_least) {
if(at_least < self->cap)
return;
size_t new_cap = self->cap > 0 ? self->cap : LIST_DEFAULT_RESERVE;
while(at_least >= new_cap) {
new_cap *= 2;
}
void* new;
if(self->data == NULL)
new = malloc(new_cap * self->element_size);
else
new = realloc(self->data, new_cap * self->element_size);
ASSERT_RETURN(new != NULL,, "Failed to reserve space for %zu extra elements in list", new_cap);
self->data = new;
self->cap = new_cap;
}
void* list_at_unchecked(List* self, size_t at) {
union {
uint8_t* as_byte;
void* as_void;
} data = {
.as_void = self->data
};
return data.as_byte + self->element_size * at;
}
void* list_at(List* self, size_t at) {
ASSERT_RETURN(at < self->len, NULL, "Index %zu out of bounds", at);
return list_at_unchecked(self, at);
}
size_t list_add(List* self, void* item) {
list_reserve(self, self->len + 1);
union {
uint8_t* as_byte;
void* as_void;
} data = {
.as_void = self->data
};
uint8_t* into = data.as_byte + (self->element_size * self->len);
memcpy(into, item, self->element_size);
++self->len;
return self->len - 1;
}
void list_insert(List* self, void* item, size_t at) {
list_reserve(self, self->len + 1);
if(at >= self->len) {
list_add(self, item);
return;
}
union {
uint8_t* as_byte;
void* as_void;
} data = {
.as_void = self->data
};
uint8_t* from = data.as_byte + (self->element_size * at);
uint8_t* into = data.as_byte + (self->element_size * (at + 1));
uint8_t* end = data.as_byte + (self->element_size * self->len);
memmove(into, from, end - from);
memcpy(from, item, self->element_size);
++self->len;
}
void list_erase(List* self, size_t at) {
ASSERT_RETURN(at < self->len,, "Index %zu out of bounds", at);
union {
uint8_t* as_byte;
void* as_void;
} data = {
.as_void = self->data
};
uint8_t* into = data.as_byte + at * self->element_size;
uint8_t* from = data.as_byte + (at + 1) * self->element_size;
if(at < self->len - 1)
memmove(into, from, (self->len - at) * self->element_size);
--self->len;
size_t new_cap = self->cap;
while(new_cap > self->len) {
new_cap /= 2;
}
new_cap *= 2;
if(new_cap == self->cap)
return;
void* shrunk = realloc(self->data, new_cap * self->element_size);
ASSERT_RETURN(shrunk != NULL || new_cap == 0,, "Failed to shrink List to %zu", new_cap);
self->data = shrunk;
self->cap = new_cap;
}
void* list_iterator_begin(List* self) {
return list_at_unchecked(self, 0);
}
void* list_iterator_end(List* self) {
return list_at_unchecked(self, self->len);
}
size_t list_contains(List* self, void* query) {
union {
uint8_t* as_byte;
void* as_void;
} data = {
.as_void = self->data
};
for(size_t i = 0; i < self->len; ++i) {
if(memcmp(data.as_byte + (i * self->element_size), query, self->element_size) == 0)
return i;
}
return self->len;
}

38
list.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef _fencer_list_h
#define _fencer_list_h
#include "stddef.h"
typedef struct List List;
struct List {
void* data;
size_t cap;
size_t len;
size_t element_size;
};
extern List list_init(size_t element_size);
extern List list_copy(const List* source);
extern void list_empty(List* list);
extern void list_reserve(List* self, size_t at_least);
extern void* list_at(List* list, size_t at);
extern void* list_at_unchecked(List* self, size_t at);
extern size_t list_add(List* self, void* item);
extern void list_insert(List* self, void* item, size_t at);
extern void list_erase(List* self, size_t at);
extern void* list_iterator_begin(List* self);
extern void* list_iterator_end(List* self);
extern size_t list_contains(List* self, void* query);
#define list_from_type(T) list_init(sizeof(T))
#define list_foreach(T, iter, list) for(T iter = list_iterator_begin(list); iter != (T)list_iterator_end(list); ++iter)
#define list_at_as(T, __list, __i) ((T*)(list_at(__list, __i)))
#define list_iterator_begin_as(T, __list) ((T*)(list_iterator_begin(__list)))
#endif // !_fencer_list_h

21
mirror.c Normal file
View File

@ -0,0 +1,21 @@
#include "mirror.h"
MirroredTypeclass* internal_mirror_get_typeclass(void* self, IMirror const* tc, const char* typeclass) {
return dictionary_get_raw(tc->get_typeclasses(self), typeclass);
}
const void* mirror_get_typeclass(void* data, IMirror const* tc, const char* typeclass) {
MirroredTypeclass* class = internal_mirror_get_typeclass(data, tc, typeclass);
if(class != NULL)
return class->typeclass;
else
return NULL;
}
void* mirror_get_function(void* data, IMirror const* tc, const char* typeclass_name) {
MirroredTypeclass* class = internal_mirror_get_typeclass(data, tc, typeclass_name);
if(class != NULL)
return class->function;
else
return NULL;
}

126
mirror.h Normal file
View File

@ -0,0 +1,126 @@
#ifndef _fencer_mirror_h
#define _fencer_mirror_h
#include "typeclass_helpers.h"
#include "stdint.h"
#include "string.h"
#include "dictionary.h"
#include "strutil.h" // included because the impl macros require strhash
typedef uintptr_t typeid;
typedef struct {
const char* (*const get_typestring)(void* self);
typeid (*const get_typeid)(void* self);
Dictionary* (*const get_typeclasses)(void* self);
} IMirror;
typedef struct {
void* data;
union {
IMirror const* tc;
// this is cursed, but it allows the TC_CAST macro to work
IMirror const* mirror;
};
} Mirror;
typedef struct {
const void* typeclass;
void* function;
} MirroredTypeclass;
static inline int mirror_is_typeid(const Mirror* mirror, typeid id) {
return mirror->tc->get_typeid(mirror->data) == id;
}
static inline int mirror_is_typestring(const Mirror* mirror, const char* id) {
return strcmp(id, mirror->tc->get_typestring(mirror->data)) == 0;
}
static inline int mirror_eq(const Mirror* lhs, const Mirror* rhs) {
return lhs->tc->get_typeid(lhs->data) == rhs->tc->get_typeid(rhs->data);
}
extern const void* mirror_get_typeclass(void* data, IMirror const* tc, const char* typeclass);
// get the wrapper function for a given typeclass name
// example:
// mirror_get_function(physics_entity.data, physics_entity.mirror, "BehaviourEntity")
extern void* mirror_get_function(void* data, IMirror const* tc, const char* typeclass_name);
// macro reexport of mirror_get_function which will cast the function so it can be called immediately
// example:
// MIRROR_GET_WRAP_FUNC(physics_entity.data, physics_entity.mirror, BehaviourEntity)(physics_entity.data)
#define MIRROR_GET_WRAP_FUNC(Data_, MirrorTc_, Typeclass_)\
((Typeclass_(*)(void*))mirror_get_function(Data_, MirrorTc_, #Typeclass_))
// casting only works if the typeclass in question exposes IMirror as .mirror
// will segfault if the Mirror does not expose To_
// example:
// TC_CAST(physics_entity, BehaviourEntity)
#define TC_CAST(From_, To_)\
MIRROR_GET_WRAP_FUNC(From_.data, From_.mirror, To_)(From_.data)
#define TC_MIRRORS(From_, To_)\
MIRROR_GET_WRAP_FUNC(From_.data, From_.mirror, To_) != NULL
#define MIRROR_TRY_WRAP(Into_, Mirror_, Typeclass_){\
MirroredTypeclassWrapFunc fn_ = mirror_get_typeclass(Mirror_, #Typeclass_);\
if(fn_ != NULL) {\
Into_ = (TypeClass_)fn(Mirror_->data);\
}\
}
#define impl_Mirror_for(T, get_typestring_f, get_typeid_f, get_typeclasses_f)\
Mirror T##_as_Mirror(T* x) {\
TC_FN_TYPECHECK(const char*, get_typestring_f, T*);\
TC_FN_TYPECHECK(typeid, get_typeid_f, T*);\
TC_FN_TYPECHECK(Dictionary*, get_typeclasses_f, T*);\
static IMirror const tc = {\
.get_typestring = (const char*(*const)(void*)) get_typestring_f,\
.get_typeid = (typeid (*const)(void*)) get_typeid_f,\
.get_typeclasses = (Dictionary* (*const)(void*)) get_typeclasses_f,\
};\
return (Mirror){.tc = &tc, .data = x};\
}
#define DECL_REFLECT(T)\
extern const char* T##_get_typestring(T* self);\
extern typeid T##_get_typeid(T* self);\
extern Dictionary* T##_get_typeclasses(T* self);\
decl_typeclass_impl(Mirror, T)
#define START_REFLECT(T)\
const char* T##_get_typestring(T* self) {\
static const char* const typestring = #T;\
return typestring;\
}\
typeid T##_get_typeid(T* self) {\
static char init_flag = 0;\
static typeid id = 0;\
if(!init_flag) {\
init_flag = 1;\
id = strhash(#T);\
}\
return id;\
}\
Dictionary* T##_get_typeclasses(T* self) {\
static char init_flag = 0;\
static Dictionary typeclasses;\
if(!init_flag) {\
init_flag = 1;\
typeclasses = dictionary_new(sizeof(MirroredTypeclass));\
MirroredTypeclass tc;\
REFLECT_TYPECLASS(T, Mirror)
#define REFLECT_TYPECLASS(T, TypeClass_)\
tc = (MirroredTypeclass){\
.typeclass = (void*)T##_as_##TypeClass_(NULL).tc,\
.function = (void*)T##_as_##TypeClass_\
};\
dictionary_set_raw(&typeclasses, #TypeClass_, &tc);
#define END_REFLECT(T)\
}\
return &typeclasses;\
}\
impl_Mirror_for(T, T##_get_typestring, T##_get_typeid, T##_get_typeclasses)
#endif // !_fencer_mirror_h

54
strutil.c Normal file
View File

@ -0,0 +1,54 @@
#include "strutil.h"
#include "string.h"
uintptr_t strnhash(const char* s, size_t n) {
static const size_t shift = sizeof(uintptr_t) * 8 - 4;
uintptr_t hash = 0;
for(size_t i = 0; i < n; ++i) {
hash = ((hash << 4) | s[i]) ^ (((uintptr_t)0xF << shift) & hash);
}
return hash;
}
uintptr_t strhash(const char* s) {
return strnhash(s, strlen(s));
}
long strlast(const char* rbegin, const char* rend, char search) {
const char* itr = rbegin;
while(itr < rend && *itr != '\0')
if(*itr == search) return itr - rend;
else itr--;
return -1;
}
long strfirst(const char* begin, const char* end, char search) {
const char* itr = begin;
while(itr < end && *itr != '\0')
if(*itr == search) return itr - begin;
else itr++;
return -1;
}
long strcount(const char* begin, const char* end, char search) {
long count = 0;
for(;begin < end && *begin != '\0'; ++begin)
if(*begin == search) ++count;
return count;
}
long strfirst_pred(const char* begin, const char* end, CharPredFn pred) {
const char* itr = begin;
while(itr < end && *itr != '\0')
if(pred(*itr)) return itr - begin;
else itr++;
return -1;
}
long strlast_pred(const char* rbegin, const char* rend, CharPredFn pred) {
const char* itr = rbegin;
while(itr < rend && *itr != '\0')
if(pred(*itr)) return itr - rend;
else itr--;
return -1;
}

17
strutil.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _fencer_strutil_h
#define _fencer_strutil_h
#include "stdlib.h"
#include "stdint.h"
typedef int(*CharPredFn)(int);
extern uintptr_t strnhash(const char* s, size_t n);
extern uintptr_t strhash(const char* s);
extern long strlast(const char* rbegin, const char* rend, char search);
extern long strfirst(const char* begin, const char* end, char search);
extern long strcount(const char* begin, const char* end, char search);
extern long strfirst_pred(const char* begin, const char* end, CharPredFn pred);
extern long strlast_pred(const char* rbegin, const char* rend, CharPredFn pred);
#endif // !_fencer_strutil_h

10
typeclass_helpers.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _fencer_typeclass_helpers_h
#define _fencer_typeclass_helpers_h
#define TC_FN_TYPECHECK(__Return, __Name, ...)\
__Return (*const __Name##_)(__VA_ARGS__) = __Name; (void)__Name##_
#define decl_typeclass_impl(__Typeclass, __Type)\
extern __Typeclass __Type##_as_##__Typeclass(__Type*);
#endif // !_fencer_typeclass_helpers_h

61
variant.c Normal file
View File

@ -0,0 +1,61 @@
#include "variant.h"
#include "debug.h"
#include "ctype.h"
#include "string.h"
#include "strutil.h"
Variant variant_from_str(const char* str) {
size_t length = strlen(str);
if(isdigit(str[0])) {
// variant is a number
// convert to double
return NumberVariant(atof(str));
} else if(str[0] == '"') {
// variant should be a string
// format: "<content>"
// copy the input string without the quotes
size_t result_length = strfirst(str+1, str+length, '"');
char* string = malloc(result_length);
strncpy(string, str+1, result_length-1);
string[result_length] = '\0';
return StringVariant(string, result_length);
} else if(strncmp(str, "Vector(", 7) == 0) {
// variant is a vector
// format: Vector(<x>, <y>)
// get the location of the brackets
long close_bracket = strfirst(str, str + length, ')');
if(close_bracket == -1) goto variant_from_str_err;
char buf[24]; buf[23] = '\0';
// copy what is within the brackets
// 7 is the number of characters in "Vector(", which should be skipped
strncpy(buf, str + 7, close_bracket - 7);
length = strlen(buf);
long comma_ind = strfirst(buf, buf+length, ',');
if(comma_ind == -1) goto variant_from_str_err;
// split the string at the comma by inserting a null terminator
buf[comma_ind] = '\0';
return VectorVariant(MakeVector(atof(buf), atof(buf + comma_ind + 1)));
}
variant_from_str_err:
return UndefinedVariant();
}
void destroy_variant(Variant* self) {
destroy_contained(self);
free(self);
}
void destroy_contained(Variant* self) {
switch(self->type) {
default: break;
case Variant_String:
if(self->as_string != NULL)
free(self->as_string);
self->as_string = NULL;
break;
case Variant_Object:
free(self->as_object);
self->as_object = NULL;
break;
}
}

35
variant.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _fencer_variant_h
#define _fencer_variant_h
#include "vmath.h"
typedef enum VariantType {
Variant_Undefined = 0x0,
Variant_Number = 0x1,
Variant_Vector = 0x2,
Variant_Object = 0x3,
Variant_String = 0x4,
} VariantType;
typedef struct Variant {
VariantType type;
size_t string_size;
union {
double as_number;
Vector as_vector;
void* as_object;
char* as_string;
};
} Variant;
extern Variant variant_from_str(const char* str);
extern void destroy_variant(Variant* self);
extern void destroy_contained(Variant* self);
#define NumberVariant(Value_) (Variant){.type = Variant_Number, .as_number = Value_}
#define VectorVariant(Value_) (Variant){.type = Variant_Vector, .as_vector = Value_}
#define ObjectVariant(Value_) (Variant){.type = Variant_Object, .as_object = Value_}
#define StringVariant(Value_, BufSize_) (Variant){.type = Variant_String, .as_string = Value_, .string_size = BufSize_}
#define UndefinedVariant() (Variant){.type = Variant_Undefined }
#endif // !_fencer_variant_h

181
vmath.h Normal file
View File

@ -0,0 +1,181 @@
#ifndef _fencer_vmath_h
#define _fencer_vmath_h
#include "stddef.h"
#include <math.h>
#if defined _WIN32 && ! defined isnanf
# define isnanf(x) _isnanf(x)
# define HAVE_ISNANF
#endif
#if VMATH_SDL == 1
#include <SDL2/SDL_rect.h>
typedef SDL_FPoint Vector;
typedef SDL_Point IVector;
#else
typedef struct Vector {
float x;
float y;
} Vector;
typedef struct IVector {
int x;
int y;
} IVector;
#endif
// Vector Constant Macros
#define ZeroVector (Vector){0.0f, 0.0f}
#define InfinityVector (Vector){INFINITY, INFINITY}
#define OneVector (Vector){1.0f,1.0f}
#define UpVector (Vector){0.0f,-1.0f}
#define RightVector (Vector){1.0f,0.0f}
#define LeftVector (Vector){-1.0f,0.0f}
#define DownVector (Vector){0.0f,1.0f}
#define MakeVector(__X, __Y) (Vector){__X, __Y}
#define VectorFrom(__A) (Vector){__A, __A}
// Integer Vector Constant Macros
#define ZeroIVector (IVector){0,0}
#define OneIVector (IVector){1,1}
#define UpIVector (IVector){-1,0}
#define DownIVector (IVector){1,0}
#define RightIVector (IVector){1,0}
#define LeftIVector (IVector){-1,0}
#define MakeIVector(__X, __Y) (IVector){__X, __Y}
#define IVectorFrom(__A) (IVector){__A, __A}
///
// Floating point vector maths functions.
///
static inline
int veqf(Vector a, Vector b) {
const float e = 0.0001f;
return fabsf(a.x - b.x) + fabsf(a.y - b.y) < e;
}
static inline
int visnanf(Vector a) {
return isnanf(a.x) || isnanf(a.y);
}
static inline
Vector vaddf(Vector a, Vector b) {
return (Vector){a.x + b.x, a.y + b.y};
}
static inline
Vector vsubf(Vector a, Vector b) {
return (Vector){a.x - b.x, a.y - b.y};
}
static inline
Vector vmulff(Vector a, float b) {
return (Vector){a.x * b, a.y * b};
}
static inline
Vector vmulf(Vector a, Vector b) {
return (Vector) {a.x * b.x, a.y * b.y};
}
static inline
Vector vinvf(Vector a) {
return (Vector){-a.x, -a.y};
}
static inline
Vector vperpendicularf(Vector a) {
return (Vector){a.y, -a.x};
}
static inline
float vmagnitudef(Vector a) {
if(veqf(a, ZeroVector)) return 0.f;
a.x = fabsf(a.x);
a.y = fabsf(a.y);
return sqrtf(a.x*a.x + a.y*a.y);
}
static inline
float vsqrmagnitudef(Vector a) {
a.x = fabsf(a.x);
a.y = fabsf(a.y);
return a.x*a.x + a.y*a.y;
}
static inline
Vector vnormalizedf(Vector a) {
if(veqf(a, ZeroVector)) return ZeroVector;
return vmulff(a, 1.0f/vmagnitudef(a));
}
static inline
float vdotf(Vector a, Vector b) {
return (a.x*b.x) + (a.y*b.y);
}
static inline
float vdistancef(Vector a, Vector b) {
return vmagnitudef(vsubf(a, b));
}
static inline
float vsqrdistf(Vector a, Vector b) {
return vsqrmagnitudef(vsubf(a, b));
}
static inline
Vector vreciprocalf(Vector a) {
return (Vector){1.0f/a.x, 1.0f/a.y};
}
static inline
Vector vrotatef(Vector a, float t) {
return (Vector){
cosf(t) * a.x - sinf(t) * a.y,
sinf(t) * a.x + cosf(t) * a.y
};
}
static inline
float vanglebetweenf(Vector a, Vector b) {
return vdotf(a, b) / (vmagnitudef(a) * vmagnitudef(b));
}
static inline
Vector vprojectf(Vector onto, Vector from) {
float dot = vdotf(onto, from);
return vmulff(onto, dot);
}
static inline
Vector vlerpf(Vector start, Vector end, float t) {
if(veqf(start, end))
return end;
t = fminf(fmaxf(0.0f, t), 1.0f);
return vaddf(start, vmulff(vsubf(end, start), t));
}
static inline
Vector vmovetowardsf(Vector start, Vector end, float delta) {
return vlerpf(start, end, delta / vdistancef(end, start));
}
static inline
Vector vaveragef(Vector* array, size_t count) {
Vector acc = ZeroVector;
for(size_t i = 0; i < count; ++i) {
acc = vaddf(acc, array[i]);
}
return vmulff(acc, 1.0f/(float)count);
}
static inline
int veqi(IVector a, IVector b) {
return a.x == b.x && a.y == b.y;
}
static inline
IVector vaddi(IVector a, IVector b) {
return (IVector){a.x + b.x, a.y + b.y};
}
static inline
IVector vsubi(IVector a, IVector b) {
return (IVector){a.x - b.x, a.y - b.y};
}
static inline
IVector vmuli(IVector a, IVector b) {
return (IVector){a.x * b.x, a.y * b.y};
}
#endif // !_fencer_vmath_h