/* Low-level drawing for the Mac interface to Xconq.
   Copyright (C) 1992-1999 Stanley T. Shebs.

Xconq is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.  See the file COPYING.  */

/* This file is the low-level code that renders images of things into windows/offscreen
   buffers.  At this level, routines do not know about maps, lists, or other interface
   components - they just get a window and a position and make something appear there. */

/* Routines in this file should rarely, if ever, call run_warning,
   since the exposure following the handling of the warning dialog
   can cause the same warning to appear again, and the player can
   get pretty wedged. */

#include "conq.h"
#include "macconq.h"

#define wind_dir(w) ((w) & 0x07)
#define wind_force(w) ((w) >> 3)

#define cell_style(map, x, y, power)  \
  ((map->see_all || terrain_visible(dside, x, y) || unseen_image != NULL || !in_area(x, y))  \
   ? (power >= 3 ? usepolygons : useblocks)  \
   : dontdraw);

extern short any_los;

short pref_color_unit_images = TRUE;

/* When true, this causes terrain to be drawn with solid colors if possible;
   otherwise, color patterns will be preferred.  */

short pref_solid_color_terrain = FALSE;

PolyHandle *polygons;
int *lastpolyx, *lastpolyy;

RgnHandle *cellrgns;
int *lastcellrgnx, *lastcellrgny;
RgnHandle *gridcellrgns;
int *lastgridcellrgnx, *lastgridcellrgny;

RgnHandle *cellrgns30;
int *lastcellrgnx30, *lastcellrgny30;
RgnHandle *gridcellrgns30;
int *lastgridcellrgnx30, *lastgridcellrgny30;

RgnHandle *cellrgns15;
int *lastcellrgnx15, *lastcellrgny15;
RgnHandle *gridcellrgns15;
int *lastgridcellrgnx15, *lastgridcellrgny15;

int numwindsicns = 0;

Handle windsicnhandle[5];

int numblastsicns = 0;

Handle blastsicnhandle[3];

extern Image **best_terrain_images = NULL;

static Image **best_unseen_images = NULL;

static void draw_unit_mask(BitMap mm, Rect srcrect, Rect destrect, int wid1, int wid2);
static void draw_unit_mask_layer(BitMap mm, Rect srcrect, Rect imagerect, int d, int mode);
static void draw_unit_mask_and_shadow(BitMap mm, Rect srcrect, Rect destrect, int wid1, int wid2, int wid3);
static void draw_unit_shadow(BitMap mm, Rect srcrect, Rect destrect, int wid);
static void draw_unit_shadow_layer(BitMap mm, Rect srcrect, Rect imagerect, int d, int mode);
static void calc_best_terrain_images(void);
static int mac_compute_transition(Side *side, Map *map, int x, int y, int dir,
		   int *sxp, int *syp, int *swp, int *shp, int *offsetp);

/* 	Draw an image of the given type of unit in the given rectangle, adding an emblem if requested. */

void
draw_unit_image(WindowPtr win, int sx, int sy, int sw, int sh, int u, int e, int sidecolors, int selected, int mod, int emblem)
{
	int ex, ey, ew, eh, bx, by, bw, bh;
	int iconmasks = FALSE;
	int usebox = FALSE;
	char *ename;
	Rect srcrect, imagerect;
	CIconHandle cicnhandle;
	MacImage *macuimg;
	Image *uimg;
	Map *curmap;
	BitMap portbits;			/* Target BitMap for CopyBits */
	BitMap bm, mm;			/* icon BitMap & MaskMap */
	PixMap pm;			/* icon PixMap */

	/* Filter out very small images. */
	if (sw <= 1)
	    return; 

	/* Default colors used in the absence of defined side colors. */
	RGBForeColor(&forecolor);
	RGBBackColor(&maskcolor);

	/* Optionally use side colors. */
	if (sidecolors) {
		if (main_icon_color[e])
			RGBForeColor(&(get_sideColor(e, main_icon_color[e])));
		if (icon_mask_color[e])
			RGBBackColor(&(get_sideColor(e, icon_mask_color[e])));
	}	    	
	/* Optionally set the iconmasks flag. */
	curmap = map_from_window(win);
	if (curmap && curmap->iconmasks
	    || (!curmap && default_iconmasks)) {
		iconmasks = TRUE;
	}
	/* Get the best unit image from family. */
	uimg = best_image(uimages[u], sw, sh); 

	/* Use unit image if it exists and unit size > 4. */
	if (sw > 4  && uimg  && uimg->hook) {
		macuimg = (MacImage *) uimg->hook;

		/* Plot incomplete units in gray. */
		if (mod) {
			RGBForeColor(&graycolor);
			BackColor(whiteColor);
		}
		/* Only change the size of the rectangle being drawn if it's
		   smaller than what was passed in. */
		if (uimg->w < sw) {
		    sx += (sw - uimg->w) / 2;  
		    sw = uimg->w;
		}
		if (uimg->h < sh) {
		    sy += (sh - uimg->h) / 2;
		    sh = uimg->h;
		}
		SetRect(&imagerect, sx, sy, sx + sw, sy + sh);
		portbits = QD(thePort)->portBits;

		/* Use pict resource if available (obsolete?). */
		if (macuimg->monopict != nil) {
			DrawPicture(macuimg->monopict, &imagerect);

		/* Use cicn if drawing in color (also in B/W if no ICON or SICN exists). */
		} else if (macuimg->colricon != nil
				   && (minscreendepth > 1
					   || (macuimg->monoicon == nil && macuimg->monosicn == nil))) {

			/* Set srcerect and get the cicnhandle. */
			SetRect(&srcrect, 0, 0, uimg->w, uimg->h);
			cicnhandle = (CIconHandle) macuimg->colricon;

			/* Get pixmap, bitmap & maskmap. */
			pm = (*(cicnhandle))->iconPMap;
			bm = (*(cicnhandle))->iconBMap;
			mm = (*(cicnhandle))->iconMask;

			/* Always use mask if iconmasks is on. */
			if (iconmasks)
			    CopyBits(&mm, &portbits, &srcrect, &imagerect, srcBic, 0);
			
			/* Plot the PixMap if preferred, and always for incomplete units. */
			if (pref_color_unit_images || mod) {
				/* Draw selection mask if asked to. */
				if (selected && curmap->selectionmasks)
				      draw_unit_mask(mm, srcrect, imagerect, 1, 0);
				/* Draw white mask under native color pixmap. */
				if (!sidecolors)
				    BackColor(whiteColor);	
				/* Optionally use the BitMap as mask here. This makes it possible to use
				a single "unified" cicn instead of the the "standard" and "color" cicns. It 
				also allows usemasks to control B/W "color" cicns, which otherwise are 
				plotted with a white mask (if available) even if usemasks is off. */
				if (unified_cicns)
					CopyBits(&bm, &portbits, &srcrect, &imagerect, srcBic, 0);
				else	CopyBits(&mm, &portbits, &srcrect, &imagerect, srcBic, 0);
				/* Use CopyMask since cicns made from gifs have their transparency
				info in the mask map. */
				CopyMask((BitMap*) &pm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
				/* Optionally use a second side color to plot the right half of the icon. */
				if (sidecolors && half_icon_color[e] && split_icon[e] &! mod) {
					RGBForeColor(&(get_sideColor(e, half_icon_color[e])));
					/* Restrict plotting to right half of image. */
					srcrect.left = srcrect.right / 2;
					imagerect.left += sw/2;
					CopyMask((BitMap*) &pm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
				}

			/* Plot the BitMap in all other cases. */
			} else {
				if (selected && curmap->selectionmasks)
				      draw_unit_mask(mm, srcrect, imagerect, 1, 0);
				/* Use CopyMask since cicns made from gifs carry their transparency
				info in the mask map. */
				CopyMask(&bm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
				/* Optionally use a second side color to plot the right half of the icon. */
				if (sidecolors && half_icon_color[e] && split_icon[e]) {
					RGBForeColor(&(get_sideColor(e, half_icon_color[e])));
					/* Restrict plotting to right half of image. */
					srcrect.left = srcrect.right / 2;
					imagerect.left += sw/2;
					CopyMask(&bm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
				}
			}

		/* Use ICON if no pict or cicn exists (or when cicn does but drawing is in B/W). */
		} else if (macuimg->monoicon != nil) {
			SetRect(&srcrect, 0, 0, 32, 32);
			bm.rowBytes = 4;
			bm.bounds = srcrect;

			/* Plot the mask ICON if iconmasks is on. */
			if (iconmasks) {
				if (macuimg->maskicon != nil) {
					bm.baseAddr = *(macuimg->maskicon);
					CopyBits(&bm, &portbits, &srcrect, &imagerect, srcBic, 0);
				} else {
					/* Use mask box if no mask ICON exists. */
					FillRect(&imagerect, QDPat(white));
				}
			}

			/* Now plot the real ICON. */ 
			bm.baseAddr = *(macuimg->monoicon);
				if (selected && curmap->selectionmasks)
				draw_unit_mask(bm, srcrect, imagerect, 1, 0);
			/* Plot incomplete units in gray. */
			if (mod) {
				RGBForeColor(&graycolor);
				BackColor(whiteColor);
			}
			CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, 0);
			/* Optionally use a second color to plot the right half of the ICON. */
			if (sidecolors && half_icon_color[e] && split_icon[e] &! mod) {
				RGBForeColor(&(get_sideColor(e, half_icon_color[e])));
				/* Restrict plotting to right half of image. */
				srcrect.left = srcrect.right/2;
				imagerect.left += sw/2;
				CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, 0);
			}

		/* Use SICN if no pict, cicn or ICON exist. */
		} else if (macuimg->monosicn != nil) {
			SetRect(&srcrect, 0, 0, 16, 16);
			bm.rowBytes = 2;
			bm.bounds = srcrect;

			/* Plot the mask SICN if iconmasks is on and plotting is to map. */
			if (iconmasks) {
				if (macuimg->masksicn != nil) {
					bm.baseAddr = *(macuimg->masksicn);
					CopyBits(&bm, &portbits, &srcrect, &imagerect, srcBic, 0);
				/* Use mask box if no mask SICN exists. */
				} else {
					FillRect(&imagerect, QDPat(white));
				}
			}
			/* Now plot the real SICN. */
			bm.baseAddr = *(macuimg->monosicn);
			if (selected && curmap->selectionmasks)
				draw_unit_mask(bm, srcrect, imagerect, 1, 0);
			/* Plot incomplete units in gray. */
			if (mod) {
				RGBForeColor(&graycolor);
				BackColor(whiteColor);
			}
			CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, 0);
			/* Optionally use a second color to plot the right half of the SICN. */
			if (sidecolors && half_icon_color[e] && split_icon[e] &! mod) {
				RGBForeColor(&(get_sideColor(e, half_icon_color[e])));
				/* Restrict plotting to right half of image. */
				srcrect.left = srcrect.right / 2;
				imagerect.left += sw / 2;
				CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, 0);
			}

		/* Use a default box if no pict, cicn, ICON or SICN was found. */
		} else usebox = TRUE;
	/* and also for very small images or if the image does not exist. */
	} else usebox = TRUE;

	if (usebox) {
		int done = FALSE;

		SetRect(&imagerect, sx, sy, sx + sw, sy + sh);
		/* Use the default emblem color if it is available and we are not
		using side colors. */
		if (between(0, e, numsides) 
		    && sidecolors != TRUE) {
			if (eimages[e]) {
				Image *eimg = best_image(eimages[e], 1, 1);
				MacImage *maceimg;
						
				if (eimg && eimg->hook) {
					maceimg = (MacImage *) eimg->hook;
					if (maceimg->colrpat != nil) {
						/* Make a black shadow. */
						ForeColor(blackColor);
						FillRect(&imagerect, QDPat(black));
						imagerect.bottom -= 1;
						imagerect.right -= 1;
		 			    	FillCRect(&imagerect, maceimg->colrpat);
						done = TRUE;
					}
				}
			}
		}
		/* Always use sidecolors as a fallback even if sidecolors are off
		for this map. */
		if (!done) {
			/* Make a black shadow. */
			ForeColor(blackColor);
			FillRect(&imagerect, QDPat(black));
			imagerect.bottom -= 1;
			imagerect.right -= 1;
			if (main_icon_color[e])
			    RGBForeColor(&(get_sideColor(e, main_icon_color[e])));
			FillRect(&imagerect, QDPat(black));
			/* Optionally use a second color to plot the right half of the square. */
			if (half_icon_color[e] && split_icon[e]) {
				RGBForeColor(&(get_sideColor(e, half_icon_color[e])));
				/* Restrict plotting to right half of image. */
				imagerect.left += sw/2;
				FillRect(&imagerect, QDPat(black));
			}
		}
		/* Gray out units under construction. */
		if (mod) {
			SetRect(&imagerect, sx, sy, sx + sw, sy + sh);
			gray_out_rect(&imagerect);
		}
		/* Draw selection masks if asked to. */
		if (selected && curmap->selectionmasks) {
			SetRect(&imagerect, sx, sy, sx + sw, sy + sh);
			InsetRect(&imagerect, -1, -1);
			PenPat(QDPat(white));
			FrameRect(&imagerect);
			InsetRect(&imagerect, -1, -1);
			PenPat(QDPat(black));
			FrameRect(&imagerect);
		}
	}
	/* Restore colors before proceeding. */
	BackColor(whiteColor);							
	ForeColor(blackColor);							
	/* Now draw a side emblem if asked for. */
	if (between(0, e, numsides) && emblem && sw > 4 ) {
		ename = (side_n(e) ? side_n(e)->emblemname : NULL);
		if (emblem_position(uimg, ename, eimages[e], sw, sh, &ex, &ey, &ew, &eh)) {
			/* Make sure emblem stays within the cell. */
			if (curmap && uimg->h > curmap->vp->uh)
				sy += (curmap->vp->hh - curmap->vp->uh) / 2;
			/* Do the drawing proper. */
			draw_side_emblem(win, sx + ex, sy + ey, ew, eh, e, plain_emblem);
		}
	}
}

