summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--demos/checkerboard/checkerboard.c2
-rw-r--r--demos/isomap/isomap.c6
-rw-r--r--include/isogfx/gfx2d.h19
-rw-r--r--src/gfx2d.c51
4 files changed, 59 insertions, 19 deletions
diff --git a/demos/checkerboard/checkerboard.c b/demos/checkerboard/checkerboard.c
index 243f7a8..f9631d8 100644
--- a/demos/checkerboard/checkerboard.c
+++ b/demos/checkerboard/checkerboard.c
@@ -137,7 +137,7 @@ static void render(const GfxApp* app, GfxAppState* state) {
137 137
138 Gfx2d* iso = state->gfx; 138 Gfx2d* iso = state->gfx;
139 139
140 gfx2d_render(iso); 140 gfx2d_render(iso, 0, 0);
141 141
142 if ((state->xpick != -1) && (state->ypick != -1)) { 142 if ((state->xpick != -1) && (state->ypick != -1)) {
143 gfx2d_draw_tile(iso, state->xpick, state->ypick, state->red); 143 gfx2d_draw_tile(iso, state->xpick, state->ypick, state->red);
diff --git a/demos/isomap/isomap.c b/demos/isomap/isomap.c
index 471ef57..e66d14d 100644
--- a/demos/isomap/isomap.c
+++ b/demos/isomap/isomap.c
@@ -47,7 +47,7 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) {
47 Gfx2d* iso = state->gfx; 47 Gfx2d* iso = state->gfx;
48 48
49 if (!gfx2d_load_map( 49 if (!gfx2d_load_map(
50 iso, "/home/jeanne/Nextcloud/assets/tilemaps/scrabling1.tm")) { 50 iso, "/home/jeanne/Nextcloud/assets/tilemaps/desert1.tm")) {
51 return false; 51 return false;
52 } 52 }
53 53
@@ -100,9 +100,9 @@ static void update(GfxApp* app, GfxAppState* state, double t, double dt) {
100 assert(state); 100 assert(state);
101 101
102 state->camera = vec2_add(state->camera, get_camera_movement(app, (R)dt)); 102 state->camera = vec2_add(state->camera, get_camera_movement(app, (R)dt));
103 gfx2d_clip_camera(state->gfx, &state->camera.x, &state->camera.y);
103 104
104 Gfx2d* iso = state->gfx; 105 Gfx2d* iso = state->gfx;
105 gfx2d_set_camera(iso, (int)state->camera.x, (int)state->camera.y);
106 gfx2d_update(iso, t); 106 gfx2d_update(iso, t);
107} 107}
108 108
@@ -111,7 +111,7 @@ static void render(const GfxApp* app, GfxAppState* state) {
111 assert(state); 111 assert(state);
112 112
113 Gfx2d* iso = state->gfx; 113 Gfx2d* iso = state->gfx;
114 gfx2d_render(iso); 114 gfx2d_render(iso, (int)state->camera.x, (int)state->camera.y);
115 gfx2d_backend_render(state->backend, iso); 115 gfx2d_backend_render(state->backend, iso);
116} 116}
117 117
diff --git a/include/isogfx/gfx2d.h b/include/isogfx/gfx2d.h
index a3ddbb6..33a4591 100644
--- a/include/isogfx/gfx2d.h
+++ b/include/isogfx/gfx2d.h
@@ -110,15 +110,8 @@ void gfx2d_set_sprite_animation(Gfx2d*, Sprite, int animation);
110/// Currently, this updates the sprite animations. 110/// Currently, this updates the sprite animations.
111void gfx2d_update(Gfx2d*, double t); 111void gfx2d_update(Gfx2d*, double t);
112 112
113// TODO: Do we really need to store the camera in the library? It's not used
114// for anything other than to render, so we could remove library state and
115// take a camera argument in render() instead.
116
117/// Set the camera.
118void gfx2d_set_camera(Gfx2d*, int x, int y);
119
120/// Render the world. 113/// Render the world.
121void gfx2d_render(Gfx2d*); 114void gfx2d_render(Gfx2d*, int camera_x, int camera_y);
122 115
123/// Draw/overlay a tile at position (x,y). 116/// Draw/overlay a tile at position (x,y).
124/// 117///
@@ -127,6 +120,16 @@ void gfx2d_render(Gfx2d*);
127/// position (x,y) instead, use gfx2d_set_tile(). 120/// position (x,y) instead, use gfx2d_set_tile().
128void gfx2d_draw_tile(Gfx2d*, int x, int y, Tile); 121void gfx2d_draw_tile(Gfx2d*, int x, int y, Tile);
129 122
123/// Clip camera coordinates to the loaded map.
124///
125/// This is useful for implementing camera movement, in which you typically
126/// want the camera to stay within the map's bounds.
127///
128/// (x,y) are the top-left coordinates of the camera.
129///
130/// A map must have previously been loaded.
131void gfx2d_clip_camera(const Gfx2d*, float* x, float* y);
132
130/// Get the virtual screen's dimensions. 133/// Get the virtual screen's dimensions.
131void gfx2d_get_screen_size(const Gfx2d*, int* width, int* height); 134void gfx2d_get_screen_size(const Gfx2d*, int* width, int* height);
132 135
diff --git a/src/gfx2d.c b/src/gfx2d.c
index f609c98..f1f26cb 100644
--- a/src/gfx2d.c
+++ b/src/gfx2d.c
@@ -20,6 +20,12 @@
20/// Time between animation updates. 20/// Time between animation updates.
21#define ANIMATION_UPDATE_DELTA (1.0 / ANIMATION_FPS) 21#define ANIMATION_UPDATE_DELTA (1.0 / ANIMATION_FPS)
22 22
23/// Take the maximum of two values.
24#define max(a, b) ((a) > (b) ? (a) : (b))
25
26/// Take the minimum of two values.
27#define min(a, b) ((a) < (b) ? (a) : (b))
28
23typedef struct ivec2 { 29typedef struct ivec2 {
24 int x, y; 30 int x, y;
25} ivec2; 31} ivec2;
@@ -565,7 +571,6 @@ static void draw_rect(
565 571
566 // Rect origin can be outside screen bounds, so we must offset accordingly to 572 // Rect origin can be outside screen bounds, so we must offset accordingly to
567 // draw only the visible portion. 573 // draw only the visible portion.
568#define max(a, b) (a > b ? a : b)
569 const int px_offset = max(0, -top_left.x); 574 const int px_offset = max(0, -top_left.x);
570 const int py_offset = max(0, -top_left.y); 575 const int py_offset = max(0, -top_left.y);
571 576
@@ -763,13 +768,11 @@ static void draw_sprites(Gfx2d* gfx) {
763 } 768 }
764} 769}
765 770
766void gfx2d_set_camera(Gfx2d* gfx, int x, int y) { 771void gfx2d_render(Gfx2d* gfx, int camera_x, int camera_y) {
767 assert(gfx);
768 gfx->camera = (ivec2){x, y};
769}
770
771void gfx2d_render(Gfx2d* gfx) {
772 assert(gfx); 772 assert(gfx);
773 // Storing the camera mostly for debugging convenience. It could otherwise be
774 // passed around.
775 gfx->camera = (ivec2){camera_x, camera_y};
773 draw_map(gfx); 776 draw_map(gfx);
774 draw_sprites(gfx); 777 draw_sprites(gfx);
775} 778}
@@ -789,6 +792,40 @@ void gfx2d_draw_tile(Gfx2d* gfx, int x, int y, Tile tile) {
789 } 792 }
790} 793}
791 794
795static void clip_camera_ortho(const Gfx2d* gfx, float* x, float* y) {
796 assert(gfx);
797 assert(gfx->map);
798
799 if (x != nullptr) {
800 const int width_pixels = gfx->map->world_width * gfx->map->base_tile_width;
801 const int x_max = width_pixels - gfx->screen.width;
802 *x = min((float)x_max, max(0.F, *x));
803 }
804 if (y != nullptr) {
805 const int height_pixels =
806 gfx->map->world_height * gfx->map->base_tile_height;
807 const int y_max = height_pixels - gfx->screen.height;
808 *y = min((float)y_max, max(0.F, *y));
809 }
810}
811
812void gfx2d_clip_camera(const Gfx2d* gfx, float* x, float* y) {
813 assert(gfx);
814 assert(gfx->map);
815 assert(x);
816 assert(y);
817
818 const Tm_Flags* flags = (const Tm_Flags*)&gfx->map->flags;
819 switch (flags->orientation) {
820 case Tm_Orthogonal:
821 clip_camera_ortho(gfx, x, y);
822 break;
823 case Tm_Isometric:
824 // TODO: Clip camera in isometric maps.
825 break;
826 }
827}
828
792void gfx2d_get_screen_size(const Gfx2d* gfx, int* width, int* height) { 829void gfx2d_get_screen_size(const Gfx2d* gfx, int* width, int* height) {
793 assert(gfx); 830 assert(gfx);
794 assert(width); 831 assert(width);