diff options
-rw-r--r-- | demos/checkerboard/checkerboard.c | 2 | ||||
-rw-r--r-- | demos/isomap/isomap.c | 6 | ||||
-rw-r--r-- | include/isogfx/gfx2d.h | 19 | ||||
-rw-r--r-- | src/gfx2d.c | 51 |
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. |
111 | void gfx2d_update(Gfx2d*, double t); | 111 | void 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. | ||
118 | void gfx2d_set_camera(Gfx2d*, int x, int y); | ||
119 | |||
120 | /// Render the world. | 113 | /// Render the world. |
121 | void gfx2d_render(Gfx2d*); | 114 | void 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(). |
128 | void gfx2d_draw_tile(Gfx2d*, int x, int y, Tile); | 121 | void 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. | ||
131 | void gfx2d_clip_camera(const Gfx2d*, float* x, float* y); | ||
132 | |||
130 | /// Get the virtual screen's dimensions. | 133 | /// Get the virtual screen's dimensions. |
131 | void gfx2d_get_screen_size(const Gfx2d*, int* width, int* height); | 134 | void 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 | |||
23 | typedef struct ivec2 { | 29 | typedef 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 | ||
766 | void gfx2d_set_camera(Gfx2d* gfx, int x, int y) { | 771 | void gfx2d_render(Gfx2d* gfx, int camera_x, int camera_y) { |
767 | assert(gfx); | ||
768 | gfx->camera = (ivec2){x, y}; | ||
769 | } | ||
770 | |||
771 | void 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 | ||
795 | static 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 | |||
812 | void 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 | |||
792 | void gfx2d_get_screen_size(const Gfx2d* gfx, int* width, int* height) { | 829 | void gfx2d_get_screen_size(const Gfx2d* gfx, int* width, int* height) { |
793 | assert(gfx); | 830 | assert(gfx); |
794 | assert(width); | 831 | assert(width); |