void
draw_unit_mask(BitMap mm, Rect srcrect, Rect imagerect, int wid1, int wid2)
{
	RGBColor oldfore;
	RGBColor oldback;
	int i;
	
	/* Save current colors. */
	GetForeColor(&oldfore);
	GetBackColor(&oldback);

	/* First draw the outer layer using the fore color. */ 
	for (i = wid1 + 1; i <= wid1 + wid2; i++) {
		draw_unit_mask_layer(mm, srcrect, imagerect, i, srcOr);
	}
	/* Then draw the inner layer using the mask color. */
	for (i = 1; i <= wid1; i++) {
		draw_unit_mask_layer(mm, srcrect, imagerect, i, srcBic);
	}
	/* Restore current colors. */
	RGBForeColor(&oldfore);
	RGBBackColor(&oldback);
}

void
draw_unit_mask_layer(BitMap mm, Rect srcrect, Rect imagerect, int d, int mode)
{
	BitMap portbits = QD(thePort)->portBits;

	OffsetRect(&imagerect,   d, d);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* NE */
	OffsetRect(&imagerect, -d, 0);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* E */
	OffsetRect(&imagerect, -d, 0);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* SE */
	OffsetRect(&imagerect, 0, -d);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* S	*/
	OffsetRect(&imagerect, 0, -d);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* SW */
	OffsetRect(&imagerect,   d, 0);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* W */
	OffsetRect(&imagerect,   d, 0);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* NW */
	OffsetRect(&imagerect,  0, d);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* N */
	OffsetRect(&imagerect, -d, 0);
}

void
draw_unit_mask_and_shadow(BitMap mm, Rect srcrect, Rect imagerect, int wid1, int wid2, int wid3)
{
	RGBColor oldfore;
	RGBColor oldback;
	int i;
	
	GetForeColor(&oldfore);
	GetBackColor(&oldback);

	/* First draw the shadow layer using dkgraycolor. */ 
	RGBForeColor(&dkgraycolor);
	for (i = wid1 + wid2 + 1; i <= wid1 + wid2 + wid3; i++) {
		draw_unit_shadow_layer(mm, srcrect, imagerect, i, srcOr);
	}
	/* First draw the outer layer using the fore color. */ 
	ForeColor(blackColor);
	for (i = wid1 + 1; i <= wid1 + wid2; i++) {
		draw_unit_mask_layer(mm, srcrect, imagerect, i, srcOr);
	}
	/* Then draw the inner layer using the mask color. */
	BackColor(whiteColor);
	for (i = 1; i <= wid1; i++) {
		draw_unit_mask_layer(mm, srcrect, imagerect, i, srcBic);
	}
	RGBForeColor(&oldfore);
	RGBBackColor(&oldback);
}

void
draw_unit_shadow(BitMap mm, Rect srcrect, Rect imagerect, int wid)
{
	BitMap portbits = QD(thePort)->portBits;
	RGBColor oldfore;
	int i;
	
	GetForeColor(&oldfore);

	/* Draw the shadow layer using dkgraycolor. */ 
	RGBForeColor(&dkgraycolor);
	for (i = 1; i <= wid; i++) {
		OffsetRect(&imagerect,  i,   i);
		CopyBits(&mm, &portbits, &srcrect, &imagerect, srcOr, 0);		/* SE */
		OffsetRect(&imagerect,  -i,   -i);
	}
	RGBForeColor(&oldfore);
}

void
draw_unit_shadow_layer(BitMap mm, Rect srcrect, Rect imagerect, int d, int mode)
{
	BitMap portbits = QD(thePort)->portBits;

	OffsetRect(&imagerect,  0,   d);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* E */
	OffsetRect(&imagerect,  d,   0);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* SE */
	OffsetRect(&imagerect,  0, -d);
	CopyBits(&mm, &portbits, &srcrect, &imagerect, mode, 0);		/* S	*/
	OffsetRect(&imagerect, -d,  0);
}

/* Draw a given side id's emblem. Uses the current GrafPort.  No iconmasks or sidecolors,
   since emblems are very rarely colorizable silhouettes. */

