17 enum { AS_GNU, AS_NASM };
19 int csprite(struct image *img, int x, int y, int xsz, int ysz);
20 int proc_sheet(const char *fname);
21 void print_usage(const char *argv0);
23 int tile_xsz, tile_ysz;
27 int fbpitch, fbwidth = 320;
28 const char *name = "sprite";
32 const char *wrop = "mov";
34 int main(int argc, char **argv)
39 for(i=1; i<argc; i++) {
40 if(argv[i][0] == '-') {
41 if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-size") == 0) {
42 if(sscanf(argv[++i], "%dx%d", &tile_xsz, &tile_ysz) != 2 ||
43 tile_xsz <= 0 || tile_ysz <= 0) {
44 fprintf(stderr, "%s must be followed by WIDTHxHEIGHT\n", argv[i - 1]);
48 } else if(strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "-rect") == 0) {
50 if(sscanf(argv[++i], "%dx%d+%d+%d", &rect.w, &rect.h, &rect.x, &rect.y) < 2 || rect.w <= 0 || rect.h <= 0) {
51 fprintf(stderr, "%s must be followed by WIDTHxHEIGHT+X+Y\n", argv[i - 1]);
55 } else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pad") == 0) {
56 padding = strtol(argv[++i], &endp, 10);
57 if(endp == argv[i] || padding < 0) {
58 fprintf(stderr, "%s must be followed by a positive number\n", argv[i - 1]);
62 } else if(strcmp(argv[i], "-coffset") == 0) {
63 cmap_offs = strtol(argv[++i], &endp, 10);
64 if(endp == argv[i] || cmap_offs < 0 || cmap_offs >= 256) {
65 fprintf(stderr, "-coffset must be followed by a valid colormap offset\n");
69 } else if(strcmp(argv[i], "-fbwidth") == 0) {
70 fbwidth = atoi(argv[++i]);
72 fprintf(stderr, "-fbwidth must be followed by a positive number\n");
76 } else if(strcmp(argv[i], "-fbpitch") == 0) {
77 fbpitch = atoi(argv[++i]);
79 fprintf(stderr, "-fbpitch must be followed by a positive number\n");
83 } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "-name") == 0) {
86 fprintf(stderr, "%s must be followed by a name\n", argv[i - 1]);
90 } else if(strcmp(argv[i], "-k") == 0 || strcmp(argv[i], "-key") == 0) {
91 ckey = strtol(argv[++i], &endp, 10);
92 if(endp == argv[i] || ckey < 0) {
93 fprintf(stderr, "%s must be followed by a valid color key\n", argv[i - 1]);
97 } else if(strcmp(argv[i], "-conv565") == 0) {
100 } else if(strcmp(argv[i], "-x") == 0 || strcmp(argv[i], "-xor") == 0) {
103 } else if(strcmp(argv[i], "-gas") == 0) {
106 } else if(strcmp(argv[i], "-nasm") == 0) {
109 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
110 print_usage(argv[0]);
114 fprintf(stderr, "invalid option: %s\n", argv[i]);
115 print_usage(argv[0]);
120 if(proc_sheet(argv[i]) == -1) {
129 /* prototype of generated function is (void *fb, int x, int y, int idx) */
130 const char *prefixfmt[] = {
131 /* GNU assembler template */
137 "\tmov 12(%%esp), %%eax\n"
140 "\tadd 8(%%esp), %%eax\n"
141 "\tadd 4(%%esp), %%eax\n"
142 "\tmov %%eax, %%edx\n"
143 "\tmov 16(%%esp), %%eax\n"
144 "\tjmp *tiletab(,%%eax,4)\n\n"
148 /* TODO hardcoding the 16bpp changes for now, generalize later
149 * and while we're at it, let's get rid of the mul too ...
151 "\tsection .text USE32\n"
157 "\tmov eax, [esp + 12]\n"
164 "\tadd eax, [esp + 8]\n"
165 "\tadd eax, [esp + 8]\n"
166 "\tadd eax, [esp + 4]\n"
168 "\tmov eax, [esp + 16]\n"
169 "\tjmp [titletab + eax * 4]\n\n"
180 "\tjmp [titletab + ecx * 4]\n\n"
184 int proc_sheet(const char *fname)
186 int i, j, x, y, num_xtiles, num_ytiles, xsz, ysz, tidx;
189 if(load_image(&img, fname) == -1) {
190 fprintf(stderr, "failed to load image: %s\n", fname);
195 if(conv_image_rgb565(&tmp, &img) == -1) {
196 fprintf(stderr, "failed to convert image to 16bpp 565: %s\n", fname);
204 if(!fbpitch) fbpitch = fbwidth * img.bpp / 8;
212 num_xtiles = num_ytiles = 1;
213 xsz = rect.w - padding;
214 ysz = rect.h - padding;
217 num_xtiles = num_ytiles = 0;
221 i += tile_xsz + padding;
226 i += tile_ysz + padding;
229 num_xtiles = rect.w / tile_xsz;
230 num_ytiles = rect.h / tile_ysz;
236 printf(prefixfmt[asyntax], name, name, name, name, name, fbpitch, name);
237 for(i=0; i<num_ytiles*num_xtiles; i++) {
238 if(asyntax == AS_GNU) {
239 printf("\t.long tile%d\n", i);
241 printf("\tdd tile%d\n", i);
248 for(i=0; i<num_ytiles; i++) {
250 for(j=0; j<num_xtiles; j++) {
251 printf("tile%d:\n", tidx++);
252 csprite(&img, x, y, xsz, ysz);
270 unsigned char op, val;
274 int csprite(struct image *img, int x, int y, int xsz, int ysz)
276 int i, j, numops, mode, new_mode, start, skip_acc, lenbytes, pixsz = img->bpp / 8;
277 unsigned char *pptr = img->pixels + y * img->scansz + x * pixsz;
278 struct csop *ops, *optr;
280 ops = optr = alloca((xsz + 1) * ysz * sizeof *ops);
282 for(i=0; i<ysz; i++) {
287 optr++->op = CSOP_ENDL;
290 for(j=0; j<xsz; j++) {
291 if(memcmp(pptr, &ckey, pixsz) == 0) {
292 new_mode = CSOP_SKIP;
294 new_mode = CSOP_COPY;
297 if(new_mode != mode) {
301 optr->len = j - start;
309 pptr += img->scansz - xsz * pixsz;
314 optr->len = xsz - start;
320 pptr = img->pixels + y * img->scansz + x * img->bpp / 8;
323 /* edx points to dest */
324 for(i=0; i<numops; i++) {
327 skip_acc += optr->len;
328 pptr += optr->len * pixsz;
332 skip_acc += fbwidth - xsz;
333 pptr += img->scansz - xsz * pixsz;
338 if(asyntax == AS_GNU) {
339 printf("\tadd $%d, %%edx\n", skip_acc * pixsz);
341 printf("\tadd edx, %d\n", skip_acc * pixsz);
346 lenbytes = optr->len * pixsz;
347 for(j=0; j<lenbytes / 4; j++) {
348 if(asyntax == AS_GNU) {
349 printf("\t%sl $0x%x, %d(%%edx)\n", wrop, *(uint32_t*)pptr, j * 4);
351 printf("\t%s dword [edx + %d], 0x%x\n", wrop, j * 4, *(uint32_t*)pptr);
356 switch(lenbytes % 4) {
358 if(asyntax == AS_GNU) {
359 printf("\t%sb $0x%x, %d(%%edx)\n", wrop, (unsigned int)*pptr++, j++);
361 printf("\t%s byte [edx + %d], 0x%x\n", wrop, j++, (unsigned int)*pptr++);
364 if(asyntax == AS_GNU) {
365 printf("\t%sw $0x%x, %d(%%edx)\n", wrop, (unsigned int)*(uint16_t*)pptr, j);
367 printf("\t%s word [edx + %d], 0x%x\n", wrop, j, (unsigned int)*(uint16_t*)pptr);
373 if(asyntax == AS_GNU) {
374 printf("\t%sb $0x%x, %d(%%edx)\n", wrop, (unsigned int)*pptr++, j++);
376 printf("\t%s byte [edx + %d], 0x%x\n", wrop, j++, (unsigned int)*pptr++);
381 skip_acc = optr->len;
385 printf("\t%c invalid op: %d\n", asyntax == AS_GNU ? '#' : ';', optr->op);
394 void print_usage(const char *argv0)
396 printf("Usage: %s [options] <spritesheet>\n", argv0);
397 printf("Options:\n");
398 printf(" -s,-size <WxH>: tile size (default: whole image)\n");
399 printf(" -r,-rect <WxH+X+Y>: use rectangle of the input image (default: whole image)\n");
400 printf(" -p,-pad <N>: how many pixels to skip between tiles in source image (default: 0)\n");
401 printf(" -coffset <offs>: colormap offset [0, 255] (default: 0)\n");
402 printf(" -fbpitch <pitch>: target framebuffer pitch (scanline size in bytes)\n");
403 printf(" -k,-key <color>: color-key for transparency (default: 0)\n");
404 printf(" -conv565: convert image to 16bpp 565 before processing\n");
405 printf(" -x,-xor: use XOR for writing pixels instead of MOV\n");
406 printf(" -gas: output GNU assembler code (default)\n");
407 printf(" -nasm: output NASM-compatible code\n");
408 printf(" -h: print usage and exit\n");