Nimbin[12]?Games / Entropie / entropie/src/core/platform.c

Entropie git · main

Entropie festival game; first steps

sdl c game entropie cmake · first commit 2026-10-10 · last commit 2026-11-02 (18 hours ago) · synced 10 hours ago

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.gz
entropie/src/core/platform.c 4 KB · 122 lines 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);
}