13 enum { AS_GNU, AS_NASM };
15 int csprite(struct image *img, int x, int y, int xsz, int ysz);
16 int proc_sheet(const char *fname);
17 void print_usage(const char *argv0);
19 int tile_xsz, tile_ysz;
24 const char *name = "sprite";
27 int main(int argc, char **argv)
32 for(i=1; i<argc; i++) {
33 if(argv[i][0] == '-') {
34 if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-size") == 0) {
35 if(sscanf(argv[++i], "%dx%d", &tile_xsz, &tile_ysz) != 2 ||
36 tile_xsz <= 0 || tile_ysz <= 0) {
37 fprintf(stderr, "%s must be followed by WIDTHxHEIGHT\n", argv[i - 1]);
41 } else if(strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "-rect") == 0) {
43 if(sscanf(argv[++i], "%dx%d+%d+%d", &rect.w, &rect.h, &rect.x, &rect.y) < 2 || rect.w <= 0 || rect.h <= 0) {
44 fprintf(stderr, "%s must be followed by WIDTHxHEIGHT+X+Y\n", argv[i - 1]);
48 } else if(strcmp(argv[i], "-coffset") == 0) {
49 cmap_offs = strtol(argv[++i], &endp, 10);
50 if(endp == argv[i] || cmap_offs < 0 || cmap_offs >= 256) {
51 fprintf(stderr, "-coffset must be followed by a valid colormap offset\n");
55 } else if(strcmp(argv[i], "-fbpitch") == 0) {
56 fbpitch = atoi(argv[++i]);
58 fprintf(stderr, "-fbpitch must be followed by a positive number\n");
62 } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "-name") == 0) {
65 fprintf(stderr, "%s must be followed by a name\n", argv[i - 1]);
69 } else if(strcmp(argv[i], "-k") == 0 || strcmp(argv[i], "-key") == 0) {
70 ckey = strtol(argv[++i], &endp, 10);
71 if(endp == argv[i] || ckey < 0 || ckey >= 256) {
72 fprintf(stderr, "%s must be followed by a valid color key\n", argv[i - 1]);
76 } else if(strcmp(argv[i], "-gas") == 0) {
79 } else if(strcmp(argv[i], "-nasm") == 0) {
82 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
87 fprintf(stderr, "invalid option: %s\n", argv[i]);
93 if(proc_sheet(argv[i]) == -1) {
102 const char *prefixfmt[] = {
103 /* GNU assembler template */
106 "\tmov 12(%%esp), %%eax\n"
109 "\tadd 8(%%esp), %%eax\n"
110 "\tadd 4(%%esp), %%eax\n"
111 "\tmov %%eax, %%edx\n"
112 "\tmov 16(%%esp), %%eax\n"
113 "\tjmp *tiletab(,%%eax,4)\n\n"
119 "\tmov eax, [esp + 12]\n"
122 "\tadd eax, [esp + 8]\n"
123 "\tadd eax, [esp + 4]\n"
125 "\tmov eax, [esp + 16]\n"
126 "\tjmp [titletab + eax * 4]\n\n"
130 int proc_sheet(const char *fname)
132 int i, j, num_xtiles, num_ytiles, xsz, ysz, tidx;
135 if(load_image(&img, fname) == -1) {
136 fprintf(stderr, "failed to load image: %s\n", fname);
145 num_xtiles = num_ytiles = 1;
149 num_xtiles = rect.w / tile_xsz;
150 num_ytiles = rect.h / tile_ysz;
155 printf(prefixfmt[asyntax], name, name, fbpitch);
156 for(i=0; i<num_ytiles*num_xtiles; i++) {
157 if(asyntax == AS_GNU) {
158 printf("\t.long tile%d\n", i);
160 printf("\tdd tile%d\n", i);
166 for(i=0; i<num_ytiles; i++) {
167 for(j=0; j<num_xtiles; j++) {
168 printf("tile%d:\n", tidx++);
169 csprite(&img, rect.x + j * xsz, rect.y + i * ysz, xsz, ysz);
184 unsigned char op, val;
188 int csprite(struct image *img, int x, int y, int xsz, int ysz)
190 int i, j, numops, mode, new_mode, start, skip_acc;
191 unsigned char *pptr = img->pixels + y * img->scansz + x;
192 struct csop *ops, *optr;
194 ops = optr = alloca((xsz + 1) * ysz * sizeof *ops);
196 for(i=0; i<ysz; i++) {
201 optr++->op = CSOP_ENDL;
204 for(j=0; j<xsz; j++) {
206 new_mode = CSOP_SKIP;
208 new_mode = CSOP_COPY;
211 if(new_mode != mode) {
215 optr->len = j - start;
223 pptr += img->scansz - xsz;
228 optr->len = xsz - start;
234 pptr = img->pixels + y * img->scansz + x;
237 /* edx points to dest */
238 for(i=0; i<numops; i++) {
241 skip_acc += optr->len;
246 skip_acc += fbpitch - xsz;
247 pptr += img->scansz - xsz;
252 if(asyntax == AS_GNU) {
253 printf("\tadd $%d, %%edx\n", skip_acc);
255 printf("\tadd edx, %d\n", skip_acc);
260 for(j=0; j<optr->len / 4; j++) {
261 if(asyntax == AS_GNU) {
262 printf("\tmovl $0x%x, %d(%%edx)\n", *(uint32_t*)pptr, j * 4);
264 printf("\tmov dword [edx + %d], 0x%x\n", j * 4, *(uint32_t*)pptr);
269 switch(optr->len % 4) {
271 if(asyntax == AS_GNU) {
272 printf("\tmovb $0x%x, %d(%%edx)\n", (unsigned int)*pptr++, j++);
274 printf("\tmov byte [edx + %d], 0x%x\n", j++, (unsigned int)*pptr++);
277 if(asyntax == AS_GNU) {
278 printf("\tmovw $0x%x, %d(%%edx)\n", (unsigned int)*(uint16_t*)pptr, j);
280 printf("\tmov word [edx + %d], 0x%x\n", j, (unsigned int)*(uint16_t*)pptr);
286 if(asyntax == AS_GNU) {
287 printf("\tmovb $0x%x, %d(%%edx)\n", (unsigned int)*pptr++, j++);
289 printf("\tmov byte [edx + %d], 0x%x\n", j++, (unsigned int)*pptr++);
294 skip_acc = optr->len;
298 printf("\t%c invalid op: %d\n", asyntax == AS_GNU ? '#' : ';', optr->op);
307 void print_usage(const char *argv0)
309 printf("Usage: %s [options] <spritesheet>\n", argv0);
310 printf("Options:\n");
311 printf(" -s,-size <WxH>: tile size (default: whole image)\n");
312 printf(" -r,-rect <WxH+X+Y>: use rectangle of the input image (default: whole image)\n");
313 printf(" -coffset <offs>: colormap offset [0, 255] (default: 0)\n");
314 printf(" -fbpitch <pitch>: target framebuffer pitch (scanline size in bytes)\n");
315 printf(" -k,-key <color>: color-key for transparency (default: 0)\n");
316 printf(" -gas: output GNU assembler code (default)\n");
317 printf(" -nasm: output NASM-compatible code\n");
318 printf(" -h: print usage and exit\n");