summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-04-20 10:32:31 +0200
committerBad Diode <bd@badd10de.dev>2021-04-20 10:32:31 +0200
commitc2080e499ab119c70f3fc7c6122bdf0751153986 (patch)
tree3c25392a371ec78408ea969946c7d4ba01690fd7
parentca98cb0c5d3e38b8e12e2d8a3aa66b4cbe0cca3d (diff)
downloadgba-dev-tools-c2080e499ab119c70f3fc7c6122bdf0751153986.tar.gz
gba-dev-tools-c2080e499ab119c70f3fc7c6122bdf0751153986.zip
Clean up code with more structured data
-rw-r--r--src/main.c158
1 files changed, 96 insertions, 62 deletions
diff --git a/src/main.c b/src/main.c
index bcd72c9..65dc94d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,14 +20,33 @@ rgb15(u32 red, u32 green, u32 blue ) {
20// TODO: Write more documentation about this. 20// TODO: Write more documentation about this.
21typedef u32 Tile[TILE_SIZE]; 21typedef u32 Tile[TILE_SIZE];
22 22
23typedef struct Tiles {
24 Tile *data;
25 size_t size;
26 size_t capacity;
27} Tiles;
28
29typedef struct Palette {
30 Color *data;
31 size_t size;
32 size_t capacity;
33} Palette;
34
35typedef struct Image {
36 unsigned char *data;
37 int width;
38 int height;
39 int n_channels;
40} Image;
41
23void 42void
24export_c_file(Tile *tiles, Color *palette, size_t n_tiles, size_t palette_size) { 43export_c_file(Tiles *tiles, Palette *palette) {
25 // Output tiles. 44 // Output tiles.
26 printf("u32 tiles[][%u] = {\n", TILE_SIZE); 45 printf("u32 tiles[%u][%u] = {\n", tiles->capacity, TILE_SIZE);
27 for (size_t i = 0; i < n_tiles; ++i) { 46 for (size_t i = 0; i < tiles->capacity; ++i) {
28 printf(" {"); 47 printf(" {");
29 for (size_t j = 0; j < TILE_SIZE; ++j) { 48 for (size_t j = 0; j < TILE_SIZE; ++j) {
30 printf("0x%08x", tiles[i][j]); 49 printf("0x%08x", tiles->data[i][j]);
31 if (j != (TILE_SIZE - 1)) { 50 if (j != (TILE_SIZE - 1)) {
32 printf(", "); 51 printf(", ");
33 } 52 }
@@ -38,15 +57,15 @@ export_c_file(Tile *tiles, Color *palette, size_t n_tiles, size_t palette_size)
38 printf("\n"); 57 printf("\n");
39 58
40 // Output palette. 59 // Output palette.
41 printf("u16 palette[%u] = {\n", palette_size); 60 printf("u16 palette[%u] = {\n", palette->capacity);
42 printf(" "); 61 printf(" ");
43 size_t counter = 0; 62 size_t counter = 0;
44 for (size_t i = 0; i < palette_size; ++i, ++counter) { 63 for (size_t i = 0; i < palette->capacity; ++i, ++counter) {
45 if (counter == 4) { 64 if (counter == 4) {
46 counter = 0; 65 counter = 0;
47 printf("\n "); 66 printf("\n ");
48 } 67 }
49 printf("0x%04x,", palette[i]); 68 printf("0x%04x,", palette->data[i]);
50 if (counter < 3) { 69 if (counter < 3) {
51 printf(" "); 70 printf(" ");
52 } 71 }
@@ -64,6 +83,47 @@ print_usage(void) {
64 // TODO: Print valid options as a suggestion. 83 // TODO: Print valid options as a suggestion.
65} 84}
66 85
86void
87extract_tile(Tiles *tiles, Palette *palette, Image *img,
88 size_t offset_x, size_t offset_y) {
89 for (size_t j = 0; j < TILE_SIZE; ++j) {
90 u32 col_index = 0x00000000;
91 for (size_t i = 0; i < TILE_SIZE; ++i) {
92 size_t pal_index = palette->size;
93 // Find the memory index for this pixel.
94 int idx = (i + offset_x) + (j + offset_y) * img->width;
95 idx *= img->n_channels;
96
97 int red = img->data[idx];
98 int green = img->data[idx + 1];
99 int blue = img->data[idx + 2];
100
101 // Quantize to 5 bits per channel.
102 red = (red * 31 / 255);
103 green = (green * 31 / 255);
104 blue = (blue * 31 / 255);
105
106 Color clr = rgb15(red, green, blue);
107 bool found = false;
108 // TODO: If the palette is full, find the closest perceived
109 // color instead.
110 for (size_t p = 0; p < palette->capacity; ++p) {
111 if (clr == palette->data[p]) {
112 pal_index = p;
113 found = true;
114 break;
115 }
116 }
117 if (!found) {
118 palette->data[palette->size++] = clr;
119 }
120 col_index |= pal_index << i * 4; // TODO: FlipH?
121 }
122 tiles->data[tiles->size][j] = col_index;
123 }
124 tiles->size++;
125}
126
67int 127int
68main(int argc, char *argv[]) { 128main(int argc, char *argv[]) {
69 u16 background_color = DEFAULT_BG_COLOR; 129 u16 background_color = DEFAULT_BG_COLOR;
@@ -122,85 +182,59 @@ main(int argc, char *argv[]) {
122 char *file_name = argv[optind]; 182 char *file_name = argv[optind];
123 183
124 // Fill the palette with the background color if one was given. 184 // Fill the palette with the background color if one was given.
125 Color *palette = malloc(palette_size * sizeof(Color)); 185 Palette palette = {
186 .data = malloc(palette_size * sizeof(Color)),
187 .size = 1,
188 .capacity = palette_size,
189 };
126 for (size_t i = 0; i < palette_size; ++i) { 190 for (size_t i = 0; i < palette_size; ++i) {
127 palette[i] = background_color; 191 palette.data[i] = background_color;
128 } 192 }
129 193
130 int x; 194 Image img = {0};
131 int y;
132 int n;
133 unsigned char *data;
134 195
135 // Open the given file. 196 // Open the given file.
136 data = stbi_load(file_name, &x, &y, &n, 0); 197 img.data = stbi_load(file_name, &img.width, &img.height, &img.n_channels, 0);
137 if (data == NULL) { 198 if (img.data == NULL) {
138 fprintf(stderr, "Error: can't open the given file.\n"); 199 fprintf(stderr, "Error: can't open the given file.\n");
139 return EXIT_FAILURE; 200 return EXIT_FAILURE;
140 } 201 }
141 202
142 // TODO: Implement support for different file inputs. 203 // TODO: Implement support for different file inputs.
143 if (n != 3) { 204 if (img.n_channels != 3) {
144 fprintf(stderr, "File format not supported. Only 3 channel files for now.\n"); 205 fprintf(stderr, "File format not supported. Only 3 channel files for now.\n");
145 return EXIT_FAILURE; 206 return EXIT_FAILURE;
146 } 207 }
147 208
148 int n_tiles_x = x / TILE_SIZE; 209 int n_tiles_x = img.width / TILE_SIZE;
149 int n_tiles_y = y / TILE_SIZE; 210 int n_tiles_y = img.height / TILE_SIZE;
150 int n_tiles = n_tiles_x * n_tiles_y; 211 int n_tiles = n_tiles_x * n_tiles_y;
151 212
152 // Allocate memory for the tiles in this file. 213 // Allocate memory for the tiles in this file, with zero-initialization.
153 Tile *tiles = malloc(n_tiles * sizeof(Tile)); 214 Tiles tiles = {
215 .data = calloc(n_tiles, sizeof(Tile)),
216 .size = 0,
217 .capacity = n_tiles,
218 };
154 219
155 // NOTE: We are going to brute-force this for now. Checking if the color is 220 // NOTE: We are going to brute-force this for now. Checking if the color is
156 // in the palette and add it to the next slot if possible. In the future we 221 // in the palette and add it to the next slot if possible. In the future we
157 // may want to use a hash-table instead. 222 // may want to use a hash-table instead.
158 int pal_idx = 1; 223 int pal_idx = 1;
159 int tile_offset_x = 0; 224 int offset_x = 0;
160 int tile_offset_y = 0; 225 int offset_y = 0;
161 for (size_t k = 0; k < n_tiles; ++k) { 226 for (size_t k = 0; k < n_tiles; ++k) {
162 for (size_t j = 0; j < TILE_SIZE; ++j) { 227 extract_tile(&tiles, &palette, &img, offset_x, offset_y);
163 u32 col_index = 0x00000000; 228 offset_x += TILE_SIZE;
164 for (size_t i = 0; i < TILE_SIZE; ++i) { 229 if (offset_x >= img.width) {
165 // Find the memory index for this pixel. 230 offset_x = 0;
166 int idx = (i + tile_offset_x) + (j + tile_offset_y) * x; 231 offset_y += TILE_SIZE;
167 idx *= n;
168
169 int red = data[idx];
170 int green = data[idx + 1];
171 int blue = data[idx + 2];
172
173 // Quantize to 5 bits per channel.
174 red = (red * 31 / 255);
175 green = (green * 31 / 255);
176 blue = (blue * 31 / 255);
177
178 Color clr = rgb15(red, green, blue);
179 bool found = false;
180 // TODO: If the palette is full, find the closest perceived
181 // color instead.
182 for (size_t p = 0; p < palette_size; ++p) {
183 if (clr == palette[p]) {
184 col_index |= (p & 0xF) << ((i) * 4) ;
185 found = true;
186 break;
187 }
188 }
189 if (!found) {
190 col_index |= pal_idx << (i) * 4; // TODO: FlipH?
191 palette[pal_idx++] = clr;
192 }
193 }
194 tiles[k][j] = col_index;
195 }
196 tile_offset_x += TILE_SIZE;
197 if (tile_offset_x >= x) {
198 tile_offset_x = 0;
199 tile_offset_y += TILE_SIZE;
200 } 232 }
201 } 233 }
202 234
203 export_c_file(tiles, palette, n_tiles, palette_size); 235 export_c_file(&tiles, &palette);
204 stbi_image_free(data); 236
237 // TODO: Cleanup other resources.
238 stbi_image_free(img.data);
205 return EXIT_SUCCESS; 239 return EXIT_SUCCESS;
206} 240}