summaryrefslogtreecommitdiff
path: root/src/daw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daw.c')
-rw-r--r--src/daw.c344
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;
+}