6 #include <leptonica/allheaders.h>
7 #define assert(x) if(!(x)) __asm__("int3");
9 #pragma RcB2 LINK "-llept"
10 #pragma RcB2 LINK "-llept -lpng -ljpeg -ltiff -lgif -lz"
20 static const l_int32 L_RED_SHIFT =
21 8 * (sizeof(l_uint32) - 1 - COLOR_RED); //24
22 static const l_int32 L_GREEN_SHIFT =
23 8 * (sizeof(l_uint32) - 1 - COLOR_GREEN); //16
24 static const l_int32 L_BLUE_SHIFT =
25 8 * (sizeof(l_uint32) - 1 - COLOR_BLUE); //8
26 static const l_int32 L_ALPHA_SHIFT =
27 8 * (sizeof(l_uint32) - 1 - L_ALPHA_CHANNEL); //0
29 composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
31 *ppixel = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) | (bval << L_BLUE_SHIFT);
35 static unsigned get_sprite_start(unsigned sprite_nr
, unsigned row_nr
, unsigned sprite_w
, unsigned sprite_h
, unsigned sprites_per_row
) {
36 unsigned sprite_row
= sprite_nr
/ sprites_per_row
;
37 unsigned row_off
= (row_nr
* sprite_w
* sprites_per_row
);
38 unsigned res
= (sprite_row
* sprite_w
* sprite_h
* sprites_per_row
) + row_off
+ ((sprite_nr
% sprites_per_row
) * sprite_w
);
39 //printf("sprite %.2u, row %.2u : %u\n", sprite_nr, row_nr, res);
43 static int usage(char *a0
) {
44 printf("syntax: %s [-t] [-s WxH] infile outfile\n"
45 "where WxH denotes the dimensions of a single picture in the spritesheet\n"
46 "-t, if given, means the first color in the bitmap is the transparent color\n"
47 "if -s is omitted, the file will be considered a single sprite\n"
48 "if the file extension is .c, a C file will be written, else a binary ppic\n", a0
);
52 #define STRSZ(lit) lit, sizeof(lit) - 1
53 #define LIT_SIZE(lit) ( sizeof(lit) - 1)
54 int main(int argc
, char** argv
) {
56 struct palpic pp
= palpic_empty
;
62 unsigned sprite_w
= 0, sprite_h
= 0;
63 unsigned sprite_count
;
66 while((c
= getopt(argc
, argv
, "s:t")) != EOF
) switch(c
) {
67 case 't': pp
.flags
|= PPF_TRANSPARENT
; break;
70 char* str_h
= strchr(str_w
, 'x');
72 sprite_w
= atoi(str_w
);
73 sprite_h
= atoi(str_h
);
76 default: return usage(argv
[0]);
79 if(!argv
[optind
] || !argv
[optind
+1]) return usage(argv
[0]);
81 char *in_filename
= argv
[optind
];
82 char *out_filename
= argv
[optind
+1];
84 if(access(in_filename
, R_OK
) == -1) {
90 int to_c
= (cp
= strrchr(out_filename
, '.')) && cp
== out_filename
+ strlen(out_filename
) - 2 && cp
[1] == 'c';
91 char struct_name
[256];
93 char *st_start
= strrchr(out_filename
, '/');
94 if(st_start
) st_start
++;
95 else st_start
= out_filename
;
96 size_t l
= snprintf(struct_name
, sizeof struct_name
, "%s", st_start
);
101 infile
= pixRead(in_filename
);
103 pixGetDimensions(infile
, &w
, &h
, NULL
);
105 if(sprite_w
&& sprite_h
) {
106 sprite_count
= (h
* w
) / (sprite_h
* sprite_w
);
107 unsigned rest
= (h
* w
) % (sprite_h
* sprite_w
);
109 printf("error: the picture dimensions are no multiple of the sprite dimensions!\n");
113 printf("error: the picture width is no multiple of the sprite width!\n");
123 unsigned sprites_per_row
= w
/ sprite_w
;
125 /* we always align sprites vertically */
126 pp
.height
= sprite_h
* sprite_count
;
129 pp
.spritecount
= sprite_count
;
131 pix32
= pixConvertTo32(infile
);
132 prgb
* bufptr
= (prgb
*) pix32
->data
;
134 unsigned x
, y
= 0, p
;
135 for(y
= 0; y
< (unsigned) h
; y
++) {
136 for(x
= 0; x
< (unsigned) w
; x
++) {
137 for(p
= 0; p
< pp
.palcount
; p
++)
138 if(pal
[p
].val
== bufptr
->val
)
140 pal
[pp
.palcount
++] = *bufptr
;
146 FILE* outfile
= fopen(out_filename
, "w");
151 palpic_fileformat(&pp
);
152 fwrite(&pp
, sizeof(pp
), 1, outfile
);
153 fwrite(pal
, sizeof(prgb
) * pp
.palcount
, 1, outfile
);
155 for(sprite
= 0; sprite
< sprite_count
; sprite
++) {
156 for(y
= 0; y
< sprite_h
; y
++) {
157 unsigned sprite_start_y
= get_sprite_start(sprite
, y
, sprite_w
, sprite_h
, sprites_per_row
);
158 bufptr
= &((prgb
*) pix32
->data
)[sprite_start_y
];
160 for(x
= 0; x
< sprite_w
; x
++) {
161 for(p
= 0; p
< pp
.palcount
; p
++)
162 if(pal
[p
].val
== bufptr
->val
) {
164 fwrite(&val
, sizeof(val
), 1, outfile
);
167 fprintf(stderr
, "bug: could not find color in palette\n");
176 snprintf(buf
, sizeof(buf
),
177 "#include \"palpic.h\"\n"
178 "#define PAL_COUNT %d\n"
179 "#define SPRITE_COUNT %d\n"
181 "#define HEIGHT %d\n"
184 "#define STRUCT_NAME %s\n\n"
185 "static const struct {\n"
186 "\tstruct palpic header;\n"
187 "\tprgb palette[PAL_COUNT];\n"
188 "\tuint8_t data[WIDTH * HEIGHT];\n"
189 "} STRUCT_NAME = { \n"
190 "\t{ {'p', 'P', 'i', 'C', }, 1, PAL_COUNT, SPRITE_COUNT, WIDTH, HEIGHT, %s, 0 },\n"
197 (pp
.flags
& PPF_TRANSPARENT
? "PPF_TRANSPARENT" : "0")
199 fwrite(buf
, strlen(buf
), 1, outfile
);
201 for(p
= 0; p
< pp
.palcount
; p
++) {
202 if(p
== 0 && pp
.flags
& PPF_TRANSPARENT
)
203 snprintf(buf
, sizeof(buf
), "PRGB(%3u, %3u, %3u), ", (unsigned) 0,(unsigned) 0, (unsigned) 0);
205 snprintf(buf
, sizeof(buf
), "PRGB(%3u, %3u, %3u), ", (unsigned) pal
[p
].colors
.r
,(unsigned) pal
[p
].colors
.g
, (unsigned) pal
[p
].colors
.b
);
206 fwrite(buf
, strlen(buf
), 1, outfile
);
208 fwrite(STRSZ("\n\t\t"), 1, outfile
);
211 snprintf(buf
, sizeof(buf
), "\n\t},\n\t{\n\t\t");
212 fwrite(buf
, strlen(buf
), 1, outfile
);
213 unsigned counter
= 0;
214 unsigned values_per_line
= sprite_w
;
215 const char *value_format
= pp
.palcount
> 99 ? "%3u," : "%2u,";
216 const char *o_format
= pp
.palcount
> 99 ? " o," : " o,";
217 for(sprite
= 0; sprite
< sprite_count
; sprite
++) {
218 fprintf(outfile
, "/* sprite #%.3u */\n\t\t", sprite
);
219 for(y
= 0; y
< sprite_h
; y
++) {
220 unsigned sprite_start_y
= get_sprite_start(sprite
, y
, sprite_w
, sprite_h
, sprites_per_row
);
221 assert(sprite_start_y
+ sprite_w
<= h
* w
);
222 bufptr
= &((prgb
*) pix32
->data
)[sprite_start_y
];
224 for(x
= 0; x
< sprite_w
; x
++) {
225 for(p
= 0; p
< pp
.palcount
; p
++) {
226 if(pal
[p
].val
== bufptr
->val
) {
228 snprintf(buf
, sizeof(buf
), o_format
);
230 snprintf(buf
, sizeof(buf
), value_format
, (unsigned) p
);
231 fwrite(buf
, strlen(buf
), 1, outfile
);
232 if(counter
% values_per_line
== values_per_line
- 1)
233 fwrite(STRSZ("\n\t\t"), 1, outfile
);
237 fprintf(stderr
, "bug: could not find color in palette\n");
246 fwrite(STRSZ("\n\t},\n"), 1, outfile
);
248 snprintf(buf
, sizeof(buf
),
252 "#undef SPRITE_COUNT\n"
255 "#undef STRUCT_NAME\n\n");
256 fwrite(buf
, strlen(buf
), 1, outfile
);