9 void print_usage(const char *argv0);
10 int proc_image(const char *fname);
11 void wrtiles_carr(FILE *fp, const char *name, struct image *timg, int ntiles);
12 void wrtilemap_carr(FILE *fp, const char *name, int *tmap, int xtiles, int ytiles);
13 void wrpalette_carr(FILE *fp, const char *name, struct cmapent *cmap, int ncol);
15 enum { OUT_IMG, OUT_C, OUT_ASM } outmode;
16 static const char *otype_suffix[] = {".png", ".c", ".s"};
18 int tile_xsz = 8, tile_ysz = 8;
19 const char *output_filename;
21 int main(int argc, char **argv)
25 for(i=1; i<argc; i++) {
26 if(argv[i][0] == '-') {
30 output_filename = argv[++i];
34 if(sscanf(argv[++i], "%dx%d", &tile_xsz, &tile_ysz) != 2) {
35 fprintf(stderr, "-t must be followed by the tile size (WxH)\n");
53 fprintf(stderr, "invalid option: %s\n", argv[i]);
58 fprintf(stderr, "invalid option: %s\n", argv[i]);
64 if(proc_image(argv[i]) == -1) {
73 void print_usage(const char *argv0)
75 printf("Usage: %s [options] <img1> [<img2> ... <imgN>]\n", argv0);
77 printf(" -o <file>: output file\n");
78 printf(" -t WxH: tile size (default 8x8)\n");
79 printf(" -c: output C array\n");
80 printf(" -s: output GNU assembler data\n");
81 printf(" -h: print usage and exit\n\n");
84 int find_tile(struct image *tile, struct image *tiles)
87 count = dynarr_size(tiles);
88 for(i=0; i<count; i++) {
89 if(cmp_image(tile, tiles + i) == 0) {
96 int proc_image(const char *fname)
98 int i, j, k, idx, xtiles, ytiles, ntiles, result = -1;
100 struct image img, tile;
101 struct image *tiles = 0;
102 unsigned char *tiles_pixels, *tptr;
104 int *tilemap = 0, *mapptr;
105 char *basename, *suffix, *outfile;
107 if(load_image(&img, fname) == -1) {
108 fprintf(stderr, "failed to load image: %s\n", fname);
111 basename = alloca(strlen(fname) + 1);
112 strcpy(basename, fname);
113 if((suffix = strrchr(basename, '/'))) {
114 basename = suffix + 1;
116 if((suffix = strchr(basename, '.'))) {
120 xtiles = img.width / tile_xsz;
121 ytiles = img.height / tile_ysz;
122 if(img.width % tile_xsz != 0 || img.height % tile_ysz != 0) {
123 fprintf(stderr, "image size (%dx%d) not evenly divisible into %dx%d tiles\n",
124 img.width, img.height, tile_xsz, tile_ysz);
128 if(!(tilemap = malloc(xtiles * ytiles * sizeof *tilemap))) {
129 fprintf(stderr, "failed to allocate %dx%d tilemap\n", xtiles, ytiles);
134 if(!(tiles = dynarr_alloc(0, sizeof *tiles))) {
135 fprintf(stderr, "failed to allocate tile array\n");
138 /* alloc a contiguous buffer for the full tileset pixels, to make it easier to write it
139 * out as a single image in the end
141 if(!(tiles_pixels = dynarr_alloc(0, tile_xsz * tile_ysz * img.bpp / 8))) {
142 fprintf(stderr, "failed to allocate tile pixel buffer\n");
147 tile.width = tile_xsz;
148 tile.height = tile_ysz;
149 tile.scansz = tile_xsz * tile.bpp / 8;
152 for(i=0; i<ytiles; i++) {
153 for(j=0; j<xtiles; j++) {
156 if((idx = find_tile(&tile, tiles)) == -1) {
157 /* we don't have a duplicate of this tile */
158 idx = dynarr_size(tiles);
160 if(!(tiles = dynarr_push(tiles, 0))) {
163 if(!(tptr = dynarr_push(tiles_pixels, 0))) {
168 tiles[idx].scansz = tiles[idx].pitch = tile.scansz;
170 /* did the array get relocated? */
171 if(tptr != tiles_pixels) {
173 /* make each tile's pixels pointer point to the right place in the large pixelbuffer */
174 for(k=0; k<idx+1; k++) {
175 tiles[k].pixels = tptr;
176 tptr += tile_ysz * tiles[idx].pitch;
179 /* otherwise just set the new one */
180 tiles[idx].pixels = tiles_pixels + idx * tile_ysz * tiles[idx].pitch;
183 blit(&tile, 0, 0, tile_xsz, tile_ysz, tiles + idx, 0, 0);
188 printf("%2dx%-2d: %d\n", j, i, idx);
193 sptr += (tile_ysz - 1) * tile.pitch;
196 ntiles = dynarr_size(tiles);
197 fprintf(stderr, "%s (%dx%d) -> %d tiles, %d unique\n", fname, img.width, img.height,
198 xtiles * ytiles, ntiles);
202 /* make a big image out of the tiles and write it out */
204 tile.height = ntiles * tile_ysz;
206 if(output_filename) {
207 outfile = (char*)output_filename;
209 outfile = alloca(strlen(basename) + 5);
210 sprintf(outfile, "%s%s", basename, otype_suffix[outmode]);
215 if(save_image(&tile, outfile) == -1) {
216 fprintf(stderr, "failed to write output image\n");
222 if(!(fp = fopen(outfile, "w"))) {
223 fprintf(stderr, "failed to open output file: %s: %s\n", outfile, strerror(errno));
226 wrtiles_carr(fp, basename, &tile, ntiles);
227 wrtilemap_carr(fp, basename, tilemap, xtiles, ytiles);
228 wrpalette_carr(fp, basename, tile.cmap, tile.cmap_ncolors);
239 dynarr_free(tiles_pixels);
246 void wrtiles_carr(FILE *fp, const char *name, struct image *timg, int ntiles)
249 unsigned char *ptr = timg->pixels;
251 fprintf(fp, "\nint %s_num_tiles = %d;\n", name, ntiles);
252 fprintf(fp, "int %s_tiles_width = %d;\n", name, timg->width);
253 fprintf(fp, "int %s_tiles_height = %d;\n", name, timg->height);
254 fprintf(fp, "int %s_tiles_bpp = %d;\n", name, timg->bpp);
255 fprintf(fp, "unsigned char %s_tiles[] = {\n", name);
257 for(i=0; i<timg->height; i++) {
258 for(j=0; j<timg->scansz; j++) {
260 curx = 3 + fprintf(fp, "\t%u", (unsigned int)*ptr++);
262 curx += fprintf(fp, ", %u", (unsigned int)*ptr++);
269 ptr += timg->pitch - timg->scansz;
272 fprintf(fp, "\n};\n\n");
275 void wrtilemap_carr(FILE *fp, const char *name, int *tmap, int xtiles, int ytiles)
279 fprintf(fp, "\nint %s_tilemap_cols = %d;\n", name, xtiles);
280 fprintf(fp, "int %s_tilemap_rows = %d;\n", name, ytiles);
281 fprintf(fp, "unsigned int %s_tilemap[] = {\n", name);
283 sz = xtiles * ytiles;
284 for(i=0; i<sz; i++) {
286 curx = 3 + fprintf(fp, "\t%u", (unsigned int)tmap[i]);
288 curx += fprintf(fp, ", %u", (unsigned int)tmap[i]);
296 fprintf(fp, "\n};\n\n");
299 void wrpalette_carr(FILE *fp, const char *name, struct cmapent *cmap, int ncol)
303 fprintf(fp, "\nint %s_cmap_colors = %d;\n", name, ncol);
304 fprintf(fp, "unsigned char %s_cmap[][3] = {\n", name);
305 for(i=0; i<ncol; i++) {
306 fprintf(fp, "\t{%u, %u, %u}", cmap[i].r, cmap[i].g, cmap[i].b);
313 fprintf(fp, "};\n\n");