2017-04-25 14:41:48 +02:00
|
|
|
/* grClip.c -
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*
|
|
|
|
|
* 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-8.0/graphics/grClip.c,v 1.4 2010/06/24 12:37:18 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!
|
|
|
|
|
*/
|
|
|
|
|
|
2024-10-04 18:02:09 +02:00
|
|
|
global Rect GrCrossRect = {{-GR_CROSSSIZE, -GR_CROSSSIZE}, {GR_CROSSSIZE, GR_CROSSSIZE}};
|
2017-04-25 14:41:48 +02:00
|
|
|
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.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* Results:
|
2017-04-25 14:41:48 +02:00
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
grInformDriver()
|
|
|
|
|
{
|
|
|
|
|
/* Now let the device drivers know */
|
|
|
|
|
(*grSetWMandCPtr)(grCurWMask, grCurColor);
|
|
|
|
|
(*grSetLineStylePtr)(grCurOutline);
|
|
|
|
|
(*grSetStipplePtr)(grCurStipple);
|
|
|
|
|
grDriverInformed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* 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)
|
2020-05-23 23:13:14 +02:00
|
|
|
LinkedRect **startllr; /* A pointer to the pointer that heads
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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! */
|
2020-05-23 23:13:14 +02:00
|
|
|
(void) GrDisjoint(&lr->r_r, clip, grClipAddFunc,
|
2017-04-25 14:41:48 +02:00
|
|
|
(ClientData) &llr);
|
|
|
|
|
freeMagic( (char *) lr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
llr = &((*llr)->r_next);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Add a box to our linked list, and advance
|
|
|
|
|
* our pointer into the list
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
bool grClipAddFunc(box, cd)
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
else
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
else
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
else
|
2017-04-25 14:41:48 +02:00
|
|
|
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? */
|
2020-05-23 23:13:14 +02:00
|
|
|
return ok1 || ok2 ||
|
2017-04-25 14:41:48 +02:00
|
|
|
((x1 >= box->r_xbot) && (x1 <= box->r_xtop) && (y1 >= box->r_ybot)
|
|
|
|
|
&& (y1 <= box->r_ytop));
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#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;
|
2024-09-30 00:00:00 +02:00
|
|
|
bool ok1 = FALSE, ok2 = FALSE;
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
if (ok1 &&
|
2017-04-25 14:41:48 +02:00
|
|
|
( ((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 */
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
if (ok2 &&
|
2017-04-25 14:41:48 +02:00
|
|
|
( ((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);
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tile) && SplitSide(tile))
|
|
|
|
|
isolate |= 0x1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ttype = TiGetLeftType(tile);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (IsSplit(tile) && !SplitSide(tile))
|
|
|
|
|
isolate |= 0x2;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ttype = TiGetRightType(tile);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tile) &&
|
|
|
|
|
(SplitSide(tile) == SplitDirection(tile)))
|
|
|
|
|
isolate |= 0x4;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ttype = TiGetBottomType(tile);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tile) &&
|
|
|
|
|
(SplitSide(tile) != SplitDirection(tile)))
|
|
|
|
|
isolate |= 0x8;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ttype = TiGetTopType(tile);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
if (IsSplit(tile))
|
|
|
|
|
WindSurfaceToScreenNoClip(mw, &r2, &r);
|
|
|
|
|
else
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
if ((grCurFill == GR_STSOLID) ||
|
2017-04-25 14:41:48 +02:00
|
|
|
(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
|
|
|
|
|
{
|
|
|
|
|
if (needObscure)
|
|
|
|
|
grObsBox(&clipr);
|
|
|
|
|
else if (grFillPolygonPtr)
|
|
|
|
|
(void) (*grFillPolygonPtr)(polyp, np);
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* 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);
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* GrDrawFastBox:
|
|
|
|
|
* GrDrawFastBox 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 GrDrawFastBox calls then GrSetStuff
|
|
|
|
|
* must be called to set the parameters back.
|
|
|
|
|
*
|
|
|
|
|
* Usually this is called as GrFastBox, defined as GrDrawFastBox(p, 0).
|
|
|
|
|
* The "scale" is only used to reduce the size of crosses drawn at
|
|
|
|
|
* point positions, to prevent point labels from dominating a layout
|
2020-05-23 23:13:14 +02:00
|
|
|
* in top-level views.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results: None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* The rectangle is drawn in the style specified.
|
|
|
|
|
* The rectangle is clipped before being drawn.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
GrDrawFastBox(prect, scale)
|
|
|
|
|
Rect *prect; /* The rectangle to be drawn, given in
|
|
|
|
|
* screen coordinates.
|
|
|
|
|
*/
|
|
|
|
|
int scale; /* If < 0, we reduce the cross size for
|
|
|
|
|
* points according to the (negative) scale,
|
|
|
|
|
* so point labels don't dominate a top-level
|
|
|
|
|
* layout.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
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 */
|
2020-05-23 23:13:14 +02:00
|
|
|
if ( (grCurFill == GR_STSOLID) ||
|
2017-04-25 14:41:48 +02:00
|
|
|
(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);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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) )
|
|
|
|
|
{
|
|
|
|
|
int crossSize = GR_CROSSSIZE;
|
|
|
|
|
|
|
|
|
|
if (scale < 0)
|
|
|
|
|
{
|
|
|
|
|
crossSize += scale;
|
|
|
|
|
if (crossSize < 0)
|
|
|
|
|
goto endit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* turn the outline into a cross */
|
2020-05-23 23:13:14 +02:00
|
|
|
if (needClip || needObscure)
|
2017-04-25 14:41:48 +02:00
|
|
|
goto clipit;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool crossClip, crossObscure;
|
|
|
|
|
Rect crossBox;
|
|
|
|
|
|
|
|
|
|
/* check the larger cross area for clipping */
|
|
|
|
|
crossBox.r_xbot = r->r_xbot - crossSize;
|
|
|
|
|
crossBox.r_ybot = r->r_ybot - crossSize;
|
|
|
|
|
crossBox.r_xtop = r->r_xtop + crossSize;
|
|
|
|
|
crossBox.r_ytop = r->r_ytop + crossSize;
|
|
|
|
|
|
|
|
|
|
crossClip = !GEO_SURROUND(&grCurClip, &crossBox);
|
|
|
|
|
crossObscure = FALSE;
|
|
|
|
|
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
|
|
|
|
|
crossObscure |= GEO_TOUCH(&crossBox, &(ob->r_r));
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
if (crossClip || crossObscure)
|
2017-04-25 14:41:48 +02:00
|
|
|
goto clipit;
|
|
|
|
|
else
|
|
|
|
|
goto noclipit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clipit:
|
|
|
|
|
GrClipLine(r->r_xbot, r->r_ybot - crossSize,
|
|
|
|
|
r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
|
|
|
|
|
GrClipLine(r->r_xbot - crossSize, r->r_ybot,
|
|
|
|
|
r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
|
|
|
|
|
goto endit;
|
|
|
|
|
|
|
|
|
|
noclipit:
|
|
|
|
|
(*grDrawLinePtr)(r->r_xbot, r->r_ybot - crossSize,
|
|
|
|
|
r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
|
|
|
|
|
(*grDrawLinePtr)(r->r_xbot - crossSize, r->r_ybot,
|
|
|
|
|
r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
|
|
|
|
|
|
|
|
|
|
endit: ;
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* 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 */
|
2020-05-23 23:13:14 +02:00
|
|
|
/* a 3- to 5-sided polygon, or empty. */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
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 existence */
|
|
|
|
|
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 existence */
|
|
|
|
|
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 existence */
|
|
|
|
|
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 existence */
|
|
|
|
|
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++)
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
j = (i + 1) % tnum;
|
2020-05-23 23:13:14 +02:00
|
|
|
if (tpoints[i].p_x != tpoints[j].p_x &&
|
2017-04-25 14:41:48 +02:00
|
|
|
tpoints[i].p_y != tpoints[j].p_y)
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
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 */
|
2020-05-23 23:13:14 +02:00
|
|
|
if ( (grCurFill == GR_STSOLID) ||
|
2017-04-25 14:41:48 +02:00
|
|
|
(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
|
|
|
|
|
{
|
|
|
|
|
if (needObscure)
|
|
|
|
|
grObsBox(&clipr);
|
|
|
|
|
else if (grFillPolygonPtr)
|
|
|
|
|
(void) (*grFillPolygonPtr)(polyp, np);
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* return if rectangle is too small to see */
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
if ((r->r_xtop - r->r_xbot < GR_THRESH) &&
|
2017-04-25 14:41:48 +02:00
|
|
|
(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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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*/
|