/* LibreFront --- an OpenFront clone Copyright (C) 2025 Adrien Jaguenet Copyright (C) 2025 Emil Kosz This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #define SDL_MAIN_USE_CALLBACKS 1 #include #include #include #include #include #include static GfxContext *gfx_ctx; static World *test_world; World * _make_test_World () { World *self = World_load_from_path ("res/test_map_2.png"); /* TODO: add players and so on. That will be in GameState, though. Or GameData. */ return self; } SDL_AppResult SDL_AppInit (void **appstate, int argc, char **argv) { UNUSED (appstate, argc, argv); /* Makes GLib use less dumb useless shit. */ setenv ("GIO_USE_VFS", "local", 1); setenv ("GSETTINGS_BACKEND", "memory", 1); /* This is set in the Makefile. By default it's 1, so we get all the debug messages printed. */ #ifdef DEBUG setenv ("G_MESSAGES_DEBUG", "all", 1); #endif SDL_SetAppMetadata (GAME_NAME, GAME_VERSION, GAME_URL); if (!SDL_Init (SDL_INIT_VIDEO)) { g_error ("Couldn't initialize SDL: %s", SDL_GetError ()); } gfx_ctx = GfxContext_new (); test_world = _make_test_World (); GfxContext_cache_World (gfx_ctx, test_world); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent (void *appstate, SDL_Event *event) { UNUSED (appstate); if (event->type == SDL_EVENT_QUIT) { return SDL_APP_SUCCESS; } /* TODO: implement an event manager so this isn't in the main client file. */ static bool dragging = false; static float drag_start_x = 0, drag_start_y = 0; static float drag_origin_x = 0, drag_origin_y = 0; if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN && event->button.button == SDL_BUTTON_LEFT) { dragging = true; drag_start_x = event->button.x; drag_start_y = event->button.y; drag_origin_x = gfx_ctx->world_x_offset; drag_origin_y = gfx_ctx->world_y_offset; } else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP && event->button.button == SDL_BUTTON_LEFT) { dragging = false; } else if (event->type == SDL_EVENT_MOUSE_MOTION && dragging) { float dx = event->motion.x - drag_start_x; float dy = event->motion.y - drag_start_y; gfx_ctx->world_x_offset = drag_origin_x + dx; gfx_ctx->world_y_offset = drag_origin_y + dy; } if (event->type == SDL_EVENT_MOUSE_WHEEL) { float zoom_factor = 1.0f + (event->wheel.y * 0.1f); /* ±10% per notch */ /* Zoom around the mouse cursor */ int win_w, win_h; SDL_GetWindowSize (gfx_ctx->window, &win_w, &win_h); float mouse_x = event->wheel.mouse_x; float mouse_y = event->wheel.mouse_y; float before_x = (mouse_x - gfx_ctx->world_x_offset) / gfx_ctx->world_scale; float before_y = (mouse_y - gfx_ctx->world_y_offset) / gfx_ctx->world_scale; gfx_ctx->world_scale *= zoom_factor; if (gfx_ctx->world_scale < 0.1f) { gfx_ctx->world_scale = 0.1f; /* clamp */ } if (gfx_ctx->world_scale > 10.0f) { gfx_ctx->world_scale = 10.0f; } float after_x = before_x * gfx_ctx->world_scale; float after_y = before_y * gfx_ctx->world_scale; gfx_ctx->world_x_offset = mouse_x - after_x; gfx_ctx->world_y_offset = mouse_y - after_y; } return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate (void *appstate) { UNUSED (appstate); GfxContext_render (gfx_ctx); return SDL_APP_CONTINUE; } void SDL_AppQuit (void *appstate, SDL_AppResult result) { UNUSED (appstate, result); GfxContext_free (gfx_ctx); }