1 /* Interpretation of generic GDL images for Xconq.
2    Copyright (C) 1994-2001 Stanley T. Shebs.
3 
4 Xconq is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.  See the file COPYING.  */
8 
9 /* Note!  This file does not use the standard "conq.h" header, so
10    can't assume all the usual definitions. */
11 
12 #include "config.h"
13 #include "misc.h"
14 #include "lisp.h"
15 #include "imf.h"
16 #include "module.h"
17 #include "system.h"
18 
19 /* RGB above this value should be considered white. */
20 
21 #define WHITE_THRESHOLD (65535 - 256)
22 
23 /* RGB below this value should be considered black. */
24 
25 #define BLACK_THRESHOLD (0 + 255)
26 
27 enum {
28     K_MONO_,
29     K_MASK_,
30     K_COLR_,
31     K_FILE_,
32     K_OTHER_
33 };
34 
35 typedef struct _MFEntry {
36     int value, count;
37 } MFEntry;
38 typedef MFEntry *ModeFilter;
39 
40 static Image *get_subimg(ImageFamily *imf, int w, int h);
41 static Image *largest_image(ImageFamily *imf);
42 static int image_pixel_at(Image *img, int imtype, int x, int y);
43 static void set_image_pixel_at(Image *img, int imtype, int x, int y, int val);
44 static ImageFamily *new_imf(char *name);
45 static int bitmaps_match(int w, int h, Obj *lispdata, char *rawdata);
46 static int color_matches_mono(Image *img);
47 static void write_pixmap(FILE *fp, int w, int h, int aw, int ah,
48 			 int pixelsize, int orig_pixelsize,
49 			 Obj *palette, int *rawpalette, int numcolors,
50 			 Obj *lispdata, char *rawdata);
51 static void write_bitmap(FILE *fp, char *subtyp, int w, int h,
52 			 Obj *data, char *rawdata);
53 static void write_palette_contents(FILE *fp, Obj *palette,
54 				   int *rawpalette, int numcolors);
55 static void write_color(FILE *fp, int n, int r, int g, int b);
56 static ModeFilter new_mf(int maxvals);
57 static void add_to_mf(ModeFilter mf, int val);
58 static int mode_of_mf(ModeFilter mf);
59 static void zero_mf(ModeFilter mf);
60 static void delete_mf(ModeFilter mf);
61 static void add_hex_mask(Image *img);
62 static void remove_hex_mask(Image *img);
63 static void scale_image_layer(Image *imgin, Image *imgout, int layer,
64     int use_mask, ModeFilter mf);
65 static void scale_image(ImageFamily *imf, Image *img, Image *img2, int dhm);
66 static Image *add_scaled_image(ImageFamily *imf, Image *img, int w, int h);
67 static int size_match_score(int wa, int ha, int wb, int hb);
68 static int calculate_hch(int h);
69 
70 /* This is the array and count of known image families. */
71 
72 ImageFamily **images;
73 
74 int numimages = 0;
75 
76 /* Head of the linked list of image files. */
77 
78 ImageFile *image_files;
79 
80 /* Head of the linked list of "file" images used by several image families. */
81 
82 FileImage *file_images;
83 
84 ImageFamily *(*imf_load_hook)(ImageFamily *imf);
85 
86 ImageFamily *(*imf_interp_hook)(ImageFamily *imf, Image *img, int force);
87 
88 short write_synthetic_also;
89 
90 /* There are two ways to use image families.  The "old" way is to use
91    the image families' masks and other bitmaps as clip masks.  tcl/tk
92    for Windows doesn't support clip masks however, so the "new" way is
93    to do a GXand with the mask, carving out a mask-shaped black hole,
94    then do a GXor with the image proper.  Note that the part of the
95    image that is not included in the mask must be converted to black
96    if the ORing is to have the right effect.  X doesn't guarantee that
97    ANDing and ORing will work in general though; we just know that the
98    X emulation in tcl/tk for Windows can be used in this way. */
99 
100 /* This should be TRUE everywhere except on Windows. */
101 
102 int use_clip_mask = TRUE;
103 
104 /* Flag that indicates limited GDI memory in Windows ME and below. */
105 
106 short poor_memory = FALSE;
107 
108 /* Create and return an image family. */
109 
110 static ImageFamily *
new_imf(char * name)111 new_imf(char *name)
112 {
113     ImageFamily *imf;
114 
115     imf = (ImageFamily *) xmalloc(sizeof(ImageFamily));
116     imf->name = name;
117     imf->notes = lispnil;
118     return imf;
119 }
120 
121 ImageFamily *
clone_imf(ImageFamily * imf)122 clone_imf(ImageFamily *imf)
123 {
124     Image *img, *img2, *truenext;
125     ImageFamily *imf2;
126 
127     imf2 = new_imf(imf->name);
128     memcpy(imf2, imf, sizeof(ImageFamily));
129     /* Clear the hook, we expect that the caller of this routine will
130        supply any new hook that might be necessary. */
131     imf2->hook = NULL;
132     imf2->images = NULL;
133     imf2->numsizes = 0;
134     /* Clone the images. */
135     for_all_images(imf, img) {
136 	img2 = get_img(imf2, img->w, img->h);
137 	truenext = img2->next;
138 	memcpy(img2, img, sizeof(Image));
139 	/* Clear the hook, we expect that the caller of this routine
140 	   will supply any new hook that might be necessary. */
141 	img2->hook = NULL;
142 	/* Restore the link. */
143 	img2->next = truenext;
144 	/* Note that pointers to raw image data and suchlike can be
145 	   left as-is, since they should be shared by image clones. */
146 	/* (should copy anyway, for safety?) */
147     }
148     return imf2;
149 }
150 
151 /* Test that the given name is a valid image family name (all alphanumeric,
152    hyphens anywhere but as first char). */
153 
154 int
valid_imf_name(char * name)155 valid_imf_name(char *name)
156 {
157     char *tmp;
158 
159     for (tmp = name; *tmp; ++tmp) {
160 	if (!(isalnum(*tmp)
161 	      || (tmp != name && *tmp == '-')))
162 	  return FALSE;
163     }
164     return TRUE;
165 }
166 
167 /* Bash invalid chars in a prospective imf name. */
168 
169 void
validify_imf_name(char * buf)170 validify_imf_name(char *buf)
171 {
172     char *tmp;
173 
174     for (tmp = buf; *tmp; ++tmp) {
175 	if (tmp == buf && *tmp == '-')
176 	  *tmp = 'Z';
177 	if (!isalnum(*tmp) && *tmp != '-')
178 	  *tmp = '-';
179     }
180 }
181 
182 /* Given a name, find or create an image family with that name. */
183 
184 ImageFamily *
get_imf(char * name)185 get_imf(char *name)
186 {
187     ImageFamily *imf = NULL;
188 
189     if (name == NULL) {
190 	init_warning("can't get an unnamed image family");
191 	return NULL;
192     }
193     if (!valid_imf_name(name)) {
194 	init_warning("\"%s\" is not a valid image family name", name);
195 	return NULL;
196     }
197     if (images == NULL) {
198 	images =
199 	  (ImageFamily **) xmalloc(MAXIMAGEFAMILIES * sizeof(ImageFamily *));
200     }
201     imf = find_imf(name);
202     if (imf == NULL) {
203 	if (numimages >= MAXIMAGEFAMILIES) {
204 	    init_warning("MAXIMAGEFAMILIES exceeded, skipping image family %s", name);
205 	    return NULL;
206 	}
207 	imf = new_imf(copy_string(name));
208 	if (imf != NULL) {
209 	    images[numimages++] = imf;
210 	}
211     }
212     return imf;
213 }
214 
215 ImageFile *
get_image_file(char * name)216 get_image_file(char *name)
217 {
218     ImageFile *imfile;
219 
220     if (name == NULL)
221       run_error("can't get an unnamed image file");
222     for (imfile = image_files; imfile != NULL; imfile = imfile->next) {
223 	if (strcmp(name, imfile->name) == 0)
224 	  return imfile;
225     }
226     imfile = (ImageFile *) xmalloc(sizeof(ImageFile));
227     imfile->name = copy_string(name);
228     imfile->next = image_files;
229     image_files = imfile;
230     return imfile;
231 }
232 
233 void
load_image_families(FILE * fp,int loadnow,void (* callback)(ImageFamily * imf,int loadnow))234 load_image_families(FILE *fp, int loadnow,
235 		    void (*callback)(ImageFamily *imf, int loadnow))
236 {
237     int done = FALSE, first = TRUE;
238     char buf[BUFSIZE], *buf1, *buf2, *tmp;
239     ImageFamily *imf = NULL;
240     ImageFile *imfile;
241 
242     while (!done) {
243 	/* Get a line from the file and parse it. */
244 	if (fgets(buf, BUFSIZE-1, fp)) {
245 	  buf1 = buf;
246 	  buf2 = strchr(buf, ' ');
247 	  if (buf2 == NULL)
248 	    break;
249 	  *buf2 = '\0';
250 	  ++buf2;
251 	  tmp = strchr(buf2, '\n');
252 	  if (tmp)
253 	    *tmp = '\0';
254 	} else
255 	  break;
256 	if (strcmp(buf1, ".") == 0
257 	    && strcmp(buf2, ".") == 0)
258 	  done = TRUE;
259 	else if (first) {
260 	    if (strcmp(buf1, "ImageFamilyName") == 0
261 		&& strcmp(buf2, "FileName") == 0)
262 	      first = FALSE;
263 	    else {
264 		init_warning("File not a valid imf dir, will close and ignore");
265 		/* We've already given a warning message, so pretend we're done
266 		   so the format error message doesn't get displayed below. */
267 		done = TRUE;
268 		break;
269 	    }
270 	} else {
271 	    imf = get_imf(buf1);
272 	    if (imf != NULL) {
273 		imfile = get_image_file(buf2);
274 		imf->location = imfile;
275 		if (loadnow && !imfile->loaded) {
276 		    load_imf_file(imfile->name, callback);
277 		    imfile->loaded = TRUE;
278 		} else {
279 		    if (callback != NULL)
280 		      (*callback)(imf, loadnow);
281 		}
282 	    }
283 	}
284     }
285     if (!done) {
286 	init_warning("Format error in imf dir near %s, will only use part",
287 		     (imf ? imf->name : "???"));
288     }
289 }
290 
291 /* Given a filename, open it and read/interpret all the image-related
292    forms therein. */
293 
294 int
load_imf_file(char * filename,void (* callback)(ImageFamily * imf,int loadnow))295 load_imf_file(char *filename, void (*callback)(ImageFamily *imf, int loadnow))
296 {
297     int startlineno = 1, endlineno = 1;
298     Obj *form;
299     FILE *fp;
300 
301     fp = open_file(filename, "r");
302     if (fp != NULL) {
303 	/* Read everything in the file. */
304 	while ((form = read_form(fp, &startlineno, &endlineno)) != lispeof) {
305 	    interp_imf_form(form, filename, callback);
306 	}
307 	fclose(fp);
308 	return TRUE;
309     }
310     return FALSE;
311 }
312 
313 /* Interpret a form, looking specifically for image-related forms. */
314 
315 void
interp_imf_form(Obj * form,char * filename,void (* imf_callback)(ImageFamily * imf,int loadnow))316 interp_imf_form(Obj *form, char *filename, void (*imf_callback)(ImageFamily *imf, int loadnow))
317 {
318     Obj *head;
319     ImageFamily *imf;
320     ImageFile *imfile;
321 
322     /* Ignore any non-lists, we might be reading from a normal game design. */
323     if (!consp(form))
324       return;
325     head = car(form);
326     if (match_keyword(head, K_IMF)) {
327 	imf = interp_imf(form);
328 	if (imf != NULL) {
329 		imfile = get_image_file(filename);
330 		imf->location = imfile;
331 		imf->location->loaded = TRUE;
332 		if (imf_callback != NULL) {
333 			(*imf_callback)(imf, TRUE);
334 		}
335 	}
336     } else {
337 	/* Ignore any non-image forms, we might be reading from a
338 	   normal game design. */
339     }
340 }
341 
342 /* Find the image family of the given name, if it exists. */
343 
344 ImageFamily *
find_imf(char * name)345 find_imf(char *name)
346 {
347     int i;
348 
349     for (i = 0; i < numimages; ++i) {
350 	if (strcmp(name, images[i]->name) == 0)
351 	  return images[i];
352     }
353     return NULL;
354 }
355 
356 /* Get an image of the given size from the family, creating a new one
357    if necessary. */
358 
359 Image *
get_img(ImageFamily * imf,int w,int h)360 get_img(ImageFamily *imf, int w, int h)
361 {
362     Image *img, *nimg, *previmg;
363 
364     for_all_images(imf, img) {
365 	if (w == img->w && h == img->h)
366 	  return img;
367     }
368     /* Not found; create a new image and add it to the family. */
369     nimg = (Image *) xmalloc(sizeof(Image));
370     nimg->w = w;  nimg->h = h;
371     nimg->embedx = nimg->embedy = -1;
372     nimg->embedw = nimg->embedh = -1;
373     nimg->monodata = nimg->colrdata = nimg->maskdata = lispnil;
374     nimg->filedata = lispnil;
375     nimg->palette = lispnil;
376     nimg->actualw = w;  nimg->actualh = h;
377     nimg->notes = lispnil;
378     nimg->bboxw = w;  nimg->bboxh = h;
379     /* Rely on zeroing of xmalloc blocks to avoid clearing other fields. */
380     /* Link in order by size, smallest first. */
381     previmg = NULL;
382     for_all_images(imf, img) {
383 	if ((nimg->w < img->w)
384 	    || (nimg->w == img->w && nimg->h < img->h))
385 	  break;
386 	previmg = img;
387     }
388     if (previmg != NULL) {
389 	nimg->next = previmg->next;
390 	previmg->next = nimg;
391     } else {
392 	nimg->next = imf->images;
393 	imf->images = nimg;
394     }
395     ++(imf->numsizes);
396     return nimg;
397 }
398 
399 /* Get an image of the given size from the family, creating a new one
400    if necessary. */
401 
402 Image *
get_subimg(ImageFamily * imf,int w,int h)403 get_subimg(ImageFamily *imf, int w, int h)
404 {
405     Image *nimg;
406 
407     /* Not found; create a new image and add it to the family. */
408     nimg = (Image *) xmalloc(sizeof(Image));
409     nimg->w = w;  nimg->h = h;
410     nimg->embedx = nimg->embedy = -1;
411     nimg->embedw = nimg->embedh = -1;
412     nimg->monodata = nimg->colrdata = nimg->maskdata = lispnil;
413     nimg->filedata = lispnil;
414     nimg->palette = lispnil;
415     nimg->actualw = w;  nimg->actualh = h;
416     nimg->notes = lispnil;
417     nimg->bboxw = w;  nimg->bboxh = h;
418     return nimg;
419 }
420 
421 Image *
find_img(ImageFamily * imf,int w,int h)422 find_img(ImageFamily *imf, int w, int h)
423 {
424     Image *img;
425 
426     for_all_images(imf, img) {
427 	if (w == img->w && h == img->h)
428 	  return img;
429     }
430     return NULL;
431 }
432 
433 ImageFamily *
interp_imf(Obj * form)434 interp_imf(Obj *form)
435 {
436     ImageFamily *imf;
437 
438     if (stringp(cadr(form))) {
439 	imf = get_imf(c_string(cadr(form)));
440 	if (imf != NULL) {
441 	    interp_imf_contents(imf, cddr(form));
442 	}
443 	return imf;
444     } else {
445 	run_warning("image family name must be a string");
446     }
447     return NULL;
448 }
449 
450 /* Interpret the image family definition as a list of images and/or a
451    notes property. */
452 
453 void
interp_imf_contents(ImageFamily * imf,Obj * clauses)454 interp_imf_contents(ImageFamily *imf, Obj *clauses)
455 {
456     Obj *rest, *clause;
457 
458     for_all_list(clauses, rest) {
459 	clause = car(rest);
460 	if (consp(clause)) {
461 	    if (symbolp(car(clause))) {
462 		if (match_keyword(car(clause), K_NOTES)) {
463 		    imf->notes = cadr(clause);
464 		    syntax_error(clause, "extra junk after property value");
465 		} else {
466 		    syntax_error(clause, "unknown image family property");
467 		}
468 	    } else if (consp(car(clause))) {
469 		interp_image(imf, car(clause), cdr(clause));
470 	    } else {
471 		syntax_error(clause, "not image or image family property");
472 	    }
473 	} else {
474 	    syntax_error(clause, "bogus clause");
475 	}
476     }
477     compute_image_bboxes(imf);
478 }
479 
480 /* Given an image family, a size, and a list describing the elements
481    of a single image, parse the size and elements, put those into the
482    right slots of an image object.  Also detect and warn about changes
483    to an existing image, since this usually indicates some kind of
484    problem. */
485 
486 void
interp_image(ImageFamily * imf,Obj * size,Obj * parts)487 interp_image(ImageFamily *imf, Obj *size, Obj *parts)
488 {
489     int w, h, imtype, emx, emy, emw, emh, numsubs, subi;
490     char *name;
491     Image *img, *subimg;
492     Obj *head, *rest, *typ, *prop, *proptype, *datalist;
493 
494     w = c_number(car(size));  h = c_number(cadr(size));
495     img = get_img(imf, w, h);
496     if (img == NULL)
497       run_error("no image?");
498     if (img->w == 1 && img->h == 1) {
499 	/* A color is more like a tile than an icon. */
500 	img->istile = TRUE;
501 	img->palette = cons(cons(new_number(0), parts), lispnil);
502 	return;
503     }
504     if (match_keyword(car(cddr(size)), K_TILE))
505       img->istile = TRUE;
506     if (match_keyword(car(cddr(size)), K_TERRAIN))
507       img->isterrain = TRUE;
508     if (match_keyword(car(cddr(size)), K_CONNECTION))
509       img->isconnection = TRUE;
510     if (match_keyword(car(cddr(size)), K_BORDER))
511       img->isborder = TRUE;
512     if (match_keyword(car(cddr(size)), K_TRANSITION))
513       img->istransition = TRUE;
514     numsubs = 0;
515     for_all_list(parts, rest) {
516 	head = car(rest);
517 	typ = car(head);
518 	imtype = K_OTHER_;
519 	if (match_keyword(typ, K_MONO)) {
520 	    imtype = K_MONO_;
521 	} else if (match_keyword(typ, K_MASK)) {
522 	    imtype = K_MASK_;
523 	} else if (match_keyword(typ, K_COLOR)) {
524 	    imtype = K_COLR_;
525 	} else if (match_keyword(typ, K_FILE)) {
526 	    imtype = K_FILE_;
527 	} else if (match_keyword(typ, K_EMBED)) {
528 	    name = c_string(cadr(head));
529 	    if (img->embedname != NULL
530 		&& strcmp(img->embedname, name) != 0)
531 	      run_warning("Changing embed name from \"%s\" to \"%s\" in %dx%d image of \"%s\"",
532 			  img->embedname, name, w, h, imf->name);
533 	    img->embedname = name;
534 	} else if (match_keyword(typ, K_EMBED_AT)) {
535 	    emx = c_number(cadr(head));  emy = c_number(caddr(head));
536 	    if ((img->embedx >= 0 && emx != img->embedx)
537 		|| (img->embedy >= 0 && emy != img->embedy))
538 	      run_warning("Changing embed x,y from %d,%d to %d,%d in %dx%d image of \"%s\"",
539 			  img->embedx, img->embedy, emx, emy, w, h, imf->name);
540 	    img->embedx = emx;  img->embedy = emy;
541 	} else if (match_keyword(typ, K_EMBED_SIZE)) {
542 	    emw = c_number(cadr(head));  emh = c_number(caddr(head));
543 	    if ((img->embedw >= 0 && emw != img->embedw)
544 		|| (img->embedh >= 0 && emh != img->embedh))
545 	      run_warning("Changing embed w,h from %d,%d to %d,%d in %dx%d image of \"%s\"",
546 			  img->embedw, img->embedh, emw, emh, w, h, imf->name);
547 	    img->embedw = emw;  img->embedh = emh;
548 	} else if (match_keyword(typ, K_HEXGRID)) {
549 	    img->hexgridx = c_number(cadr(head));
550 	    img->hexgridy = c_number(caddr(head));
551 	    numsubs = img->hexgridx*img->hexgridy;
552 	} else if (match_keyword(typ, K_NOTES)) {
553 	    img->notes = cadr(head);
554 	    syntax_error(head, "extra junk after image notes property");
555 	} else if (match_keyword(typ, K_X)) {
556 	    numsubs = c_number(cadr(head));
557 	    if (cddr(head) != lispnil) {
558 		img->subx = c_number(caddr(head));
559 		img->suby = c_number(car(cdddr(head)));
560 	    }
561 	} else {
562 	    run_warning("unknown image property in \"%s\"", imf->name);
563 	}
564 	/* If there is no actual image data to process, skip to the next
565 	   clause in the form. */
566 	if (imtype == K_OTHER_)
567 	  continue;
568 	datalist = cdr(head);
569 	/* Interpret random image subproperties. */
570 	while (consp(car(datalist))) {
571 	    prop = car(datalist);
572 	    proptype = car(prop);
573 	    if (match_keyword(proptype, K_ACTUAL)) {
574 		img->actualw = c_number(cadr(prop));
575 		img->actualh = c_number(caddr(prop));
576 	    } else if (match_keyword(proptype, K_PIXEL_SIZE)) {
577 		img->pixelsize = c_number(cadr(prop));
578 	    } else if (match_keyword(proptype, K_PALETTE)) {
579 		img->palette = cdr(prop);
580 	    } else {
581 		char imferrbuf[200];
582 
583 		sprintlisp(imferrbuf, prop, 100);
584 		run_warning("unknown image subproperty in \"%s\": %s",
585 			    imf->name, imferrbuf);
586 	    }
587 	    datalist = cdr(datalist);
588 	}
589 	switch (imtype) {
590 	  case K_MONO_:
591 	    if (img->monodata != lispnil && !equal(datalist, img->monodata))
592 	      run_warning("Changing mono data in %dx%d image of \"%s\"",
593 			  w, h, imf->name);
594 	    img->monodata = datalist;
595 	    break;
596 	  case K_COLR_:
597 	    if (img->colrdata != lispnil && !equal(datalist, img->colrdata))
598 	      run_warning("Changing color data in %dx%d image of \"%s\"",
599 			  w, h, imf->name);
600 	    img->colrdata = datalist;
601 	    break;
602 	  case K_MASK_:
603 	    if (img->maskdata != lispnil && !equal(datalist, img->maskdata))
604 	      run_warning("Changing mask data in %dx%d image of \"%s\"",
605 			  w, h, imf->name);
606 	    img->maskdata = datalist;
607 	    break;
608 	  case K_FILE_:
609 	    if (img->filedata != lispnil && !equal(datalist, img->filedata))
610 	      run_warning("Changing file data in %dx%d image of \"%s\"",
611 			  w, h, imf->name);
612 	    img->filedata = datalist;
613 	    break;
614 	  default:
615 	    break;
616 	}
617     }
618     /* Allocate space for any subimages that might be needed. */
619     /* First set some standard numbers of subimages. */
620     if (img->isborder) {
621 	numsubs = 16;
622     } else if (img->isconnection) {
623 	numsubs = 64;
624     } else if (img->istransition) {
625 	numsubs = 4 * 4;
626     /* Limit the number of terrain subimages if we lack memory. */
627     } else if (poor_memory) { /* FIXME - what about hexgrid? */
628     	numsubs = min(numsubs, 3);
629     }
630     /* Deal with possible weird situations. */
631     if (img->numsubimages > 0 && numsubs != img->numsubimages) {
632 	run_warning("Going from %d to %d subimages in %dx%d image of \"%s\"",
633 		    img->numsubimages, numsubs, w, h, imf->name);
634 	img->subimages = NULL;
635     }
636     img->numsubimages = numsubs;
637     if (img->subimages == NULL) {
638 	img->subimages = (Image **) xmalloc(numsubs * sizeof(Image *));
639 	for (subi = 0; subi < numsubs; ++subi) {
640 	    subimg = get_subimg(imf, img->w, img->h);
641 	    img->subimages[subi] = subimg;
642 	}
643     }
644 }
645 
646 void
compute_image_bboxes(ImageFamily * imf)647 compute_image_bboxes(ImageFamily *imf)
648 {
649     Image *img;
650 
651     if (imf == NULL)
652       return;
653     for_all_images(imf, img) {
654 	compute_image_bbox(img);
655     }
656 }
657 
658 void
compute_image_bbox(Image * img)659 compute_image_bbox(Image *img)
660 {
661     int numbytes, i, j = 0, byte, x, y, x1, x2, k;
662     int xmin, ymin, xmax, ymax;
663     char *data = NULL;
664     Obj *datalist, *next;
665 
666     datalist = img->maskdata;
667     numbytes = img->h * computed_rowbytes(img->w, 1);
668     x = y = 0;
669     xmin = img->w;  ymin = img->h;
670     xmax = 0;  ymax = 0;
671     for (i = 0; i < numbytes; ++i) {
672 	if (img->maskdata != lispnil) {
673 	    if (data == NULL || data[j] == '\0') {
674 		next = car(datalist);
675 		if (!stringp(next)) {
676 		    syntax_error(datalist, "garbage in image data list");
677 		    return;
678 		}
679 		data = c_string(next);
680 		j = 0;
681 		datalist = cdr(datalist);
682 	    }
683 	    /* Just skip over slashes, which are for readability only. */
684 	    if (data[j] == '/')
685 	      ++j;
686 	    byte = hextoi(data[j]) * 16 + hextoi(data[j+1]);
687 	    j += 2;
688 	} else if (img->rawmaskdata != NULL) {
689 	    byte = img->rawmaskdata[i] & 0xff;
690 	} else {
691 	    byte = 0xff;
692 	}
693 	if (byte != 0) {
694 	    /* Find the most-significant and least-significant bits in
695 	       the mask byte. */
696 	    x1 = x2 = -1;
697 	    k = 0;
698 	    while (byte != 0) {
699 		if ((byte & 0x1) != 0 && x2 < 0)
700 		  x2 = x + 7 - k;
701 		byte >>= 1;
702 		if (byte == 0 && x1 < 0)
703 		  x1 = x + 7 - k;
704 		++k;
705 	    }
706 	    xmin = min(x1, xmin);  ymin = min(y, ymin);
707 	    xmax = max(x2, xmax);  ymax = max(y, ymax);
708 	}
709 	x += 8;
710 	if (x >= img->w) {
711 	    x = 0;
712 	    ++y;
713 	}
714     }
715     /* Compute position and size of bounding box. */
716     if (xmin <= xmax && ymin <= ymax) {
717 	img->bboxx = xmin;  img->bboxy = ymin;
718 	img->bboxw = xmax - xmin;  img->bboxh = ymax - ymin;
719     }
720 }
721 
722 /* Get a single pixel from the given type of data of an image. */
723 
724 int
image_pixel_at(Image * img,int imtype,int x,int y)725 image_pixel_at(Image *img, int imtype, int x, int y)
726 {
727     int rowbytes, psize, i, byte, rslt;
728     char *rawdata = NULL;
729 
730     if (imtype == K_MONO_) {
731 	rawdata = img->rawmonodata;
732 	psize = 1;
733     } else if (imtype == K_MASK_) {
734 	rawdata = img->rawmaskdata;
735 	psize = 1;
736     } else if (imtype == K_COLR_) {
737 	rawdata = img->rawcolrdata;
738 	psize = img->pixelsize;
739     }
740     if (rawdata == NULL)
741       return 0;
742     rowbytes = computed_rowbytes(img->w, psize);
743     i = y * rowbytes + ((x * psize) >> 3);
744     byte = rawdata[i];
745     rslt = (byte >> ((8 - psize) - ((x * psize) & 0x7))) & ((1 << psize) - 1);
746     return rslt;
747 }
748 
749 /* Set a single pixel in the given type of data of an image. */
750 
751 void
set_image_pixel_at(Image * img,int imtype,int x,int y,int val)752 set_image_pixel_at(Image *img, int imtype, int x, int y, int val)
753 {
754     int rowbytes, psize, i, byte;
755     char *rawdata = NULL;
756 
757     if (imtype == K_MONO_) {
758 	rawdata = img->rawmonodata;
759 	psize = 1;
760     } else if (imtype == K_MASK_) {
761 	rawdata = img->rawmaskdata;
762 	psize = 1;
763     } else if (imtype == K_COLR_) {
764 	rawdata = img->rawcolrdata;
765 	psize = img->pixelsize;
766     }
767     if (rawdata != NULL) {
768 	rowbytes = computed_rowbytes(img->w, psize);
769 	i = y * rowbytes + ((x * psize) >> 3);
770 	byte = rawdata[i];
771         byte &= ~ (((1 << psize) - 1) << ((8 - psize) - ((x * psize) & 0x7)));
772 	byte |= val << ((8 - psize) - ((x * psize) & 0x7));
773 	rawdata[i] = byte;
774     }
775 }
776 
777 /* Create a new data structure for mode filtering; maxvals is how many
778    distinct values we might call add_to_mf on.  The way this works is that
779    you create the structure with new_mf, then you call add_to_mf a bunch of
780    times with different values.  Then you can call mode_of_mf and it'll
781    tell which value you used the most times in calls to add_to_mf.  Calling
782    zero_mf resets the filter in a way that is cheaper than deleting and
783    re-creating it, and delete_mf is called when you're finally finished. */
784 
785 static ModeFilter
new_mf(int maxval)786 new_mf(int maxval)
787 {
788     ModeFilter rval = (ModeFilter)xmalloc(sizeof(MFEntry)*(maxval+1));
789 
790     return rval;
791 }
792 
793 /* Add a new value to the mode filter. */
794 
795 static void
add_to_mf(ModeFilter mf,int val)796 add_to_mf(ModeFilter mf, int val)
797 {
798     int i;
799     MFEntry mfe;
800 
801     if (mf == NULL) return;
802     for (i = 0; (mf[i].value != val) && (mf[i].count != 0); i++);
803     mf[i].value = val;
804     mf[i].count++;
805     if (mf[i].count > mf[0].count) {
806         mfe = mf[i];
807         mf[i] = mf[0];
808         mf[0] = mfe;
809     }
810 }
811 
812 /* Find the most common value in the mode filter. */
813 
814 static int
mode_of_mf(ModeFilter mf)815 mode_of_mf(ModeFilter mf)
816 {
817     if (mf != NULL)
818         return mf[0].value;
819     else
820         return 0;
821 }
822 
823 /* Empty the mode filter of all counts. */
824 
825 static void
zero_mf(ModeFilter mf)826 zero_mf(ModeFilter mf)
827 {
828     int i;
829 
830     if (mf == NULL) return;
831     for (i = 0; mf[i].count != 0; i++)
832         mf[i].count = 0;
833     mf[0].value = 0;
834 }
835 
836 /* Get rid of the mode filter. */
837 
838 static void
delete_mf(ModeFilter mf)839 delete_mf(ModeFilter mf)
840 {
841     if (mf != NULL) free(mf);
842 }
843 
844 /* Calculate hch by a formula that matches Stan's magic tables, but also
845    gives reasonable results at intermediate sizes.  Needed because the
846    standard hex shapes have been tweaked away from geometric perfection,
847    for graphics expediency. */
848 
849 static int
calculate_hch(int h)850 calculate_hch(int h)
851 {
852     return (h*3)/4 + h/72 + h/144 + 1;
853 }
854 
855 /* Mask the image down to a hexagon that fills the image rectangle - points
856    at the centres of the top and bottom, flat sides along left and right. */
857 
858 static void
add_hex_mask(Image * img)859 add_hex_mask(Image *img)
860 {
861     int tw, th, x, y, numbytes;
862 
863     if (img == NULL)
864         return;
865     if (img->w > img->h)
866         return;
867 
868     /* Ensure that binary version of mask exists.  Create one even if none
869        was specified. */
870     if (img->rawmaskdata == NULL) {
871 	img->rawmaskdata = (char *)xmalloc(numbytes);
872         if (img->maskdata != lispnil)
873 	    interp_bytes(img->maskdata, numbytes, img->rawmaskdata, 0);
874         else
875 	    for (y = 0; y < img->h; y++)
876 	        for (x = 0; x < img->w; x++)
877 	            set_image_pixel_at(img, K_MASK_, x, y, 1);
878     }
879 
880     /* Calculate size of triangles to mask out */
881     tw = img->w / 2 - 1;
882     th = img->h - calculate_hch(img->h) - 1;
883 
884     /* Mask out the bits */
885     for (x = 1; x <= tw; x++)
886         for (y = 0; y <= (x*th) / tw; y++) {
887 	    set_image_pixel_at(img, K_MASK_, tw-x, y, 0);
888 	    set_image_pixel_at(img, K_MASK_, tw+1+x, y, 0);
889 	    set_image_pixel_at(img, K_MASK_, tw-x, img->h-1-y, 0);
890 	    set_image_pixel_at(img, K_MASK_, tw+1+x, img->h-1-y, 0);
891 	}
892 }
893 
894 /* Remove the mask from the four triangular areas outside the inscribed
895    hexagon (see add_hex_mask above).  Fill in those triangles with data
896    copied from the diagonal edges just inside the hex area.  This is
897    useful because it means we can do remove_hex_mask, scale up, and then
898    add_hex_mask, and the result will have smooth edges instead of
899    magnified jaggies from the lower resolution.  Warning: caller must
900    load raw mono and color data before calling this, this function won't
901    do that. */
902 
903 static void
remove_hex_mask(Image * img)904 remove_hex_mask(Image *img)
905 {
906     int tw, th, x, y, ylim, c1, c2, c3, c4, numbytes;
907 
908     if (img == NULL)
909         return;
910     if (img->w > img->h)
911         return;
912 
913     /* Ensure that binary version of mask exists.  Abort if no mask.  */
914     if (img->rawmaskdata == NULL) {
915 	img->rawmaskdata = (char *)xmalloc(numbytes);
916         if (img->maskdata != lispnil)
917 	    interp_bytes(img->maskdata, numbytes, img->rawmaskdata, 0);
918         else
919 	    return;
920     }
921 
922     /* Calculate size of triangles to unmask */
923     tw = img->w / 2 - 1;
924     th = img->h - calculate_hch(img->h) - 1;
925 
926     /* Unmask the pixels */
927     for (x = 1; x <= tw; x++) {
928         ylim = (x*th) / tw;
929         c1 = image_pixel_at(img, K_MASK_, tw-x, ylim+1);
930 	c2 = image_pixel_at(img, K_MASK_, tw+1+x, ylim+1);
931 	c3 = image_pixel_at(img, K_MASK_, tw-x, img->h-2-ylim);
932 	c4 = image_pixel_at(img, K_MASK_, tw+1+x, img->h-2-ylim);
933         for (y = 0; y <= ylim; y++) {
934 	    set_image_pixel_at(img, K_MASK_, tw-x, y, c1);
935 	    set_image_pixel_at(img, K_MASK_, tw+1+x, y, c2);
936 	    set_image_pixel_at(img, K_MASK_, tw-x, img->h-1-y, c3);
937 	    set_image_pixel_at(img, K_MASK_, tw+1+x, img->h-1-y, c4);
938 	}
939         if (img->rawmonodata != NULL) {
940 	    c1 = image_pixel_at(img, K_MONO_, tw-x, ylim+1);
941 	    c2 = image_pixel_at(img, K_MONO_, tw+1+x, ylim+1);
942 	    c3 = image_pixel_at(img, K_MONO_, tw-x, img->h-2-ylim);
943 	    c4 = image_pixel_at(img, K_MONO_, tw+1+x, img->h-2-ylim);
944             for (y = 0; y <= ylim; y++) {
945 	        set_image_pixel_at(img, K_MONO_, tw-x, y, c1);
946 	        set_image_pixel_at(img, K_MONO_, tw+1+x, y, c2);
947 	        set_image_pixel_at(img, K_MONO_, tw-x, img->h-1-y, c3);
948 	        set_image_pixel_at(img, K_MONO_, tw+1+x, img->h-1-y, c4);
949 	    }
950 	}
951         if (img->rawcolrdata != NULL) {
952 	    c1 = image_pixel_at(img, K_COLR_, tw-x, ylim+1);
953 	    c2 = image_pixel_at(img, K_COLR_, tw+1+x, ylim+1);
954 	    c3 = image_pixel_at(img, K_COLR_, tw-x, img->h-2-ylim);
955 	    c4 = image_pixel_at(img, K_COLR_, tw+1+x, img->h-2-ylim);
956             for (y = 0; y <= ylim; y++) {
957 	        set_image_pixel_at(img, K_COLR_, tw-x, y, c1);
958 	        set_image_pixel_at(img, K_COLR_, tw+1+x, y, c2);
959 	        set_image_pixel_at(img, K_COLR_, tw-x, img->h-1-y, c3);
960 	        set_image_pixel_at(img, K_COLR_, tw+1+x, img->h-1-y, c4);
961 	    }
962 	}
963     }
964 }
965 
966 /* Scale one layer of an image. */
967 
968 static void
scale_image_layer(Image * imgin,Image * imgout,int layer,int use_mask,ModeFilter mf)969 scale_image_layer(Image *imgin, Image *imgout, int layer, int use_mask,
970 		  ModeFilter mf)
971 {
972     int u, v, x, y, xa, xb, ya, yb, tmp;
973 
974     /* Perform a mode-filtered scaling operation. */
975 
976     /* The way this works is that u and v are coordinates in the output image
977        rval.  For each pixel (u,v) we compute the rectangle (xa..xb,ya..yb)
978        in the input image img, which rectangle covers all the pixels that are
979        touched by the pixel (u,v) when it's projected onto img, noting that
980        a pixel is defined to be closed on the sides with lesser coordinate
981        values and open on the sides with greater coordinate values.  We
982        perform a mode filter over (xa..xb,ya..yb), that is, we find the
983        pixel value that occurs most commonly in that rectangle, splitting
984        ties by preferring the value that occurs first in reading order; the
985        result is the pixel value for the pixel (u,v).  We do not count input
986        pixels that are masked out.  If the scaling is by less than a factor
987        of 2 up or down, the result will be basically the same as
988        nearest-neighbour resampling. */
989 
990     /* Loop for each pixel (u,v) */
991     for (v = 0; v < imgout->h; v++) {
992 
993         /* Might as well calculate ya and yb here because v determines them */
994         ya = (v*imgin->h)/imgout->h;
995         yb = ((v+1)*imgin->h-1)/imgout->h;
996 
997         for (u = 0; u < imgout->w; u++) {
998 
999 	    /* Calculate xa and xb */
1000 	    xa = (u*imgin->w)/imgout->w;
1001 	    xb = ((u+1)*imgin->w-1)/imgout->w;
1002 
1003 	    /* If the rectangle is small, and we don't have a mask, then
1004 	       skip the mode filter business because the first pixel wins. */
1005 	    if ((xb-xa+1)*(yb-ya+1) <= 2 && !use_mask) {
1006 	        set_image_pixel_at(imgout, layer, u, v,
1007 		    image_pixel_at(imgin, layer, xa, ya));
1008 
1009 	    /* Otherwise we have to do the filter thing. */
1010 	    } else {
1011 
1012 	        /* Look through the input rectangle and compute modes */
1013 	        for (y = yb; y >= ya; y--)
1014 		    for (x = xb; x >= xa; x--)
1015 		        if (!use_mask
1016 			    || image_pixel_at(imgin, K_MASK_, x, y) != 0)
1017 		        add_to_mf(mf, image_pixel_at(imgin, layer, x, y));
1018 
1019 	        /* Set output pixel */
1020 		set_image_pixel_at(imgout, layer, u, v, mode_of_mf(mf));
1021 		zero_mf(mf);
1022 	    }
1023         }
1024     }
1025 }
1026 
1027 /* Scale an image (or subimage). */
1028 
1029 static void
scale_image(ImageFamily * imf,Image * img,Image * img2,int dhm)1030 scale_image(ImageFamily *imf, Image *img, Image *img2, int dhm)
1031 {
1032     int numbytes, numbytes2;
1033     ModeFilter mf;
1034 
1035     /* Scale the embedding coordinates. */
1036     img2->embedx = (img->embedx*img2->w)/img->w;
1037     img2->embedy = (img->embedy*img2->h)/img->h;
1038     img2->embedw = (img->embedw*img2->w)/img->w;
1039     img2->embedh = (img->embedh*img2->h)/img->h;
1040 
1041     /* Actually get the input image if we haven't yet. */
1042     if (img->rawcolrdata == NULL) {
1043 	/* Try different ways to get some image data. */
1044 	if (img->colrdata != lispnil) {
1045 	    numbytes = img->h * computed_rowbytes(img->w, img->pixelsize);
1046 	    img->rawcolrdata = (char *)xmalloc(numbytes);
1047 	    interp_bytes(img->colrdata, numbytes, img->rawcolrdata, 0);
1048 	} else if (img->filedata != lispnil) {
1049 	    make_image_from_file_image(imf, img, img, 0);
1050 	}
1051     }
1052 
1053     /* Copy over a bunch of other fields. */
1054     img2->pixelsize = img->pixelsize;
1055     img2->palette = img->palette;
1056     img2->rawpalette = img->rawpalette;
1057     img2->numcolors = img->numcolors;
1058     img2->istile = img->istile;
1059     img2->isterrain = img->isterrain;
1060     img2->isconnection = img->isconnection;
1061     img2->isborder = img->isborder;
1062     img2->istransition = img->istransition;
1063     img2->hexgridx = img->hexgridx;
1064     img2->hexgridy = img->hexgridy;
1065 
1066     /* Mark the image as having been computed rather than read in. */
1067     img2->synthetic = TRUE;
1068 
1069     if (img->rawcolrdata != NULL) {
1070 	numbytes2 = img2->h * computed_rowbytes(img2->w, img2->pixelsize);
1071 	img2->rawcolrdata = (char *)xmalloc(numbytes2);
1072     }
1073     numbytes = img->h * computed_rowbytes(img->w, 1);
1074     numbytes2 = img2->h * computed_rowbytes(img2->w, 1);
1075 
1076     /* Ensure that binary version of mono image exists. */
1077     make_raw_mono_data(img, FALSE);
1078     if (img->rawmonodata != NULL)
1079       img2->rawmonodata = (char *)xmalloc(numbytes2);
1080 
1081     /* Ensure that binary version of mask exists. */
1082     if (img->rawmaskdata == NULL && img->maskdata != lispnil) {
1083 	img->rawmaskdata = (char *)xmalloc(numbytes);
1084 	interp_bytes(img->maskdata, numbytes, img->rawmaskdata, 0);
1085     }
1086     if (img->rawmaskdata != NULL)
1087       img2->rawmaskdata = (char *)xmalloc(numbytes2);
1088 
1089     /* Tweak the input image's mask if appropriate */
1090     if (dhm)
1091         remove_hex_mask(img);
1092 
1093     /* Do the scaling operation */
1094     mf = new_mf(256);
1095     if (img2->rawmaskdata != NULL) {
1096         if (img2->rawcolrdata != NULL)
1097 	    scale_image_layer(img, img2, K_COLR_, TRUE, mf);
1098         if (img2->rawmonodata != NULL)
1099 	    scale_image_layer(img, img2, K_MONO_, TRUE, mf);
1100         scale_image_layer(img, img2, K_MASK_, FALSE, mf);
1101     } else {
1102         if (img2->rawcolrdata != NULL)
1103 	    scale_image_layer(img, img2, K_COLR_, FALSE, mf);
1104         if (img2->rawmonodata != NULL)
1105 	    scale_image_layer(img, img2, K_MONO_, FALSE, mf);
1106     }
1107     delete_mf(mf);
1108 
1109     /* Put the hex masks back */
1110     if (dhm) {
1111         add_hex_mask(img);
1112         add_hex_mask(img2);
1113     }
1114 
1115     /* Set the image bounding box */
1116     compute_image_bbox(img2);
1117 
1118     /* Recognize flat colors */
1119     if (img2->w == 1 && img2->h == 1 && img2->rawcolrdata != NULL) {
1120 	if (img2->rawpalette == NULL)
1121 	    make_raw_palette(img2);
1122         img2->istile = TRUE;
1123         img2->r = img2->rawpalette[4 * img2->rawcolrdata[0] + 1];
1124         img2->g = img2->rawpalette[4 * img2->rawcolrdata[0] + 2];
1125         img2->b = img2->rawpalette[4 * img2->rawcolrdata[0] + 3];
1126     }
1127 
1128     /* Call the interface hook */
1129     if (imf_interp_hook)
1130         (*imf_interp_hook)(imf, img2, FALSE);
1131 }
1132 
1133 /* Scale image img in family imf to size w by h and add it to the family. */
1134 
1135 static Image *
add_scaled_image(ImageFamily * imf,Image * img,int w,int h)1136 add_scaled_image(ImageFamily *imf, Image *img, int w, int h)
1137 {
1138     Image *rval;
1139     int i, dhm;
1140 
1141     /* We must have a family and an input image, and the size must be sane. */
1142     if (imf == NULL || img == NULL || w <= 0 || h <= 0)
1143         return NULL;
1144 
1145     /* Create a data structure for the output. */
1146     rval = get_img(imf, w, h);
1147 
1148     /* Figure out whether to Do Hex Masking */
1149     dhm = (img->isterrain || img->isconnection
1150 	|| img->istransition) && (img->h >= img->w) && (h >= w);
1151 
1152     /* Scale the main image */
1153     scale_image(imf, img, rval, dhm);
1154 
1155     /* Handle subimages */
1156     if (img->numsubimages > 0 && img->subimages != NULL) {
1157         rval->numsubimages = img->numsubimages;
1158         rval->subimages
1159 	    = (Image **) xmalloc(img->numsubimages * sizeof(Image *));
1160         for (i = 0; i < img->numsubimages; i++) {
1161 	    rval->subimages[i] = get_subimg(imf, rval->w, rval->h);
1162 	    scale_image(imf, img->subimages[i], rval->subimages[i], dhm);
1163 	}
1164     }
1165 
1166     /* Return result */
1167     return rval;
1168 }
1169 
1170 void
make_raw_mono_data(Image * img,int force)1171 make_raw_mono_data(Image *img, int force)
1172 {
1173     int numbytes = img->h * computed_rowbytes(img->w, 1);
1174 
1175     if ((img->rawmonodata == NULL || force) && img->monodata != lispnil) {
1176 	img->rawmonodata = (char *)xmalloc(numbytes);
1177 	interp_bytes(img->monodata, numbytes, img->rawmonodata, 0);
1178     }
1179 }
1180 
1181 /* Given a list of strings, interpret the hex digits and put the
1182    results at the given address. */
1183 
1184 void
interp_bytes(Obj * datalist,int numbytes,char * destaddr,int jump)1185 interp_bytes(Obj *datalist, int numbytes, char *destaddr, int jump)
1186 {
1187     int i, j = 0;
1188     char *data = NULL;
1189 
1190     for (i = 0; i < numbytes; ++i) {
1191 	if (data == NULL || data[j] == '\0') {
1192 	    if (datalist == lispnil) {
1193 		return;
1194 	    } else if (stringp(car(datalist))) {
1195 		data = c_string(car(datalist));
1196 		j = 0;
1197 	    } else {
1198 		syntax_error(datalist, "Non-string in image data list");
1199 		/* Have to give up now. */
1200 		return;
1201 	    }
1202 	    datalist = cdr(datalist);
1203 	}
1204 	/* Just skip over slashes, which are for readability only. */
1205 	if (data[j] == '/')
1206 	  ++j;
1207 	destaddr[i] = hextoi(data[j]) * 16 + hextoi(data[j+1]);
1208 	if (jump == 1 || (jump > 0 && i % jump == 0)) {
1209 	    i += jump;
1210 	    /* Be neat, put a zero in the location we're jumping over. */
1211 	    /* (doesn't work for jump > 1, but that never happens anymore?) */
1212 	    destaddr[i] = 0;
1213 	}
1214 	j += 2;
1215     }
1216 }
1217 
1218 /* Compute a score describing how much scaling or tiling a given image will
1219    need to match a given size. */
1220 
1221 static int
size_match_score(int wa,int ha,int wb,int hb)1222 size_match_score(int wa, int ha, int wb, int hb)
1223 {
1224     if (!wb) wb = 1;  if (!wa) wa = 1;  if (!hb) hb = 1;  if (!ha) ha = 1;
1225     return (wa*100)/wb + (wb*100)/wa + (ha*100)/hb + (hb*100)/ha - 400;
1226 }
1227 
1228 /* Try to find an image within the specified range and as close to the
1229    specified size as possible in the family.  If no designer-specified
1230    image is available in the range, generate one of size w by h by
1231    scaling. */
1232 
1233 Image *
best_image_in_range(ImageFamily * imf,int w,int h,int wmin,int hmin,int wmax,int hmax)1234 best_image_in_range(ImageFamily *imf, int w, int h, int wmin, int hmin,
1235 		    int wmax, int hmax)
1236 {
1237     Image *img, *best_nonsynth = NULL, *best_in_range = NULL,
1238         *best_tile = NULL, *exact_match = NULL;
1239     int best_nonsynth_score = INT_MAX, best_tile_score = INT_MAX,
1240 	best_in_range_score = INT_MAX, s;
1241 
1242     if (imf == NULL || imf->images == NULL)
1243         return NULL;
1244 
1245     for_all_images(imf, img) {
1246 
1247         /* Skip all basic terrain images except power 4 and 5
1248 	   if we are low on memory. */
1249     	if (poor_memory
1250     	    && img->isterrain
1251     	    && img->w != 24
1252     	    && img->w != 44) {
1253     		continue;
1254     	}
1255 
1256         /* Don't cross the isometric/non-isometric boundary */
1257         if (img->isterrain || img->isborder || img->isconnection ||
1258 	     img->istransition) {
1259 	    if (img->w > img->h && w <= h)
1260 	        continue;
1261 	    if (img->w <= img->h && w > h)
1262 	        continue;
1263 	}
1264 
1265         /* Check if there's an exact match - this is no longer an immediate
1266 	   success because it might be synthetic */
1267         if (img->w == w && img->h == h && !img->istile)
1268 	    exact_match = img;
1269 
1270         /* Find best image that isn't synthetic or tile (scaling candidate) */
1271         if (!img->istile && !img->synthetic) {
1272 	    s = size_match_score(w, h, img->w, img->h);
1273 	    if (best_nonsynth == NULL || s < best_nonsynth_score) {
1274 	        best_nonsynth = img;
1275 	        best_nonsynth_score = s;
1276 	    }
1277 
1278 	    /* Find best in range */
1279 	    if ((best_in_range == NULL || s < best_in_range_score)
1280 		&& img->w >= wmin && img->h >= hmin
1281 		&& img->w <= wmax && img->h <= hmax) {
1282 	        best_in_range = img;
1283 	        best_in_range_score = s;
1284 	    }
1285 	}
1286 
1287         /* Find best tile */
1288         if (img->istile) {
1289 	    s = size_match_score(w, h, img->w, img->h);
1290 	    if (best_tile == NULL || s < best_tile_score) {
1291 	        best_tile = img;
1292 	        best_tile_score = s;
1293 	    }
1294 	}
1295     } /* for_all_images */
1296 
1297     /* If we have a "best in range" then use it */
1298     if (best_in_range != NULL)
1299         return best_in_range;
1300 
1301     /* If we have an exact size match, use that */
1302     if (exact_match != NULL)
1303         return exact_match;
1304 
1305     /* If we have a tile, and we're low on memory, we can't scale, or
1306        the best scaling candidate isn't as good as the tile, use tile. */
1307     if (best_tile != NULL && (poor_memory || best_nonsynth == NULL ||
1308 			      best_tile_score < best_nonsynth_score))
1309         return best_tile;
1310 
1311     /* Now we know we want to scale, so there had better exist a candidate.
1312        If not, we still might try looking for a flat colour. */
1313     if (best_nonsynth == NULL) {
1314         if ((w != 1) || (h != 1)) {
1315 	    return best_image_in_range(imf, 1, 1, 1, 1, 1, 1);
1316         } else {
1317 	    return NULL;
1318 	}
1319     }
1320 
1321     /* Scale the candidate. */
1322     return add_scaled_image(imf, best_nonsynth, w, h);
1323 }
1324 
1325 Image *
smallest_image(ImageFamily * imf)1326 smallest_image(ImageFamily *imf)
1327 {
1328     Image *img, *smallest = NULL;
1329 
1330     if (imf == NULL)
1331       return NULL;
1332     for_all_images(imf, img) {
1333 	if (smallest == NULL || (img->w < smallest->w && img->h < smallest->h))
1334 	  smallest = img;
1335     }
1336     return smallest;
1337 }
1338 
1339 Image *
largest_image(ImageFamily * imf)1340 largest_image(ImageFamily *imf)
1341 {
1342     Image *img, *largest = NULL;
1343 
1344     if (imf == NULL)
1345       return NULL;
1346     for_all_images(imf, img) {
1347 	if (largest == NULL || (img->w > largest->w && img->h > largest->h))
1348 	  largest = img;
1349     }
1350     return largest;
1351 }
1352 
1353 /* Compute the right location for the given emblem and unit images. */
1354 
1355 static int tmpbw;  /* work around Think C bug */
1356 
1357 int
emblem_position(Image * uimg,char * ename,ImageFamily * eimf,int sw,int sh,int vpuh,int vphh,int * exxp,int * eyyp,int * ewp,int * ehp)1358 emblem_position(Image *uimg, char *ename, ImageFamily *eimf, int sw, int sh,
1359 		int vpuh, int vphh, int *exxp, int *eyyp, int *ewp, int *ehp)
1360 {
1361     int ew1, eh1, ex, ey, ew, eh, bx, by, bw, bh, overlap;
1362     Image *eimg;
1363 
1364     /* Check if correct emblem is part of the unit's image, and don't draw
1365        if it is. */
1366     if (uimg
1367 	&& uimg->embedname
1368 	&& ename != NULL
1369 	&& strcmp(uimg->embedname, ename) == 0) {
1370 	return FALSE;
1371     }
1372     /* (should use emblem bbox to help calc) */
1373     /* Get the size of the emblem, either from the image or by computing
1374        a reasonable default. */
1375     if (uimg && uimg->embedw > 0 && uimg->embedh > 0) {
1376 	ew = uimg->embedw;  eh = uimg->embedh;
1377     } else {
1378 	ew1 = min(sw, max(8, sw / 4));  eh1 = min(sh, max(8, sh / 4));
1379 	eimg = NULL;
1380 	/* Look up the best emblem for the current zoom. */
1381 	if (eimf != NULL) {
1382 	    eimg = best_image(eimf, ew1, eh1);
1383 	}
1384 	if (eimg) {
1385 	    ew = eimg->w;  eh = eimg->h;
1386 	    /* Make a default 8x6 size for a solid color emblem. */
1387 	    if (ew == 1 && eh == 1) {
1388 		ew = 8;  eh = 6;
1389 	    }
1390 	} else {
1391 	    ew = ew1;  eh = eh1;
1392 	}
1393     }
1394     /* Position the emblem, either explicitly, or default to UR corner
1395        (note that we need the emblem's width to do this) */
1396     if (uimg && uimg->embedx >= 0 && uimg->embedy >= 0) {
1397 	ex = uimg->embedx;  ey = uimg->embedy;
1398 	/* Don't let the emblem stick out of the unit's area. */
1399 	if (ex + ew > sw)
1400 	  ex = sw - ew;
1401 	if (ey + eh > sh)
1402 	  ey = sh - eh;
1403     } else if (uimg && (uimg->bboxw != uimg->w || uimg->bboxh != uimg->h)) {
1404 	overlap = FALSE;
1405 	/* Scale bounding box by space given to image. */
1406 	bx = (uimg->bboxx * sw) / uimg->w;  by = (uimg->bboxy * sh) / uimg->h;
1407 	tmpbw = (uimg->bboxw * sw) / uimg->w;
1408 	bh = (uimg->bboxh * sh) / uimg->h;
1409 	bw = tmpbw;
1410 	/* Position the emblem outside the image's bbox if possible,
1411 	   moving in if necessary to stay inside the image's allowed
1412 	   area (sw x sh). */
1413 	ex = bx + bw;
1414 	if (ex + ew > sw) {
1415 	    /* Emblem too wide to fit between unit bbox and edge of
1416 	       area; butt it against edge of area, note the
1417 	       overlap. */
1418 	    ex = sw - ew;
1419 	    overlap = TRUE;
1420 	}
1421 	if (ex < 0)
1422 	  ex = 0;
1423 	ey = by;
1424 	if (overlap)
1425 	  ey -= eh;
1426 	if (ey + eh > sh)
1427 	  ey = sh - eh;
1428 	if (ey < 0)
1429 	  ey = 0;
1430     } else {
1431 	ex = sw - ew;  ey = 0;
1432     }
1433     /* Adjust for an oversized unit image. */
1434     if (sh > vpuh) {
1435 	ey += (vphh - vpuh) / 2;
1436 #if (0)
1437 	/* Tweaked by hand. */
1438 	if (vpuh > 16) {
1439 	    ex -= 1;
1440 	}
1441 #endif
1442     }
1443     /* Adjust for a shrunken unit image. */
1444     if (sh < vpuh) {
1445 	ex = sw - ew;
1446 	/* Tweaked by hand. */
1447 	if (vpuh > 8) {
1448 	    ey = vpuh / 8;
1449 	}
1450     }
1451     /* Return the results. */
1452     *exxp = ex;  *eyyp = ey;
1453     *ewp = ew;  *ehp = eh;
1454     return TRUE;
1455 }
1456 
1457 /* Transform the masked-out part of an image into a single chosen
1458    color. */
1459 
1460 void
blacken_masked_area(ImageFamily * imf,Image * img,int rd,int g,int b)1461 blacken_masked_area(ImageFamily *imf, Image *img, int rd, int g, int b)
1462 {
1463     int r, ri, rc, c, rmask;
1464     int rmi, rmc, rmmask;
1465     char *rp, *rmp;
1466     int black = -1;
1467     int rowsz = -1;
1468 
1469     if (img->rawpalette == NULL)
1470       make_raw_palette(img);
1471     for (c = 0; c < img->numcolors; c++) {
1472 	if (img->rawpalette[4 * c + 1] == rd
1473 	    && img->rawpalette[4 * c + 2] == g
1474 	    && img->rawpalette[4 * c + 3] == b) {
1475 	    black = c;
1476 	    break;
1477 	}
1478     }
1479     if (black < 0
1480 	&& (1 << img->pixelsize) == img->numcolors
1481 	&& img->pixelsize < 8) {
1482 	char *newdata, *nrp;
1483 	int newpsize, nrmask, nri;
1484 
1485 	newpsize = img->pixelsize * 2;
1486 	/* Don't need to mess with palette because it already has an
1487 	   additional spot allocated, and we only need the one. */
1488 	rmask = (1 << img->pixelsize) - 1;
1489 	ri = 8 - img->pixelsize;
1490 	rp = img->rawcolrdata;
1491 	newdata = (char *)xmalloc(img->h * computed_rowbytes(img->w, newpsize));
1492 	nrmask = (1 << newpsize) - 1;
1493 	nri = 8 - newpsize;
1494 	nrp = newdata;
1495 	for (r = 0; r < img->h; r++) {
1496 	  for (c = 0; c < img->w; c++) {
1497 	    rc = ((int) (*rp >> ri)) & rmask;
1498 	    /* OR the color data into its new location. */
1499 	    *nrp |= (char) (rc << nri);
1500 	    if (ri) {
1501 		ri -= img->pixelsize;
1502 	    } else {
1503 		ri = 8 - img->pixelsize;
1504 		++rp;
1505 	    }
1506 	    if (nri) {
1507 		nri -= newpsize;
1508 	    } else {
1509 		nri = 8 - newpsize;
1510 		++nrp;
1511 	    }
1512 	  }
1513 	  if ((img->pixelsize * img->w) % 8) {
1514 	    ri = 8 - img->pixelsize;
1515 	    ++rp;
1516 	  }
1517 	  if ((newpsize * img->w) % 8) {
1518 	    nri = 8 - newpsize;
1519 	    ++nrp;
1520 	  }
1521 	}
1522 	img->orig_pixelsize = img->pixelsize;
1523 	img->pixelsize = newpsize;
1524 	img->rawcolrdata = newdata;
1525     }
1526     /* If a spare color is available, put black there. */
1527     if (black < 0 && (1 << img->pixelsize) > img->numcolors) {
1528 	black = img->numcolors;
1529 	img->rawpalette[4 * black + 0] = black;
1530 	img->rawpalette[4 * black + 1] = rd;
1531 	img->rawpalette[4 * black + 2] = g;
1532 	img->rawpalette[4 * black + 3] = b;
1533 	++(img->numcolors);
1534     }
1535     rmask = (1 << img->pixelsize) - 1;
1536     ri = 8 - img->pixelsize;
1537     rp = img->rawcolrdata;
1538     /* OK, now we're getting desperate; use the color in the upper left
1539        corner and pretend it's a transparent color. But, only if it
1540        appears to be the vertex of two edges of the same color. */
1541     /*! \note This is a stupid hack. In cases where the UL corner cannot
1542 	      be relied upon, the designer should have the option of
1543 	      specifying a 'mask-color' keyword with a RGB triplet. */
1544     if (black < 0) {
1545 	black = ((int) *rp >> ri) & rmask;
1546 	rowsz = computed_rowbytes(img->w, img->pixelsize);
1547 	/* Check pixels in UR and LL corners. */
1548 	/* If the corners don't match, then grab something from the LR
1549 	   corner and hope for the best. (This is very hackish!) */
1550 	if ((black != (((int) rp[rowsz - 1] >> ri) & rmask))
1551 	    || (black != (((int) rp[rowsz * (img->h - 2)] >> ri) & rmask))) {
1552 	    black = ((int) rp[(rowsz * img->h) - 1] >> ri) & rmask;
1553 	}
1554 	img->rawpalette[4 * black + 1] = rd;
1555 	img->rawpalette[4 * black + 2] = g;
1556 	img->rawpalette[4 * black + 3] = b;
1557     }
1558     rmmask = 1;
1559     rmi = 7;
1560     rmp = img->rawmaskdata;
1561     for (r = 0; r < img->h; r++) {
1562 	for (c = 0; c < img->w; c++) {
1563 	    rc = ((int) (*rp >> ri)) & rmask;
1564 	    rmc = ((int) (*rmp >> rmi)) & rmmask;
1565 	    if (rmc == 0) {
1566 		/* Mask off the old value. */
1567 		*rp &= (char) (~ (rmask << ri));
1568 		/* Insert the color for black. */
1569 		*rp |= (char) (black << ri);
1570 	    }
1571 	    if (ri) {
1572 		ri -= img->pixelsize;
1573 	    } else {
1574 		ri = 8 - img->pixelsize;
1575 		++rp;
1576 	    }
1577 	    if (rmi) {
1578 		rmi -= 1;
1579 	    } else {
1580 		rmi = 7;
1581 		++rmp;
1582 	    }
1583 	}
1584 	if ((img->pixelsize * img->w) % 8) {
1585 	    ri = 8 - img->pixelsize;
1586 	    ++rp;
1587 	}
1588 	if (img->w % 8) {
1589 	    rmi = 7;
1590 	    ++rmp;
1591 	}
1592     }
1593 }
1594 
1595 void
blacken_mono_masked_area(ImageFamily * imf,Image * img,int rd,int g,int b)1596 blacken_mono_masked_area(ImageFamily *imf, Image *img, int rd, int g, int b)
1597 {
1598     int r, ri, rc, c, rmask;
1599     int rmi, rmc, rmmask;
1600     char *rp, *rmp;
1601 
1602     rmask = 1;
1603     ri = 7;
1604     rp = img->rawmonodata;
1605     rmmask = 1;
1606     rmi = 7;
1607     rmp = img->rawmaskdata;
1608     for (r = 0; r < img->h; r++) {
1609 	for (c = 0; c < img->w; c++) {
1610 	    rc = ((int) (*rp >> ri)) & rmask;
1611 	    rmc = ((int) (*rmp >> rmi)) & rmmask;
1612 	    if (rmc == 0) {
1613 		/* Mask off the old value. */
1614 		*rp &= (char) (~ (rmask << ri));
1615 		/* Insert the color for black. */
1616 		*rp |= (char) (1 << ri);
1617 	    }
1618 	    if (ri) {
1619 		ri -= 1;
1620 	    } else {
1621 		ri = 7;
1622 		++rp;
1623 	    }
1624 	    if (rmi) {
1625 		rmi -= 1;
1626 	    } else {
1627 		rmi = 7;
1628 		++rmp;
1629 	    }
1630 	}
1631 	if (img->w % 8) {
1632 	    ri = 7;
1633 	    ++rp;
1634 	}
1635 	if (img->w % 8) {
1636 	    rmi = 7;
1637 	    ++rmp;
1638 	}
1639     }
1640 }
1641 
1642 void
make_raw_palette(Image * img)1643 make_raw_palette(Image *img)
1644 {
1645     int ipal[4][256];
1646     int c, ln;
1647     Obj *pal;
1648 
1649     /* Parse the Lispified palette. */
1650     /* (should allocate and store directly instead of using ipal) */
1651     c = 0;
1652     for_all_list(img->palette, pal) {
1653 	parse_lisp_palette_entry(car(pal), &ipal[0][c],
1654 				 &ipal[1][c], &ipal[2][c], &ipal[3][c]);
1655 	c++;
1656     }
1657     img->numcolors = c;
1658     if (c == 0)
1659       return;
1660     /* store palette */
1661     img->rawpalette = (int *) xmalloc(257/*(img->numcolors + 1)*/ * 4 * sizeof(int));
1662     for (c = 0; c < img->numcolors; c++) {
1663 	for (ln = 0; ln < 4; ln++) {
1664 	    img->rawpalette[4 * c + ln] = ipal[ln][c];
1665 	}
1666     }
1667 }
1668 
1669 /* The comparison function for the image list just does "strcmp" order
1670    and *requires* that all image families be named and named uniquely. */
1671 
1672 static int
image_name_compare(CONST void * imf1,CONST void * imf2)1673 image_name_compare(CONST void *imf1, CONST void *imf2)
1674 {
1675     return strcmp((*((ImageFamily **) imf1))->name,
1676 		  (*((ImageFamily **) imf2))->name);
1677 }
1678 
1679 void
sort_all_images(void)1680 sort_all_images(void)
1681 {
1682     qsort(&(images[0]), numimages, sizeof(ImageFamily *), image_name_compare);
1683 }
1684 
1685 /* Check Lisp-format and binary-format data for consistency. */
1686 
1687 void
check_imf(ImageFamily * imf)1688 check_imf(ImageFamily *imf)
1689 {
1690     Image *img;
1691 
1692     if (imf == NULL)
1693       return;
1694     if (imf->name == NULL) {
1695 	return;
1696     }
1697     for_all_images(imf, img) {
1698 	/* Check consistency of Lisp and binary data. */
1699 	if (img->colrdata != lispnil && img->rawcolrdata) {
1700 	    /* (should add color image comparison) */
1701 	}
1702 	if (img->monodata != lispnil && img->rawmonodata) {
1703 	    if (!bitmaps_match(img->w, img->h, img->monodata, img->rawmonodata))
1704 	      run_warning("mono bitmap data not consistent in  %dx%d image of \"%s\"",
1705 			  img->w, img->h, imf->name);
1706 	}
1707 	if (img->maskdata != lispnil && img->rawmaskdata) {
1708 	    if (!bitmaps_match(img->w, img->h, img->maskdata, img->rawmaskdata))
1709 	      run_warning("mask bitmap data not consistent in  %dx%d image of \"%s\"",
1710 			  img->w, img->h, imf->name);
1711 	}
1712     }
1713 }
1714 
1715 static int
bitmaps_match(int w,int h,Obj * lispdata,char * rawdata)1716 bitmaps_match(int w, int h, Obj *lispdata, char *rawdata)
1717 {
1718     int i, j = 0, rowbytes, numbytes, byte;
1719     char *datastr = NULL;
1720 
1721     rowbytes = computed_rowbytes(w, 1);
1722     numbytes =  h * rowbytes;
1723     for (i = 0; i < numbytes; ++i) {
1724 	if (datastr == NULL || datastr[j] == '\0') {
1725 		if (!stringp(car(lispdata)))
1726 		  break;
1727 		datastr = c_string(car(lispdata));
1728 		j = 0;
1729 		lispdata = cdr(lispdata);
1730 	}
1731 	if (datastr[j] == '/')
1732 	  ++j;
1733 	byte = hextoi(datastr[j]) * 16 + hextoi(datastr[j+1]);
1734 	j += 2;
1735 	if (byte != rawdata[i])
1736 	  return FALSE;
1737     }
1738     return TRUE;
1739 }
1740 
1741 /* Write the imf directory for the given set of images. */
1742 
1743 void
write_imf_dir(char * filename,ImageFamily ** imfimages,int num)1744 write_imf_dir(char *filename, ImageFamily **imfimages, int num)
1745 {
1746     int i;
1747     char *loc, *token, *delims;
1748     ImageFamily *imf;
1749     FILE *fp;
1750 
1751     fp = open_file(filename, "w");
1752     if (fp != NULL) {
1753 	fprintf(fp, "ImageFamilyName FileName\n");
1754 	for (i = 0; i < num; ++i) {
1755 	    imf = images[i];
1756 	    loc = "???";
1757 	    if (imf->location && !empty_string(imf->location->name)) {
1758 		/* First remove any Unix, Mac or Windows pathnames. */
1759 		loc = copy_string(imf->location->name);
1760 		delims = "/:\\";
1761 		token = strtok(loc, delims);
1762 		while (token != NULL) {
1763 			loc = token;
1764 			token = strtok(NULL, delims);
1765 		}
1766 		/* Remove any leading dots left from Unix pathnames. */
1767 		loc += strspn(loc, ".");
1768 	    }
1769 	    fprintf(fp, "%s %s\n", imf->name, loc);
1770 	    /* (to write imf files, should scan through images once for
1771 	       each file, writing all images found that are in that file) */
1772 	}
1773 	fprintf(fp, ". .\n");
1774 	fclose(fp);
1775     } else {
1776 	run_warning("could not open file \"%s\" for writing", filename);
1777     }
1778 }
1779 
1780 /* Write out the entire image family. */
1781 
1782 void
write_imf(FILE * fp,ImageFamily * imf)1783 write_imf(FILE *fp, ImageFamily *imf)
1784 {
1785     Obj *palent, *posdata;
1786     Image *img;
1787 
1788     if (fp == NULL || imf == NULL)
1789       return;
1790     if (imf->name == NULL) {
1791 	fprintf(fp, "; garbage image family?\n");
1792 	return;
1793     }
1794     if (imf->notes != lispnil) {
1795 	fprintf(fp, "(%s \"%s\"", keyword_name(K_IMF), imf->name);
1796 	fprintf(fp, "\n  (%s ", keyword_name(K_NOTES));
1797 	fprintlisp(fp, imf->notes);
1798 	fprintf(fp, "))\n");
1799     }
1800     for_all_images(imf, img) {
1801 	if (img->monodata != lispnil
1802 	    || img->maskdata != lispnil
1803 	    || img->colrdata != lispnil
1804 	    || img->filedata != lispnil
1805 	    || img->rawmonodata != NULL
1806 	    || img->rawmaskdata != NULL
1807 	    || img->rawcolrdata != NULL
1808 	    || (img->w == 1 && img->h == 1)) {
1809 	    /* Skip over synthesized images. */
1810 	    if (img->synthetic && !write_synthetic_also) {
1811 		continue;
1812 	    }
1813 	    /* Skip over empty (undefined) 1 x 1 images. */
1814 	    if (img->w == 1
1815 	        && img->h == 1
1816 	        && img->rawpalette == NULL
1817 	        && img->palette == lispnil) {
1818 	    	continue;
1819 	    }
1820 	    fprintf(fp, "(%s \"%s\"", keyword_name(K_IMF), imf->name);
1821 	    fprintf(fp, " (");
1822 	    fprintf(fp, "(%d %d", img->w, img->h);
1823 	    if (img->istile && !(img->w == 1 && img->h == 1))
1824 	      fprintf(fp, " %s", keyword_name(K_TILE));
1825 	    if (img->isterrain)
1826 	      fprintf(fp, " %s", keyword_name(K_TERRAIN));
1827 	    if (img->isconnection)
1828 	      fprintf(fp, " %s", keyword_name(K_CONNECTION));
1829 	    if (img->isborder)
1830 	      fprintf(fp, " %s", keyword_name(K_BORDER));
1831 	    if (img->istransition)
1832 	      fprintf(fp, " %s", keyword_name(K_TRANSITION));
1833 	    fprintf(fp, ")");
1834 	    if (img->numsubimages > 0) {
1835 		fprintf(fp, " (%s %d", keyword_name(K_X), img->numsubimages);
1836 		if (img->subx > 0 || img->suby > 0)
1837 		  fprintf(fp, " %d %d", img->subx, img->suby);
1838 		fprintf(fp, ")");
1839 	    }
1840 	    if (img->hexgridx > 0 && img->hexgridy > 0) {
1841 	        fprintf(fp, " (%s %d %d)", keyword_name(K_HEXGRID),
1842 		    img->hexgridx, img->hexgridy);
1843 	    }
1844 	    if (img->embedname) {
1845 		fprintf(fp, " (%s \"%s\")",
1846 			keyword_name(K_EMBED), img->embedname);
1847 	    }
1848 	    if (img->embedx >= 0 && img->embedy >= 0) {
1849 		fprintf(fp, " (%s %d %d)",
1850 			keyword_name(K_EMBED_AT), img->embedx, img->embedy);
1851 	    }
1852 	    if (img->embedw >= 0 && img->embedh >= 0) {
1853 		fprintf(fp, " (%s %d %d)",
1854 			keyword_name(K_EMBED_SIZE), img->embedw, img->embedh);
1855 	    }
1856 	    if (img->notes != lispnil) {
1857 		fprintf(fp, "\n  (%s ", keyword_name(K_NOTES));
1858 		fprintlisp(fp, img->notes);
1859 		fprintf(fp, ")\n ");
1860 	    }
1861 	    /* Write a single color if that's what this image is. */
1862 	    if (img->w == 1 && img->h == 1) {
1863 		if (img->rawpalette != NULL) {
1864 		    write_color(fp, -1,
1865 				img->rawpalette[1],
1866 				img->rawpalette[2],
1867 				img->rawpalette[3]);
1868 		} else if (img->palette != lispnil) {
1869 		    palent = cdr(car(img->palette));
1870 		    if (stringp(car(palent)) || symbolp(car(palent))) {
1871 			fprintf(fp, " %s", c_string(car(palent)));
1872 		    } else {
1873 			write_color(fp, -1,
1874 				    c_number(car(palent)),
1875 				    c_number(cadr(palent)),
1876 				    c_number(caddr(palent)));
1877 		    }
1878 		}
1879 	    } else if (img->filedata != lispnil) {
1880 		fprintf(fp, " (%s ", keyword_name(K_FILE));
1881 		fprintf(fp, " \"%s\"", c_string(car(img->filedata)));
1882 		posdata = cdr(img->filedata);
1883 		if (posdata != lispnil) {
1884 		    if (symbolp(car(posdata))) {
1885 			fprintf(fp, " %s", c_string(car(posdata)));
1886 			posdata = cdr(posdata);
1887 		    }
1888 		    fprintf(fp, " %d %d",
1889 			    c_number(car(posdata)), c_number(cadr(posdata)));
1890 		}
1891 		fprintf(fp, ")");
1892 	    } else if ((img->colrdata != lispnil || img->rawcolrdata)
1893 			&& !color_matches_mono(img)) {
1894 		fprintf(fp, "\n  ");
1895 		write_pixmap(fp, img->w, img->h, img->actualw, img->actualh,
1896 			     img->pixelsize, img->orig_pixelsize,
1897 			     img->palette, img->rawpalette, img->numcolors,
1898 			     img->colrdata, img->rawcolrdata);
1899 	    }
1900 	    if (img->monodata != lispnil || img->rawmonodata) {
1901 		fprintf(fp, "\n  ");
1902 		write_bitmap(fp, keyword_name(K_MONO), img->w, img->h,
1903 			     img->monodata, img->rawmonodata);
1904 	    }
1905 	    if (img->maskdata != lispnil || img->rawmaskdata) {
1906 		fprintf(fp, "\n  ");
1907 		write_bitmap(fp, keyword_name(K_MASK), img->w, img->h,
1908 			     img->maskdata, img->rawmaskdata);
1909 	    }
1910 	    fprintf(fp, "))\n");
1911 	}
1912     }
1913 }
1914 
1915 /* Study an ostensibly color image to see if its color table includes
1916    black and white only (white first, then black), and if its data is
1917    the same as the mono version of the image. */
1918 
1919 static int
color_matches_mono(Image * img)1920 color_matches_mono(Image *img)
1921 {
1922     int i, cj, mj, rowbytes, numbytes, cbyte, mbyte;
1923     int col[2], red[2], grn[2], blu[2];
1924     char *cdatastr = NULL, *mdatastr = NULL;
1925     Obj *clispdata = img->colrdata, *mlispdata = img->monodata, *palette;
1926 
1927     if (img->pixelsize != 1)
1928       return FALSE;
1929 
1930     /* No match possible if not a black-white-only palette. */
1931     if (img->numcolors > 2)
1932       return FALSE;
1933 
1934     if (img->rawpalette != NULL) {
1935 	for (i = 0; i < 2; i++) {
1936 	    col[i] = img->rawpalette[4*i+0];
1937 	    red[i] = img->rawpalette[4*i+1];
1938 	    grn[i] = img->rawpalette[4*i+2];
1939 	    blu[i] = img->rawpalette[4*i+3];
1940 	}
1941     } else if (img->palette != lispnil) {
1942 	palette = img->palette;
1943 	parse_lisp_palette_entry(car(palette), &col[0],
1944 				 &red[0], &grn[0], &blu[0]);
1945 	if (cdr(palette) == lispnil) {
1946 	    /* If only one color in the palette, say the other one is
1947 	       black. */
1948 	    col[1] = 1;
1949 	    red[1] = grn[1] = blu[1] = 0;
1950 	    /* If the one color is black, say it's white. */
1951 	    if (col[0] == 0
1952 		&& red[0] < BLACK_THRESHOLD
1953 		&& grn[0] < BLACK_THRESHOLD
1954 		&& blu[0] < BLACK_THRESHOLD) {
1955 		col[0] = 0;
1956 		red[0] = grn[0] = blu[0] = 65535;
1957 	    }
1958 	} else {
1959 	    /* Parse the second entry in the palette. */
1960 	    parse_lisp_palette_entry(cadr(palette), &col[1],
1961 				     &red[1], &grn[1], &blu[1]);
1962 	}
1963     } else {
1964 	return FALSE;
1965     }
1966 
1967     if (!(col[0] == 0
1968 	  && red[0] > WHITE_THRESHOLD
1969 	  && grn[0] > WHITE_THRESHOLD
1970 	  && blu[0] > WHITE_THRESHOLD
1971 	  && col[1] == 1
1972 	  && red[1] < BLACK_THRESHOLD
1973 	  && grn[1] < BLACK_THRESHOLD
1974 	  && blu[1] < BLACK_THRESHOLD))
1975 	return FALSE;
1976 
1977     /* Now compare the contents. */
1978     rowbytes = computed_rowbytes(img->w, 1);
1979     numbytes =  img->h * rowbytes;
1980     cj = mj = 0;
1981     for (i = 0; i < numbytes; ++i) {
1982 	/* Extract one byte of the color image. */
1983 	if (clispdata != lispnil) {
1984 	    if (cdatastr == NULL || cdatastr[cj] == '\0') {
1985 		if (!stringp(car(clispdata)))
1986 		  break;
1987 		cdatastr = c_string(car(clispdata));
1988 		cj = 0;
1989 		clispdata = cdr(clispdata);
1990 	    }
1991 	    if (cdatastr[cj] == '/')
1992 	      ++cj;
1993 	    cbyte = hextoi(cdatastr[cj]) * 16 + hextoi(cdatastr[cj+1]);
1994 	    cj += 2;
1995 	} else if (img->rawcolrdata != NULL) {
1996 	    cbyte = (img->rawcolrdata)[i];
1997 	} else {
1998 	    return FALSE;
1999 	}
2000 	/* Extract one byte of the mono image. */
2001 	if (mlispdata != lispnil) {
2002 	    if (mdatastr == NULL || mdatastr[mj] == '\0') {
2003 		if (!stringp(car(mlispdata)))
2004 		  break;
2005 		mdatastr = c_string(car(mlispdata));
2006 		mj = 0;
2007 		mlispdata = cdr(mlispdata);
2008 	    }
2009 	    if (mdatastr[mj] == '/')
2010 	      ++mj;
2011 	    mbyte = hextoi(mdatastr[mj]) * 16 + hextoi(mdatastr[mj+1]);
2012 	    mj += 2;
2013 	} else if (img->rawmonodata != NULL) {
2014 	    mbyte = (img->rawmonodata)[i];
2015 	} else {
2016 	    return FALSE;
2017 	}
2018 	/* Compare the bytes. */
2019 	if (cbyte != mbyte)
2020 	  return FALSE;
2021     }
2022     return TRUE;
2023 }
2024 
2025 static void
write_pixmap(FILE * fp,int w,int h,int actualw,int actualh,int pixelsize,int orig_pixelsize,Obj * palette,int * rawpalette,int numcolors,Obj * lispdata,char * rawdata)2026 write_pixmap(FILE *fp, int w, int h, int actualw, int actualh,
2027 	     int pixelsize, int orig_pixelsize,
2028 	     Obj *palette, int *rawpalette, int numcolors,
2029 	     Obj *lispdata, char *rawdata)
2030 {
2031     int dolisp, i, j = 0, rowbytes, numbytes, byte;
2032     char *datastr = NULL;
2033 
2034     actualw = (actualw != 0 ? actualw : w);
2035     actualh = (actualh != 0 ? actualh : h);
2036     dolisp = (lispdata != lispnil);
2037     /* If the pixel size was mangled (Windows) we need to use the original pixel size. */
2038     rowbytes = computed_rowbytes(actualw, (orig_pixelsize ? orig_pixelsize : pixelsize));
2039     numbytes = actualh * rowbytes;
2040     fprintf(fp, "(%s", keyword_name(K_COLOR));
2041     if (actualw != w || actualh != h)
2042       fprintf(fp, " (%s %d %d)", keyword_name(K_ACTUAL), actualw, actualh);
2043     /* (should not use orig_pixelsize if !dolisp?) Yes! See above. */
2044     fprintf(fp, " (%s %d)", keyword_name(K_PIXEL_SIZE),
2045 	    (orig_pixelsize ? orig_pixelsize : pixelsize));
2046     if (palette != lispnil || (rawpalette && numcolors))
2047       write_palette_contents(fp, palette, rawpalette, numcolors);
2048     fprintf(fp, "\n   \"");
2049     for (i = 0; i < numbytes; ++i) {
2050 	if (i > 0 && i % 32 == 0)
2051 	  fprintf(fp, "\"\n   \"");
2052 	if (i > 0 && i % 32 != 0 && i % rowbytes == 0)
2053 	  fprintf(fp, "/");
2054 	if (dolisp) {
2055 	    if (datastr == NULL || datastr[j] == '\0') {
2056 		if (!stringp(car(lispdata)))
2057 		  break;
2058 		datastr = c_string(car(lispdata));
2059 		j = 0;
2060 		lispdata = cdr(lispdata);
2061 	    }
2062 	    if (datastr[j] == '/')
2063 	      ++j;
2064 	    byte = hextoi(datastr[j]) * 16 + hextoi(datastr[j+1]);
2065 	    j += 2;
2066 	} else {
2067 	    byte = rawdata[i];
2068 	}
2069 	fprintf(fp, "%02x", (unsigned char) byte);
2070     }
2071     fprintf(fp, "\")");
2072 }
2073 
2074 static void
write_bitmap(FILE * fp,char * subtyp,int w,int h,Obj * lispdata,char * rawdata)2075 write_bitmap(FILE *fp, char *subtyp, int w, int h, Obj *lispdata,
2076 	     char *rawdata)
2077 {
2078     int dolisp, i, j = 0, rowbytes, numbytes, byte;
2079     char *datastr = NULL;
2080 
2081     /* Lisp data overrides raw byte data. */
2082     dolisp = (lispdata != lispnil);
2083     rowbytes = computed_rowbytes(w, 1);
2084     numbytes =  h * rowbytes;
2085     fprintf(fp, "(%s", subtyp);
2086     if (w > 16 || h > 16)
2087       fprintf(fp, "\n  ");
2088     fprintf(fp, " \"");
2089     for (i = 0; i < numbytes; ++i) {
2090 	if (i > 0 && i % 32 == 0)
2091 	  fprintf(fp, "\"\n   \"");
2092 	if (i > 0 && i % 32 != 0 && i % rowbytes == 0)
2093 	  fprintf(fp, "/");
2094 	if (dolisp) {
2095 	    if (datastr == NULL || datastr[j] == '\0') {
2096 		if (!stringp(car(lispdata)))
2097 		  break;
2098 		datastr = c_string(car(lispdata));
2099 		j = 0;
2100 		lispdata = cdr(lispdata);
2101 	    }
2102 	    /* Ignore any slashes, they're for human readability. */
2103 	    if (datastr[j] == '/')
2104 	      ++j;
2105 	    byte = hextoi(datastr[j]) * 16 + hextoi(datastr[j+1]);
2106 	    j += 2;
2107 	} else {
2108 	    byte = rawdata[i];
2109 	}
2110 	fprintf(fp, "%02x", (unsigned char) byte);
2111     }
2112     fprintf(fp, "\")");
2113 }
2114 
2115 static void
write_palette_contents(FILE * fp,Obj * palette,int * rawpalette,int numcolors)2116 write_palette_contents(FILE *fp, Obj *palette, int *rawpalette, int numcolors)
2117 {
2118     int len, i, col, red, grn, blu;
2119     Obj *restpal;
2120 
2121     len = (palette != lispnil ? length(palette) : numcolors);
2122     if (len > 2)
2123       fprintf(fp, "\n  ");
2124     fprintf(fp, " (%s", keyword_name(K_PALETTE));
2125     if (palette != lispnil) {
2126 	for_all_list(palette, restpal) {
2127 	    parse_lisp_palette_entry(car(restpal), &col, &red, &grn, &blu);
2128 	    if (len > 2)
2129 	      fprintf(fp, "\n   ");
2130  	    write_color(fp, col, red, grn, blu);
2131 	}
2132     } else if (rawpalette != NULL) {
2133 	for (i = 0; i < numcolors; i++) {
2134 	    if (len > 2)
2135 	      fprintf(fp, "\n   ");
2136 	    write_color(fp, rawpalette[4*i],
2137 			rawpalette[4*i+1], rawpalette[4*i+2], rawpalette[4*i+3]);
2138 	}
2139     } else {
2140 	fprintf(fp, " #| no palette? |# ");
2141     }
2142     fprintf(fp, ")");
2143 }
2144 
2145 static void
write_color(FILE * fp,int n,int r,int g,int b)2146 write_color(FILE *fp, int n, int r, int g, int b)
2147 {
2148     char *colorname;
2149 
2150     if (n >= 0)
2151       fprintf(fp, " (%d", n);
2152     colorname = find_color_name(r, g, b);
2153     if (!empty_string(colorname)) {
2154 	/* Write color name.  Note that we write as a symbol, so that
2155 	   each instance of "white" doesn't become a separate string. */
2156 	fprintf(fp, " %s", colorname);
2157     } else {
2158 	/* Write individual color components. */
2159 	fprintf(fp, " %d %d %d", r, g, b);
2160     }
2161     if (n >= 0)
2162       fprintf(fp, ")");
2163 }
2164 
2165 /* Given rgb components, return names of standard colors if the match
2166    is close. */
2167 
2168 char *
find_color_name(int r,int g,int b)2169 find_color_name(int r, int g, int b)
2170 {
2171     if (r > WHITE_THRESHOLD
2172 	&& g > WHITE_THRESHOLD
2173 	&& b > WHITE_THRESHOLD)
2174       return "white";
2175     else if (r < BLACK_THRESHOLD
2176 	&& g < BLACK_THRESHOLD
2177 	&& b < BLACK_THRESHOLD)
2178       return "black";
2179     else if (r > WHITE_THRESHOLD
2180 	&& g < BLACK_THRESHOLD
2181 	&& b < BLACK_THRESHOLD)
2182       return "red";
2183     else if (r < BLACK_THRESHOLD
2184 	&& g > WHITE_THRESHOLD
2185 	&& b < BLACK_THRESHOLD)
2186       return "green";
2187     else if (r < BLACK_THRESHOLD
2188 	&& g < BLACK_THRESHOLD
2189 	&& b > WHITE_THRESHOLD)
2190       return "blue";
2191     else
2192       return NULL;
2193 }
2194 
2195 void
parse_lisp_palette_entry(Obj * palentry,int * col,int * red,int * grn,int * blu)2196 parse_lisp_palette_entry(Obj *palentry, int *col, int *red, int *grn, int *blu)
2197 {
2198     Obj *colorcomp;
2199     char *colorname;
2200 
2201     *col = c_number(car(palentry));
2202     colorcomp = cdr(palentry);
2203     if (colorcomp == lispnil)
2204         return;
2205     if (symbolp(car(colorcomp)) || stringp(car(colorcomp))) {
2206 	colorname = c_string(car(colorcomp));
2207 	*red = *grn = *blu = 0;
2208 	if (strcmp(colorname, "white") == 0) {
2209 	    *red = *grn = *blu = 65535;
2210 	} else if (strcmp(colorname, "black") == 0) {
2211 	    /* done */
2212 	} else if (strcmp(colorname, "red") == 0) {
2213 	    *red = 65535;
2214 	} else if (strcmp(colorname, "green") == 0) {
2215 	    *grn = 65535;
2216 	} else if (strcmp(colorname, "blue") == 0) {
2217 	    *blu = 65535;
2218 	} else {
2219 	    init_warning("No color named \"%s\" found, substituting gray",
2220 			 colorname);
2221 	    *red = *grn = *blu = 128 * 256;
2222 	}
2223     } else if (numberp(car(colorcomp))) {
2224 	*red = c_number(car(colorcomp));
2225 	*grn = c_number(cadr(colorcomp));
2226 	*blu = c_number(caddr(colorcomp));
2227 	/* Assume small values are 8-bit rather than 16-bit colors.
2228 	   (Works because as 16-bit colors, they would all be nearly
2229 	   identical shades of black.) */
2230 	if (*red < 256)
2231 	  *red *= 256;
2232 	if (*grn < 256)
2233 	  *grn *= 256;
2234 	if (*blu < 256)
2235 	  *blu *= 256;
2236     } else {
2237 	init_warning("palette color info is not a name or set of numbers, ignoring");
2238     }
2239 }
2240 
2241 /* Given a filename, find or create a file image structure for it. */
2242 
get_file_image(char * fname)2243 FileImage *get_file_image(char *fname)
2244 {
2245     FileImage *fimg, *newfimg;
2246 
2247     for (fimg = file_images; fimg != NULL; fimg = fimg->next) {
2248 	if (strcmp(fimg->name, fname) == 0)
2249 	  return fimg;
2250     }
2251     newfimg = (FileImage *) xmalloc(sizeof(FileImage));
2252     newfimg->name = fname;
2253     newfimg->next = file_images;
2254     file_images = newfimg;
2255     return newfimg;
2256 }
2257 
2258 /* Collect the file image for the given image and use it to generate
2259    the image's (or subimage's) raw data. */
2260 
2261 void
make_image_from_file_image(ImageFamily * imf,Image * img,Image * subimg,int subi)2262 make_image_from_file_image(ImageFamily *imf, Image *img, Image *subimg,
2263 			   int subi)
2264 {
2265     int hch, pad = 2, stdlayout = FALSE;
2266     int xoffset, yoffset, xoff, yoff;
2267     Obj *posdata;
2268     FileImage *fimg;
2269 
2270     if (img->filedata != lispnil) {
2271 	if (img->file_image == NULL) {
2272 	    img->file_image = get_file_image(c_string(car(img->filedata)));
2273 	}
2274     }
2275     fimg = img->file_image;
2276     load_file_image(fimg);
2277     if (!fimg->loaded) {
2278 	init_warning("Could not load file \"%s\" for image family \"%s\", ignoring",
2279 		     fimg->name, imf->name);
2280 	return;
2281     }
2282     xoffset = yoffset = 0;
2283     stdlayout = FALSE;
2284     posdata = cdr(img->filedata);
2285     if (posdata != lispnil) {
2286 	if (match_keyword(car(posdata), K_STD)) {
2287 	    stdlayout = TRUE;
2288 	    posdata = cdr(posdata);
2289 	}
2290 	xoffset = c_number(car(posdata));
2291 	yoffset = c_number(cadr(posdata));
2292 	if (stdlayout) {
2293 	    xoffset = (xoffset * (img->w + 2)) + 2;
2294 	    yoffset = (yoffset * (img->h + 2)) + 2;
2295 	}
2296     }
2297     /* All subimages share color data. */
2298     if (subimg == img ||
2299 	(img->subimages != NULL && subimg == img->subimages[0])) {
2300 	subimg->pixelsize = 8;
2301 	/* Copy the palette over verbatim from the file image. */
2302 	subimg->numcolors = fimg->numcolors;
2303 	subimg->rawpalette =
2304 	  (int *) xmalloc(257 /*subimg->numcolors*/ * 4 * sizeof(int));
2305 	memcpy(subimg->rawpalette, fimg->palette,
2306 	       subimg->numcolors * 4 * sizeof(int));
2307     } else {
2308 	/* Inherit color data from the first subimage. */
2309 	subimg->pixelsize = img->subimages[0]->pixelsize;
2310 	subimg->numcolors = img->subimages[0]->numcolors;
2311 	subimg->rawpalette = img->subimages[0]->rawpalette;
2312     }
2313     if (img->isborder) {
2314 	hch = calculate_hch(img->h);
2315 	xoff = xoffset + (subi % 4) * img->w;
2316 	yoff = yoffset + (subi / 4) * hch;
2317 	copy_from_file_image(subimg, fimg, xoff, yoff, 0, hch);
2318     } else if (img->isconnection) {
2319 	xoff = xoffset + (subi % 8) * (img->w + pad);
2320 	yoff = yoffset + (subi / 8) * (img->h + pad);
2321 	copy_from_file_image(subimg, fimg, xoff, yoff, 0, 0);
2322     } else if (img->istransition) {
2323 	xoff = xoffset + (subi % 4) * (img->w + pad);
2324 	yoff = yoffset + (subi / 4) * (img->h + pad);
2325 	copy_from_file_image(subimg, fimg, xoff, yoff, 0, 0);
2326     } else if (img->numsubimages > 0) {
2327 	/* Figure where the next subimage is at. */
2328         if (img->hexgridx > 0 && img->hexgridy > 0) {
2329 	    xoff = xoffset + (subi%img->hexgridx) * img->w;
2330 	    if ((subi/img->hexgridx)%2 != 0)
2331 	        xoff += (img->w/2);
2332 	    yoff = yoffset + (subi/img->hexgridx) * ((img->h*3)/4 + 1);
2333 	} else if (img->subx != 0 || img->suby != 0) {
2334 	    xoff = xoffset + subi * img->subx;
2335 	    yoff = yoffset + subi * img->suby;
2336 	} else {
2337 	    xoff = xoffset + subi * img->w;
2338 	    yoff = yoffset;
2339 	}
2340 	copy_from_file_image(subimg, fimg, xoff, yoff, 0, 0);
2341     } else {
2342 	copy_from_file_image(img, fimg, xoffset, yoffset, 0, 0);
2343     }
2344 
2345     /* If this is any sort of terrain, apply a hex mask, and blow away
2346        the LISP version of the mask if it no longer matches */
2347     if (img->isterrain || img->isconnection ||
2348 	img->istransition) {
2349         add_hex_mask(subimg);
2350         if (subimg->maskdata != lispnil && !bitmaps_match(subimg->w, subimg->h,
2351 	    subimg->maskdata, subimg->rawmaskdata))
2352 	    subimg->maskdata = lispnil;
2353     }
2354 }
2355 
2356 /* Extract a single color image from a file image.  Also create mask
2357    data for the image, if the file image has any transparent colors.  */
2358 
2359 void
copy_from_file_image(Image * img,FileImage * fimg,int xoffset,int yoffset,int actualw,int actualh)2360 copy_from_file_image(Image *img, FileImage *fimg, int xoffset, int yoffset,
2361 		     int actualw, int actualh)
2362 {
2363     char pix;
2364     int i, j, k, ii, val, kk, kkb;
2365 
2366     /* Make space for the color data (assuming 1 byte/pixel). */
2367     img->rawcolrdata = (char *) xmalloc(img->w * img->h);
2368     if (fimg->numtransparent > 0)
2369       img->rawmaskdata =
2370 	(char *) xmalloc(img->h * computed_rowbytes(img->w, 1));
2371     /* Scan through all the pixels of the subimage we're building. */
2372     for (i = 0; i < img->h; ++i) {
2373 	for (j = 0; j < img->w; ++j) {
2374 	    k = (yoffset + i) * fimg->width + xoffset + j;
2375 	    pix = fimg->data[k];
2376 	    kk = i * img->w + j;
2377 	    img->rawcolrdata[kk] = pix;
2378 	    if ((actualw > 0 && j >= actualw)
2379 		|| (actualh > 0 && i >= actualh))
2380 	      img->rawcolrdata[kk] = img->rawcolrdata[0];
2381 	    /* If there are transparent colors in the image, modify
2382 	       the mask bitmap. */
2383 	    if (fimg->numtransparent > 0) {
2384 		val = 1;
2385 		for (ii = 0; ii < fimg->numtransparent; ++ii) {
2386 		    if (pix == fimg->transparent[ii]) {
2387 			val = 0;
2388 			break;
2389 		    }
2390 		}
2391 		if (val) {
2392 		    kkb = i * computed_rowbytes(img->w, 1) + j / 8;
2393 		    img->rawmaskdata[kkb] |= 1 << (7 - j % 8);
2394 		    if ((actualw > 0 && j >= actualw)
2395 			|| (actualh > 0 && i >= actualh))
2396 		      img->rawmaskdata[kkb] = 0;
2397 		}
2398 	    }
2399 	}
2400     }
2401 }
2402 
2403 /* Give a file image, attempt to load it into memory. */
2404 
2405 void
load_file_image(FileImage * fimg)2406 load_file_image(FileImage *fimg)
2407 {
2408     int rslt;
2409 
2410     if (fimg->loaded)
2411       return;
2412     /* Only doing GIFs right now. */
2413     rslt = get_gif(fimg);
2414     if (rslt)
2415       fimg->loaded = TRUE;
2416 }
2417 
2418 /* Generic image setup. */
2419 
2420 static short imf_dir_loaded;
2421 
2422 ImageFamily *
get_generic_images(char * name)2423 get_generic_images(char *name)
2424 {
2425     FILE *fp;
2426     ImageFamily *imf;
2427     LibraryPath *path;
2428 
2429     imf = get_imf(name);
2430     if (imf == NULL)
2431       return NULL;
2432     if (imf->numsizes > 0 && imf_interp_hook != NULL)
2433       imf = (*imf_interp_hook)(imf, NULL, FALSE);
2434     if (imf_load_hook != NULL)
2435       imf = (*imf_load_hook)(imf);
2436     /* Always check that the imf location is loaded
2437 	(fixes emblem loading from saved games on the mac). */
2438     if (imf->numsizes == 0
2439 	|| (imf->location && imf->location->loaded != TRUE)) {
2440 	/* Maybe collect the names/locations of all image families. */
2441 	if (!imf_dir_loaded) {
2442 	    /* (should let name be decided by platform?) */
2443 	    fp = open_library_file("imf.dir");
2444 	    if (fp != NULL) {
2445 		load_image_families(fp, FALSE, NULL);
2446 		fclose(fp);
2447 	    } else {
2448 		init_warning("Cannot open \"%s\", will not use it", "imf.dir");
2449 	    }
2450 	    imf_dir_loaded = TRUE;
2451 	}
2452 	/* Get a (possibly empty) family. */
2453 	imf = get_imf(name);
2454 	if (imf == NULL)
2455 	  return NULL;
2456 	if (imf->location != NULL) {
2457 	    /* Load data filling in the family. */
2458 	    for_all_library_paths(path) {
2459 		make_pathname(path->path, imf->location->name, "", spbuf);
2460 		if (load_imf_file(spbuf, NULL)) {
2461 			imf->location->loaded = TRUE;
2462 			break;
2463 		}
2464 	    }
2465 	    /* Maybe try the plain filename, just in case. */
2466 	    if (!imf->location->loaded) {
2467 	    	imf->location->loaded =
2468 		    load_imf_file(imf->location->name, NULL);
2469 	    }
2470 	    /* We don't complain here about not finding the file, because
2471 	       we'll get a more useful warning alert later on. */
2472 	    if (imf_interp_hook != NULL)
2473 	      imf = (*imf_interp_hook)(imf, NULL, FALSE);
2474 	}
2475     }
2476     return imf;
2477 }
2478