1 /* NetHack 3.6	txt2iff.c	$NHDT-Date: 1432512795 2015/05/25 00:13:15 $  $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */
2 /* 	Copyright (c) 1995 by Gregg Wonderly, Naperville, Illinois */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include <stdlib.h>
6 
7 #include "config.h"
8 #include "tile.h"
9 
10 #include <dos/dos.h>
11 #include <dos/dos.h>
12 #include <dos/dosextens.h>
13 #include <graphics/gfx.h>
14 #include <graphics/gfxbase.h>
15 #include <graphics/view.h>
16 #include <libraries/iffparse.h>
17 #include <libraries/dos.h>
18 #include <clib/dos_protos.h>
19 #include <clib/iffparse_protos.h>
20 #ifndef _DCC
21 #include <proto/exec.h>
22 #include <proto/iffparse.h>
23 #include <proto/dos.h>
24 #endif
25 
26 void panic(const char *);
27 void map_colors(void);
28 int BestMatch(int, int, int);
29 
30 extern pixval ColorMap[3][MAXCOLORMAPSIZE];
31 extern int colorsinmap;
32 
33 /*
34  * WARNING:
35  * This program carries forth the assumption that the colormaps in all
36  * of the .txt files are the same.  This is a bug.
37  */
38 
39 struct {
40     int Height;
41     int Width;
42 } IFFScreen;
43 
44 /*
45  * We are using a hybrid form of our own design which we call a BMAP (for
46  * bitmap) form.  It is an ILBM with the bitmaps already deinterleaved,
47  * completely uncompressed.
48  * This speeds the loading of the images from the games point of view because
49  * it
50  * does not have to deinterleave and uncompress them.
51  */
52 #define ID_BMAP MAKE_ID('B', 'M', 'A', 'P') /* instead of ILBM */
53 #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* Same as ILBM */
54 #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* Same as ILBM */
55 #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* Same as ILBM */
56 #define ID_PDAT                                                             \
57     MAKE_ID('P', 'D', 'A', 'T')             /* Extra data describing plane  \
58                                              * size due to graphics.library \
59                                              * rounding requirements.       \
60                                              */
61 #define ID_PLNE MAKE_ID('P', 'L', 'N', 'E') /* The planes of the image */
62 
63 #ifndef _DCC
64 extern
65 #endif
66     struct Library *IFFParseBase;
67 
68 int nplanes;
69 
70 /* BMHD from IFF documentation */
71 typedef struct {
72     UWORD w, h;
73     WORD x, y;
74     UBYTE nPlanes;
75     UBYTE masking;
76     UBYTE compression;
77     UBYTE reserved1;
78     UWORD transparentColor;
79     UBYTE xAspect, yAspect;
80     WORD pageWidth, pageHeight;
81 } BitMapHeader;
82 
83 typedef struct {
84     UBYTE r, g, b;
85 } AmiColorMap;
86 
87 pixel pixels[TILE_Y][TILE_X];
88 AmiColorMap *cmap;
89 
90 int findcolor(register pixel *pix);
91 void packwritebody(pixel (*tile)[TILE_X], char **planes, int tileno);
92 
93 void
error(char * str)94 error(char *str)
95 {
96     fprintf(stderr, "ERROR: %s\n", str);
97 }
98 
99 /*
100  * This array maps the image colors to the amiga's first 16 colors.  The
101  * colors
102  * are reordered to help with maintaining dripen settings.
103  */
104 int colrmap[] = { 0, 6, 9, 15, 4, 10, 2, 3, 5, 11, 7, 13, 8, 1, 14, 12 };
105 
106 /* How many tiles fit across and down. */
107 
108 #define COLS 20
109 #define ROWS ((tiles + COLS - 1) / COLS)
110 
main(int argc,char ** argv)111 main(int argc, char **argv)
112 {
113     int colors;
114     struct {
115         long nplanes;
116         long pbytes;
117         long across;
118         long down;
119         long npics;
120         long xsize;
121         long ysize;
122     } pdat;
123     long pbytes; /* Bytes of data in a plane */
124     int i, cnt;
125     BitMapHeader bmhd;
126     struct IFFHandle *iff;
127     long camg = HIRES | LACE;
128     int tiles = 0;
129     char **planes;
130 
131     if (argc != 3) {
132         fprintf(stderr, "Usage: %s source destination\n", argv[0]);
133         exit(1);
134     }
135 
136 #if defined(_DCC) || defined(__GNUC__)
137     IFFParseBase = OpenLibrary("iffparse.library", 0);
138     if (!IFFParseBase) {
139         error("unable to open iffparse.library");
140         exit(1);
141     }
142 #endif
143 
144     /* First, count the files in the file */
145     if (fopen_text_file(argv[1], "r") != TRUE) {
146         perror(argv[1]);
147         return (1);
148     }
149 
150     nplanes = 0;
151     i = colorsinmap - 1; /*IFFScreen.Colors - 1; */
152     while (i != 0) {
153         nplanes++;
154         i >>= 1;
155     }
156 
157     planes = malloc(nplanes * sizeof(char *));
158     if (planes == 0) {
159         error("can not allocate planes pointer");
160         exit(1);
161     }
162 
163     while (read_text_tile(pixels) == TRUE)
164         ++tiles;
165     fclose_text_file();
166 
167     IFFScreen.Width = COLS * TILE_X;
168     IFFScreen.Height = ROWS * TILE_Y;
169 
170     pbytes = (COLS * ROWS * TILE_X + 15) / 16 * 2 * TILE_Y;
171 
172     for (i = 0; i < nplanes; ++i) {
173         planes[i] = calloc(1, pbytes);
174         if (planes[i] == 0) {
175             error("can not allocate planes pointer");
176             exit(1);
177         }
178     }
179 
180     /* Now, process it */
181     if (fopen_text_file(argv[1], "r") != TRUE) {
182         perror(argv[1]);
183         return (1);
184     }
185 
186     iff = AllocIFF();
187     if (!iff) {
188         error("Can not allocate IFFHandle");
189         return (1);
190     }
191 
192     iff->iff_Stream = Open(argv[2], MODE_NEWFILE);
193     if (!iff->iff_Stream) {
194         error("Can not open output file");
195         return (1);
196     }
197 
198     InitIFFasDOS(iff);
199     OpenIFF(iff, IFFF_WRITE);
200 
201     PushChunk(iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN);
202 
203     bmhd.w = IFFScreen.Width;
204     bmhd.h = IFFScreen.Height;
205     bmhd.x = 0;
206     bmhd.y = 0;
207     bmhd.nPlanes = nplanes;
208     bmhd.masking = 0;
209     bmhd.compression = 0;
210     bmhd.reserved1 = 0;
211     bmhd.transparentColor = 0;
212     bmhd.xAspect = 100;
213     bmhd.yAspect = 100;
214     bmhd.pageWidth = TILE_X;
215     bmhd.pageHeight = TILE_Y;
216 
217     PushChunk(iff, ID_BMAP, ID_BMHD, sizeof(bmhd));
218     WriteChunkBytes(iff, &bmhd, sizeof(bmhd));
219     PopChunk(iff);
220 
221     PushChunk(iff, ID_BMAP, ID_CAMG, sizeof(camg));
222     WriteChunkBytes(iff, &camg, sizeof(camg));
223     PopChunk(iff);
224 
225     /* We need to reorder the colors to get reasonable default pens but
226      * we also need to know where some of the colors are - so go find out.
227      */
228     map_colors();
229 
230     cmap = malloc((colors = (1L << nplanes)) * sizeof(AmiColorMap));
231     for (i = 0; i < colors; ++i) {
232         cmap[colrmap[i]].r = ColorMap[CM_RED][i];
233         cmap[colrmap[i]].g = ColorMap[CM_GREEN][i];
234         cmap[colrmap[i]].b = ColorMap[CM_BLUE][i];
235     }
236 
237     PushChunk(iff, ID_BMAP, ID_CMAP, IFFSIZE_UNKNOWN);
238     for (i = 0; i < colors; ++i)
239         WriteChunkBytes(iff, &cmap[i], 3);
240     PopChunk(iff);
241 
242     cnt = 0;
243     while (read_text_tile(pixels) == TRUE) {
244         packwritebody(pixels, planes, cnt);
245         if (cnt % 20 == 0)
246             printf("%d..", cnt);
247         ++cnt;
248         fflush(stdout);
249     }
250 
251     pdat.nplanes = nplanes;
252     pdat.pbytes = pbytes;
253     pdat.xsize = TILE_X;
254     pdat.ysize = TILE_Y;
255     pdat.across = COLS;
256     pdat.down = ROWS;
257     pdat.npics = cnt;
258 
259     PushChunk(iff, ID_BMAP, ID_PDAT, IFFSIZE_UNKNOWN);
260     WriteChunkBytes(iff, &pdat, sizeof(pdat));
261     PopChunk(iff);
262 
263     PushChunk(iff, ID_BMAP, ID_PLNE, IFFSIZE_UNKNOWN);
264     for (i = 0; i < nplanes; ++i)
265         WriteChunkBytes(iff, planes[i], pbytes);
266     PopChunk(iff);
267 
268     CloseIFF(iff);
269     Close(iff->iff_Stream);
270     FreeIFF(iff);
271 
272     printf("\n%d tiles converted\n", cnt);
273 
274 #if defined(_DCC) || defined(__GNUC__)
275     CloseLibrary(IFFParseBase);
276 #endif
277     exit(0);
278 }
279 
findcolor(register pixel * pix)280 findcolor(register pixel *pix)
281 {
282     register int i;
283 
284     for (i = 0; i < MAXCOLORMAPSIZE; ++i) {
285         if ((pix->r == ColorMap[CM_RED][i])
286             && (pix->g == ColorMap[CM_GREEN][i])
287             && (pix->b == ColorMap[CM_BLUE][i])) {
288             return (i);
289         }
290     }
291     return (-1);
292 }
293 
294 void
packwritebody(pixel (* tile)[TILE_X],char ** planes,int tileno)295 packwritebody(pixel (*tile)[TILE_X], char **planes, int tileno)
296 {
297     register int i, j, k, col;
298     register char *buf;
299     register int across, rowbytes, xoff, yoff;
300 
301     /* how many tiles fit across? */
302     across = COLS;
303 
304     /* How many bytes per pixel row */
305     rowbytes = ((IFFScreen.Width + 15) / 16) * 2;
306 
307     /* How many bytes to account for y distance in planes */
308     yoff = ((tileno / across) * TILE_Y) * rowbytes;
309 
310     /* How many bytes to account for x distance in planes */
311     xoff = (tileno % across) * (TILE_X / 8);
312 
313     /* For each row... */
314     for (i = 0; i < TILE_Y; ++i) {
315         /* For each bitplane... */
316         for (k = 0; k < nplanes; ++k) {
317             const int mask = 1l << k;
318 
319             /* Go across the row */
320             for (j = 0; j < TILE_X; j++) {
321                 col = findcolor(&tile[i][j]);
322                 if (col == -1) {
323                     error("can not convert pixel color to colormap index");
324                     return;
325                 }
326                 /* Shift the colors around to have good complements and to
327                  * know the dripen values.
328                  */
329                 col = colrmap[col];
330 
331                 /* To top left corner of tile */
332                 buf = planes[k] + yoff + xoff;
333 
334                 /*To i'th row of tile and the correct byte for the j'th
335                  * pixel*/
336                 buf += (i * rowbytes) + (j / 8);
337 
338                 /* Or in the bit for this color */
339                 *buf |= (((col & mask) != 0) << (7 - (j % 8)));
340             }
341         }
342     }
343 }
344 
345 /* #define DBG */
346 
347 /* map_colors
348  * The incoming colormap is in arbitrary order and has arbitrary colors in
349  * it, but we need (some) specific colors in specific places.  Find the
350  * colors we need and fix the mapping table to match.
351  */
352 /* What we are aiming for: */
353 /* XXX was 0-7 */
354 #define CX_BLACK 0
355 #define CX_WHITE 1
356 #define CX_BROWN 11
357 #define CX_CYAN 2
358 #define CX_GREEN 5
359 #define CX_MAGENTA 10
360 #define CX_BLUE 4
361 #define CX_RED 7
362 /* we don't care about the rest, at least now */
363 /* should get: black white blue red grey greyblue ltgrey */
364 void
map_colors()365 map_colors()
366 {
367     int x;
368 #if 1
369     int tmpmap[] = { 0, 2, 3, 7, 4, 5, 8, 9, 10, 11, 13, 15, 12, 1, 14, 6 };
370 /* still not right: gray green yellow lost somewhere? */
371 #else
372     int tmpmap[16];
373     int x, y;
374     for (x = 0; x < 16; x++)
375         tmpmap[x] = -1; /* set not assigned yet */
376 
377     tmpmap[BestMatch(0, 0, 0)] = CX_BLACK;
378     tmpmap[BestMatch(255, 255, 255)] = CX_WHITE;
379     tmpmap[BestMatch(255, 0, 0)] = CX_RED;
380     tmpmap[BestMatch(0, 255, 0)] = CX_GREEN;
381     tmpmap[BestMatch(0, 0, 255)] = CX_BLUE;
382 
383     /* clean up the rest */
384     for (x = 0; x < 16; x++) {
385         for (y = 0; y < 16; y++)
386             if (tmpmap[y] == x)
387                 goto outer_cont;
388         for (y = 0; y < 16; y++)
389             if (tmpmap[y] == -1) {
390                 tmpmap[y] = x;
391                 break;
392             }
393         if (y == 16)
394             panic("too many colors?");
395     outer_cont:
396         ;
397     }
398     for (x = 0; x < 16; x++)
399         if (tmpmap[y] == -1)
400             panic("lost color?");
401 #endif
402     for (x = 0; x < 16; x++) {
403 #ifdef DBG
404         printf("final: c[%d]=%d (target: %d)\n", x, tmpmap[x], colrmap[x]);
405 #endif
406         colrmap[x] = tmpmap[x];
407     }
408 }
BestMatch(r,g,b)409 BestMatch(r, g, b) int r, g, b;
410 {
411     int x;
412     int bestslot;
413     int bestrate = 99999999L;
414     for (x = 0; x < 16; x++) {
415         int rr = r - ColorMap[CM_RED][x];
416         int gg = g - ColorMap[CM_GREEN][x];
417         int bb = b - ColorMap[CM_BLUE][x];
418         int rate = rr * rr + gg * gg + bb * bb;
419         if (bestrate > rate) {
420             bestrate = rate;
421             bestslot = x;
422         }
423     }
424 #ifdef DBG
425     printf("map (%d,%d,%d) -> %d (error=%d)\n", r, g, b, bestslot, bestrate);
426 #endif
427     return bestslot;
428 }
429 
430 long *
alloc(unsigned int n)431 alloc(unsigned int n)
432 {
433     long *ret = malloc(n);
434     if (!ret) {
435         error("Can't allocate memory");
436         exit(1);
437     }
438     return (ret);
439 }
440 
441 void
panic(const char * msg)442 panic(const char *msg)
443 {
444     fprintf(stderr, "PANIC: %s\n", msg);
445     exit(1);
446 }
447