summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/isogfx/asset.h132
-rw-r--r--src/isogfx.c129
2 files changed, 142 insertions, 119 deletions
diff --git a/include/isogfx/asset.h b/include/isogfx/asset.h
new file mode 100644
index 0000000..298c469
--- /dev/null
+++ b/include/isogfx/asset.h
@@ -0,0 +1,132 @@
1/*
2 * File format definitions for isogfx assets.
3 *
4 * All formats are defined so that they can be simply read into memory and used
5 * by the engine. Likewise, a tool that generates these formats can generate
6 * the structures in memory and then write them as is to a file.
7 */
8#pragma once
9
10#include <assert.h>
11#include <stdint.h>
12
13// Maximum length of path strings in .TS and .TM files.
14#define ISOGFX_MAX_PATH_LENGTH 128
15
16// -----------------------------------------------------------------------------
17// Tile set (TS) file format.
18// -----------------------------------------------------------------------------
19
20typedef struct Ts_Tile {
21 uint16_t width; // Tile width in pixels.
22 uint16_t height; // Tile height in pixels.
23 Pixel pixels[1]; // Count: width * height.
24} Ts_Tile;
25
26typedef struct Ts_TileSet {
27 uint16_t num_tiles;
28 uint16_t max_tile_width; // Maximum tile width in pixels.
29 uint16_t max_tile_height; // Maximum tile height in pixels.
30 Ts_Tile tiles[1]; // Count: num_tiles.
31} Ts_TileSet;
32
33// -----------------------------------------------------------------------------
34// Tile map (TM) file format.
35// -----------------------------------------------------------------------------
36
37typedef struct Tm_Layer {
38 union {
39 char tileset_path[ISOGFX_MAX_PATH_LENGTH]; // Relative to the Tm_Map file.
40 };
41 Tile tiles[1]; // Count: world_width * world_height.
42} Tm_Layer;
43
44typedef struct Tm_Map {
45 uint16_t world_width; // World width in number of tiles.
46 uint16_t world_height; // World height in number of tiles.
47 uint16_t base_tile_width;
48 uint16_t base_tile_height;
49 uint16_t num_layers;
50 Tm_Layer layers[1]; // Count: num_layers.
51} Tm_Map;
52
53// -----------------------------------------------------------------------------
54// Sprite sheet file format.
55// -----------------------------------------------------------------------------
56
57/// A row of sprites in a sprite sheet.
58///
59/// Each row in a sprite sheet can have a different number of columns.
60///
61/// The pixels of the row follow a "sprite-major" order. It contains the
62/// 'sprite_width * sprite_height' pixels for the first column/sprite, then the
63/// second column/sprite, etc.
64///
65/// Pixels are 8-bit indices into the sprite sheet's colour palette.
66typedef struct Ss_Row {
67 uint16_t num_cols; /// Number of columns in this row.
68 uint8_t pixels[1]; /// Count: num_cols * sprite_width * sprite_height.
69} Ss_Row;
70
71typedef struct Ss_Palette {
72 uint16_t num_colours;
73 Pixel colours[1]; /// Count: num_colors.
74} Ss_Palette;
75
76/// Sprite sheet top-level data definition.
77///
78/// Sprite width and height are assumed constant throughout the sprite sheet.
79typedef struct Ss_SpriteSheet {
80 uint16_t sprite_width; /// Sprite width in pixels.
81 uint16_t sprite_height; /// Sprite height in pixels.
82 uint16_t num_rows;
83 Ss_Palette palette; /// Variable size.
84 Ss_Row rows[1]; /// Count: num_rows. Variable offset.
85} Ss_SpriteSheet;
86
87// -----------------------------------------------------------------------------
88// Data accessors.
89// -----------------------------------------------------------------------------
90
91/// Return the next tile in the tile set.
92static inline const Ts_Tile* ts_tileset_get_next_tile(
93 const Ts_TileSet* tileset, const Ts_Tile* tile) {
94 assert(tileset);
95 assert(tile);
96 return (const Ts_Tile*)((const uint8_t*)tile + sizeof(Ts_Tile) +
97 ((tile->width * tile->height - 1) * sizeof(Pixel)));
98}
99
100/// Return the next layer in the tile map.
101static inline const Tm_Layer* tm_map_get_next_layer(
102 const Tm_Map* map, const Tm_Layer* layer) {
103 assert(map);
104 assert(layer);
105 return (const Tm_Layer*)((const uint8_t*)layer + sizeof(Tm_Layer) +
106 ((map->world_width * map->world_height - 1) *
107 sizeof(Tile)));
108}
109
110/// Return the ith row in the sprite sheet.
111static inline const Ss_Row* get_sprite_sheet_row(
112 const Ss_SpriteSheet* sheet, int row) {
113 assert(sheet);
114 assert(row >= 0);
115 assert(row < sheet->num_rows);
116 // Skip over the palette.
117 const Ss_Row* rows =
118 (const Ss_Row*)(&sheet->palette.colours[0] + sheet->palette.num_colours);
119 return &rows[row];
120}
121
122/// Return the ith sprite in the row.
123static inline const uint8_t* get_sprite_sheet_sprite(
124 const Ss_SpriteSheet* sheet, const Ss_Row* row, int col) {
125 assert(sheet);
126 assert(row);
127 assert(col >= 0);
128 assert(col < row->num_cols);
129 const int sprite_offset = col * sheet->sprite_width * sheet->sprite_height;
130 const uint8_t* sprite = &row->pixels[sprite_offset];
131 return sprite;
132}
diff --git a/src/isogfx.c b/src/isogfx.c
index 52c4ae2..baf422f 100644
--- a/src/isogfx.c
+++ b/src/isogfx.c
@@ -1,5 +1,7 @@
1#include <isogfx/isogfx.h> 1#include <isogfx/isogfx.h>
2 2
3#include <isogfx/asset.h>
4
3#include <filesystem.h> 5#include <filesystem.h>
4#include <mem.h> 6#include <mem.h>
5#include <mempool.h> 7#include <mempool.h>
@@ -38,115 +40,6 @@ typedef struct vec2 {
38} vec2; 40} vec2;
39 41
40// ----------------------------------------------------------------------------- 42// -----------------------------------------------------------------------------
41// Tile set (TS) and tile map (TM) file formats.
42// -----------------------------------------------------------------------------
43
44/// Maximum length of path strings in .TS and .TM files.
45#define MAX_PATH_LENGTH 128
46
47typedef struct Ts_Tile {
48 uint16_t width; /// Tile width in pixels.
49 uint16_t height; /// Tile height in pixels.
50 Pixel pixels[1]; /// Count: width * height.
51} Ts_Tile;
52
53typedef struct Ts_TileSet {
54 uint16_t num_tiles;
55 uint16_t max_tile_width; /// Maximum tile width in pixels.
56 uint16_t max_tile_height; /// Maximum tile height in pixels.
57 Ts_Tile tiles[1]; /// Count: num_tiles.
58} Ts_TileSet;
59
60typedef struct Tm_Layer {
61 union {
62 char tileset_path[MAX_PATH_LENGTH]; // Relative to the Tm_Map file.
63 };
64 Tile tiles[1]; /// Count: world_width * world_height.
65} Tm_Layer;
66
67typedef struct Tm_Map {
68 uint16_t world_width; /// World width in number of tiles.
69 uint16_t world_height; /// World height in number of tiles.
70 uint16_t base_tile_width;
71 uint16_t base_tile_height;
72 uint16_t num_layers;
73 Tm_Layer layers[1]; // Count: num_layers.
74} Tm_Map;
75
76static inline const Tm_Layer* tm_map_get_next_layer(
77 const Tm_Map* map, const Tm_Layer* layer) {
78 assert(map);
79 assert(layer);
80 return (const Tm_Layer*)((const uint8_t*)layer + sizeof(Tm_Layer) +
81 ((map->world_width * map->world_height - 1) *
82 sizeof(Tile)));
83}
84
85static inline const Ts_Tile* ts_tileset_get_next_tile(
86 const Ts_TileSet* tileset, const Ts_Tile* tile) {
87 assert(tileset);
88 assert(tile);
89 return (const Ts_Tile*)((const uint8_t*)tile + sizeof(Ts_Tile) +
90 ((tile->width * tile->height - 1) * sizeof(Pixel)));
91}
92
93// -----------------------------------------------------------------------------
94// Sprite sheet file format.
95// -----------------------------------------------------------------------------
96
97/// A row of sprites in a sprite sheet.
98///
99/// Each row in a sprite sheet can have a different number of columns.
100///
101/// The pixels of the row follow a "sprite-major" order. It contains the
102/// 'sprite_width * sprite_height' pixels for the first column/sprite, then the
103/// second column/sprite, etc.
104///
105/// Pixels are 8-bit indices into the sprite sheet's colour palette.
106typedef struct Ss_Row {
107 uint16_t num_cols; /// Number of columns in this row.
108 uint8_t pixels[1]; /// Count: num_cols * sprite_width * sprite_height.
109} Ss_Row;
110
111typedef struct Ss_Palette {
112 uint16_t num_colours;
113 Pixel colours[1]; /// Count: num_colors.
114} Ss_Palette;
115
116/// Sprite sheet top-level data definition.
117///
118/// Sprite width and height are assumed constant throughout the sprite sheet.
119typedef struct Ss_SpriteSheet {
120 uint16_t sprite_width; /// Sprite width in pixels.
121 uint16_t sprite_height; /// Sprite height in pixels.
122 uint16_t num_rows;
123 Ss_Palette palette; /// Variable size.
124 Ss_Row rows[1]; /// Count: num_rows. Variable offset.
125} Ss_SpriteSheet;
126
127static inline const Ss_Row* get_sprite_sheet_row(
128 const Ss_SpriteSheet* sheet, int row) {
129 assert(sheet);
130 assert(row >= 0);
131 assert(row < sheet->num_rows);
132 // Skip over the palette.
133 const Ss_Row* rows =
134 (const Ss_Row*)(&sheet->palette.colours[0] + sheet->palette.num_colours);
135 return &rows[row];
136}
137
138static inline const uint8_t* get_sprite_sheet_sprite(
139 const Ss_SpriteSheet* sheet, const Ss_Row* row, int col) {
140 assert(sheet);
141 assert(row);
142 assert(col >= 0);
143 assert(col < row->num_cols);
144 const int sprite_offset = col * sheet->sprite_width * sheet->sprite_height;
145 const uint8_t* sprite = &row->pixels[sprite_offset];
146 return sprite;
147}
148
149// -----------------------------------------------------------------------------
150// Renderer state. 43// Renderer state.
151// ----------------------------------------------------------------------------- 44// -----------------------------------------------------------------------------
152 45
@@ -204,8 +97,8 @@ static inline ivec2 ivec2_scale(ivec2 a, int s) {
204} 97}
205 98
206static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { 99static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) {
207 return (ivec2){ 100 return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2),
208 .x = (iso.x - iso.y) * (s / 2) + (w / 2), .y = (iso.x + iso.y) * (t / 2)}; 101 .y = (iso.x + iso.y) * (t / 2)};
209} 102}
210 103
211// Method 1. 104// Method 1.
@@ -221,9 +114,8 @@ static inline vec2 cart2iso(vec2 cart, int s, int t, int w) {
221 const double one_over_s = 1. / (double)s; 114 const double one_over_s = 1. / (double)s;
222 const double one_over_t = 1. / (double)t; 115 const double one_over_t = 1. / (double)t;
223 const double x = cart.x - (double)(w / 2); 116 const double x = cart.x - (double)(w / 2);
224 return (vec2){ 117 return (vec2){.x = (one_over_s * x + one_over_t * cart.y),
225 .x = (one_over_s * x + one_over_t * cart.y), 118 .y = (-one_over_s * x + one_over_t * cart.y)};
226 .y = (-one_over_s * x + one_over_t * cart.y)};
227} 119}
228 120
229static const Pixel* tile_xy_const_ref( 121static const Pixel* tile_xy_const_ref(
@@ -752,11 +644,10 @@ static Pixel alpha_blend(Pixel src, Pixel dst) {
752 (double)((uint16_t)s * (uint16_t)src.a + \ 644 (double)((uint16_t)s * (uint16_t)src.a + \
753 (uint16_t)d * one_minus_alpha) / \ 645 (uint16_t)d * one_minus_alpha) / \
754 255.0) 646 255.0)
755 return (Pixel){ 647 return (Pixel){.r = blend(src.r, dst.r),
756 .r = blend(src.r, dst.r), 648 .g = blend(src.g, dst.g),
757 .g = blend(src.g, dst.g), 649 .b = blend(src.b, dst.b),
758 .b = blend(src.b, dst.b), 650 .a = src.a};
759 .a = src.a};
760} 651}
761 652
762/// Draw a rectangle (tile or sprite). 653/// Draw a rectangle (tile or sprite).