From 22c14129c1c6d0befa45ad1d1e36bcad60c474b0 Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Thu, 25 Sep 2025 09:57:27 +0200 Subject: [PATCH] Implement map dragging and zooming --- src/client/client.c | 62 ++++++++++++++++++++++++++++++++++++++++ src/client/gfx_context.c | 26 +++++++++++++++-- src/client/gfx_context.h | 2 ++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/client/client.c b/src/client/client.c index 29835ae..1d0c365 100644 --- a/src/client/client.c +++ b/src/client/client.c @@ -83,6 +83,68 @@ SDL_AppEvent (void *appstate, SDL_Event *event) 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; } diff --git a/src/client/gfx_context.c b/src/client/gfx_context.c index 02ea7eb..f8691a9 100644 --- a/src/client/gfx_context.c +++ b/src/client/gfx_context.c @@ -42,6 +42,8 @@ GfxContext_new () SDL_GetError ()); } + GfxContext_reset (self); + return self; } @@ -53,12 +55,30 @@ GfxContext_render (GfxContext *self) if (self->world_texture) { - SDL_RenderTexture (self->renderer, self->world_texture, NULL, NULL); + float tex_w, tex_h; + SDL_GetTextureSize (self->world_texture, &tex_w, &tex_h); + + SDL_FRect dst = { + .x = self->world_x_offset, + .y = self->world_y_offset, + .w = tex_w * self->world_scale, + .h = tex_h * self->world_scale + }; + + SDL_RenderTexture (self->renderer, self->world_texture, NULL, &dst); } SDL_RenderPresent (self->renderer); } +void +GfxContext_reset (GfxContext *self) +{ + self->world_scale = 1.0; + self->world_x_offset = 0.0; + self->world_y_offset = 0.0; +} + void GfxContext_free (GfxContext *self) { @@ -99,7 +119,9 @@ GfxContext_cache_World (GfxContext *self, World *world) g_array_index (world->tiles, MapTile *, y * world->width + x); if (!mt) - continue; + { + continue; + } switch (mt->terrain_type) { diff --git a/src/client/gfx_context.h b/src/client/gfx_context.h index e839b6e..6c0770c 100644 --- a/src/client/gfx_context.h +++ b/src/client/gfx_context.h @@ -38,10 +38,12 @@ typedef struct GfxContext and it could be done concurrently. */ + float world_scale, world_x_offset, world_y_offset; } GfxContext; GfxContext *GfxContext_new (); void GfxContext_render (GfxContext * self); +void GfxContext_reset (GfxContext *self); void GfxContext_free (GfxContext * self); void GfxContext_cache_World (GfxContext * self, World * world);