1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - tools - ppmconvbg
3 File: ppmconvbg.c
4
5 Copyright 2003-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: $
14 $Rev:$
15 $Author:$
16 *---------------------------------------------------------------------------*/
17 //
18 // The 'ppmconvbg' tool is for $TwlSDK/build/demos/tips/OnScreenWarning
19 //
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h> // getopt()
25 #include <ctype.h>
26
27 #ifndef MAX_COLORS
28 #define MAX_COLORS 256 // 256 color limits
29 #endif
30
31 #define TRUE 1
32 #define FALSE 0
33
34 #define NUM_COLUMN_BYTE 16
35 #define NUM_COLUMN_HALF 8
36
37 #define V5bit( x ) ((x)>>3)
38 #define RGB5551( r, g, b, a ) ((V5bit(r)<<0) | (V5bit(g)<<5) | (V5bit(b)<<10)| (((a)&1)<<15))
39
40 #define SIZE_READBUFFER 1024
41
42 enum
43 {
44 PHASE_READ_MAGIC_NUMBER,
45 PHASE_READ_WIDTH,
46 PHASE_READ_HEIGHT,
47 PHASE_READ_DEPTH,
48 };
49
50 enum
51 {
52 COLOR_MAX_8bit = 256,
53 COLOR_MAX_4bit = 16,
54 };
55
56 enum
57 {
58 PARTS_CLUT = 1,
59 PARTS_INDEX = 2,
60 PARTS_ALL = 3,
61 };
62
63 typedef unsigned char u8;
64 typedef unsigned short u16;
65
66 typedef struct
67 {
68 u16 *color;
69 int num_colors;
70 int max_colors;
71 }
72 ColorTable;
73
usage(char * str,int num)74 static void usage(char *str, int num)
75 {
76 if (str)
77 {
78 fprintf(stderr, "Error: ");
79 fprintf(stderr, str, num);
80 fprintf(stderr, "\n\n");
81 }
82 fprintf(stderr,
83 "Usage: ppmconvbg [-a labelname] [-b] [-c [4|8]] [-p] [-i] ppmfile outputfile \n");
84 fprintf(stderr, "\n");
85 fprintf(stderr, " - Read [ppmfile] and convert it to [outputfile]\n");
86 fprintf(stderr, "\n");
87 fprintf(stderr, " -a labelname : output as C source code \n");
88 fprintf(stderr, " -b : output as binary file (default:binary)\n");
89 fprintf(stderr, " -c 4 or 8 : color mode 4bit or 8bit (default:8bit )\n");
90 fprintf(stderr, " -p : output palette data \n");
91 fprintf(stderr, " -i : output color index data\n");
92 fprintf(stderr, "\n");
93
94 exit(1);
95 }
96
97 static int Rgb2Index(int num_pixels, u8 *rgb_buffer, u8 *index_buffer, int max_colors,
98 ColorTable * cp);
99 static void OutputColumnInit(void);
100 static void OutputByte(FILE * fp, int val);
101 static void OutputHalf(FILE * fp, int val);
102 static void OutputIndex(FILE * fp, char *label, int max_colors, int width, int height, u8 *pixel);
103 static void OutputCLUT(FILE * fp, char *label, ColorTable * cp);
104
105 int DebugMode = FALSE;
106
107 /*---------------------------------------------------------------------------*
108 Name: ReadHeader
109
110 Description: Read header information of ppm file
111
112 Arguments: fp ppm file
113 pwidth output ptr for the width of ppm picture
114 pheight output ptr for the height of ppm picture
115 pdepth output ptr for the depth of ppm picture
116
117 Returns: 1 if success, 0 if error
118 *---------------------------------------------------------------------------*/
ReadHeader(FILE * fp,int * pwidth,int * pheight,int * pdepth)119 static int ReadHeader(FILE * fp, int *pwidth, int *pheight, int *pdepth)
120 {
121 // Get ppm header
122 //
123 // P6[WS]256[WS]192[WS]255[WS]\n WS=Space,Tab,CR
124 //
125 char buffer[SIZE_READBUFFER], *p;
126 int n;
127 int phase = PHASE_READ_MAGIC_NUMBER;
128
129 while (buffer == fgets(buffer, sizeof(buffer), fp))
130 {
131 if (buffer[0] == '#') // comment
132 {
133 continue;
134 }
135
136 p = buffer;
137 while (*p != '\0')
138 {
139 switch (phase)
140 {
141 case PHASE_READ_MAGIC_NUMBER:
142 if (0 != sscanf(p, "P6%n", &n))
143 {
144 return FALSE; // not ppm file
145 }
146 phase = PHASE_READ_WIDTH;
147 break;
148
149 case PHASE_READ_WIDTH:
150 if (1 != sscanf(p, "%d%n", pwidth, &n))
151 {
152 return FALSE;
153 }
154 phase = PHASE_READ_HEIGHT;
155 break;
156
157 case PHASE_READ_HEIGHT:
158 if (1 != sscanf(p, "%d%n", pheight, &n))
159 {
160 return FALSE;
161 }
162 phase = PHASE_READ_DEPTH;
163 break;
164
165 case PHASE_READ_DEPTH:
166 if (1 != sscanf(p, "%d%n", pdepth, &n))
167 {
168 return FALSE;
169 }
170 return TRUE;
171
172 default:
173 break;
174 }
175
176 for (p += n; isspace(*p); p++)
177 {
178 // Do nothing
179 }
180 }
181 }
182 return FALSE;
183 }
184
185
186 /*---------------------------------------------------------------------------*
187 Name: ReadBody
188
189 Description: Read picture image
190
191 Arguments: fp ppm file
192 buffer output ptr for image
193 size buffer size
194
195 Returns: 1 if success, 0 if error
196 *---------------------------------------------------------------------------*/
ReadBody(FILE * fp,u8 * buffer,int size)197 static int ReadBody(FILE * fp, u8 *buffer, int size)
198 {
199 return size == fread(buffer, sizeof(u8), size, fp);
200 }
201
202
203 /*---------------------------------------------------------------------------*
204 Name: ColorTableInit
205
206 Description: Initialize Color Table
207
208 Arguments: None
209
210 Returns: N/A
211 *---------------------------------------------------------------------------*/
ColorTableInit(ColorTable * t,int max_colors)212 static void ColorTableInit(ColorTable * t, int max_colors)
213 {
214 if (NULL == (t->color = (u16 *)calloc(max_colors, sizeof(u16))))
215 {
216 fprintf(stderr, "Cannot allocate memory.");
217 exit(1);
218 }
219
220 t->num_colors = 0;
221 t->max_colors = max_colors;
222 }
223
224 /*---------------------------------------------------------------------------*
225 Name: ColorTableAppend
226
227 Description: Get color index from Color Table
228
229 Arguments: t ptr for color table
230 color color to be added
231
232 Returns: >= 0 : index number if color is in color table
233 == -1 : error no room to append color
234 *---------------------------------------------------------------------------*/
ColorTableAppend(ColorTable * t,u16 color)235 static int ColorTableAppend(ColorTable * t, u16 color)
236 {
237 int i;
238
239 for (i = 0; i < t->num_colors; i++)
240 {
241 if (t->color[i] == color)
242 {
243 return i;
244 }
245 }
246
247 if (i >= t->max_colors)
248 {
249 return -1;
250 }
251
252 t->color[i] = color;
253 t->num_colors++;
254 return i;
255 }
256
257
258 /*---------------------------------------------------------------------------*
259 Name: ColorTableGetColor
260
261 Description: Get color from Color Table
262
263 Arguments: None
264
265 Returns: color u16
266 *---------------------------------------------------------------------------*/
ColorTableGetColor(ColorTable * t,int index)267 static u16 ColorTableGetColor(ColorTable * t, int index)
268 {
269 return index < t->num_colors ? t->color[index] : 0x0000;
270 }
271
272
273 /*---------------------------------------------------------------------------*
274 Name: Rgb2Index
275
276 Description: Convert Rgb to index
277
278 Arguments: None
279
280 Returns:
281 *---------------------------------------------------------------------------*/
Rgb2Index(int num_pixels,u8 * rgb_buffer,u8 * index_buffer,int max_colors,ColorTable * cp)282 static int Rgb2Index(int num_pixels, u8 *rgb_buffer, u8 *index_buffer, int max_colors,
283 ColorTable * cp)
284 {
285 int i, n;
286
287 ColorTableInit(cp, max_colors);
288
289 for (i = n = 0; i < num_pixels; i++, n += 3)
290 {
291 int index;
292 u16 color;
293
294 color = RGB5551(rgb_buffer[n], rgb_buffer[n + 1], rgb_buffer[n + 2], 1);
295 index = ColorTableAppend(cp, color);
296
297 if (index < 0)
298 {
299 fprintf(stderr, "ppmconvbg: Error too many colors (over %d)\n", max_colors);
300 return FALSE;
301 }
302
303 index_buffer[i] = index;
304 }
305 return TRUE;
306 }
307
308
309 /*---------------------------------------------------------------------------*
310 Name: Output Byte/Half
311
312 Description: Output Byte
313
314 Arguments: fp output file
315 val byte value
316
317 Returns: None
318 *---------------------------------------------------------------------------*/
319 static int OutputColumn = 0;
320
OutputColumnInit(void)321 static void OutputColumnInit(void)
322 {
323 OutputColumn = 0;
324 }
325
OutputByte(FILE * fp,int val)326 static void OutputByte(FILE * fp, int val)
327 {
328 if (OutputColumn % NUM_COLUMN_BYTE == 0)
329 fprintf(fp, "\t");
330
331 fprintf(fp, "0x%02x, ", val);
332
333 OutputColumn++;
334 if (OutputColumn % NUM_COLUMN_BYTE == 0)
335 fprintf(fp, "\n");
336 }
337
OutputHalf(FILE * fp,int val)338 static void OutputHalf(FILE * fp, int val)
339 {
340 if (OutputColumn % NUM_COLUMN_HALF == 0)
341 fprintf(fp, "\t");
342
343 fprintf(fp, "0x%04x, ", val);
344
345 OutputColumn++;
346 if (OutputColumn % NUM_COLUMN_HALF == 0)
347 fprintf(fp, "\n");
348 }
349
350
351 /*---------------------------------------------------------------------------*
352 Name: Output Color Table
353
354 Description: Output Color Lookup Table
355
356 Arguments: fp output file
357 label label name
358 cp CLUT
359
360 Returns: None
361 *---------------------------------------------------------------------------*/
OutputCLUT(FILE * fp,char * label,ColorTable * cp)362 static void OutputCLUT(FILE * fp, char *label, ColorTable * cp)
363 {
364 // Round up num_colors for alignment
365 if (cp->num_colors % 2)
366 {
367 cp->num_colors++;
368 }
369
370 // Show color table
371 if (label)
372 {
373 int i;
374 OutputColumnInit();
375
376 fprintf(fp, "const int Num_%s_Palette = %d;\n\n", label, cp->num_colors);
377 fprintf(fp, "const unsigned short %s_Palette[] =\n{\n", label);
378
379 for (i = 0; i < cp->num_colors; i++)
380 {
381 OutputHalf(fp, ColorTableGetColor(cp, i));
382 }
383 fprintf(fp, "\n};\n\n");
384 }
385 else
386 {
387 // Colors
388 fwrite(cp->color, sizeof(u16), cp->num_colors, fp);
389 }
390 return;
391 }
392
393
394 /*---------------------------------------------------------------------------*
395 Name: Output Index
396
397 Description: Output Index
398
399 Arguments: fp output file
400 label label name
401 cp CLUT
402
403 Returns: None
404 *---------------------------------------------------------------------------*/
OutputIndex(FILE * fp,char * label,int max_colors,int width,int height,u8 * pixel)405 static void OutputIndex(FILE * fp, char *label, int max_colors, int width, int height, u8 *pixel)
406 {
407 // Show color index
408 if (label)
409 {
410 int i, j, ii, jj, n;
411
412 OutputColumnInit();
413
414 fprintf(fp, "const int Num_%s_Texel = %d * %d;\n\n", label, width, height);
415 fprintf(fp, "const unsigned char %s_Texel[] =\n{\n", label);
416
417 for (i = 0; i < height; i += 8)
418 {
419 for (j = 0; j < width; j += 8)
420 {
421 for (ii = 0; ii < 8; ii++)
422 {
423 for (jj = 0; jj < 8; jj++)
424 {
425 n = (i + ii) * width + j + jj;
426
427 if (max_colors == COLOR_MAX_8bit)
428 {
429 OutputByte(fp, pixel[n]);
430 }
431 else if (n % 2 == 1)
432 {
433 OutputByte(fp, (pixel[n] << 4) | (pixel[n - 1] & 15));
434 }
435 }
436 }
437 }
438 }
439 fprintf(fp, "\n};\n\n");
440 }
441 else
442 {
443 int i, j, ii, jj, n;
444 u8 buffer;
445
446 // Colors
447 for (i = 0; i < height; i += 8)
448 {
449 for (j = 0; j < width; j += 8)
450 {
451 for (ii = 0; ii < 8; ii++)
452 {
453 for (jj = 0; jj < 8; jj++)
454 {
455 n = (i + ii) * width + j + jj;
456
457 if (max_colors == COLOR_MAX_8bit)
458 {
459 fwrite(&pixel[n], sizeof(u8), 1, fp);
460 }
461 else if (n % 2 == 1)
462 {
463 buffer = (u8)(pixel[n] << 4) | (pixel[n - 1] & 15);
464 fwrite(&buffer, sizeof(u8), 1, fp);
465 }
466 }
467 }
468 }
469 }
470 }
471 return;
472 }
473
474
475 /*---------------------------------------------------------------------------*
476 Name: Convert
477
478 Description: Convert ppm file
479
480 Arguments: ppmfile ppm file
481 outfile output file
482 colormax max of color
483 valuelabel labelname for C source mode if not NULL
484 binary mode if NULL
485
486 Returns:
487 *---------------------------------------------------------------------------*/
Convert(char * ppmfile,char * outfile,int parts,int colormax,char * valuelabel)488 int Convert(char *ppmfile, char *outfile, int parts, int colormax, char *valuelabel)
489 {
490 int result;
491 FILE *fp = NULL;
492 u8 *rgb_buffer = NULL;
493 u8 *index_buffer = NULL;
494
495 int width;
496 int height;
497 int depth;
498 int num_pixels;
499
500 ColorTable clut = { 0 };
501
502 //
503 // Read PPM file into rgb_buffer
504 //
505 fp = fopen(ppmfile, "rb");
506 if (!fp)
507 goto error;
508
509 result = ReadHeader(fp, &width, &height, &depth);
510 if (!result || depth != 255)
511 goto error;
512
513 num_pixels = width * height;
514
515 rgb_buffer = (u8 *)malloc(num_pixels * 3);
516 if (!rgb_buffer)
517 goto error;
518
519 result = ReadBody(fp, rgb_buffer, num_pixels * 3);
520 if (!result)
521 goto error;
522
523 fclose(fp);
524 fp = NULL;
525
526 //
527 // Convert to index_buffer & clut
528 //
529 index_buffer = (u8 *)malloc(num_pixels * 1);
530 if (!index_buffer)
531 goto error;
532
533 result = Rgb2Index(num_pixels, rgb_buffer, index_buffer, colormax, &clut);
534 if (!result)
535 goto error;
536
537 free(rgb_buffer);
538 rgb_buffer = NULL;
539
540 //
541 // Write clut & index
542 //
543 fp = fopen(outfile, valuelabel ? "w" : "wb");
544 if (!fp)
545 goto error;
546
547 if (parts & PARTS_CLUT)
548 {
549 OutputCLUT(fp, valuelabel, &clut);
550 }
551 if (parts & PARTS_INDEX)
552 {
553 OutputIndex(fp, valuelabel, colormax, width, height, index_buffer);
554 }
555 fclose(fp);
556 free(index_buffer);
557 free(clut.color);
558 return TRUE;
559
560 error:
561 if (rgb_buffer)
562 free(rgb_buffer);
563 if (clut.color)
564 free(clut.color);
565 if (index_buffer)
566 free(index_buffer);
567 if (fp)
568 fclose(fp);
569
570 fprintf(stderr, "Cannot convert file \"%s\".\n", ppmfile);
571 return FALSE;
572 }
573
574
575 /*---------------------------------------------------------------------------*
576 Name: main
577
578 Description: output 256 color-ed ppm image bitmap as the format
579 like C source code
580 *---------------------------------------------------------------------------*/
main(int argc,char * argv[])581 int main(int argc, char *argv[])
582 {
583 int n;
584 int ColorMax = COLOR_MAX_8bit;
585 char *ValueLabel = NULL;
586 int Parts = PARTS_ALL;
587 int result;
588
589 while ((n = getopt(argc, argv, "ba:c:pihvd")) != -1)
590 {
591 switch (n)
592 {
593 case 'b':
594 if (ValueLabel)
595 free(ValueLabel);
596 ValueLabel = NULL; // BinaryMode
597 break;
598
599 case 'a':
600 if (ValueLabel)
601 free(ValueLabel);
602 ValueLabel = strdup(optarg); // Source Mode
603 break;
604
605 case 'c':
606 if (!strcmp(optarg, "8"))
607 ColorMax = COLOR_MAX_8bit;
608 else if (!strcmp(optarg, "4"))
609 ColorMax = COLOR_MAX_4bit;
610 else
611 usage("-c : must be followed by 8 or 4", 0); // Never returns
612 break;
613
614 case 'd':
615 DebugMode = TRUE;
616 break;
617
618 case 'p':
619 Parts = (Parts == PARTS_INDEX) ? PARTS_ALL : PARTS_CLUT;
620 break;
621
622 case 'i':
623 Parts = (Parts == PARTS_CLUT) ? PARTS_ALL : PARTS_INDEX;
624 break;
625
626 case 'h':
627 case 'v':
628 if (ValueLabel)
629 free(ValueLabel);
630 usage(NULL, 0); // Never returns
631 break;
632
633 default:
634 if (ValueLabel)
635 free(ValueLabel);
636 usage("-%c : Unknown option", n); // Never returns
637 break;
638 }
639
640 if (DebugMode)
641 {
642 fprintf(stderr, "option -%c: %s\n", n, optarg ? optarg : "No ARG");
643 }
644 }
645
646 if (DebugMode)
647 {
648 int i;
649
650 fprintf(stderr, "argc=%d optind=%d\n", argc, optind);
651 for (i = optind; i < argc; i++)
652 {
653 fprintf(stderr, "argv[%d] = [%s]\n", i, argv[i]);
654 }
655 }
656
657 argc -= optind;
658 argv += optind;
659
660 if (argc != 2)
661 {
662 if (ValueLabel)
663 free(ValueLabel);
664 usage("need 2 arguments", 0);
665 // Never returns
666 }
667
668 result = Convert(argv[0], argv[1], Parts, ColorMax, ValueLabel);
669
670 if (ValueLabel)
671 free(ValueLabel);
672
673 return result ? 0 : 1;
674 }
675