Logo Search packages:      
Sourcecode: magic version File versions  Download package

grClip.c

/* grClip.c -
 *
 *     ********************************************************************* 
 *     * Copyright (C) 1985, 1990 Regents of the University of California. * 
 *     * Permission to use, copy, modify, and distribute this              * 
 *     * software and its documentation for any purpose and without        * 
 *     * fee is hereby granted, provided that the above copyright          * 
 *     * notice appear in all copies.  The University of California        * 
 *     * makes no representations about the suitability of this            * 
 *     * software for any purpose.  It is provided "as is" without         * 
 *     * express or implied warranty.  Export of this software outside     * 
 *     * of the United States of America may require an export license.    * 
 *     *********************************************************************
 *
 * This file contains additional functions to manipulate a
 * color display.  Included here are rectangle clipping and
 * drawing routines.
 */


#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-7.5/graphics/grClip.c,v 1.4 2010/05/13 21:28:13 tim Exp $";
#endif  /* not lint */

#include <stdio.h>

#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/styles.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "graphics/graphicsInt.h"
#include "utils/malloc.h"

/* Forward declaration: */

extern bool GrDisjoint();
extern void GrClipTriangle();

/* The following rectangle defines the size of the cross drawn for
 * zero-size rectangles.  This must be all on one line to keep
 * lintpick happy!
 */

global Rect GrCrossRect = {-GR_CROSSSIZE, -GR_CROSSSIZE, GR_CROSSSIZE, GR_CROSSSIZE};
global int GrNumClipBoxes = 0;      /* for benchmarking */
global int grCurDStyle;
global unsigned char GrGridMultiple = 1;

/* A rectangle that is one square of the grid */
static Rect *grGridRect;

/*
 * ----------------------------------------------------------------------------
 * GrSetStuff --
 *
 *    Set up current drawing style.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Variables are changed.  If anything is drawn, it will appear in the
 *    specified style.
 * ----------------------------------------------------------------------------
 */

/* Current state for rectangle and text drawing */
static int grCurWMask, grCurStipple;
#ifndef MAGIC_WRAPPER
static                        /* Used in grTkCommon.c, so don't make static */
#endif
int grCurOutline, grCurFill, grCurColor;

/* Has the device driver been informed of the above?  We only inform it
 * when we actually need to draw something -- this makes it harmless (in terms
 * of graphics bandwidth) to call GrSetStuff extra times.
 */
bool grDriverInformed = TRUE;

void
GrSetStuff(style)
    int style;
{
    grCurDStyle = style;
    grCurWMask = GrStyleTable[style].mask;
    grCurColor = GrStyleTable[style].color;
    grCurOutline = GrStyleTable[style].outline;
    grCurStipple = GrStyleTable[style].stipple;
    grCurFill = GrStyleTable[style].fill;
    grDriverInformed = FALSE;
}

/*---------------------------------------------------------------------------
 * grInformDriver:
 *
 *    Inform the driver about the last GrSetStuff call.
 *
 * Results: 
 *    None.
 *
 * Side Effects:
 *    None.
 *
 *----------------------------------------------------------------------------
 */

void
grInformDriver()
{
    /* Now let the device drivers know */
    (*grSetWMandCPtr)(grCurWMask, grCurColor);
    (*grSetLineStylePtr)(grCurOutline);
    (*grSetStipplePtr)(grCurStipple);
    grDriverInformed = TRUE;
}


/*
 * ----------------------------------------------------------------------------
 * grClipAgainst --
 *
 *    Clip a linked list of rectangles against a single rectangle.  This
 *    may result in the list getting longer or shorter.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    The original list may change.
 * ----------------------------------------------------------------------------
 */

void
grClipAgainst(startllr, clip)
    LinkedRect **startllr;    /* A pointer to the pointer that heads 
                         * the list .
                         */
    Rect *clip;               /* The rectangle to clip against */
{
    extern bool grClipAddFunc();    /* forward declaration */
    LinkedRect **llr, *lr;

    for (llr = startllr; *llr != (LinkedRect *) NULL; /*nop*/ )
    {
      if ( GEO_TOUCH(&(*llr)->r_r, clip) )
      {
          lr = *llr;
          *llr = lr->r_next;
          /* this will modify the list that we are traversing! */
          (void) GrDisjoint(&lr->r_r, clip, grClipAddFunc, 
                (ClientData) &llr);
          freeMagic( (char *) lr);
      }
      else
          llr = &((*llr)->r_next);
    }
}


/* Add a box to our linked list, and advance
 * our pointer into the list
 */

bool grClipAddFunc(box, cd)  
    Rect *box;
    ClientData cd;
{
    LinkedRect ***lllr, *lr;

    lllr = (LinkedRect ***) cd;

    lr = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
    lr->r_r = *box;
    lr->r_next = **lllr;
    **lllr = lr;
    *lllr = &lr->r_next;
}


void
grObsBox(r)
    Rect *r;
{
    LinkedRect *ob;
    LinkedRect *ar;
    LinkedRect **areas;

    ar = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
    ar->r_r = *r;
    ar->r_next = NULL;
    areas = &ar;

    /* clip against obscuring areas */
    for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
    {
      if ( GEO_TOUCH(r, &(ob->r_r)) )
          grClipAgainst(areas, &(ob->r_r));
    }

    while (*areas != NULL)
    {
      LinkedRect *oldarea;
      if (grCurFill == GR_STGRID)
          (*grDrawGridPtr)(grGridRect, grCurOutline, &((*areas)->r_r));
      else
          (*grFillRectPtr)(&((*areas)->r_r));
      oldarea = *areas;
      *areas = (*areas)->r_next;
      freeMagic( (char *) oldarea );
    }
}


/*---------------------------------------------------------
 * grClipPoints:
 *    This routine computes the 0, 1, or 2 intersection points
 *    between a line and a box.
 *
 * Results:
 *    FALSE if the line is completely outside of the box.
 *
 * Side Effects:
 *---------------------------------------------------------
 */

