-- 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.