summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/include')
-rw-r--r--src/include/daw/daw.h73
-rw-r--r--src/include/daw/dltools.h23
-rw-r--r--src/include/daw/input.h108
-rw-r--r--src/include/daw/keycodes.h93
-rw-r--r--src/include/daw/logging.h56
-rw-r--r--src/include/daw/memory.h31
-rw-r--r--src/include/daw/model.h30
-rw-r--r--src/include/daw/platform.h56
-rw-r--r--src/include/daw/platform_glfw.h32
-rw-r--r--src/include/daw/rendering.h288
-rw-r--r--src/include/daw/resources.h138
-rw-r--r--src/include/daw/scancodes.h89
-rw-r--r--src/include/daw/state.h41
-rw-r--r--src/include/daw/texture.h17
-rw-r--r--src/include/daw/types.h41
-rw-r--r--src/include/daw/utils.h43
-rw-r--r--src/include/daw/utils/btree.h61
-rw-r--r--src/include/daw/utils/fov.h28
-rw-r--r--src/include/daw/utils/hashmap.h61
-rw-r--r--src/include/daw/utils/list.h18
-rw-r--r--src/include/daw/utils/stack.h33
-rw-r--r--src/include/daw/window.h55
22 files changed, 1415 insertions, 0 deletions
diff --git a/src/include/daw/daw.h b/src/include/daw/daw.h
new file mode 100644
index 0000000..acbbcd9
--- /dev/null
+++ b/src/include/daw/daw.h
@@ -0,0 +1,73 @@
+#ifndef ENGINE_ENGINE_H
+#define ENGINE_ENGINE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+#include <cglm/ivec2.h>
+
+#include <daw/types.h>
+#include <daw/logging.h>
+#include <daw/memory.h>
+#include <daw/state.h>
+#include <daw/input.h>
+#include <daw/utils/stack.h>
+#include <daw/window.h>
+#include <daw/resources.h>
+
+typedef struct {
+ u32 texture_id;
+ i32 x, y, w, h;
+} RenderUnit;
+
+#include <daw/window.h>
+
+typedef struct Instance {
+
+ Window* window;
+ bool quit;
+
+ u64 frame;
+ u16 fps_target;
+
+ /* TODO: Move input ctx/bindings to window */
+ /* TODO: Move cam to window->renderer */
+ Camera *cam;
+
+ /* Global resources that live from engine_init to engine_free */
+ Resources* resources;
+
+ memory* mem;
+
+} Instance;
+
+/* Essential functions */
+Instance* engine_init(const char* windowtitle, i32 windowWidth, i32 windowHeight,
+ const u32 flags,
+ const usize initial_memory);
+
+i32 engine_run(Instance* p, StateType initial_state, void* state_arg);
+
+void engine_stop(Instance* p);
+
+/* Utility functions */
+void engine_fps_max(Instance* p, u16 cap);
+
+void render_set_zoom(f32 new_zoom);
+void render_adjust_zoom(f32 diff);
+void render_add_unit(RenderUnit* u);
+
+/* move this */
+void delay(uint64_t ms);
+
+// file operations
+usize f_get_sz(FILE* f);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/dltools.h b/src/include/daw/dltools.h
new file mode 100644
index 0000000..d9c74ee
--- /dev/null
+++ b/src/include/daw/dltools.h
@@ -0,0 +1,23 @@
+#ifndef DLTOOLS_H
+#define DLTOOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+/* Utility functions for handling runtime linked shared libraries */
+bool dynamic_library_close(void* shared_library);
+void* dynamic_library_open(const char* library_path);
+void* dynamic_library_reload(void* shared_library, const char* library_path);
+
+/* Returns the address of symbol in the provided shared_library handle.
+ * NULL on error*/
+void* dynamic_library_get_symbol(void* shared_library, const char* symbol);
+char* dynamic_library_get_error(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/input.h b/src/include/daw/input.h
new file mode 100644
index 0000000..9fbcd15
--- /dev/null
+++ b/src/include/daw/input.h
@@ -0,0 +1,108 @@
+#ifndef ENGINE_CTRL_INPUT_H
+#define ENGINE_CTRL_INPUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cglm/ivec2.h>
+#include <daw/types.h>
+#include <daw/keycodes.h>
+
+typedef void input_callback_t(void*);
+typedef i32 scancode_t;
+typedef i32 keycode_t;
+
+typedef enum InputType {
+ InputType_error = 0,
+ InputType_action,
+ InputType_state,
+ InputType_range, /* TBD */
+} InputType;
+
+typedef union action_t {
+ InputType type;
+
+ struct {
+ InputType type;
+ input_callback_t* callback;
+ char* callback_str;
+ } action;
+
+ struct {
+ InputType type;
+ input_callback_t* activate;
+ input_callback_t* deactivate;
+ char* activate_str;
+ char* deactivate_str;
+ } state;
+} action_t;
+
+typedef struct binding_t {
+ action_t action;
+
+ // Change type depending on input handling back-end. like u16 for GLFW_KEY
+ keycode_t keycode;
+ keycode_t keycode_alt;
+
+ u64 since_last_activation;
+} binding_t;
+
+typedef struct i_ctx {
+
+ // Current mouse position
+ ivec2 mouse_pos;
+
+ usize len;
+ binding_t* bindings;
+} i_ctx;
+
+void i_ctx_t_free(i_ctx* c);
+/* Executes all callbacks that has been pushed onto the callstack and resets the
+ * callstack */
+void i_flush_bindings(u64 dt, usize numcalls, input_callback_t* c[], void* state_mem);
+action_t i_get_action(const i_ctx* restrict ctx, u64 time, keycode_t keycode);
+
+void key_callback(void* window, int key, int scancode, int action, int mods);
+
+void i_ctx_push(i_ctx* ctx);
+void i_ctx_pop(void);
+void i_ctx_reset(void);
+
+/* Finds and updates the keycode of a binding with the given action in ctx */
+void i_bind_ctx(i_ctx* c, keycode_t s, action_t* a);
+void i_bind_ctx_alt(i_ctx* c, keycode_t s, action_t* a);
+
+/* Update the keycode of a binding */
+void i_bind(binding_t* b, keycode_t s);
+void i_bind_alt(binding_t* b, keycode_t s);
+
+#define BindAction(key, altkey, f_action) \
+ (binding_t) { \
+ .action = (action_t){.action = \
+ { \
+ .type = InputType_action, \
+ .callback = (input_callback_t*)&f_action, \
+ .callback_str = strdup(#f_action), \
+ }}, \
+ .keycode = key, .keycode_alt = altkey, .since_last_activation = 0 \
+ }
+
+#define BindState(key, altkey, f_activate, f_deactivate) \
+ (binding_t) { \
+ .action = \
+ (action_t){.state = \
+ { \
+ .type = InputType_state, \
+ .activate = (input_callback_t*)&f_activate, \
+ .deactivate = (input_callback_t*)&f_deactivate, \
+ .activate_str = strdup(#f_activate), \
+ .deactivate_str = strdup(#f_deactivate), \
+ }}, \
+ .keycode = key, .keycode_alt = altkey, .since_last_activation = 0 \
+ }
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/keycodes.h b/src/include/daw/keycodes.h
new file mode 100644
index 0000000..869809f
--- /dev/null
+++ b/src/include/daw/keycodes.h
@@ -0,0 +1,93 @@
+#ifndef ENGINE_CTRL_SCANCODES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// We want to reserve the following bytes marked with X for MODS,
+// one bit per MODIFIER (shift, control, alt, super):
+// XXXX 0000 0000 0000 0000 0000 0000 0000
+//
+// We want to reserve the following bytes marked with X for ACTIONS
+// enumerate by action type, pressed, released, repeat
+// 0000 0000 XXXX 0000 0000 0000 0000 0000
+//
+// We want to reserve the following bytes marked with X for the KEYCODE
+// 0000 0000 0000 0000 XXXX XXXX XXXX XXXX
+#define KEY_MOD(x) (1 << (32-4 + x))
+#define ACTION(x) ((1 << (32-8)) + x)
+
+typedef enum {
+ KEY_SPACE = ' ',
+ KEY_APOSTROPHE = '\'',
+ KEY_COMMA = ',',
+ KEY_MINUS = '-',
+ KEY_PERIOD = '.',
+ KEY_SLASH = '/',
+
+ KEY_0 = '0',
+ KEY_1 = '1',
+ KEY_2 = '2',
+ KEY_3 = '3',
+ KEY_4 = '4',
+ KEY_5 = '5',
+ KEY_6 = '6',
+ KEY_7 = '7',
+ KEY_8 = '8',
+ KEY_9 = '9',
+
+ KEY_SEMICOLON = ';',
+ KEY_EQUAL = '=',
+
+ KEY_A = 'A',
+ KEY_B = 'B',
+ KEY_C = 'C',
+ KEY_D = 'D',
+ KEY_E = 'E',
+ KEY_F = 'F',
+ KEY_G = 'G',
+ KEY_H = 'H',
+ KEY_I = 'I',
+ KEY_J = 'J',
+ KEY_K = 'K',
+ KEY_L = 'L',
+ KEY_M = 'M',
+ KEY_N = 'N',
+ KEY_O = 'O',
+ KEY_P = 'P',
+ KEY_Q = 'Q',
+ KEY_R = 'R',
+ KEY_S = 'S',
+ KEY_T = 'T',
+ KEY_U = 'U',
+ KEY_V = 'V',
+ KEY_W = 'W',
+ KEY_X = 'X',
+ KEY_Y = 'Y',
+ KEY_Z = 'Z',
+
+ KEY_LEFT_BRACKET = '[',
+ KEY_BACKSLASH = '\\',
+ KEY_RIGHT_BRACKET = ']',
+ KEY_GRAVE_ACCENT = '`',
+
+ ACTION_PRESS = ACTION(0),
+ ACTION_RELEASE = ACTION(1),
+ ACTION_REPEAT = ACTION(2),
+
+ MOD_SHIFT = KEY_MOD(0),
+ MOD_CONTROL = KEY_MOD(1),
+ MOD_ALT = KEY_MOD(2),
+ MOD_SUPER = KEY_MOD(3),
+} KeyCode;
+#define MOD_SHFT MOD_SHIFT
+#define MOD_CTRL MOD_CONTROL
+#define MOD_SUPR MOD_SUPER
+
+#undef ACTION
+#undef KEY_MOD
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/logging.h b/src/include/daw/logging.h
new file mode 100644
index 0000000..65ca827
--- /dev/null
+++ b/src/include/daw/logging.h
@@ -0,0 +1,56 @@
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <daw/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, ...);
+
+#ifdef _DEBUG
+#define DEBUG(fmt, ...) __DEBUG(__FILE__, __LINE__, __func__, fmt, __VA_ARGS__)
+void __DEBUG(const char* file, const i32 line, const char* func,
+ const char* fmt, ...);
+#else
+#define DEBUG(...)
+#endif
+
+void WARN(const char* fmt, ...);
+
+void ERROR(const char* fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/memory.h b/src/include/daw/memory.h
new file mode 100644
index 0000000..bc10fe2
--- /dev/null
+++ b/src/include/daw/memory.h
@@ -0,0 +1,31 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/model.h b/src/include/daw/model.h
new file mode 100644
index 0000000..a78c4b8
--- /dev/null
+++ b/src/include/daw/model.h
@@ -0,0 +1,30 @@
+#ifndef ENGINE_RESOURCES_MODEL_H
+#define ENGINE_RESOURCES_MODEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+
+typedef enum {
+ Model_error,
+ Model_obj,
+} ModelType;
+
+typedef struct {
+ ModelType format;
+
+ u32 m_uiVAO;
+ u32 m_uiVBO;
+ u32 m_uiIBO;
+ unsigned m_uiNumIndices;
+} Model;
+
+#include <daw/resources.h>
+Model load_model(const Asset_ModelSpec *restrict ms);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/platform.h b/src/include/daw/platform.h
new file mode 100644
index 0000000..c837c63
--- /dev/null
+++ b/src/include/daw/platform.h
@@ -0,0 +1,56 @@
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cglm/ivec2.h>
+
+#include <daw/types.h>
+// TODO: We only need the window once all the garbage in Instance is cleaned up.
+#include <daw/window.h>
+
+#define DAW_WINDOW_VSYNC (1 << 0)
+#define DAW_WINDOW_FULLSCREEN (1 << 1)
+#define DAW_WINDOW_RESIZEABLE (1 << 2)
+
+// Whether or not it is clever to force API consistency using a struct like this
+// can be debated, at the time of writing it seemed like a smart idea.
+
+// Platform libraries must implement a struct Platform:
+struct Platform {
+ /* Initialize a window for the given platform. The rendering backend should
+ * also be initialized here.
+ * Parameters:
+ * const char* title: window title.
+ * ivec2 windowsize: the size in pixels for the new window.
+ * const u32 flags: window flags, such as static size and fullscreen.
+ * The flags are platform agnostic and needs to be
+ * converted to the specific library
+ * Returns:
+ * A pointer to a struct Window, NULL on error.
+ */
+ Window* (*window_init)(const char *restrict title, ivec2 windowsize, const u32 flags);
+
+ /* Destroy, close, and free up resources related to the window and the
+ * platform library specific resources.
+ */
+ void (*window_destroy)(Window *restrict w);
+
+ /* Resize the given window. Resize callbacks are handled by the wrapper
+ * implementation.
+ */
+ void (*window_resize)(Window *restrict window, int width, int height);
+
+ /* Return true if the platform has ordered the window to exit. */
+ bool (*window_should_close)(Window *restrict w);
+
+ /* Poll events on the window from the operating system. */
+ void (*window_poll)(void);
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/platform_glfw.h b/src/include/daw/platform_glfw.h
new file mode 100644
index 0000000..1136a9f
--- /dev/null
+++ b/src/include/daw/platform_glfw.h
@@ -0,0 +1,32 @@
+#ifndef ENGINE_RENDERING_PLATFORM_GLFW_H
+#define ENGINE_RENDERING_PLATFORM_GLFW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cglm/ivec2.h>
+
+#include <daw/types.h>
+#include <daw/platform.h>
+#include <daw/window.h>
+
+Window* window_init_glfw(const char *restrict windowtitle, ivec2 windowsize, const u32 flags);
+void window_destroy_glfw(Window *restrict w);
+void window_resize_glfw(Window *restrict window, int width, int height);
+bool window_should_close_glfw(Window *restrict window);
+void window_poll_glfw(void);
+
+const struct Platform Platform_GLFW = {
+ .window_init = window_init_glfw,
+ .window_destroy = window_destroy_glfw,
+ .window_resize = window_resize_glfw,
+ .window_should_close = window_should_close_glfw,
+ .window_poll = window_poll_glfw,
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/src/include/daw/rendering.h b/src/include/daw/rendering.h
new file mode 100644
index 0000000..0da97f5
--- /dev/null
+++ b/src/include/daw/rendering.h
@@ -0,0 +1,288 @@
+#ifndef ENGINE_RENDERING_RENDERING_H
+#define ENGINE_RENDERING_RENDERING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+#include <daw/window.h>
+
+#include <cglm/ivec2.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 */
+/* TODO: Cleanup these types. */
+typedef struct {
+ u8 r;
+ u8 g;
+ u8 b;
+ u8 a;
+} Engine_color;
+
+typedef struct {
+ /* Maybe implement types, such as `atlas` (default), `standalone`, or
+ * something idk. */
+ u32 id;
+ i32 width;
+ i32 height;
+} Texture;
+
+typedef struct {
+ u32 texture_id;
+ ivec2 coord;
+} Sprite;
+
+typedef enum {
+ Shader_Error,
+
+ Shader_Program,
+ Shader_Vertex,
+ Shader_Tessellation,
+ Shader_Geometry,
+ Shader_Fragment,
+ Shader_Compute,
+} ShaderType;
+
+typedef struct {
+ /* Shader proram */
+ ShaderType type;
+ u32 program;
+} Shader;
+
+typedef struct {
+ vec3 position;
+ vec3 size;
+ mat4 rotation;
+} Transform;
+
+typedef enum {
+ ShaderBufferFlag_none = 0x00,
+
+ // First 3 bytes describe the access frequency.
+ ShaderBuffer_AccessFrequency_stream = 1, // 1
+ ShaderBuffer_AccessFrequency_static = 2, // 2
+ ShaderBuffer_AccessFrequency_dynamic = 3, // 3
+
+ // Next 3 bytes describe the access type.
+ ShaderBuffer_AccessType_draw = 1 << 3, // 8
+ ShaderBuffer_AccessType_read = 2 << 3, // 16
+ ShaderBuffer_AccessType_copy = 3 << 3, // 24
+
+ // Next 3 bytes describe the buffer type
+ ShaderBuffer_Type_vertexData = 1 << 6, // 64
+ ShaderBuffer_Type_vertexPosition = 2 << 6, // 128
+ ShaderBuffer_Type_vertexIndex = 3 << 6, // 192
+
+ // Next 4 bytes are designated for the data type
+ ShaderBuffer_DataType_nil = 1 << 9, // 512
+
+ ShaderBuffer_DataType_f32 = 2 << 9, // 1024
+ ShaderBuffer_DataType_f64 = 3 << 9, // 1536
+
+ ShaderBuffer_DataType_i8 = 4 << 9, // 2048
+ ShaderBuffer_DataType_i16 = 5 << 9, // 2560
+ ShaderBuffer_DataType_i32 = 6 << 9, // 3072
+ ShaderBuffer_DataType_i64 = 7 << 9, // 3584
+
+ ShaderBuffer_DataType_u8 = 8 << 9, // 4096
+ ShaderBuffer_DataType_u16 = 9 << 9, // 4608
+ ShaderBuffer_DataType_u32 = 10 << 9, // 5120
+ ShaderBuffer_DataType_u64 = 11 << 9, // 5632
+} ShaderBufferFlag;
+
+typedef struct {
+ // The backend ID, ie. glGenBuffer(numBufferObjects, &this->buffername)
+ u32 buffername;
+ // Array, access, and data, type.
+ u32 buffertype;
+ // Buffer size of `data`. To get the size of the actual data, size_elem * count
+ usize size;
+ // Number of elements
+ usize count;
+ // components per generic vertex attribute (ie, 3 for RGB, 2 for UV)
+ usize components;
+ // size of each element
+ usize size_elem;
+ // Pointer to the data
+ void* data;
+} ShaderBuffer;
+
+// SHADERBUFFER_NEW is a constructor that takes the
+// * type T, as one of f32, f64, i8, i16, i32, i64, u8, u16, u32, or u64.
+// * COUNT, number of elements in the buffer
+// * COMPONENTS, number of elements to be grouped together, ie. 3 for a vec3.
+// * DATA, the buffer (it is pointed to automatically)
+// * FLAGS, are low-level GL flags that hints the access frequency, the access
+// type, and what buffer type it is, such as "data" or an index buffer.
+#define SHADERBUFFER_NEW(T, COUNT, COMPONENTS, DATA, FLAGS) \
+ (ShaderBuffer){ \
+ .buffername = 0, \
+ .buffertype = ShaderBuffer_DataType_##T | FLAGS, \
+ .size = COUNT * sizeof(T), \
+ .count = COUNT, \
+ .components = COMPONENTS, \
+ .size_elem = sizeof(T), \
+ .data = DATA, \
+ }
+
+typedef struct {
+ /* Shader proram */
+ Shader shader;
+ /* Vertex Array Object */
+ u32 vao;
+
+ /* MVP (a uniform from the shader).
+ * This could also probably be generalized */
+ i32 mvp;
+
+ // The texture ID, glBindTextures(target, &this->texture)
+ u32 texture;
+
+ // Number of buffers
+ usize buffer_len;
+
+ // The vertex buffer is also just a buffer
+ ShaderBuffer* buffer;
+} RenderObject;
+
+typedef struct {
+ // Index of the model in the RenderBatch models buffer
+ usize model_idx;
+ // The transformation of the model
+ Transform transform;
+} BatchModelInstance;
+
+typedef struct {
+ // Size of models buffer
+ usize msize;
+ // number of models in the `models` buffer
+ usize mcount;
+ // Pointers to original models in this batch
+ RenderObject **models;
+
+ // Size of instance buffer
+ usize inst_size;
+ // number of instances in the `instances` buffer
+ usize inst_count;
+ // Pointers to original models in this batch
+ BatchModelInstance *instances;
+
+ // The rendered destination object
+ RenderObject renderobj;
+} RenderBatch;
+
+typedef enum {
+ Camera_Perspective,
+ Camera_Orthogonal,
+} CameraType;
+
+typedef struct {
+ /* Position of the camera in world-space. */
+ vec3 pos;
+
+ /* The viewing direction of the camera, relative to the camera. */
+ vec3 dir;
+
+ /* Perspective matrix. Initialize with r_perspective_ortho or r_perspective. */
+ /* Alternatively, use `glm_perspective` or `glm_ortho`. */
+ mat4 per;
+
+ /* Used to re-calculate the perspective matrix when resizing the window */
+ CameraType type;
+ /* Yes, could use a singular "f32 arg", but this is more extendable in the
+ * future. */
+ union {
+ struct {f32 fov;} perspective;
+ struct {f32 sz;} orthogonal;
+ } parameters;
+
+} Camera;
+
+usize ShaderBufferDataType_size(u16 flags);
+
+ShaderBufferFlag ShaderBuffer_get_access_frequency(u64 flags);
+ShaderBufferFlag ShaderBuffer_get_access_type(u64 flags);
+ShaderBufferFlag ShaderBuffer_get_type(u64 flags);
+ShaderBufferFlag ShaderBuffer_get_data_type(u64 flags);
+
+/* Conversion to GL types */
+u32 ShaderBuffer_get_gl_type(u64 flags);
+u32 ShaderBuffer_get_gl_accesstype(u64 flags);
+u32 ShaderBuffer_get_gl_datatype(u64 flags);
+
+/* Rendering functions */
+void render_begin(Window* w);
+void render_present(Window* w);
+void drawcall_reset(void);
+void render(Window* w);
+
+/* Misc */
+void r_perspective(f32 fov, Camera *c);
+void r_perspective_ortho(f32 sz, Camera *c);
+
+void r_set_camera(Camera* c);
+void r_reset_camera(Camera* c);
+
+//void window_size_callback(GLFWwindow* window, i32 width, i32 height);
+
+void engine_draw_sprite(Sprite* s, ivec2* pos, f32 scale);
+void engine_draw_sprite_ex(Sprite* s, ivec2* pos, f32 scale,
+ Engine_color colormod);
+void engine_draw_model(RenderObject* o, vec3 pos);
+
+Sprite sprite_new(u64 tid, u8 coord);
+
+typedef enum {
+ RenderDrawCallType_Text,
+ RenderDrawCallType_Sprite,
+ RenderDrawCallType_Model,
+} RenderDrawCallType;
+
+typedef struct {
+ RenderDrawCallType type;
+ union {
+ void* data;
+ struct {
+ Sprite* sprite;
+ i32 x;
+ i32 y;
+ f32 scale;
+ } sprite;
+ struct {
+ RenderObject* model;
+ vec3 pos;
+ f32 scale;
+ } model;
+ } data;
+} RenderDrawCall;
+
+// TODO make all the shader buffers a list
+
+RenderObject RenderObject_new(
+ Shader* shader,
+ u32 texture,
+ ShaderBuffer *restrict buffers, usize num_buffers);
+
+int renderbatch_new(RenderBatch* renderbatch, usize count);
+i32 renderbatch_add(RenderBatch* renderbatch, RenderObject* obj, Transform* t);
+void renderbatch_transform(RenderBatch* renderbatch, usize obj_idx, Transform* t);
+int renderbatch_refresh(RenderBatch* renderbatch);
+
+Shader compile_shader(const char* file_path, const ShaderType shader_type);
+Shader compose_shader(Shader *shaders, usize shaders_len);
+void shaders_delete(Shader* shader, usize shader_len);
+
+u32 ComposeShader(u32 *shaders, usize shaders_len);
+
+ShaderType guess_shadertype_from_filename(const char *restrict fname);
+
+Texture createTextureFromImageData(unsigned char* image_data, i32 width, i32 height, u8 components);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/resources.h b/src/include/daw/resources.h
new file mode 100644
index 0000000..90f3b16
--- /dev/null
+++ b/src/include/daw/resources.h
@@ -0,0 +1,138 @@
+#ifndef ENGINE_RESOURCES_H
+#define ENGINE_RESOURCES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+#include <daw/rendering.h>
+
+// TODO
+/* We need some "global resources", available to all states.
+ * These are resources used throughout the applications lifetime, such as common
+ * fonts, GUI frames, button background images.
+ *
+ * We need to define state-specific resources as well.
+ * - Can both be defined alike?
+ * If we lazy-load all resources we can get away with a lot.
+ * Maybe use fall-back resources? like the missing source texture, and an ugly
+ * font?
+ * - Then declare to the engine, in the main function for the game, that these
+ * resources are to be made available throughout?
+ * - Shaders, oh boy oh shaders.
+ * We need to make some meta-shader declaration, so we can declare a set of
+ * shaders, that are used to link with other shaders, s.t. we can free up the
+ * shaders after compilation.
+ * - Make all resource specifications a union.
+ * */
+
+enum Asset {
+ Asset_error,
+ Asset_audio,
+ Asset_font,
+ Asset_shader,
+ Asset_shaderprog,
+ Asset_texture,
+ Asset_model,
+};
+
+typedef struct {
+ enum Asset type;
+ const char* path;
+} Asset_AudioSpec;
+
+typedef struct {
+ enum Asset type;
+ const char* path;
+} Asset_FontSpec;
+
+// if a shader is declared GLOBALLY, we should not destroy it when done with the
+// "main" shader compilations.
+typedef struct {
+ enum Asset type;
+ // Assume shader type from filename
+ const char* path;
+} Asset_ShaderSpec;
+
+// Use list of gluint shader program ids to link against. This translates to a
+// call to compose_shader.
+typedef struct {
+ enum Asset type;
+ const u32* shader;
+ const usize shader_len;
+} Asset_ShaderProgramSpec;
+
+typedef struct {
+ enum Asset type;
+ const char* path;
+ /* Bits per component, set to zero if you don't want to change the format. */
+ i32 bpc;
+} Asset_TextureSpec;
+
+typedef struct {
+ enum Asset type;
+ const char* path;
+} Asset_ModelSpec;
+
+typedef union {
+ enum Asset type;
+ Asset_AudioSpec audio;
+ Asset_FontSpec font;
+ Asset_ShaderSpec shader;
+ Asset_ShaderProgramSpec shaderprog;
+ Asset_TextureSpec texture;
+ Asset_ModelSpec model;
+} asset_t;
+
+#include <daw/model.h>
+
+// The resource spec
+typedef struct {
+ /* Assorted asset specification, makes reloading them easier. */
+ usize assets_len;
+ asset_t* assets;
+
+ /* Translation from `assets`'s indices to type-specific loaded assets: */
+ usize* get; // Let r=Resources, then use as: `r.shader[ r.get[ MyShader ] ]`
+
+ /* Loaded assets */
+ usize shader_len;
+ Shader* shader;
+
+ usize texture_len;
+ Texture* texture;
+
+ usize model_len;
+ Model* model;
+} Resources;
+
+#define TextureDefinition(_path, ...) unimplemented
+#define Resource_AudioDefinition(_path, ...) unimplemented
+#define Declare_Shader(PATH) (const asset_t){.shader = {.type = Asset_shader, .path=PATH}}
+#define Declare_ShaderProgram(SHADERS, NUMSHADERS) (const asset_t){.shaderprog = {.type = Asset_shaderprog, .shader=SHADERS, .shader_len=NUMSHADERS}}
+#define Declare_Texture(PATH) (const asset_t){.texture = {.type = Asset_texture, .path=PATH, .bpc=0}}
+
+void* get_asset(Resources* r, u32 idx);
+
+/* Each of resource_load_font, resource_load_texture, and resource_load_audio
+ * loads a given resource into the engines memory and returns an identifier.
+ */
+//isize resource_load_font(Asset_FontSpec font_def);
+//isize resource_load_texture(Asset_TextureSpec texture_def);
+//isize resource_load_audio(Asset_AudioSpec audio_def);
+
+// Loads all resources specified in `assets` and populates corresponding
+// resources members.
+i32 resources_load(Resources *resources);
+
+/* Makes a resource globally available. This must be called **BEFORE** any call
+ * to `engine_run` */
+isize resource_make_global(isize resource_id);
+
+#include <daw/texture.h>
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/scancodes.h b/src/include/daw/scancodes.h
new file mode 100644
index 0000000..5b18833
--- /dev/null
+++ b/src/include/daw/scancodes.h
@@ -0,0 +1,89 @@
+#ifndef ENGINE_CTRL_SCANCODES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// We want to reserve the following bytes marked with X for MODS,
+// one bit per MODIFIER (shift, control, alt, super):
+// XXXX 0000 0000 0000 0000 0000 0000 0000
+//
+// We want to reserve the following bytes marked with X for ACTIONS
+// enumerate by action type, pressed, released, repeat
+// 0000 0000 XXXX 0000 0000 0000 0000 0000
+//
+// We want to reserve the following bytes marked with X for the SCANCODE
+// 0000 0000 0000 0000 XXXX XXXX XXXX XXXX
+#define MOD(x) 1 << (32-4 + x)
+#define ACTION(x) (1 << (32-8)) + x
+
+typedef enum {
+ SCAN_KEY_SPACE = ' ',
+ SCAN_KEY_APOSTROPHE = '\'',
+ SCAN_KEY_COMMA = ',',
+ SCAN_KEY_MINUS = '-',
+ SCAN_KEY_PERIOD = '.',
+ SCAN_KEY_SLASH = '/',
+
+ SCAN_KEY_0 = '0',
+ SCAN_KEY_1 = '1',
+ SCAN_KEY_2 = '2',
+ SCAN_KEY_3 = '3',
+ SCAN_KEY_4 = '4',
+ SCAN_KEY_5 = '5',
+ SCAN_KEY_6 = '6',
+ SCAN_KEY_7 = '7',
+ SCAN_KEY_8 = '8',
+ SCAN_KEY_9 = '9',
+
+ SCAN_KEY_SEMICOLON = ';',
+ SCAN_KEY_EQUAL = '=',
+
+ SCAN_KEY_A = 'A',
+ SCAN_KEY_B = 'B',
+ SCAN_KEY_C = 'C',
+ SCAN_KEY_D = 'D',
+ SCAN_KEY_E = 'E',
+ SCAN_KEY_F = 'F',
+ SCAN_KEY_G = 'G',
+ SCAN_KEY_H = 'H',
+ SCAN_KEY_I = 'I',
+ SCAN_KEY_J = 'J',
+ SCAN_KEY_K = 'K',
+ SCAN_KEY_L = 'L',
+ SCAN_KEY_M = 'M',
+ SCAN_KEY_N = 'N',
+ SCAN_KEY_O = 'O',
+ SCAN_KEY_P = 'P',
+ SCAN_KEY_Q = 'Q',
+ SCAN_KEY_R = 'R',
+ SCAN_KEY_S = 'S',
+ SCAN_KEY_T = 'T',
+ SCAN_KEY_U = 'U',
+ SCAN_KEY_V = 'V',
+ SCAN_KEY_W = 'W',
+ SCAN_KEY_X = 'X',
+ SCAN_KEY_Y = 'Y',
+ SCAN_KEY_Z = 'Z',
+
+ SCAN_KEY_LEFT_BRACKET = '[',
+ SCAN_KEY_BACKSLASH = '\\',
+ SCAN_KEY_RIGHT_BRACKET = ']',
+ SCAN_KEY_GRAVE_ACCENT = '`',
+
+ SCAN_ACTION_PRESS = ACTION(0),
+ SCAN_ACTION_RELEASE = ACTION(1),
+ SCAN_ACTION_REPEAT = ACTION(2),
+
+ SCAN_MOD_SHIFT = MOD(0),
+ SCAN_MOD_CONTROL = MOD(1),
+ SCAN_MOD_ALT = MOD(2),
+ SCAN_MOD_SUPER = MOD(3),
+} ScanCode;
+#undef ACTION
+#undef MOD
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/state.h b/src/include/daw/state.h
new file mode 100644
index 0000000..f98d5ff
--- /dev/null
+++ b/src/include/daw/state.h
@@ -0,0 +1,41 @@
+#ifndef STATE_H
+#define STATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/memory.h>
+
+typedef enum StateType {
+ STATE_null,
+#define State(name) STATE_##name,
+#include <states/list_of_states.h>
+#undef State
+ STATE_quit,
+} StateType;
+
+extern const char* StateTypeStr[];
+
+StateType (*State_updateFunc(StateType type))(f64, void*);
+
+void State_init(StateType type, memory* mem, void* arg);
+void* State_free(StateType type, memory* mem);
+StateType State_update(StateType type, f64 dt, memory* mem);
+
+/* Reloads shared object file associated with state */
+#ifdef DAW_BUILD_HOTRELOAD
+#include <daw/input.h>
+bool State_reload(StateType type, i_ctx** ctx, usize ctx_len);
+bool state_refresh_input_ctx(void* lib, i_ctx** ctx, usize ctx_len);
+
+#else
+#define State_reload(_, _0, _1) true
+#define state_refresh_input_ctx(_0, _1, _2) true
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/texture.h b/src/include/daw/texture.h
new file mode 100644
index 0000000..5904fc1
--- /dev/null
+++ b/src/include/daw/texture.h
@@ -0,0 +1,17 @@
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+#include <daw/resources.h>
+#include <daw/rendering.h>
+
+Texture load_texture(const Asset_TextureSpec *restrict ts);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/types.h b/src/include/daw/types.h
new file mode 100644
index 0000000..a7d794d
--- /dev/null
+++ b/src/include/daw/types.h
@@ -0,0 +1,41 @@
+#ifndef ENGINE_TYPES_H
+#define ENGINE_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.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
+
+typedef bool(predicate_t)(const void*);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/utils.h b/src/include/daw/utils.h
new file mode 100644
index 0000000..5f735e9
--- /dev/null
+++ b/src/include/daw/utils.h
@@ -0,0 +1,43 @@
+#ifndef ENGINE_UTILS_H
+#define ENGINE_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+#include <cglm/ivec2.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 3x3 */
+/* 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 ivec2 mapsize,
+ predicate_t* predicate);
+
+/* Returns an index from the given weights. */
+i32 pick_from_sample(const i32* weights, i32 len);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/utils/btree.h b/src/include/daw/utils/btree.h
new file mode 100644
index 0000000..1dd2023
--- /dev/null
+++ b/src/include/daw/utils/btree.h
@@ -0,0 +1,61 @@
+#ifndef BTREE_H
+#define BTREE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/utils/fov.h b/src/include/daw/utils/fov.h
new file mode 100644
index 0000000..74ccee8
--- /dev/null
+++ b/src/include/daw/utils/fov.h
@@ -0,0 +1,28 @@
+#ifndef ENGINE_FOV_H
+#define ENGINE_FOV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+#include <stdbool.h>
+#include <cglm/ivec2.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 ivec2 mapsize,
+ bool (*visblocking)(const void*), i32* lightmap,
+ const i32 range, const ivec2 src);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/utils/hashmap.h b/src/include/daw/utils/hashmap.h
new file mode 100644
index 0000000..15ec5f0
--- /dev/null
+++ b/src/include/daw/utils/hashmap.h
@@ -0,0 +1,61 @@
+#ifndef ENGINE_HASHMAP_H
+#define ENGINE_HASHMAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <daw/types.h>
+#include <daw/memory.h>
+#include <daw/utils/list.h>
+
+usize lolhash(const usize s, usize 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 usize 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 usize 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)); \
+ } \
+ }
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/utils/list.h b/src/include/daw/utils/list.h
new file mode 100644
index 0000000..04dda04
--- /dev/null
+++ b/src/include/daw/utils/list.h
@@ -0,0 +1,18 @@
+#ifndef ENGINE_LIST_H
+#define ENGINE_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEFINE_LLIST(type) \
+ struct List_##type { \
+ type value; \
+ struct List_##type* next; \
+ /* Force the user to add `;` for style consistency */ \
+ } List_##type
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/utils/stack.h b/src/include/daw/utils/stack.h
new file mode 100644
index 0000000..004e686
--- /dev/null
+++ b/src/include/daw/utils/stack.h
@@ -0,0 +1,33 @@
+#ifndef STACK_H
+#define STACK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <daw/types.h>
+
+typedef struct {
+ usize 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);
+usize stack_size(const Stack* s);
+void stack_swap(Stack* s, Stack* t);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/daw/window.h b/src/include/daw/window.h
new file mode 100644
index 0000000..2924448
--- /dev/null
+++ b/src/include/daw/window.h
@@ -0,0 +1,55 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cglm/ivec2.h>
+
+#include <daw/types.h>
+#include <daw/input.h>
+
+#ifndef ENGINE_RENDERING_WINDOW_H_EXCLUDE_EXTERNS
+extern u64 (*get_time)(void);
+#endif
+
+typedef enum {
+ WINDOW_FRAMEWORK_NONE = 0,
+ WINDOW_FRAMEWORK_GLFW,
+} Window_framework;
+
+typedef enum {
+ WINDOW_RENDERER_NONE = 0,
+ WINDOW_RENDERER_OPENGL,
+} Window_renderer;
+
+typedef struct {
+ // Specifies the framwork & renderer combo used.
+ Window_framework framework;
+ Window_renderer renderer;
+
+ // Window *buffer* size, in pixels.
+ ivec2 windowsize;
+
+ // These are used differently depending on the framework / renderer combo.
+ // Subject to change to a union of backend-dependent structs
+ void* window;
+ void* context;
+
+ /* The ctrl is probably the only sensible thing in this struct. */
+ usize bindings_sz;
+ usize bindings_len;
+ i_ctx** bindings;
+} Window;
+
+#include <daw/platform.h>
+
+Window* Window_new(const struct Platform *p, const char *restrict title, Window_framework framework, Window_renderer renderer, ivec2 size, u32 flags);
+
+void get_mousepos(double *x, double *y);
+
+#ifdef __cplusplus
+}
+#endif
+#endif