diff options
author | 3gg <3gg@shellblade.net> | 2023-07-26 08:39:37 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2023-07-26 08:39:37 -0700 |
commit | cef3385c2bee0b098a7795548345a9281ace008e (patch) | |
tree | b594e9cc151a4ae7fd8b5732cf349eb01f37683d /gfx-iso/src | |
parent | 48cef82988d6209987ae27fe29b72d7d5e402b3c (diff) |
Add support for paletted sprites.
Diffstat (limited to 'gfx-iso/src')
-rw-r--r-- | gfx-iso/src/isogfx.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/gfx-iso/src/isogfx.c b/gfx-iso/src/isogfx.c index 9ba1bec..4568375 100644 --- a/gfx-iso/src/isogfx.c +++ b/gfx-iso/src/isogfx.c | |||
@@ -100,26 +100,49 @@ static inline const Ts_Tile* ts_tileset_get_next_tile( | |||
100 | /// The pixels of the row follow a "sprite-major" order. It contains the | 100 | /// The pixels of the row follow a "sprite-major" order. It contains the |
101 | /// 'sprite_width * sprite_height' pixels for the first column/sprite, then the | 101 | /// 'sprite_width * sprite_height' pixels for the first column/sprite, then the |
102 | /// second column/sprite, etc. | 102 | /// second column/sprite, etc. |
103 | /// | ||
104 | /// Pixels are 8-bit indices into the sprite sheet's colour palette. | ||
103 | typedef struct Ss_Row { | 105 | typedef struct Ss_Row { |
104 | uint16_t num_cols; /// Number of columns in this row. | 106 | uint16_t num_cols; /// Number of columns in this row. |
105 | Pixel pixels[1]; /// Count: num_cols * sprite_width * sprite_height. | 107 | uint8_t pixels[1]; /// Count: num_cols * sprite_width * sprite_height. |
106 | } Ss_Row; | 108 | } Ss_Row; |
107 | 109 | ||
110 | typedef struct Ss_Palette { | ||
111 | uint16_t num_colours; | ||
112 | Pixel colours[1]; /// Count: num_colors. | ||
113 | } Ss_Palette; | ||
114 | |||
108 | /// Sprite sheet top-level data definition. | 115 | /// Sprite sheet top-level data definition. |
109 | /// | 116 | /// |
110 | /// Sprite width and height are assumed constant throughout the sprite sheet. | 117 | /// Sprite width and height are assumed constant throughout the sprite sheet. |
111 | typedef struct Ss_SpriteSheet { | 118 | typedef struct Ss_SpriteSheet { |
112 | uint16_t sprite_width; /// Sprite width in pixels. | 119 | uint16_t sprite_width; /// Sprite width in pixels. |
113 | uint16_t sprite_height; /// Sprite height in pixels. | 120 | uint16_t sprite_height; /// Sprite height in pixels. |
114 | uint16_t num_rows; | 121 | uint16_t num_rows; |
115 | Ss_Row rows[1]; /// Count: num_rows. | 122 | Ss_Palette palette; /// Variable size. |
123 | Ss_Row rows[1]; /// Count: num_rows. Variable offset. | ||
116 | } Ss_SpriteSheet; | 124 | } Ss_SpriteSheet; |
117 | 125 | ||
118 | const Ss_Row* get_sprite_sheet_row(const Ss_SpriteSheet* sheet, int row) { | 126 | static inline const Ss_Row* get_sprite_sheet_row( |
127 | const Ss_SpriteSheet* sheet, int row) { | ||
119 | assert(sheet); | 128 | assert(sheet); |
120 | assert(row >= 0); | 129 | assert(row >= 0); |
121 | assert(row < sheet->num_rows); | 130 | assert(row < sheet->num_rows); |
122 | return &sheet->rows[row]; | 131 | // Skip over the palette. |
132 | const Ss_Row* rows = | ||
133 | (const Ss_Row*)(&sheet->palette.colours[0] + sheet->palette.num_colours); | ||
134 | return &rows[row]; | ||
135 | } | ||
136 | |||
137 | static inline const uint8_t* get_sprite_sheet_sprite( | ||
138 | const Ss_SpriteSheet* sheet, const Ss_Row* row, int col) { | ||
139 | assert(sheet); | ||
140 | assert(row); | ||
141 | assert(col >= 0); | ||
142 | assert(col < row->num_cols); | ||
143 | const int sprite_offset = col * sheet->sprite_width * sheet->sprite_height; | ||
144 | const uint8_t* sprite = &row->pixels[sprite_offset]; | ||
145 | return sprite; | ||
123 | } | 146 | } |
124 | 147 | ||
125 | // ----------------------------------------------------------------------------- | 148 | // ----------------------------------------------------------------------------- |
@@ -732,11 +755,19 @@ static Pixel alpha_blend(Pixel src, Pixel dst) { | |||
732 | /// | 755 | /// |
733 | /// The rectangle's pixels are assumed to be arranged in a linear, row-major | 756 | /// The rectangle's pixels are assumed to be arranged in a linear, row-major |
734 | /// fashion. | 757 | /// fashion. |
758 | /// | ||
759 | /// If indices are given, then the image is assumed to be colour-paletted, where | ||
760 | /// 'pixels' is the palette and 'indices' the pixel indices. Otherwise, the | ||
761 | /// image is assumed to be in plain RGBA format. | ||
735 | static void draw_rect( | 762 | static void draw_rect( |
736 | IsoGfx* iso, ivec2 origin, int rect_width, int rect_height, | 763 | IsoGfx* iso, ivec2 origin, int rect_width, int rect_height, |
737 | const Pixel* pixels) { | 764 | const Pixel* pixels, const uint8_t* indices) { |
738 | assert(iso); | 765 | assert(iso); |
739 | 766 | ||
767 | #define rect_pixel(x, y) \ | ||
768 | (indices ? pixels[indices[py * rect_width + px]] \ | ||
769 | : pixels[py * rect_width + px]) | ||
770 | |||
740 | // Rect can exceed screen bounds, so we must clip it. | 771 | // Rect can exceed screen bounds, so we must clip it. |
741 | #define max(a, b) (a > b ? a : b) | 772 | #define max(a, b) (a > b ? a : b) |
742 | const int py_offset = max(0, rect_height - origin.y); | 773 | const int py_offset = max(0, rect_height - origin.y); |
@@ -748,7 +779,7 @@ static void draw_rect( | |||
748 | const int sy = origin.y + py - py_offset; | 779 | const int sy = origin.y + py - py_offset; |
749 | for (int px = 0; (px < rect_width) && (origin.x + px < iso->screen_width); | 780 | for (int px = 0; (px < rect_width) && (origin.x + px < iso->screen_width); |
750 | ++px) { | 781 | ++px) { |
751 | const Pixel colour = pixels[py * rect_width + px]; | 782 | const Pixel colour = rect_pixel(px, py); |
752 | if (colour.a > 0) { | 783 | if (colour.a > 0) { |
753 | const int sx = origin.x + px; | 784 | const int sx = origin.x + px; |
754 | const Pixel dst = screen_xy(iso, sx, sy); | 785 | const Pixel dst = screen_xy(iso, sx, sy); |
@@ -767,7 +798,7 @@ static void draw_tile(IsoGfx* iso, ivec2 origin, Tile tile) { | |||
767 | 798 | ||
768 | const Pixel* pixels = tile_xy_const_ref(iso, tile_data, 0, 0); | 799 | const Pixel* pixels = tile_xy_const_ref(iso, tile_data, 0, 0); |
769 | 800 | ||
770 | draw_rect(iso, origin, tile_data->width, tile_data->height, pixels); | 801 | draw_rect(iso, origin, tile_data->width, tile_data->height, pixels, 0); |
771 | } | 802 | } |
772 | 803 | ||
773 | static void draw(IsoGfx* iso) { | 804 | static void draw(IsoGfx* iso) { |
@@ -807,15 +838,11 @@ static void draw_sprite( | |||
807 | assert(sprite->animation < sheet->num_rows); | 838 | assert(sprite->animation < sheet->num_rows); |
808 | assert(sprite->frame >= 0); | 839 | assert(sprite->frame >= 0); |
809 | 840 | ||
810 | const SpriteSheetRow* ss_row = &sheet->rows[sprite->animation]; | 841 | const SpriteSheetRow* row = get_sprite_sheet_row(sheet, sprite->animation); |
811 | assert(sprite->frame < ss_row->num_cols); | 842 | const uint8_t* frame = get_sprite_sheet_sprite(sheet, row, sprite->frame); |
812 | 843 | draw_rect( | |
813 | const int sprite_offset = | 844 | iso, origin, sheet->sprite_width, sheet->sprite_height, |
814 | sprite->frame * sheet->sprite_width * sheet->sprite_height; | 845 | sheet->palette.colours, frame); |
815 | |||
816 | const Pixel* frame = &ss_row->pixels[sprite_offset]; | ||
817 | |||
818 | draw_rect(iso, origin, sheet->sprite_width, sheet->sprite_height, frame); | ||
819 | } | 846 | } |
820 | 847 | ||
821 | static void draw_sprites(IsoGfx* iso) { | 848 | static void draw_sprites(IsoGfx* iso) { |