summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authoronelin <oscar@nelin.dk>2025-10-31 23:55:42 +0000
committeronelin <oscar@nelin.dk>2025-11-02 22:07:17 +0000
commitd38deeef3af2316a666f8fc0173940bd769b748e (patch)
tree6e30d4a9eea18daa5705c894f28cd99ff047e8f9 /src/include
parent6c077751982ea2c7bd2d9262b01b9f8602f80dc8 (diff)
Flatten project structure
This will make it easier to break up the code into smaller chunks again later. One would think doing this seems fun to me at this point.
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