Updated copyright notice to 2013
[xboard.git] / zic2xpm.c
1 /*
2         zic2xpm.c
3
4         Program to convert pieces from ZIICS format to XPM & XIM format.
5         (C version)  By Frank McIngvale <frankm@hiwaay.net>.
6
7         Copyright (C) 1996, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
8
9         NOTICE: The piece images distributed with ZIICS are
10             copyrighted works of their original creators.  Images 
11             converted with zic2xpm may not be redistributed without
12             the permission of the copyright holders.  Do not contact
13             the authors of zic2xpm or of ZIICS itself to request
14             permission. 
15
16         NOTICE:  The format of the ZIICS piece file was gleaned from
17             SHOWSETS.PAS, a part of ZIICS.  Thanks to Andy McFarland
18             (Zek on ICC) for making this source available!  ZIICS is a 
19             completely separate and copyrighted work of Andy
20             McFarland.  Use and distribution of ZIICS falls under the
21             ZIICS license, NOT the GNU General Public License.
22
23         NOTICE: The format of the VGA imageblocks was determined
24             by experimentation, and without access to any
25             of Borland Inc.'s BGI library source code.
26
27
28             GNU XBoard is free software: you can redistribute it
29             and/or modify it under the terms of the GNU General Public
30             License as published by the Free Software Foundation,
31             either version 3 of the License, or (at your option) any
32             later version.
33             
34             GNU XBoard is distributed in the hope that it will be
35             useful, but WITHOUT ANY WARRANTY; without even the implied
36             warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
37             PURPOSE. See the GNU General Public License for more
38             details.
39             
40             You should have received a copy of the GNU General Public
41             License along with this program. If not, see
42             http://www.gnu.org/licenses/.
43
44
45         ** If you find a bug in zic2xpm.c, please report it to me,
46            Frank McIngvale (frankm@hiwaay.net) so that I may fix it. **
47 */
48
49 /*
50         Usage: zic2xpm file1 [file2 ...]
51
52         We split the ZIICS file(s) into 24 XPM & 24 XIM files with names:
53
54         <piece><type><size>.(xpm|xim).
55
56         Where:
57                 piece = p, n, b, r, q, k
58                 type = ll, ld, dl, dd
59                 size = Piece size.
60
61         Plus 4 files for the light & dark squares.
62         
63         This means that you can extract multiple SIZES in one directory
64         without name clashes. Extracting two sets of the SAME
65         size in a directory will cause the second to overwrite
66         the first.
67 */
68
69 /*
70    Technical note: Yes, this file is huge. I made it by cramming
71                    `zic2xpm' and `zic2xim' together. This should
72                    be less confusing to use, though.
73 */
74
75 #include "config.h"
76 #include <stdio.h>
77 #if STDC_HEADERS
78 #include <stdlib.h>
79 #endif
80
81 #ifndef SEEK_SET
82 #define SEEK_SET 0
83 #endif
84
85 /*
86    XIM file format:
87
88    width        byte
89    height       byte
90
91    Data (1 byte per pixel, row major)
92 */
93
94 /*
95    Map colors from ZIICS -> XIM :
96
97    0    0       Dark piece
98    2    1       Dark square
99    15   2       Light piece
100    14   3       Light square
101 */
102
103 typedef struct {
104   int zval;             /* ZIICS value */
105   int xval;             /* XIM value */
106 } z2xim;
107
108 /* Associate VGA color with XPM color/sym */
109
110 typedef struct {
111   int cval;             /* VGA pixel value */
112   char xchar;   /* XPM character for this color */
113   char *csym;   /* Symbolic name */
114   char *cdefault; /* Default color */
115 } z2xpm;
116
117 #define NR_ZIICS_COLORS 4
118 #define BUFLEN 100
119
120 /* SHOWSETS.PAS (from ZIICS) states that images may only
121    use color numbers 0, 2, 14, and 15 */
122
123 z2xim z2xim_tab[NR_ZIICS_COLORS] = {
124   { 0, 0 },
125   { 2, 1 },
126   { 15, 2 },
127   { 14, 3 } };
128
129 z2xpm z2xpm_tab[NR_ZIICS_COLORS] = {
130   { 15, 'X', "light_piece", "white" },
131   { 0, ' ', "dark_piece", "black" },
132   { 14, '*', "light_square", "gray" },
133   { 2, '.', "dark_square", "green" } };
134
135 void
136 fatal (char *str)
137 {
138   printf("Fatal error: %s\n", str );
139   exit(1);
140 }
141
142 z2xim *
143 lookup_xim_color (int color)
144 {
145   int i;
146
147   for( i=0; i<NR_ZIICS_COLORS; ++i )
148         {
149           if ( z2xim_tab[i].zval == color )
150                 return (z2xim_tab + i);
151         }
152
153   fatal("Illegal color in image.");
154
155   /* NOT REACHED */
156   return NULL;                                  /* Make compiler happy */
157 }
158
159 z2xpm *
160 lookup_xpm_color (int color)
161 {
162   int i;
163
164   for( i=0; i<NR_ZIICS_COLORS; ++i )
165         {
166           if ( z2xpm_tab[i].cval == color )
167                 return (z2xpm_tab + i);
168         }
169
170   fatal("Illegal color in image.");
171
172   /* NOT REACHED */
173   return NULL;                                  /* Make compiler happy */
174 }
175
176 char *src_name;
177
178 int
179 up8 (int i)
180 {
181   int r;
182
183   r = i % 8;
184   if ( r == 0 )
185         return i;
186
187   return i + 8 - r;
188 }
189
190 unsigned int
191 vga_imagesize (int w, int h)
192 {
193   int w8;
194   unsigned int s;
195
196   w8 = up8( w );
197
198   s = 4 + w8/2 * h + 2;
199
200   return s;
201 }
202
203 unsigned char *
204 decode_byte (unsigned char *dest, unsigned char *b, int w)
205 {
206   int i, j;
207   unsigned char byte, bit;
208
209   for( i=7; w > 0; --i, --w )
210         {
211           byte = 0;
212
213           /* 1 bit from each plane */
214           for( j=0; j<4; ++j )
215                 {
216                   bit = b[j];
217                   bit &= (1 << i);
218                   bit >>= i;
219                   bit <<= 3-j;
220                   byte |= bit;
221                 }
222
223           *(dest++) = byte;
224         }
225
226   return dest;
227 }
228
229 /*
230    W is width of image in PIXELS.
231    SRC is in packed pixel format.
232    DEST is filled with 1 BYTE per PIXEL.
233 */
234 unsigned char *
235 decode_line (unsigned char *dest, unsigned char *src, int w)
236 {
237   unsigned int w8;
238   unsigned int bpp;
239   unsigned char b[4];
240   int i;
241   unsigned char *p;
242
243   p = src;
244   w8 = up8( w );
245
246   /* 4 planes, bpp BYTES per plane */
247   /* Planes are MSB -> LSB */
248   bpp = w8 >> 3;
249
250   while( w > 0 )
251         {
252           for( i=0; i<4; ++i )
253                 b[i] = p[i*bpp];
254
255           if ( w > 8 )
256                 dest = decode_byte( dest, b, 8 );
257           else
258                 dest = decode_byte( dest, b, w );
259
260           w -= 8;
261           ++p;
262         }
263
264   return (src + bpp * 4);
265 }
266
267 int
268 write_xim_header (FILE *fp, int w, int h)
269 {
270   fputc( w, fp );
271   fputc( h, fp );
272   
273   return 0;
274 }
275
276 int
277 write_xpm_header (FILE *fp, int w, int h)
278 {
279   int i;
280   z2xpm *cv;
281
282   fprintf(fp, "/* XPM */\n");
283   fprintf(fp, "/* This file was automatically generated from the file %s\n",
284           src_name );
285   fprintf(fp, "using the program ``zic2xpm''.\n");
286   fprintf(fp, "\n    %s\n    %s\n    %s\n    %s\n    %s\n    %s */\n",
287           "NOTICE: The piece images distributed with ZIICS are",
288           "    copyrighted works of their original creators.  Images",
289           "    converted with zic2xpm may not be redistributed without",
290           "    the permission of the copyright holders.  Do not contact",
291           "    the authors of zic2xpm or of ZIICS itself to request",
292           "    permission.");
293   fprintf( fp, "static char * image_name[] = {\n" );
294   fprintf( fp, "\"%d %d %d 1\",\n", h, w, NR_ZIICS_COLORS );
295
296   cv = z2xpm_tab;
297
298   for( i=0; i<NR_ZIICS_COLORS; ++i, ++cv )
299         {
300           fprintf( fp, "\"%c\tc %s s %s\",\n", cv->xchar,
301                           cv->cdefault, cv->csym );
302         }
303
304   return 0;
305 }
306
307 void
308 create_piece_xim (char *outname, FILE *fpin, int W, int H)
309 {
310   FILE *fpout;
311   int w, h, i, j, c;
312   unsigned char *lump, *p, *line;
313   long size;
314   z2xim *ent;
315   
316   fpout = fopen( outname, "wb" );
317   if ( !fpout )
318         fatal( "Can't create output file.");
319
320   /* Header is two ints -- Width then Height, x86 format */
321   c = fgetc( fpin );
322   w = (fgetc(fpin) << 8) | c;
323
324   c = fgetc( fpin );
325   h = (fgetc(fpin) << 8) | c;
326   
327   ++w; ++h;
328
329   if ( w != W || h != H )
330         fatal( "Bad header." );   
331
332   size = vga_imagesize( w, h ) - 4;
333   lump = (unsigned char*)malloc( size );
334   line = (unsigned char*)malloc( w );
335
336   if ( !lump || !line )
337         fatal( "Out of memory." );
338
339   fread( lump, 1, size, fpin );
340
341   /* Write XIM header */
342   write_xim_header( fpout, w, h );
343
344   p = lump;
345   
346   /* Write XIM data */
347   for( i=0; i<h; ++i )
348         {
349           p = decode_line( line, p, w );
350           
351           for( j=0; j<w; ++j )
352                 {
353                   ent = lookup_xim_color( line[j] );
354                   fputc( ent->xval, fpout );
355                 }
356         }
357   
358   free( lump );
359   free( line );
360   fclose( fpout );
361 }
362
363 void
364 create_piece_xpm (char *outname, FILE *fpin, int W, int H)
365 {
366   FILE *fpout;
367   int w, h, i, j, c;
368   unsigned char *lump, *p, *line;
369   long size;
370   z2xpm *cv;
371   
372   fpout = fopen( outname, "wb" );
373   if ( !fpout )
374         fatal( "Can't create output file.");
375
376   /* Header is two ints -- Width then Height, x86 format */
377   c = fgetc( fpin );
378   w = (fgetc(fpin) << 8) | c;
379
380   c = fgetc( fpin );
381   h = (fgetc(fpin) << 8) | c;
382   
383   ++w; ++h;
384
385   if ( w != W || h != H )
386         fatal( "Bad header." );   
387
388   size = vga_imagesize( w, h ) - 4;
389   lump = (unsigned char*)malloc( size );
390   line = (unsigned char*)malloc( w );
391
392   if ( !lump || !line )
393         fatal( "Out of memory." );
394
395   fread( lump, 1, size, fpin );
396
397   /* Write XPM header */
398   write_xpm_header( fpout, w, h );
399
400   p = lump;
401   
402   /* Write XPM data */
403   for( i=0; i<h; ++i )
404         {
405           p = decode_line( line, p, w );
406           
407           fprintf( fpout, "\"" );
408           for( j=0; j<w; ++j )
409                 {
410                   cv = lookup_xpm_color( line[j] );
411                   fprintf( fpout, "%c", cv->xchar );
412                 }
413           fprintf( fpout, "\",\n" );
414         }
415
416   fprintf( fpout, "};\n" );
417   
418   free( lump );
419   free( line );
420   fclose( fpout );
421 }
422
423 /* The order of the pieces in the ZIICS piece file (from SHOWSETS.PAS) */
424 char *pieces = "prkqbn";
425 char *pname[] = { "Pawn", "Rook", "King", "Queen", "Bishop", "Knight" };
426
427 /* The suborder - Light/Light, Light/Dark, etc. */
428 char *prefixes[] = { "ll", "ld", "dl", "dd" };
429
430 int
431 process_file_xim (char *filename)
432 {
433   int w, h, piece, kind, c;
434   int nr_pieces = 6;
435   int nr_kinds = 4;
436   FILE *fp;
437   char buf[BUFLEN];
438
439   src_name = filename;
440   
441   fp = fopen( filename, "rb" );
442   if ( !fp )
443         fatal( "Can't open input file." );
444   
445   /* Header is two ints -- Width then Height, x86 format */
446   c = fgetc( fp );
447   w = (fgetc(fp) << 8) | c;
448
449   c = fgetc( fp );
450   h = (fgetc(fp) << 8) | c;
451   
452   ++w; ++h;
453
454   if ( w != h )
455         {
456           printf("ERROR: Can only convert square pieces.\n");
457           printf("       (This set is %dx%d)\n", w, h );
458           exit(1);
459         }
460
461   printf("Creating XIM files...\n");
462   printf("File: %s, W=%d, H=%d\n", filename, w, h );
463   fseek( fp, 0, SEEK_SET );
464   
465   /* Write .XIM files */
466   for( piece = 0; piece < nr_pieces; ++piece )
467         {
468           printf("%s ", pname[piece] );
469           
470           for( kind = 0; kind < nr_kinds; ++kind )
471                 {
472                   printf( "." );
473                   /* Form output filename -- <piece><kind><size>.xim */
474                   snprintf(buf, BUFLEN, "%c%s%d.xim", pieces[piece], prefixes[kind], w);
475                   create_piece_xim( buf, fp, w, h );
476                 }
477           printf("\n");
478         }
479
480   /* Write the light & dark squares */
481   snprintf( buf, BUFLEN, "lsq%d.xim", w );
482   printf("Light Square" );
483   create_piece_xim( buf, fp, w, h );
484
485   snprintf( buf, BUFLEN, "dsq%d.xim", w );
486   printf("\nDark Square" );
487   create_piece_xim( buf, fp, w, h );  
488   printf("\n");
489   
490   printf("Successfully converted!!\n" );
491
492   fclose( fp );
493   
494   return 0;
495 }
496
497 int
498 process_file_xpm (char *filename)
499 {
500   int w, h, piece, kind, c;
501   int nr_pieces = 6;
502   int nr_kinds = 4;
503   FILE *fp;
504   char buf[BUFLEN];
505
506   src_name = filename;
507   
508   fp = fopen( filename, "rb" );
509   if ( !fp )
510         fatal( "Can't open input file." );
511   
512   /* Header is two ints -- Width then Height, x86 format */
513   c = fgetc( fp );
514   w = (fgetc(fp) << 8) | c;
515
516   c = fgetc( fp );
517   h = (fgetc(fp) << 8) | c;
518   
519   ++w; ++h;
520
521   if ( w != h )
522         {
523           printf("ERROR: Can only convert square pieces.\n");
524           printf("       (This set is %dx%d)\n", w, h );
525           exit(1);
526         }
527   
528   printf("Creating XPM files...\n");
529   printf("File: %s, W=%d, H=%d\n", filename, w, h );
530   fseek( fp, 0, SEEK_SET );
531   
532   /* Write .XPM files */
533   for( piece = 0; piece < nr_pieces; ++piece )
534         {
535           printf("%s ", pname[piece] );
536           
537           for( kind = 0; kind < nr_kinds; ++kind )
538                 {
539                   printf( "." );
540                   /* Form output filename -- <piece><kind><size>.xpm */
541                   snprintf(buf, BUFLEN, "%c%s%d.xpm", pieces[piece], prefixes[kind], w);
542                   create_piece_xpm( buf, fp, w, h );
543                 }
544           printf("\n");
545         }
546
547   /* Write the light & dark squares */
548   snprintf( buf, BUFLEN, "lsq%d.xpm", w );
549   printf("Light Square" );
550   create_piece_xpm( buf, fp, w, h );
551
552   snprintf( buf, BUFLEN, "dsq%d.xpm", w );
553   printf("\nDark Square" );
554   create_piece_xpm( buf, fp, w, h );  
555   printf("\n");
556   
557   printf("Successfully converted!!\n" );
558
559   fclose( fp );
560   
561   return 0;
562 }
563
564 int
565 main (int argc, char **argv)
566 {
567   int i;
568   
569   if ( argc < 2 )
570         {
571           printf("ZIC2XPM 2.01 - by Frank McIngvale (frankm@hiwaay.net)\n");
572           printf("Copyright (C) 1996 Free Software Foundation, Inc.\n\n");
573           printf("Usage: zic2xpm file1 [file2 ...]\n\n");
574           printf("  Splits each file (ZIICS piece files) into 26 XPM & XIM files\n");
575           printf("  suitable for use in XBoard 3.5 or later.\n");
576           printf("\n* ZIICS is a copyrighted work of Andy McFarland (Zek on ICC) *\n");
577           return 1;
578         }
579
580
581   setbuf( stdout, NULL );
582   
583   for( i=1; i<argc; ++i )
584         {
585           process_file_xpm( argv[i] );
586           process_file_xim( argv[i] );
587         }
588   
589   fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
590           "NOTICE: The piece images distributed with ZIICS are",
591           "    copyrighted works of their original creators.  Images",
592           "    converted with zic2xpm may not be redistributed without",
593           "    the permission of the copyright holders.  Do not contact",
594           "    the authors of zic2xpm or of ZIICS itself to request",
595           "    permission.");
596   return 0;
597 }