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/daw.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 src/daw.c (limited to 'src/daw.c') 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 +#include +#include +#include +#include + +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +/* include winapi */ +#include +#elif defined(__APPLE__) +/* mac includes */ +#elif defined(__linux) || defined(__linux__) || defined(linux) + +#include +#include + +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#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 +#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; +} -- cgit v1.3