-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved. -- DisplayImplG.mesa - last edited by -- Poskanzer 29-Sep-83 13:05:18 -- Rick 28-Oct-83 15:32:22 -- Daniels 7-Jun-84 14:58:39 DIRECTORY BitBlt USING [BITBLT, BitBltFlags, GrayParm], Display USING [Brick, fiftyPercent], DisplayFormat USING [CircleType], DisplayInternal USING [], DisplayOps USING [AbsPlace, FillList, FillObject, Intersect], Inline USING [DIVMOD], SpecialDisplay USING [defaultContext, LineStyle, Special], Window USING [BoxHandle, Place], WindowOps USING [ AbsoluteBoxHandle, bbPtr, Bounds, GetContext, lock, Object, RecList, ScreenBox, SpecialTimesWpl]; DisplayImplG: MONITOR LOCKS WindowOps.lock IMPORTS BitBlt, DisplayOps, Inline, SpecialDisplay, WindowOps EXPORTS DisplayOps, 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; -- filled circles LineBlt: PROCEDURE [ aLeft, aRight, aY: INTEGER, gray: Display.Brick, flags: BitBlt.BitBltFlags, window: Handle, r: WindowOps.RecList, context: SpecialDisplay.Special ← SpecialDisplay.defaultContext] = BEGIN left: INTEGER = MAX[r.box.left, aLeft]; top: INTEGER = MAX[r.box.top, aY]; right: INTEGER = MIN[r.box.right, aRight + 1]; bottom: INTEGER = MIN[r.box.bottom, aY + 1]; width: INTEGER = right - left; height: INTEGER = bottom - top; ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context]; offset, bit, yOffset: INTEGER; IF width <= 0 OR height <= 0 THEN RETURN; yOffset ← (top - window.place.y) MOD gray.LENGTH; [quotient: offset, remainder: bit] ← Inline.DIVMOD[left, 16]; WindowOps.bbPtr↑ ← [ dst: [ word: ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx] + offset, bit: bit], src: [word: gray.BASE + yOffset, bit: (left - window.place.x) MOD 16], srcDesc: [ gray[ BitBlt.GrayParm[ yOffset: yOffset, widthMinusOne: 0, heightMinusOne: gray.LENGTH - 1]]], dstBpl: ctx.bpl, width: width, height: height, flags: flags]; BitBlt.BITBLT[WindowOps.bbPtr]; END; SpecialFilledCircle: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, radius: INTEGER, gray: Display.Brick, flags: BitBlt.BitBltFlags, circleType: DisplayFormat.CircleType, bounds: Window.BoxHandle, context: Special ← SpecialDisplay.defaultContext] = { ENABLE UNWIND => NULL; firstRec: WindowOps.RecList = DisplayOps.FillList[window, FALSE]; IF gray = Display.fiftyPercent THEN gray ← DESCRIPTOR[fifty]; SpFilledCircleInternal[ firstRec, window, place, radius, gray, flags, circleType, bounds, context]}; fifty: ARRAY [0..2) OF CARDINAL ← [125252B, 52525B]; SpFilledCircleInternal: INTERNAL PROC [ firstRec: WindowOps.RecList, window: Handle, place: Window.Place, radius: INTEGER, gray: Display.Brick, flags: BitBlt.BitBltFlags, circleType: DisplayFormat.CircleType, bounds: Window.BoxHandle, 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 xes are maintained to determine xys in -- all eight octants. Scanlines start top, middle, middle, bottom. xes -- start left, middle, middle, right. All end on the 45s. absBounds: WindowOps.ScreenBox = IF bounds = NIL THEN WindowOps.Bounds[window] ELSE WindowOps.AbsoluteBoxHandle[window, bounds]; abs: Window.Place = DisplayOps.AbsPlace[window, place]; newError: INTEGER; twoRadius: INTEGER ← 2*radius; FOR r: WindowOps.RecList ← firstRec, r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { ctx: Special = WindowOps.GetContext[r, context]; minY: INTEGER = r.box.top; maxY: INTEGER = r.box.bottom - 1; minX: INTEGER = r.box.left; maxX: INTEGER = r.box.right - 1; error: INTEGER ← (radius - 1)/2; twoxma: INTEGER ← 1; twoymb: INTEGER ← 2*radius - 1; y1: INTEGER ← abs.y - radius; y2, y3: INTEGER ← abs.y; y4: INTEGER ← abs.y + radius; x1: INTEGER ← abs.x - radius; x2, x3: INTEGER ← abs.x; x4: INTEGER ← abs.x + radius; UNTIL x3 > x4 DO IF y1 IN [minY..maxY] THEN LineBlt[ MAX[x2, minX], MIN[x3, maxX], y1, gray, flags, window, r, context]; IF y2 IN [minY..maxY] THEN LineBlt[ MAX[x1, minX], MIN[x4, maxX], y2, gray, flags, window, r, context]; IF y3 IN [minY..maxY] THEN LineBlt[ MAX[x1, minX], MIN[x4, maxX], y3, gray, flags, window, r, context]; IF y4 IN [minY..maxY] THEN LineBlt[ MAX[x2, minX], MIN[x3, maxX], y4, gray, flags, window, r, context]; x2 ← x2 - 1; x3 ← x3 + 1; y2 ← y2 - 1; y3 ← y3 + 1; error ← error + twoxma; IF ABS[newError ← error - twoymb] < ABS[error] THEN { error ← newError; x1 ← x1 + 1; x4 ← x4 - 1; y1 ← y1 + 1; y4 ← y4 - 1; twoymb ← twoymb - 2}; twoxma ← twoxma + 2; ENDLOOP}; ENDLOOP}; END.