bool
grClipPoints(line, box, p1, p1OK, p2, p2OK)
    Rect *line;         /* Actually a line from line->r_ll to
                   * line->r_ur.  It is assumed that r_ll is to
                   * the left of r_ur, but we don't assume that
                   * r_ll is below r_ur.
                   */
    Rect *box;          /* A box to check intersections with */
    Point *p1, *p2;     /* To be filled in with 0, 1, or 2 points
                   * that are on the border of the box as well as
                   * on the line.
                   */
    bool *p1OK, *p2OK;  /* Says if the point was filled in */
{
    int tmp, delx, dely;
    bool delyneg;
    int x1, x2, y1, y2;
    bool ok1, ok2;

    if (p1OK != NULL) *p1OK = FALSE;
    ok1 = FALSE;
    if (p2OK != NULL) *p2OK = FALSE;
    ok2 = FALSE;

    x1 = line->r_xbot;
    x2 = line->r_xtop;
    y1 = line->r_ybot;
    y2 = line->r_ytop;

    delx = x2-x1;
    dely = y2-y1;

    /* We have to be careful because of machine-dependent problems
     * with rounding during division by negative numbers.
     */

    if (dely<0)
    {
      dely = -dely;
      delyneg = TRUE;
    }
    else 
      delyneg = FALSE;
    /* we know that delx is nonnegative if this is a real (non-empty) line */
    if (delx < 0) return FALSE;

    if (x1 < box->r_xbot)
    {
      if (delx == 0) return FALSE;
      tmp = (((box->r_xbot-x1)*dely) + (delx>>1))/delx;
      if (delyneg) y1 -= tmp;
      else y1 += tmp;
      x1 = box->r_xbot;
    }
    else 
      if (x1 > box->r_xtop) return FALSE;

    if (x2 > box->r_xtop)
    {
      if (delx == 0) return FALSE;
      tmp = ((x2-box->r_xtop)*dely + (delx>>1))/delx;
      if (delyneg) y2 += tmp;
      else y2 -= tmp;
      x2 = box->r_xtop;
    }
    else 
      if (x2 < box->r_xbot) return FALSE;

    if (y2 > y1)
    {
      if (y1 < box->r_ybot)
      {
          x1 += (((box->r_ybot-y1)*delx) + (dely>>1))/dely;
          y1 = box->r_ybot;
      }
      else if (y1 > box->r_ytop) return FALSE;
      if (y2 > box->r_ytop)
      {
          x2 -= (((y2 - box->r_ytop)*delx) + (dely>>1))/dely;
          y2 = box->r_ytop;
      }
      else if (y2 < box->r_ybot) return FALSE;
    }
    else
    {
      if (y1 > box->r_ytop)
      {
          if (dely == 0) return FALSE;
          x1 += (((y1-box->r_ytop)*delx) + (dely>>1))/dely;
          y1 = box->r_ytop;
      }
      else if (y1 < box->r_ybot) return FALSE;
      if (y2 < box->r_ybot)
      {
          if (dely == 0) return FALSE;
          x2 -= (((box->r_ybot-y2)*delx) + (dely>>1))/dely;
          y2 = box->r_ybot;
      }
      else if (y2 > box->r_ytop) return FALSE;
    }

    if ( (x1 == box->r_xbot) || (y1 == box->r_ybot) || (y1 == box->r_ytop) )
    {
      if (p1 != NULL)
      {
          p1->p_x = x1;
          p1->p_y = y1;
      }
      if (p1OK != NULL) *p1OK = TRUE;
      ok1 = TRUE;
    }
    if ( (x2 == box->r_xtop) || (y2 == box->r_ybot) || (y2 == box->r_ytop) )
    {
      if (p2 != NULL)
      {
          p2->p_x = x2;
          p2->p_y = y2;
      }
      if (p2OK != NULL) *p2OK = TRUE;
      ok2 = TRUE;
    }
    /* is part of the line in the box? */
    return ok1 || ok2 || 
          ((x1 >= box->r_xbot) && (x1 <= box->r_xtop) && (y1 >= box->r_ybot)
          && (y1 <= box->r_ytop));
}


#define NEWAREA(lr,x1,y1,x2,y2)     {LinkedRect *tmp; \
    tmp = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect))); \
    tmp->r_r.r_xbot = x1; tmp->r_r.r_xtop = x2; \
    tmp->r_r.r_ybot = y1; tmp->r_r.r_ytop = y2; tmp->r_next = lr; lr = tmp;}

/*---------------------------------------------------------
 * GrClipLine:
 *    GrClipLine will draw a line on the screen in the current
 *    style and clip stuff.
 *
 * Results: None.
 *
 * Side Effects:
 *    The line is drawn in the current style.
 *---------------------------------------------------------
 */

