Entropie git · main
Entropie festival game; first steps
C 88.5% Markdown 9.1% GLSL 2.3%git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gzentropie/src/core/platform.c raw
#include "core/platform.h"
#include "core/gl.h"
#include "build_info.h" /* ASSET_DIR, generated by the Makefile */
#include <stdio.h>
#include <string.h>
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);
}