summaryrefslogtreecommitdiff
path: root/include/engine
diff options
context:
space:
mode:
Diffstat (limited to 'include/engine')
-rw-r--r--include/engine/btree.h57
-rw-r--r--include/engine/engine.h138
-rw-r--r--include/engine/fov.h26
-rw-r--r--include/engine/hashmap.h55
-rw-r--r--include/engine/list.h11
-rw-r--r--include/engine/logging.h44
-rw-r--r--include/engine/memory.h25
-rw-r--r--include/engine/rendering.h81
-rw-r--r--include/engine/stack.h49
-rw-r--r--include/engine/state.h22
-rw-r--r--include/engine/types.h32
-rw-r--r--include/engine/ui.h234
-rw-r--r--include/engine/utils.h34
-rw-r--r--include/engine/vector.h31
14 files changed, 839 insertions, 0 deletions
diff --git a/include/engine/btree.h b/include/engine/btree.h
new file mode 100644
index 0000000..5405e7e
--- /dev/null
+++ b/include/engine/btree.h
@@ -0,0 +1,57 @@
+#ifndef BTREE_H
+#define BTREE_H
+
+#include <stddef.h>
+
+#define BTREE_DEGREE_DEFAULT 4
+
+#define BTREE_SIZE_MIN 8
+#define BTREE_SIZE_MAX 4096
+
+#define BTREE_CMP_LT ( -1 )
+#define BTREE_CMP_EQ ( 0 )
+#define BTREE_CMP_GT ( 1 )
+
+struct btree;
+struct btree_iter_t;
+
+/* elem_size: the size of the elements, typically `sizeof(struct <your struct>)`
+ * t: degree of the btree, if you're in doubt, use `BTREE_SIZE_DEFAULT`
+ * cmp: comparison function, in order to support any operations on the tree.
+ *
+ * This function just calls `btree_new_with_allocator` with `free` and `malloc`
+ * as initializers.
+ */
+struct btree* btree_new(size_t elem_size,
+ size_t t,
+ int (*cmp)(const void *a, const void *b));
+
+/* Same as `btree_new`, except that it actually initializes a btree, but with
+ * the given allocators.
+ */
+struct btree* btree_new_with_allocator(
+ size_t elem_size,
+ size_t t,
+ int (*cmp)(const void *a, const void *b),
+ void *(*alloc)(size_t),
+ void (*dealloc)(void*));
+
+void btree_free(struct btree **btree);
+
+void* btree_search(struct btree *btree, void *elem);
+void btree_insert(struct btree *btree, void *elem);
+int btree_delete(struct btree *btree, void *elem);
+
+void btree_print(struct btree *btree, void (*print_elem)(const void*));
+
+void* btree_first(struct btree *btree);
+void* btree_last(struct btree *btree);
+
+size_t btree_size(struct btree *btree);
+
+struct btree_iter_t* btree_iter_t_new(struct btree* tree);
+void btree_iter_t_reset(struct btree *tree, struct btree_iter_t** it);
+
+void* btree_iter(struct btree *tree, struct btree_iter_t *iter);
+
+#endif
diff --git a/include/engine/engine.h b/include/engine/engine.h
new file mode 100644
index 0000000..bd961a6
--- /dev/null
+++ b/include/engine/engine.h
@@ -0,0 +1,138 @@
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <stdbool.h>
+
+#include <engine/types.h>
+#include <engine/stack.h>
+#include <engine/vector.h>
+#include <engine/memory.h>
+#include <engine/logging.h>
+#include <engine/state.h>
+
+typedef struct {
+ u32 texture_id;
+ i32 x, y,
+ w, h;
+} RenderUnit;
+
+typedef struct {
+ const char *font_path;
+ i32 ptsize;
+} FontSpec;
+
+typedef struct {
+ i32 width;
+ i32 height;
+ const char *path;
+} TextureSpec;
+
+typedef struct Window Window;
+
+typedef struct Keybinding {
+ i32 keycode;
+ i32 modifiers;
+ void (*action)(void*);
+} Keybinding;
+
+typedef struct {
+ void *data; /* Contains textures and such */
+ u64 data_len;
+
+ Window *window;
+ bool quit;
+
+ u64 frame;
+ f32 fps_target;
+
+ v2_i32 mouse_pos;
+
+ v2_i32 mousedown;
+ v2_i32 mouseup;
+
+ bool mouse_lclick;
+ bool mouse_rclick;
+
+ i32 camera_x;
+ i32 camera_y;
+
+ /* Text input/editing is currently not used/implemented */
+ char *edit_text;
+ usize edit_pos;
+
+ memory *mem;
+
+ void *bindings;
+} Platform;
+
+/* Essential functions */
+Platform *engine_init(
+ const char *windowtitle,
+ v2_i32 windowsize,
+ const f32 render_scale,
+ const u32 flags,
+ const usize initial_memory,
+ const FontSpec *fonts[],
+ const TextureSpec *textures[]);
+
+i32 engine_run(Platform *p, StateType initial_state);
+
+void engine_stop(Platform *p);
+
+/* Utility functions */
+void engine_fps_max(u64 cap);
+void engine_bindkey(i32 key, void (*action)(void*));
+
+void render_set_zoom(f32 new_zoom);
+void render_adjust_zoom(f32 diff);
+void render_add_unit(RenderUnit *u);
+
+u32 get_time(void);
+v2_i32 get_windowsize(void);
+v2_i32 *get_mousepos(void);
+
+#include "rendering.h"
+
+#ifdef ENGINE_INTERNALS
+
+#define MAX(a,b) (a > b ? a : b)
+
+/* Window */
+struct Window {
+ SDL_Window *window;
+ SDL_Renderer *renderer;
+ f32 render_scale;
+
+ v2_i32 windowsize;
+
+ i32* game_w;
+ i32* game_h;
+};
+
+typedef struct {
+ SDL_Texture *texture;
+ const i32 tilesize;
+ const i32 width;
+ const i32 height;
+} Texture;
+
+struct Resources {
+ usize textures_len;
+ usize textures_size;
+ usize fonts_len;
+
+ usize texturepaths_len;
+ usize fontpaths_len;
+
+ /* Paths for our sources, kept in case the user wants to reload them */
+ TextureSpec **texture_paths;
+ FontSpec **font_paths;
+
+ /* Our actual sources */
+ Texture **textures;
+ TTF_Font **fonts;
+};
+
+
+#endif
+#endif
diff --git a/include/engine/fov.h b/include/engine/fov.h
new file mode 100644
index 0000000..3af421e
--- /dev/null
+++ b/include/engine/fov.h
@@ -0,0 +1,26 @@
+#ifndef ENGINE_FOV_H
+#define ENGINE_FOV_H
+
+#include <stdbool.h>
+#include "types.h"
+#include "vector.h"
+
+/* `fov_shadowcast`: */
+/* map: your 2D enum tile grid
+ * mapsize: x: width, y: height of the map
+ * visblocking: pointer to a function that returns `true` when receiving a
+ * pointer to a LOS blocking tile
+ * lightmap: [out] 2D lightmap, this is simply overwritten with the distance to
+ * the source.
+ * range: visibility range/radius.
+ * src: 2D point to calculate FOV from
+ * */
+void fov_shadowcast(
+ const void *map,
+ const v2_i32 mapsize,
+ bool (*visblocking)(const void*),
+ i32 *lightmap,
+ const i32 range,
+ v2_i32 src);
+
+#endif
diff --git a/include/engine/hashmap.h b/include/engine/hashmap.h
new file mode 100644
index 0000000..4b97b8e
--- /dev/null
+++ b/include/engine/hashmap.h
@@ -0,0 +1,55 @@
+#ifndef ENGINE_HASHMAP_H
+#define ENGINE_HASHMAP_H
+
+#include "types.h"
+
+#include <stdlib.h>
+#include "list.h"
+#include "memory.h"
+
+
+i32 lolhash(const usize s, i32 v);
+
+/* Define a linked list before using this */
+/* Example: DEFINE_LLIST(i32) */
+#define DEFINE_HASHMAP(type, lsize, cmp, type_to_int) \
+typedef DEFINE_LLIST(type); \
+typedef struct hashmap_##type { \
+ usize size; \
+ List_##type elems[64]; \
+} hashmap_##type; \
+ \
+type* hashmap_##type##_lookup(hashmap_##type* hmap, const type* val) { \
+ const i32 idx = lolhash(64, type_to_int(val)); \
+ List_##type *head = &hmap->elems[idx]; \
+ while (head != NULL) { \
+ if (!cmp(&(head->value), val)) return &(head->value); \
+ head = head->next; \
+ } \
+ return NULL; \
+} \
+ \
+void hashmap_##type##_insert(memory *m, hashmap_##type *hmap, const type *val) { \
+ const i32 idx = lolhash(64, type_to_int(val)); \
+ List_##type *head = &(hmap->elems[idx]); \
+ \
+ /* This is highly dependant on whether the memory is zero-initialized */ \
+ if (!type_to_int(&(head->value))) \
+ { \
+ memcpy(&(head->value), val, sizeof(type)); \
+ return; \
+ } \
+ \
+ \
+ while (head->next != NULL && cmp(&head->value, val)) { \
+ head = head->next; \
+ } \
+ \
+ if (!cmp(&head->value, val)) memcpy(&(head->value), val, sizeof(type)); \
+ else { \
+ head->next = memory_allocate(m, sizeof(List_##type)); \
+ memcpy(&(head->next->value), val, sizeof(type)); \
+ } \
+}
+
+#endif
diff --git a/include/engine/list.h b/include/engine/list.h
new file mode 100644
index 0000000..5d3f80b
--- /dev/null
+++ b/include/engine/list.h
@@ -0,0 +1,11 @@
+#ifndef ENGINE_LIST_H
+#define ENGINE_LIST_H
+
+#define DEFINE_LLIST(type) \
+struct List_##type { \
+ type value; \
+ struct List_##type* next; \
+ /* Force the user to add `;` for style consistency */\
+} List_##type
+
+#endif
diff --git a/include/engine/logging.h b/include/engine/logging.h
new file mode 100644
index 0000000..1365a5b
--- /dev/null
+++ b/include/engine/logging.h
@@ -0,0 +1,44 @@
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+
+#include "types.h"
+
+#if defined __linux__ || defined __APPLE__
+#define TERM_COLOR_RESET "\033[0m"
+#define TERM_COLOR_RED "\033[31m"
+#define TERM_COLOR_GREEN "\033[32m"
+#define TERM_COLOR_YELLOW "\033[33m"
+#define TERM_COLOR_BLUE "\033[34m"
+#define TERM_COLOR_PURPLE "\033[35m"
+#else
+#define TERM_COLOR_RESET
+#define TERM_COLOR_RED
+#define TERM_COLOR_GREEN
+#define TERM_COLOR_YELLOW
+#define TERM_COLOR_BLUE
+#define TERM_COLOR_PURPLE
+#endif
+
+#define STR(a) (#a)
+
+void _log(FILE *stream, const char *prefix, const char *fmt, va_list ap);
+
+void LOG(const char *fmt, ...);
+
+void INFO_(const char *fmt, ...);
+void INFO(const char *fmt, ...);
+
+#define _DEBUG(...) __DEBUG(__FILE__,__LINE__, __func__, __VA_ARGS__)
+void __DEBUG(const char* file, const i32 line, const char* func, const char *fmt, ...);
+
+void WARN(const char *fmt, ...);
+
+void ERROR(const char *fmt, ...);
+
+#endif
diff --git a/include/engine/memory.h b/include/engine/memory.h
new file mode 100644
index 0000000..8b37747
--- /dev/null
+++ b/include/engine/memory.h
@@ -0,0 +1,25 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#include "types.h"
+//#include <stdlib.h>
+
+typedef struct memory {
+ void *data;
+ usize size;
+ usize pos;
+ usize free;
+} memory;
+
+memory *memory_new(usize max_size);
+
+/* Returns a pointer to the allocated data */
+void *memory_allocate(memory* mem, usize size);
+
+memory memory_init(void *data, usize size);
+
+void memory_free(memory *mem, usize size);
+
+void memory_clear(memory *mem);
+
+#endif
diff --git a/include/engine/rendering.h b/include/engine/rendering.h
new file mode 100644
index 0000000..3ec8416
--- /dev/null
+++ b/include/engine/rendering.h
@@ -0,0 +1,81 @@
+#ifndef RENDERING_H
+#define RENDERING_H
+
+#include "types.h"
+#include "vector.h"
+
+/* Definitions */
+#define RGBA(_r,_g,_b,_a) ((Engine_color){.r=_r, .g=_g, .b=_b, .a=_a})
+#define RGB(_r,_g,_b) RGBA(_r,_g,_b,0xFF)
+
+/* Types */
+typedef struct {
+ u8 r;
+ u8 g;
+ u8 b;
+ u8 a;
+} Engine_color;
+
+typedef struct {
+ u32 texture_id;
+ v2_i32 coord;
+} Sprite;
+
+#include "ui.h"
+#include "engine.h"
+
+/* Rendering functions */
+void render_begin(Window *w);
+void render_present(Window *w);
+void drawcall_reset(void);
+void render(Window *w);
+
+/* Misc */
+void engine_window_resize_pointers(i32* w, i32* h);
+void engine_window_resize_pointers_reset(void);
+
+/* UI rendering */
+/* See rendering_ui.c for implementation */
+i64 engine_render_text(i32 font_id, Engine_color fg, char *text, v2_i32 *size_out, bool wrapped);
+void engine_draw_uitree(UITree *t);
+void engine_draw_sprite(Sprite *s, v2_i32 *pos, f32 scale);
+void engine_draw_sprite_ex(Sprite *s, v2_i32 *pos, f32 scale, Engine_color colormod);
+
+Sprite sprite_new(u64 tid, u8 coord);
+
+#ifdef ENGINE_INTERNALS
+#include "engine.h"
+
+#define TEXTURES_INCREMENT 512
+
+typedef enum {
+ RenderDrawCallType_UITree,
+ /*RenderDrawCallType_UIButton,*/
+ RenderDrawCallType_Text,
+ RenderDrawCallType_Sprite,
+} RenderDrawCallType;
+
+typedef struct {
+ RenderDrawCallType type;
+ union {
+ void *data;
+ struct {
+ Sprite *sprite;
+ i32 x; i32 y;
+ f32 scale;
+ SDL_Color mod;
+ } sprite;
+ } data;
+} RenderDrawCall;
+
+void render_uitree(Window *w, UITree *t);
+
+void render_container(Window *w, UITree_container *t);
+void render_button(Window *w, UITree_button *t);
+void render_title(Window *w, UITree_title *t);
+void render_text(Window *w, UITree_text *t);
+v2_i32 elem_size(UITree *root);
+
+#endif
+
+#endif
diff --git a/include/engine/stack.h b/include/engine/stack.h
new file mode 100644
index 0000000..636c306
--- /dev/null
+++ b/include/engine/stack.h
@@ -0,0 +1,49 @@
+/* Copyright © 2021 Upqwerk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * */
+
+/* Stack implementation
+ * Author: Upqwerk
+ */
+#ifndef STACK_H
+#define STACK_H
+
+#include "types.h"
+
+typedef struct {
+ isize head; /* current number of elements */
+ const usize elem_size; /* size in bytes of each element */
+ usize size; /* current memory size used by the stack */
+ const usize chunk_size; /* size of which the stack increases when running out of mem */
+ void *data; /* memory buffer */
+} Stack;
+
+Stack stack_new_ex(const usize element_size, const usize size);
+
+Stack stack_new(const usize element_size);
+
+void stack_free(Stack *s);
+void *stack_pop(Stack *s);
+void stack_push(Stack *s, void *elem);
+void *stack_peek(Stack *s);
+isize stack_size(const Stack *s);
+void stack_swap(Stack *s, Stack *t);
+
+#endif
diff --git a/include/engine/state.h b/include/engine/state.h
new file mode 100644
index 0000000..83b57a2
--- /dev/null
+++ b/include/engine/state.h
@@ -0,0 +1,22 @@
+#ifndef STATE_H
+#define STATE_H
+
+#include <engine/memory.h>
+
+typedef enum StateType {
+ STATE_null,
+#define State(name) STATE_##name,
+#include <state_type_list.h>
+#undef State
+ STATE_quit,
+} StateType;
+
+extern const char *StateTypeStr[];
+
+StateType(*State_updateFunc(StateType type))(void*);
+
+void State_init(StateType type, memory *mem);
+void State_free(StateType type, memory *mem);
+StateType State_update(StateType type, memory *mem);
+
+#endif
diff --git a/include/engine/types.h b/include/engine/types.h
new file mode 100644
index 0000000..0fc5870
--- /dev/null
+++ b/include/engine/types.h
@@ -0,0 +1,32 @@
+#ifndef ENGINE_TYPES_H
+#define ENGINE_TYPES_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* Signed */
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+
+/* Unsigned */
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+/* floating points */
+typedef float f32;
+typedef double f64;
+
+/* sizes */
+#if __x86_64__ || __ppc64__ || _WIN64
+typedef u64 usize;
+typedef i64 isize;
+#else
+typedef u32 usize;
+typedef i32 isize;
+#endif
+
+#endif
diff --git a/include/engine/ui.h b/include/engine/ui.h
new file mode 100644
index 0000000..bea8d3e
--- /dev/null
+++ b/include/engine/ui.h
@@ -0,0 +1,234 @@
+#ifndef ENGINE_UI_H
+#define ENGINE_UI_H
+
+#include "types.h"
+#include "vector.h"
+#include "list.h"
+
+#define DIRECTION_HORIZONTAL true
+#define DIRECTION_VERTICAL false
+
+/* Ui positioning constraints */
+typedef enum {
+ ui_size_pixel,
+ ui_size_percent,
+} ui_size_t;
+
+
+typedef union {
+ ui_size_t type;
+ struct {ui_size_t type; i32 value;} pixel;
+ struct {ui_size_t type; f32 value;} percent;
+} ui_size;
+
+
+typedef enum {
+ ui_constraint_width,
+ ui_constraint_height,
+
+ ui_constraint_horizontal_align,
+ ui_constraint_vertical_align,
+
+ ui_constraint_left,
+ ui_constraint_right,
+ ui_constraint_top,
+ ui_constraint_bottom,
+} ui_constraint_t;
+
+
+typedef enum {
+ ui_constraint_vertical_align_top,
+ ui_constraint_vertical_align_center,
+ ui_constraint_vertical_align_bottom,
+} ui_constraint_vertical_align_t;
+
+
+typedef enum {
+ ui_constraint_horizontal_align_left,
+ ui_constraint_horizontal_align_center,
+ ui_constraint_horizontal_align_right,
+} ui_constraint_horizontal_align_t;
+
+typedef union {
+ struct {ui_size size;} width;
+ struct {ui_size size;} height;
+
+ /* spacing is the padding between the aligned edge and the container itself */
+ struct {ui_constraint_horizontal_align_t align; ui_size spacing;} horizontal_align;
+ struct {ui_constraint_vertical_align_t align; ui_size spacing;} vertical_align;
+
+ struct {ui_size pos;} left;
+ struct {ui_size pos;} top;
+ struct {ui_size pos;} right;
+ struct {ui_size pos;} bottom;
+} constraintval_t;
+
+#define CONSTRAINT_POSITION(axis, alignment_sub, margin, cnext) { \
+ .value = { \
+ .type = ui_constraint_##axis##_align, \
+ .constraint.axis##_align = { \
+ .align = ui_constraint_##axis##_align_##alignment_sub, \
+ .spacing = margin, \
+ }, \
+ }, \
+ .next = cnext, \
+ }
+
+#define CONSTRAINT_SIZE(c_type, csize, cnext) { \
+ .value = { \
+ .type = ui_constraint_##c_type, \
+ .constraint.c_type = { \
+ .size = csize, \
+ }, \
+ }, \
+ .next = cnext, \
+ }
+
+typedef struct {
+ ui_constraint_t type;
+ constraintval_t constraint;
+} ui_constraint;
+
+typedef DEFINE_LLIST(ui_constraint);
+
+
+enum uitype {
+ uitype_container,
+ uitype_button,
+ uitype_title,
+ uitype_text,
+
+ uitype_MAX,
+};
+
+
+typedef struct UITree_container {
+ enum uitype type;
+ bool visible;
+ bool direction;
+ i32 x, y, w, h;
+ i32 padding;
+ i32 margin;
+
+ Engine_color fg;
+ Engine_color bg;
+ Engine_color bordercolor;
+
+ usize children_len; /* Number of children */
+ usize children_size; /* Memory size */
+ union UITree** children;
+ struct List_ui_constraint *constraints;
+} UITree_container;
+
+typedef struct UITree_button {
+ enum uitype type;
+
+ bool enabled;
+ u64 id;
+
+ i32 x, y, w, h;
+ i32 padding;
+ i32 margin;
+
+ Engine_color fg;
+ Engine_color bg;
+
+ i32 font_id;
+ const char *text_original;
+ u64 text_texture_index;
+ v2_i32 texture_size;
+ struct List_ui_constraint *constraints;
+} UITree_button;
+
+typedef struct UITree_title {
+ enum uitype type;
+ i32 x, y, w, h;
+
+ i32 padding;
+ i32 margin;
+
+ Engine_color fg;
+
+ i32 font_id;
+ const char *text_original;
+ u64 text_texture_index;
+ v2_i32 texture_size;
+ struct List_ui_constraint *constraints;
+} UITree_title;
+
+typedef struct UITree_text {
+ enum uitype type;
+ i32 x, y, w, h;
+
+ i32 padding;
+ i32 margin;
+
+ Engine_color fg;
+
+ i32 font_id;
+ const char *text_original;
+ u64 text_texture_index;
+ v2_i32 texture_size;
+ struct List_ui_constraint *constraints;
+} UITree_text;
+
+typedef union UITree {
+ enum uitype type;
+
+ UITree_container container;
+ UITree_button button;
+ UITree_title title;
+ UITree_text text;
+ struct List_ui_constraint constraints;
+} UITree;
+
+/* Sizes */
+f32 ui_size_pixel_to_percent_width(i32 pixels);
+f32 ui_size_pixel_to_percent_height(i32 pixels);
+f32 ui_size_pixel_to_percent(i32 pixels);
+i32 ui_size_percent_width_to_pixel(f32 percent);
+i32 ui_size_percent_height_to_pixel(f32 percent);
+i32 ui_size_percent_to_pixel(f32 percent);
+i32 ui_size_to_pixel(ui_size s);
+
+#define ui_size_percent_new(p) {.percent = {.type = ui_size_percent, .value = p}}
+#define ui_size_pixel_new(p) {.pixel = {.type = ui_size_pixel, .value = p}}
+
+/* Constructors */
+UITree *ui_container(bool direction, struct List_ui_constraint *constraints);
+UITree *ui_button(u64 id, i32 font_id, char *text, struct List_ui_constraint *constraints);
+UITree *ui_title(i32 font_id, const char *text, struct List_ui_constraint *constraints);
+UITree *ui_text(i32 font_id, const char *text, struct List_ui_constraint *constraints);
+
+/* Extended Constructors */
+UITree *ui_container_new_ex(
+ Engine_color fg,
+ Engine_color bg,
+ Engine_color border,
+ bool direction,
+ struct List_ui_constraint *constraints);
+
+/* Destructors */
+void clear_ui(void);
+void uitree_free(UITree *t);
+
+/* Manipulation */
+void ui_container_attach(UITree *container, UITree *child);
+
+void ui_resolve_constraints(void);
+
+void ui_button_enable(UITree_button *b);
+void ui_button_disable(UITree_button *b);
+
+/* Tweaking default colors */
+void ui_set_default_colors(Engine_color fg, Engine_color bg);
+void ui_set_default_padding(i32 padding);
+Engine_color ui_get_default_fg(void);
+Engine_color ui_get_default_bg(void);
+
+#define ELEM_NOT_FOUND (-1)
+#define NO_CLICK (-2)
+/* Returns -1 if not found */
+u64 ui_check_click(UITree *root);
+
+#endif
diff --git a/include/engine/utils.h b/include/engine/utils.h
new file mode 100644
index 0000000..65fa35c
--- /dev/null
+++ b/include/engine/utils.h
@@ -0,0 +1,34 @@
+#ifndef ENGINE_UTILS_H
+#define ENGINE_UTILS_H
+
+#include "types.h"
+#include "vector.h"
+
+#define MIN(a,b) ((a < b) ? (a) : (b))
+#define MAX(a,b) ((a > b) ? (a) : (b))
+
+#define MASK_TL (1 << 0)
+#define MASK_T (1 << 1)
+#define MASK_TR (1 << 2)
+#define MASK_L (1 << 3)
+#define MASK_C (1 << 4)
+#define MASK_R (1 << 5)
+#define MASK_BL (1 << 6)
+#define MASK_B (1 << 7)
+#define MASK_BR (1 << 8)
+
+/* Linear interpolate */
+f32 lerp(f32 dt, f32 a, f32 b);
+i32 int_lerp(f32 dt, i32 a, i32 b);
+
+/* Hashes */
+u32 hash(char *str);
+
+/* Masks surrounding tiles of a kernel size of 3 */
+/* In reality we only need 9 bits for this, but I think I had a reason for using i32 */
+i32* kernmap(const void *map, i32 *dstmap, const v2_i32 mapsize, bool (*predicate)(const void*));
+
+/* Returns an index from the given weights. */
+i32 pick_from_sample(const i32 *weights, i32 len);
+
+#endif
diff --git a/include/engine/vector.h b/include/engine/vector.h
new file mode 100644
index 0000000..396e12d
--- /dev/null
+++ b/include/engine/vector.h
@@ -0,0 +1,31 @@
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include "types.h"
+
+#include <stdio.h>
+#include <stdbool.h>
+
+typedef struct {
+ i32 x;
+ i32 y;
+} v2_i32;
+
+bool v2_i32_eq(const v2_i32 a, const v2_i32 b);
+
+v2_i32 v2_i32_add (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_add_i(v2_i32 a, i32 b);
+v2_i32 v2_i32_sub (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_sub_i(v2_i32 a, i32 b);
+v2_i32 v2_i32_div (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_div_i(v2_i32 a, i32 b);
+v2_i32 v2_i32_mul (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_mul_i(v2_i32 a, i32 b);
+v2_i32 v2_i32_mod (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_mod_i(v2_i32 a, i32 b);
+v2_i32 v2_i32_max (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_min (v2_i32 a, v2_i32 b);
+v2_i32 v2_i32_lerp (f32 dt, v2_i32 a, v2_i32 b);
+
+void v2_i32_fprintf(FILE *stream, v2_i32 a);
+#endif