Updated copyright notice to 2011
[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 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 fatal( str )
136          char *str;
137 {
138   printf("Fatal error: %s\n", str );
139   exit(1);
140 }
141
142 z2xim *lookup_xim_color( color )
143          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 *lookup_xpm_color( color )
160          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 up8( i )
179          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 vga_imagesize( w, h )
191          int w, 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 *decode_byte( dest, b, w )
204          unsigned char *dest, *b;
205          int w;
206 {
207   int i, j;
208   unsigned char byte, bit;
209
210   for( i=7; w > 0; --i, --w )
211         {
212           byte = 0;
213
214           /* 1 bit from each plane */
215           for( j=0; j<4; ++j )
216                 {
217                   bit = b[j];
218                   bit &= (1 << i);
219                   bit >>= i;
220                   bit <<= 3-j;
221                   byte |= bit;
222                 }
223
224           *(dest++) = byte;
225         }
226
227   return dest;
228 }
229
230 /*
231    W is width of image in PIXELS.
232    SRC is in packed pixel format.
233    DEST is filled with 1 BYTE per PIXEL.
234 */
235 unsigned char *decode_line( dest, src, w )
236          unsigned char *dest, *src;
237          int w;
238 {
239   unsigned int w8;
240   unsigned int bpp;
241   unsigned char b[4];
242   int i;
243   unsigned char *p;
244
245   p = src;
246   w8 = up8( w );
247
248   /* 4 planes, bpp BYTES per plane */
249   /* Planes are MSB -> LSB */
250   bpp = w8 >> 3;
251
252   while( w > 0 )
253         {
254           for( i=0; i<4; ++i )
255                 b[i] = p[i*bpp];
256
257           if ( w > 8 )
258                 dest = decode_byte( dest, b, 8 );
259           else
260                 dest = decode_byte( dest, b, w );
261
262           w -= 8;
263           ++p;
264         }
265
266   return (src + bpp * 4);
267 }
268
269 int write_xim_header( fp, w, h )
270          FILE *fp;
271          int w, h;
272 {
273   fputc( w, fp );
274   fputc( h, fp );
275   
276   return 0;
277 }
278
279 int write_xpm_header( fp, w, h )
280          FILE *fp;
281          int w, h;
282 {
283   int i;
284   z2xpm *cv;
285
286   fprintf(fp, "/* XPM */\n");
287   fprintf(fp, "/* This file was automatically generated from the file %s\n",
288           src_name );
289   fprintf(fp, "using the program ``zic2xpm''.\n");
290   fprintf(fp, "\n    %s\n    %s\n    %s\n    %s\n    %s\n    %s */\n",
291           "NOTICE: The piece images distributed with ZIICS are",
292           "    copyrighted works of their original creators.  Images",
293           "    converted with zic2xpm may not be redistributed without",
294           "    the permission of the copyright holders.  Do not contact",
295           "    the authors of zic2xpm or of ZIICS itself to request",
296           "    permission.");
297   fprintf( fp, "static char * image_name[] = {\n" );
298   fprintf( fp, "\"%d %d %d 1\",\n", h, w, NR_ZIICS_COLORS );
299
300   cv = z2xpm_tab;
301
302   for( i=0; i<NR_ZIICS_COLORS; ++i, ++cv )
303         {
304           fprintf( fp, "\"%c\tc %s s %s\",\n", cv->xchar,
305                           cv->cdefault, cv->csym );
306         }
307
308   return 0;
309 }
310
311 void create_piece_xim( outname, fpin, W, H )
312          char *outname;
313          FILE *fpin;
314          int W, H;
315 {
316   FILE *fpout;
317   int w, h, i, j, c;
318   unsigned char *lump, *p, *line;
319   long size;
320   z2xim *ent;
321   
322   fpout = fopen( outname, "wb" );
323   if ( !fpout )
324         fatal( "Can't create output file.");
325
326   /* Header is two ints -- Width then Height, x86 format */
327   c = fgetc( fpin );
328   w = (fgetc(fpin) << 8) | c;
329
330   c = fgetc( fpin );
331   h = (fgetc(fpin) << 8) | c;
332   
333   ++w; ++h;
334
335   if ( w != W || h != H )
336         fatal( "Bad header." );   
337
338   size = vga_imagesize( w, h ) - 4;
339   lump = (unsigned char*)malloc( size );
340   line = (unsigned char*)malloc( w );
341
342   if ( !lump || !line )
343         fatal( "Out of memory." );
344
345   fread( lump, 1, size, fpin );
346
347   /* Write XIM header */
348   write_xim_header( fpout, w, h );
349
350   p = lump;
351   
352   /* Write XIM data */
353   for( i=0; i<h; ++i )
354         {
355           p = decode_line( line, p, w );
356           
357           for( j=0; j<w; ++j )
358                 {
359                   ent = lookup_xim_color( line[j] );
360                   fputc( ent->xval, fpout );
361                 }
362         }
363   
364   free( lump );
365   free( line );
366   fclose( fpout );
367 }
368
369 void create_piece_xpm( outname, fpin, W, H )
370          char *outname;
371          FILE *fpin;
372          int W, H;
373 {
374   FILE *fpout;
375   int w, h, i, j, c;
376   unsigned char *lump, *p, *line;
377   long size;
378   z2xpm *cv;
379   
380   fpout = fopen( outname, "wb" );
381   if ( !fpout )
382         fatal( "Can't create output file.");
383
384   /* Header is two ints -- Width then Height, x86 format */
385   c = fgetc( fpin );
386   w = (fgetc(fpin) << 8) | c;
387
388   c = fgetc( fpin );
389   h = (fgetc(fpin) << 8) | c;
390   
391   ++w; ++h;
392
393   if ( w != W || h != H )
394         fatal( "Bad header." );   
395
396   size = vga_imagesize( w, h ) - 4;
397   lump = (unsigned char*)malloc( size );
398   line = (unsigned char*)malloc( w );
399
400   if ( !lump || !line )
401         fatal( "Out of memory." );
402
403   fread( lump, 1, size, fpin );
404
405   /* Write XPM header */
406   write_xpm_header( fpout, w, h );
407
408   p = lump;
409   
410   /* Write XPM data */
411   for( i=0; i<h; ++i )
412         {
413           p = decode_line( line, p, w );
414           
415           fprintf( fpout, "\"" );
416           for( j=0; j<w; ++j )
417                 {
418                   cv = lookup_xpm_color( line[j] );
419                   fprintf( fpout, "%c", cv->xchar );
420                 }
421           fprintf( fpout, "\",\n" );
422         }
423
424   fprintf( fpout, "};\n" );
425   
426   free( lump );
427   free( line );
428   fclose( fpout );
429 }
430
431 /* The order of the pieces in the ZIICS piece file (from SHOWSETS.PAS) */
432 char *pieces = "prkqbn";
433 char *pname[] = { "Pawn", "Rook", "King", "Queen", "Bishop", "Knight" };
434
435 /* The suborder - Light/Light, Light/Dark, etc. */
436 char *prefixes[] = { "ll", "ld", "dl", "dd" };
437
438 int process_file_xim( filename )
439          char *filename;
440 {
441   int w, h, piece, kind, c;
442   int nr_pieces = 6;
443   int nr_kinds = 4;
444   FILE *fp;
445   char buf[BUFLEN];
446
447   src_name = filename;
448   
449   fp = fopen( filename, "rb" );
450   if ( !fp )
451         fatal( "Can't open input file." );
452   
453   /* Header is two ints -- Width then Height, x86 format */
454   c = fgetc( fp );
455   w = (fgetc(fp) << 8) | c;
456
457   c = fgetc( fp );
458   h = (fgetc(fp) << 8) | c;
459   
460   ++w; ++h;
461
462   if ( w != h )
463         {
464           printf("ERROR: Can only convert square pieces.\n");
465           printf("       (This set is %dx%d)\n", w, h );
466           exit(1);
467         }
468
469   printf("Creating XIM files...\n");
470   printf("File: %s, W=%d, H=%d\n", filename, w, h );
471   fseek( fp, 0, SEEK_SET );
472   
473   /* Write .XIM files */
474   for( piece = 0; piece < nr_pieces; ++piece )
475         {
476           printf("%s ", pname[piece] );
477           
478           for( kind = 0; kind < nr_kinds; ++kind )
479                 {
480                   printf( "." );
481                   /* Form output filename -- <piece><kind><size>.xim */
482                   snprintf(buf, BUFLEN, "%c%s%d.xim", pieces[piece], prefixes[kind], w);
483                   create_piece_xim( buf, fp, w, h );
484                 }
485           printf("\n");
486         }
487
488   /* Write the light & dark squares */
489   snprintf( buf, BUFLEN, "lsq%d.xim", w );
490   printf("Light Square" );
491   create_piece_xim( buf, fp, w, h );
492
493   snprintf( buf, BUFLEN, "dsq%d.xim", w );
494   printf("\nDark Square" );
495   create_piece_xim( buf, fp, w, h );  
496   printf("\n");
497   
498   printf("Successfully converted!!\n" );
499
500   fclose( fp );
501   
502   return 0;
503 }
504
505 int process_file_xpm( filename )
506          char *filename;
507 {
508   int w, h, piece, kind, c;
509   int nr_pieces = 6;
510   int nr_kinds = 4;
511   FILE *fp;
512   char buf[BUFLEN];
513
514   src_name = filename;
515   
516   fp = fopen( filename, "rb" );
517   if ( !fp )
518         fatal( "Can't open input file." );
519   
520   /* Header is two ints -- Width then Height, x86 format */
521   c = fgetc( fp );
522   w = (fgetc(fp) << 8) | c;
523
524   c = fgetc( fp );
525   h = (fgetc(fp) << 8) | c;
526   
527   ++w; ++h;
528
529   if ( w != h )
530         {
531           printf("ERROR: Can only convert square pieces.\n");
532           printf("       (This set is %dx%d)\n", w, h );
533           exit(1);
534         }
535   
536   printf("Creating XPM files...\n");
537   printf("File: %s, W=%d, H=%d\n", filename, w, h );
538   fseek( fp, 0, SEEK_SET );
539   
540   /* Write .XPM files */
541   for( piece = 0; piece < nr_pieces; ++piece )
542         {
543           printf("%s ", pname[piece] );
544           
545           for( kind = 0; kind < nr_kinds; ++kind )
546                 {
547                   printf( "." );
548                   /* Form output filename -- <piece><kind><size>.xpm */
549                   snprintf(buf, BUFLEN, "%c%s%d.xpm", pieces[piece], prefixes[kind], w);
550                   create_piece_xpm( buf, fp, w, h );
551                 }
552           printf("\n");
553         }
554
555   /* Write the light & dark squares */
556   snprintf( buf, BUFLEN, "lsq%d.xpm", w );
557   printf("Light Square" );
558   create_piece_xpm( buf, fp, w, h );
559
560   snprintf( buf, BUFLEN, "dsq%d.xpm", w );
561   printf("\nDark Square" );
562   create_piece_xpm( buf, fp, w, h );  
563   printf("\n");
564   
565   printf("Successfully converted!!\n" );
566
567   fclose( fp );
568   
569   return 0;
570 }
571
572 int main( argc, argv )
573          int argc;
574          char *argv[];
575 {
576   int i;
577   
578   if ( argc < 2 )
579         {
580           printf("ZIC2XPM 2.01 - by Frank McIngvale (frankm@hiwaay.net)\n");
581           printf("Copyright (C) 1996 Free Software Foundation, Inc.\n\n");
582           printf("Usage: zic2xpm file1 [file2 ...]\n\n");
583           printf("  Splits each file (ZIICS piece files) into 26 XPM & XIM files\n");
584           printf("  suitable for use in XBoard 3.5 or later.\n");
585           printf("\n* ZIICS is a copyrighted work of Andy McFarland (Zek on ICC) *\n");
586           return 1;
587         }
588
589
590   setbuf( stdout, NULL );
591   
592   for( i=1; i<argc; ++i )
593         {
594           process_file_xpm( argv[i] );
595           process_file_xim( argv[i] );
596         }
597   
598   fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
599           "NOTICE: The piece images distributed with ZIICS are",
600           "    copyrighted works of their original creators.  Images",
601           "    converted with zic2xpm may not be redistributed without",
602           "    the permission of the copyright holders.  Do not contact",
603           "    the authors of zic2xpm or of ZIICS itself to request",
604           "    permission.");
605   return 0;
606 }