From a19049d7a6bed9b236c5e714dde844925750e39d Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 19 Jul 2025 13:23:29 -0700 Subject: Implement camera pan --- CMakeLists.txt | 1 + demos/isomap/isomap.c | 28 +++++++++++++++++++++++++++- include/isogfx/isogfx.h | 3 +++ src/isogfx.c | 24 +++++++++++++++++------- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 498adc8..72429c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ target_include_directories(isogfx PUBLIC target_link_libraries(isogfx PUBLIC filesystem + math memstack) target_compile_options(isogfx PRIVATE -Wall -Wextra -Wpedantic) diff --git a/demos/isomap/isomap.c b/demos/isomap/isomap.c index efae7fd..a940535 100644 --- a/demos/isomap/isomap.c +++ b/demos/isomap/isomap.c @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -15,6 +16,8 @@ static const int MAX_FPS = 60; static const int SCREEN_WIDTH = 704; static const int SCREEN_HEIGHT = 480; +static const R CAMERA_SPEED = 400; + #define MEMORY_SIZE (2 * 1024 * 1024) uint8_t MEMORY[MEMORY_SIZE]; @@ -23,6 +26,7 @@ typedef struct GfxAppState { IsoGfx* iso; int xpick; int ypick; + vec2 camera; SpriteSheet stag_sheet; Sprite stag; } GfxAppState; @@ -67,11 +71,33 @@ static void shutdown(GfxAppState* state) { // } +static vec2 get_camera_movement(R dt) { + vec2 offset = {0}; + if (gfx_app_is_key_pressed(KeyA)) { + offset.x -= 1; + } + if (gfx_app_is_key_pressed(KeyD)) { + offset.x += 1; + } + if (gfx_app_is_key_pressed(KeyW)) { + offset.y -= 1; + } + if (gfx_app_is_key_pressed(KeyS)) { + offset.y += 1; + } + if ((offset.x != 0) || (offset.y != 0)) { + offset = vec2_scale(vec2_normalize(offset), dt * CAMERA_SPEED); + } + return offset; +} + static void update(GfxAppState* state, double t, double dt) { assert(state); - (void)dt; + + state->camera = vec2_add(state->camera, get_camera_movement((R)dt)); IsoGfx* iso = state->iso; + isogfx_set_camera(iso, (int)state->camera.x, (int)state->camera.y); isogfx_update(iso, t); } diff --git a/include/isogfx/isogfx.h b/include/isogfx/isogfx.h index 93c6d4e..e901231 100644 --- a/include/isogfx/isogfx.h +++ b/include/isogfx/isogfx.h @@ -102,6 +102,9 @@ void isogfx_set_sprite_animation(IsoGfx*, Sprite, int animation); /// Currently this updates the sprite animations. void isogfx_update(IsoGfx*, double t); +/// Set the camera. +void isogfx_set_camera(IsoGfx*, int x, int y); + /// Render the world. void isogfx_render(IsoGfx*); diff --git a/src/isogfx.c b/src/isogfx.c index 0aaeb9d..5d23ae4 100644 --- a/src/isogfx.c +++ b/src/isogfx.c @@ -55,6 +55,7 @@ typedef struct SpriteInstance { typedef struct IsoGfx { Screen screen; CoordSystem iso_space; + ivec2 camera; double last_animation_time; Tile next_tile; // For procedurally-generated tiles. Tm_Map* map; @@ -76,6 +77,8 @@ static inline ivec2 ivec2_scale(ivec2 a, int s) { return (ivec2){.x = a.x * s, .y = a.y * s}; } +static inline ivec2 ivec2_neg(ivec2 a) { return (ivec2){.x = -a.x, .y = -a.y}; } + static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2), .y = (iso.x + iso.y) * (t / 2)}; @@ -490,13 +493,13 @@ void isogfx_update(IsoGfx* iso, double t) { /// Get the screen position of the top diamond-corner of the tile at world /// (x,y). static ivec2 GetTileScreenOrigin( - const CoordSystem iso_space, int world_x, int world_y) { + const CoordSystem iso_space, ivec2 camera, int world_x, int world_y) { const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x); const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y); const ivec2 screen_origin = ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); - - return screen_origin; + const ivec2 origin_view_space = ivec2_add(screen_origin, ivec2_neg(camera)); + return origin_view_space; } static Pixel alpha_blend(Pixel src, Pixel dst) { @@ -598,8 +601,9 @@ static void draw_world(IsoGfx* iso) { // screen-centric approach would juggle multiple tiles throughout the scan. for (int wy = 0; wy < iso->map->world_height; ++wy) { for (int wx = 0; wx < iso->map->world_width; ++wx) { - const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); - const ivec2 screen_origin = GetTileScreenOrigin(iso->iso_space, wx, wy); + const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); + const ivec2 screen_origin = + GetTileScreenOrigin(iso->iso_space, iso->camera, wx, wy); draw_tile(iso, screen_origin, tile); } } @@ -631,11 +635,16 @@ static void draw_sprites(IsoGfx* iso) { assert(sheet); const ivec2 screen_origin = GetTileScreenOrigin( - iso->iso_space, sprite->position.x, sprite->position.y); + iso->iso_space, iso->camera, sprite->position.x, sprite->position.y); draw_sprite(iso, screen_origin, sprite, sheet); } } +void isogfx_set_camera(IsoGfx* iso, int x, int y) { + assert(iso); + iso->camera = (ivec2){x, y}; +} + void isogfx_render(IsoGfx* iso) { assert(iso); draw_world(iso); @@ -649,7 +658,8 @@ void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) { assert(x < iso->map->world_width); assert(y < iso->map->world_height); - const ivec2 screen_origin = GetTileScreenOrigin(iso->iso_space, x, y); + const ivec2 screen_origin = + GetTileScreenOrigin(iso->iso_space, iso->camera, x, y); draw_tile(iso, screen_origin, tile); } -- cgit v1.2.3