void
GrClipLine(x1, y1, x2, y2)
    int x1, y1, x2, y2;
{
    LinkedRect **ar;
    LinkedRect *ob;
    LinkedRect *areas;

    GR_CHECK_LOCK();
    if (!grDriverInformed) grInformDriver();

    /* we will pretend the the ll corner of a rectangle is the
     * left endpoint of a line, and the ur corner the right endpoint
     * of the line.
     */
    areas = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
    areas->r_next = NULL;
    if (x1 < x2)
    {
      areas->r_r.r_xbot = x1;
      areas->r_r.r_ybot = y1;
      areas->r_r.r_xtop = x2;
      areas->r_r.r_ytop = y2;
    }
    else
    {
      areas->r_r.r_xtop = x1;
      areas->r_r.r_ytop = y1;
      areas->r_r.r_xbot = x2;
      areas->r_r.r_ybot = y2;
    }

    /* clip against the clip box */
    for (ar = &areas; *ar != NULL; )
    {
      Rect *l;
      Rect canonRect;
      l = &((*ar)->r_r);
      GeoCanonicalRect(l, &canonRect);
      if (!GEO_TOUCH(&canonRect, &grCurClip))
      {
          /* line is totally outside of clip area */
          goto deleteit;
      }
      else
      {
          /* is there some intersection with clip area? */
          if (!grClipPoints(l, &grCurClip, &(l->r_ll), (bool *) NULL,
                &(l->r_ur), (bool*) NULL))
          {
            /* no intersection */
            goto deleteit;
          }

          /* clip against obscuring areas */
          for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
          {
            Point p1, p2;
            Rect c;
            bool ok1, ok2;
            c = ob->r_r;
            c.r_xbot--;  c.r_ybot--;
            c.r_xtop++;  c.r_ytop++;
            if (grClipPoints(l, &c, &p1, &ok1, &p2, &ok2) &&
                  !ok1 && !ok2)
            {
                /* Line is not completely outside of the box,
                 * nor does it intersect it.
                 * Therefore, line is completely obscured.
                 */
                 goto deleteit;
            }

            if (ok1 && 
               ( ((l->r_xbot == p1.p_x) && (l->r_ybot == p1.p_y)) ||
                 ((l->r_xtop == p1.p_x) && (l->r_ytop == p1.p_y)) ) )
            {
                ok1 = FALSE;  /* do not split or clip at an endpoint */
            }
            if (ok2 && 
               ( ((l->r_xbot == p2.p_x) && (l->r_ybot == p2.p_y)) ||
                 ((l->r_xtop == p2.p_x) && (l->r_ytop == p2.p_y)) ) )
            {
                ok2 = FALSE;  /* do not split or clip at an endpoint */
            }

            if (ok1 ^ ok2)
            {
                /* one segment to deal with */
                if (ok1)
                  l->r_ur = p1;
                else
                  l->r_ll = p2;
            }
            else if (ok1 && ok2)
            {
                /* clip both sides */
                LinkedRect *new;
                new = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
                new->r_r.r_ur = l->r_ur;
                new->r_r.r_ll = p2;
                new->r_next = (*ar);
                l->r_ur = p1;
                (*ar) = new;
            }
          }

      }

      ar = &((*ar)->r_next);
      continue;

deleteit: {
          LinkedRect *reclaim;
          reclaim = (*ar);
          *ar = reclaim->r_next;
          freeMagic( (char *) reclaim);
      }

    } /* for ar */


    /* draw the lines */
    while (areas != NULL)
    {
      LinkedRect *oldarea;
      (*grDrawLinePtr)(areas->r_r.r_xbot, areas->r_r.r_ybot,
            areas->r_r.r_xtop, areas->r_r.r_ytop);
      oldarea = areas;
      areas = areas->r_next;
      freeMagic( (char *) oldarea );
    }
}

/*
 *---------------------------------------------------------
 * grAddSegment:
 *    Add a segment to a linked list of rectangles
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Allocates memory;  appends LinkedRect structure to
 *    list "segments".
 *
 * Notes:
 *    INLINE this for speedup?
 *---------------------------------------------------------
 */

void
grAddSegment(llx, lly, urx, ury, segments)
    int llx, lly, urx, ury;
    LinkedRect **segments;
{
    LinkedRect *curseg;

    curseg = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
    curseg->r_r.r_xbot = llx;
    curseg->r_r.r_ybot = lly;
    curseg->r_r.r_xtop = urx;
    curseg->r_r.r_ytop = ury;
    curseg->r_next = *segments;
    *segments = curseg;
}

/*---------------------------------------------------------
 * GrBoxOutline:
 *    For box outlines, works around the boundary of
 *    the box according to the associated tile structure,
 *    and returns a linked rect list defining all the
 *    segments which need to be drawn.
 *
 * Results:
 *    TRUE if tile is isolated (GrFastBox can be used).
 *    Otherwise, result is FALSE.
 *
 * Side Effects:
 *    May allocate memory for a linked rect structure,
 *    with pointer returned in tilesegs.  If non-NULL,
 *    the calling function needs to free memory for the
 *    linked rect structure.
 *
 * Implementation notes:
 *    Standard tech files define most bordered styles as
 *    contact types, and most if not all contacts are
 *    required to be square.  So we want the case of an
 *    isolated tile to go fast, avoiding any calls to
 *    allocate memory.  This complicates the routine but
 *    keeps the routine from slowing down the layout
 *    rendering.
 *---------------------------------------------------------
 */

bool
GrBoxOutline(tile, tilesegs)
    Tile *tile;
    LinkedRect **tilesegs;
{
    Rect rect;
    TileType ttype;
    LinkedRect *curseg;
    Tile *tpleft, *tpright, *tptop, *tpbot;
    int edgeTop, edgeBot, edgeRight, edgeLeft;
    int isolate = 0;
    bool sense;

    *tilesegs = NULL;
    TiToRect(tile, &rect);

#ifdef NONMANHATTAN
    if (IsSplit(tile) && SplitSide(tile))
      isolate |= 0x1;
    else
    {
#endif
    ttype = TiGetLeftType(tile);   /* = TiGetType when NONMANHATTAN not def'd */

    edgeBot = rect.r_ybot;
    sense = TRUE;
    for (tpleft = BL(tile); BOTTOM(tpleft) < rect.r_ytop; tpleft = RT(tpleft))
    {
      if (TiGetRightType(tpleft) != ttype)
      {
          if (!sense)
          {
            edgeBot = BOTTOM(tpleft);
            if (TOP(tpleft) >= rect.r_ytop)
                grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, rect.r_ytop,
                        tilesegs);
            sense = TRUE;
          }
      }
      else
      {
          if (sense)
          {
            edgeTop = BOTTOM(tpleft);
            if (edgeTop > edgeBot)
                grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, edgeTop,
                        tilesegs);
            isolate |= 0x1;
            sense = FALSE;
          }
      }
    }

#ifdef NONMANHATTAN
    }
    if (IsSplit(tile) && !SplitSide(tile))
      isolate |= 0x2;
    else
    {
      ttype = TiGetRightType(tile);
#endif
    edgeTop = rect.r_ytop;
    sense = TRUE;
    for (tpright = TR(tile); TOP(tpright) > rect.r_ybot; tpright = LB(tpright))
    {
      if (TiGetLeftType(tpright) != ttype)
      {
          if (!sense)
          {
            edgeTop = TOP(tpright);
            if (BOTTOM(tpright) <= rect.r_ybot)
                grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, edgeTop,
                        tilesegs);
            sense = TRUE;
          }
      }
      else
      {
          if (sense)
          {
            edgeBot = TOP(tpright);
            if (edgeBot < edgeTop)
                grAddSegment(rect.r_xtop, edgeBot, rect.r_xtop, edgeTop,
                        tilesegs);
            isolate |= 0x2;
            sense = FALSE;
          }
      }
    }

