summaryrefslogtreecommitdiff
path: root/src/engine.c
diff options
context:
space:
mode:
author0scar <qgt268@alumni.ku.dk>2020-09-29 06:51:02 +0000
committer0scar <qgt268@alumni.ku.dk>2023-07-28 09:48:17 +0000
commit6c16f339224a4736f4ed57d15bb3e5f968a635ab (patch)
treeab13afea4b6f9acfb4a139a3125f265c90bc9d80 /src/engine.c
Initial independent commit
Diffstat (limited to 'src/engine.c')
-rw-r--r--src/engine.c686
1 files changed, 686 insertions, 0 deletions
diff --git a/src/engine.c b/src/engine.c
new file mode 100644
index 0000000..fa528c0
--- /dev/null
+++ b/src/engine.c
@@ -0,0 +1,686 @@
+#include <stdlib.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_ttf.h>
+
+#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32)
+ /* include winapi */
+#elif defined (__APPLE__)
+ /* mac includes */
+#elif defined (__linux) || defined (__linux__) || defined (linux)
+
+#include <unistd.h>
+
+#endif
+
+
+#define ENGINE_INTERNALS
+#include <engine/engine.h>
+#include <engine/btree.h>
+#include <engine/hashmap.h>
+#include <engine/list.h>
+
+#include <engine/state.h>
+//#include <states/titlescreen.h>
+//#include <states/gameover.h>
+
+#define DEFAULT_NUM_PROCS 8
+
+#ifdef BENCHMARK
+#define BENCHEXPR(timevar, expr) { \
+ u32 t = SDL_GetTicks(); \
+ expr \
+ timevar += SDL_GetTicks() - t; \
+}
+
+extern i32 drawcall_len;
+
+#else
+#define BENCHEXPR(timevar, expr) expr
+#endif
+
+i32 bindings_cmp(const Keybinding *a, const Keybinding *b) {
+ return a->modifiers ^ b->modifiers;
+}
+
+i32 binding_to_int(const Keybinding *b) {
+ return b->keycode;
+}
+
+/* Defines (struct) List_Keybinding */
+/* Defines (struct) hashmap_Keybinding,
+ * and hashmap_Keybinding_lookup, and hashmap_Keybinding_insert */
+DEFINE_HASHMAP(Keybinding, 64, bindings_cmp, binding_to_int)
+
+static u64 FPS_CAP = 50;
+Platform *GLOBAL_PLATFORM = NULL;
+
+i32 nproc(void) {
+ return SDL_GetCPUCount();
+}
+
+i32 cmp_int(const void *a, const void *b) {
+ const i32 *x = a;
+ const i32 *y = b;
+
+ return *x - *y;
+}
+
+v2_i32 get_canvas_size(SDL_Renderer *renderer) {
+ v2_i32 realsize;
+ SDL_GetRendererOutputSize(renderer, &(realsize.x), &(realsize.y));
+
+ /* Set logical render size */
+ return realsize;
+}
+
+Texture *load_texture(SDL_Renderer *render, const TextureSpec *ts) {
+ SDL_Texture* new_texture = NULL;
+ SDL_Surface* loaded_surface = NULL;
+ Texture *t = NULL;
+
+ if (ts == NULL) {
+ ERROR("Invalid TextureSpec\n");
+ return NULL;
+ }
+
+ loaded_surface = IMG_Load(ts->path);
+ if (loaded_surface == NULL) {
+ ERROR("Unable to load image \"%s\"!\n", ts->path);
+ ERROR("SDL_image Error: %s\n", IMG_GetError());
+ return NULL;
+ }
+
+ const i32 tw = loaded_surface->w / ts->width;
+
+ SDL_SetColorKey(loaded_surface, SDL_TRUE,
+ SDL_MapRGB(loaded_surface->format, 0xFF, 0x00, 0xFF));
+
+ /*Create texture from surface pixels */
+ new_texture = SDL_CreateTextureFromSurface(render, loaded_surface);
+ if (new_texture == NULL) {
+ ERROR("Unable to create texture from \"%s\"!\n", ts->path);
+ ERROR("SDL Error: %s\n", SDL_GetError());
+ }
+
+ /*Get rid of old loaded surface */
+ SDL_FreeSurface(loaded_surface);
+
+ t = (Texture*)malloc(sizeof(Texture));
+ t->texture = new_texture;
+ /* Assigning const value */
+ *(i32*)&t->tilesize = tw;
+ *(i32*)&t->width = ts->width;
+ *(i32*)&t->height = ts->height;
+
+ return t;
+}
+
+void engine_update_window(Window *w, SDL_WindowEvent *e) {
+ switch (e->event) {
+ case SDL_WINDOWEVENT_NONE:
+ case SDL_WINDOWEVENT_SHOWN:
+ case SDL_WINDOWEVENT_HIDDEN:
+ case SDL_WINDOWEVENT_EXPOSED:
+ case SDL_WINDOWEVENT_MOVED:
+ break;
+ case SDL_WINDOWEVENT_RESIZED:
+ w->windowsize = get_canvas_size(w->renderer);
+ LOG("Resized window to %dx%d", w->windowsize.x, w->windowsize.y);
+ ui_resolve_constraints();
+ if (w->game_w != NULL && w->game_h != NULL) {
+ *w->game_h = w->windowsize.x;
+ *w->game_w = w->windowsize.y;
+ }
+ break;
+ case SDL_WINDOWEVENT_SIZE_CHANGED:
+ case SDL_WINDOWEVENT_MINIMIZED:
+ case SDL_WINDOWEVENT_MAXIMIZED:
+ case SDL_WINDOWEVENT_RESTORED:
+ case SDL_WINDOWEVENT_ENTER:
+ case SDL_WINDOWEVENT_LEAVE:
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ case SDL_WINDOWEVENT_CLOSE:
+ case SDL_WINDOWEVENT_TAKE_FOCUS:
+ case SDL_WINDOWEVENT_HIT_TEST:
+ break;
+ default:
+ WARN("Unhandled window event 0x%04x", (i32)e->event);
+ break;
+ }
+ return;
+}
+
+Platform *engine_init(
+ const char *windowtitle,
+ v2_i32 windowsize,
+ const f32 render_scale,
+ const u32 flags,
+ const usize initial_memory,
+ const FontSpec *fonts[],
+ const TextureSpec *textures[]) {
+
+#ifdef BENCHMARK
+ u32 init_start = SDL_GetTicks();
+#endif
+
+#if defined (__linux) || defined (__linux__) || defined (linux)
+ {
+ pid_t pid = getpid();
+ INFO("Starting with pid %lu", pid);
+ }
+#endif
+
+ Platform *p = (Platform*)malloc(sizeof(Platform));
+ Window *w = (Window*)malloc(sizeof(Window));
+ SDL_Window *window = NULL;
+ SDL_Renderer *renderer = NULL;
+
+ /* initialize resources */
+ struct Resources *resources = (struct Resources*)malloc(sizeof(struct Resources));
+ resources->textures_len = 0;
+ resources->fonts_len = 0;
+ resources->texturepaths_len = 0;
+ resources->fontpaths_len = 0;
+ resources->texture_paths = NULL;
+ resources->font_paths = NULL;
+ resources->textures = NULL;
+ resources->fonts = NULL;
+
+
+ { /* Init subsystems */
+ INFO_("initializing sdl...");
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ ERROR("failed to initialize sdl: %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ } else printf("ok\n");
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+
+ INFO_("creating window...");
+ window = SDL_CreateWindow(windowtitle,
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ windowsize.x, windowsize.y,
+ SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS | flags);
+
+ if (window == NULL) {
+ ERROR("failed to create window: %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ } else printf("ok\n");
+
+ INFO_("creating renderer...");
+ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+ if (renderer == NULL) {
+ ERROR("failed to create renderer: %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+ } else printf("ok\n");
+
+ INFO_("initializing sdl_image...");
+ if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) {
+ ERROR("failed to initialize sdl_image png support\n");
+ exit(EXIT_FAILURE);
+ } else printf("ok\n");
+
+ INFO_("initializing sdl_ttf...");
+ if (TTF_Init() == -1) {
+ ERROR("failed to initialize sdl_ttf: %s\n", TTF_GetError());
+ exit(EXIT_FAILURE);
+ } else printf("ok\n");
+ }
+
+
+ { /* Resource loading */
+
+ /* Count resources */
+ usize n_textures = 0;
+ usize n_fonts = 0;
+
+ if (textures != NULL) while (textures[n_textures] != NULL) n_textures++;
+ if (fonts != NULL) while (fonts[n_fonts] != NULL) n_fonts++;
+
+ INFO("Number of textures: "TERM_COLOR_YELLOW"%d"TERM_COLOR_RESET, n_textures);
+ INFO("Number of fonts: "TERM_COLOR_YELLOW"%d"TERM_COLOR_RESET, n_fonts);
+
+
+ /* Save the textures and fonts, if we should need to reload them later */
+ resources->texture_paths = (TextureSpec**)textures;
+ resources->font_paths = (FontSpec**)fonts;
+
+ /* Allocate memory for textures and fonts */
+ resources->textures = (Texture**)malloc(sizeof(Texture*) * n_textures);
+ resources->fonts = (TTF_Font**)malloc(sizeof(TTF_Font*) * n_fonts);
+ resources->textures_size = n_textures;
+
+ for (usize i = 0; i < n_textures; i++) resources->textures[i] = NULL;
+ for (usize i = 0; i < n_fonts; i++) resources->fonts[i] = NULL;
+
+ /* Load textures */
+ for (usize i = 0; i < n_textures; i++) {
+ Texture *t = NULL;
+ INFO_("loading texture \""
+ TERM_COLOR_YELLOW"%s"TERM_COLOR_RESET
+ "\"...", textures[i]->path);
+
+ t = load_texture(renderer, textures[i]);
+ if (t == NULL) {
+ puts("");
+ ERROR("failed to load texture\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (t->tilesize < 8) {
+ puts("");
+ ERROR("texture too small!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (t->texture == NULL) {
+ puts("");
+ ERROR("failed to load texture\n");
+ } else {
+ printf("ok\n");
+ resources->textures[i] = t;
+ resources->textures_len++;
+ }
+ }
+
+ /* Load fonts */
+ for (usize i = 0; i < n_fonts; i++) {
+ INFO_("loading font \""
+ TERM_COLOR_YELLOW"%s"TERM_COLOR_RESET
+ "\"...", fonts[i]->font_path);
+
+ TTF_Font *font = TTF_OpenFont(fonts[i]->font_path
+ , fonts[i]->ptsize);
+ if (!font) {
+ ERROR("failed to load font: %s\n", TTF_GetError());
+ } else {
+ printf("ok\n");
+ resources->fonts[i] = font;
+ resources->fonts_len++;
+ }
+ }
+
+ if (resources->textures_len != n_textures) {
+ WARN("Done. %d/%d textures loaded.", resources->textures_len, n_textures);
+ } else {
+ INFO("Done. All %d textures loaded.", n_textures);
+ }
+
+ if (resources->fonts_len != n_fonts) {
+ WARN("Done. %d/%d fonts loaded.", resources->fonts_len, n_fonts);
+ } else {
+ INFO("Done. All %d fonts loaded.", n_fonts);
+ }
+
+ resources->texturepaths_len = resources->textures_len;
+ resources->fontpaths_len = resources->fonts_len;
+
+ }
+
+
+ { /* Adjust window and such */
+ /* Set actual windowsize, which might be forced by OS */
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
+ INFO("Adjusting window size...");
+ windowsize = get_canvas_size(renderer);
+
+ SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
+
+ INFO("Windowsize: <%d,%d>", windowsize.x, windowsize.y);
+ }
+
+ w->renderer = renderer;
+ w->window = window;
+ w->render_scale = render_scale;
+ w->windowsize = windowsize;
+ w->game_w = NULL;
+ w->game_h = NULL;
+
+ p->data = (void*)resources;
+ p->data_len = sizeof(struct Resources);
+ p->window = w;
+ p->quit = false;
+
+ p->frame = 0;
+ p->fps_target = 60;
+
+ p->mem = memory_new(initial_memory);
+
+ /* Getting the mouse coords now resolves the issue where a click "isn't
+ * registered" when the mouse isn't moved before the user clicks */
+ SDL_GetMouseState(&p->mouse_pos.x, &p->mouse_pos.y);
+
+ p->mousedown = (v2_i32){-1, -1};
+ p->mouseup = (v2_i32){-1, -1};
+
+ p->mouse_lclick = false;
+ p->mouse_rclick = false;
+
+ p->camera_x = 0;
+ p->camera_y = 0;
+
+ p->edit_text = NULL;
+ p->edit_pos = 0;
+
+ p->bindings = NULL;
+
+#ifdef BENCHMARK
+ u32 init_stop = SDL_GetTicks();
+ INFO("Initialization took %dms", init_stop - init_start);
+#endif
+
+ INFO("Available cores: %d", nproc());
+
+ GLOBAL_PLATFORM = p;
+
+ return p;
+}
+
+i32 engine_run(Platform *p, StateType initial_state) {
+ if (p == NULL) {
+ ERROR("Platform is uninitialized.\n");
+ INFO("initialize with `engine_init`");
+ return -1;
+ }
+
+ memory* mem = p->mem;
+
+ StateType state = initial_state;
+
+ {
+ u32 state_init_time = SDL_GetTicks();
+ State_init(state, mem);
+ INFO("Initializing state \"%s\" took %ldms", StateTypeStr[state], SDL_GetTicks() - state_init_time);
+ }
+
+ u32 time = SDL_GetTicks();
+
+ // Update ticks
+ u64 ticks = 0;
+
+ /* Profiling values */
+#ifdef BENCHMARK
+ u64 profile_tick_counter = 0;
+ //u64 profile_slack = 0;
+ u64 profile_rendering = 0;
+ u64 profile_gameloop = 0;
+ u64 profile_input = 0;
+ u64 profile_input_handling = 0;
+ u64 profile_num_drawcalls = 0;
+ u32 profile_interval_timer = time;
+ const u32 profile_interval_ms = 5000;
+ const f32 profile_interval_scale = (f32)(profile_interval_ms) / 100.0f;
+#endif
+
+ const f64 frame_interval = 1000.0 / FPS_CAP;
+
+ StateType (*update_func)(void*) = State_updateFunc(state);
+
+ /* Main loop */
+ do {
+ const u32 now = SDL_GetTicks();
+ const u64 dt = now - time;
+ time = now;
+ /* Wait frame_interval */
+ if (dt < frame_interval) {
+#ifndef BENCHMARK
+ SDL_Delay(frame_interval - dt);
+
+#else
+ /* We want to know how much time is spend sleeping */
+ //profile_slack += frame_interval - dt;
+#endif
+ }
+
+#ifdef BENCHMARK
+ if (time - profile_interval_timer > profile_interval_ms) {
+ /* Ticks/frames since last measurement */
+ u32 fps = (ticks - profile_tick_counter) / profile_interval_scale;
+ u64 drawcalls = profile_num_drawcalls / profile_interval_scale / fps;
+
+ u32 sum =
+ + profile_rendering
+ //+ profile_slack
+ + profile_input
+ + profile_input_handling
+ + profile_gameloop
+ ;
+
+
+ /* Log fps and slack percentage */
+ LOG("fps:%d\t"
+ "rendering:%.2f%%\t"
+ //"slack:%.2f%%\t"
+ "input:%.2f%% (%.2f%%)\t"
+ "gameloop:%.2f%%\t"
+ "unaccounted:%llu / %llu ms\t"
+ "avg drawcalls:%llu",
+ fps,
+ 100.0f * (f32)profile_rendering / (f32)sum,
+ //100.0f * (f32)profile_slack / (f32)sum,
+ 100.0f * (f32)profile_input / (f32)sum,
+ 100.0f * (f32)profile_input_handling / (f32)sum,
+ 100.0f * (f32)profile_gameloop / (f32)sum,
+ time - profile_interval_timer - sum, sum,
+ drawcalls);
+ /* Reset values */
+ profile_tick_counter = ticks;
+ profile_interval_timer = time;
+ //profile_slack = 0;
+ profile_rendering = 0;
+ profile_gameloop = 0;
+ profile_input = 0;
+ profile_input_handling = 0;
+ profile_num_drawcalls = 0;
+ }
+#endif
+
+ /* Events */
+ BENCHEXPR(profile_input, {
+
+ if (GLOBAL_PLATFORM->mouse_lclick) {
+ GLOBAL_PLATFORM->mouseup.x = -1;
+ GLOBAL_PLATFORM->mouseup.y = -1;
+ GLOBAL_PLATFORM->mousedown.x = -1;
+ GLOBAL_PLATFORM->mousedown.y = -1;
+ GLOBAL_PLATFORM->mouse_lclick = false;
+ }
+ if (GLOBAL_PLATFORM->mouse_rclick) {
+ GLOBAL_PLATFORM->mouse_rclick = false;
+ }
+
+ /* Window events */
+ SDL_Event e[8];
+ i32 num_events;
+ SDL_PumpEvents();
+ while ((num_events = SDL_PeepEvents(e, 8, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_SYSWMEVENT)) > 0) {
+ for (i32 i = 0; i < num_events; i++) {
+ switch (e[i].type) {
+ case SDL_QUIT:
+ state = STATE_quit;
+ break;
+ case SDL_WINDOWEVENT:
+ engine_update_window(p->window, &e[i].window);
+ break;
+ default:
+ WARN("Unhandled event 0x%04x", (i32)e[i].type);
+ }
+ }
+ }
+
+ /* Mouse events */
+ while ((num_events = SDL_PeepEvents(e, 8, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEWHEEL)) > 0) {
+ for (i32 i = 0; i < num_events; i++) {
+ switch (e[i].type) {
+ case SDL_MOUSEWHEEL: break;
+ case SDL_MOUSEMOTION:
+ {
+ SDL_MouseMotionEvent m = e[i].motion;
+ /* In case of a first-person game, use xrel and yrel */
+ GLOBAL_PLATFORM->mouse_pos.x = m.x;
+ GLOBAL_PLATFORM->mouse_pos.y = m.y;
+ }
+ break;
+ case SDL_MOUSEBUTTONUP:
+ {
+ switch (e[i].button.button) {
+ case SDL_BUTTON_LEFT:
+ GLOBAL_PLATFORM->mouseup = GLOBAL_PLATFORM->mouse_pos;
+
+ GLOBAL_PLATFORM->mouse_lclick = true;
+ case SDL_BUTTON_RIGHT:
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ switch (e[i].button.button) {
+ case SDL_BUTTON_LEFT:
+ GLOBAL_PLATFORM->mousedown = GLOBAL_PLATFORM->mouse_pos;
+ break;
+ case SDL_BUTTON_RIGHT:
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ WARN("Unhandled mouse event 0x%04x", (i32)e[i].type);
+ break;
+ }
+ }
+ }
+
+ BENCHEXPR(profile_input_handling, {
+ while ((num_events = SDL_PeepEvents(e, 8, SDL_GETEVENT, SDL_KEYDOWN, SDL_KEYUP)) > 0) {
+ for (i32 i = 0; i < num_events; i++) {
+ switch (e[i].type) {
+ case SDL_KEYDOWN: {
+ Keybinding lookupkey = ((Keybinding){
+ .keycode = e[i].key.keysym.sym,
+ .modifiers = e[i].key.keysym.mod
+ });
+ Keybinding *kb = hashmap_Keybinding_lookup(GLOBAL_PLATFORM->bindings, &lookupkey);
+ if (kb != NULL && kb->action != NULL) kb->action(mem->data);
+ }
+ break;
+ case SDL_KEYUP:
+ break;
+ default:
+ WARN("Unhandled mouse event 0x%04x", (i32)e[i].type);
+ break;
+ }
+ }
+ }
+ });
+ });
+
+ /* update */
+ StateType next_state;
+ BENCHEXPR(profile_gameloop, {next_state = update_func((void*)(mem->data));} );//State_update(state, mem);});
+
+ if (next_state != STATE_null) {
+ if (next_state == STATE_quit) break;
+
+ drawcall_reset();
+
+ engine_window_resize_pointers_reset();
+ State_free(state, mem);
+ memory_clear(mem);
+
+ GLOBAL_PLATFORM->bindings = NULL;
+
+ state = next_state;
+ update_func = State_updateFunc(state);
+#ifdef BENCHMARK
+ {
+ u32 t = SDL_GetTicks();
+ State_init(state, mem);
+ LOG("Initializing %s took %dms", StateTypeStr[state], SDL_GetTicks() - t);
+ }
+#else
+ State_init(state, mem);
+#endif
+ } else {
+#ifdef BENCHMARK
+ profile_num_drawcalls += drawcall_len;
+#endif
+ render_begin(p->window);
+ BENCHEXPR(profile_rendering, {render_present(p->window);})
+ }
+
+
+ ticks++;
+ } while (state != STATE_quit);
+
+ return 0;
+}
+
+
+void stop(Platform *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) {
+ SDL_DestroyTexture(r->textures[i]->texture);
+ r->textures[i] = NULL;
+ }
+ }
+ free(r->textures);
+
+ /* Destroy Fonts */
+ for (usize i = 0; i < r->fonts_len; i++) {
+ if (r->fonts[i] != NULL) {
+ TTF_CloseFont(r->fonts[i]);
+ r->fonts[i] = NULL;
+ }
+ }
+ free(r->fonts);
+ }
+ }
+
+ { /* Deallocate window */
+ Window *w = p->window;
+ if (w != NULL) {
+ if (w->window != NULL) { SDL_DestroyWindow(w->window); w->window = NULL; }
+ if (w->renderer != NULL) { SDL_DestroyRenderer(w->renderer); w->renderer = NULL; }
+ }
+ }
+
+ TTF_Quit();
+ IMG_Quit();
+ SDL_Quit();
+}
+
+void engine_fps_max(u64 cap) { FPS_CAP = cap; }
+
+void engine_bindkey(i32 key, void (*action)(void*)) {
+ /* TODO: Make a hashmap ++ linked list */
+ //if (key >= 512) {
+ // ERROR("Key value too high! (got %d)\n", key);
+ //}
+ if (GLOBAL_PLATFORM->bindings == NULL) {
+ //GLOBAL_PLATFORM->bindings = memory_allocate(GLOBAL_PLATFORM->mem, 512 * sizeof(Keybinding));
+ GLOBAL_PLATFORM->bindings = memory_allocate(GLOBAL_PLATFORM->mem, sizeof(hashmap_Keybinding));
+ }
+
+ Keybinding kb = (Keybinding){.keycode = key, .action = action};
+ hashmap_Keybinding_insert(GLOBAL_PLATFORM->mem, GLOBAL_PLATFORM->bindings, &kb);
+}
+
+
+u32 get_time(void) {return SDL_GetTicks();}
+v2_i32 get_windowsize(void) {return GLOBAL_PLATFORM->window->windowsize;}
+v2_i32 *get_mousepos(void) { return &GLOBAL_PLATFORM->mouse_pos; }