9 void print_usage(const char *argv0);
10 int proc_image(const char *fname);
11 void wrtiles(FILE *fp, const char *name, struct image *timg, int ntiles);
12 void wrtilemap(FILE *fp, const char *name, int *tmap, int xtiles, int ytiles);
13 void wrpalette(FILE *fp, const char *name, struct cmapent *cmap, int ncol);
15 int tile_xsz = 8, tile_ysz = 8;
16 const char *output_filename;
18 int main(int argc, char **argv)
22 for(i=1; i<argc; i++) {
23 if(argv[i][0] == '-') {
27 output_filename = argv[++i];
31 if(sscanf(argv[++i], "%dx%d", &tile_xsz, &tile_ysz) != 2) {
32 fprintf(stderr, "-t must be followed by the tile size (WxH)\n");
42 fprintf(stderr, "invalid option: %s\n", argv[i]);
47 fprintf(stderr, "invalid option: %s\n", argv[i]);
53 if(proc_image(argv[i]) == -1) {
62 void print_usage(const char *argv0)
64 printf("Usage: %s [options] <img1> [<img2> ... <imgN>]\n", argv0);
66 printf(" -o <file>: output file\n");
67 printf(" -t WxH: tile size (default 8x8)\n");
68 printf(" -h: print usage and exit\n\n");
71 int find_tile(struct image *tile, struct image *tiles)
74 count = dynarr_size(tiles);
75 for(i=0; i<count; i++) {
76 if(cmp_image(tile, tiles + i) == 0) {
83 int proc_image(const char *fname)
85 int i, j, k, idx, xtiles, ytiles, ntiles, result = -1;
87 struct image img, tile;
88 struct image *tiles = 0;
89 unsigned char *tiles_pixels, *tptr;
91 int *tilemap = 0, *mapptr;
92 char *basename, *suffix, *outfile;
94 if(load_image(&img, fname) == -1) {
95 fprintf(stderr, "failed to load image: %s\n", fname);
98 basename = alloca(strlen(fname) + 1);
99 strcpy(basename, fname);
100 if((suffix = strrchr(basename, '/'))) {
101 basename = suffix + 1;
103 if((suffix = strchr(basename, '.'))) {
107 xtiles = img.width / tile_xsz;
108 ytiles = img.height / tile_ysz;
109 if(img.width % tile_xsz != 0 || img.height % tile_ysz != 0) {
110 fprintf(stderr, "image size (%dx%d) not evenly divisible into %dx%d tiles\n",
111 img.width, img.height, tile_xsz, tile_ysz);
115 if(!(tilemap = malloc(xtiles * ytiles * sizeof *tilemap))) {
116 fprintf(stderr, "failed to allocate %dx%d tilemap\n", xtiles, ytiles);
121 if(!(tiles = dynarr_alloc(0, sizeof *tiles))) {
122 fprintf(stderr, "failed to allocate tile array\n");
125 /* alloc a contiguous buffer for the full tileset pixels, to make it easier to write it
126 * out as a single image in the end
128 if(!(tiles_pixels = dynarr_alloc(0, tile_xsz * tile_ysz * img.bpp / 8))) {
129 fprintf(stderr, "failed to allocate tile pixel buffer\n");
134 tile.width = tile_xsz;
135 tile.height = tile_ysz;
136 tile.scansz = tile_xsz * tile.bpp / 8;
139 for(i=0; i<ytiles; i++) {
140 for(j=0; j<xtiles; j++) {
143 if((idx = find_tile(&tile, tiles)) == -1) {
144 /* we don't have a duplicate of this tile */
145 idx = dynarr_size(tiles);
147 if(!(tiles = dynarr_push(tiles, 0))) {
150 if(!(tptr = dynarr_push(tiles_pixels, 0))) {
155 tiles[idx].scansz = tiles[idx].pitch = tile.scansz;
157 /* did the array get relocated? */
158 if(tptr != tiles_pixels) {
160 /* make each tile's pixels pointer point to the right place in the large pixelbuffer */
161 for(k=0; k<idx+1; k++) {
162 tiles[k].pixels = tptr;
163 tptr += tile_ysz * tiles[idx].pitch;
166 /* otherwise just set the new one */
167 tiles[idx].pixels = tiles_pixels + idx * tile_ysz * tiles[idx].pitch;
170 blit(&tile, 0, 0, tile_xsz, tile_ysz, tiles + idx, 0, 0);
177 sptr += (tile_ysz - 1) * tile.pitch;
180 ntiles = dynarr_size(tiles);
181 fprintf(stderr, "%s (%dx%d) -> %d tiles, %d unique\n", fname, img.width, img.height,
182 xtiles * ytiles, ntiles);
186 /* make a big image out of the tiles and write it out */
188 tile.height = ntiles * tile_ysz;
190 if(output_filename) {
191 outfile = (char*)output_filename;
193 outfile = alloca(strlen(basename) + 5);
194 sprintf(outfile, "%s.asm", basename);
197 if(!(fp = fopen(outfile, "w"))) {
198 fprintf(stderr, "failed to open output file: %s: %s\n", outfile, strerror(errno));
201 wrtiles(fp, basename, &tile, ntiles);
202 wrtilemap(fp, basename, tilemap, xtiles, ytiles);
203 wrpalette(fp, basename, tile.cmap, tile.cmap_ncolors);
209 dynarr_free(tiles_pixels);
217 unsigned int packbitplane4bpp(unsigned char *pix, int bit)
220 unsigned int val = 0;
223 val = (val << 1) | ((*pix >> (bit + 4)) & 1);
224 val = (val << 1) | ((*pix >> bit) & 1);
231 void wrtile4bpp(FILE *fp, unsigned char *tpix, struct image *timg)
233 int i, x, y, curx = 0;
237 /* for each pair of bitplanes */
238 for(i=0; i<timg->bpp/2; i++) {
240 for(y=0; y<tile_ysz; y++) {
241 for(x=0; x<tile_xsz/8; x++) {
242 val = packbitplane4bpp(ptr, i * 2);
243 val |= packbitplane4bpp(ptr, i * 2 + 1) << 8;
246 curx = 7 + fprintf(fp, "\t.word $%x", (unsigned int)val);
248 curx += fprintf(fp, ", $%x", (unsigned int)val);
255 ptr += tile_xsz * timg->bpp / 8;
264 void wrtiles(FILE *fp, const char *name, struct image *timg, int ntiles)
267 unsigned char *ptr = timg->pixels;
269 fprintf(fp, "\n\t%s_num_tiles = %d\n", name, ntiles);
270 fprintf(fp, "\t%s_tiles_width = %d\n", name, timg->width);
271 fprintf(fp, "\t%s_tiles_height = %d\n", name, timg->height);
272 fprintf(fp, "\t%s_tiles_bpp = %d\n", name, timg->bpp);
273 fprintf(fp, "%s_tiles:\n", name);
275 for(i=0; i<ntiles; i++) {
276 fprintf(fp, "\t; tile %d:", i);
277 for(j=0; j<timg->scansz * tile_ysz; j++) {
278 fprintf(fp, " %x", ptr[j]);
284 wrtile4bpp(fp, ptr, timg);
288 fprintf(stderr, "unsupported bpp: %d\n", timg->bpp);
291 ptr += timg->scansz * tile_ysz;
298 void wrtilemap(FILE *fp, const char *name, int *tmap, int xtiles, int ytiles)
302 fprintf(fp, "\n\t%s_tilemap_cols = %d\n", name, xtiles);
303 fprintf(fp, "\t%s_tilemap_rows = %d\n", name, ytiles);
304 fprintf(fp, "%s_tilemap:\n", name);
306 sz = xtiles * ytiles;
307 for(i=0; i<sz; i++) {
309 curx = 7 + fprintf(fp, "\t.word %u", (unsigned int)tmap[i]);
311 curx += fprintf(fp, ", %u", (unsigned int)tmap[i]);
322 void wrpalette(FILE *fp, const char *name, struct cmapent *cmap, int ncol)
326 fprintf(fp, "\n\t%s_cmap_colors = %d\n", name, ncol);
327 fprintf(fp, "%s_cmap:\n", name);
328 for(i=0; i<ncol; i++) {
329 unsigned int col = (cmap[i].r * 31 / 255) | ((cmap[i].g * 31 / 255) << 5) |
330 ((cmap[i].b * 31 / 255) << 10);
331 fprintf(fp, "\t.word $%04x\n", col);