-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved. -- DisplayImplD.mesa - last edited by -- Rick 12-Nov-83 14:51:57 -- Bruce 24-Feb-83 16:08:25 -- Daniels 7-Jun-84 14:56:02 DIRECTORY BitBlt USING [BitBltFlags], DisplayFormat USING [CircleType], Display USING [paintGrayFlags], DisplayOps USING [ AbsPlace, Color, HasUnder, LogError, FillList, FillObject, Intersect, Shade], DisplayInternal USING [], SpecialDisplay USING [DashCnt, defaultContext, LineStyle, solid, Special], Window USING [BoxHandle, Place], WindowOps USING [ AbsoluteBoxHandle, bitmapAddress, Bounds, DisplayList, GetContext, lock, Object, RecList, ScanLine, ScreenBox, SpecialTimesWpl]; DisplayImplD: MONITOR LOCKS WindowOps.lock IMPORTS DisplayOps, SpecialDisplay, WindowOps EXPORTS DisplayInternal, 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; -- circles Circle: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, radius: INTEGER, circleType: DisplayFormat.CircleType, bounds: Window.BoxHandle ← NIL] = { -- This routine observes that: -- radius IN [0..8000] -- place.x, place.y IN [-8000.. 8000] -- Also the circle bouding box intersects each reclist and before any integer -- math is done, the circle is in each reclist. Four scanlines and four -- bitIndexes are maintained to determine xys in all eight octants. Scanlines -- start top, middle, middle, bottom. BitIndexes start left, middle, middle, -- right. All end on the 45s. ENABLE UNWIND => NULL; absBounds: WindowOps.ScreenBox = IF bounds = NIL THEN WindowOps.Bounds[window] ELSE WindowOps.AbsoluteBoxHandle[window, bounds]; startTwoxma: INTEGER ← 1; startTwoymb: INTEGER ← 2*radius - 1; abs: Window.Place = DisplayOps.AbsPlace[window, place]; IF ~window.inTree THEN RETURN; FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { IF abs.x - radius < r.box.left OR -- clipped? abs.x + radius > r.box.right OR abs.y + radius > r.box.bottom OR abs.y - radius < r.box.top OR DisplayOps.HasUnder[r] THEN { [] ← SpCircleInternal[ r, FALSE, window, place, radius, circleType, bounds, SpecialDisplay.solid, Display.paintGrayFlags]; RETURN}; { -- not clipped, so these values can't be negative wpl: CARDINAL = SpecialDisplay.defaultContext.wpl; bitAddress1: WindowOps.ScanLine ← WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[abs.y - radius]; bitAddress2: WindowOps.ScanLine ← WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[abs.y]; bitAddress3: WindowOps.ScanLine ← bitAddress2; bitAddress4: WindowOps.ScanLine ← WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[abs.y + radius]; bitIndex1: INTEGER ← abs.x - radius; bitIndex2, bitIndex3: INTEGER ← abs.x; bitIndex4: INTEGER ← abs.x + radius; newError: INTEGER; twoxma: INTEGER ← startTwoxma; twoymb: INTEGER ← startTwoymb; error: INTEGER ← (radius - 1)/2; IF circleType[0] THEN { bitIndex1 ← bitIndex1 + 1; bitIndex2 ← bitIndex2 + 1}; IF circleType[1] THEN { bitIndex1 ← bitIndex1 - 1; bitIndex2 ← bitIndex2 - 1}; IF circleType[2] THEN { bitIndex3 ← bitIndex3 - 1; bitIndex4 ← bitIndex4 - 1}; IF circleType[3] THEN { bitIndex3 ← bitIndex3 + 1; bitIndex4 ← bitIndex4 + 1}; IF circleType[4] THEN { bitAddress1 ← bitAddress1 + wpl; bitAddress2 ← bitAddress2 + wpl}; IF circleType[5] THEN { bitAddress1 ← bitAddress1 - wpl; bitAddress2 ← bitAddress2 - wpl}; IF circleType[6] THEN { bitAddress3 ← bitAddress3 - wpl; bitAddress4 ← bitAddress4 - wpl}; IF circleType[7] THEN { bitAddress3 ← bitAddress3 + wpl; bitAddress4 ← bitAddress4 + wpl}; -- Provided this loop quits when it's supposed to, less thanradius/2times, -- twoxma IN [0..radius] -- twoymb IN [0..2*radius] -- error starts at [0..radius/2], and stays IN [-twoymb..twoymb] -- as twoymb goes to zero. UNTIL bitIndex3 > bitIndex4 DO bitAddress1[bitIndex2] ← TRUE; -- set a bit bitAddress1[bitIndex3] ← TRUE; bitAddress2[bitIndex1] ← TRUE; bitAddress2[bitIndex4] ← TRUE; bitAddress3[bitIndex1] ← TRUE; bitAddress3[bitIndex4] ← TRUE; bitAddress4[bitIndex2] ← TRUE; bitAddress4[bitIndex3] ← TRUE; bitIndex2 ← bitIndex2 - 1; bitIndex3 ← bitIndex3 + 1; bitAddress2 ← bitAddress2 - wpl; bitAddress3 ← bitAddress3 + wpl; error ← error + twoxma; IF ABS[newError ← error - twoymb] < ABS[error] THEN { error ← newError; bitIndex1 ← bitIndex1 + 1; bitIndex4 ← bitIndex4 - 1; bitAddress1 ← bitAddress1 + wpl; bitAddress4 ← bitAddress4 - wpl; twoymb ← twoymb - 2}; twoxma ← twoxma + 2; ENDLOOP}}; ENDLOOP}; SpecialCircle: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, radius: INTEGER, circleType: DisplayFormat.CircleType, bounds: Window.BoxHandle, dashes: SpecialDisplay.LineStyle, flags: BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext] = { ENABLE UNWIND => NULL; filled: BOOLEAN = context.alloc # NIL; firstRec: WindowOps.RecList = DisplayOps.FillList[window, filled]; SpCircleInternal[ firstRec, filled, window, place, radius, circleType, bounds, dashes, flags, context]}; SpCircleInternal: INTERNAL PROC [ firstRec: WindowOps.RecList, filled: BOOLEAN, window: Handle, place: Window.Place, radius: INTEGER, circleType: DisplayFormat.CircleType, bounds: Window.BoxHandle, dashes: SpecialDisplay.LineStyle, flags: BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext]={ -- This routine observes that: -- radius IN [0..8000] -- place.x, place.y IN [-8000.. 8000] -- Also the circle bouding box intersects Display.clip.box. -- Display.clip.box.left, right IN [0.. 1000] -- Display.clip.box.top, bottom IN [0..800] -- Four scanlines and four bitIndexes are maintained to determine xys in -- all eight octants. Scanlines start top, middle, middle, bottom. BitIndexes -- start left, middle, middle, right. All end on the 45s. L: PROCEDURE [l: LONG POINTER] RETURNS [LONG ORDERED POINTER] = INLINE { RETURN[LOOPHOLE[l]]}; absBounds: WindowOps.ScreenBox = IF bounds = NIL THEN WindowOps.Bounds[window] ELSE WindowOps.AbsoluteBoxHandle[window, bounds]; abs: Window.Place = DisplayOps.AbsPlace[window, place]; newError: INTEGER; bitIndex2, bitIndex3: INTEGER ← abs.x; dashCnt, dashSum: CARDINAL; widths: ARRAY [0..SpecialDisplay.DashCnt) OF CARDINAL; inc1, inc2, inc3, inc4, inc5, inc6: CARDINAL; paint: DisplayOps.Color = DisplayOps.Shade[flags]; fillLength: INTEGER; fillcnt1,fillcnt2,fillFudge1,fillFudge2,fillFudge3,fillFudge4,index: INTEGER; fill: FillHandle; inLeft, outLeft, inRight, outRight, inTop, outTop, inBottom, outBottom: BOOLEAN ← FALSE; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO widths[i] ← dashes.widths[i]; ENDLOOP; inc1 ← 0; inc2 ← widths[0]*10; inc3 ← inc2 + widths[1]*10; inc4 ← inc3 + widths[2]*10; inc5 ← inc4 + widths[3]*10; inc6 ← inc5 + widths[4]*10; FOR r: WindowOps.RecList ← firstRec, r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { int: WindowOps.ScreenBox = [ left: MAX[r.box.left, absBounds.left], right: MIN[r.box.right, absBounds.right], top: MAX[r.box.top, absBounds.top], bottom: MIN[r.box.bottom, absBounds.bottom]]; ctx: Special = WindowOps.GetContext[r, context]; minBitAddress: LONG ORDERED POINTER = LOOPHOLE[ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[int.top], ctx]]; maxBitAddress: LONG ORDERED POINTER = LOOPHOLE[ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[int.bottom - 1],ctx]]; minBitIndex: INTEGER ← MAX[0, int.left]; maxBitIndex: INTEGER ← int.right - 1; IF int.top = int.bottom THEN LOOP; IF filled THEN { minBitIndex ← MAX[0, minBitIndex]; maxBitIndex ← absBounds.right; fillcnt1 ← fillcnt2 ← 0; fillFudge1 ← abs.y - int.top - radius; -- bA1 in fill place fillFudge2 ← fillFudge3 ← abs.y - int.top; -- bA2, bA3 in fill place fillFudge4 ← abs.y - int.top + radius; -- bA4 in fill place fillLength ← int.bottom - int.top; fill ← ctx.alloc[window, int.top, fillLength]; fill.xs[0] ← minBitIndex}; FOR i: CARDINAL IN [0..dashes.thickness) DO -- for thicking error: INTEGER ← (radius - 1)/2; twoxma: INTEGER ← 1; twoymb: INTEGER ← 2*radius - 1; bitAddress1: WindowOps.ScanLine ← LOOPHOLE[ctx.bmAddress + WindowOps.SpecialTimesWpl[ INTEGER[abs.y - radius + i], ctx]]; bitAddress2: WindowOps.ScanLine ← LOOPHOLE[ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[abs.y], ctx]]; bitAddress3: WindowOps.ScanLine ← bitAddress2; bitAddress4: WindowOps.ScanLine ← LOOPHOLE[ctx.bmAddress + WindowOps.SpecialTimesWpl[ INTEGER[abs.y + radius - i], ctx]]; bitIndex1: INTEGER ← abs.x - radius + i; bitIndex4: INTEGER ← abs.x + radius - i; bitIndex2 ← bitIndex3 ← abs.x; IF circleType[0] THEN { bitIndex1 ← bitIndex1 + 1; bitIndex2 ← bitIndex2 + 1}; IF circleType[1] THEN { bitIndex1 ← bitIndex1 - 1; bitIndex2 ← bitIndex2 - 1}; IF circleType[2] THEN { bitIndex3 ← bitIndex3 - 1; bitIndex4 ← bitIndex4 - 1}; IF circleType[3] THEN { bitIndex3 ← bitIndex3 + 1; bitIndex4 ← bitIndex4 + 1}; IF circleType[4] THEN { bitAddress1 ← bitAddress1 + ctx.wpl; bitAddress2 ← bitAddress2 + ctx.wpl; fillFudge1 ← fillFudge1 + 1; fillFudge2 ← fillFudge2 + 1}; IF circleType[5] THEN { bitAddress1 ← bitAddress1 - ctx.wpl; bitAddress2 ← bitAddress2 - ctx.wpl; fillFudge1 ← fillFudge1 - 1; fillFudge2 ← fillFudge2 - 1}; IF circleType[6] THEN { bitAddress3 ← bitAddress3 - ctx.wpl; bitAddress4 ← bitAddress4 - ctx.wpl; fillFudge3 ← fillFudge3 - 1; fillFudge4 ← fillFudge4 - 1}; IF circleType[7] THEN { bitAddress3 ← bitAddress3 + ctx.wpl; bitAddress4 ← bitAddress4 + ctx.wpl; fillFudge3 ← fillFudge3 + 1; fillFudge4 ← fillFudge4 + 1}; dashSum ← inc6 + widths[5]*10; dashCnt ← inc2/2; UNTIL bitIndex3 > bitIndex4 DO IF dashCnt IN [inc1..inc2) OR dashCnt IN [inc3..inc4) -- dashes OR dashCnt IN [inc5..inc6) THEN { inL1: BOOLEAN = L[bitAddress1] IN [minBitAddress..maxBitAddress]; inL2: BOOLEAN = L[bitAddress2] IN [minBitAddress..maxBitAddress]; inL3: BOOLEAN = L[bitAddress3] IN [minBitAddress..maxBitAddress]; inL4: BOOLEAN = L[bitAddress4] IN [minBitAddress..maxBitAddress]; inC1: BOOLEAN = bitIndex1 IN [minBitIndex..maxBitIndex]; inC2: BOOLEAN = bitIndex2 IN [minBitIndex..maxBitIndex]; inC3: BOOLEAN = bitIndex3 IN [minBitIndex..maxBitIndex]; inC4: BOOLEAN = bitIndex4 IN [minBitIndex..maxBitIndex]; IF inL1 AND inC2 THEN -- sector 8 IF filled THEN { index ← fillcnt2 + fillFudge1; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex2} ELSE bitAddress1[bitIndex2] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress1[bitIndex2]); IF inL1 AND inC3 THEN -- sector 1 IF filled THEN { index ← fillcnt2 + fillFudge1; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex3} ELSE bitAddress1[bitIndex3] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress1[bitIndex3]); IF inL2 AND inC1 THEN -- sector 7 IF filled THEN { index ← fillFudge2 - fillcnt1; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex1} ELSE bitAddress2[bitIndex1] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress2[bitIndex1]); IF inL2 AND inC4 THEN -- sector 2 IF filled THEN { index ← fillFudge2 - fillcnt1; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex4} ELSE bitAddress2[bitIndex4] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress2[bitIndex4]); IF inL3 AND inC1 THEN -- sector 6 IF filled THEN { index ← fillFudge3 + fillcnt1; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex1} ELSE bitAddress3[bitIndex1] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress3[bitIndex1]); IF inL3 AND inC4 THEN -- secter 3 IF filled THEN { index ← fillFudge3 + fillcnt1; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex4} ELSE bitAddress3[bitIndex4] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress3[bitIndex4]); IF inL4 AND inC2 THEN -- secter 5 IF filled THEN { index ← fillFudge4 - fillcnt2; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex2} ELSE bitAddress4[bitIndex2] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress4[bitIndex2]); IF inL4 AND inC3 THEN -- sector 4 IF filled THEN { index ← fillFudge4 - fillcnt2; IF index ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[index] ← bitIndex3} ELSE bitAddress4[bitIndex3] ← (SELECT paint FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress4[bitIndex3])}; IF filled THEN fillcnt1 ← fillcnt1 + 1; bitIndex2 ← bitIndex2 - 1; bitIndex3 ← bitIndex3 + 1; bitAddress2 ← bitAddress2 - ctx.wpl; bitAddress3 ← bitAddress3 + ctx.wpl; error ← error + twoxma; dashCnt ← (dashCnt + 10) MOD dashSum; IF ABS[newError ← error - twoymb] < ABS[error] THEN { IF filled THEN fillcnt2 ← fillcnt2 + 1; error ← newError; bitIndex1 ← bitIndex1 + 1; bitIndex4 ← bitIndex4 - 1; bitAddress1 ← bitAddress1 + ctx.wpl; bitAddress4 ← bitAddress4 - ctx.wpl; twoymb ← twoymb - 2; dashCnt ← (dashCnt + 4) MOD dashSum}; twoxma ← twoxma + 2; ENDLOOP; ENDLOOP}; ENDLOOP}; END.