palpic2png.c: improve, make usable with ppic binary files
[rofl0r-openDOW.git] / utils / 2palpic.c
blob70a3fac28db6983571596cccba951d52d619f0f4
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include "../palpic.h"
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"
12 /* leptonica:
13 enum {
14 COLOR_RED = 0,
15 COLOR_GREEN = 1,
16 COLOR_BLUE = 2,
17 L_ALPHA_CHANNEL = 3
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);
32 return 0;
33 } */
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);
40 return 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);
49 return 1;
52 #define STRSZ(lit) lit, sizeof(lit) - 1
53 #define LIT_SIZE(lit) ( sizeof(lit) - 1)
54 int main(int argc, char** argv) {
55 int w, h;
56 struct palpic pp = palpic_empty;
57 prgb pal[256];
59 struct Pix* infile;
60 struct Pix* pix32;
62 unsigned sprite_w = 0, sprite_h = 0;
63 unsigned sprite_count;
65 int c;
66 while((c = getopt(argc, argv, "s:t")) != EOF) switch(c) {
67 case 't': pp.flags |= PPF_TRANSPARENT; break;
68 case 's': {
69 char* str_w = optarg;
70 char* str_h = strchr(str_w, 'x');
71 *(str_h++) = 0;
72 sprite_w = atoi(str_w);
73 sprite_h = atoi(str_h);
75 }; break;
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) {
85 perror(in_filename);
86 return 1;
89 char* cp;
90 int to_c = (cp = strrchr(out_filename, '.')) && cp == out_filename + strlen(out_filename) - 2 && cp[1] == 'c';
91 char struct_name[256];
92 if(to_c) {
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);
97 struct_name[l-2] = 0;
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);
108 if(rest) {
109 printf("error: the picture dimensions are no multiple of the sprite dimensions!\n");
110 return 1;
112 if(w % sprite_w) {
113 printf("error: the picture width is no multiple of the sprite width!\n");
114 return 1;
116 } else {
117 // no sprite support
118 sprite_w = w;
119 sprite_h = h;
120 sprite_count = 1;
123 unsigned sprites_per_row = w / sprite_w;
125 /* we always align sprites vertically */
126 pp.height = sprite_h * sprite_count;
127 pp.width = sprite_w;
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)
139 goto next_x;
140 pal[pp.palcount++] = *bufptr;
141 next_x:
142 bufptr++;
146 FILE* outfile = fopen(out_filename, "w");
149 unsigned sprite;
150 if(!to_c) {
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) {
163 uint8_t val = p;
164 fwrite(&val, sizeof(val), 1, outfile);
165 goto success;
167 fprintf(stderr, "bug: could not find color in palette\n");
168 return 1;
169 success:
170 bufptr++;
174 } else {
175 char buf[1024];
176 snprintf(buf, sizeof(buf),
177 "#include \"palpic.h\"\n"
178 "#define PAL_COUNT %d\n"
179 "#define SPRITE_COUNT %d\n"
180 "#define WIDTH %d\n"
181 "#define HEIGHT %d\n"
182 "#define o 0\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"
191 "\t{\n\t\t",
192 (int) pp.palcount,
193 (int) sprite_count,
194 (int) pp.width,
195 (int) pp.height,
196 struct_name,
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);
204 else
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);
207 //if(p % 8 == 7)
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) {
227 if(p == 0)
228 snprintf(buf, sizeof(buf), o_format);
229 else
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);
234 goto success2;
237 fprintf(stderr, "bug: could not find color in palette\n");
238 return 1;
239 success2:
240 bufptr++;
241 counter++;
246 fwrite(STRSZ("\n\t},\n"), 1, outfile);
248 snprintf(buf, sizeof(buf),
249 "};\n\n"
250 "#undef o\n"
251 "#undef PAL_COUNT\n"
252 "#undef SPRITE_COUNT\n"
253 "#undef WIDTH\n"
254 "#undef HEIGHT\n"
255 "#undef STRUCT_NAME\n\n");
256 fwrite(buf, strlen(buf), 1, outfile);
259 fclose(outfile);
260 pixDestroy(&pix32);
261 pixDestroy(&infile);
262 return 0;