summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--demos/checkerboard/checkerboard.c62
-rw-r--r--demos/isomap/isomap.c50
-rw-r--r--include/isogfx/backend.h29
-rw-r--r--include/isogfx/gfx2d.h54
-rw-r--r--src/backend.c28
-rw-r--r--src/gfx2d.c381
6 files changed, 303 insertions, 301 deletions
diff --git a/demos/checkerboard/checkerboard.c b/demos/checkerboard/checkerboard.c
index 4f43526..467da61 100644
--- a/demos/checkerboard/checkerboard.c
+++ b/demos/checkerboard/checkerboard.c
@@ -47,21 +47,21 @@ typedef enum Colour {
47} Colour; 47} Colour;
48 48
49typedef struct GfxAppState { 49typedef struct GfxAppState {
50 IsoBackend* backend; 50 Gfx2dBackend* backend;
51 IsoGfx* iso; 51 Gfx2d* gfx;
52 Tile red; 52 Tile red;
53 int xpick; 53 int xpick;
54 int ypick; 54 int ypick;
55} GfxAppState; 55} GfxAppState;
56 56
57static void make_checkerboard(IsoGfx* iso, Tile black, Tile white) { 57static void make_checkerboard(Gfx2d* iso, Tile black, Tile white) {
58 assert(iso); 58 assert(iso);
59 for (int y = 0; y < isogfx_world_height(iso); ++y) { 59 for (int y = 0; y < gfx2d_world_height(iso); ++y) {
60 for (int x = 0; x < isogfx_world_width(iso); ++x) { 60 for (int x = 0; x < gfx2d_world_width(iso); ++x) {
61 const int odd_col = x & 1; 61 const int odd_col = x & 1;
62 const int odd_row = y & 1; 62 const int odd_row = y & 1;
63 const Tile value = (odd_row ^ odd_col) == 0 ? black : white; 63 const Tile value = (odd_row ^ odd_col) == 0 ? black : white;
64 isogfx_set_tile(iso, x, y, value); 64 gfx2d_set_tile(iso, x, y, value);
65 } 65 }
66 } 66 }
67} 67}
@@ -72,28 +72,28 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) {
72 (void)argc; 72 (void)argc;
73 (void)argv; 73 (void)argv;
74 74
75 if (!((state->iso = 75 if (!((state->gfx =
76 isogfx_new(&(IsoGfxDesc){.memory = MEMORY, 76 gfx2d_new(&(Gfx2dDesc){.memory = MEMORY,
77 .memory_size = MEMORY_SIZE, 77 .memory_size = MEMORY_SIZE,
78 .screen_width = SCREEN_WIDTH, 78 .screen_width = SCREEN_WIDTH,
79 .screen_height = SCREEN_HEIGHT})))) { 79 .screen_height = SCREEN_HEIGHT})))) {
80 return false; 80 return false;
81 } 81 }
82 IsoGfx* iso = state->iso; 82 Gfx2d* iso = state->gfx;
83 83
84 isogfx_make_map( 84 gfx2d_make_map(
85 iso, &(MapDesc){.tile_width = TILE_WIDTH, 85 iso, &(MapDesc){.tile_width = TILE_WIDTH,
86 .tile_height = TILE_HEIGHT, 86 .tile_height = TILE_HEIGHT,
87 .world_width = WORLD_WIDTH, 87 .world_width = WORLD_WIDTH,
88 .world_height = WORLD_HEIGHT, 88 .world_height = WORLD_HEIGHT,
89 .num_tiles = NUM_TILES}); 89 .num_tiles = NUM_TILES});
90 90
91 const Tile black = isogfx_make_tile(iso, &tile_set[Black]); 91 const Tile black = gfx2d_make_tile(iso, &tile_set[Black]);
92 const Tile white = isogfx_make_tile(iso, &tile_set[White]); 92 const Tile white = gfx2d_make_tile(iso, &tile_set[White]);
93 state->red = isogfx_make_tile(iso, &tile_set[Red]); 93 state->red = gfx2d_make_tile(iso, &tile_set[Red]);
94 make_checkerboard(iso, black, white); 94 make_checkerboard(iso, black, white);
95 95
96 if (!((state->backend = iso_backend_init(iso)))) { 96 if (!((state->backend = gfx2d_backend_init(iso)))) {
97 return false; 97 return false;
98 } 98 }
99 99
@@ -104,8 +104,8 @@ static void shutdown(GfxApp* app, GfxAppState* state) {
104 assert(app); 104 assert(app);
105 assert(state); 105 assert(state);
106 106
107 iso_backend_shutdown(&state->backend); 107 gfx2d_backend_shutdown(&state->backend);
108 isogfx_del(&state->iso); 108 gfx2d_del(&state->gfx);
109} 109}
110 110
111static void update(GfxApp* app, GfxAppState* state, double t, double dt) { 111static void update(GfxApp* app, GfxAppState* state, double t, double dt) {
@@ -113,19 +113,19 @@ static void update(GfxApp* app, GfxAppState* state, double t, double dt) {
113 assert(state); 113 assert(state);
114 (void)dt; 114 (void)dt;
115 115
116 IsoGfx* iso = state->iso; 116 Gfx2d* iso = state->gfx;
117 117
118 isogfx_update(iso, t); 118 gfx2d_update(iso, t);
119 119
120 // Get mouse position in window coordinates. 120 // Get mouse position in window coordinates.
121 double mouse_x, mouse_y; 121 double mouse_x, mouse_y;
122 gfx_app_get_mouse_position(app, &mouse_x, &mouse_y); 122 gfx_app_get_mouse_position(app, &mouse_x, &mouse_y);
123 123
124 // Map from window coordinates to virtual screen coordinates. 124 // Map from window coordinates to virtual screen coordinates.
125 iso_backend_get_mouse_position( 125 gfx2d_backend_get_mouse_position(
126 state->backend, mouse_x, mouse_y, &mouse_x, &mouse_y); 126 state->backend, mouse_x, mouse_y, &mouse_x, &mouse_y);
127 127
128 isogfx_pick_tile(iso, mouse_x, mouse_y, &state->xpick, &state->ypick); 128 gfx2d_pick_tile(iso, mouse_x, mouse_y, &state->xpick, &state->ypick);
129 129
130 printf("Picked tile: (%d, %d)\n", state->xpick, state->ypick); 130 printf("Picked tile: (%d, %d)\n", state->xpick, state->ypick);
131} 131}
@@ -134,22 +134,22 @@ static void render(const GfxApp* app, GfxAppState* state) {
134 assert(app); 134 assert(app);
135 assert(state); 135 assert(state);
136 136
137 IsoGfx* iso = state->iso; 137 Gfx2d* iso = state->gfx;
138 138
139 isogfx_render(iso); 139 gfx2d_render(iso);
140 140
141 if ((state->xpick != -1) && (state->ypick != -1)) { 141 if ((state->xpick != -1) && (state->ypick != -1)) {
142 isogfx_draw_tile(iso, state->xpick, state->ypick, state->red); 142 gfx2d_draw_tile(iso, state->xpick, state->ypick, state->red);
143 } 143 }
144 144
145 iso_backend_render(state->backend, iso); 145 gfx2d_backend_render(state->backend, iso);
146} 146}
147 147
148static void resize(GfxApp* app, GfxAppState* state, int width, int height) { 148static void resize(GfxApp* app, GfxAppState* state, int width, int height) {
149 assert(app); 149 assert(app);
150 assert(state); 150 assert(state);
151 151
152 iso_backend_resize_window(state->backend, state->iso, width, height); 152 gfx2d_backend_resize_window(state->backend, state->gfx, width, height);
153} 153}
154 154
155int main(int argc, const char** argv) { 155int main(int argc, const char** argv) {
diff --git a/demos/isomap/isomap.c b/demos/isomap/isomap.c
index bca27f6..471ef57 100644
--- a/demos/isomap/isomap.c
+++ b/demos/isomap/isomap.c
@@ -22,13 +22,13 @@ static const R CAMERA_SPEED = 800;
22uint8_t MEMORY[MEMORY_SIZE]; 22uint8_t MEMORY[MEMORY_SIZE];
23 23
24typedef struct GfxAppState { 24typedef struct GfxAppState {
25 IsoBackend* backend; 25 Gfx2dBackend* backend;
26 IsoGfx* iso; 26 Gfx2d* gfx;
27 int xpick; 27 int xpick;
28 int ypick; 28 int ypick;
29 vec2 camera; 29 vec2 camera;
30 SpriteSheet stag_sheet; 30 SpriteSheet stag_sheet;
31 Sprite stag; 31 Sprite stag;
32} GfxAppState; 32} GfxAppState;
33 33
34static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) { 34static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) {
@@ -37,31 +37,31 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) {
37 (void)argc; 37 (void)argc;
38 (void)argv; 38 (void)argv;
39 39
40 if (!((state->iso = 40 if (!((state->gfx =
41 isogfx_new(&(IsoGfxDesc){.memory = MEMORY, 41 gfx2d_new(&(Gfx2dDesc){.memory = MEMORY,
42 .memory_size = MEMORY_SIZE, 42 .memory_size = MEMORY_SIZE,
43 .screen_width = SCREEN_WIDTH, 43 .screen_width = SCREEN_WIDTH,
44 .screen_height = SCREEN_HEIGHT})))) { 44 .screen_height = SCREEN_HEIGHT})))) {
45 return false; 45 return false;
46 } 46 }
47 IsoGfx* iso = state->iso; 47 Gfx2d* iso = state->gfx;
48 48
49 if (!isogfx_load_map( 49 if (!gfx2d_load_map(
50 iso, "/home/jeanne/Nextcloud/assets/tilemaps/scrabling1.tm")) { 50 iso, "/home/jeanne/Nextcloud/assets/tilemaps/scrabling1.tm")) {
51 return false; 51 return false;
52 } 52 }
53 53
54 if (!((state->stag_sheet = isogfx_load_sprite_sheet( 54 if (!((state->stag_sheet = gfx2d_load_sprite_sheet(
55 iso, 55 iso,
56 "/home/jeanne/Nextcloud/assets/tilesets/scrabling/critters/stag/" 56 "/home/jeanne/Nextcloud/assets/tilesets/scrabling/critters/stag/"
57 "stag.ss")))) { 57 "stag.ss")))) {
58 return false; 58 return false;
59 } 59 }
60 60
61 state->stag = isogfx_make_sprite(iso, state->stag_sheet); 61 state->stag = gfx2d_make_sprite(iso, state->stag_sheet);
62 isogfx_set_sprite_position(iso, state->stag, 0, 0); 62 gfx2d_set_sprite_position(iso, state->stag, 0, 0);
63 63
64 if (!((state->backend = iso_backend_init(iso)))) { 64 if (!((state->backend = gfx2d_backend_init(iso)))) {
65 return false; 65 return false;
66 } 66 }
67 67
@@ -101,25 +101,25 @@ static void update(GfxApp* app, GfxAppState* state, double t, double dt) {
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 103
104 IsoGfx* iso = state->iso; 104 Gfx2d* iso = state->gfx;
105 isogfx_set_camera(iso, (int)state->camera.x, (int)state->camera.y); 105 gfx2d_set_camera(iso, (int)state->camera.x, (int)state->camera.y);
106 isogfx_update(iso, t); 106 gfx2d_update(iso, t);
107} 107}
108 108
109static void render(const GfxApp* app, GfxAppState* state) { 109static void render(const GfxApp* app, GfxAppState* state) {
110 assert(app); 110 assert(app);
111 assert(state); 111 assert(state);
112 112
113 IsoGfx* iso = state->iso; 113 Gfx2d* iso = state->gfx;
114 isogfx_render(iso); 114 gfx2d_render(iso);
115 iso_backend_render(state->backend, iso); 115 gfx2d_backend_render(state->backend, iso);
116} 116}
117 117
118static void resize(GfxApp* app, GfxAppState* state, int width, int height) { 118static void resize(GfxApp* app, GfxAppState* state, int width, int height) {
119 assert(app); 119 assert(app);
120 assert(state); 120 assert(state);
121 121
122 iso_backend_resize_window(state->backend, state->iso, width, height); 122 gfx2d_backend_resize_window(state->backend, state->gfx, width, height);
123} 123}
124 124
125int main(int argc, const char** argv) { 125int main(int argc, const char** argv) {
diff --git a/include/isogfx/backend.h b/include/isogfx/backend.h
index 76ee13d..86afed5 100644
--- a/include/isogfx/backend.h
+++ b/include/isogfx/backend.h
@@ -2,28 +2,29 @@
2 2
3#include <stdbool.h> 3#include <stdbool.h>
4 4
5typedef struct Gfx Gfx; 5typedef struct Gfx Gfx;
6typedef struct IsoGfx IsoGfx; 6typedef struct Gfx2d Gfx2d;
7 7
8typedef struct IsoBackend IsoBackend; 8typedef struct Gfx2dBackend Gfx2dBackend;
9 9
10/// Initialize the backend. 10/// Initialize the backend.
11IsoBackend* iso_backend_init(const IsoGfx*); 11Gfx2dBackend* gfx2d_backend_init(const Gfx2d*);
12 12
13/// Shut down the backend. 13/// Shut down the backend.
14void iso_backend_shutdown(IsoBackend**); 14void gfx2d_backend_shutdown(Gfx2dBackend**);
15 15
16/// Notify the backend of a window resize event. 16/// Notify the backend of a window resize event.
17/// This allows the backend to determine how to position and scale the iso 17/// This allows the backend to determine how to position and scale the gfx
18/// screen buffer on the graphics window. 18/// screen buffer on the graphics window.
19void iso_backend_resize_window( 19void gfx2d_backend_resize_window(
20 IsoBackend*, const IsoGfx*, int width, int height); 20 Gfx2dBackend*, const Gfx2d*, int width, int height);
21 21
22/// Render the iso screen to the graphics window. 22/// Render the gfx screen to the graphics window.
23void iso_backend_render(const IsoBackend*, const IsoGfx*); 23void gfx2d_backend_render(const Gfx2dBackend*, const Gfx2d*);
24 24
25/// Map window coordinates to iso space coordinates. 25/// Map window coordinates to gfx space coordinates.
26/// This takes into account any possible resizing done by the backend in 26/// This takes into account any possible resizing done by the backend in
27/// response to calls to iso_backend_resize_window(). 27/// response to calls to gfx2d_backend_resize_window().
28bool iso_backend_get_mouse_position( 28bool gfx2d_backend_get_mouse_position(
29 const IsoBackend*, double window_x, double window_y, double* x, double* y); 29 const Gfx2dBackend*, double window_x, double window_y, double* x,
30 double* y);
diff --git a/include/isogfx/gfx2d.h b/include/isogfx/gfx2d.h
index 323b389..59566f3 100644
--- a/include/isogfx/gfx2d.h
+++ b/include/isogfx/gfx2d.h
@@ -8,7 +8,7 @@
8#include <stddef.h> 8#include <stddef.h>
9#include <stdint.h> 9#include <stdint.h>
10 10
11typedef struct IsoGfx IsoGfx; 11typedef struct Gfx2d Gfx2d;
12 12
13/// Sprite sheet handle. 13/// Sprite sheet handle.
14typedef uintptr_t SpriteSheet; 14typedef uintptr_t SpriteSheet;
@@ -50,43 +50,43 @@ typedef struct IsoGfxDesc {
50 size_t memory_size; // Size of memory block in bytes. 50 size_t memory_size; // Size of memory block in bytes.
51 int screen_width; // Screen width in pixels. 51 int screen_width; // Screen width in pixels.
52 int screen_height; // Screen height in pixels. 52 int screen_height; // Screen height in pixels.
53} IsoGfxDesc; 53} Gfx2dDesc;
54 54
55/// Create a new isometric graphics engine. 55/// Create a new isometric graphics engine.
56IsoGfx* isogfx_new(const IsoGfxDesc*); 56Gfx2d* gfx2d_new(const Gfx2dDesc*);
57 57
58/// Destroy the isometric graphics engine. 58/// Destroy the isometric graphics engine.
59void isogfx_del(IsoGfx**); 59void gfx2d_del(Gfx2d**);
60 60
61/// Clear all loaded worlds and sprites. 61/// Clear all loaded worlds and sprites.
62void isogfx_clear(IsoGfx*); 62void gfx2d_clear(Gfx2d*);
63 63
64/// Create an empty map. 64/// Create an empty map.
65void isogfx_make_map(IsoGfx*, const MapDesc*); 65void gfx2d_make_map(Gfx2d*, const MapDesc*);
66 66
67/// Load a tile map (.TM) file. 67/// Load a tile map (.TM) file.
68bool isogfx_load_map(IsoGfx*, const char* filepath); 68bool gfx2d_load_map(Gfx2d*, const char* filepath);
69 69
70/// Return the world's width. 70/// Return the world's width.
71int isogfx_world_width(const IsoGfx*); 71int gfx2d_world_width(const Gfx2d*);
72 72
73/// Return the world's height. 73/// Return the world's height.
74int isogfx_world_height(const IsoGfx*); 74int gfx2d_world_height(const Gfx2d*);
75 75
76/// Create a new tile. 76/// Create a new tile.
77Tile isogfx_make_tile(IsoGfx*, const TileDesc*); 77Tile gfx2d_make_tile(Gfx2d*, const TileDesc*);
78 78
79/// Set the tile at position (x,y). 79/// Set the tile at position (x,y).
80void isogfx_set_tile(IsoGfx*, int x, int y, Tile); 80void gfx2d_set_tile(Gfx2d*, int x, int y, Tile);
81 81
82/// Set the tiles in positions in the range (x0,y0) - (x1,y1). 82/// Set the tiles in positions in the range (x0,y0) - (x1,y1).
83void isogfx_set_tiles(IsoGfx*, int x0, int y0, int x1, int y1, Tile); 83void gfx2d_set_tiles(Gfx2d*, int x0, int y0, int x1, int y1, Tile);
84 84
85/// Load a sprite sheet (.SS) file. 85/// Load a sprite sheet (.SS) file.
86SpriteSheet isogfx_load_sprite_sheet(IsoGfx*, const char* filepath); 86SpriteSheet gfx2d_load_sprite_sheet(Gfx2d*, const char* filepath);
87 87
88/// Create an animated sprite. 88/// Create an animated sprite.
89Sprite isogfx_make_sprite(IsoGfx*, SpriteSheet); 89Sprite gfx2d_make_sprite(Gfx2d*, SpriteSheet);
90 90
91// TODO: Add a function to delete a sprite. Making the caller manage and re-use 91// TODO: Add a function to delete a sprite. Making the caller manage and re-use
92// sprites is a shitty API. 92// sprites is a shitty API.
@@ -94,41 +94,41 @@ Sprite isogfx_make_sprite(IsoGfx*, SpriteSheet);
94// list of sprites so that we can re-use the ones that have been "freed". 94// list of sprites so that we can re-use the ones that have been "freed".
95 95
96/// Set the sprite's position. 96/// Set the sprite's position.
97void isogfx_set_sprite_position(IsoGfx*, Sprite, int x, int y); 97void gfx2d_set_sprite_position(Gfx2d*, Sprite, int x, int y);
98 98
99/// Set the sprite's current animation. 99/// Set the sprite's current animation.
100void isogfx_set_sprite_animation(IsoGfx*, Sprite, int animation); 100void gfx2d_set_sprite_animation(Gfx2d*, Sprite, int animation);
101 101
102/// Update the renderer. 102/// Update the renderer.
103/// 103///
104/// Currently, this updates the sprite animations. 104/// Currently, this updates the sprite animations.
105void isogfx_update(IsoGfx*, double t); 105void gfx2d_update(Gfx2d*, double t);
106 106
107// TODO: Do we really need to store the camera in the library? It's not used 107// TODO: Do we really need to store the camera in the library? It's not used
108// for anything other than to render, so we could remove library state and 108// for anything other than to render, so we could remove library state and
109// take a camera argument in render() instead. 109// take a camera argument in render() instead.
110 110
111/// Set the camera. 111/// Set the camera.
112void isogfx_set_camera(IsoGfx*, int x, int y); 112void gfx2d_set_camera(Gfx2d*, int x, int y);
113 113
114/// Render the world. 114/// Render the world.
115void isogfx_render(IsoGfx*); 115void gfx2d_render(Gfx2d*);
116 116
117/// Draw/overlay a tile at position (x,y). 117/// Draw/overlay a tile at position (x,y).
118/// 118///
119/// This function just renders a tile at position (x,y) and should be called 119/// This function just renders a tile at position (x,y) and should be called
120/// after isogfx_render() to obtain the correct result. To set the tile at 120/// after gfx2d_render() to obtain the correct result. To set the tile at
121/// position (x,y) instead, use isogfx_set_tile(). 121/// position (x,y) instead, use gfx2d_set_tile().
122void isogfx_draw_tile(IsoGfx*, int x, int y, Tile); 122void gfx2d_draw_tile(Gfx2d*, int x, int y, Tile);
123 123
124/// Get the virtual screen's dimensions. 124/// Get the virtual screen's dimensions.
125void isogfx_get_screen_size(const IsoGfx*, int* width, int* height); 125void gfx2d_get_screen_size(const Gfx2d*, int* width, int* height);
126 126
127/// Return a pointer to the virtual screen's colour buffer. 127/// Return a pointer to the virtual screen's colour buffer.
128/// 128///
129/// Call after each call to isogfx_render() to retrieve the render output. 129/// Call after each call to gfx2d_render() to retrieve the render output.
130const Pixel* isogfx_get_screen_buffer(const IsoGfx*); 130const Pixel* gfx2d_get_screen_buffer(const Gfx2d*);
131 131
132/// Translate Cartesian to isometric coordinates. 132/// Translate Cartesian to isometric coordinates.
133void isogfx_pick_tile( 133void gfx2d_pick_tile(
134 const IsoGfx*, double xcart, double ycart, int* xiso, int* yiso); 134 const Gfx2d*, double xcart, double ycart, int* xiso, int* yiso);
diff --git a/src/backend.c b/src/backend.c
index 80c5974..4bb3592 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -13,7 +13,7 @@
13#include <assert.h> 13#include <assert.h>
14#include <stdlib.h> 14#include <stdlib.h>
15 15
16typedef struct IsoBackend { 16typedef struct Gfx2dBackend {
17 Gfx* gfx; 17 Gfx* gfx;
18 Mesh* quad_mesh; 18 Mesh* quad_mesh;
19 /// The screen or "iso screen" refers to the colour buffer of the iso graphics 19 /// The screen or "iso screen" refers to the colour buffer of the iso graphics
@@ -29,12 +29,12 @@ typedef struct IsoBackend {
29 int viewport_x, viewport_y, viewport_width, viewport_height; 29 int viewport_x, viewport_y, viewport_width, viewport_height;
30 double stretch; // Stretch factor from iso screen dimensions to viewport 30 double stretch; // Stretch factor from iso screen dimensions to viewport
31 // dimensions. 31 // dimensions.
32} IsoBackend; 32} Gfx2dBackend;
33 33
34IsoBackend* iso_backend_init(const IsoGfx* iso) { 34Gfx2dBackend* gfx2d_backend_init(const Gfx2d* iso) {
35 assert(iso); 35 assert(iso);
36 36
37 IsoBackend* backend = calloc(1, sizeof(IsoBackend)); 37 Gfx2dBackend* backend = calloc(1, sizeof(Gfx2dBackend));
38 if (!backend) { 38 if (!backend) {
39 return nullptr; 39 return nullptr;
40 } 40 }
@@ -45,7 +45,7 @@ IsoBackend* iso_backend_init(const IsoGfx* iso) {
45 GfxCore* gfxcore = gfx_get_core(backend->gfx); 45 GfxCore* gfxcore = gfx_get_core(backend->gfx);
46 46
47 int screen_width, screen_height; 47 int screen_width, screen_height;
48 isogfx_get_screen_size(iso, &screen_width, &screen_height); 48 gfx2d_get_screen_size(iso, &screen_width, &screen_height);
49 49
50 if (!((backend->screen_texture = gfx_make_texture( 50 if (!((backend->screen_texture = gfx_make_texture(
51 gfxcore, &(TextureDesc){.width = screen_width, 51 gfxcore, &(TextureDesc){.width = screen_width,
@@ -95,10 +95,10 @@ cleanup:
95 return nullptr; 95 return nullptr;
96} 96}
97 97
98void iso_backend_shutdown(IsoBackend** ppApp) { 98void gfx2d_backend_shutdown(Gfx2dBackend** ppApp) {
99 assert(ppApp); 99 assert(ppApp);
100 100
101 IsoBackend* app = *ppApp; 101 Gfx2dBackend* app = *ppApp;
102 if (!app) { 102 if (!app) {
103 return; 103 return;
104 } 104 }
@@ -106,8 +106,8 @@ void iso_backend_shutdown(IsoBackend** ppApp) {
106 gfx_destroy(&app->gfx); 106 gfx_destroy(&app->gfx);
107} 107}
108 108
109void iso_backend_resize_window( 109void gfx2d_backend_resize_window(
110 IsoBackend* app, const IsoGfx* iso, int width, int height) { 110 Gfx2dBackend* app, const Gfx2d* iso, int width, int height) {
111 assert(app); 111 assert(app);
112 assert(iso); 112 assert(iso);
113 113
@@ -116,7 +116,7 @@ void iso_backend_resize_window(
116 116
117 // Virtual screen dimensions. 117 // Virtual screen dimensions.
118 int screen_width, screen_height; 118 int screen_width, screen_height;
119 isogfx_get_screen_size(iso, &screen_width, &screen_height); 119 gfx2d_get_screen_size(iso, &screen_width, &screen_height);
120 120
121 // Stretch the virtual screen onto the viewport while respecting the screen's 121 // Stretch the virtual screen onto the viewport while respecting the screen's
122 // aspect ratio to prevent distortion. 122 // aspect ratio to prevent distortion.
@@ -135,11 +135,11 @@ void iso_backend_resize_window(
135 } 135 }
136} 136}
137 137
138void iso_backend_render(const IsoBackend* app, const IsoGfx* iso) { 138void gfx2d_backend_render(const Gfx2dBackend* app, const Gfx2d* iso) {
139 assert(app); 139 assert(app);
140 assert(iso); 140 assert(iso);
141 141
142 const Pixel* screen = isogfx_get_screen_buffer(iso); 142 const Pixel* screen = gfx2d_get_screen_buffer(iso);
143 assert(screen); 143 assert(screen);
144 gfx_update_texture(app->screen_texture, &(TextureDataDesc){.pixels = screen}); 144 gfx_update_texture(app->screen_texture, &(TextureDataDesc){.pixels = screen});
145 145
@@ -162,8 +162,8 @@ void iso_backend_render(const IsoBackend* app, const IsoGfx* iso) {
162 gfx_end_frame(gfxcore); 162 gfx_end_frame(gfxcore);
163} 163}
164 164
165bool iso_backend_get_mouse_position( 165bool gfx2d_backend_get_mouse_position(
166 const IsoBackend* app, double window_x, double window_y, double* x, 166 const Gfx2dBackend* app, double window_x, double window_y, double* x,
167 double* y) { 167 double* y) {
168 assert(app); 168 assert(app);
169 169
diff --git a/src/gfx2d.c b/src/gfx2d.c
index 698e32c..266a5f7 100644
--- a/src/gfx2d.c
+++ b/src/gfx2d.c
@@ -32,11 +32,11 @@ typedef struct vec2 {
32// Renderer state. 32// Renderer state.
33// ----------------------------------------------------------------------------- 33// -----------------------------------------------------------------------------
34 34
35typedef struct CoordSystem { 35typedef struct IsoCoordSystem {
36 ivec2 o; // Origin. 36 ivec2 o; // Origin.
37 ivec2 x; 37 ivec2 x;
38 ivec2 y; 38 ivec2 y;
39} CoordSystem; 39} IsoCoordSystem;
40 40
41typedef struct Screen { 41typedef struct Screen {
42 int width; 42 int width;
@@ -52,9 +52,9 @@ typedef struct SpriteInstance {
52 int frame; // Current frame of animation. 52 int frame; // Current frame of animation.
53} SpriteInstance; 53} SpriteInstance;
54 54
55typedef struct IsoGfx { 55typedef struct Gfx2d {
56 Screen screen; 56 Screen screen;
57 CoordSystem iso_space; 57 IsoCoordSystem iso_space;
58 ivec2 camera; 58 ivec2 camera;
59 double last_animation_time; 59 double last_animation_time;
60 Tile next_tile; // For procedurally-generated tiles. 60 Tile next_tile; // For procedurally-generated tiles.
@@ -63,7 +63,7 @@ typedef struct IsoGfx {
63 SpriteInstance* head_sprite; // Head of sprites list. 63 SpriteInstance* head_sprite; // Head of sprites list.
64 memstack stack; 64 memstack stack;
65 size_t watermark; 65 size_t watermark;
66} IsoGfx; 66} Gfx2d;
67 67
68// ----------------------------------------------------------------------------- 68// -----------------------------------------------------------------------------
69// Math and world / tile / screen access. 69// Math and world / tile / screen access.
@@ -102,7 +102,7 @@ static ivec2 map2screen(
102 102
103/// Create the basis for the isometric coordinate system with origin and vectors 103/// Create the basis for the isometric coordinate system with origin and vectors
104/// expressed in the Cartesian system. 104/// expressed in the Cartesian system.
105static CoordSystem make_iso_coord_system( 105static IsoCoordSystem make_iso_coord_system(
106 const Tm_Map* const map, const Screen* const screen) { 106 const Tm_Map* const map, const Screen* const screen) {
107 assert(map); 107 assert(map);
108 assert(screen); 108 assert(screen);
@@ -111,7 +111,7 @@ static CoordSystem make_iso_coord_system(
111 .x = map->base_tile_width / 2, .y = map->base_tile_height / 2}; 111 .x = map->base_tile_width / 2, .y = map->base_tile_height / 2};
112 const ivec2 y = { 112 const ivec2 y = {
113 .x = -map->base_tile_width / 2, .y = map->base_tile_height / 2}; 113 .x = -map->base_tile_width / 2, .y = map->base_tile_height / 2};
114 return (CoordSystem){o, x, y}; 114 return (IsoCoordSystem){o, x, y};
115} 115}
116 116
117/// Map isometric coordinates to Cartesian coordinates. 117/// Map isometric coordinates to Cartesian coordinates.
@@ -121,7 +121,7 @@ static CoordSystem make_iso_coord_system(
121/// 121///
122/// Takes the camera displacement into account. 122/// Takes the camera displacement into account.
123static ivec2 iso2cart( 123static ivec2 iso2cart(
124 const CoordSystem iso_space, ivec2 camera, int iso_x, int iso_y) { 124 const IsoCoordSystem iso_space, ivec2 camera, int iso_x, int iso_y) {
125 const ivec2 vx_offset = ivec2_scale(iso_space.x, iso_x); 125 const ivec2 vx_offset = ivec2_scale(iso_space.x, iso_x);
126 const ivec2 vy_offset = ivec2_scale(iso_space.y, iso_y); 126 const ivec2 vy_offset = ivec2_scale(iso_space.y, iso_y);
127 const ivec2 origin_world_space = 127 const ivec2 origin_world_space =
@@ -170,63 +170,63 @@ static inline Pixel* screen_xy_mut(Screen* screen, int x, int y) {
170// Renderer, world and tile management. 170// Renderer, world and tile management.
171// ----------------------------------------------------------------------------- 171// -----------------------------------------------------------------------------
172 172
173IsoGfx* isogfx_new(const IsoGfxDesc* desc) { 173Gfx2d* gfx2d_new(const Gfx2dDesc* desc) {
174 assert(desc->screen_width > 0); 174 assert(desc->screen_width > 0);
175 assert(desc->screen_height > 0); 175 assert(desc->screen_height > 0);
176 // Part of our implementation assumes even widths and heights for precision. 176 // Part of our implementation assumes even widths and heights for precision.
177 assert((desc->screen_width & 1) == 0); 177 assert((desc->screen_width & 1) == 0);
178 assert((desc->screen_height & 1) == 0); 178 assert((desc->screen_height & 1) == 0);
179 179
180 IsoGfx tmp = {0}; 180 Gfx2d tmp = {0};
181 if (!memstack_make(&tmp.stack, desc->memory_size, desc->memory)) { 181 if (!memstack_make(&tmp.stack, desc->memory_size, desc->memory)) {
182 goto cleanup; 182 goto cleanup;
183 } 183 }
184 IsoGfx* iso = 184 Gfx2d* gfx =
185 memstack_alloc_aligned(&tmp.stack, sizeof(IsoGfx), alignof(IsoGfx)); 185 memstack_alloc_aligned(&tmp.stack, sizeof(Gfx2d), alignof(Gfx2d));
186 *iso = tmp; 186 *gfx = tmp;
187 187
188 const size_t screen_size_bytes = 188 const size_t screen_size_bytes =
189 desc->screen_width * desc->screen_height * sizeof(Pixel); 189 desc->screen_width * desc->screen_height * sizeof(Pixel);
190 Pixel* screen = 190 Pixel* screen =
191 memstack_alloc_aligned(&iso->stack, screen_size_bytes, alignof(Pixel)); 191 memstack_alloc_aligned(&gfx->stack, screen_size_bytes, alignof(Pixel));
192 192
193 iso->screen = (Screen){.width = desc->screen_width, 193 gfx->screen = (Screen){.width = desc->screen_width,
194 .height = desc->screen_height, 194 .height = desc->screen_height,
195 .pixels = screen}; 195 .pixels = screen};
196 196
197 iso->last_animation_time = 0.0; 197 gfx->last_animation_time = 0.0;
198 iso->watermark = memstack_watermark(&iso->stack); 198 gfx->watermark = memstack_watermark(&gfx->stack);
199 199
200 return iso; 200 return gfx;
201 201
202cleanup: 202cleanup:
203 isogfx_del(&iso); 203 gfx2d_del(&gfx);
204 return nullptr; 204 return nullptr;
205} 205}
206 206
207void isogfx_clear(IsoGfx* iso) { 207void gfx2d_clear(Gfx2d* gfx) {
208 assert(iso); 208 assert(gfx);
209 iso->last_animation_time = 0.0; 209 gfx->last_animation_time = 0.0;
210 iso->next_tile = 0; 210 gfx->next_tile = 0;
211 iso->map = nullptr; 211 gfx->map = nullptr;
212 iso->tileset = nullptr; 212 gfx->tileset = nullptr;
213 iso->head_sprite = nullptr; 213 gfx->head_sprite = nullptr;
214 // The base of the stack contains the IsoGfx and the screen buffer. Make sure 214 // The base of the stack contains the Gfx2d and the screen buffer. Make sure
215 // we don't clear them. 215 // we don't clear them.
216 memstack_set_watermark(&iso->stack, iso->watermark); 216 memstack_set_watermark(&gfx->stack, gfx->watermark);
217} 217}
218 218
219void isogfx_del(IsoGfx** ppIso) { 219void gfx2d_del(Gfx2d** ppGfx) {
220 assert(ppIso); 220 assert(ppGfx);
221 IsoGfx* iso = *ppIso; 221 Gfx2d* gfx = *ppGfx;
222 if (iso) { 222 if (gfx) {
223 memstack_del(&iso->stack); 223 memstack_del(&gfx->stack);
224 *ppIso = nullptr; 224 *ppGfx = nullptr;
225 } 225 }
226} 226}
227 227
228void isogfx_make_map(IsoGfx* iso, const MapDesc* desc) { 228void gfx2d_make_map(Gfx2d* gfx, const MapDesc* desc) {
229 assert(iso); 229 assert(gfx);
230 assert(desc); 230 assert(desc);
231 assert(desc->tile_width > 0); 231 assert(desc->tile_width > 0);
232 assert(desc->tile_height > 0); 232 assert(desc->tile_height > 0);
@@ -241,7 +241,7 @@ void isogfx_make_map(IsoGfx* iso, const MapDesc* desc) {
241 assert(desc->num_tiles > 0); 241 assert(desc->num_tiles > 0);
242 242
243 // Handle recreation by destroying the previous world and sprites. 243 // Handle recreation by destroying the previous world and sprites.
244 isogfx_clear(iso); 244 gfx2d_clear(gfx);
245 245
246 const int world_size = desc->world_width * desc->world_height; 246 const int world_size = desc->world_width * desc->world_height;
247 const size_t map_size_bytes = sizeof(Tm_Map) + (world_size * sizeof(Tile)); 247 const size_t map_size_bytes = sizeof(Tm_Map) + (world_size * sizeof(Tile));
@@ -256,8 +256,8 @@ void isogfx_make_map(IsoGfx* iso, const MapDesc* desc) {
256 (desc->num_tiles * sizeof(Ts_Tile)) + 256 (desc->num_tiles * sizeof(Ts_Tile)) +
257 tile_data_size_bytes; 257 tile_data_size_bytes;
258 258
259 iso->map = memstack_alloc_aligned(&iso->stack, map_size_bytes, 4); 259 gfx->map = memstack_alloc_aligned(&gfx->stack, map_size_bytes, 4);
260 *iso->map = (Tm_Map){ 260 *gfx->map = (Tm_Map){
261 .world_width = desc->world_width, 261 .world_width = desc->world_width,
262 .world_height = desc->world_height, 262 .world_height = desc->world_height,
263 .base_tile_width = desc->tile_width, 263 .base_tile_width = desc->tile_width,
@@ -265,34 +265,34 @@ void isogfx_make_map(IsoGfx* iso, const MapDesc* desc) {
265 .num_layers = 1, 265 .num_layers = 1,
266 }; 266 };
267 267
268 iso->tileset = memstack_alloc_aligned(&iso->stack, tileset_size_bytes, 4); 268 gfx->tileset = memstack_alloc_aligned(&gfx->stack, tileset_size_bytes, 4);
269 *iso->tileset = (Ts_TileSet){ 269 *gfx->tileset = (Ts_TileSet){
270 .num_tiles = desc->num_tiles, 270 .num_tiles = desc->num_tiles,
271 }; 271 };
272 272
273 iso->iso_space = make_iso_coord_system(iso->map, &iso->screen); 273 gfx->iso_space = make_iso_coord_system(gfx->map, &gfx->screen);
274} 274}
275 275
276bool isogfx_load_map(IsoGfx* iso, const char* filepath) { 276bool gfx2d_load_map(Gfx2d* gfx, const char* filepath) {
277 assert(iso); 277 assert(gfx);
278 assert(filepath); 278 assert(filepath);
279 279
280 bool success = false; 280 bool success = false;
281 281
282 // Handle recreation by destroying the previous world and sprites. 282 // Handle recreation by destroying the previous world and sprites.
283 isogfx_clear(iso); 283 gfx2d_clear(gfx);
284 284
285 // Load the map. 285 // Load the map.
286 printf("Load tile map: %s\n", filepath); 286 printf("Load tile map: %s\n", filepath);
287 WITH_FILE(filepath, { 287 WITH_FILE(filepath, {
288 const size_t map_size = get_file_size_f(file); 288 const size_t map_size = get_file_size_f(file);
289 iso->map = memstack_alloc_aligned(&iso->stack, map_size, 4); 289 gfx->map = memstack_alloc_aligned(&gfx->stack, map_size, 4);
290 success = read_file_f(file, iso->map); 290 success = read_file_f(file, gfx->map);
291 }); 291 });
292 if (!success) { 292 if (!success) {
293 goto cleanup; 293 goto cleanup;
294 } 294 }
295 Tm_Map* const map = iso->map; 295 Tm_Map* const map = gfx->map;
296 296
297 printf("Map orientation: %d\n", ((Tm_Flags*)&map->flags)->orientation); 297 printf("Map orientation: %d\n", ((Tm_Flags*)&map->flags)->orientation);
298 298
@@ -308,39 +308,39 @@ bool isogfx_load_map(IsoGfx* iso, const char* filepath) {
308 printf("Load tile set: %s\n", ts_path_cwd); 308 printf("Load tile set: %s\n", ts_path_cwd);
309 WITH_FILE(ts_path_cwd, { 309 WITH_FILE(ts_path_cwd, {
310 const size_t file_size = get_file_size_f(file); 310 const size_t file_size = get_file_size_f(file);
311 iso->tileset = memstack_alloc_aligned(&iso->stack, file_size, 4); 311 gfx->tileset = memstack_alloc_aligned(&gfx->stack, file_size, 4);
312 success = read_file_f(file, iso->tileset); 312 success = read_file_f(file, gfx->tileset);
313 }); 313 });
314 if (!success) { 314 if (!success) {
315 // TODO: Log errors using the log library. 315 // TODO: Log errors using the log library.
316 goto cleanup; 316 goto cleanup;
317 } 317 }
318 const Ts_TileSet* const tileset = iso->tileset; 318 const Ts_TileSet* const tileset = gfx->tileset;
319 printf("Loaded tile set (%u tiles): %s\n", tileset->num_tiles, ts_path_cwd); 319 printf("Loaded tile set (%u tiles): %s\n", tileset->num_tiles, ts_path_cwd);
320 320
321 // TODO: These assertions on input data should be library runtime errors. 321 // TODO: These assertions on input data should be library runtime errors.
322 assert(ts_validate_tileset(tileset)); 322 assert(ts_validate_tileset(tileset));
323 assert(tm_validate_map(map, tileset)); 323 assert(tm_validate_map(map, tileset));
324 324
325 iso->iso_space = make_iso_coord_system(iso->map, &iso->screen); 325 gfx->iso_space = make_iso_coord_system(gfx->map, &gfx->screen);
326 326
327 success = true; 327 success = true;
328 328
329cleanup: 329cleanup:
330 if (!success) { 330 if (!success) {
331 isogfx_clear(iso); 331 gfx2d_clear(gfx);
332 } 332 }
333 return success; 333 return success;
334} 334}
335 335
336int isogfx_world_width(const IsoGfx* iso) { 336int gfx2d_world_width(const Gfx2d* gfx) {
337 assert(iso); 337 assert(gfx);
338 return iso->map->world_width; 338 return gfx->map->world_width;
339} 339}
340 340
341int isogfx_world_height(const IsoGfx* iso) { 341int gfx2d_world_height(const Gfx2d* gfx) {
342 assert(iso); 342 assert(gfx);
343 return iso->map->world_height; 343 return gfx->map->world_height;
344} 344}
345 345
346static void make_tile_from_colour( 346static void make_tile_from_colour(
@@ -368,19 +368,19 @@ static void make_tile_from_colour(
368 } 368 }
369} 369}
370 370
371Tile isogfx_make_tile(IsoGfx* iso, const TileDesc* desc) { 371Tile gfx2d_make_tile(Gfx2d* gfx, const TileDesc* desc) {
372 assert(iso); 372 assert(gfx);
373 assert(desc); 373 assert(desc);
374 // Client must create a world first. 374 // Client must create a world first.
375 assert(iso->map); 375 assert(gfx->map);
376 assert(iso->tileset); 376 assert(gfx->tileset);
377 // Currently, procedural tiles must match the base tile size. 377 // Currently, procedural tiles must match the base tile size.
378 assert(desc->width == iso->map->base_tile_width); 378 assert(desc->width == gfx->map->base_tile_width);
379 assert(desc->height == iso->map->base_tile_height); 379 assert(desc->height == gfx->map->base_tile_height);
380 // Cannot exceed max tiles. 380 // Cannot exceed max tiles.
381 assert(iso->next_tile < iso->tileset->num_tiles); 381 assert(gfx->next_tile < gfx->tileset->num_tiles);
382 382
383 const Tile tile = iso->next_tile++; 383 const Tile tile = gfx->next_tile++;
384 384
385 const size_t tile_size_bytes = desc->width * desc->height * sizeof(Pixel); 385 const size_t tile_size_bytes = desc->width * desc->height * sizeof(Pixel);
386 386
@@ -389,16 +389,16 @@ Tile isogfx_make_tile(IsoGfx* iso, const TileDesc* desc) {
389 assert(desc->width > 0); 389 assert(desc->width > 0);
390 assert(desc->height > 0); 390 assert(desc->height > 0);
391 391
392 Ts_Tile* const ts_tile = ts_tileset_get_tile_mut(iso->tileset, tile); 392 Ts_Tile* const ts_tile = ts_tileset_get_tile_mut(gfx->tileset, tile);
393 393
394 *ts_tile = (Ts_Tile){ 394 *ts_tile = (Ts_Tile){
395 .width = iso->map->base_tile_width, 395 .width = gfx->map->base_tile_width,
396 .height = iso->map->base_tile_height, 396 .height = gfx->map->base_tile_height,
397 .pixels = tile * tile_size_bytes, 397 .pixels = tile * tile_size_bytes,
398 }; 398 };
399 399
400 Pixel* const tile_pixels = 400 Pixel* const tile_pixels =
401 ts_tileset_get_tile_pixels_mut(iso->tileset, tile); 401 ts_tileset_get_tile_pixels_mut(gfx->tileset, tile);
402 make_tile_from_colour(desc->colour, ts_tile, tile_pixels); 402 make_tile_from_colour(desc->colour, ts_tile, tile_pixels);
403 break; 403 break;
404 } 404 }
@@ -416,31 +416,31 @@ Tile isogfx_make_tile(IsoGfx* iso, const TileDesc* desc) {
416 return tile; 416 return tile;
417} 417}
418 418
419void isogfx_set_tile(IsoGfx* iso, int x, int y, Tile tile) { 419void gfx2d_set_tile(Gfx2d* gfx, int x, int y, Tile tile) {
420 assert(iso); 420 assert(gfx);
421 421
422 Tm_Layer* const layer = tm_map_get_layer_mut(iso->map, 0); 422 Tm_Layer* const layer = tm_map_get_layer_mut(gfx->map, 0);
423 Tile* map_tile = tm_layer_get_tile_mut(iso->map, layer, x, y); 423 Tile* map_tile = tm_layer_get_tile_mut(gfx->map, layer, x, y);
424 424
425 *map_tile = tile; 425 *map_tile = tile;
426} 426}
427 427
428void isogfx_set_tiles(IsoGfx* iso, int x0, int y0, int x1, int y1, Tile tile) { 428void gfx2d_set_tiles(Gfx2d* gfx, int x0, int y0, int x1, int y1, Tile tile) {
429 assert(iso); 429 assert(gfx);
430 for (int y = y0; y < y1; ++y) { 430 for (int y = y0; y < y1; ++y) {
431 for (int x = x0; x < x1; ++x) { 431 for (int x = x0; x < x1; ++x) {
432 isogfx_set_tile(iso, x, y, tile); 432 gfx2d_set_tile(gfx, x, y, tile);
433 } 433 }
434 } 434 }
435} 435}
436 436
437SpriteSheet isogfx_load_sprite_sheet(IsoGfx* iso, const char* filepath) { 437SpriteSheet gfx2d_load_sprite_sheet(Gfx2d* gfx, const char* filepath) {
438 assert(iso); 438 assert(gfx);
439 assert(filepath); 439 assert(filepath);
440 440
441 bool success = false; 441 bool success = false;
442 SpriteSheet spriteSheet = 0; 442 SpriteSheet spriteSheet = 0;
443 const size_t watermark = memstack_watermark(&iso->stack); 443 const size_t watermark = memstack_watermark(&gfx->stack);
444 444
445 // Load sprite sheet file. 445 // Load sprite sheet file.
446 printf("Load sprite sheet: %s\n", filepath); 446 printf("Load sprite sheet: %s\n", filepath);
@@ -448,7 +448,7 @@ SpriteSheet isogfx_load_sprite_sheet(IsoGfx* iso, const char* filepath) {
448 WITH_FILE(filepath, { 448 WITH_FILE(filepath, {
449 const size_t file_size = get_file_size_f(file); 449 const size_t file_size = get_file_size_f(file);
450 ss_sheet = 450 ss_sheet =
451 memstack_alloc_aligned(&iso->stack, file_size, alignof(Ss_SpriteSheet)); 451 memstack_alloc_aligned(&gfx->stack, file_size, alignof(Ss_SpriteSheet));
452 success = read_file_f(file, ss_sheet); 452 success = read_file_f(file, ss_sheet);
453 }); 453 });
454 if (!success) { 454 if (!success) {
@@ -461,63 +461,63 @@ SpriteSheet isogfx_load_sprite_sheet(IsoGfx* iso, const char* filepath) {
461cleanup: 461cleanup:
462 if (!success) { 462 if (!success) {
463 if (ss_sheet) { 463 if (ss_sheet) {
464 memstack_set_watermark(&iso->stack, watermark); 464 memstack_set_watermark(&gfx->stack, watermark);
465 } 465 }
466 } 466 }
467 return spriteSheet; 467 return spriteSheet;
468} 468}
469 469
470Sprite isogfx_make_sprite(IsoGfx* iso, SpriteSheet sheet) { 470Sprite gfx2d_make_sprite(Gfx2d* gfx, SpriteSheet sheet) {
471 assert(iso); 471 assert(gfx);
472 assert(sheet); 472 assert(sheet);
473 473
474 // TODO: Remove memstack_alloc() and replace it with a same-name macro that 474 // TODO: Remove memstack_alloc() and replace it with a same-name macro that
475 // calls memstack_alloc_aligned() with sizeof/alignof. No real point in 475 // calls memstack_alloc_aligned() with sizeof/alignof. No real point in
476 // having unaligned allocations. 476 // having unaligned allocations.
477 SpriteInstance* sprite = memstack_alloc_aligned( 477 SpriteInstance* sprite = memstack_alloc_aligned(
478 &iso->stack, sizeof(SpriteInstance), alignof(SpriteInstance)); 478 &gfx->stack, sizeof(SpriteInstance), alignof(SpriteInstance));
479 479
480 sprite->sheet = (const Ss_SpriteSheet*)sheet; 480 sprite->sheet = (const Ss_SpriteSheet*)sheet;
481 sprite->next = iso->head_sprite; 481 sprite->next = gfx->head_sprite;
482 iso->head_sprite = sprite; 482 gfx->head_sprite = sprite;
483 483
484 return (Sprite)sprite; 484 return (Sprite)sprite;
485} 485}
486 486
487void isogfx_set_sprite_position(IsoGfx* iso, Sprite hSprite, int x, int y) { 487void gfx2d_set_sprite_position(Gfx2d* gfx, Sprite hSprite, int x, int y) {
488 assert(iso); 488 assert(gfx);
489 SpriteInstance* sprite = (SpriteInstance*)hSprite; 489 SpriteInstance* sprite = (SpriteInstance*)hSprite;
490 sprite->position.x = x; 490 sprite->position.x = x;
491 sprite->position.y = y; 491 sprite->position.y = y;
492} 492}
493 493
494void isogfx_set_sprite_animation(IsoGfx* iso, Sprite hSprite, int animation) { 494void gfx2d_set_sprite_animation(Gfx2d* gfx, Sprite hSprite, int animation) {
495 assert(iso); 495 assert(gfx);
496 SpriteInstance* sprite = (SpriteInstance*)hSprite; 496 SpriteInstance* sprite = (SpriteInstance*)hSprite;
497 sprite->animation = animation; 497 sprite->animation = animation;
498} 498}
499 499
500void isogfx_update(IsoGfx* iso, double t) { 500void gfx2d_update(Gfx2d* gfx, double t) {
501 assert(iso); 501 assert(gfx);
502 502
503 // If this is the first time update() is called after initialization, just 503 // If this is the first time update() is called after initialization, just
504 // record the starting animation time. 504 // record the starting animation time.
505 if (iso->last_animation_time == 0.0) { 505 if (gfx->last_animation_time == 0.0) {
506 iso->last_animation_time = t; 506 gfx->last_animation_time = t;
507 return; 507 return;
508 } 508 }
509 509
510 if ((t - iso->last_animation_time) >= ANIMATION_UPDATE_DELTA) { 510 if ((t - gfx->last_animation_time) >= ANIMATION_UPDATE_DELTA) {
511 // TODO: Consider linking animated sprites in a separate list so that we 511 // TODO: Consider linking animated sprites in a separate list so that we
512 // only walk over those here and not also the static sprites. 512 // only walk over those here and not also the static sprites.
513 for (SpriteInstance* sprite = iso->head_sprite; sprite; 513 for (SpriteInstance* sprite = gfx->head_sprite; sprite;
514 sprite = sprite->next) { 514 sprite = sprite->next) {
515 const Ss_SpriteSheet* sheet = sprite->sheet; 515 const Ss_SpriteSheet* sheet = sprite->sheet;
516 const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); 516 const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation);
517 sprite->frame = (sprite->frame + 1) % row->num_cols; 517 sprite->frame = (sprite->frame + 1) % row->num_cols;
518 } 518 }
519 519
520 iso->last_animation_time = t; 520 gfx->last_animation_time = t;
521 } 521 }
522} 522}
523 523
@@ -556,6 +556,7 @@ static void draw_rect(
556 Screen* screen, ivec2 top_left, int rect_width, int rect_height, 556 Screen* screen, ivec2 top_left, int rect_width, int rect_height,
557 const Pixel* pixels, const uint8_t* indices) { 557 const Pixel* pixels, const uint8_t* indices) {
558 assert(screen); 558 assert(screen);
559 assert(pixels);
559 560
560#define rect_pixel(X, Y) \ 561#define rect_pixel(X, Y) \
561 (indices ? pixels[indices[Y * rect_width + X]] : pixels[Y * rect_width + X]) 562 (indices ? pixels[indices[Y * rect_width + X]] : pixels[Y * rect_width + X])
@@ -584,116 +585,116 @@ static void draw_rect(
584} 585}
585 586
586/// Draw a tile in an orthogonal map. 587/// Draw a tile in an orthogonal map.
587static void draw_tile_ortho(IsoGfx* iso, Tile tile, int x, int y) { 588static void draw_tile_ortho(Gfx2d* gfx, Tile tile, int x, int y) {
588 assert(iso); 589 assert(gfx);
589 assert(iso->tileset); 590 assert(gfx->tileset);
590 assert(x >= 0); 591 assert(x >= 0);
591 assert(y >= 0); 592 assert(y >= 0);
592 assert(x < iso->map->world_width); 593 assert(x < gfx->map->world_width);
593 assert(y < iso->map->world_height); 594 assert(y < gfx->map->world_height);
594 595
595 const Ts_Tile* pTile = ts_tileset_get_tile(iso->tileset, tile); 596 const Ts_Tile* pTile = ts_tileset_get_tile(gfx->tileset, tile);
596 const Pixel* pixels = ts_tileset_get_tile_pixels(iso->tileset, tile); 597 const Pixel* pixels = ts_tileset_get_tile_pixels(gfx->tileset, tile);
597 598
598 const ivec2 screen_origin = map2screen( 599 const ivec2 screen_origin = map2screen(
599 iso->camera, iso->map->base_tile_width, iso->map->base_tile_height, x, y); 600 gfx->camera, gfx->map->base_tile_width, gfx->map->base_tile_height, x, y);
600 601
601 draw_rect( 602 draw_rect(
602 &iso->screen, screen_origin, pTile->width, pTile->height, pixels, 603 &gfx->screen, screen_origin, pTile->width, pTile->height, pixels,
603 nullptr); 604 nullptr);
604} 605}
605 606
606/// Draw a tile in an isometric map. 607/// Draw a tile in an isometric map.
607static void draw_tile_iso(IsoGfx* iso, Tile tile, int iso_x, int iso_y) { 608static void draw_tile_iso(Gfx2d* gfx, Tile tile, int iso_x, int iso_y) {
608 assert(iso); 609 assert(gfx);
609 assert(iso->tileset); 610 assert(gfx->tileset);
610 assert(iso_x >= 0); 611 assert(iso_x >= 0);
611 assert(iso_y >= 0); 612 assert(iso_y >= 0);
612 assert(iso_x < iso->map->world_width); 613 assert(iso_x < gfx->map->world_width);
613 assert(iso_y < iso->map->world_height); 614 assert(iso_y < gfx->map->world_height);
614 615
615 const Ts_Tile* pTile = ts_tileset_get_tile(iso->tileset, tile); 616 const Ts_Tile* pTile = ts_tileset_get_tile(gfx->tileset, tile);
616 const Pixel* pixels = ts_tileset_get_tile_pixels(iso->tileset, tile); 617 const Pixel* pixels = ts_tileset_get_tile_pixels(gfx->tileset, tile);
617 618
618 // Compute the screen coordinates of the top diamond-corner of the tile (the 619 // Compute the screen coordinates of the top diamond-corner of the tile (the
619 // base tile for super tiles). 620 // base tile for super tiles).
620 // World (0, 0) -> (screen_width / 2, 0). 621 // World (0, 0) -> (screen_width / 2, 0).
621 const ivec2 screen_origin = 622 const ivec2 screen_origin =
622 iso2cart(iso->iso_space, iso->camera, iso_x, iso_y); 623 iso2cart(gfx->iso_space, gfx->camera, iso_x, iso_y);
623 624
624 // Move from the top diamond-corner to the top-left corner of the tile image. 625 // Move from the top diamond-corner to the top-left corner of the tile image.
625 // For regular tiles, tile height == base tile height, so the y offset is 0. 626 // For regular tiles, tile height == base tile height, so the y offset is 0.
626 // For super tiles, move as high up as the height of the tile. 627 // For super tiles, move as high up as the height of the tile.
627 const ivec2 offset = { 628 const ivec2 offset = {
628 -(iso->map->base_tile_width / 2), 629 -(gfx->map->base_tile_width / 2),
629 pTile->height - iso->map->base_tile_height}; 630 pTile->height - gfx->map->base_tile_height};
630 const ivec2 top_left = ivec2_add(screen_origin, offset); 631 const ivec2 top_left = ivec2_add(screen_origin, offset);
631 632
632 draw_rect( 633 draw_rect(
633 &iso->screen, top_left, pTile->width, pTile->height, pixels, nullptr); 634 &gfx->screen, top_left, pTile->width, pTile->height, pixels, nullptr);
634} 635}
635 636
636static void draw_map_ortho(IsoGfx* iso) { 637static void draw_map_ortho(Gfx2d* gfx) {
637 assert(iso); 638 assert(gfx);
638 assert(iso->map); 639 assert(gfx->map);
639 640
640 // TODO: Same TODOs as in draw_map_iso(). 641 // TODO: Same TODOs as in draw_map_iso().
641 642
642 const Tm_Layer* layer = tm_map_get_layer(iso->map, 0); 643 const Tm_Layer* layer = tm_map_get_layer(gfx->map, 0);
643 644
644 for (int wy = 0; wy < iso->map->world_height; ++wy) { 645 for (int wy = 0; wy < gfx->map->world_height; ++wy) {
645 for (int wx = 0; wx < iso->map->world_width; ++wx) { 646 for (int wx = 0; wx < gfx->map->world_width; ++wx) {
646 const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); 647 const Tile tile = tm_layer_get_tile(gfx->map, layer, wx, wy);
647 draw_tile_ortho(iso, tile, wx, wy); 648 draw_tile_ortho(gfx, tile, wx, wy);
648 } 649 }
649 } 650 }
650} 651}
651 652
652static void draw_map_iso(IsoGfx* iso) { 653static void draw_map_iso(Gfx2d* gfx) {
653 assert(iso); 654 assert(gfx);
654 assert(iso->map); 655 assert(gfx->map);
655 656
656 // TODO: Support for multiple layers. 657 // TODO: Support for multiple layers.
657 const Tm_Layer* layer = tm_map_get_layer(iso->map, 0); 658 const Tm_Layer* layer = tm_map_get_layer(gfx->map, 0);
658 659
659 // TODO: Culling. 660 // TODO: Culling.
660 // Ex: map the screen corners to tile space to cull. 661 // Ex: map the screen corners to tile space to cull.
661 // Ex: walk in screen space and fetch the tile. 662 // Ex: walk in screen space and fetch the tile.
662 // The tile-centric approach might be more cache-friendly since the 663 // The tile-centric approach might be more cache-friendly since the
663 // screen-centric approach would juggle multiple tiles throughout the scan. 664 // screen-centric approach would juggle multiple tiles throughout the scan.
664 for (int wy = 0; wy < iso->map->world_height; ++wy) { 665 for (int wy = 0; wy < gfx->map->world_height; ++wy) {
665 for (int wx = 0; wx < iso->map->world_width; ++wx) { 666 for (int wx = 0; wx < gfx->map->world_width; ++wx) {
666 const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); 667 const Tile tile = tm_layer_get_tile(gfx->map, layer, wx, wy);
667 draw_tile_iso(iso, tile, wx, wy); 668 draw_tile_iso(gfx, tile, wx, wy);
668 } 669 }
669 } 670 }
670} 671}
671 672
672static void draw_map(IsoGfx* iso) { 673static void draw_map(Gfx2d* gfx) {
673 assert(iso); 674 assert(gfx);
674 assert(iso->map); 675 assert(gfx->map);
675 assert(iso->screen.pixels); 676 assert(gfx->screen.pixels);
676 677
677 const int W = iso->screen.width; 678 const int W = gfx->screen.width;
678 const int H = iso->screen.height; 679 const int H = gfx->screen.height;
679 680
680 memset(iso->screen.pixels, 0, W * H * sizeof(Pixel)); 681 memset(gfx->screen.pixels, 0, W * H * sizeof(Pixel));
681 682
682 const Tm_Flags* flags = (const Tm_Flags*)&iso->map->flags; 683 const Tm_Flags* flags = (const Tm_Flags*)&gfx->map->flags;
683 switch (flags->orientation) { 684 switch (flags->orientation) {
684 case Tm_Orthogonal: 685 case Tm_Orthogonal:
685 draw_map_ortho(iso); 686 draw_map_ortho(gfx);
686 break; 687 break;
687 case Tm_Isometric: 688 case Tm_Isometric:
688 draw_map_iso(iso); 689 draw_map_iso(gfx);
689 break; 690 break;
690 } 691 }
691} 692}
692 693
693/// Draw a sprite in an orthogonal/Cartesian coordinate system. 694/// Draw a sprite in an orthogonal/Cartesian coordinate system.
694static void draw_sprite_ortho( 695static void draw_sprite_ortho(
695 IsoGfx* iso, const SpriteInstance* sprite, const Ss_SpriteSheet* sheet) { 696 Gfx2d* gfx, const SpriteInstance* sprite, const Ss_SpriteSheet* sheet) {
696 assert(iso); 697 assert(gfx);
697 assert(sprite); 698 assert(sprite);
698 assert(sheet); 699 assert(sheet);
699 assert(sprite->animation >= 0); 700 assert(sprite->animation >= 0);
@@ -704,20 +705,20 @@ static void draw_sprite_ortho(
704 // -base_tile_width/2 along the x-axis to align the sprite with the leftmost 705 // -base_tile_width/2 along the x-axis to align the sprite with the leftmost
705 // edge of the tile it is on. 706 // edge of the tile it is on.
706 const ivec2 screen_origin = map2screen( 707 const ivec2 screen_origin = map2screen(
707 iso->camera, iso->map->base_tile_width, iso->map->base_tile_height, 708 gfx->camera, gfx->map->base_tile_width, gfx->map->base_tile_height,
708 sprite->position.x, sprite->position.y); 709 sprite->position.x, sprite->position.y);
709 710
710 const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); 711 const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation);
711 const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); 712 const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame);
712 draw_rect( 713 draw_rect(
713 &iso->screen, screen_origin, sheet->sprite_width, sheet->sprite_height, 714 &gfx->screen, screen_origin, sheet->sprite_width, sheet->sprite_height,
714 sheet->palette.colours, frame); 715 sheet->palette.colours, frame);
715} 716}
716 717
717/// Draw a sprite in an isometric coordinate system. 718/// Draw a sprite in an isometric coordinate system.
718static void draw_sprite_iso( 719static void draw_sprite_iso(
719 IsoGfx* iso, const SpriteInstance* sprite, const Ss_SpriteSheet* sheet) { 720 Gfx2d* gfx, const SpriteInstance* sprite, const Ss_SpriteSheet* sheet) {
720 assert(iso); 721 assert(gfx);
721 assert(sprite); 722 assert(sprite);
722 assert(sheet); 723 assert(sheet);
723 assert(sprite->animation >= 0); 724 assert(sprite->animation >= 0);
@@ -728,92 +729,92 @@ static void draw_sprite_iso(
728 // -base_tile_width/2 along the x-axis to align the sprite with the leftmost 729 // -base_tile_width/2 along the x-axis to align the sprite with the leftmost
729 // edge of the tile it is on. 730 // edge of the tile it is on.
730 const ivec2 screen_origin = iso2cart( 731 const ivec2 screen_origin = iso2cart(
731 iso->iso_space, iso->camera, sprite->position.x, sprite->position.y); 732 gfx->iso_space, gfx->camera, sprite->position.x, sprite->position.y);
732 const ivec2 offset = {-(iso->map->base_tile_width / 2), 0}; 733 const ivec2 offset = {-(gfx->map->base_tile_width / 2), 0};
733 const ivec2 top_left = ivec2_add(screen_origin, offset); 734 const ivec2 top_left = ivec2_add(screen_origin, offset);
734 735
735 const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); 736 const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation);
736 const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); 737 const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame);
737 draw_rect( 738 draw_rect(
738 &iso->screen, top_left, sheet->sprite_width, sheet->sprite_height, 739 &gfx->screen, top_left, sheet->sprite_width, sheet->sprite_height,
739 sheet->palette.colours, frame); 740 sheet->palette.colours, frame);
740} 741}
741 742
742static void draw_sprites(IsoGfx* iso) { 743static void draw_sprites(Gfx2d* gfx) {
743 assert(iso); 744 assert(gfx);
744 assert(iso->map); 745 assert(gfx->map);
745 746
746 const Tm_Flags* flags = (const Tm_Flags*)&iso->map->flags; 747 const Tm_Flags* flags = (const Tm_Flags*)&gfx->map->flags;
747 switch (flags->orientation) { 748 switch (flags->orientation) {
748 case Tm_Orthogonal: 749 case Tm_Orthogonal:
749 for (const SpriteInstance* sprite = iso->head_sprite; sprite; 750 for (const SpriteInstance* sprite = gfx->head_sprite; sprite;
750 sprite = sprite->next) { 751 sprite = sprite->next) {
751 draw_sprite_ortho(iso, sprite, sprite->sheet); 752 draw_sprite_ortho(gfx, sprite, sprite->sheet);
752 } 753 }
753 break; 754 break;
754 case Tm_Isometric: 755 case Tm_Isometric:
755 for (const SpriteInstance* sprite = iso->head_sprite; sprite; 756 for (const SpriteInstance* sprite = gfx->head_sprite; sprite;
756 sprite = sprite->next) { 757 sprite = sprite->next) {
757 draw_sprite_iso(iso, sprite, sprite->sheet); 758 draw_sprite_iso(gfx, sprite, sprite->sheet);
758 } 759 }
759 break; 760 break;
760 } 761 }
761} 762}
762 763
763void isogfx_set_camera(IsoGfx* iso, int x, int y) { 764void gfx2d_set_camera(Gfx2d* gfx, int x, int y) {
764 assert(iso); 765 assert(gfx);
765 iso->camera = (ivec2){x, y}; 766 gfx->camera = (ivec2){x, y};
766} 767}
767 768
768void isogfx_render(IsoGfx* iso) { 769void gfx2d_render(Gfx2d* gfx) {
769 assert(iso); 770 assert(gfx);
770 draw_map(iso); 771 draw_map(gfx);
771 draw_sprites(iso); 772 draw_sprites(gfx);
772} 773}
773 774
774void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) { 775void gfx2d_draw_tile(Gfx2d* gfx, int x, int y, Tile tile) {
775 assert(iso); 776 assert(gfx);
776 assert(iso->map); 777 assert(gfx->map);
777 778
778 const Tm_Flags* flags = (const Tm_Flags*)&iso->map->flags; 779 const Tm_Flags* flags = (const Tm_Flags*)&gfx->map->flags;
779 switch (flags->orientation) { 780 switch (flags->orientation) {
780 case Tm_Orthogonal: 781 case Tm_Orthogonal:
781 draw_tile_ortho(iso, tile, x, y); 782 draw_tile_ortho(gfx, tile, x, y);
782 break; 783 break;
783 case Tm_Isometric: 784 case Tm_Isometric:
784 draw_tile_iso(iso, tile, x, y); 785 draw_tile_iso(gfx, tile, x, y);
785 break; 786 break;
786 } 787 }
787} 788}
788 789
789void isogfx_get_screen_size(const IsoGfx* iso, int* width, int* height) { 790void gfx2d_get_screen_size(const Gfx2d* gfx, int* width, int* height) {
790 assert(iso); 791 assert(gfx);
791 assert(width); 792 assert(width);
792 assert(height); 793 assert(height);
793 *width = iso->screen.width; 794 *width = gfx->screen.width;
794 *height = iso->screen.height; 795 *height = gfx->screen.height;
795} 796}
796 797
797const Pixel* isogfx_get_screen_buffer(const IsoGfx* iso) { 798const Pixel* gfx2d_get_screen_buffer(const Gfx2d* gfx) {
798 assert(iso); 799 assert(gfx);
799 return iso->screen.pixels; 800 return gfx->screen.pixels;
800} 801}
801 802
802void isogfx_pick_tile( 803void gfx2d_pick_tile(
803 const IsoGfx* iso, double xcart, double ycart, int* xiso, int* yiso) { 804 const Gfx2d* gfx, double xcart, double ycart, int* xiso, int* yiso) {
804 assert(iso); 805 assert(gfx);
805 assert(xiso); 806 assert(xiso);
806 assert(yiso); 807 assert(yiso);
807 808
808 const vec2 camera = ivec2_to_vec2(iso->camera); 809 const vec2 camera = ivec2_to_vec2(gfx->camera);
809 const vec2 xy_cart = vec2_add(camera, (vec2){xcart, ycart}); 810 const vec2 xy_cart = vec2_add(camera, (vec2){xcart, ycart});
810 811
811 const vec2 xy_iso = cart2iso( 812 const vec2 xy_iso = cart2iso(
812 xy_cart, iso->map->base_tile_width, iso->map->base_tile_height, 813 xy_cart, gfx->map->base_tile_width, gfx->map->base_tile_height,
813 iso->screen.width); 814 gfx->screen.width);
814 815
815 if ((0 <= xy_iso.x) && (xy_iso.x < iso->map->world_width) && 816 if ((0 <= xy_iso.x) && (xy_iso.x < gfx->map->world_width) &&
816 (0 <= xy_iso.y) && (xy_iso.y < iso->map->world_height)) { 817 (0 <= xy_iso.y) && (xy_iso.y < gfx->map->world_height)) {
817 *xiso = (int)xy_iso.x; 818 *xiso = (int)xy_iso.x;
818 *yiso = (int)xy_iso.y; 819 *yiso = (int)xy_iso.y;
819 } else { 820 } else {