Files
librefront/src/client/client.c
T
2025-09-25 09:57:45 +02:00

170 lines
4.2 KiB
C

/*
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 <https://www.gnu.org/licenses/>.
*/
#define SDL_MAIN_USE_CALLBACKS 1
#include <stdlib.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <glib-2.0/glib.h>
#include <common/util.h>
#include <client/gfx_context.h>
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);
}