1 /*
2  * Convert the given input files into an output file that is expected
3  * by nethack.
4  *
5  * Assumptions:
6  * 	+ Two dimensional byte arrays are in row order and are not padded
7  *	  between rows (x11_colormap[][]).
8  */
9 #include "hack.h"		/* for MAX_GLYPH */
10 #include "tile.h"
11 #include "tile2x11.h"		/* x11 output file header structure */
12 
13 #define OUTNAME "x11tiles"	/* Default output file name */
14 /* #define PRINT_COLORMAP */	/* define to print the colormap */
15 
16 
17 x11_header	header;
18 unsigned char	*tile_bytes = NULL;
19 unsigned char	*curr_tb = NULL;
20 unsigned char	x11_colormap[MAXCOLORMAPSIZE][3];
21 
22 
23 /* Look up the given pixel and return its colormap index. */
24 static unsigned char
pix_to_colormap(pix)25 pix_to_colormap(pix)
26     pixel pix;
27 {
28     int i;
29 
30     for (i = 0; i < header.ncolors; i++) {
31 	if (pix.r == x11_colormap[i][CM_RED] &&
32 		pix.g == x11_colormap[i][CM_GREEN] &&
33 		pix.b == x11_colormap[i][CM_BLUE])
34 	    break;
35     }
36 
37     if (i == header.ncolors) {
38 	Fprintf(stderr, "can't find color: [%u,%u,%u]\n", pix.r, pix.g, pix.b);
39 	exit(1);
40     }
41     return (unsigned char) (i & 0xFF);
42 }
43 
44 
45 /* Convert the tiles in the file to our format of bytes. */
46 static unsigned long
convert_tiles(tb_ptr)47 convert_tiles(tb_ptr)
48     unsigned char **tb_ptr;	/* pointer to a tile byte pointer */
49 {
50     unsigned char *tb = *tb_ptr;
51     unsigned long count = 0;
52     pixel tile[MAX_TILE_Y][MAX_TILE_X];
53     int x, y;
54 
55     while (read_text_tile(tile)) {
56 	count++;
57 	for (y = 0; y < tile_y; y++)
58 	    for (x = 0; x < tile_x; x++)
59 		*tb++ = pix_to_colormap(tile[y][x]);
60     }
61 
62     *tb_ptr = tb;	/* update return val */
63     return count;
64 }
65 
66 
67 /* Merge the current text colormap (ColorMap) with ours (x11_colormap). */
68 static void
merge_text_colormap()69 merge_text_colormap()
70 {
71     int i, j;
72 
73     for (i = 0; i < colorsinmap; i++) {
74 	for (j = 0; j < header.ncolors; j++)
75 	    if (x11_colormap[j][CM_RED] == ColorMap[CM_RED][i] &&
76 		    x11_colormap[j][CM_GREEN] == ColorMap[CM_GREEN][i] &&
77 		    x11_colormap[j][CM_BLUE] == ColorMap[CM_BLUE][i])
78 		break;
79 
80 	if (j >= MAXCOLORMAPSIZE) {
81 	    Fprintf(stderr, "colormap overflow\n");
82 	    exit(1);
83 	}
84 
85 	if (j == header.ncolors) {	/* couldn't find it */
86 #ifdef PRINT_COLORMAP
87 	    printf("color %2d: %3d %3d %3d\n", header.ncolors,
88 	    	ColorMap[CM_RED][i], ColorMap[CM_GREEN][i],
89 	    	ColorMap[CM_BLUE][i]);
90 #endif
91 
92 	    x11_colormap[j][CM_RED] = ColorMap[CM_RED][i];
93 	    x11_colormap[j][CM_GREEN] = ColorMap[CM_GREEN][i];
94 	    x11_colormap[j][CM_BLUE] = ColorMap[CM_BLUE][i];
95 	    header.ncolors++;
96 	}
97     }
98 }
99 
100 
101 /* Open the given file, read & merge the colormap, convert the tiles. */
102 static void
process_file(fname)103 process_file(fname)
104     char *fname;
105 {
106     unsigned long count;
107 
108     if (!fopen_text_file(fname, RDTMODE)) {
109 	Fprintf(stderr, "can't open file \"%s\"\n", fname);
110 	exit(1);
111 	}
112 
113     if (!tile_bytes) {
114 	/*
115 	 * Delayed until we open the first input file so that
116 	 * we know the size of the tiles we are processing.
117 	 */
118 	tile_bytes = malloc(tile_x*tile_y*MAX_GLYPH);
119 	if (!tile_bytes) {
120 	    Fprintf(stderr, "Not enough memory.\n");
121 	    exit(1);
122 	}
123 	curr_tb = tile_bytes;
124     }
125     merge_text_colormap();
126     count = convert_tiles(&curr_tb);
127     Fprintf(stderr, "%s: %lu tiles\n", fname, count);
128     header.ntiles += count;
129     fclose_text_file();
130 }
131 
132 
133 #ifdef USE_XPM
134 static int
xpm_write(fp)135 xpm_write(fp)
136 FILE *fp;
137 {
138     int i,j,x,y;
139     char c[3]="?";
140     unsigned char *bytes;
141 
142     if (header.ncolors > 4096) {
143 	Fprintf(stderr, "Sorry, only configured for up to 4096 colors\n");
144 	exit(1);
145 	/* All you need to do is add more char per color - below */
146     }
147 
148     /* Fill unused entries with "checkerboard" pattern */
149     for(i = TILES_PER_COL * TILES_PER_ROW - header.ntiles; i > 0; i--)
150 	for (y = 0; y < tile_y; y++)
151 	    for (x = 0; x < tile_x; x+=2)
152 	    {
153 		*curr_tb++ = 0;
154 		*curr_tb++ = 1;
155 	    }
156 
157     Fprintf(fp, "/* XPM */\n");
158     Fprintf(fp, "static char* nhtiles[] = {\n");
159     Fprintf(fp, "\"%lu %lu %lu %d\",\n",
160 		header.tile_width*TILES_PER_ROW,
161 		header.tile_height*TILES_PER_COL,
162 		header.ncolors,
163 		header.ncolors > 64 ? 2 : 1 /* char per color */);
164     for (i = 0; i < header.ncolors; i++) {
165 	if (header.ncolors > 64) {
166 	    /* two chars per color */
167 	    c[0] = i / 64 + '0';
168 	    c[1] = i % 64 + '0';
169 	}
170 	else
171 	    c[0] = i + '0';	/* just one char per color */
172 	Fprintf(fp, "\"%s  c #%02x%02x%02x\",\n", c,
173 		x11_colormap[i][0],
174 		x11_colormap[i][1],
175 		x11_colormap[i][2]);
176     }
177 
178     for (j = 0; j < TILES_PER_COL; j++)
179 	for (y = 0; y < header.tile_height; y++) {
180 	    bytes=tile_bytes+(j*TILES_PER_ROW*header.tile_height+y)*
181 	      header.tile_width;
182 	    Fprintf(fp, "\"");
183 	    for (i = 0; i < TILES_PER_ROW; i++) {
184 		for (x = 0; x < header.tile_width; x++) {
185 		    if (header.ncolors > 64) {
186 			/* two chars per color */
187 			c[0] = bytes[x] / 64 + '0';
188 			c[1] = bytes[x] % 64 + '0';
189 		    }
190 		    else
191 			c[0] = bytes[x] + '0';	/* just one char per color */
192 		    fputs(c, fp);
193 		}
194 		bytes+=header.tile_height*header.tile_width;
195 	    }
196 	    Fprintf(fp, "\",\n");
197 	}
198 
199     return fprintf(fp, "};\n")>=0;
200 }
201 #endif	/* USE_XPM */
202 
203 /*
204  * ALI
205  *
206  * Architecture independent tile file so that x11tiles can always be
207  * stored in FILE_AREA_SHARE, thus simplifying the configuration.
208  */
209 
210 static boolean
fwrite_tile_header_item(item,fp)211 fwrite_tile_header_item(item, fp)
212 long item;
213 FILE *fp;
214 {
215     putc((item>>24)&0xff,fp);
216     putc((item>>16)&0xff,fp);
217     putc((item>>8)&0xff,fp);
218     putc(item&0xff,fp);
219     return !ferror(fp);
220 }
221 
222 static boolean
fwrite_tile_header(header,fp)223 fwrite_tile_header(header, fp)
224 x11_header *header;
225 FILE *fp;
226 {
227     return fwrite_tile_header_item(header->version,fp) &&
228       fwrite_tile_header_item(header->ncolors,fp) &&
229       fwrite_tile_header_item(header->tile_width,fp) &&
230       fwrite_tile_header_item(header->tile_height,fp) &&
231       fwrite_tile_header_item(header->ntiles,fp) &&
232       fwrite_tile_header_item(header->per_row,fp);
233 }
234 
235 int
main(argc,argv)236 main(argc, argv)
237     int argc;
238     char **argv;
239 {
240     FILE *fp;
241     int i, argn = 1;
242     char *outname = OUTNAME;
243 
244     header.version	= 2;		/* version 1 had no per_row field */
245     header.ncolors	= 0;
246     header.ntiles	= 0;		/* updated as we read in files */
247     header.per_row	= 1;
248 
249     while (argn < argc) {
250 	if (argn + 1 < argc && !strcmp(argv[argn], "-o")) {
251 	    outname = argv[argn + 1];
252 	    argn += 2;
253 	}
254 	else
255 	    break;
256     }
257 
258     if (argn == argc) {
259 	Fprintf(stderr, "usage: %s [-o out_file] txt_file1 [txt_file2 ...]\n",
260 	  argv[0]);
261 	exit(1);
262     }
263 
264     fp = fopen(outname, "w");
265     if (!fp) {
266 	perror(outname);
267 	exit(1);
268 	}
269 
270     for (i = argn; i < argc; i++)
271 	process_file(argv[i]);
272     Fprintf(stderr, "Total tiles: %ld\n", header.ntiles);
273 
274     header.tile_width	= tile_x;
275     header.tile_height	= tile_y;
276 
277 #ifdef USE_XPM
278     if (xpm_write(fp) == 0) {
279 	Fprintf(stderr, "can't write XPM file\n");
280 	exit(1);
281     }
282 #else
283     if (fwrite_tile_header(&header, fp) == 0) {
284 	Fprintf(stderr, "can't write output header\n");
285 	exit(1);
286 	}
287 
288     if (fwrite((char *)x11_colormap, 1, header.ncolors*3, fp) == 0) {
289 	Fprintf(stderr, "can't write output colormap\n");
290 	exit(1);
291     }
292 
293     if (fwrite((char *)tile_bytes, 1,
294 	(int) header.ntiles*header.tile_width*header.tile_height, fp) == 0) {
295 
296 	Fprintf(stderr, "can't write tile bytes\n");
297 	exit(1);
298     }
299 #endif
300 
301     fclose(fp);
302     free(tile_bytes);
303     return 0;
304 }
305