void
draw_side_emblem(WindowPtr win, int ex, int ey, int ew, int eh, int e, int style)
{
	int ex2, ey2;
	Rect srcrect, imagerect, shadowrect;
	CIconHandle cicnhandle;
	Image *eimg;
	MacImage *maceimg;
	BitMap portbits;			/* Target BitMap for CopyBits */
	BitMap bm, mm;				/* icon BitMap & MaskMap */
	PixMap pm;					/* icon PixMap */

	/* Filter out very small images. */
	if (ew <= 4)
	  return;

	/* Get best emblem image from family. */
	eimg = best_image(eimages[e], ew, eh);

#if 0		/* This code forces default color emblems to be 1 x 1 pixels in size. */

	if (eimg->w < ew || eimg->h < eh) {
		ex2 = ex + (ew - eimg->w) / 2;  ey2 = ey + (eh - eimg->h) / 2;
		/* Only change the size of the rectangle being drawn if it's
		   smaller than what was passed in. */
		if (eimg->w < ew) {
		    ex = ex2;
		    ew = eimg->w;
		}
		if (eimg->h < eh) {
		    ey = ey2;
		    eh = eimg->h;
		}
	}
	
#endif

	SetRect(&imagerect, ex, ey, ex + ew, ey + eh);

	/* If an image is available, display it, otherwise do nothing. */
	if (eimg && eimg->hook) {
		maceimg = (MacImage *) eimg->hook;

		portbits = QD(thePort)->portBits;

		/* Use pict resource if available */
		/* Note: no offscreen support yet for picts! */
		if (maceimg->monopict != nil) {
			DrawPicture(maceimg->monopict, &imagerect);

		/* Use color icon (cicn) if drawing in color (also in B/W if no ICON or SICN exists) */
		} else if (maceimg->colricon != nil
				   && (minscreendepth > 1
				   || (maceimg->monoicon == nil && maceimg->monosicn == nil))) {

			SetRect(&srcrect, 0, 0, ew, eh);
			cicnhandle = (CIconHandle) maceimg->colricon;
		
			if (style == shadow_emblem) {
				shadowrect = imagerect;
				OffsetRect(&shadowrect, (ew < 16 ? 1 : 2), (ew < 16 ? 1 : 2));
				bm.rowBytes = (*cicnhandle)->iconBMap.rowBytes;
				bm.bounds = srcrect;
				if (bm.rowBytes > 0) {
					bm.baseAddr = (char *) (*cicnhandle)->iconMaskData;
				}
				if (hasColorQD) {
					RGBForeColor(&ltgraycolor);
					if (bm.rowBytes > 0) {
						 CopyBits(&bm, &portbits, &srcrect, &shadowrect, srcCopy, nil);
					} else {
						PaintRect(&shadowrect);
					}
					/* Restore the previous color. */
					RGBForeColor(&blackcolor);
				} else {
					FillRect(&shadowrect, QDPat(gray));
				}
			}

			/* PlotCIcon seems to have logic for the 1-bit
			   case that our CopyBits does not, so use it in
			   this special case only. */
			if (eimg->pixelsize == 1) {
				PlotCIcon(&imagerect, cicnhandle);
				return;
			}
			/* Get pixmap, bitmap & maskmap from cicn and set srcrect */
			pm = (*(cicnhandle))->iconPMap;
			bm = (*(cicnhandle))->iconBMap;
			mm = (*(cicnhandle))->iconMask;

			/* Always use emblem masks (whether or not iconmasks etc is on) */
			CopyBits(&mm, &portbits, &srcrect, &imagerect, srcBic, nil);

			if (hasColorQD) {
				/* Use CopyMask since cicns made from gifs have their transparency
				info in the mask map. */
				CopyMask((BitMap*) &pm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
			} else {
				CopyMask(&bm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
			}
		/* This handles default emblems generated from side colorschemes. */
		} else if (maceimg->colrpat != nil) {
			imagerect.bottom = min(imagerect.top + 12, imagerect.bottom);
			if (style == shadow_emblem) {
				shadowrect = imagerect;
				OffsetRect(&shadowrect, (ew < 16 ? 1 : 2), (ew < 16 ? 1 : 2));
				RGBForeColor(&ltgraycolor);
				PaintRect(&shadowrect);
				RGBForeColor(&blackcolor);
			}
			FillCRect(&imagerect, maceimg->colrpat);
			FrameRect(&imagerect);
		} else if (maceimg->monoicon != nil) {
			/* Use ICON if no pict or cicn exists (or when cicn does but drawing
			   is in B/W) */
			SetRect(&srcrect, 0, 0, 32, 32);
			bm.rowBytes = 4;
			bm.bounds = srcrect;

			/* Always try to use the mask ICON. */
			if (maceimg->maskicon != nil) {
				bm.baseAddr = *(maceimg->maskicon);
				CopyBits(&bm, &portbits, &srcrect, &imagerect, srcBic, nil);
			} else {
				/* Use WHITE mask box if no mask ICON exists */
				FillRect(&imagerect, QDPat(white));
			}
			/* Now plot the real ICON */ 
			bm.baseAddr = *(maceimg->monoicon);
			CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, nil);

		} else if (maceimg->monosicn != nil) {
			/* Use SICN if no pict, cicn or ICON exist. */
			SetRect(&srcrect, 0, 0, 16, 16);
			bm.rowBytes = 2;
			bm.bounds = srcrect;

			/* Always try to use the mask SICN. */
			if (maceimg->masksicn != nil) {
				bm.baseAddr = *(maceimg->masksicn);
				CopyBits(&bm, &portbits, &srcrect, &imagerect, srcBic, nil);
			} else {
				/* Use WHITE mask box if no mask SICN exists. */
				FillRect(&imagerect, QDPat(white));
			}
			/* Now plot the real SICN. */
			CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, nil);

		} else {
			/* Use BLACK box if no pict, cicn, ICON or SICN was found. */
			FillRect(&imagerect, QDPat(black));
		}
	}
}

/* Compute and cache the set of terrain images we will want to use. */

void
calc_best_terrain_images()
{
	int p, t;
	Image *timg;

	best_terrain_images = (Image **) xmalloc(NUMPOWERS * numttypes * sizeof(Image *));
	for_all_terrain_types(t) {
		for (p = 0; p < NUMPOWERS; ++p) {
			timg = best_image(timages[t], hws[p], hhs[p]);
			best_terrain_images[p * numttypes + t] = timg;
		}
	}
	best_unseen_images = (Image **) xmalloc(NUMPOWERS * sizeof(Image *));
	if (unseen_image != NULL) {
		for (p = 0; p < NUMPOWERS; ++p) {
			timg = best_image(unseen_image, hws[p], hhs[p]);
			best_unseen_images[p] = timg;
		}
	}
}

/* Draw a row of cell terrain, as a single rectangle. */

void
draw_cell_block(int sx, int sy, int n, int power, int t, int over, int angle, int dosolid)
{
    int paintcolor = FALSE, tweakedcolor = FALSE;
	Rect rect;
	Image *timg;
	MacImage *mactimg;
	RGBColor cellcolor, oldcolor;

	rect.left = sx;  rect.top = sy;
	rect.right = rect.left + n * hws[power];  rect.bottom = rect.top + hcs[power];
	if (angle == 30) {
		rect.bottom = rect.top + hcs[power] / 2;
	} else if (angle == 15) {
		rect.bottom = rect.top + hcs[power] / 4;
	}
	if (best_terrain_images == NULL)
	  calc_best_terrain_images();
	mactimg = NULL;
	/* Use background color when erasing outside the map. */
	if (t == BACKTTYPE) {
		if (hasColorQD) {
			RGBForeColor(&backcolor);
			PaintRect(&rect);
			RGBForeColor(&blackcolor);
		} else {
			switch (bggray) {
				case blackgray:
					PenPat(QDPat(black));  break;
				case darkgray:
					PenPat(QDPat(dkGray));  break;
				case mediumgray:
					PenPat(QDPat(gray));  break;
				case lightgray:
					PenPat(QDPat(ltGray));  break;
				case whitegray:
					PenPat(QDPat(white));  break;
			}
			PaintRect(&rect);
			PenNormal();
		}	
		return;
	} else
	if (t == NONTTYPE)
	  timg = best_unseen_images[power];
	else {
		timg = best_terrain_images[power * numttypes + t];
		if (hasColorQD
			&& (dosolid || timg == NULL || timg->hook == NULL)
			&& tcolors[t] != NULL
			&& minscreendepth > 1) {
			mactimg = tcolors[t];
		}
	}
	if (timg && timg->hook && mactimg == NULL)
	  mactimg = (MacImage *) timg->hook;
	if (mactimg) {
		if (hasColorQD) {
			if (dosolid && minscreendepth > 1) {
				paintcolor = TRUE;
			} else if (mactimg->colrpat != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
				FillCRect(&rect, mactimg->colrpat);
			} else if (minscreendepth > 1) {
				paintcolor = TRUE;
			} else if (mactimg->patdefined) {
				FillRect(&rect, IMG_PAT(mactimg));
			}
		} else {
			FillRect(&rect, IMG_PAT(mactimg));
		}
	}
	if (hasColorQD && paintcolor) {
		if (t == NONTTYPE)
			cellcolor = unseencolor;
		else {	
			cellcolor.red   = mactimg->color.red;
			cellcolor.green = mactimg->color.green;
			cellcolor.blue  = mactimg->color.blue;
		}
		RGBForeColor(&cellcolor);
		PaintRect(&rect);
		/* Restore the previous color. */
		RGBForeColor(&blackcolor);
	}
	/* If any graying/shading was requested, do it. */
	if (over < 0) {
		if (over == -1) {
			PenPat(QDPat(ltGray));
			PenMode(patOr);
		} else if (over == -2) {
			PenPat(QDPat(gray));
/*				PenMode(patBic);  */
			PenMode(notPatOr);
		}
		PaintRect(&rect);
		PenNormal();
	}
}

/* Draw the given terrain type into a hexagonal region of the given size and position. */