#ifdef NONMANHATTAN
    }
    if (IsSplit(tile) &&
            (SplitSide(tile) == SplitDirection(tile)))
      isolate |= 0x4;
    else
    {
      ttype = TiGetBottomType(tile);
#endif
    edgeLeft = rect.r_xbot;
    sense = TRUE;
    for (tpbot = LB(tile); LEFT(tpbot) < rect.r_xtop; tpbot = TR(tpbot))
    {
      if (TiGetTopType(tpbot) != ttype)
      {
          if (!sense)
          {
            edgeLeft = LEFT(tpbot);
            if (RIGHT(tpbot) >= rect.r_xtop)
                grAddSegment(edgeLeft, rect.r_ybot, rect.r_xtop, rect.r_ybot,
                        tilesegs);
            sense = TRUE;
          }
      }
      else
      {
          if (sense)
          {
            edgeRight = LEFT(tpbot);
            if (edgeRight > edgeLeft)
                grAddSegment(edgeLeft, rect.r_ybot, edgeRight, rect.r_ybot,
                        tilesegs);
            isolate |= 0x4;
            sense = FALSE;
          }
      }
    }

#ifdef NONMANHATTAN
    }
    if (IsSplit(tile) &&
            (SplitSide(tile) != SplitDirection(tile)))
      isolate |= 0x8;
    else
    {
      ttype = TiGetTopType(tile);
#endif
    edgeRight = rect.r_xtop;
    sense = TRUE;
    for (tptop = RT(tile); RIGHT(tptop) > rect.r_xbot; tptop = BL(tptop))
    {
      if (TiGetBottomType(tptop) != ttype)
      {
          if (!sense)
          {
            edgeRight = RIGHT(tptop);
            if (LEFT(tptop) <= rect.r_xbot)
                grAddSegment(rect.r_xbot, rect.r_ytop, edgeRight, rect.r_ytop,
                        tilesegs);
            sense = TRUE;
          }
      }
      else
      {
          if (sense)
          {
            edgeLeft = RIGHT(tptop);
            if (edgeLeft < edgeRight)
                grAddSegment(edgeLeft, rect.r_ytop, edgeRight, rect.r_ytop,
                        tilesegs);
            isolate |= 0x8;
            sense = FALSE;
          }
      }
    }
#ifdef NONMANHATTAN
    }
#endif

    if (isolate == 0)   /* Common case */
      return TRUE;
    else
    {
      /* Need to malloc segments for isolated sides */
      if (!(isolate & 0x1))   /* Left */
          grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xbot, rect.r_ytop,
                  tilesegs);
      if (!(isolate & 0x2))   /* Right */
          grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, rect.r_ytop,
                  tilesegs);
      if (!(isolate & 0x4))   /* Bottom */
          grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xtop, rect.r_ybot,
                  tilesegs);
      if (!(isolate & 0x8))   /* Top */
          grAddSegment(rect.r_xbot, rect.r_ytop, rect.r_xtop, rect.r_ytop,
                  tilesegs);
      return FALSE;
    }
}

/* Threshold for determining if outlines are too small to draw */
#define GR_THRESH 4

/*---------------------------------------------------------
 * GrBox --
 *
 *    GrBox draws a rectangle on the screen in the style
 *    set by the previous call to GrSetStuff.   It will
 *    be clipped against the rectangles passed to GrSetStuff.
 *
 *    Unlike GrFastBox (see below), GrBox makes no assumptions
 *    about how the outline will be drawn.  If there is no
 *    outline, GrFastBox is called.  The tile border is checked,
 *    and if the tile outline is simple, GrFastBox is called.
 *    Otherwise, we do a fast fill a la GrFastBox but draw the
 *    outline segment by segment.
 *
 * Results: None.
 *
 * Side Effects:
 *    The rectangle is drawn in the style specified.
 *    The rectangle may be clipped before being drawn.
 *---------------------------------------------------------
 */
