#include "core/platform.h" #include "core/gl.h" #include "build_info.h" /* ASSET_DIR, generated by the Makefile */ #include #include static char g_asset_dir[1024]; static void resolveAssetDir(void) { const char *base = SDL_GetBasePath(); /* owned by SDL, ends with '/' */ if (base) { char local[sizeof(g_asset_dir)]; snprintf(local, sizeof(local), "%sassets/", base); if (SDL_GetPathInfo(local, NULL)) { snprintf(g_asset_dir, sizeof(g_asset_dir), "%s", local); return; } } snprintf(g_asset_dir, sizeof(g_asset_dir), "%s", ASSET_DIR); } bool Platform_assetPath(const char *relative, char *out, size_t out_size) { int n = snprintf(out, out_size, "%s%s", g_asset_dir, relative); return n > 0 && (size_t)n < out_size; } bool Platform_init(Platform *p, const char *title, int width, int height) { memset(p, 0, sizeof(*p)); if (!SDL_Init(SDL_INIT_VIDEO)) { SDL_Log("SDL_Init failed: %s", SDL_GetError()); return false; } p->sdl_ready = true; SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); p->window = SDL_CreateWindow(title, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!p->window) { SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError()); return false; } p->gl_context = SDL_GL_CreateContext(p->window); if (!p->gl_context) { SDL_Log("SDL_GL_CreateContext failed: %s", SDL_GetError()); return false; } if (!SDL_GL_MakeCurrent(p->window, p->gl_context)) { SDL_Log("SDL_GL_MakeCurrent failed: %s", SDL_GetError()); return false; } if (!Gl_load()) return false; SDL_Log("OpenGL %s", (const char *)glGetString(GL_VERSION)); /* vsync (adaptive if there is it): no more frames than the screen shows */ if (!SDL_GL_SetSwapInterval(-1) && !SDL_GL_SetSwapInterval(1)) SDL_Log("No vsync: %s (the frame cap keeps it at %d fps)", SDL_GetError(), FRAME_CAP); SDL_SetWindowRelativeMouseMode(p->window, true); resolveAssetDir(); SDL_Log("Assets: %s", g_asset_dir); p->last_ticks_ns = SDL_GetTicksNS(); return true; } void Platform_shutdown(Platform *p) { if (p->gl_context) SDL_GL_DestroyContext(p->gl_context); if (p->window) SDL_DestroyWindow(p->window); if (p->sdl_ready) SDL_Quit(); memset(p, 0, sizeof(*p)); } float Platform_frameDelta(Platform *p) { Uint64 now = SDL_GetTicksNS(); float dt = (float)(now - p->last_ticks_ns) / 1e9f; p->last_ticks_ns = now; return dt; } void Platform_drawableSize(const Platform *p, int *width, int *height) { SDL_GetWindowSizeInPixels(p->window, width, height); if (*width < 1) *width = 1; if (*height < 1) *height = 1; } void Platform_swap(Platform *p) { SDL_GL_SwapWindow(p->window); /* the cap: a frame never quicker than 1 / FRAME_CAP s (vsync off or ignored: the GPU would run flat out) */ const Uint64 frame = 1000000000ull / FRAME_CAP; Uint64 now = SDL_GetTicksNS(), spent = now - p->frame_start_ns; if (p->frame_start_ns && spent < frame) SDL_DelayPrecise(frame - spent); p->frame_start_ns = SDL_GetTicksNS(); } void Platform_windowSize(const Platform *p, int *width, int *height) { SDL_GetWindowSize(p->window, width, height); } void Platform_captureMouse(const Platform *p, bool captured) { SDL_SetWindowRelativeMouseMode(p->window, captured); } bool Platform_saveDir(char *out, size_t out_size) { char *base = SDL_GetPrefPath("entropie", "entropie"); if (!base) return false; snprintf(out, out_size, "%ssaves", base); SDL_free(base); return true; } void Platform_typing(const Platform *p, bool on) { if (on) SDL_StartTextInput(p->window); else SDL_StopTextInput(p->window); }