-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved.
-- DisplayImplE.mesa - last edited by
-- S. Schiller 7-Mar-83 13:55:16
-- Rick 22-Nov-83 16:49:41
-- Bruce 6-Feb-83 21:13:09
-- Daniels 7-Jun-84 14:58:00
DIRECTORY
BitBlt USING [BitBltFlags],
Display USING [paintGrayFlags],
DisplayOps USING [AbsPlace, FillList, FillObject, HasUnder, Intersect, Shade],
SpecialDisplay USING [defaultContext, LineStyle, solid, Special],
Window USING [Place, BoxHandle],
WindowOps USING [
AbsoluteBoxHandle, bitmapAddress, Bounds, DisplayList, GetContext,
lock, Object, RecList, ScanLine, ScreenBox, SpecialTimesWpl];
DisplayImplE: MONITOR LOCKS WindowOps.lock
IMPORTS DisplayOps, SpecialDisplay, WindowOps
EXPORTS Display, SpecialDisplay, Window =
BEGIN
-- exported types
Handle: TYPE = LONG POINTER TO Object;
Object: PUBLIC TYPE = WindowOps.Object;
FillHandle: TYPE = LONG POINTER TO FillObject;
FillObject: PUBLIC TYPE = DisplayOps.FillObject;
-- copied types because John doesn't like them
LineStyle: TYPE = SpecialDisplay.LineStyle;
Special: TYPE = SpecialDisplay.Special;
Ellipse: PUBLIC ENTRY PROC [
window: Handle, center: Window.Place, xRadius, yRadius: INTEGER,
bounds: Window.BoxHandle ← NIL] = {
ENABLE UNWIND => NULL;
absBounds: WindowOps.ScreenBox =
IF bounds = NIL THEN WindowOps.Bounds[window]
ELSE WindowOps.AbsoluteBoxHandle[window, bounds];
-- switch to screen coords
absCenter: Window.Place = DisplayOps.AbsPlace[window, center];
IF ~window.inTree THEN RETURN;
FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL
DO
IF DisplayOps.Intersect[r, absBounds] THEN {
wpl: CARDINAL = SpecialDisplay.defaultContext.wpl;
error: LONG INTEGER ← 0;
xerror, yerror, xyerror: LONG INTEGER;
a, b, dx, dy, dxdx, dydy: LONG INTEGER;
xRight: INTEGER ← absCenter.x;
xLeft: INTEGER ← absCenter.x;
yLow: WindowOps.ScanLine ← WindowOps.bitmapAddress +
WindowOps.SpecialTimesWpl[INTEGER[absCenter.y-yRadius]];
yHigh: WindowOps.ScanLine ← WindowOps.bitmapAddress +
WindowOps.SpecialTimesWpl[INTEGER[absCenter.y + yRadius]];
safetyCount: INTEGER ← 0;
IF absCenter.x - xRadius < r.box.left OR absCenter.x + xRadius >= r.box.right
OR absCenter.y + yRadius >= r.box.bottom
OR absCenter.y - yRadius < r.box.top OR DisplayOps.HasUnder[r] THEN {
SpEllipseInternal[
r, FALSE, window, center, xRadius, yRadius, bounds,
SpecialDisplay.solid, Display.paintGrayFlags];
RETURN};
a ← LONG[yRadius]*LONG[yRadius];
dxdx ← 2*a;
b ← LONG[xRadius]*LONG[xRadius];
dydy ← 2*b;
dx ← a;
dy ← b*(1 - 2*yRadius);
-- Inner Loop
UNTIL yLow >= yHigh OR safetyCount > xRadius DO
yLow[xRight] ← TRUE; -- set bit
yHigh[xRight] ← TRUE;
yLow[xLeft] ← TRUE;
yHigh[xLeft] ← TRUE;
xerror ← error + dx;
xyerror ← xerror + dy;
safetyCount ← safetyCount + 1;
IF ABS[xyerror] < ABS[xerror] THEN {
IF ABS[error + dy] < ABS[xyerror] THEN {
error ← error + dy;
yLow ← yLow + wpl;
yHigh ← yHigh - wpl;
dy ← dy + dydy;
-- Y varies more quickly now
-- stay in this loop until done
UNTIL yLow >= yHigh DO
yLow[xRight] ← TRUE;
yHigh[xRight] ← TRUE;
yLow[xLeft] ← TRUE;
yHigh[xLeft] ← TRUE;
yerror ← error + dy;
xyerror ← yerror + dx;
IF ABS[xyerror] < ABS[yerror] THEN {
error ← xyerror;
yLow ← yLow + wpl;
yHigh ← yHigh - wpl;
xRight ← xRight + 1;
xLeft ← xLeft - 1;
safetyCount ← safetyCount + 1;
dx ← dx + dxdx;
dy ← dy + dydy}
ELSE {
error ← yerror;
yLow ← yLow + wpl;
yHigh ← yHigh - wpl;
dy ← dy + dydy};
ENDLOOP;
EXIT};
error ← xyerror;
yLow ← yLow + wpl;
yHigh ← yHigh - wpl;
xRight ← xRight + 1;
xLeft ← xLeft - 1;
dx ← dx + dxdx;
dy ← dy + dydy}
ELSE {
error ← xerror;
xRight ← xRight + 1;
xLeft ← xLeft - 1;
dx ← dx + dxdx};
ENDLOOP;
yLow[xRight] ← TRUE;
yLow[xLeft] ← TRUE;
-- don't need to set yHigh cause its equal to yLow now
-- loop below fills out long skinny ellipses
UNTIL safetyCount >= xRadius DO
xRight ← xRight + 1;
xLeft ← xLeft - 1;
yLow[xLeft] ← TRUE;
yLow[xRight] ← TRUE;
safetyCount ← safetyCount + 1
ENDLOOP};
ENDLOOP};
SpEllipse: PUBLIC ENTRY PROC [
window: Handle, center: Window.Place, xRadius, yRadius: INTEGER,
bounds: Window.BoxHandle, dashes: LineStyle, flags: BitBlt.BitBltFlags,
context: Special ← SpecialDisplay.defaultContext] = {
ENABLE UNWIND => NULL;
filled: BOOLEAN = context.alloc # NIL;
firstRec: WindowOps.RecList = DisplayOps.FillList[window, filled];
SpEllipseInternal[
firstRec, filled, window, center, xRadius, yRadius, bounds, dashes, flags,
context]};
SpEllipseInternal: INTERNAL PROC [
firstRec: WindowOps.RecList, filled: BOOLEAN, window: Handle,
center: Window.Place, xRadius, yRadius: INTEGER, bounds: Window.BoxHandle,
dashes: LineStyle, flags: BitBlt.BitBltFlags,
context: Special ← SpecialDisplay.defaultContext] = {
absBounds: WindowOps.ScreenBox =
IF bounds = NIL THEN WindowOps.Bounds[window]
ELSE WindowOps.AbsoluteBoxHandle[window, bounds];
-- switch to screen coords
absCenter: Window.Place = DisplayOps.AbsPlace[window, center];
IF ~window.inTree THEN RETURN;
FOR r: WindowOps.RecList ← firstRec, r.link UNTIL r = NIL DO
IF DisplayOps.Intersect[r, absBounds] THEN {
ctx: Special = WindowOps.GetContext[r, context];
error: LONG INTEGER ← 0;
xerror, yerror, xyerror: LONG INTEGER;
a, b, dx, dy, dxdx, dydy: LONG INTEGER;
xRight: INTEGER ← absCenter.x;
xLeft: INTEGER ← absCenter.x;
yHighSL: WindowOps.ScanLine ← ctx.bmAddress +
WindowOps.SpecialTimesWpl[INTEGER[absCenter.y - yRadius], ctx];
yLowSL: WindowOps.ScanLine ← ctx.bmAddress +
WindowOps.SpecialTimesWpl[INTEGER[absCenter.y + yRadius], ctx];
yHigh: INTEGER ← absCenter.y - yRadius;
yLow: INTEGER ← absCenter.y + yRadius;
xTravel: INTEGER ← 0;
start1: CARDINAL = 0;
dOrtho: CARDINAL = 5;
dDiag: CARDINAL = 7;
stop1: CARDINAL = dashes.widths[0]*dOrtho;
start2: CARDINAL = stop1 + dashes.widths[1]*dOrtho;
stop2: CARDINAL = start2 + dashes.widths[2]*dOrtho;
start3: CARDINAL = stop2 + dashes.widths[3]*dOrtho;
stop3: CARDINAL = start3 + dashes.widths[4]*dOrtho;
dashSum: CARDINAL = stop3 + dashes.widths[5]*dOrtho;
dashCnt: CARDINAL ← 0;
thickness: CARDINAL = dashes.thickness;
left: INTEGER = r.box.left;
right: INTEGER = r.box.right;
top: INTEGER = r.box.top;
bottom: INTEGER = r.box.bottom;
yMin, yLen: INTEGER; -- used for filing
fillLeft, fillRight: FillHandle;
PaintDot: PROC [x, y: INTEGER, ySL: WindowOps.ScanLine] = INLINE {
IF x IN [left..right) AND y IN [top..bottom) THEN
ySL[x] ←
(SELECT DisplayOps.Shade[flags] FROM
white => FALSE,
black => TRUE,
ENDCASE => NOT ySL[x])};
FillLine: PROC [xL, xR, ybiz: INTEGER] = INLINE {
IF ybiz IN [top..bottom) THEN {
xL ← MAX[xL, left];
xR ← MIN[xR, right];
ybiz ← ybiz - yMin;
fillLeft.xs[ybiz] ← xL;
fillRight.xs[ybiz] ← xR}};
ShallowEllipsePart: PROC[] = {
UNTIL yHighSL >= yLowSL DO
IF NOT filled THEN {
IF
(dashCnt IN [start1..stop1) OR dashCnt IN [start2..stop2)
OR dashCnt IN [start3..stop3)) THEN {
PaintDot[xRight, yHigh, yHighSL];
PaintDot[xRight, yLow, yLowSL];
PaintDot[xLeft, yHigh, yHighSL];
PaintDot[xLeft, yLow, yLowSL];
IF thickness > 1 THEN {
quotiet: INTEGER = thickness/2;
remainder: INTEGER = thickness MOD 2;
FOR i: INTEGER IN [1..quotiet] DO
xl: INTEGER = xLeft + i;
xr: INTEGER = xRight - i;
PaintDot[xr, yHigh, yHighSL];
PaintDot[xr, yLow, yLowSL];
PaintDot[xl, yHigh, yHighSL];
PaintDot[xl, yLow, yLowSL];
IF i < quotiet OR remainder = 1 THEN {
xl: INTEGER = xLeft - i;
xr: INTEGER = xRight + i;
PaintDot[xr, yHigh, yHighSL];
PaintDot[xr, yLow, yLowSL];
PaintDot[xl, yHigh, yHighSL];
PaintDot[xl, yLow, yLowSL]};
ENDLOOP}}}
ELSE {FillLine[xLeft, xRight, yLow]; FillLine[xLeft, xRight, yHigh]};
yerror ← error + dy;
xyerror ← yerror + dx;
IF ABS[xyerror] < ABS[yerror] THEN {
error ← xyerror;
yHighSL ← yHighSL + ctx.wpl;
yLowSL ← yLowSL - ctx.wpl;
yHigh ← yHigh + 1;
yLow ← yLow - 1;
xRight ← xRight + 1;
xLeft ← xLeft - 1;
xTravel ← xTravel + 1;
dx ← dx + dxdx;
dy ← dy + dydy;
dashCnt ← dashCnt + dDiag}
ELSE {
error ← yerror;
yHighSL ← yHighSL + ctx.wpl;
yLowSL ← yLowSL - ctx.wpl;
yHigh ← yHigh + 1;
yLow ← yLow - 1;
dy ← dy + dydy;
dashCnt ← dashCnt + dOrtho};
UNTIL dashCnt < dashSum DO dashCnt ← dashCnt - dashSum ENDLOOP
ENDLOOP;
IF NOT filled THEN {
IF
(dashCnt IN [start1..stop1) OR dashCnt IN [start2..stop2)
OR dashCnt IN [start3..stop3)) THEN {
PaintDot[xRight, yHigh, yHighSL];
PaintDot[xLeft, yHigh, yHighSL];
IF thickness > 1 THEN {
quotiet: INTEGER = thickness/2;
remainder: INTEGER = thickness MOD 2;
FOR i: INTEGER IN [1..quotiet] DO
xl: INTEGER = xLeft + i;
xr: INTEGER = xRight - i;
PaintDot[xr, yHigh, yHighSL];
PaintDot[xl, yHigh, yHighSL];
IF i < quotiet OR remainder = 1 THEN {
xl: INTEGER = xLeft - i;
xr: INTEGER = xRight + i;
PaintDot[xr, yHigh, yHighSL];
PaintDot[xl, yHigh, yHighSL]}
ENDLOOP}}}
ELSE {FillLine[xLeft, xRight, yLow]; FillLine[xLeft, xRight, yHigh]}};
-- start of code
IF filled THEN {
yMin ← MAX[r.box.top, absCenter.y - yRadius];
yLen ← MIN[r.box.bottom, absCenter.y + yRadius] - yMin + 2;
fillLeft ← ctx.alloc[window, yMin, yLen];
fillRight ← ctx.alloc[window, yMin, yLen]};
a ← LONG[yRadius]*LONG[yRadius];
dxdx ← 2*a;
b ← LONG[xRadius]*LONG[xRadius];
dydy ← 2*b;
dx ← a;
dy ← b*(1 - 2*yRadius);
-- right up
UNTIL yHighSL >= yLowSL OR xTravel > xRadius DO
IF NOT filled THEN {
IF
(dashCnt IN [start1..stop1) OR dashCnt IN [start2..stop2)
OR dashCnt IN [start3..stop3)) THEN {
PaintDot[xRight, yLow, yLowSL]; -- set bit
PaintDot[xRight, yHigh, yHighSL];
PaintDot[xLeft, yLow, yLowSL];
PaintDot[xLeft, yHigh, yHighSL];
IF thickness > 1 THEN {
quotiet: INTEGER = thickness/2;
remainder: INTEGER = thickness MOD 2;
FOR i: INTEGER IN [1..quotiet] DO
yl: INTEGER = yLow - i;
yh: INTEGER = yHigh + i;
yLSL: WindowOps.ScanLine = yLowSL - i*ctx.wpl;
yHSL: WindowOps.ScanLine = yHighSL + i*ctx.wpl;
PaintDot[xRight, yl, yLSL]; -- set inside bit
PaintDot[xRight, yh, yHSL];
PaintDot[xLeft, yl, yLSL];
PaintDot[xLeft, yh, yHSL];
IF i < quotiet OR remainder = 1 THEN {
yl: INTEGER = yLow + i;
yh: INTEGER = yHigh - i;
yLSL: WindowOps.ScanLine = yLowSL + i*ctx.wpl;
yHSL: WindowOps.ScanLine = yHighSL - i*ctx.wpl;
PaintDot[xRight, yl, yLSL]; -- set inside bit
PaintDot[xRight, yh, yHSL];
PaintDot[xLeft, yl, yLSL];
PaintDot[xLeft, yh, yHSL]}
ENDLOOP}}}
ELSE {FillLine[xLeft, xRight, yLow]; FillLine[xLeft, xRight, yHigh]};
xerror ← error + dx;
xyerror ← xerror + dy;
xTravel ← xTravel + 1;
IF ABS[xyerror] < ABS[xerror] THEN {
IF ABS[error + dy] < ABS[xyerror] THEN {
error ← error + dy;
yHighSL ← yHighSL + ctx.wpl;
yLowSL ← yLowSL - ctx.wpl;
yLow ← yLow - 1;
yHigh ← yHigh + 1;
dy ← dy + dydy;
-- Y varies more quickly now
ShallowEllipsePart[];
EXIT};
error ← xyerror;
yHighSL ← yHighSL + ctx.wpl;
yLowSL ← yLowSL - ctx.wpl;
yLow ← yLow - 1;
yHigh ← yHigh + 1;
xRight ← xRight + 1;
xLeft ← xLeft - 1;
dx ← dx + dxdx;
dy ← dy + dydy;
dashCnt ← dashCnt + dDiag}
ELSE {
error ← xerror;
xRight ← xRight + 1;
xLeft ← xLeft - 1;
dx ← dx + dxdx;
dashCnt ← dashCnt + dOrtho};
UNTIL dashCnt < dashSum DO dashCnt ← dashCnt - dashSum ENDLOOP;
REPEAT
FINISHED => {
IF NOT filled THEN {
IF
(dashCnt IN [start1..stop1) OR dashCnt IN [start2..stop2)
OR dashCnt IN [start3..stop3)) THEN {
PaintDot[xLeft, yHigh, yHighSL];
PaintDot[xRight, yHigh, yHighSL];
IF thickness > 1 THEN {
quotiet: INTEGER = thickness/2;
remainder: INTEGER = thickness MOD 2;
FOR i: INTEGER IN [1..quotiet] DO
yh: INTEGER = yHigh + i;
yHSL: WindowOps.ScanLine = yHighSL + i*ctx.wpl;
PaintDot[xRight, yh, yHSL];
PaintDot[xLeft, yh, yHSL];
IF i < quotiet OR remainder = 1 THEN {
yh: INTEGER = yHigh - i;
yHSL: WindowOps.ScanLine = yHighSL - i*ctx.wpl;
PaintDot[xRight, yh, yHSL];
PaintDot[xLeft, yh, yHSL]}
ENDLOOP}}}
ELSE {FillLine[xLeft, xRight, yLow]; FillLine[xLeft, xRight, yHigh]}}
ENDLOOP;
-- don't need to set yLowSL cause its equal to yLowSL now
-- loop below fills out long skinny ellipses
UNTIL xTravel >= xRadius DO
IF NOT filled THEN {
IF
(dashCnt IN [start1..stop1) OR dashCnt IN [start2..stop2)
OR dashCnt IN [start3..stop3)) THEN {
PaintDot[xLeft, yHigh, yHighSL];
PaintDot[xRight, yHigh, yHighSL];
IF thickness > 1 THEN {
quotiet: INTEGER = thickness/2;
remainder: INTEGER = thickness MOD 2;
FOR i: INTEGER IN [1..quotiet] DO
yh: INTEGER = yHigh + i;
yHSL: WindowOps.ScanLine = yHighSL + i*ctx.wpl;
PaintDot[xRight, yh, yHSL];
PaintDot[xLeft, yh, yHSL];
IF i < quotiet OR remainder = 1 THEN {
yh: INTEGER = yHigh - i;
yHSL: WindowOps.ScanLine = yHighSL - i*ctx.wpl;
PaintDot[xRight, yh, yHSL];
PaintDot[xLeft, yh, yHSL]}
ENDLOOP}}}
ELSE {
diff: INTEGER = xRadius - xTravel;
FillLine[xRight + diff, xLeft - diff, yHigh];
xTravel ← xRadius};
xRight ← xRight + 1;
xLeft ← xLeft - 1;
xTravel ← xTravel + 1;
dashCnt ← dashCnt + dOrtho;
UNTIL dashCnt < dashSum DO dashCnt ← dashCnt - dashSum ENDLOOP;
ENDLOOP};
ENDLOOP};
END.