/* 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"
#define wind_dir(w) ((w) & 0x07)
#define wind_force(w) ((w) >> 3)
#include "macconq.h"

extern short any_los;

short pref_color_unit_images;

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

short pref_solid_color_terrain;

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;

/* 	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 mod, int emblem)
{
	int ex, ey, ew, eh, bx, by, bw, bh, sx2, sy2;
	int desperate = FALSE;
	int sidecolors = FALSE;
	int iconmasks = FALSE;
	char *ename;
	Rect srcrect, imagerect, fullrect;
	CIconHandle cicnhandle;
	Image *uimg;
	MacImage *macuimg;
	Map *curmap;
	List *curlist;
	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; 

	/* Find current map or list. */
	curmap = map_from_window(win);
	curlist = list_from_window(win);

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

	/* Optionally set side colors and sidecolors flag. */
	if (curmap && curmap->sidecolors
	    || curlist && curlist->sidecolors
	    || (!curmap && !curlist && default_sidecolors)) {
		sidecolors = TRUE;
		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. */
	if (curmap && curmap->iconmasks
	    || (!curmap && default_iconmasks)) {
		iconmasks = TRUE;
	}	    	
	/* Set destination rectangle. */
	SetRect(&imagerect, sx, sy, sx + sw, sy + sh);
	if (mod)
		SetRect(&fullrect, sx, sy, sx + sw, sy + sh);

	/* Plot squares if the picture is too small. */
	if (sw <= 4) {
		FillRect(&imagerect, QDPat(black));
		/* Optionally use a second color to plot the right half of the square. */
		if (sidecolors && 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));
		}
		/* Restore colors before calling gray_out_rect! */
		ForeColor(blackColor);
		BackColor(whiteColor);
		/* Gray out incomplete units. */
		if (mod)
			gray_out_rect(&fullrect);
		return;
	}

	/* Get best unit image from family */
	uimg = best_image(uimages[u], sw, sh);
	if (uimg && uimg->hook) {
		macuimg = (MacImage *) uimg->hook;

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

		/* Use pict resource if available */
		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 the MaskMap as mask if iconmasks is on. */
			if (iconmasks) {
				/* First plot the MaskMap srcBic using mask color. */
				CopyBits(&mm, &portbits, &srcrect, &imagerect, srcBic, 0);
			}
			/* Plot the PixMap if color images are preferred and sidecolors is off. */
			if (pref_color_unit_images &! sidecolors) {
				/* Use white backColor and black forecolor to avoid color distortion. */
				BackColor(whiteColor);	
				ForeColor(blackColor);
				/* 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);
				}
				/* Then plot the PixMap itself in its native (non-side) color. */
				CopyBits((BitMap*) &pm, &portbits, &srcrect, &imagerect, srcOr, 0);
			/* Plot the BitMap in all other cases. */
			} else {
				CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, 0);
				/* 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;
					CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, 0);
				}
			}

		/* 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);
			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]) {
				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);
			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]) {
				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 box if no pict, cicn, ICON or SICN was found. */
		} else {
			desperate = TRUE;
		}
	/* And also if the unit image does not exist at all. */
	} else {
		desperate = TRUE;
	}

	if (desperate) {
		FillRect(&imagerect, QDPat(black));
		/* Optionally use a second color to plot the right half of the square */
		if (sidecolors && 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));
		}
	}

	/* Restore colors before proceeding. */
	BackColor(whiteColor);							
	ForeColor(blackColor);							
	/* Gray out units under construction. */
	if (mod) {
		gray_out_rect(&fullrect);
	}
	/* Now draw a side emblem if asked for. */
	if (between(0, e, numsides) && emblem 
	    && (curmap && curmap->draw_emblems) || (curlist && curlist->draw_emblems)) {
		ename = (side_n(e) ? side_n(e)->emblemname : NULL);
		if (emblem_position(uimg, ename, eimages[e], sw, sh, &ex, &ey, &ew, &eh)) {
			/* Do the drawing proper. */
			draw_side_emblem(win, sx + ex, sy + ey, ew, eh, e, plain_emblem);
		}
	}
}

/* Draw a given side id's emblem. Uses the current GrafPort.  No iconmasks or sidecolors,
   since emblems are vary 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 (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;
		}
	}
	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) {
					RGBColor tmpcolor;
					tmpcolor.red = tmpcolor.green = tmpcolor.blue = 49000;
					RGBForeColor(&tmpcolor);
					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));
				}
			}

			/* 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) {
				/* Always use the PixMap if has Color QD */
				CopyBits((BitMap*) &pm, &portbits, &srcrect, &imagerect, srcOr, nil);
			} else {
				/* Use the BitMap only for B/W plotting */
				CopyBits(&bm, &portbits, &srcrect, &imagerect, srcOr, nil);
			}
		} 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 */

				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);
			} 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]);
}

/* 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 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, 4, t, 0, 90, FALSE, dosolid, 0);
			break;
		case bordersubtype:
			draw_border_line_multiple(win, tmprect.left, tmprect.top, 63, 4, t, 90, 0, dosolid);
			break;
		case connectionsubtype:
			draw_connection_line_multiple(win, tmprect.left, tmprect.top, 63, 4, t, 90, 0, dosolid);
			break;
		case coatingsubtype:
			draw_hex_region(tmprect.left, tmprect.top, 4, 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));
	}
}

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);
	}
}

/* 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 + 1, 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) {
		switch (sh) {
			case 8:
				TextSize(9);
				TextFace(normal);
				break;
			case 16:
				TextSize(10);
				TextFace(normal);
				break;
			case 32:
				TextSize(14);
				TextFace(bold);
				break;
			case 64:
				TextSize(18);
				TextFace(bold);
				break;
			case 128:
				TextSize(24);
				TextFace(bold);
				break;
			case 256:
				TextSize(36);
				TextFace(bold);
				break;
			default:
				TextSize(9);
				TextFace(normal);
				break;
		}

	} 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 >= 16) {
		/* 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);
	}
}

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);
    }
}

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();
}
