diff options
| author | onelin <oscar@nelin.dk> | 2025-10-31 23:55:42 +0000 |
|---|---|---|
| committer | onelin <oscar@nelin.dk> | 2025-11-02 22:07:17 +0000 |
| commit | d38deeef3af2316a666f8fc0173940bd769b748e (patch) | |
| tree | 6e30d4a9eea18daa5705c894f28cd99ff047e8f9 /src/daw.c | |
| parent | 6c077751982ea2c7bd2d9262b01b9f8602f80dc8 (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/daw.c')
| -rw-r--r-- | src/daw.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/daw.c b/src/daw.c new file mode 100644 index 0000000..b632466 --- /dev/null +++ b/src/daw.c @@ -0,0 +1,344 @@ +#include <time.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +#include <cglm/ivec2.h> +#include <cglm/cam.h> + +#define STB_IMAGE_IMPLEMENTATION +#include <stb/stb_image.h> + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +/* include winapi */ +#include <Windows.h> +#elif defined(__APPLE__) +/* mac includes */ +#elif defined(__linux) || defined(__linux__) || defined(linux) + +#include <unistd.h> +#include <sys/sysinfo.h> + +#endif + +#include <daw/configure.h> + +#include <daw/state.h> +#include <daw/daw.h> +#include <daw/utils/btree.h> +#include <daw/utils/hashmap.h> +#include <daw/utils/list.h> + +#include <daw/resources.h> + +#include <daw/window.h> +#include <daw/rendering.h> +#include <daw/platform_glfw.h> + + +#define DEFAULT_NUM_PROCS 8 + +Instance* GLOBAL_PLATFORM = NULL; + +static Camera default_camera = { + .pos = {3, 0, 0}, + .dir = {1, 1, 1}, +}; + +input_callback_t* callbacks[128]; +usize callbacks_len; + +i32 nproc(void) { + return get_nprocs(); +} + +void delay( uint64_t us ) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + Sleep( ms ); +#else + struct timespec ts = { + .tv_sec = (i64)us / 1000000, + .tv_nsec = ((i64)us * 1000) % 1000000000 + }; + struct timespec rem = {0,0}; + int err = 0; + while((err = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &rem))) { + switch (err) { + case EINTR: + WARN("clock_nanosleep didn't sleep full duration: interrupted."); + break; + case EINVAL: + WARN("clock_nanosleep didn't sleep full duration: invalid argument."); + break; + case ENOTSUP: + WARN("clock_nanosleep didn't sleep full duration: unsupported clock."); + break; + default: + WARN("clock_nanosleep didn't sleep full duration!"); + break; + } + ts = rem; + rem = (struct timespec){0,0}; + } +#endif +} + +i32 cmp_int(const void* a, const void* b) { + const i32* x = a; + const i32* y = b; + + return *x - *y; +} + +/* Creates the window, initializes IO, Rendering, Fonts and engine-specific + * resources. */ +Instance* engine_init(const char* windowtitle, i32 windowWidth, i32 windowHeight, + const u32 flags, + const usize initial_memory) { + + INFO("Engine version " ENGINE_VERSION); + + +#if defined(__linux) || defined(__linux__) || defined(linux) + { + pid_t pid = getpid(); + INFO("Starting with pid %lu", pid); + } +#endif + ivec2 windowsize = {windowWidth, windowHeight}; + + Instance* p = (Instance*)calloc(1, sizeof(Instance)); + Window* w = (Window*)calloc(1, sizeof(Window)); + + /* initialize resources */ + Resources* resources = calloc(1, sizeof(Resources)); + // TODO: Initialize them :) + + w = Window_new(&Platform_GLFW, windowtitle, + WINDOW_FRAMEWORK_GLFW, WINDOW_RENDERER_OPENGL, + (ivec2){windowsize[0], windowsize[1]}, flags); + + p->window = w; + p->quit = false; + + p->resources = resources; + + p->frame = 0; +#ifdef _DEBUG + engine_fps_max(p, 30); +#else + engine_fps_max(p, 300); +#endif + + p->mem = memory_new(initial_memory); + + p->cam = &default_camera; + + glm_ortho_default(45.f, p->cam->per); + + // TODO: Add global bindings + + INFO("Available cores: %d", nproc()); + + GLOBAL_PLATFORM = p; + +#ifdef DAW_BUILD_HOTRELOAD + +#define State(name) \ + if (!State_reload(STATE_##name, p->window->bindings, p->window->bindings_len)) { \ + ERROR("Failed to reload shared object file for state %s", #name); \ + }; + +#include <states/list_of_states.h> +#undef State + +#endif + + return p; +} + +i32 engine_run(Instance* p, StateType initial_state, void* state_arg) { + + if (p == NULL) { + ERROR("Platform is uninitialized.\n"); + INFO("initialize with `engine_init`"); + return -1; + } + + memory* mem = p->mem; + + StateType state = initial_state; + + { + u64 state_init_time = get_time(); + State_init(state, mem, state_arg); + INFO("Initializing state \"%s\" took %.1fns", StateTypeStr[state], + (get_time() - state_init_time)); + } + + u64 frame_end = get_time(); + + // Update ticks + u64 ticks = 0; + + StateType (*update_func)(f64, void*) = State_updateFunc(state); + + u64 last_fps_measurement = frame_end; + u64 last_fps_ticks = 0; + + /* The target frametime measured in μs */ + const u32 fps_cap = p->fps_target > 0 ? 1000000 / p->fps_target : 0; + + /* Main loop */ + do { + /* frame_start is μs since engine was initialized */ + const u64 frame_start = get_time(); + + /* dt measured in μs */ + const u64 dt = frame_start - frame_end; + + /* Delta is relative to FPS cap */ + //const f64 delta = (f64)dt / (f64)fps_cap; + + /* Events */ + Platform_GLFW.window_poll(); + i_flush_bindings(dt, callbacks_len, callbacks, mem->data); + + /* Update */ + StateType next_state; + next_state = update_func(dt, (void*)(mem->data)); + + if (next_state != STATE_null) { + if (next_state == STATE_quit) break; + + drawcall_reset(); + + void* retval = State_free(state, mem); + memory_clear(mem); + + i_ctx_reset(); + + // Reset camera to default camera + p->cam = &default_camera; + + state = next_state; + update_func = State_updateFunc(state); + { + u64 state_init_time = get_time(); + State_init(state, mem, retval); + INFO("Initializing state \"%s\" took %.1fns", StateTypeStr[state], + (get_time() - state_init_time)); + } + } else { + + /* Render */ + const u64 rendertime_begin = get_time(); + render_begin(p->window); + render_present(p->window); + const u64 rendertime_dt = get_time() - rendertime_begin; + + /* Regulate FPS */ + frame_end = get_time(); + const i64 fps_diff = fps_cap - (i64)(frame_end - frame_start); + + if (fps_diff > 0) { + delay((u64)fps_diff); + } + + frame_end = frame_start; + + /* Print stats */ + const u64 dt_measurement = frame_end - last_fps_measurement; + + /* only make measurements once a second */ + if (dt_measurement > 1000000) { + + printf(" FPS: %.1f" + "\tticks: %lu" + "\tframetime: %lu.%03lums" + "\trendertime: %lu.%03lums" + "\n" + , ((f64)(ticks - last_fps_ticks)) / ((f64)dt_measurement / 1000000.0) + , ticks + , dt / 1000 , dt % 1000 + , rendertime_dt / 1000 , rendertime_dt % 1000 + ); + + last_fps_measurement = frame_end; + last_fps_ticks = ticks; + } + } + + ticks++; + } while( + !Platform_GLFW.window_should_close(p->window) + && state != STATE_quit + ); + + return 0; +} + +void engine_stop(Instance* p) { + if (p == NULL) return; + + //{ /* Deallocate resources */ + // struct Resources* r = (struct Resources*)p->data; + // if (r != NULL) { + // /* Destroy textures */ + // for (usize i = 0; i < r->textures_len; i++) { + // if (r->textures[i] != NULL) { + // r->textures[i] = NULL; + // } + // } + // free(r->textures); + + // /* Destroy Fonts */ + // } + //} + + Platform_GLFW.window_destroy(p->window); + free(p->resources); +} + +/* Set the maximum framerate */ +void engine_fps_max(Instance* p, u16 cap) { + LOG("Setting max fps to %llu", cap); + p->fps_target = cap; +} + +usize f_get_sz(FILE* f) { + if (f == NULL) { + ERROR("File was null!"); + return 0; + } + + const isize pos = ftell(f); + if (pos == -1) { + ERROR("Failed to determine file size (%d): %s", errno, strerror(errno)); + return 0; + } + + const i32 err = fseek(f, 0, SEEK_END); + if (err != 0) { + if (err == ESPIPE) { + ERROR("File is a pipe"); + } else { + ERROR("Failed to determine file size!"); + } + return 0; + } + + const isize size = ftell(f); + + if (size == -1) { + ERROR("Failed to determine file size (%d): %s", errno, strerror(errno)); + return 0; + } + + // Reset the position to the position prior to calling f_get_sz + fseek(f, pos, SEEK_SET); + + return (usize)size; +} |
