diff options
| author | Bad Diode <bd@badd10de.dev> | 2024-02-05 12:26:47 +0100 |
|---|---|---|
| committer | Bad Diode <bd@badd10de.dev> | 2024-02-05 12:26:47 +0100 |
| commit | a93591e58262917dca7011cb5fa06695c84bbdf5 (patch) | |
| tree | 8d958a201c041cf45ff2c97e30a35889c96fed3e | |
| parent | 41a6b3d259d7bd886a15bd7f033c74c6a3d53b52 (diff) | |
| download | gba-dev-tools-main.tar.gz gba-dev-tools-main.zip | |
| -rw-r--r-- | img2gba/Makefile (renamed from sprite2gba/Makefile) | 2 | ||||
| -rw-r--r-- | img2gba/src/main.c (renamed from sprite2gba/src/main.c) | 130 | ||||
| -rw-r--r-- | img2gba/src/shorthand.h (renamed from sprite2gba/src/shorthand.h) | 0 | ||||
| -rw-r--r-- | img2gba/src/stb_image.h (renamed from sprite2gba/src/stb_image.h) | 4 |
4 files changed, 97 insertions, 39 deletions
diff --git a/sprite2gba/Makefile b/img2gba/Makefile index 0d6dc07..f374ea9 100644 --- a/sprite2gba/Makefile +++ b/img2gba/Makefile | |||
| @@ -9,7 +9,7 @@ WATCH_SRC := $(wildcard $(SRC_DIR)/*.c) | |||
| 9 | WATCH_SRC += $(wildcard $(SRC_DIR)/*.h) | 9 | WATCH_SRC += $(wildcard $(SRC_DIR)/*.h) |
| 10 | 10 | ||
| 11 | # Output library names and executables. | 11 | # Output library names and executables. |
| 12 | BIN_NAME := sprite2gba | 12 | BIN_NAME := img2gba |
| 13 | BUILD_DIR := build | 13 | BUILD_DIR := build |
| 14 | BIN := $(BUILD_DIR)/$(BIN_NAME) | 14 | BIN := $(BUILD_DIR)/$(BIN_NAME) |
| 15 | 15 | ||
diff --git a/sprite2gba/src/main.c b/img2gba/src/main.c index f91ecd0..8a5edfc 100644 --- a/sprite2gba/src/main.c +++ b/img2gba/src/main.c | |||
| @@ -6,8 +6,9 @@ | |||
| 6 | #include "stb_image.h" | 6 | #include "stb_image.h" |
| 7 | 7 | ||
| 8 | #define TILE_SIZE 8 | 8 | #define TILE_SIZE 8 |
| 9 | #define DEFAULT_PALETTE_SIZE 16 | 9 | #define PALETTE_SIZE 16 |
| 10 | #define DEFAULT_BG_COLOR 0x0000 | 10 | #define DEFAULT_BG_COLOR 0x0000 |
| 11 | #define MAX_FILE_NAME 1024 | ||
| 11 | 12 | ||
| 12 | typedef u16 Color; | 13 | typedef u16 Color; |
| 13 | 14 | ||
| @@ -32,7 +33,7 @@ typedef struct Tiles { | |||
| 32 | } Tiles; | 33 | } Tiles; |
| 33 | 34 | ||
| 34 | typedef struct Palette { | 35 | typedef struct Palette { |
| 35 | Color *data; | 36 | Color data[PALETTE_SIZE]; |
| 36 | size_t size; | 37 | size_t size; |
| 37 | size_t capacity; | 38 | size_t capacity; |
| 38 | } Palette; | 39 | } Palette; |
| @@ -48,22 +49,22 @@ u8 | |||
| 48 | pack_1bb(u32 hex) { | 49 | pack_1bb(u32 hex) { |
| 49 | u32 low_nibble = hex & 0xFFFF; | 50 | u32 low_nibble = hex & 0xFFFF; |
| 50 | u32 high_nibble = (hex >> 16) & 0xFFFF; | 51 | u32 high_nibble = (hex >> 16) & 0xFFFF; |
| 51 | u32 low = (low_nibble & 0x1); | 52 | u32 low = ((low_nibble >> 12) & 0x1); |
| 52 | low += 2 * ((low_nibble >> 4) & 0x1); | 53 | low += 2 * ((low_nibble >> 8) & 0x1); |
| 53 | low += 4 * ((low_nibble >> 8) & 0x1); | 54 | low += 4 * ((low_nibble >> 4) & 0x1); |
| 54 | low += 8 * ((low_nibble >> 12) & 0x1); | 55 | low += 8 * ((low_nibble >> 0) & 0x1); |
| 55 | u32 high = (high_nibble & 0x1); | 56 | u32 high = ((high_nibble >> 12) & 0x1); |
| 56 | high += 2 * ((high_nibble >> 4) & 0x1); | 57 | high += 2 * ((high_nibble >> 8) & 0x1); |
| 57 | high += 4 * ((high_nibble >> 8) & 0x1); | 58 | high += 4 * ((high_nibble >> 4) & 0x1); |
| 58 | high += 8 * ((high_nibble >> 12) & 0x1); | 59 | high += 8 * ((high_nibble >> 0) & 0x1); |
| 59 | return (high << 4) | low; | 60 | return (low << 4) | high; |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | void | 63 | void |
| 63 | export_c_file(Tiles *tiles, Palette *palette, FILE *file, bool pack_1bpp) { | 64 | export_c_file(Tiles *tiles, Palette *palette, FILE *file, bool pack_1bpp) { |
| 64 | // Output tiles. | 65 | // Output tiles. |
| 65 | if (pack_1bpp) { | 66 | if (pack_1bpp) { |
| 66 | fprintf(file, "u32 packed_tiles[] = {\n "); | 67 | fprintf(file, "static const u32 packed_tiles[] = {\n "); |
| 67 | size_t counter = 0; | 68 | size_t counter = 0; |
| 68 | for (size_t i = 0; i < tiles->capacity; ++i) { | 69 | for (size_t i = 0; i < tiles->capacity; ++i) { |
| 69 | for (size_t j = 0; j < TILE_SIZE; j += 4, counter++) { | 70 | for (size_t j = 0; j < TILE_SIZE; j += 4, counter++) { |
| @@ -75,10 +76,10 @@ export_c_file(Tiles *tiles, Palette *palette, FILE *file, bool pack_1bpp) { | |||
| 75 | u32 tile_b = tiles->data[i][j + 1]; | 76 | u32 tile_b = tiles->data[i][j + 1]; |
| 76 | u32 tile_c = tiles->data[i][j + 2]; | 77 | u32 tile_c = tiles->data[i][j + 2]; |
| 77 | u32 tile_d = tiles->data[i][j + 3]; | 78 | u32 tile_d = tiles->data[i][j + 3]; |
| 78 | u32 packed = pack_1bb(tile_d); | 79 | u32 packed = pack_1bb(tile_d) << 0; |
| 79 | packed |= pack_1bb(tile_c) << 8; | 80 | packed |= pack_1bb(tile_c) << 8; |
| 80 | packed |= pack_1bb(tile_b) << 16; | 81 | packed |= pack_1bb(tile_b) << 16; |
| 81 | packed |= pack_1bb(tile_a) << 24; | 82 | packed |= pack_1bb(tile_a) << 24; |
| 82 | fprintf(file, "0x%08x,", packed); | 83 | fprintf(file, "0x%08x,", packed); |
| 83 | if (counter < 3) { | 84 | if (counter < 3) { |
| 84 | fprintf(file, " "); | 85 | fprintf(file, " "); |
| @@ -88,7 +89,7 @@ export_c_file(Tiles *tiles, Palette *palette, FILE *file, bool pack_1bpp) { | |||
| 88 | fprintf(file, "\n};\n"); | 89 | fprintf(file, "\n};\n"); |
| 89 | fprintf(file, "\n"); | 90 | fprintf(file, "\n"); |
| 90 | } else { | 91 | } else { |
| 91 | fprintf(file, "u32 tiles[%lu][%u] = {\n", tiles->capacity, TILE_SIZE); | 92 | fprintf(file, "static const u32 tiles[%lu][%u] = {\n", tiles->capacity, TILE_SIZE); |
| 92 | for (size_t i = 0; i < tiles->capacity; ++i) { | 93 | for (size_t i = 0; i < tiles->capacity; ++i) { |
| 93 | fprintf(file, " {"); | 94 | fprintf(file, " {"); |
| 94 | for (size_t j = 0; j < TILE_SIZE; ++j) { | 95 | for (size_t j = 0; j < TILE_SIZE; ++j) { |
| @@ -122,6 +123,36 @@ export_c_file(Tiles *tiles, Palette *palette, FILE *file, bool pack_1bpp) { | |||
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | void | 125 | void |
| 126 | export_bin_file(Tiles *tiles, Palette *palette, FILE *file, FILE *filepal, bool pack_1bpp) { | ||
| 127 | if (pack_1bpp) { | ||
| 128 | u64 counter = 0; | ||
| 129 | for (size_t i = 0; i < tiles->capacity; ++i) { | ||
| 130 | for (size_t j = 0; j < TILE_SIZE; j += 4, counter++) { | ||
| 131 | u32 tile_a = tiles->data[i][j]; | ||
| 132 | u32 tile_b = tiles->data[i][j + 1]; | ||
| 133 | u32 tile_c = tiles->data[i][j + 2]; | ||
| 134 | u32 tile_d = tiles->data[i][j + 3]; | ||
| 135 | u32 packed = pack_1bb(tile_a) << 0; | ||
| 136 | packed |= pack_1bb(tile_b) << 8; | ||
| 137 | packed |= pack_1bb(tile_c) << 16; | ||
| 138 | packed |= pack_1bb(tile_d) << 24; | ||
| 139 | fwrite(&packed, sizeof(u32), 1, file); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | // Pad with zeros to avoid alignment issues. | ||
| 143 | if (counter) { | ||
| 144 | u32 zero = 0; | ||
| 145 | fwrite(&zero, sizeof(u32), counter % 8, file); | ||
| 146 | } | ||
| 147 | } else { | ||
| 148 | for (size_t i = 0; i < tiles->capacity; ++i) { | ||
| 149 | fwrite(&tiles->data[i][0], sizeof(u32), TILE_SIZE, file); | ||
| 150 | } | ||
| 151 | fwrite(palette->data, sizeof(u16), PALETTE_SIZE, filepal); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | void | ||
| 125 | extract_tile(Tiles *tiles, Palette *palette, Image *img, | 156 | extract_tile(Tiles *tiles, Palette *palette, Image *img, |
| 126 | size_t offset_x, size_t offset_y) { | 157 | size_t offset_x, size_t offset_y) { |
| 127 | for (size_t j = 0; j < TILE_SIZE; ++j) { | 158 | for (size_t j = 0; j < TILE_SIZE; ++j) { |
| @@ -191,24 +222,24 @@ void | |||
| 191 | print_usage(void) { | 222 | print_usage(void) { |
| 192 | printf("Usage: %s [options] <filename>\n", BIN_NAME); | 223 | printf("Usage: %s [options] <filename>\n", BIN_NAME); |
| 193 | printf("\n"); | 224 | printf("\n"); |
| 194 | printf("\t-b <RRGGBB>\tSelects the background color used for transparency.\n"); | 225 | printf("\t-b <RRGGBB> Selects the background color used for transparency.\n"); |
| 195 | printf("\t-o <out_file.c>\tPath to the output file. If blank, stdout will be used.\n"); | 226 | printf("\t-o <out_file> Path to the output file. If blank, stdout will be used with C array export.\n"); |
| 196 | printf("\t-x <0>\tStart x position (in pixels).\n"); | 227 | printf("\t-x <0> Start x position (in pixels).\n"); |
| 197 | printf("\t-y <0>\tStart y position (in pixels).\n"); | 228 | printf("\t-y <0> Start y position (in pixels).\n"); |
| 198 | printf("\t-W <8>\tSelect the sprite width in pixels. Must be a multiple of the tile size.\n"); | 229 | printf("\t-W <8> Select the sprite width in pixels. Must be a multiple of the tile size.\n"); |
| 199 | printf("\t-H <8>\tSelect the sprite height in pixels. Must be a multiple of the tile size.\n"); | 230 | printf("\t-H <8> Select the sprite height in pixels. Must be a multiple of the tile size.\n"); |
| 200 | printf("\t-1\tBit pack the output to 1bbp (4x size reduction).\n"); | 231 | printf("\t-1 Bit pack the output to 1bbp (4x size reduction).\n"); |
| 201 | printf("\t-w <0>\tWidth of region to extract from (x0,y0). Defaults to image width.\n"); | 232 | printf("\t-w <0> Width of region to extract from (x0,y0). Defaults to image width.\n"); |
| 202 | printf("\t-h <0>\tHeight of region to extract from (x0,y0). Defaults to image height.\n"); | 233 | printf("\t-h <0> Height of region to extract from (x0,y0). Defaults to image height.\n"); |
| 234 | printf("\t-v Verbose mode\n"); | ||
| 203 | printf("\n"); | 235 | printf("\n"); |
| 204 | } | 236 | } |
| 205 | 237 | ||
| 206 | // TODO: Support multiple files at once? | ||
| 207 | int | 238 | int |
| 208 | main(int argc, char *argv[]) { | 239 | main(int argc, char *argv[]) { |
| 209 | // Initialize default parameters. | 240 | // Initialize default parameters. |
| 210 | u16 background_color = DEFAULT_BG_COLOR; | 241 | u16 background_color = DEFAULT_BG_COLOR; |
| 211 | u16 palette_size = DEFAULT_PALETTE_SIZE; | 242 | u16 palette_size = PALETTE_SIZE; |
| 212 | size_t sprite_width = TILE_SIZE; | 243 | size_t sprite_width = TILE_SIZE; |
| 213 | size_t sprite_height = TILE_SIZE; | 244 | size_t sprite_height = TILE_SIZE; |
| 214 | char *out_file_path = NULL; | 245 | char *out_file_path = NULL; |
| @@ -217,9 +248,10 @@ main(int argc, char *argv[]) { | |||
| 217 | size_t start_y = 0; | 248 | size_t start_y = 0; |
| 218 | size_t width = 0; | 249 | size_t width = 0; |
| 219 | size_t height = 0; | 250 | size_t height = 0; |
| 251 | bool verbose = false; | ||
| 220 | 252 | ||
| 221 | int option; | 253 | int option; |
| 222 | while ((option = getopt(argc, argv, "b:o:W:H:1x:y:w:h:")) != -1) { | 254 | while ((option = getopt(argc, argv, "b:o:W:H:1x:y:w:h:v")) != -1) { |
| 223 | switch (option) { | 255 | switch (option) { |
| 224 | case 'b': { | 256 | case 'b': { |
| 225 | // Background color. | 257 | // Background color. |
| @@ -298,6 +330,9 @@ main(int argc, char *argv[]) { | |||
| 298 | // Height of region to extract from (x0,y0). | 330 | // Height of region to extract from (x0,y0). |
| 299 | height = atoi(optarg); | 331 | height = atoi(optarg); |
| 300 | } break; | 332 | } break; |
| 333 | case 'v': { | ||
| 334 | verbose = true; | ||
| 335 | } break; | ||
| 301 | default: { | 336 | default: { |
| 302 | print_usage(); | 337 | print_usage(); |
| 303 | return EXIT_FAILURE; | 338 | return EXIT_FAILURE; |
| @@ -315,7 +350,6 @@ main(int argc, char *argv[]) { | |||
| 315 | 350 | ||
| 316 | // Fill the palette with the background color if one was given. | 351 | // Fill the palette with the background color if one was given. |
| 317 | Palette palette = { | 352 | Palette palette = { |
| 318 | .data = malloc(palette_size * sizeof(Color)), | ||
| 319 | .size = 1, | 353 | .size = 1, |
| 320 | .capacity = palette_size, | 354 | .capacity = palette_size, |
| 321 | }; | 355 | }; |
| @@ -357,8 +391,6 @@ main(int argc, char *argv[]) { | |||
| 357 | .capacity = n_tiles, | 391 | .capacity = n_tiles, |
| 358 | }; | 392 | }; |
| 359 | 393 | ||
| 360 | int offset_x = start_x; | ||
| 361 | int offset_y = start_y; | ||
| 362 | size_t n_sprites_x = width / sprite_width; | 394 | size_t n_sprites_x = width / sprite_width; |
| 363 | size_t n_sprites_y = height / sprite_height; | 395 | size_t n_sprites_y = height / sprite_height; |
| 364 | size_t n_sprite_tiles_x = sprite_width / TILE_SIZE; | 396 | size_t n_sprite_tiles_x = sprite_width / TILE_SIZE; |
| @@ -379,18 +411,42 @@ main(int argc, char *argv[]) { | |||
| 379 | if (out_file_path == NULL) { | 411 | if (out_file_path == NULL) { |
| 380 | export_c_file(&tiles, &palette, stdout, pack_1bpp); | 412 | export_c_file(&tiles, &palette, stdout, pack_1bpp); |
| 381 | } else { | 413 | } else { |
| 382 | FILE *file = fopen(out_file_path, "w"); | 414 | char file_name[MAX_FILE_NAME] = {0}; |
| 415 | char file_name_pal[MAX_FILE_NAME] = {0}; | ||
| 416 | strncpy(file_name, out_file_path, MAX_FILE_NAME - 1); | ||
| 417 | strncpy(file_name_pal, out_file_path, MAX_FILE_NAME - 1); | ||
| 418 | FILE *file = fopen(strcat(file_name, ".img.bin"), "w"); | ||
| 383 | if (!file) { | 419 | if (!file) { |
| 384 | fprintf(stderr, "%s: can't open output file: %s\n", BIN_NAME, out_file_path); | 420 | fprintf(stderr, "%s: can't open output file: %s\n", BIN_NAME, file_name); |
| 385 | return EXIT_FAILURE; | 421 | return EXIT_FAILURE; |
| 386 | } | 422 | } |
| 387 | export_c_file(&tiles, &palette, file, pack_1bpp); | 423 | if (pack_1bpp) { |
| 388 | fclose(file); | 424 | export_bin_file(&tiles, &palette, file, NULL, pack_1bpp); |
| 425 | fclose(file); | ||
| 426 | if (verbose) { | ||
| 427 | printf("Exporting binary file (1bpp packed)\n"); | ||
| 428 | printf("FILE IMG: %s\n", file_name); | ||
| 429 | } | ||
| 430 | } else { | ||
| 431 | FILE *file_pal = fopen(strcat(file_name_pal, ".pal.bin"), "w"); | ||
| 432 | if (!file_pal) { | ||
| 433 | fprintf(stderr, "%s: can't open output file: %s\n", BIN_NAME, file_name_pal); | ||
| 434 | fclose(file); | ||
| 435 | return EXIT_FAILURE; | ||
| 436 | } | ||
| 437 | if (verbose) { | ||
| 438 | printf("Exporting binary file\n"); | ||
| 439 | printf("FILE IMG: %s\n", file_name); | ||
| 440 | printf("FILE PAL: %s\n", file_name_pal); | ||
| 441 | } | ||
| 442 | export_bin_file(&tiles, &palette, file, file_pal, pack_1bpp); | ||
| 443 | fclose(file); | ||
| 444 | fclose(file_pal); | ||
| 445 | } | ||
| 389 | } | 446 | } |
| 390 | 447 | ||
| 391 | // Cleanup resources and exit. | 448 | // Cleanup resources and exit. |
| 392 | free(tiles.data); | 449 | free(tiles.data); |
| 393 | free(palette.data); | ||
| 394 | stbi_image_free(img.data); | 450 | stbi_image_free(img.data); |
| 395 | return EXIT_SUCCESS; | 451 | return EXIT_SUCCESS; |
| 396 | } | 452 | } |
diff --git a/sprite2gba/src/shorthand.h b/img2gba/src/shorthand.h index 9c2e2f0..9c2e2f0 100644 --- a/sprite2gba/src/shorthand.h +++ b/img2gba/src/shorthand.h | |||
diff --git a/sprite2gba/src/stb_image.h b/img2gba/src/stb_image.h index accef48..3448d5f 100644 --- a/sprite2gba/src/stb_image.h +++ b/img2gba/src/stb_image.h | |||
| @@ -4120,7 +4120,7 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) | |||
| 4120 | if (s >= 16) return -1; // invalid code! | 4120 | if (s >= 16) return -1; // invalid code! |
| 4121 | // code size is s, so: | 4121 | // code size is s, so: |
| 4122 | b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; | 4122 | b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; |
| 4123 | if (b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! | 4123 | if ((size_t)b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! |
| 4124 | if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. | 4124 | if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. |
| 4125 | a->code_buffer >>= s; | 4125 | a->code_buffer >>= s; |
| 4126 | a->num_bits -= s; | 4126 | a->num_bits -= s; |
| @@ -6777,6 +6777,8 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, | |||
| 6777 | int stride; | 6777 | int stride; |
| 6778 | int out_size = 0; | 6778 | int out_size = 0; |
| 6779 | int delays_size = 0; | 6779 | int delays_size = 0; |
| 6780 | (void)out_size; | ||
| 6781 | (void)delays_size; | ||
| 6780 | memset(&g, 0, sizeof(g)); | 6782 | memset(&g, 0, sizeof(g)); |
| 6781 | if (delays) { | 6783 | if (delays) { |
| 6782 | *delays = 0; | 6784 | *delays = 0; |