void
draw_hex_region(int sx, int sy, int power, int t, int over, int angle,
				int dogrid, int dosolid, int var)
{
	int paintcolor = FALSE;
	Image *timg, *subimg;
	MacImage *mactimg;
	RGBColor hexcolor, oldcolor;
	RgnHandle rgn;

	if (best_terrain_images == NULL)
	  calc_best_terrain_images();
    if (cellrgns[power] == nil)
	  make_cell_clip(power);
	if (angle == 30) {
  		OffsetRgn(cellrgns30[power], sx - lastcellrgnx30[power], sy - lastcellrgny30[power]);
  		lastcellrgnx30[power] = sx;  lastcellrgny30[power] = sy;
  		OffsetRgn(gridcellrgns30[power], sx - lastgridcellrgnx30[power], sy - lastgridcellrgny30[power]);
  		lastgridcellrgnx30[power] = sx;  lastgridcellrgny30[power] = sy;
		rgn = (dogrid ? gridcellrgns30[power] : cellrgns30[power]);
	} else if (angle == 15) {
  		OffsetRgn(cellrgns15[power], sx - lastcellrgnx15[power], sy - lastcellrgny15[power]);
 		lastcellrgnx15[power] = sx;  lastcellrgny15[power] = sy;
  		OffsetRgn(gridcellrgns15[power], sx - lastgridcellrgnx15[power], sy - lastgridcellrgny15[power]);
  		lastgridcellrgnx15[power] = sx;  lastgridcellrgny15[power] = sy;
		rgn = (dogrid ? gridcellrgns15[power] : cellrgns15[power]);
	} else {
  		OffsetRgn(cellrgns[power], sx - lastcellrgnx[power], sy - lastcellrgny[power]);
  		lastcellrgnx[power] = sx;  lastcellrgny[power] = sy;
  		OffsetRgn(gridcellrgns[power], sx - lastgridcellrgnx[power], sy - lastgridcellrgny[power]);
 		lastgridcellrgnx[power] = sx;  lastgridcellrgny[power] = sy;
		rgn = (dogrid ? gridcellrgns[power] : cellrgns[power]);
	}
	mactimg = NULL;

	/* Use background color when erasing outside the map. */
	if (t == BACKTTYPE) {
		if (hasColorQD) {
			RGBForeColor(&backcolor);
			PaintRgn(rgn);
			RGBForeColor(&blackcolor);
		} else {
			switch (bggray) {
				case blackgray:
					PenPat(QDPat(black));  break;
				case darkgray:
					PenPat(QDPat(dkGray));  break;
				case mediumgray:
					PenPat(QDPat(gray));  break;
				case lightgray:
					PenPat(QDPat(ltGray));  break;
				case whitegray:
					PenPat(QDPat(white));  break;
			}
			PaintRgn(rgn);
			PenNormal();
		}	
		return;
	} else

	if (t == NONTTYPE)
	  timg = best_unseen_images[power];
	else {
		timg = best_terrain_images[power * numttypes + t];
		if (hasColorQD
			&& (dosolid || timg == NULL || timg->hook == NULL)
			&& tcolors[t] != NULL
			&& minscreendepth > 1) {
			mactimg = tcolors[t];
		}
	}
	subimg = timg;
	if (timg->numsubimages > 0 && timg->subimages)
	  subimg = timg->subimages[var % timg->numsubimages];
	if (subimg && subimg->hook && mactimg == NULL)
	  mactimg = (MacImage *) subimg->hook;
	if (mactimg) {
		if (hasColorQD) {
			if (dosolid && minscreendepth > 1) {
				paintcolor = TRUE;
			} else if (mactimg->colricon != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
				Rect srcrect, imagerect;
				CIconHandle cicnhandle;
				BitMap portbits;			/* Target BitMap for CopyBits */
				BitMap mm;			/* icon BitMap & MaskMap */
				PixMap pm;			/* icon PixMap */

				if (angle == 90) {
					SetRect(&srcrect, 0, 0, hws[power], hhs[power]);
				} else {
					/* Offset to middle of hex if drawing at an angle so that this flatter cell image does 
					include the pointed Northern tip. */  	
					SetRect(&srcrect, 0, hhs[power]/4, hws[power], hhs[power] + hhs[power]/4);
				}				
				SetRect(&imagerect, sx, sy, sx + hws[power], sy + hhs[power]);
				portbits = QD(thePort)->portBits;
				cicnhandle = (CIconHandle) mactimg->colricon;
				/* Get pixmap & maskmap from cicn. */
				pm = (*(cicnhandle))->iconPMap;
				mm = (*(cicnhandle))->iconMask;
				/* Draw it, using the mask as the copy mask. */
				if (angle == 90) {
					CopyMask((BitMap *) &pm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
				/* But use the cellrgn as destination mask if drawing at an angle. */
				} else {
					CopyBits((BitMap *) &pm, &portbits, &srcrect, &imagerect, srcCopy, rgn);
				}
			} else if (mactimg->colrpat != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
				FillCRgn(rgn, mactimg->colrpat);
			} else if (minscreendepth > 1) {
				paintcolor = TRUE;
			} else if (mactimg->patdefined) {
				/* Fall back on the b/w pattern. */
				FillRgn(rgn, IMG_PAT(mactimg));
			}
		} else {
			FillRgn(rgn, IMG_PAT(mactimg));
		}
	}
	if (paintcolor) {
		/* Paint a solid color region. */
		if (t == NONTTYPE)
			hexcolor = unseencolor;
		else {	
			hexcolor.red   = mactimg->color.red;
			hexcolor.green = mactimg->color.green;
			hexcolor.blue  = mactimg->color.blue;
		}
		RGBForeColor(&hexcolor);
		PaintRgn(rgn);
		/* Restore the previous color. */
		RGBForeColor(&blackcolor);
	}
	/* Maybe overlay the cell. */
	if (over < 0) {
		if (over == -1) {
			PenPat(QDPat(ltGray));
			PenMode(patOr);
		} else if (over == -2) {
			PenPat(QDPat(gray));
/*				PenMode(patBic);  */
			PenMode(notPatOr);
		}
		PaintRgn(rgn);
		PenNormal();
	}
}

/* Given a magnification power, compute the clipping regions to be used at
   that power. */

void
make_cell_clip(int power)
{
	int hw = hws[power], hh = hhs[power], delt = (hhs[power] - hcs[power]);
	PolyHandle poly;
	RgnHandle tmprgn;

	/* Make a hexagon region by drawing a polygon and then framing it while
	   a region is open. */
	poly = OpenPoly();
	MoveTo(hw / 2, 0);
	LineTo(hw, delt);
	LineTo(hw, hh - delt);
	LineTo(hw / 2, hh);
	LineTo(0, hh - delt);
	LineTo(0, delt);
	LineTo(hw / 2, 0);
	ClosePoly();
	cellrgns[power] = NewRgn();
	OpenRgn();
	FramePoly(poly);
	CloseRgn(cellrgns[power]);
	/* Make the grid-displaying version of the hexagon. */
	gridcellrgns[power] = NewRgn();
	CopyRgn(cellrgns[power], gridcellrgns[power]);
	/* Cut off a one-pixel line on the side. */
	tmprgn = NewRgn();
	SetRectRgn(tmprgn, hw - 1, 0, hw + 1, hh); 
	DiffRgn(gridcellrgns[power], tmprgn, gridcellrgns[power]);
	/* Now intersect with a region shifted upwards by one, which makes
	   the grid line along the bottom of the hex. */
	tmprgn = NewRgn();
	CopyRgn(cellrgns[power], tmprgn);
	OffsetRgn(tmprgn, 0, -1);
	SectRgn(gridcellrgns[power], tmprgn, gridcellrgns[power]);

	/* Similarly, but for cells at an angle. */
	/* (should only calc when angle view first requested) */
	/* First make a region as viewed at a 30-degree angle. */
	hh /= 2;  delt /= 2;
	poly = OpenPoly();
	MoveTo(hw / 2, 0);
	LineTo(hw, delt);
	LineTo(hw, hh - delt);
	LineTo(hw / 2, hh);
	LineTo(0, hh - delt);
	LineTo(0, delt);
	LineTo(hw / 2, 0);
	ClosePoly();
	cellrgns30[power] = NewRgn();
	OpenRgn();
	FramePoly(poly);
	CloseRgn(cellrgns30[power]);
	gridcellrgns30[power] = NewRgn();
	CopyRgn(cellrgns30[power], gridcellrgns30[power]);
	/* Cut off a one-pixel line on the side. */
	tmprgn = NewRgn();
	SetRectRgn(tmprgn, hw - 1, 0, hw + 1, hh/2); 
	DiffRgn(gridcellrgns30[power], tmprgn, gridcellrgns30[power]);
	/* Now intersect with a region shifted upwards by one, which makes
	   the grid line along the bottom of the hex. */
	tmprgn = NewRgn();
	CopyRgn(cellrgns30[power], tmprgn);
	OffsetRgn(tmprgn, 0, -1);
	SectRgn(gridcellrgns30[power], tmprgn, gridcellrgns30[power]);

	/* Now make a region as viewed at a 15-degree angle. */
	hh = hhs[power] / 4;
	delt = (hhs[power] - hcs[power]) / 4;
	poly = OpenPoly();
	MoveTo(hw / 2, 0);
	LineTo(hw, delt);
	LineTo(hw, hh - delt);
	LineTo(hw / 2, hh);
	LineTo(0, hh - delt);
	LineTo(0, delt);
	LineTo(hw / 2, 0);
	ClosePoly();
	cellrgns15[power] = NewRgn();
	OpenRgn();
	FramePoly(poly);
	CloseRgn(cellrgns15[power]);
	gridcellrgns15[power] = NewRgn();
	CopyRgn(cellrgns15[power], gridcellrgns15[power]);
	/* Cut off a one-pixel line on the side. */
	tmprgn = NewRgn();
	SetRectRgn(tmprgn, hw - 1, 0, hw + 1, hh/2); 
	DiffRgn(gridcellrgns15[power], tmprgn, gridcellrgns15[power]);
	/* Now intersect with a region shifted upwards by one, which makes
	   the grid line along the bottom of the hex. */
	tmprgn = NewRgn();
	CopyRgn(cellrgns15[power], tmprgn);
	OffsetRgn(tmprgn, 0, -1);
	SectRgn(gridcellrgns15[power], tmprgn, gridcellrgns15[power]);
}

/* Differs from the kernel version in that it takes the map as arg instead of 
its vp and calls xform instead of xform_cell. Also disables transitions at the
water edge if shorelines are enabled. */

int
mac_compute_transition(Side *side, Map *map, int x, int y, int dir,
		   int *sxp, int *syp, int *swp, int *shp, int *offsetp)
{
    int t, x1, y1, t1, x2, y2, sx, sy, sw, sh, sx2, sy2;
    int trite, tleft, overrite, overleft, offset;
    VP *vp = map->vp;
    int w = vp->hw, h = vp->hh, hch = vp->hch;

    if (!point_in_dir(x, y, dir, &x1, &y1))
      return FALSE;
    if (!(vp->show_all || terrain_visible(side, x1, y1)))
      return FALSE;
    t = terrain_at(x, y);
    t1 = terrain_at(x1, y1);
    /* We want to overlap the adjacent terrain into this cell if the
       terrain type is lower-numbered (meaning that sea usually
       overlaps land for instance), but not if there is a border,
       because the border itself provides the transition. */
    if (t1 >= t || any_borders_in_dir(x, y, dir))
      return FALSE;
    /* We don't want to do overlap if there is a beach and 
    shorelines are drawn. */
    if ((t_liquid(t) != t_liquid(t1))
        && map->shorelines)
      return FALSE;
    if (point_in_dir(x, y, right_dir(dir), &x2, &y2))
      trite = terrain_at(x2, y2);
    else
      trite = t;
    /* Overlap on the right-hand corner if the third cell's terrain is
       the same as the adjacent cell's terrain. */
    overrite = (trite == t1);
    /* Border on one side suppresses overlap. */
    if (any_borders_in_dir(x, y, right_dir(dir)))
      overrite = FALSE;
    if (point_in_dir(x, y, left_dir(dir), &x2, &y2))
      tleft = terrain_at(x2, y2);
    else
      tleft = t;
    /* Overlap on the left-hand corner if the third cell's terrain is
       the same as the adjacent cell's terrain. */
    overleft = (tleft == t1);
    /* Border on one side suppresses overlap. */
    if (any_borders_in_dir(x, y, left_dir(dir)))
      overleft = FALSE;
    xform(map, x, y, &sx, &sy);
    /* Now, given the overlaps on each side, choose the right piece of
       transition bitmap to use. */
    switch (dir) {
      case NORTHEAST:
	sx2 = sx + w / 2;  sy2 = sy;
	sw = w / 2;  sh = h - hch + 1;
	if (overrite)
	  offset = 1;
	else if (overleft)
	  offset = 2;
	break;
      case EAST:
	sx2 = sx + w / 2;  sy2 = sy + (h - hch) + 1;
	sw = w / 2;  sh = h - 2 * (h - hch) - 2;
	if (overrite)
	  offset = 2;
	else if (overleft)
	  offset = 1;
	break;
      case SOUTHEAST:
	sx2 = sx + w / 2;  sy2 = sy + hch - 1;
	sw = w / 2;  sh = h - hch + 1;
	if (overrite)
	  offset = 1;
	else if (overleft)
	  offset = 2;
	break;
      case SOUTHWEST:
	sx2 = sx;  sy2 = sy + hch - 1;
	sw = w / 2;  sh = h - hch + 1;
	if (overrite)
	  offset = 2;
	else if (overleft)
	  offset = 1;
	break;
      case WEST:
	sx2 = sx;  sy2 = sy + (h - hch) + 1;
	sw = w / 2;  sh = h - 2 * (h - hch) - 2;
	if (overrite)
	  offset = 1;
	else if (overleft)
	  offset = 2;
	break;
      case NORTHWEST:
	sx2 = sx;  sy2 = sy;
	sw = w / 2;  sh = h - hch + 1;
	if (overrite)
	  offset = 2;
	else if (overleft)
	  offset = 1;
	break;
    }
    if (overrite && overleft)
      offset = 0;
    else if (!overrite && !overleft)
      offset = 3;
    *sxp = sx2;  *syp = sy2;
    *swp = sw;  *shp = sh;
    *offsetp = offset;
    return TRUE;
}

void
draw_terrain_transitions(Map *map, int x0, int y0, int len)
{
	int 			sx2, sy2, sw, sh, offset, t1, rslt, quasirand, quasirand2;
	int 			x1, y1, x, xw, t, dir, sx, sy, segstyle;
	Image 		*timg, *subimg, *trimg, *subtrimg;
	Rect 			srcrect, maskrect, imagerect;
	MacImage 		*mactrimg, *macimg;
	BitMap 		portbits, mm;			
	CIconHandle 	cicnhandle;
	PixMap 		pm;			

	trimg = best_image(generic_transition, map->vp->hw, map->vp->hh);
	if (trimg == NULL)
	    return;
	for (x = x0; x < x0 + len + 1; ++x) {
		xw = wrapx(x);
		t = terrain_at(xw, y0);
		segstyle = cell_style(map, xw, y0, map->vp->power);
		if (x == x0 + len
		|| x == area.width
		|| segstyle == dontdraw)
		    continue;
		for_all_directions(dir) {
			rslt = mac_compute_transition(dside, map, xw, y0, dir, 
								      &sx2, &sy2, &sw, &sh, &offset);
			if (!rslt)
			    continue;
			xform(map, xw, y0, &sx, &sy);
			/* A negative quasirand can cause a null pointer crash below. */
			quasirand = abs((11 * xw + y0 + 7) * 41);
			subtrimg = trimg->subimages[(quasirand % 4) * 4 + offset];
			mactrimg = (MacImage *) subtrimg->hook;
			if (mactrimg && mactrimg->colricon != nil) {
				SetRect(&maskrect, sx2 - sx, sy2 - sy, sx2 - sx + sw, sy2 - sy + sh);
				cicnhandle = (CIconHandle) mactrimg->colricon;
				mm = (*(cicnhandle))->iconMask;
			}
			point_in_dir(xw, y0, dir, &x1, &y1);
			t1 = terrain_at(x1, y1);
			timg = best_image(timages[t1], map->vp->hw, map->vp->hh);
			subimg = timg;
			quasirand2 = 0;
			if (timg->numsubimages > 0 && timg->subimages)
			    subimg = timg->subimages[quasirand2 % timg->numsubimages];
			macimg = (MacImage *) subimg->hook;
			if (macimg && macimg->colricon != nil) {
				SetRect(&srcrect,  sx2 - sx, sy2 - sy, sx2 - sx + sw, sy2 - sy + sh);
				SetRect(&imagerect, sx2, sy2, sx2 + sw, sy2 + sh);
				cicnhandle = (CIconHandle) macimg->colricon;
				pm = (*(cicnhandle))->iconPMap;
				portbits = QD(thePort)->portBits;
				CopyMask((BitMap *) &pm, &mm, &portbits, 
								&srcrect, &maskrect, &imagerect);
			}
		}
	}
}


void
draw_shore_images(Map *map, int x, int y)
{
	int			xw, bitmask, sx, sy, x2, y2, x3, y3, subi, halfside, power;
	Rect 			srcrect, imagerect;
	Image		*timg, *subimg;
	MacImage		*mactimg;
	CIconHandle	cicnhandle;
	BitMap		portbits, mm;
	PixMap		pm;

	power = map->vp->power;
	timg = best_image(beach, hws[power], hhs[power]);
         halfside = halfsides[power];
	xw = wrapx(x);
	/* Draw the junction at the top of the x,y hex. */
	bitmask = 0;
	if (interior_point_in_dir(xw, y, NORTHEAST, &x2, &y2)
	    && interior_point_in_dir(xw, y, NORTHWEST, &x3, &y3)
	    && (t_liquid(terrain_at(x2,y2)) != t_liquid(terrain_at(x3,y3)))
	    && seen_border(dside, x2, y2, WEST))
	  bitmask |= 1;
	if (interior_point_in_dir(xw, y, NORTHEAST, &x2, &y2)
	    && (t_liquid(terrain_at(x2,y2)) != t_liquid(terrain_at(xw,y)))
	    && seen_border(dside, xw, y, NORTHEAST))
	  bitmask |= 2;
	if (interior_point_in_dir(xw, y, NORTHWEST, &x2, &y2)
	    && (t_liquid(terrain_at(x2,y2)) != t_liquid(terrain_at(xw,y)))
	    && seen_border(dside, xw, y, NORTHWEST))
	  bitmask |= 4;
	if (bitmask != 0) {
		xform(map, xw, y, &sx, &sy);
		subi = (bitmask & 3) + ((bitmask & 4) ? 12 : 4);
		if (timg->numsubimages > 0 && timg->subimages)
		    subimg = timg->subimages[subi];
		if (subimg && subimg->hook)
		  mactimg = (MacImage *) subimg->hook;
		if (mactimg->colricon != nil) {
			SetRect(&srcrect, 0, 0, hws[power], hcs[power]);
			SetRect(&imagerect, sx, 
						       sy - halfside, 
						       sx + hws[power], 
						       sy - halfside + hcs[power]);
			portbits = QD(thePort)->portBits;
			cicnhandle = (CIconHandle) mactimg->colricon;
			pm = (*(cicnhandle))->iconPMap;
			mm = (*(cicnhandle))->iconMask;
			CopyMask((BitMap *) &pm, &mm, &portbits, 
							 &srcrect, &srcrect, &imagerect);
		}
	}
	/* Draw the junction at the top left corner of the x,y hex. */
	bitmask = 0;
	if (interior_point_in_dir(xw, y, WEST, &x2, &y2)
	    && (t_liquid(terrain_at(x2,y2)) != t_liquid(terrain_at(xw,y)))
	    && seen_border(dside, xw, y, WEST))
	  bitmask |= 1;
	if (interior_point_in_dir(xw, y, NORTHWEST, &x2, &y2)
	    && (t_liquid(terrain_at(x2,y2)) != t_liquid(terrain_at(xw,y)))
	    && seen_border(dside, xw, y, NORTHWEST))
	  bitmask |= 2;
	if (interior_point_in_dir(xw, y, WEST, &x2, &y2)
	    && interior_point_in_dir(xw, y, NORTHWEST, &x3, &y3)
	    && (t_liquid(terrain_at(x2,y2)) != t_liquid(terrain_at(x3,y3)))
	    && seen_border(dside, x2, y2, NORTHEAST))
	  bitmask |= 4;
	if (bitmask != 0) {
		xform(map, xw, y, &sx, &sy);
		subi = (bitmask & 3) + ((bitmask & 4) ? 8 : 0);
		subimg = timg->subimages[subi];
		if (subimg && subimg->hook)
		    mactimg = (MacImage *) subimg->hook;
		if (mactimg->colricon != nil) {
			SetRect(&srcrect, 0, 0, hws[power], hcs[power]);
			SetRect(&imagerect, sx -hws[power]/2 , 
						       sy - halfside, 
						       sx + hws[power]/2, 
						       sy - halfside + hcs[power]);
			portbits = QD(thePort)->portBits;
			cicnhandle = (CIconHandle) mactimg->colricon;
			pm = (*(cicnhandle))->iconPMap;
			mm = (*(cicnhandle))->iconMask;
			CopyMask((BitMap *) &pm, &mm, &portbits, 
							&srcrect, &srcrect, &imagerect);
		}
	}
}

/* Ported from the tcltk interface. */

void
draw_border_images(Map *map, int x, int y, int b)
{
	int			xw, bitmask, sx, sy, x3, y3, subi, halfside, power;
	Rect 			srcrect, imagerect;
	Image		*timg, *subimg;
	MacImage		*mactimg;
	CIconHandle 	cicnhandle;
	BitMap 		portbits, mm;
	PixMap 		pm;

	power = map->vp->power;
	timg = best_image(timages[b], hws[power], hhs[power]);
         halfside = halfsides[power];
	xw = wrapx(x);
	/* Draw the junction at the top of the x,y hex. */
	bitmask = 0;
	if (point_in_dir(xw, y, NORTHEAST, &x3, &y3)
	    && border_at(x3, y3, WEST, b)
	    && seen_border(dside, x3, y3, WEST))
	  bitmask |= 1;
	if (border_at(xw, y, NORTHEAST, b)
	    && seen_border(dside, xw, y, NORTHEAST))
	  bitmask |= 2;
	if (border_at(xw, y, NORTHWEST, b)
	    && seen_border(dside, xw, y, NORTHWEST))
	  bitmask |= 4;
	if (bitmask != 0) {
		xform(map, xw, y, &sx, &sy);
		subi = (bitmask & 3) + ((bitmask & 4) ? 12 : 4);
		if (timg->numsubimages > 0 && timg->subimages)
		    subimg = timg->subimages[subi];
		if (subimg && subimg->hook)
		  mactimg = (MacImage *) subimg->hook;
		if (mactimg->colricon != nil) {
			SetRect(&srcrect, 0, 0, hws[power], hcs[power]);
			SetRect(&imagerect, sx, 
						       sy - halfside, 
						       sx + hws[power], 
						       sy - halfside + hcs[power]);
			portbits = QD(thePort)->portBits;
			cicnhandle = (CIconHandle) mactimg->colricon;
			pm = (*(cicnhandle))->iconPMap;
			mm = (*(cicnhandle))->iconMask;
			CopyMask((BitMap *) &pm, &mm, &portbits, 
							 &srcrect, &srcrect, &imagerect);
		}
	}
	/* Draw the junction at the top left corner of the x,y hex. */
	bitmask = 0;
	if (border_at(xw, y, WEST, b)
	    && seen_border(dside, xw, y, WEST))
	  bitmask |= 1;
	if (border_at(xw, y, NORTHWEST, b)
	    && seen_border(dside, xw, y, NORTHWEST))
	  bitmask |= 2;
	if (point_in_dir(xw, y, WEST, &x3, &y3)
	    && border_at(x3, y3, NORTHEAST, b)
	    && seen_border(dside, x3, y3, NORTHEAST))
	  bitmask |= 4;
	if (bitmask != 0) {
		xform(map, xw, y, &sx, &sy);
		subi = (bitmask & 3) + ((bitmask & 4) ? 8 : 0);
		subimg = timg->subimages[subi];
		if (subimg && subimg->hook)
		    mactimg = (MacImage *) subimg->hook;
		if (mactimg->colricon != nil) {
			SetRect(&srcrect, 0, 0, hws[power], hcs[power]);
			SetRect(&imagerect, sx -hws[power]/2 , 
						       sy - halfside, 
						       sx + hws[power]/2, 
						       sy - halfside + hcs[power]);
			portbits = QD(thePort)->portBits;
			cicnhandle = (CIconHandle) mactimg->colricon;
			pm = (*(cicnhandle))->iconPMap;
			mm = (*(cicnhandle))->iconMask;
			CopyMask((BitMap *) &pm, &mm, &portbits, 
							 &srcrect, &srcrect, &imagerect);
		}
	}
}

/* Draw a set of borders for the given position. */

void
draw_border_line_multiple(WindowPtr win, int sx, int sy, int bitmask, int power, int t, int angle, int over, int dosolid)
{
	int wid = bwid[power], wid2, dir, paintcolor = FALSE, tweakedcolor = FALSE;
	int sx1, sy1, sx2, sy2;
	Image *timg;
	MacImage *mactimg;
	RGBColor cellcolor, oldcolor;				

	if (wid == 0)
	  return;
	wid2 = wid / 2;
	if (0 /*power == 4*/) {
		Rect srcrect, destrect;
		BitMap *winbits;

		/* Set CopyBits destination to current port, which may differ from the current window */				
		winbits = &QD(thePort)->portBits;

		SetRect(&srcrect, 0, 0, 32, 32);
		SetRect(&destrect, sx, sy, sx+32, sy+32);
		CopyBits(&(bordbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
		return;
	}
	PenSize(wid, wid);
	/* Decide on the line color/pattern to use. */
	timg = best_image(timages[t], wid, wid);
	mactimg = NULL;
	if (hasColorQD
		&& (dosolid || timg == NULL || timg->hook == NULL)
		&& tcolors[t] != NULL
		&& minscreendepth > 1) {
		mactimg = tcolors[t];
	}
	if (timg && timg->hook && mactimg == NULL)
	  mactimg = (MacImage *) timg->hook;
	if (mactimg) {
		if (hasColorQD) {
			if (dosolid && minscreendepth > 1) {
				paintcolor = TRUE;
			} else if (mactimg->colrpat && (maxscreendepth > 1 || !mactimg->patdefined)) {
				PenPixPat(mactimg->colrpat);
			} else if (minscreendepth > 1) {
				paintcolor = TRUE;
			} else {
				PenPat(IMG_PAT(mactimg));
			}
		} else {
			PenPat(IMG_PAT(mactimg));
		}
	} else {
		if (hasColorQD && minscreendepth > 1) {
			paintcolor = TRUE;
		} else {
			PenPat(QDPat(dkGray));
		}
	}
	if (paintcolor) {
		cellcolor.red   = mactimg->color.red;
		cellcolor.green = mactimg->color.green;
		cellcolor.blue  = mactimg->color.blue;
		RGBForeColor(&cellcolor);
		tweakedcolor = TRUE;
	}
	for_all_directions(dir) {
#if 0 /* although this is a tempting optimization, it doesn't actually work;
		 individual cell updates during game get messed up, not to mention
		 designer popup. */
		if (dir == EAST || dir == SOUTHWEST || dir == SOUTHEAST)
			continue;
#endif
		if (bitmask & (1 << dir)) {
			/* Actually draw the line. */
			sx1 = bsx[power][dir];  sy1 = bsy[power][dir];
			if (angle == 30) {
				sy1 /= 2;
			} else if (angle == 15) {
				sy1 /= 4;
			}
			MoveTo(sx + sx1 - wid2, sy + sy1 - wid2);
			sx2 = bsx[power][dir+1];  sy2 = bsy[power][dir+1];
			if (angle == 30) {
				sy2 /= 2;
			} else if (angle == 15) {
				sy2 /= 4;
			}
			LineTo(sx + sx2 - wid2, sy + sy2 - wid2);
		}
	}
	/* Maybe overlay the lines. */
	if (over < 0) {
		if (over == -1) {
			PenPat(QDPat(ltGray));
			PenMode(patOr);
		} else if (over == -2) {
			PenPat(QDPat(gray));
			PenMode(notPatOr);
		}
		for_all_directions(dir) {
#if 0
			if (dir == EAST || dir == SOUTHWEST || dir == SOUTHEAST)
				continue;
#endif
			if (bitmask & (1 << dir)) {
				/* Actually draw the line. */
				sx1 = bsx[power][dir];  sy1 = bsy[power][dir];
				if (angle == 30) {
					sy1 /= 2;
				} else if (angle == 15) {
					sy1 /= 4;
				}
				MoveTo(sx + sx1 - wid2, sy + sy1 - wid2);
				sx2 = bsx[power][dir+1];  sy2 = bsy[power][dir+1];
				if (angle == 30) {
					sy2 /= 2;
				} else if (angle == 15) {
					sy2 /= 4;
				}
				LineTo(sx + sx2 - wid2, sy + sy2 - wid2);
			}
		}
	}
	PenNormal();
	if (hasColorQD && tweakedcolor) {
		/* Restore the previous color. */
		RGBForeColor(&blackcolor);
	}
}

/* Draw a set of connections for the given ttype and given cell. */

void
draw_connection_line_multiple(WindowPtr win, int sx, int sy, int bitmask, int power, int t, int angle, int over, int dosolid)
{
	int dir, wid = cwid[power], lh, ly, xoff, yoff, paintcolor = FALSE, tweakedcolor = FALSE;
	Image *timg, *subimg;
	MacImage *mactimg;
	RGBColor cellcolor, oldcolor;				

	if (wid == 0)
	  return;
	if (0 /*power == 4*/) {
		Rect srcrect, destrect;
		BitMap *winbits;

		/* Set CopyBits destination to current port, which may differ from the current window */				
		winbits = &QD(thePort)->portBits;

		SetRect(&srcrect, 0, 0, 32, 32);
		SetRect(&destrect, sx, sy, sx+32, sy+32);
		CopyBits(&(connbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
		return;
	}
	if (best_terrain_images == NULL)
	  calc_best_terrain_images();
	timg = best_terrain_images[power * numttypes + t];
	/* If we have an actual connection image with all the subimages, draw it. */
	if (timg != NULL
		&& timg->isconnection
		&& timg->subimages != NULL) {
		subimg = timg->subimages[bitmask];
		if (subimg && subimg->hook)
		  mactimg = (MacImage *) subimg->hook;
		if (mactimg
			&& hasColorQD
			&& mactimg->colricon != nil
			&& (minscreendepth > 1 || !mactimg->patdefined)) {
			Rect srcrect, imagerect;
			CIconHandle cicnhandle;
			BitMap portbits;			/* Target BitMap for CopyBits */
			BitMap mm;			/* icon BitMap & MaskMap */
			PixMap pm;			/* icon PixMap */

			SetRect(&srcrect, 0, 0, hws[power], hhs[power]);
			SetRect(&imagerect, sx, sy, sx + hws[power], sy + hhs[power]);
			portbits = QD(thePort)->portBits;
			cicnhandle = (CIconHandle) mactimg->colricon;
			/* Get pixmap & maskmap from cicn. */
			pm = (*(cicnhandle))->iconPMap;
			mm = (*(cicnhandle))->iconMask;
			/* Draw it, using the mask as the copy mask. */
			CopyMask((BitMap *) &pm, &mm, &portbits, &srcrect, &srcrect, &imagerect);
		}
		return;
	}
	/* Otherwise try drawing a connection the old way, as a patterned line. */
	timg = best_image(timages[t], wid, wid);
	PenSize(wid, wid);
	mactimg = NULL;
	if (hasColorQD
		&& (dosolid || timg == NULL || timg->hook == NULL)
		&& tcolors[t] != NULL
		&& minscreendepth > 1) {
		mactimg = tcolors[t];
	}
	if (timg && timg->hook && mactimg == NULL)
	  mactimg = (MacImage *) timg->hook;
	if (mactimg) {
		if (hasColorQD) {
			if (dosolid && minscreendepth > 1) {
				paintcolor = TRUE;
			} else if (mactimg->colrpat && (maxscreendepth > 1 || !mactimg->patdefined)) {
				PenPixPat(mactimg->colrpat);
			} else if (minscreendepth > 1) {
				paintcolor = TRUE;
			} else {
				PenPat(IMG_PAT(mactimg));
			}
		} else {
			PenPat(IMG_PAT(mactimg));
		}
	} else {
		if (hasColorQD && minscreendepth > 1) {
			paintcolor = TRUE;
		} else {
			PenPat(QDPat(dkGray));
		}
	}
	if (paintcolor) {
		cellcolor.red   = mactimg->color.red;
		cellcolor.green = mactimg->color.green;
		cellcolor.blue  = mactimg->color.blue;
		RGBForeColor(&cellcolor);
		tweakedcolor = TRUE;
	}
	lh = hhs[power];
	if (angle == 30)
	  lh /= 4;
	else if (angle == 15)
	  lh /= 8;
	else
	  lh /= 2;
	xoff = hws[power] / 2 - wid / 2;
	yoff = lh - wid / 2;
	for_all_directions(dir) {
		if (bitmask & (1 << dir)) {
			MoveTo(sx + xoff, sy + yoff);
			ly = lsy[power][dir];
			if (angle == 30)
			  ly /= 2;
			else if (angle == 15)
			  ly /= 4;
			Line(lsx[power][dir], ly);
		}
	}
	/* Maybe overlay the lines. */
	if (over < 0) {
		if (over == -1) {
			PenPat(QDPat(ltGray));
			PenMode(patOr);
		} else if (over == -2) {
			PenPat(QDPat(gray));
			PenMode(notPatOr);
		}
		for_all_directions(dir) {
			if (bitmask & (1 << dir)) {
				MoveTo(sx + xoff, sy + yoff);
				ly = lsy[power][dir];
				if (angle == 30)
				  ly /= 2;
				else if (angle == 15)
				  ly /= 4;
				Line(lsx[power][dir], ly);
			}
		}
	}
	PenNormal();
	if (hasColorQD && tweakedcolor) {
		/* Restore the previous color. */
		RGBForeColor(&blackcolor);
	}
}

/* This draws a type of terrain in a way that indicates its subtype. */

void
draw_terrain_sample(WindowPtr win, Rect tmprect, int t, int power)
{
	int dosolid = FALSE;

	/* Use the first map for hints on how to draw a terrain sample. */
	if (maplist != NULL)
	  dosolid = maplist->solid_color_terrain;

	switch (t_subtype(t)) {
		case cellsubtype:
			draw_hex_region(tmprect.left, tmprect.top, power, t, 0, 90, FALSE, dosolid, 0);
			break;
		case bordersubtype:
			draw_border_line_multiple(win, tmprect.left, tmprect.top, 63, power, t, 90, 0, dosolid);
			break;
		case connectionsubtype:
			draw_connection_line_multiple(win, tmprect.left, tmprect.top, 63, power, t, 90, 0, dosolid);
			break;
		case coatingsubtype:
			draw_hex_region(tmprect.left, tmprect.top, power, t, 0, 90, FALSE, dosolid, 0);
			/* Make it a 50% pattern. (should make more obvious somehow?) */
			gray_out_rect(&tmprect);
			break;
		default:
			terrain_subtype_warning("draw sample", t);
			break;
	}
}

/* Draw a set of country (people) borders at the given position. */

void
draw_country_borders(WindowPtr win, int sx, int sy, int bitmask, int power, int shade, int angle)
{
	int wid = bwid2[power], wid2, dir, dx1, dy1;

	if (wid == 0)
	  return;
	if (shade == 0) {
		PenPat(QDPat(black));
	} else if (shade == 1) {
		PenPat(QDPat(dkGray));
	} else if (shade == 2) {
		PenPat(QDPat(gray));
		if (wid > 1)
		  wid /= 2;
	}
	wid2 = wid / 2;
	PenSize(wid, wid);
	for_all_directions(dir) {
		if (bitmask & (1 << dir)) {
			dx1 = bsx[power][dir];  dy1 = bsy[power][dir];
			if (angle == 30)
			  dy1 /= 2;
			else if (angle == 15)
			  dy1 /= 4;
			MoveTo(sx + dx1 - wid2, sy + dy1 - wid2);
			dx1 = bsx[power][dir+1];  dy1 = bsy[power][dir+1];
			if (angle == 30)
			  dy1 /= 2;
			else if (angle == 15)
			  dy1 /= 4;
			LineTo(sx + dx1 - wid2, sy + dy1 - wid2);
		}
	}
	PenNormal();
}

void
draw_feature_borders(WindowPtr win, int sx, int sy, int bitmask, int power)
{
	int wid, wid2, dir, tweakedcolor;
	RGBColor cellcolor, oldcolor;				

	if (bwid[power] > 0) {
		wid = 2;
		wid2 = 1;
		PenSize(wid, wid);
		tweakedcolor = FALSE;
		if (hasColorQD) {
			RGBForeColor(&featurecolor);
			tweakedcolor = TRUE;
		} else {
			PenPat(QDPat(ltGray));
		}
		for_all_directions(dir) {
			if (bitmask & (1 << dir)) {
				MoveTo(sx + qx[power][dir] - 1, sy + qy[power][dir] - 1);
				LineTo(sx + qx[power][dir+1] - 1, sy + qy[power][dir+1] - 1);
			}
		}
		PenNormal();
		if (hasColorQD && tweakedcolor) {
			/* Restore the usual color. */
			RGBForeColor(&blackcolor);
		}
	}
}

/* Draw a set of theater borders at the given position. */

void
draw_ai_region_borders(WindowPtr win, int sx, int sy, int bitmask, int power)
{
	int wid, wid2, dir;
	Rect tmprect;

	if (bwid[power] > 0) {
		wid = 2;
		wid2 = 1;
		PenSize(wid, wid);
		for_all_directions(dir) {
			if (bitmask & (1 << dir)) {
				MoveTo(sx + bsx[power][dir] - wid2 + 1, sy + bsy[power][dir] - wid2 + 1);
				LineTo(sx + bsx[power][dir+1] - wid2 + 1, sy + bsy[power][dir+1] - wid2 + 1);
			}
		}
		PenMode(notPatCopy);
		for_all_directions(dir) {
			if (bitmask & (1 << dir)) {
				MoveTo(sx + bsx[power][dir] - wid2, sy + bsy[power][dir] - wid2);
				LineTo(sx + bsx[power][dir+1] - wid2, sy + bsy[power][dir+1] - wid2);
			}
		}
		PenNormal();
	} else {
		SetRect(&tmprect, sx, sy, sx + hws[power], sy + hhs[power]);
		OffsetRect(&tmprect, 1, 1);
		FillRect(&tmprect, QDPat(black));
		OffsetRect(&tmprect, -1, -1);
		FillRect(&tmprect, QDPat(white));
	}
}

#if 0
int
draw_elevation_here(int x, int y)
{
	return terrain_visible(dside, x, y);
}

/* Indicate the elevation of the given location, textually for now. */

void
draw_elevation(int sx, int sy, int power, int elev)
{
	sx += hws[power] / 2;  sy += hhs[power] / 2;
	if (elev != 0) {
		sprintf(spbuf, "%d", elev);
		RGBForeColor(&textcolor);
		draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0, 1, 0);
		ForeColor(blackColor);
	}
}
#endif

/* Indicate the temperature of the given location, textually for now. */

void
draw_temperature(int sx, int sy, int power, int temp)
{
	sx += hws[power] / 2;  sy += hhs[power] / 2;
	if (1 /* draw as text */) {
		sprintf(spbuf, "%d°", temp);  /* (should do char more portably) */
		RGBForeColor(&textcolor);
		draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0, 1, 0);
		ForeColor(blackColor);
	}
	/* (Also draw isotherms eventually) */
}

int
draw_clouds_here(int x, int y)
{
	return (dside->see_all || (terrain_view(dside, x, y) != UNSEEN));
}

void
draw_cloud_block(int sx, int sy, int n, int power, int cloudtype, int angle)
{
	Rect rect;

	/* Don't draw clear sky. */
	if (cloudtype == 0)
	  return;
	rect.left = sx;  rect.top = sy;
	rect.right = rect.left + n * hws[power];  rect.bottom = rect.top + hcs[power];
	if (angle == 30) {
		rect.bottom = rect.top + hcs[power] / 2;
	} else if (angle == 15) {
		rect.bottom = rect.top + hcs[power] / 4;
	}
	/* Should use pat# 130 patterns for this instead. */
	PenPat(cloudtype >= 3 ? QDPat(dkGray) : (cloudtype == 2 ? QDPat(gray) : QDPat(ltGray)));
	PenMode(patBic);
	PaintRect(&rect);
	PenNormal();
}

void
draw_clouds(int sx, int sy, int power, int cloudtype)
{
	Rect tmprect;

	/* Don't draw clear sky. */
	if (cloudtype == 0)
	  return;
	sx += hws[power] / 2;  sy += hhs[power] / 2;
	SetRect(&tmprect, sx - hws[power] / 2, sy - hhs[power] / 2, sx + hws[power] / 2, sy + hhs[power] / 2);
	/* Should use pat# 130 patterns for this instead. */
	PenPat(cloudtype >= 3 ? QDPat(dkGray) : (cloudtype == 2 ? QDPat(gray) : QDPat(ltGray)));
	PenMode(patBic);
	PaintOval(&tmprect);
	PenNormal();
}

/* Indicate the given wind at the given location. */

void
draw_winds(int sx, int sy, int power, int rawwind)
{
	int i, wdir = wind_dir(rawwind), wforce = wind_force(rawwind), swforce;
	GrafPtr curport;

	sx += (hws[power] - 16) / 2;  sy += (hhs[power] - 16) / 2;
	if (wforce < 0) {
		DGprintf("negative wind force %d, substituting 0", wforce);
		wforce = 0;
	}
	swforce = ((wforce - minwindforce) * 5) / (maxwindforce - minwindforce);
	if (swforce > 4)
	  swforce = 4;
	if (swforce == 0)
	  wdir = 0;
	/* Collect sicns if not already in. */
	if (numwindsicns == 0) {
		for (i = 0; i <= 4; ++i) {
			windsicnhandle[i] = GetResource('SICN', sicnWinds0 + i);
		}
		numwindsicns = 5;
	}
	GetPort(&curport);
	/* Draw an offset white version, for contrast. */
	plot_sicn(curport, sx + 1, sy + 1, windsicnhandle[swforce], wdir, FALSE, srcBic);
	plot_sicn(curport, sx, sy, windsicnhandle[swforce], wdir, FALSE, srcOr);
}

/* Draw the view coverage of a cell (for debugging). */

void
draw_coverage(int sx, int sy, int power, int cov, int altcov)
{
	char buf[40];

	buf[0] = '\0';
	if (cov > 0) {
		tprintf(buf, ":%d:", cov);
	}
	if (any_los && altcov > -1) {
		tprintf(buf, ",%d:", altcov);
	}
	if (buf[0] != '\0') {
		/* Adjust to the lower left corner of the cell. */
		sx += 2;  sy += hcs[power] - 2;
		RGBForeColor(&textcolor);
		draw_legend_text(sx, sy, hhs[power] / 2, buf, -1, 1, 0);
		ForeColor(blackColor);
	}
}

/* Draw a unit's name, if it has one. */

void
draw_unit_name(Unit *unit, int sx, int sy, int sw, int sh, int masks, int optimize)
{
	if (unit->name && sh > 5) {
		RGBForeColor(&textcolor);
		draw_legend_text(sx + sw + 2, sy + sh/2, sh, unit->name, -1, masks, optimize);
		ForeColor(blackColor);
	}
}

/* Given a location and a string, draw a map legend at that location. */

void
draw_legend_text(int sx, int sy, int sh, char *legend, int just, int masks, int optimize)
{
	int strwid, strleft;
	Rect maskrect;
	FontInfo fontinfo;

	/* Make sure small font is used. */
	TextFont(small_font_id);

	sy += 3;	/* Fix for name erasing */	

	/* Use fixed optimized fonts if asked to do so. */
	if (optimize) {
		if (sh < 16) {
				TextSize(9);
				TextFace(normal);
		} else if (sh < 32) {
				TextSize(10);
				TextFace(normal);
		} else if (sh < 64) {
				TextSize(14);
				TextFace(bold);
		} else if (sh < 128) {
				TextSize(18);
				TextFace(bold);
		} else if (sh < 256) {
				TextSize(24);
				TextFace(bold);
		} else {
				TextSize(36);
				TextFace(bold);
		}
	} else {
		/* Otherwise scale text sizes according to this formula. */
		TextSize(min(max(9, sh/2), 24));
		TextFace(normal);
	}
	strwid = TextWidth(legend, 0, strlen(legend));
	if (just < 0) {
		strleft = sx;
	} else if (just > 0) {
		strleft = sx - strwid;
	} else {
		strleft = sx - strwid / 2;
	}
	MoveTo(strleft, sy);

	if (masks) {

		if (0) {
		/* Make it readable against a noisy background. */
/*			TextFace(bold|outline); */
			TextMode(srcBic);
		} else {

			/* This makes a big white box for name, less attractive but easier to read. */
			GetFontInfo(&fontinfo);
			maskrect.top = sy - fontinfo.ascent;
			/* Ensure a one pixel strip of white all along the top. */
			maskrect.top += 1;
			maskrect.left = strleft - 1;
			maskrect.bottom = sy + fontinfo.descent;
			/* Ensure a one pixel strip of white all along the bottom, even below descenders. */
			maskrect.bottom += 1;
			maskrect.right = maskrect.left + strwid + 1;
			RGBBackColor(&maskcolor);
			FillRect(&maskrect, QDPat(white));
			BackColor(whiteColor);
		}
	}
	DrawText(legend, 0, strlen(legend));
	TextSize(small_font_size);
	TextFont(small_font_id);
	/* Ensure that the text face is restored. */
	TextFace(normal);
}

void
draw_blast_image(WindowPtr win, int sx, int sy, int sw, int sh, int blasttype)
{
	int i;
	Rect tmprect;
	Rect srcrect, imagerect;
	BitMap bm, *winbits;
	GrafPtr curport;

	/* Collect sicns if not already in. */
	if (numblastsicns == 0) {
		for (i = 0; i <= 2; ++i) {
			blastsicnhandle[i] = GetResource('SICN', sicnMiss + i);
			++numblastsicns;
		}
	}
	SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
	if (sw >= 8) {
		/* Set CopyBits destination to current port, which may differ from the current window. */				
		winbits = &QD(thePort)->portBits;
		imagerect.top = sy;  imagerect.left = sx;
		imagerect.bottom = imagerect.top + sh;  imagerect.right = imagerect.left + sw;
		/* should save image under here, then draw blast */
		GetPort(&curport);
		SetRect(&srcrect, 0, 0, 16, 16);
		bm.rowBytes = 2;
		bm.bounds = srcrect;
		bm.baseAddr = *(blastsicnhandle[blasttype]);
		if (hasColorQD) {
			RGBColor tmpcolor;

			OffsetRect(&imagerect, 1, 1);
			CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
			tmpcolor.red = 60000;  tmpcolor.green = tmpcolor.blue = 0;
			RGBForeColor(&tmpcolor);
			OffsetRect(&imagerect, -1, -1);
			CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
			/* Restore the previous color. */
			RGBForeColor(&blackcolor);
		} else {
			OffsetRect(&imagerect, 1, 1);
			CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
			OffsetRect(&imagerect, -1, -1);
			CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
		}
	} else {
		InvertRect(&tmprect);
	}
}

#if 0
void
clear_blast_image(WindowPtr win, int sx, int sy, int sw, int sh, int blasttype)
{
	Rect tmprect;

	SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
	if (sw >= 16) {
		/* should restore image under here */
	} else {
		InvertRect(&tmprect);
    }
}
#endif

int
picture_width(PicHandle pichandle)
{
	return ((*pichandle)->picFrame.right - (*pichandle)->picFrame.left);
}

int
picture_height(PicHandle pichandle)
{
	return ((*pichandle)->picFrame.bottom - (*pichandle)->picFrame.top);
}

/* Generic sicn drawer. */

void
plot_sicn(WindowPtr win, int sx, int sy, Handle sicnhandle, int n, int erase, int mode)
{
	Rect srcrect, imagerect;
	BitMap bm, *winbits;

	if (sicnhandle == nil)
	  return;
	imagerect.left = sx;  imagerect.top = sy;
	imagerect.right = imagerect.left + 16;  imagerect.bottom = imagerect.top + 16;

	/* Set CopyBits destination to current port, which may differ from the current window. */				
	winbits = &QD(thePort)->portBits;

	SetRect(&srcrect, 0, 0, 16, 16);
	bm.rowBytes = 2;
	bm.bounds = srcrect;
	if (erase)
	  EraseRect(&imagerect);
	bm.baseAddr = *(sicnhandle) + 32 * n;
	CopyBits(&bm, winbits, &srcrect, &imagerect, mode, nil);
}

/* Given a rectangle, make half of its pixels white. */

void
gray_out_rect(Rect *rectptr)
{
	PenPat(QDPat(gray));
	PenMode(patBic);
	PaintRect(rectptr);
	PenNormal();
}