void
GrBox(MagWindow *mw, Transform *trans, Tile *tile)
{
    Rect r, r2, clipr;
    bool needClip, needObscure, simpleBox;
    LinkedRect *ob, *tilesegs, *segptr;
    Point polyp[5];
    int np;

    r.r_xbot = LEFT(tile);
    r.r_ybot = BOTTOM(tile);
    r.r_xtop = RIGHT(tile);
    r.r_ytop = TOP(tile);

    GeoTransRect(trans, &r, &r2);
#ifdef NONMANHATTAN
    if (IsSplit(tile))
      WindSurfaceToScreenNoClip(mw, &r2, &r);
    else
#endif
    WindSurfaceToScreen(mw, &r2, &r);

    GR_CHECK_LOCK();
    if (!grDriverInformed) grInformDriver();
    GrNumClipBoxes++;

    if (!GEO_TOUCH(&r, &grCurClip)) return;

    /* Do a quick check to make the (very common) special case of
     * no clipping go fast.
     */
    needClip = !GEO_SURROUND(&grCurClip, &r);
    needObscure = FALSE;
    for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
      needObscure |= GEO_TOUCH(&r, &(ob->r_r));

#ifdef NONMANHATTAN
    /* Nonmanhattan tiles: */
    /* Expects one of the two tile types to be masked out before */
    /* this procedure is called.                                 */

    if (IsSplit(tile))
    {
      /* Perform matrix transformations on split tiles */
      TileType dinfo;
      Rect fullr;

      dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
      clipr = fullr = r;

      if (needClip)
          GeoClip(&clipr, &grCurClip);

      GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);

      if ((grCurFill == GR_STSOLID) || 
      (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
      {
          if (needObscure)
            grObsBox(&clipr);
          else if (grFillPolygonPtr)
            (void) (*grFillPolygonPtr)(polyp, np);
      } 
    }
    else
    {
#endif

    /* do solid areas (same as GrFastBox) */

    if ((grCurFill == GR_STSOLID) || 
      (grCurFill == GR_STSTIPPLE))
    {
      /* We have a filled area to deal with */
      clipr = r;
      if (needClip)
          GeoClip(&clipr, &grCurClip);
      if (needObscure)
          grObsBox(&clipr);
      else
          (void) (*grFillRectPtr)(&clipr);
    } 

#ifdef NONMANHATTAN
    }
#endif

    /* return if outline is too small to be worth drawing */

    if ((r.r_xtop - r.r_xbot < GR_THRESH)
            && (r.r_ytop - r.r_ybot < GR_THRESH)
            && (grCurFill != GR_STOUTLINE))
      return;

    /* do diagonal lines for contacts */

    if (grCurFill == GR_STCROSS)
    {
      Rect rnc;
      /* don't clip contact diagonals */
      if (needClip || needObscure)
      {
          WindSurfaceToScreenNoClip(mw, &r2, &rnc);
/*
          (*grDrawLinePtr)(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
          (*grDrawLinePtr)(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
*/
          if (!IsSplit(tile))
          {
            GrClipLine(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
            GrClipLine(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
          }
      }
      else
      {
          if (!IsSplit(tile))
          {
            (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
            (*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ybot);
          }
      }
    }

    /* draw outlines */

    if (grCurOutline != 0)
    {
      if (GrBoxOutline(tile, &tilesegs))
      {
          /* simple box (from GrFastBox)*/

          if (needClip || needObscure)
          {
            GrClipLine(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
            GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
            GrClipLine(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
            GrClipLine(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
          }
          else
          {
            (*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
            (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
            (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
            (*grDrawLinePtr)(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
          }
      }
      else
      {
          /* non-rectangular box; requires drawing segments */
          for (segptr = tilesegs; segptr != NULL; segptr = segptr->r_next)
          {
            GeoTransRect(trans, &segptr->r_r, &r2);
            WindSurfaceToScreen(mw, &r2, &r);

            if (needClip || needObscure)
                GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
            else
                (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);

            /* Free memory, if it was allocated for outline segments */
            freeMagic(segptr);
          }

#ifdef NONMANHATTAN
          /* For non-manhattan tiles, the manhattan parts of the  */
          /* boundary have already been drawn.  The diagonal boundary */
          /* is guaranteed to be continuous by definition, and it has   */
          /* already undergone clipping with GrClipTriangle.  So just   */
          /* draw it, now.                                  */

          if (IsSplit(tile))
          {
            int cp;
            for (cp = 0; cp < np - 1; cp++)
            {
                if ((polyp[cp].p_x != polyp[cp + 1].p_x) &&
                        (polyp[cp].p_y != polyp[cp + 1].p_y))
                {
                  (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
                        polyp[cp + 1].p_x, polyp[cp + 1].p_y);
                  break;      /* only 1 diagonal line to draw */
                }
            }
            if (cp == (np - 1))
            {
                if ((polyp[cp].p_x != polyp[0].p_x) &&
                        (polyp[cp].p_y != polyp[0].p_y))
                  (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
                        polyp[0].p_x, polyp[0].p_y);
            }
          }
#endif
      }
    }
}

/*---------------------------------------------------------
 * GrFastBox:
 *    GrFastBox will draw a rectangle on the screen in the
 *    style set by the previous call to GrSetStuff.  It will also
 *    be clipped against the rectangles passed to GrSetStuff.
 *
 *    If GrClipBox is called between GrFastBox calls then GrSetStuff
 *    must be called to set the parameters back.
 *
 * Results: None.
 *
 * Side Effects:
 *    The rectangle is drawn in the style specified.
 *    The rectangle is clipped before being drawn.
 *---------------------------------------------------------
 */

void
GrFastBox(prect)
    Rect *prect;  /* The rectangle to be drawn, given in
                   * screen coordinates.
                   */
{
    Rect *r;
    bool needClip, needObscure;
    LinkedRect *ob;

    GR_CHECK_LOCK();
    if (!grDriverInformed) grInformDriver();
    GrNumClipBoxes++;
    if (grCurFill == GR_STGRID)
    {
      r = &grCurClip;
      grGridRect = prect;
    }
    else
    {
      r = prect;
      if (!GEO_TOUCH(r, &grCurClip)) return;
    }

    /* Do a quick check to make the (very common) special case of
     * no clipping go fast.
     */
    needClip = !GEO_SURROUND(&grCurClip, r);
    needObscure = FALSE;
    for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
      needObscure |= GEO_TOUCH(r, &(ob->r_r));

    /* do solid areas */
    if ( (grCurFill == GR_STSOLID) || 
      (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
    {
      Rect clipr;
      /* We have a filled area to deal with */
      clipr = *r;
      if (needClip)
          GeoClip(&clipr, &grCurClip);
      if (needObscure)
          grObsBox(&clipr);
      else
      {
          if (grCurFill == GR_STGRID)
            (*grDrawGridPtr)(grGridRect, grCurOutline, &clipr);
          else
            (void) (*grFillRectPtr)(&clipr);
      }
    } 

    /* return if rectangle is too small to see */
    if ((r->r_xtop - r->r_xbot < GR_THRESH)
            && (r->r_ytop - r->r_ybot < GR_THRESH)
            && (grCurFill != GR_STOUTLINE))
      return;

    /* draw outlines */

    if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
    {
      if ( (grCurFill == GR_STOUTLINE) && (r->r_xbot == r->r_xtop) &&
            (r->r_ybot == r->r_ytop) )
      {

          /* turn the outline into a cross */
          if (needClip || needObscure) 
            goto clipit;
          else
          {
            bool crossClip, crossObscure;
            Rect crossBox;

            /* check the larger cross area for clipping */
            crossBox.r_xbot = r->r_xbot - GR_CROSSSIZE;
            crossBox.r_ybot = r->r_ybot - GR_CROSSSIZE;
            crossBox.r_xtop = r->r_xtop + GR_CROSSSIZE;
            crossBox.r_ytop = r->r_ytop + GR_CROSSSIZE;

            crossClip = !GEO_SURROUND(&grCurClip, &crossBox);
            crossObscure = FALSE;
            for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
                crossObscure |= GEO_TOUCH(&crossBox, &(ob->r_r));

            if (crossClip || crossObscure) 
                goto clipit;
            else
                goto noclipit;
          }

          clipit:
            GrClipLine(r->r_xbot, r->r_ybot - GR_CROSSSIZE,
                r->r_xtop, r->r_ytop + GR_CROSSSIZE);
            GrClipLine(r->r_xbot - GR_CROSSSIZE, r->r_ybot,
                r->r_xtop + GR_CROSSSIZE, r->r_ytop);
            goto endit;

          noclipit:
            (*grDrawLinePtr)(r->r_xbot, r->r_ybot - GR_CROSSSIZE,
                r->r_xtop, r->r_ytop + GR_CROSSSIZE);
            (*grDrawLinePtr)(r->r_xbot - GR_CROSSSIZE, r->r_ybot,
                r->r_xtop + GR_CROSSSIZE, r->r_ytop);

          endit:  ;
      } 
      else
      {
          if (needClip || needObscure)
          {
            GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
            GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
            GrClipLine(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
            GrClipLine(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
          }
          else
          {
            (*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
            (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
            (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
            (*grDrawLinePtr)(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
          }
      }
    }

    /* do diagonal lines for contacts */
    if (grCurFill == GR_STCROSS)
    {
      if (needClip || needObscure)
      {
          GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
          GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
      }
      else
      {
          (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
          (*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
      }
    }
}

#ifdef NONMANHATTAN

/*---------------------------------------------------------
 * GrClipTriangle:
 *    Returns an array of points representing a clipped
 *    triangle.  These are always arranged in counter-
 *    clockwise order.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Returns array of points and modifies int * np
 *    to hold the number of points in the array.
 *---------------------------------------------------------
 */

#define xround(d) (int)(((((d % height) << 1) >= height) ? 1 : 0) + (d / height))
#define yround(d) (int)(((((d % width) << 1) >= width) ? 1 : 0) + (d / width))

void
GrClipTriangle(r, c, clipped, dinfo, points, np)
    Rect *r;   /* Bounding box of triangle, in screen coords      */
    Rect *c;            /* Clipping rectangle                     */
    bool clipped; /* Boolean, if bounding box is clipped          */
    TileType dinfo;     /* Split side and direction information         */
    Point *points;      /* Point array (up to 5 points) to fill         */
    int *np;            /* Number of points in the clipped polygon      */
{
    if (!(dinfo & TT_SIDE))
    {
      points[1].p_x = r->r_xbot;
      points[0].p_y = r->r_ytop;
      points[2].p_y = r->r_ybot;
      points[0].p_x = points[2].p_x = r->r_xtop;
    }
    else
    {
      points[1].p_x = r->r_xtop;
      points[0].p_y = r->r_ybot;
      points[2].p_y = r->r_ytop;
      points[0].p_x = points[2].p_x = r->r_xbot;
    }

    if (!(dinfo & TT_DIRECTION))
    {
      points[1].p_y = points[0].p_y;
      points[2].p_x = points[1].p_x;
    }
    else
    {
      points[0].p_x = points[1].p_x;
      points[1].p_y = points[2].p_y;
    }

    *np = 3;

    /* Clip the triangle to the clipping rectangle.  Result is    */
    /* a 3- to 5-sided polygon, or empty.             */ 

    if (clipped)
    {
        dlong delx, dely;
        dlong width = (dlong)(r->r_xtop - r->r_xbot);
      dlong height = (dlong)(r->r_ytop - r->r_ybot);

      switch(dinfo & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))
      {
          case TT_DIAGONAL:   /* nw */
            if (c->r_ytop < r->r_ytop)    /* clip top */
            {
                delx = (dlong)(points[1].p_y - c->r_ytop) * width;
                points[1].p_y = c->r_ytop;
                points[0].p_y = c->r_ytop;
                points[0].p_x -= xround(delx);
            }
            if (c->r_xbot > r->r_xbot)    /* clip left */
            {
                dely = (dlong)(c->r_xbot - points[2].p_x) * height;
                points[1].p_x = c->r_xbot;
                points[2].p_x = c->r_xbot;
                points[2].p_y += yround(dely);
            }
            if (c->r_ybot > points[2].p_y)      /* clip bottom */
            {
                delx = (dlong)(c->r_ybot - points[2].p_y) * width;
                points[2].p_y = c->r_ybot;
                points[3].p_y = c->r_ybot;
                points[3].p_x = points[2].p_x + xround(delx);
                *np = 4;

                if (c->r_xtop < points[3].p_x)  /* clip right, rectangle */
                {
                  points[3].p_x = c->r_xtop;
                  points[0].p_x = c->r_xtop;
                }
                else if (c->r_xtop < points[0].p_x) /* clip right, pentagon */
                {
                  dely = (dlong)(points[0].p_x - c->r_xtop) * height;
                  points[0].p_x = c->r_xtop;
                  points[4].p_x = c->r_xtop;
                  points[4].p_y = points[0].p_y - yround(dely);
                    *np = 5;
                }
            }
            else if (c->r_xtop < points[0].p_x) /* clip right, quadrangle */
            {
                dely = (dlong)(points[0].p_x - c->r_xtop) * height;
                points[0].p_x = c->r_xtop;
                points[3].p_x = c->r_xtop;
                points[3].p_y = points[0].p_y - yround(dely);
                *np = 4;
            }
            if (points[1].p_x > points[0].p_x || points[2].p_y > points[1].p_y)
                *np = 0;      /* clipped out of existance */
            break;

          case TT_DIAGONAL | TT_DIRECTION:      /* sw */
            if (c->r_xbot > r->r_xbot)    /* clip LEFT */
            {
                dely = (dlong)(c->r_xbot - points[1].p_x) * height;
                points[1].p_x = c->r_xbot;
                points[0].p_x = c->r_xbot;
                points[0].p_y -= yround(dely);
            }
            if (c->r_ybot > r->r_ybot)    /* clip BOTTOM */
            {
                delx = (dlong)(c->r_ybot - points[2].p_y) * width;
                points[1].p_y = c->r_ybot;
                points[2].p_y = c->r_ybot;
                points[2].p_x -= xround(delx);
            }
            if (c->r_xtop < points[2].p_x)      /* clip RIGHT */
            {
                dely = (dlong)(points[2].p_x - c->r_xtop) * height;
                points[2].p_x = c->r_xtop;
                points[3].p_x = c->r_xtop;
                points[3].p_y = points[1].p_y + yround(dely);
                *np = 4;

                if (c->r_ytop < points[3].p_y)  /* clip TOP, rectangle */
                {
                  points[3].p_y = c->r_ytop;
                  points[0].p_y = c->r_ytop;
                }
                else if (c->r_ytop < points[0].p_y) /* clip TOP, pentagon */
                {
                  delx = (dlong)(points[0].p_y - c->r_ytop) * width;
                  points[0].p_y = c->r_ytop;
                  points[4].p_y = c->r_ytop;
                  points[4].p_x = points[0].p_x + xround(delx);
                    *np = 5;
                }
            }
            else if (c->r_ytop < points[0].p_y) /* clip TOP, quadrangle */
            {
                delx = (dlong)(points[0].p_y - c->r_ytop) * width;
                points[0].p_y = c->r_ytop;
                points[3].p_y = c->r_ytop;
                points[3].p_x = points[0].p_x + xround(delx);
                *np = 4;
            }
            if (points[1].p_y > points[0].p_y || points[2].p_x < points[1].p_x)
                *np = 0;      /* clipped out of existance */
            break;

          case TT_DIAGONAL | TT_SIDE:     /* se */
            /* order: (bottom, right), (top, left) */
            if (c->r_ybot > r->r_ybot)    /* clip BOTTOM */
            {
                delx = (dlong)(c->r_ybot - points[1].p_y) * width;
                points[1].p_y = c->r_ybot;
                points[0].p_y = c->r_ybot;
                points[0].p_x += xround(delx);
            }
            if (c->r_xtop < r->r_xtop)    /* clip RIGHT */
            {
                dely = (dlong)(points[2].p_x - c->r_xtop) * height;
                points[1].p_x = c->r_xtop;
                points[2].p_x = c->r_xtop;
                points[2].p_y -= yround(dely);
            }
            if (c->r_ytop < points[2].p_y)      /* clip TOP */
            {
                delx = (dlong)(points[2].p_y - c->r_ytop) * width;
                points[2].p_y = c->r_ytop;
                points[3].p_y = c->r_ytop;
                points[3].p_x = points[2].p_x - xround(delx);
                *np = 4;

                if (c->r_xbot > points[3].p_x)  /* clip LEFT, rectangle */
                {
                  points[3].p_x = c->r_xbot;
                  points[0].p_x = c->r_xbot;
                }
                else if (c->r_xbot > points[0].p_x) /* clip LEFT, pentagon */
                {
                  dely = (dlong)(c->r_xbot - points[0].p_x) * height;
                  points[0].p_x = c->r_xbot;
                  points[4].p_x = c->r_xbot;
                  points[4].p_y = points[0].p_y + yround(dely);
                    *np = 5;
                }
            }
            else if (c->r_xbot > points[0].p_x) /* clip LEFT, triangle */
            {
                dely = (dlong)(c->r_xbot - points[0].p_x) * height;
                points[0].p_x = c->r_xbot;
                points[3].p_x = c->r_xbot;
                points[3].p_y = points[0].p_y + yround(dely);
                *np = 4;
            }
            if (points[0].p_x > points[1].p_x || points[1].p_y > points[2].p_y)
                *np = 0;      /* clipped out of existance */
            break;

          case TT_DIAGONAL | TT_SIDE | TT_DIRECTION:  /* ne */
            /* order: (top, right), (bottom, left) */
            if (c->r_xtop < r->r_xtop)    /* clip RIGHT */
            {
                dely = (dlong)(points[1].p_x - c->r_xtop) * height;
                points[1].p_x = c->r_xtop;
                points[0].p_x = c->r_xtop;
                points[0].p_y += yround(dely);
            }
            if (c->r_ytop < r->r_ytop)    /* clip TOP */
            {
                delx = (dlong)(points[2].p_y - c->r_ytop) * width;
                points[1].p_y = c->r_ytop;
                points[2].p_y = c->r_ytop;
                points[2].p_x += xround(delx);
            }
            if (c->r_xbot > points[2].p_x)      /* clip LEFT */
            {
                dely = (dlong)(c->r_xbot - points[2].p_x) * height;
                points[2].p_x = c->r_xbot;
                points[3].p_x = c->r_xbot;
                points[3].p_y = points[2].p_y - yround(dely);
                *np = 4;

                if (c->r_ybot > points[3].p_y)  /* clip BOTTOM, rectangle */
                {
                  points[3].p_y = c->r_ybot;
                  points[0].p_y = c->r_ybot;
                }
                else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, pentagon */
                {
                  delx = (dlong)(c->r_ybot - points[0].p_y) * width;
                  points[0].p_y = c->r_ybot;
                  points[4].p_y = c->r_ybot;
                  points[4].p_x = points[0].p_x - xround(delx);
                    *np = 5;
                }
            }
            else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, quadrangle */
            {
                delx = (dlong)(c->r_ybot - points[0].p_y) * width;
                points[0].p_y = c->r_ybot;
                points[3].p_y = c->r_ybot;
                points[3].p_x = points[0].p_x - xround(delx);
                *np = 4;
            }
            if (points[1].p_y < points[0].p_y || points[2].p_x > points[1].p_x)
                *np = 0;      /* clipped out of existance */
            break;
      }
    }
}

/*---------------------------------------------------------
 * GrDrawTriangleEdge --
 *    Draws the diagonal line in a triangle clipped by
 *    grCurClip.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Draws nonmanhattan layout geometry.
 *
 *---------------------------------------------------------
 */

void
GrDrawTriangleEdge(r, dinfo)
    Rect *r;   /* Bounding box of triangle, in screen coords      */
    TileType dinfo;
{
    Point tpoints[5];
    int tnum, i, j;

    GrClipTriangle(r, &grCurClip, TRUE, dinfo, tpoints, &tnum);

    for (i = 0; i < tnum; i++)
    { 
      j = (i + 1) % tnum;
      if (tpoints[i].p_x != tpoints[j].p_x &&  
            tpoints[i].p_y != tpoints[j].p_y)
      {   
          GrClipLine(tpoints[i].p_x, tpoints[i].p_y,
                  tpoints[j].p_x, tpoints[j].p_y);
          break;
      }
    }
}

/*---------------------------------------------------------
 * GrDiagonal:
 *    GrDiagonal will draw a triangle on the screen in the
 *    style set by the previous call to GrSetStuff.  It will also
 *    be clipped against the rectangles passed to GrSetStuff.
 *
 *    If GrDiagonal is called between GrFastBox calls then GrSetStuff
 *    must be called to set the parameters back.
 *
 * Results:
 *    None.
 *
 * Side Effects:
 *    The rectangle is drawn in the style specified.
 *    The rectangle is clipped before being drawn.
 *---------------------------------------------------------
 */

void
GrDiagonal(prect, dinfo)
    Rect *prect;  /* The rectangle to be drawn, given in
                         * screen coordinates.
                           */
    TileType dinfo;     /* split and direction information */
{
    Rect *r;
    bool needClip, needObscure;
    LinkedRect *ob;
    int cp, np;
    Rect clipr, fullr;
    Point polyp[5];

    GR_CHECK_LOCK();
    if (!grDriverInformed) grInformDriver();
    GrNumClipBoxes++;
    if (grCurFill == GR_STGRID)
    {
      r = &grCurClip;
      grGridRect = prect;
    }
    else
    {
      r = prect;
      if (!GEO_TOUCH(r, &grCurClip)) return;
    }

    /* Do a quick check to make the (very common) special case of
     * no clipping go fast.
     */
    needClip = !GEO_SURROUND(&grCurClip, r);
    needObscure = FALSE;
    for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
      needObscure |= GEO_TOUCH(r, &(ob->r_r));

    /* Generate points for the triangle and do clipping if necessary */

    clipr = fullr = *r;
    if (needClip)
      GeoClip(&clipr, &grCurClip);

    GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);

    /* do solid areas */
    if ( (grCurFill == GR_STSOLID) || 
      (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
    {
      if (needObscure)
          grObsBox(&clipr);
      else if (grFillPolygonPtr)
          (void) (*grFillPolygonPtr)(polyp, np);
    } 

    /* return if rectangle is too small to see */

    if ((r->r_xtop - r->r_xbot < GR_THRESH) && 
          (r->r_ytop - r->r_ybot < GR_THRESH) && (grCurFill != GR_STOUTLINE))
      return;

    /* draw outlines */
    if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
    {
      /* TO DO: Check for boundary with shared tile type */
      for (cp = 0; cp < np - 1; cp++)
          (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
                  polyp[cp + 1].p_x, polyp[cp + 1].p_y);

      (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
                  polyp[0].p_x, polyp[0].p_y);
    }
}

/*---------------------------------------------------------
 * GrFillPolygon --
 *    This routine is simply a call to the locally-defined
 *    grFillPolygonPtr routine.
 *
 *---------------------------------------------------------
 */

void
GrFillPolygon(polyp, np)
    Point *polyp;       /* Array of points defining polygon */
    int np;             /* number of points in array polyp  */
{
    if (grFillPolygonPtr != NULL)
    {
      (*grFillPolygonPtr)(polyp, np);
    }
}

#endif /* NONMANHATTAN */

/*---------------------------------------------------------
 * GrClipBox:
 *    GrClipBox will draw a rectangle on the screen in one
 *    of several possible styles, except that the rectangle will
 *    be clipped against a list of obscuring rectangles.
 *
 * Results: None.
 *
 * Side Effects:
 *    The rectangle is drawn in the style specified.
 *    The rectangle is clipped before being drawn.
 *---------------------------------------------------------
 */

void
GrClipBox(prect, style)
    Rect *prect;        /* The rectangle to be drawn, given in
                         * screen coordinates.
                           */
    int style;                /* The style to be used in drawing it. */
{
    GrSetStuff(style);
    GrFastBox(prect);
}


/*
 * ----------------------------------------------------------------------------
 *    GrDisjoint --
 *
 *    Clip a rectanglular area against a clipping box, applying the
 *    supplied procedure to each rectangular region in "area" which
 *    falls outside "clipbox".  This works in pixel space, where a
 *    rectangle is contains its lower x- and y-coordinates AND ALSO
 *    its upper coordinates.  This means that if the clipping box
 *    occupies a given pixel, the things being clipped must not occupy
 *    that pixel.  This procedure will NOT work in tile space.
 *
 *    The procedure should be of the form:
 *          bool func(box, cdarg)
 *                Rect     * box;
 *                ClientData   cdarg;
 *
 * Results:
 *    Return TRUE unless the supplied function returns FALSE.
 *
 * Side effects:
 *    The side effects of the invoked procedure.
 * ----------------------------------------------------------------------------
 */
bool
GrDisjoint(area, clipBox, func, cdarg)
    Rect    * area;
    Rect    * clipBox;
    bool    (*func) ();
    ClientData      cdarg;
{
    Rect      ok, rArea;
    bool      result;

#define NULLBOX(R) ((R.r_xbot>R.r_xtop)||(R.r_ybot>R.r_ytop))

    ASSERT((area!=(Rect *) NULL), "GrDisjoint");
    if((clipBox==(Rect *) NULL)||(!GEO_TOUCH(area, clipBox)))
    {
    /* Since there is no overlap, all of "area" may be processed. */

      result= (*func)(area, cdarg);
      return(result);
    }

    /* Do the disjoint operation in four steps, one for each side
     * of clipBox.  In each step, divide the area being clipped
     * into one piece that is DEFINITELY outside clipBox, and one
     * piece left to check some more.
     */
    
    /* Top edge of clipBox: */

    rArea = *area;
    result = TRUE;
    if (clipBox->r_ytop < rArea.r_ytop)
    {
      ok = rArea;
      ok.r_ybot = clipBox->r_ytop + 1;
      rArea.r_ytop = clipBox->r_ytop;
      if (!(*func)(&ok, cdarg)) result = FALSE;
    }

    /* Bottom edge of clipBox: */

    if (clipBox->r_ybot > rArea.r_ybot)
    {
      ok = rArea;
      ok.r_ytop = clipBox->r_ybot - 1;
      rArea.r_ybot = clipBox->r_ybot;
      if (!(*func)(&ok, cdarg)) result = FALSE;
    }

    /* Right edge of clipBox: */

    if (clipBox->r_xtop < rArea.r_xtop)
    {
      ok = rArea;
      ok.r_xbot = clipBox->r_xtop + 1;
      rArea.r_xtop = clipBox->r_xtop;
      if (!(*func)(&ok, cdarg)) result = FALSE;
    }

    /* Left edge of clipBox: */

    if (clipBox->r_xbot > rArea.r_xbot)
    {
      ok = rArea;
      ok.r_xtop = clipBox->r_xbot - 1;
      rArea.r_xbot = clipBox->r_xbot;
      if (!(*func)(&ok, cdarg)) result = FALSE;
    }

    /* Just throw away what's left of the area being clipped, since
     * it overlaps the clipBox.
     */

    return result;
} /*GrDisjoint*/

Generated by  Doxygen 1.6.0   Back to index