From d38deeef3af2316a666f8fc0173940bd769b748e Mon Sep 17 00:00:00 2001 From: onelin Date: Sat, 1 Nov 2025 00:55:42 +0100 Subject: 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. --- src/include/daw/daw.h | 73 ++++++++++ src/include/daw/dltools.h | 23 ++++ src/include/daw/input.h | 108 +++++++++++++++ src/include/daw/keycodes.h | 93 +++++++++++++ src/include/daw/logging.h | 56 ++++++++ src/include/daw/memory.h | 31 +++++ src/include/daw/model.h | 30 +++++ src/include/daw/platform.h | 56 ++++++++ src/include/daw/platform_glfw.h | 32 +++++ src/include/daw/rendering.h | 288 ++++++++++++++++++++++++++++++++++++++++ src/include/daw/resources.h | 138 +++++++++++++++++++ src/include/daw/scancodes.h | 89 +++++++++++++ src/include/daw/state.h | 41 ++++++ src/include/daw/texture.h | 17 +++ src/include/daw/types.h | 41 ++++++ src/include/daw/utils.h | 43 ++++++ src/include/daw/utils/btree.h | 61 +++++++++ src/include/daw/utils/fov.h | 28 ++++ src/include/daw/utils/hashmap.h | 61 +++++++++ src/include/daw/utils/list.h | 18 +++ src/include/daw/utils/stack.h | 33 +++++ src/include/daw/window.h | 55 ++++++++ 22 files changed, 1415 insertions(+) create mode 100644 src/include/daw/daw.h create mode 100644 src/include/daw/dltools.h create mode 100644 src/include/daw/input.h create mode 100644 src/include/daw/keycodes.h create mode 100644 src/include/daw/logging.h create mode 100644 src/include/daw/memory.h create mode 100644 src/include/daw/model.h create mode 100644 src/include/daw/platform.h create mode 100644 src/include/daw/platform_glfw.h create mode 100644 src/include/daw/rendering.h create mode 100644 src/include/daw/resources.h create mode 100644 src/include/daw/scancodes.h create mode 100644 src/include/daw/state.h create mode 100644 src/include/daw/texture.h create mode 100644 src/include/daw/types.h create mode 100644 src/include/daw/utils.h create mode 100644 src/include/daw/utils/btree.h create mode 100644 src/include/daw/utils/fov.h create mode 100644 src/include/daw/utils/hashmap.h create mode 100644 src/include/daw/utils/list.h create mode 100644 src/include/daw/utils/stack.h create mode 100644 src/include/daw/window.h (limited to 'src/include') 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + u32 texture_id; + i32 x, y, w, h; +} RenderUnit; + +#include + +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 + +/* 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 +#include +#include + +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 +#include +#include +#include +#include + +#include + +#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 + +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 + +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 +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 + +#include +// TODO: We only need the window once all the garbage in Instance is cleaned up. +#include + +#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 + +#include +#include +#include + +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 +#include + +#include + +/* 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 +#include + +// 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 + +// 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 + +#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 + +typedef enum StateType { + STATE_null, +#define State(name) STATE_##name, +#include +#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 +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 +#include +#include + +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 +#include + +/* 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 +#include + +#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 + +#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 )` + * 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 +#include +#include + +/* `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 + +#include +#include +#include + +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 + +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 + +#include +#include + +#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 + +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 -- cgit v1.3