diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | demos/checkerboard/checkerboard.c | 14 | ||||
-rw-r--r-- | demos/isomap/isomap.c | 6 | ||||
-rw-r--r-- | include/isogfx/asset.h | 11 | ||||
-rw-r--r-- | include/isogfx/gfx2d.h (renamed from include/isogfx/isogfx.h) | 24 | ||||
-rw-r--r-- | src/backend.c | 2 | ||||
-rw-r--r-- | src/gfx2d.c (renamed from src/isogfx.c) | 106 | ||||
-rw-r--r-- | tools/mkasset.py | 38 |
8 files changed, 113 insertions, 90 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e55aece..78aefa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -10,7 +10,7 @@ set(CMAKE_C_EXTENSIONS Off) | |||
10 | 10 | ||
11 | add_library(isogfx | 11 | add_library(isogfx |
12 | src/asset.c | 12 | src/asset.c |
13 | src/isogfx.c) | 13 | src/gfx2d.c) |
14 | 14 | ||
15 | target_include_directories(isogfx PUBLIC | 15 | target_include_directories(isogfx PUBLIC |
16 | include) | 16 | include) |
diff --git a/demos/checkerboard/checkerboard.c b/demos/checkerboard/checkerboard.c index 0c8ff37..4f43526 100644 --- a/demos/checkerboard/checkerboard.c +++ b/demos/checkerboard/checkerboard.c | |||
@@ -1,5 +1,5 @@ | |||
1 | #include <isogfx/backend.h> | 1 | #include <isogfx/backend.h> |
2 | #include <isogfx/isogfx.h> | 2 | #include <isogfx/gfx2d.h> |
3 | 3 | ||
4 | #include <gfx/app.h> | 4 | #include <gfx/app.h> |
5 | 5 | ||
@@ -81,12 +81,12 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) { | |||
81 | } | 81 | } |
82 | IsoGfx* iso = state->iso; | 82 | IsoGfx* iso = state->iso; |
83 | 83 | ||
84 | isogfx_make_world( | 84 | isogfx_make_map( |
85 | iso, &(WorldDesc){.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 = isogfx_make_tile(iso, &tile_set[Black]); |
92 | const Tile white = isogfx_make_tile(iso, &tile_set[White]); | 92 | const Tile white = isogfx_make_tile(iso, &tile_set[White]); |
diff --git a/demos/isomap/isomap.c b/demos/isomap/isomap.c index 27c2bf3..bca27f6 100644 --- a/demos/isomap/isomap.c +++ b/demos/isomap/isomap.c | |||
@@ -1,5 +1,5 @@ | |||
1 | #include <isogfx/backend.h> | 1 | #include <isogfx/backend.h> |
2 | #include <isogfx/isogfx.h> | 2 | #include <isogfx/gfx2d.h> |
3 | 3 | ||
4 | #include <gfx/app.h> | 4 | #include <gfx/app.h> |
5 | #include <math/vec2.h> | 5 | #include <math/vec2.h> |
@@ -46,7 +46,7 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) { | |||
46 | } | 46 | } |
47 | IsoGfx* iso = state->iso; | 47 | IsoGfx* iso = state->iso; |
48 | 48 | ||
49 | if (!isogfx_load_world( | 49 | if (!isogfx_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 | } |
@@ -59,7 +59,7 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | state->stag = isogfx_make_sprite(iso, state->stag_sheet); | 61 | state->stag = isogfx_make_sprite(iso, state->stag_sheet); |
62 | isogfx_set_sprite_position(iso, state->stag, 5, 4); | 62 | isogfx_set_sprite_position(iso, state->stag, 0, 0); |
63 | 63 | ||
64 | if (!((state->backend = iso_backend_init(iso)))) { | 64 | if (!((state->backend = iso_backend_init(iso)))) { |
65 | return false; | 65 | return false; |
diff --git a/include/isogfx/asset.h b/include/isogfx/asset.h index 6050500..361ffcd 100644 --- a/include/isogfx/asset.h +++ b/include/isogfx/asset.h | |||
@@ -43,6 +43,16 @@ typedef struct Ts_TileSet { | |||
43 | // Tile map (TM) file format. | 43 | // Tile map (TM) file format. |
44 | // ----------------------------------------------------------------------------- | 44 | // ----------------------------------------------------------------------------- |
45 | 45 | ||
46 | typedef enum Tm_Orientation { | ||
47 | Tm_Orthogonal = 0, | ||
48 | Tm_Isometric = 1, | ||
49 | } Tm_Orientation; | ||
50 | |||
51 | typedef struct Tm_Flags { | ||
52 | Tm_Orientation orientation : 1; | ||
53 | int unused : 15; | ||
54 | } Tm_Flags; | ||
55 | |||
46 | typedef struct Tm_Layer { | 56 | typedef struct Tm_Layer { |
47 | Tile tiles[1]; // Count: world_width * world_height. | 57 | Tile tiles[1]; // Count: world_width * world_height. |
48 | } Tm_Layer; | 58 | } Tm_Layer; |
@@ -54,6 +64,7 @@ typedef struct Tm_Map { | |||
54 | uint16_t base_tile_width; | 64 | uint16_t base_tile_width; |
55 | uint16_t base_tile_height; | 65 | uint16_t base_tile_height; |
56 | uint16_t num_layers; | 66 | uint16_t num_layers; |
67 | uint16_t flags; // Tm_flagsFlags | ||
57 | Tm_Layer layers[]; // Count: num_layers. | 68 | Tm_Layer layers[]; // Count: num_layers. |
58 | } Tm_Map; | 69 | } Tm_Map; |
59 | 70 | ||
diff --git a/include/isogfx/isogfx.h b/include/isogfx/gfx2d.h index e901231..323b389 100644 --- a/include/isogfx/isogfx.h +++ b/include/isogfx/gfx2d.h | |||
@@ -37,13 +37,13 @@ typedef struct TileDesc { | |||
37 | }; | 37 | }; |
38 | } TileDesc; | 38 | } TileDesc; |
39 | 39 | ||
40 | typedef struct WorldDesc { | 40 | typedef struct MapDesc { |
41 | int tile_width; // Base tile width in pixels. | 41 | int tile_width; // Base tile width in pixels. |
42 | int tile_height; // Base tile height in pixels. | 42 | int tile_height; // Base tile height in pixels. |
43 | int world_width; // World width in tiles. | 43 | int world_width; // World width in tiles. |
44 | int world_height; // World height in tiles. | 44 | int world_height; // World height in tiles. |
45 | int num_tiles; // Number of tiles to allocate memory for. | 45 | int num_tiles; // Number of tiles to allocate memory for. |
46 | } WorldDesc; | 46 | } MapDesc; |
47 | 47 | ||
48 | typedef struct IsoGfxDesc { | 48 | typedef struct IsoGfxDesc { |
49 | void* memory; // Block of memory for the engine to use. | 49 | void* memory; // Block of memory for the engine to use. |
@@ -61,11 +61,11 @@ void isogfx_del(IsoGfx**); | |||
61 | /// Clear all loaded worlds and sprites. | 61 | /// Clear all loaded worlds and sprites. |
62 | void isogfx_clear(IsoGfx*); | 62 | void isogfx_clear(IsoGfx*); |
63 | 63 | ||
64 | /// Create an empty world. | 64 | /// Create an empty map. |
65 | void isogfx_make_world(IsoGfx*, const WorldDesc*); | 65 | void isogfx_make_map(IsoGfx*, const MapDesc*); |
66 | 66 | ||
67 | /// Load a world from a tile map (.TM) file. | 67 | /// Load a tile map (.TM) file. |
68 | bool isogfx_load_world(IsoGfx*, const char* filepath); | 68 | bool isogfx_load_map(IsoGfx*, const char* filepath); |
69 | 69 | ||
70 | /// Return the world's width. | 70 | /// Return the world's width. |
71 | int isogfx_world_width(const IsoGfx*); | 71 | int isogfx_world_width(const IsoGfx*); |
@@ -88,8 +88,10 @@ SpriteSheet isogfx_load_sprite_sheet(IsoGfx*, const char* filepath); | |||
88 | /// Create an animated sprite. | 88 | /// Create an animated sprite. |
89 | Sprite isogfx_make_sprite(IsoGfx*, SpriteSheet); | 89 | Sprite isogfx_make_sprite(IsoGfx*, SpriteSheet); |
90 | 90 | ||
91 | /// Destroy all the sprites. | 91 | // TODO: Add a function to delete a sprite. Making the caller manage and re-use |
92 | void isogfx_del_sprites(IsoGfx*); | 92 | // sprites is a shitty API. |
93 | // Not that the stack allocator gets completely in the way; implement a free | ||
94 | // list of sprites so that we can re-use the ones that have been "freed". | ||
93 | 95 | ||
94 | /// Set the sprite's position. | 96 | /// Set the sprite's position. |
95 | void isogfx_set_sprite_position(IsoGfx*, Sprite, int x, int y); | 97 | void isogfx_set_sprite_position(IsoGfx*, Sprite, int x, int y); |
@@ -99,9 +101,13 @@ void isogfx_set_sprite_animation(IsoGfx*, Sprite, int animation); | |||
99 | 101 | ||
100 | /// Update the renderer. | 102 | /// Update the renderer. |
101 | /// | 103 | /// |
102 | /// Currently this updates the sprite animations. | 104 | /// Currently, this updates the sprite animations. |
103 | void isogfx_update(IsoGfx*, double t); | 105 | void isogfx_update(IsoGfx*, double t); |
104 | 106 | ||
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 | ||
109 | // take a camera argument in render() instead. | ||
110 | |||
105 | /// Set the camera. | 111 | /// Set the camera. |
106 | void isogfx_set_camera(IsoGfx*, int x, int y); | 112 | void isogfx_set_camera(IsoGfx*, int x, int y); |
107 | 113 | ||
diff --git a/src/backend.c b/src/backend.c index 94f1728..80c5974 100644 --- a/src/backend.c +++ b/src/backend.c | |||
@@ -1,5 +1,5 @@ | |||
1 | #include <isogfx/backend.h> | 1 | #include <isogfx/backend.h> |
2 | #include <isogfx/isogfx.h> | 2 | #include <isogfx/gfx2d.h> |
3 | 3 | ||
4 | #include <gfx/core.h> | 4 | #include <gfx/core.h> |
5 | #include <gfx/gfx.h> | 5 | #include <gfx/gfx.h> |
diff --git a/src/isogfx.c b/src/gfx2d.c index c3a87bf..9767308 100644 --- a/src/isogfx.c +++ b/src/gfx2d.c | |||
@@ -1,4 +1,4 @@ | |||
1 | #include <isogfx/isogfx.h> | 1 | #include <isogfx/gfx2d.h> |
2 | 2 | ||
3 | #include <isogfx/asset.h> | 3 | #include <isogfx/asset.h> |
4 | 4 | ||
@@ -79,17 +79,49 @@ static inline ivec2 ivec2_scale(ivec2 a, int s) { | |||
79 | 79 | ||
80 | static inline ivec2 ivec2_neg(ivec2 a) { return (ivec2){.x = -a.x, .y = -a.y}; } | 80 | static inline ivec2 ivec2_neg(ivec2 a) { return (ivec2){.x = -a.x, .y = -a.y}; } |
81 | 81 | ||
82 | static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { | ||
83 | return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2), | ||
84 | .y = (iso.x + iso.y) * (t / 2)}; | ||
85 | } | ||
86 | |||
87 | static inline vec2 vec2_add(vec2 a, vec2 b) { | 82 | static inline vec2 vec2_add(vec2 a, vec2 b) { |
88 | return (vec2){.x = a.x + b.x, .y = a.y + b.y}; | 83 | return (vec2){.x = a.x + b.x, .y = a.y + b.y}; |
89 | } | 84 | } |
90 | 85 | ||
91 | static inline vec2 ivec2_to_vec2(ivec2 a) { return (vec2){a.x, a.y}; } | 86 | static inline vec2 ivec2_to_vec2(ivec2 a) { return (vec2){a.x, a.y}; } |
92 | 87 | ||
88 | // Not actually used because we pre-compute the two axis vectors instead. | ||
89 | // See make_iso_coord_system() and the other definition of iso2cart() below. | ||
90 | // static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { | ||
91 | // return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2), | ||
92 | // .y = (iso.x + iso.y) * (t / 2)}; | ||
93 | // } | ||
94 | |||
95 | /// Create the basis for the isometric coordinate system with origin and vectors | ||
96 | /// expressed in the Cartesian system. | ||
97 | static CoordSystem make_iso_coord_system( | ||
98 | const Tm_Map* const map, const Screen* const screen) { | ||
99 | assert(map); | ||
100 | assert(screen); | ||
101 | const ivec2 o = {screen->width / 2, 0}; | ||
102 | const ivec2 x = { | ||
103 | .x = map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
104 | const ivec2 y = { | ||
105 | .x = -map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
106 | return (CoordSystem){o, x, y}; | ||
107 | } | ||
108 | |||
109 | /// Map isometric coordinates to Cartesian coordinates. | ||
110 | /// | ||
111 | /// For a tile, this gets the screen position of the top diamond-corner of the | ||
112 | /// tile. | ||
113 | /// | ||
114 | /// Takes the camera displacement into account. | ||
115 | static ivec2 iso2cart( | ||
116 | const CoordSystem iso_space, ivec2 camera, int iso_x, int iso_y) { | ||
117 | const ivec2 vx_offset = ivec2_scale(iso_space.x, iso_x); | ||
118 | const ivec2 vy_offset = ivec2_scale(iso_space.y, iso_y); | ||
119 | const ivec2 screen_origin = | ||
120 | ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); | ||
121 | const ivec2 origin_view_space = ivec2_add(screen_origin, ivec2_neg(camera)); | ||
122 | return origin_view_space; | ||
123 | } | ||
124 | |||
93 | // Method 1. | 125 | // Method 1. |
94 | // static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { | 126 | // static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { |
95 | // const double x = cart.x - (double)(w / 2); | 127 | // const double x = cart.x - (double)(w / 2); |
@@ -125,20 +157,6 @@ static inline Pixel* screen_xy_mut(Screen* screen, int x, int y) { | |||
125 | return (Pixel*)screen_xy_const_ref(screen, x, y); | 157 | return (Pixel*)screen_xy_const_ref(screen, x, y); |
126 | } | 158 | } |
127 | 159 | ||
128 | /// Create the basis for the isometric coordinate system with origin and vectors | ||
129 | /// expressed in the Cartesian system. | ||
130 | static CoordSystem make_iso_coord_system( | ||
131 | const Tm_Map* const map, const Screen* const screen) { | ||
132 | assert(map); | ||
133 | assert(screen); | ||
134 | const ivec2 o = {screen->width / 2, 0}; | ||
135 | const ivec2 x = { | ||
136 | .x = map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
137 | const ivec2 y = { | ||
138 | .x = -map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
139 | return (CoordSystem){o, x, y}; | ||
140 | } | ||
141 | |||
142 | // ----------------------------------------------------------------------------- | 160 | // ----------------------------------------------------------------------------- |
143 | // Renderer, world and tile management. | 161 | // Renderer, world and tile management. |
144 | // ----------------------------------------------------------------------------- | 162 | // ----------------------------------------------------------------------------- |
@@ -198,7 +216,7 @@ void isogfx_del(IsoGfx** ppIso) { | |||
198 | } | 216 | } |
199 | } | 217 | } |
200 | 218 | ||
201 | void isogfx_make_world(IsoGfx* iso, const WorldDesc* desc) { | 219 | void isogfx_make_map(IsoGfx* iso, const MapDesc* desc) { |
202 | assert(iso); | 220 | assert(iso); |
203 | assert(desc); | 221 | assert(desc); |
204 | assert(desc->tile_width > 0); | 222 | assert(desc->tile_width > 0); |
@@ -246,7 +264,7 @@ void isogfx_make_world(IsoGfx* iso, const WorldDesc* desc) { | |||
246 | iso->iso_space = make_iso_coord_system(iso->map, &iso->screen); | 264 | iso->iso_space = make_iso_coord_system(iso->map, &iso->screen); |
247 | } | 265 | } |
248 | 266 | ||
249 | bool isogfx_load_world(IsoGfx* iso, const char* filepath) { | 267 | bool isogfx_load_map(IsoGfx* iso, const char* filepath) { |
250 | assert(iso); | 268 | assert(iso); |
251 | assert(filepath); | 269 | assert(filepath); |
252 | 270 | ||
@@ -267,6 +285,8 @@ bool isogfx_load_world(IsoGfx* iso, const char* filepath) { | |||
267 | } | 285 | } |
268 | Tm_Map* const map = iso->map; | 286 | Tm_Map* const map = iso->map; |
269 | 287 | ||
288 | printf("Map orientation: %d\n", ((Tm_Flags*)&map->flags)->orientation); | ||
289 | |||
270 | // Load the tile set. | 290 | // Load the tile set. |
271 | // | 291 | // |
272 | // Tile set path is relative to the tile map file. Make it relative to the | 292 | // Tile set path is relative to the tile map file. Make it relative to the |
@@ -496,18 +516,6 @@ void isogfx_update(IsoGfx* iso, double t) { | |||
496 | // Rendering and picking. | 516 | // Rendering and picking. |
497 | // ----------------------------------------------------------------------------- | 517 | // ----------------------------------------------------------------------------- |
498 | 518 | ||
499 | /// Get the screen position of the top diamond-corner of the tile at world | ||
500 | /// (x,y). | ||
501 | static ivec2 GetTileScreenOrigin( | ||
502 | const CoordSystem iso_space, ivec2 camera, int world_x, int world_y) { | ||
503 | const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x); | ||
504 | const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y); | ||
505 | const ivec2 screen_origin = | ||
506 | ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); | ||
507 | const ivec2 origin_view_space = ivec2_add(screen_origin, ivec2_neg(camera)); | ||
508 | return origin_view_space; | ||
509 | } | ||
510 | |||
511 | static Pixel alpha_blend(Pixel src, Pixel dst) { | 519 | static Pixel alpha_blend(Pixel src, Pixel dst) { |
512 | if ((src.a == 255) || (dst.a == 0)) { | 520 | if ((src.a == 255) || (dst.a == 0)) { |
513 | return src; | 521 | return src; |
@@ -590,7 +598,7 @@ static void draw_tile(IsoGfx* iso, ivec2 screen_origin, Tile tile) { | |||
590 | &iso->screen, top_left, pTile->width, pTile->height, pixels, nullptr); | 598 | &iso->screen, top_left, pTile->width, pTile->height, pixels, nullptr); |
591 | } | 599 | } |
592 | 600 | ||
593 | static void draw_world(IsoGfx* iso) { | 601 | static void draw_map(IsoGfx* iso) { |
594 | assert(iso); | 602 | assert(iso); |
595 | 603 | ||
596 | const int W = iso->screen.width; | 604 | const int W = iso->screen.width; |
@@ -607,17 +615,15 @@ static void draw_world(IsoGfx* iso) { | |||
607 | // screen-centric approach would juggle multiple tiles throughout the scan. | 615 | // screen-centric approach would juggle multiple tiles throughout the scan. |
608 | for (int wy = 0; wy < iso->map->world_height; ++wy) { | 616 | for (int wy = 0; wy < iso->map->world_height; ++wy) { |
609 | for (int wx = 0; wx < iso->map->world_width; ++wx) { | 617 | for (int wx = 0; wx < iso->map->world_width; ++wx) { |
610 | const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); | 618 | const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); |
611 | const ivec2 screen_origin = | 619 | const ivec2 screen_origin = iso2cart(iso->iso_space, iso->camera, wx, wy); |
612 | GetTileScreenOrigin(iso->iso_space, iso->camera, wx, wy); | ||
613 | draw_tile(iso, screen_origin, tile); | 620 | draw_tile(iso, screen_origin, tile); |
614 | } | 621 | } |
615 | } | 622 | } |
616 | } | 623 | } |
617 | 624 | ||
618 | static void draw_sprite( | 625 | static void draw_sprite( |
619 | IsoGfx* iso, ivec2 origin, const SpriteInstance* sprite, | 626 | IsoGfx* iso, const SpriteInstance* sprite, const Ss_SpriteSheet* sheet) { |
620 | const Ss_SpriteSheet* sheet) { | ||
621 | assert(iso); | 627 | assert(iso); |
622 | assert(sprite); | 628 | assert(sprite); |
623 | assert(sheet); | 629 | assert(sheet); |
@@ -625,10 +631,18 @@ static void draw_sprite( | |||
625 | assert(sprite->animation < sheet->num_rows); | 631 | assert(sprite->animation < sheet->num_rows); |
626 | assert(sprite->frame >= 0); | 632 | assert(sprite->frame >= 0); |
627 | 633 | ||
634 | // Apply an offset similarly to how we offset tiles. The sprite is offset by | ||
635 | // -base_tile_width/2 along the x-axis to align the sprite with the leftmost | ||
636 | // edge of the tile it is on. | ||
637 | const ivec2 screen_origin = iso2cart( | ||
638 | iso->iso_space, iso->camera, sprite->position.x, sprite->position.y); | ||
639 | const ivec2 offset = {-(iso->map->base_tile_width / 2), 0}; | ||
640 | const ivec2 top_left = ivec2_add(screen_origin, offset); | ||
641 | |||
628 | const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); | 642 | const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); |
629 | const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); | 643 | const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); |
630 | draw_rect( | 644 | draw_rect( |
631 | &iso->screen, origin, sheet->sprite_width, sheet->sprite_height, | 645 | &iso->screen, top_left, sheet->sprite_width, sheet->sprite_height, |
632 | sheet->palette.colours, frame); | 646 | sheet->palette.colours, frame); |
633 | } | 647 | } |
634 | 648 | ||
@@ -639,10 +653,7 @@ static void draw_sprites(IsoGfx* iso) { | |||
639 | sprite = sprite->next) { | 653 | sprite = sprite->next) { |
640 | const Ss_SpriteSheet* sheet = sprite->sheet; | 654 | const Ss_SpriteSheet* sheet = sprite->sheet; |
641 | assert(sheet); | 655 | assert(sheet); |
642 | 656 | draw_sprite(iso, sprite, sheet); | |
643 | const ivec2 screen_origin = GetTileScreenOrigin( | ||
644 | iso->iso_space, iso->camera, sprite->position.x, sprite->position.y); | ||
645 | draw_sprite(iso, screen_origin, sprite, sheet); | ||
646 | } | 657 | } |
647 | } | 658 | } |
648 | 659 | ||
@@ -653,7 +664,7 @@ void isogfx_set_camera(IsoGfx* iso, int x, int y) { | |||
653 | 664 | ||
654 | void isogfx_render(IsoGfx* iso) { | 665 | void isogfx_render(IsoGfx* iso) { |
655 | assert(iso); | 666 | assert(iso); |
656 | draw_world(iso); | 667 | draw_map(iso); |
657 | draw_sprites(iso); | 668 | draw_sprites(iso); |
658 | } | 669 | } |
659 | 670 | ||
@@ -664,8 +675,7 @@ void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) { | |||
664 | assert(x < iso->map->world_width); | 675 | assert(x < iso->map->world_width); |
665 | assert(y < iso->map->world_height); | 676 | assert(y < iso->map->world_height); |
666 | 677 | ||
667 | const ivec2 screen_origin = | 678 | const ivec2 screen_origin = iso2cart(iso->iso_space, iso->camera, x, y); |
668 | GetTileScreenOrigin(iso->iso_space, iso->camera, x, y); | ||
669 | draw_tile(iso, screen_origin, tile); | 679 | draw_tile(iso, screen_origin, tile); |
670 | } | 680 | } |
671 | 681 | ||
diff --git a/tools/mkasset.py b/tools/mkasset.py index 9b9dc76..f21a2f9 100644 --- a/tools/mkasset.py +++ b/tools/mkasset.py | |||
@@ -13,6 +13,7 @@ | |||
13 | import argparse | 13 | import argparse |
14 | import ctypes | 14 | import ctypes |
15 | import sys | 15 | import sys |
16 | from enum import IntEnum | ||
16 | from typing import Generator | 17 | from typing import Generator |
17 | from xml.etree import ElementTree | 18 | from xml.etree import ElementTree |
18 | 19 | ||
@@ -23,6 +24,12 @@ from PIL import Image | |||
23 | MAX_PATH_LENGTH = 128 | 24 | MAX_PATH_LENGTH = 128 |
24 | 25 | ||
25 | 26 | ||
27 | class Orientation(IntEnum): | ||
28 | """Map orientation. Must match Tm_Orientation in asset.h""" | ||
29 | Orthogonal = 0 | ||
30 | Isometric = 1 | ||
31 | |||
32 | |||
26 | def drop_extension(filepath): | 33 | def drop_extension(filepath): |
27 | return filepath[:filepath.rfind('.')] | 34 | return filepath[:filepath.rfind('.')] |
28 | 35 | ||
@@ -51,14 +58,9 @@ def carve_image(rgba_bytes, tile_width, tile_height, columns) -> Generator[bytea | |||
51 | image_width = columns * tile_width | 58 | image_width = columns * tile_width |
52 | image_height = len(rgba_bytes) // image_width // 4 | 59 | image_height = len(rgba_bytes) // image_width // 4 |
53 | 60 | ||
54 | tiles_x = image_width // tile_width | ||
55 | tiles_y = image_height // tile_height | ||
56 | |||
57 | tile_bytes = bytearray(tile_width * tile_height * 4) | 61 | tile_bytes = bytearray(tile_width * tile_height * 4) |
58 | for i in range(tiles_y): | 62 | for image_y0 in range(0, image_height, tile_height): # y-origin of tile inside image |
59 | image_y0 = i * tile_height # y-origin of tile inside image | 63 | for image_x0 in range(0, image_width, tile_width): # x-origin of tile inside image |
60 | for j in range(tiles_x): | ||
61 | image_x0 = j * tile_width # x-origin of tile inside image | ||
62 | for y in range(tile_height): | 64 | for y in range(tile_height): |
63 | image_y = image_y0 + y # y of current pixel inside image | 65 | image_y = image_y0 + y # y of current pixel inside image |
64 | for x in range(tile_width): | 66 | for x in range(tile_width): |
@@ -183,11 +185,13 @@ def convert_tmx(input_filepath, output_filepath): | |||
183 | base_tile_width = int(root.attrib["tilewidth"]) | 185 | base_tile_width = int(root.attrib["tilewidth"]) |
184 | base_tile_height = int(root.attrib["tileheight"]) | 186 | base_tile_height = int(root.attrib["tileheight"]) |
185 | num_layers = 1 | 187 | num_layers = 1 |
188 | flags = Orientation.Isometric if (root.attrib["orientation"] == "isometric") else Orientation.Orthogonal | ||
186 | 189 | ||
187 | print(f"Map width: {map_width}") | 190 | print(f"Map width: {map_width}") |
188 | print(f"Map height: {map_height}") | 191 | print(f"Map height: {map_height}") |
189 | print(f"Tile width: {base_tile_width}") | 192 | print(f"Tile width: {base_tile_width}") |
190 | print(f"Tile height: {base_tile_height}") | 193 | print(f"Tile height: {base_tile_height}") |
194 | print(f"Orientation: {flags}") | ||
191 | 195 | ||
192 | tileset_path = None | 196 | tileset_path = None |
193 | 197 | ||
@@ -210,6 +214,7 @@ def convert_tmx(input_filepath, output_filepath): | |||
210 | output.write(ctypes.c_uint16(base_tile_width)) | 214 | output.write(ctypes.c_uint16(base_tile_width)) |
211 | output.write(ctypes.c_uint16(base_tile_height)) | 215 | output.write(ctypes.c_uint16(base_tile_height)) |
212 | output.write(ctypes.c_uint16(num_layers)) | 216 | output.write(ctypes.c_uint16(num_layers)) |
217 | output.write(ctypes.c_uint16(flags)) | ||
213 | elif child.tag == "layer": | 218 | elif child.tag == "layer": |
214 | layer = child | 219 | layer = child |
215 | layer_id = int(layer.attrib["id"]) | 220 | layer_id = int(layer.attrib["id"]) |
@@ -349,25 +354,16 @@ def convert_sprite_sheet(input_file_paths, sprite_width, sprite_height, | |||
349 | # that. getcolors() returns the number of unique colors. | 354 | # that. getcolors() returns the number of unique colors. |
350 | # getpalette() also returns a flattened list, which is why we must *4. | 355 | # getpalette() also returns a flattened list, which is why we must *4. |
351 | num_colours = len(im.getcolors()) | 356 | num_colours = len(im.getcolors()) |
352 | colours = im.getpalette(rawmode="RGBA")[:4 * num_colours] | 357 | palette = bytearray(im.getpalette(rawmode="RGBA")[:4 * num_colours]) |
353 | # TODO: This palette list does not seem really necessary. | 358 | assert (num_colours == (len(palette) // 4)) |
354 | # Define palette = bytearray(im.getpalette(...)) | ||
355 | palette = [] | ||
356 | for i in range(0, 4 * num_colours, 4): | ||
357 | palette.append((colours[i], colours[i + 1], colours[i + 2], | ||
358 | colours[i + 3])) | ||
359 | 359 | ||
360 | output.write(ctypes.c_uint16(len(palette))) | 360 | output.write(ctypes.c_uint16(num_colours)) |
361 | output.write(bytearray(colours)) | 361 | output.write(palette) |
362 | 362 | ||
363 | print(f"Sprite width: {sprite_width}") | 363 | print(f"Sprite width: {sprite_width}") |
364 | print(f"Sprite height: {sprite_height}") | 364 | print(f"Sprite height: {sprite_height}") |
365 | print(f"Rows: {len(rows)}") | 365 | print(f"Rows: {len(rows)}") |
366 | print(f"Colours: {len(palette)}") | 366 | print(f"Colours: {num_colours}") |
367 | |||
368 | # print("Palette") | ||
369 | # for i, colour in enumerate(palette): | ||
370 | # print(f"{i}: {colour}") | ||
371 | 367 | ||
372 | for row, num_columns in enumerate(rows): | 368 | for row, num_columns in enumerate(rows): |
373 | output.write(ctypes.c_uint16(num_columns)) | 369 | output.write(ctypes.c_uint16(num_columns)) |