summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-07-19 13:23:29 -0700
committer3gg <3gg@shellblade.net>2025-07-19 13:23:29 -0700
commita19049d7a6bed9b236c5e714dde844925750e39d (patch)
tree0113934ffe8e94fc2e20c4248886a1b79ae64a55
parent6e0913a3f77354eab2eeceba66db7d1750e22581 (diff)
Implement camera pan
-rw-r--r--CMakeLists.txt1
-rw-r--r--demos/isomap/isomap.c28
-rw-r--r--include/isogfx/isogfx.h3
-rw-r--r--src/isogfx.c24
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
17 17
18target_link_libraries(isogfx PUBLIC 18target_link_libraries(isogfx PUBLIC
19 filesystem 19 filesystem
20 math
20 memstack) 21 memstack)
21 22
22target_compile_options(isogfx PRIVATE -Wall -Wextra -Wpedantic) 23target_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 @@
2#include <isogfx/isogfx.h> 2#include <isogfx/isogfx.h>
3 3
4#include <gfx/app.h> 4#include <gfx/app.h>
5#include <math/vec2.h>
5 6
6#include <assert.h> 7#include <assert.h>
7#include <stdbool.h> 8#include <stdbool.h>
@@ -15,6 +16,8 @@ static const int MAX_FPS = 60;
15static const int SCREEN_WIDTH = 704; 16static const int SCREEN_WIDTH = 704;
16static const int SCREEN_HEIGHT = 480; 17static const int SCREEN_HEIGHT = 480;
17 18
19static const R CAMERA_SPEED = 400;
20
18#define MEMORY_SIZE (2 * 1024 * 1024) 21#define MEMORY_SIZE (2 * 1024 * 1024)
19uint8_t MEMORY[MEMORY_SIZE]; 22uint8_t MEMORY[MEMORY_SIZE];
20 23
@@ -23,6 +26,7 @@ typedef struct GfxAppState {
23 IsoGfx* iso; 26 IsoGfx* iso;
24 int xpick; 27 int xpick;
25 int ypick; 28 int ypick;
29 vec2 camera;
26 SpriteSheet stag_sheet; 30 SpriteSheet stag_sheet;
27 Sprite stag; 31 Sprite stag;
28} GfxAppState; 32} GfxAppState;
@@ -67,11 +71,33 @@ static void shutdown(GfxAppState* state) {
67 // 71 //
68} 72}
69 73
74static vec2 get_camera_movement(R dt) {
75 vec2 offset = {0};
76 if (gfx_app_is_key_pressed(KeyA)) {
77 offset.x -= 1;
78 }
79 if (gfx_app_is_key_pressed(KeyD)) {
80 offset.x += 1;
81 }
82 if (gfx_app_is_key_pressed(KeyW)) {
83 offset.y -= 1;
84 }
85 if (gfx_app_is_key_pressed(KeyS)) {
86 offset.y += 1;
87 }
88 if ((offset.x != 0) || (offset.y != 0)) {
89 offset = vec2_scale(vec2_normalize(offset), dt * CAMERA_SPEED);
90 }
91 return offset;
92}
93
70static void update(GfxAppState* state, double t, double dt) { 94static void update(GfxAppState* state, double t, double dt) {
71 assert(state); 95 assert(state);
72 (void)dt; 96
97 state->camera = vec2_add(state->camera, get_camera_movement((R)dt));
73 98
74 IsoGfx* iso = state->iso; 99 IsoGfx* iso = state->iso;
100 isogfx_set_camera(iso, (int)state->camera.x, (int)state->camera.y);
75 isogfx_update(iso, t); 101 isogfx_update(iso, t);
76} 102}
77 103
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);
102/// Currently this updates the sprite animations. 102/// Currently this updates the sprite animations.
103void isogfx_update(IsoGfx*, double t); 103void isogfx_update(IsoGfx*, double t);
104 104
105/// Set the camera.
106void isogfx_set_camera(IsoGfx*, int x, int y);
107
105/// Render the world. 108/// Render the world.
106void isogfx_render(IsoGfx*); 109void isogfx_render(IsoGfx*);
107 110
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 {
55typedef struct IsoGfx { 55typedef struct IsoGfx {
56 Screen screen; 56 Screen screen;
57 CoordSystem iso_space; 57 CoordSystem iso_space;
58 ivec2 camera;
58 double last_animation_time; 59 double last_animation_time;
59 Tile next_tile; // For procedurally-generated tiles. 60 Tile next_tile; // For procedurally-generated tiles.
60 Tm_Map* map; 61 Tm_Map* map;
@@ -76,6 +77,8 @@ static inline ivec2 ivec2_scale(ivec2 a, int s) {
76 return (ivec2){.x = a.x * s, .y = a.y * s}; 77 return (ivec2){.x = a.x * s, .y = a.y * s};
77} 78}
78 79
80static inline ivec2 ivec2_neg(ivec2 a) { return (ivec2){.x = -a.x, .y = -a.y}; }
81
79static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { 82static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) {
80 return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2), 83 return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2),
81 .y = (iso.x + iso.y) * (t / 2)}; 84 .y = (iso.x + iso.y) * (t / 2)};
@@ -490,13 +493,13 @@ void isogfx_update(IsoGfx* iso, double t) {
490/// Get the screen position of the top diamond-corner of the tile at world 493/// Get the screen position of the top diamond-corner of the tile at world
491/// (x,y). 494/// (x,y).
492static ivec2 GetTileScreenOrigin( 495static ivec2 GetTileScreenOrigin(
493 const CoordSystem iso_space, int world_x, int world_y) { 496 const CoordSystem iso_space, ivec2 camera, int world_x, int world_y) {
494 const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x); 497 const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x);
495 const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y); 498 const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y);
496 const ivec2 screen_origin = 499 const ivec2 screen_origin =
497 ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); 500 ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset));
498 501 const ivec2 origin_view_space = ivec2_add(screen_origin, ivec2_neg(camera));
499 return screen_origin; 502 return origin_view_space;
500} 503}
501 504
502static Pixel alpha_blend(Pixel src, Pixel dst) { 505static Pixel alpha_blend(Pixel src, Pixel dst) {
@@ -598,8 +601,9 @@ static void draw_world(IsoGfx* iso) {
598 // screen-centric approach would juggle multiple tiles throughout the scan. 601 // screen-centric approach would juggle multiple tiles throughout the scan.
599 for (int wy = 0; wy < iso->map->world_height; ++wy) { 602 for (int wy = 0; wy < iso->map->world_height; ++wy) {
600 for (int wx = 0; wx < iso->map->world_width; ++wx) { 603 for (int wx = 0; wx < iso->map->world_width; ++wx) {
601 const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); 604 const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy);
602 const ivec2 screen_origin = GetTileScreenOrigin(iso->iso_space, wx, wy); 605 const ivec2 screen_origin =
606 GetTileScreenOrigin(iso->iso_space, iso->camera, wx, wy);
603 draw_tile(iso, screen_origin, tile); 607 draw_tile(iso, screen_origin, tile);
604 } 608 }
605 } 609 }
@@ -631,11 +635,16 @@ static void draw_sprites(IsoGfx* iso) {
631 assert(sheet); 635 assert(sheet);
632 636
633 const ivec2 screen_origin = GetTileScreenOrigin( 637 const ivec2 screen_origin = GetTileScreenOrigin(
634 iso->iso_space, sprite->position.x, sprite->position.y); 638 iso->iso_space, iso->camera, sprite->position.x, sprite->position.y);
635 draw_sprite(iso, screen_origin, sprite, sheet); 639 draw_sprite(iso, screen_origin, sprite, sheet);
636 } 640 }
637} 641}
638 642
643void isogfx_set_camera(IsoGfx* iso, int x, int y) {
644 assert(iso);
645 iso->camera = (ivec2){x, y};
646}
647
639void isogfx_render(IsoGfx* iso) { 648void isogfx_render(IsoGfx* iso) {
640 assert(iso); 649 assert(iso);
641 draw_world(iso); 650 draw_world(iso);
@@ -649,7 +658,8 @@ void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) {
649 assert(x < iso->map->world_width); 658 assert(x < iso->map->world_width);
650 assert(y < iso->map->world_height); 659 assert(y < iso->map->world_height);
651 660
652 const ivec2 screen_origin = GetTileScreenOrigin(iso->iso_space, x, y); 661 const ivec2 screen_origin =
662 GetTileScreenOrigin(iso->iso_space, iso->camera, x, y);
653 draw_tile(iso, screen_origin, tile); 663 draw_tile(iso, screen_origin, tile);
654} 664}
655 665