DIRECTORY Atom, GGBoundBox, GGCaret, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGObjects, GGRefresh, GGSelect, GGShapes, GGTouch, GGTransform, GGUtility, Imager, ImagerBackdoor, ImagerColor, ImagerOps, ImagerPath, ImagerTransformation, Rosary, Rope; GGRefreshImpl: CEDAR PROGRAM IMPORTS Atom, GGBoundBox, GGCaret, GGError, GGGravity, GGObjects, GGSelect, GGShapes, GGTouch, GGTransform, GGUtility, Imager, ImagerBackdoor, ImagerColor, Rope, Rosary EXPORTS GGRefresh = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = GGObjects.BoundBoxGenerator; Camera: TYPE = GGModelTypes.Camera; Caret: TYPE = GGInterfaceTypes.Caret; Cluster: TYPE = GGModelTypes.Cluster; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; JointPair: TYPE = GGModelTypes.JointPair; JointGenerator: TYPE = GGObjects.JointGenerator; Outline: TYPE = GGModelTypes.Outline; Point: TYPE = GGModelTypes.Point; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGModelTypes.Segment; SegmentGenerator: TYPE = GGObjects.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SelectionClass: TYPE = GGInterfaceTypes.SelectionClass; Traj: TYPE = GGModelTypes.Traj; ActionAreaPaint: PUBLIC PROC [dc: Imager.Context, whatToDo: ATOM, gargoyleData: GargoyleData] = { SELECT whatToDo FROM $PaintEntireScene => PaintEntireScene[dc, gargoyleData]; $PaintSelectedRegion => PaintEntireScene[dc, gargoyleData]; $PickUpEntity => {}; $EraseOverlay => EraseOverlay[dc, gargoyleData]; $PaintDragOverlay => PaintDragOverlay[dc, gargoyleData]; $PaintNewAnchor => PaintNewAnchor[dc, gargoyleData]; $PaintSpot => PaintSpot[dc, gargoyleData]; $PaintHitLine => PaintHitLine[dc, gargoyleData]; $PaintTouchPoints => PaintTouchPoints[dc, gargoyleData]; $PaintAlign => PaintAlign[dc, gargoyleData]; $PaintBoundBoxes => PaintBoundBoxes[dc, gargoyleData]; $PaintSelectionBox => PaintSelectionBox[dc, gargoyleData]; ENDCASE => { GGError.Append[ Rope.Cat["Gargoyle GGRefreshImpl doesn't know how to ", Atom.GetPName[whatToDo], "."], oneLiner]; }; }; WorldCoordsContext: PROC [dc: Imager.Context, camera: Camera] = { Imager.TranslateT[dc, [camera.cameraScreen[1], camera.cameraScreen[2]]]; }; DrawCluster: PUBLIC PROC [dc: Imager.Context, cluster: Cluster, gargoyleData: GargoyleData] = { }; DrawOutline: PUBLIC PROC [dc: Imager.Context, outline: Outline, gargoyleData: GargoyleData] = { fence: Traj; fence _ outline.children.first; IF fence.role = fence THEN { FillTraj[dc, fence, outline.fillColor]; }; DrawTraj[dc, fence, gargoyleData]; }; DrawTraj: PUBLIC PROC [dc: Imager.Context, traj: Traj, gargoyleData: GargoyleData] = { seg: Segment; FOR i: INT IN [0..GGObjects.HiSegment[traj]] DO seg _ GGObjects.FetchSegment[traj, i]; Imager.SetStrokeWidth[dc, seg.strokeWidth]; Imager.SetColor[dc, seg.color]; seg.class.maskStroke[dc, seg]; ENDLOOP; Imager.SetStrokeWidth[dc, 1.0]; DrawJoints[dc, traj, gargoyleData]; }; DrawSequence: PUBLIC PROC [dc: Imager.Context, seq: Sequence, gargoyleData: GargoyleData] = { segGen: SegmentGenerator; segGen _ GGObjects.SegmentsInSequence[seq]; FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO Imager.SetStrokeWidth[dc, seg.strokeWidth]; Imager.SetColor[dc, seg.color]; seg.class.maskStroke[dc, seg]; ENDLOOP; Imager.SetStrokeWidth[dc, 1.0]; DrawJointsInSequence[dc, seq, gargoyleData]; }; DrawJoints: PROC [dc: Imager.Context, traj: Traj, gargoyleData: GargoyleData] = { visible: BOOL; joint: Joint; IF GGSelect.IsSelected[traj, gargoyleData, normal] THEN { FOR i: INT IN [0..GGObjects.HiJoint[traj]] DO GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[traj, i]]; ENDLOOP; RETURN; }; visible _ traj.visibleJoints OR traj.outline.onOverlay; FOR i: INT IN [0..GGObjects.HiJoint[traj]] DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; IF GGSelect.IsSelected[joint, gargoyleData, normal] THEN GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[traj, i]] ELSE IF visible THEN GGShapes.DrawJoint[dc, GGObjects.FetchJointPos[traj, i]]; ENDLOOP; }; DrawJointsInSequence: PROC [dc: Imager.Context, seq: Sequence, gargoyleData: GargoyleData] = { visible: BOOL; joint: Joint; jointGen: JointGenerator; jointGen _ GGObjects.JointsInSequence[seq]; IF GGSelect.IsSelected[seq.traj, gargoyleData, normal] THEN { FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[seq.traj, i]]; ENDLOOP; RETURN; }; visible _ seq.traj.visibleJoints OR seq.traj.outline.onOverlay; FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, i]]; IF GGSelect.IsSelected[joint, gargoyleData, normal] THEN GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[seq.traj, i]] ELSE IF visible THEN GGShapes.DrawJoint[dc, GGObjects.FetchJointPos[seq.traj, i]]; ENDLOOP; }; FillTraj: PUBLIC PROC [dc: Imager.Context, traj: Traj, fillColor: Imager.Color] = { BuildPath: Imager.PathProc = { seg: Segment; firstPoint: Point _ GGObjects.FetchJointPos[traj, 0]; moveTo[ [firstPoint[1], firstPoint[2]] ]; FOR i: INT IN [0..GGObjects.HiSegment[traj]] DO seg _ GGObjects.FetchSegment[traj, i]; seg.class.buildPath[seg, lineTo, curveTo, conicTo, arcTo]; ENDLOOP; }; Imager.SetColor[dc, fillColor]; Imager.MaskFill[dc, BuildPath]; }; NotYetImplemented: PUBLIC SIGNAL = CODE; DrawOutlineTransformSeq: PROC [dc: Imager.Context, outline: Outline, selSeq: Sequence, transform: ImagerTransformation.Transformation, gargoyleData: GargoyleData] = { fence: Traj; fence _ outline.children.first; IF fence.role = fence THEN FillTrajTransformSeq[dc, outline.fillColor, selSeq, transform]; FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO IF trajs.first = selSeq.traj THEN DrawTrajTransformSeq[dc, selSeq, transform] ELSE DrawTraj[dc, trajs.first, gargoyleData]; ENDLOOP; }; MaxSegments: NAT = GGModelTypes.MaxSegments; DrawSegArray: TYPE = REF DrawSegArrayObj; DrawSegArrayObj: TYPE = RECORD [ entire: ARRAY [0..MaxSegments-1] OF BOOL, lo: ARRAY [0..MaxSegments-1] OF BOOL, hi: ARRAY [0..MaxSegments-1] OF BOOL ]; arrayPool: ARRAY [0..PoolSize-1] OF DrawSegArray; arrayPoolIndex: NAT; PoolSize: NAT = 3; Init: PROC [] = { FOR i: NAT IN [0..PoolSize) DO arrayPool[i] _ NEW[DrawSegArrayObj]; ENDLOOP; arrayPoolIndex _ 0; }; AllocateDrawSegArray: PROC [] RETURNS [array: DrawSegArray] = { IF arrayPoolIndex = PoolSize THEN ERROR; array _ arrayPool[arrayPoolIndex]; arrayPoolIndex _ arrayPoolIndex + 1; }; ReturnDrawSegArray: PROC [array: DrawSegArray] = { IF arrayPoolIndex = 0 THEN ERROR; arrayPoolIndex _ arrayPoolIndex - 1; arrayPool[arrayPoolIndex] _ array; }; SegAndIndex: TYPE = GGObjects.SegAndIndex; StoreTruthInArrayAboutSequence: PROC [segData: DrawSegArray, selSeq: Sequence] = { start, end, prevSegNum, followSegNum: NAT; segGen: SegmentGenerator; IF selSeq.all THEN ERROR; FOR i: NAT IN [0..GGObjects.HiSegment[selSeq.traj]] DO segData.entire[i] _ FALSE; segData.lo[i] _ FALSE; segData.hi[i] _ FALSE; ENDLOOP; FOR partList: LIST OF JointPair _ selSeq.parts, partList.rest UNTIL partList = NIL DO start _ partList.first.start; end _ partList.first.end; IF NOT(selSeq.traj.role = open AND start = 0) THEN { prevSegNum _ GGObjects.PreviousSegmentNum[selSeq.traj, start]; segData.hi[prevSegNum] _ TRUE; }; segGen _ GGObjects.SegmentsInJointPair[selSeq.traj, start, end]; FOR midSeg: SegAndIndex _ GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL midSeg.seg = NIL DO segData.entire[midSeg.index] _ TRUE; ENDLOOP; IF NOT(selSeq.traj.role = open AND end = GGObjects.HiJoint[selSeq.traj]) THEN { followSegNum _ end; segData.lo[followSegNum] _ TRUE; }; ENDLOOP; }; DrawTrajTransformSeq: PROC [dc: Imager.Context, selSeq: Sequence, transform: ImagerTransformation.Transformation] = { segData: DrawSegArray _ AllocateDrawSegArray[]; seg: Segment; entire, lo, hi: BOOL; StoreTruthInArrayAboutSequence[segData, selSeq]; FOR i: INT IN [0..GGObjects.HiSegment[selSeq.traj]] DO entire _ segData.entire[i]; lo _ segData.lo[i]; hi _ segData.hi[i]; seg _ GGObjects.FetchSegment[selSeq.traj, i]; Imager.SetStrokeWidth[dc, seg.strokeWidth]; seg.class.maskStrokeTransform[dc, seg, transform, entire, lo, hi]; ENDLOOP; ReturnDrawSegArray[segData]; }; FillTrajTransformSeq: PROC [dc: Imager.Context, fillColor: Imager.Color, selSeq: Sequence, transform: ImagerTransformation.Transformation] = { oldColor: Imager.Color _ ImagerBackdoor.GetColor[dc]; segData: DrawSegArray _ AllocateDrawSegArray[]; seg: Segment; BuildPath: Imager.PathProc = { firstPoint: Point; entire, lo, hi: BOOL; lo _ segData.lo[0]; entire _ segData.entire[0]; firstPoint _ GGObjects.FetchJointPos[selSeq.traj, 0]; IF lo OR entire THEN firstPoint _ GGTransform.Transform[transform, firstPoint]; moveTo[ [firstPoint[1], firstPoint[2]] ]; FOR i: INT IN [0..GGObjects.HiSegment[selSeq.traj]] DO entire _ segData.entire[i]; lo _ segData.lo[i]; hi _ segData.hi[i]; seg _ GGObjects.FetchSegment[selSeq.traj, i]; seg.class.buildPathTransform[seg, lineTo, curveTo, conicTo, arcTo, transform, entire, lo, hi]; ENDLOOP; }; StoreTruthInArrayAboutSequence[segData, selSeq]; Imager.SetColor[dc, fillColor]; Imager.MaskFill[dc, BuildPath]; Imager.SetColor[dc, oldColor]; ReturnDrawSegArray[segData]; }; MoveJointsToOverlay: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData] = { gargoyleData.refresh.overlayList _ CONS[traj, gargoyleData.refresh.overlayList]; }; RemoveJointsFromOverlay: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData] = { gargoyleData.refresh.overlayList _ GGUtility.DeleteEntityFromList[traj, gargoyleData.refresh.overlayList]; }; MoveToOverlay: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData] = { parentOutline: Outline; WITH entity SELECT FROM outline: Outline => { IF OnOverlay[outline] THEN ERROR; outline.onOverlay _ TRUE; outline.whyOnOverlay _ outline; gargoyleData.refresh.overlayList _ CONS[outline, gargoyleData.refresh.overlayList]; }; traj: Traj => { parentOutline _ GGObjects.OutlineOfTraj[traj]; IF OnOverlay[parentOutline] THEN ERROR; parentOutline.onOverlay _ TRUE; parentOutline.whyOnOverlay _ traj; gargoyleData.refresh.overlayList _ CONS[parentOutline, gargoyleData.refresh.overlayList]; }; seq: Sequence => { parentOutline _ GGObjects.OutlineOfTraj[seq.traj]; IF OnOverlay[parentOutline] THEN ERROR; parentOutline.onOverlay _ TRUE; parentOutline.whyOnOverlay _ seq; gargoyleData.refresh.overlayList _ CONS[parentOutline, gargoyleData.refresh.overlayList]; }; caret: Caret => { IF OnOverlay[caret] THEN ERROR; GGCaret.TellOnOverlay[caret, TRUE]; gargoyleData.refresh.overlayList _ CONS[caret, gargoyleData.refresh.overlayList]; }; ENDCASE => ERROR NotYetImplemented; }; MoveToBackground: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData] = { IF NOT OnOverlay[entity] THEN RETURN; gargoyleData.refresh.overlayList _ GGUtility.DeleteEntityFromList[entity, gargoyleData.refresh.overlayList]; WITH entity SELECT FROM outline: Outline => outline.onOverlay _ FALSE; caret: Caret => GGCaret.TellOnOverlay[caret, FALSE]; ENDCASE => ERROR NotYetImplemented; }; MoveAllSelectedToOverlay: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] = { entityGen: EntityGenerator; entityGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO MoveToOverlay[entity, gargoyleData]; ENDLOOP; }; MoveOverlayToBackground: PUBLIC PROC [gargoyleData: GargoyleData] = { FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO WITH overlayList.first SELECT FROM outline: Outline => outline.onOverlay _ FALSE; caret: Caret => GGCaret.TellOnOverlay[caret, FALSE]; traj: Traj => {}; -- can only happen if Gargoyle is confused. Normally, trajectories are only added and removed by MoveJointsToOverlay[] and RemoveJointsFromOverlay[], above. ENDCASE => ERROR NotYetImplemented; ENDLOOP; gargoyleData.refresh.overlayList _ NIL; }; EmptyOverlay: PUBLIC PROC [gargoyleData: GargoyleData] RETURNS [BOOL] = { RETURN[gargoyleData.refresh.overlayList = NIL]; }; OnOverlay: PROC [entity: REF ANY] RETURNS [BOOL] = { WITH entity SELECT FROM outline: Outline => RETURN[outline.onOverlay]; caret: Caret => RETURN[GGCaret.IsOnOverlay[caret]]; ENDCASE => ERROR; }; EraseOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; background: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap; chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; IF gargoyleData.refresh.suppressRefresh THEN RETURN; ImagerBackdoor.DrawBits[chunkingContext, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]; }; PaintEntireScene: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; camera: Camera _ gargoyleData.camera; rect: Imager.Rectangle; PaintEntireSceneAux: PROC = { rect _ ImagerBackdoor.GetBounds[chunkingContext]; Imager.SetColor[chunkingContext, Imager.white]; Imager.MaskRectangle[chunkingContext, rect]; WorldCoordsContext[chunkingContext, camera]; DrawObjects[chunkingContext, gargoyleData]; DrawCaret[chunkingContext, gargoyleData.caret, Imager.black]; DrawAnchor[chunkingContext, gargoyleData.anchor, Imager.black]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; IF gargoyleData.refresh.doubleBuffer.state = on THEN { Imager.DoSaveAll[chunkingContext, PaintEntireSceneAux]; ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; } ELSE { rect _ ImagerBackdoor.GetBounds[dc]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; WorldCoordsContext[dc, camera]; DrawObjects[dc, gargoyleData]; DrawCaret[dc, gargoyleData.caret, Imager.black]; DrawAnchor[dc, gargoyleData.anchor, Imager.black]; }; }; PaintSelectedRegion: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; background: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap; camera: Camera _ gargoyleData.camera; boundBox: BoundBox; rect: Imager.Rectangle; PaintSelectedRegionAux: PROC = { ImagerBackdoor.DrawBits[chunkingContext, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]; WorldCoordsContext[chunkingContext, camera]; GGBoundBox.Clip[chunkingContext, boundBox]; rect _ ImagerBackdoor.GetBounds[chunkingContext]; Imager.SetColor[chunkingContext, Imager.white]; Imager.MaskRectangle[chunkingContext, rect]; DrawObjects[chunkingContext, gargoyleData]; DrawCaret[chunkingContext, gargoyleData.caret, Imager.black]; DrawAnchor[chunkingContext, gargoyleData.anchor, Imager.black]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; boundBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData]; IF gargoyleData.refresh.doubleBuffer.state = on THEN { Imager.DoSaveAll[chunkingContext, PaintSelectedRegionAux]; ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; } ELSE { ImagerBackdoor.DrawBits[dc, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]; WorldCoordsContext[dc, camera]; GGBoundBox.Clip[dc, boundBox]; rect _ ImagerBackdoor.GetBounds[dc]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; DrawObjects[dc, gargoyleData]; DrawCaret[dc, gargoyleData.caret, Imager.black]; DrawAnchor[dc, gargoyleData.anchor, Imager.black]; }; }; InterpressEntireScene: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; WorldCoordsContext[dc, camera]; DrawObjects[dc, gargoyleData]; }; StoreBackground: PUBLIC PROC [gargoyleData: GargoyleData] = { PaintAllButSelected: PROC = { camera: Camera _ gargoyleData.camera; scene: Scene _ gargoyleData.scene; rect: Imager.Rectangle; rect _ ImagerBackdoor.GetBounds[gargoyleData.refresh.backgroundContext]; Imager.SetColor[gargoyleData.refresh.backgroundContext, Imager.white]; Imager.MaskRectangle[gargoyleData.refresh.backgroundContext, rect]; Imager.SetColor[gargoyleData.refresh.backgroundContext, Imager.black]; Imager.TranslateT[gargoyleData.refresh.backgroundContext, [camera.cameraScreen[1], camera.cameraScreen[2]]]; FOR entities: LIST OF REF ANY _ gargoyleData.scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM outline: Outline => { IF OnOverlay[outline] THEN LOOP ELSE DrawOutline[gargoyleData.refresh.backgroundContext, outline, gargoyleData]; }; cluster: Cluster => StoreCluster[gargoyleData.refresh.backgroundContext, cluster, gargoyleData]; ENDCASE => ERROR; ENDLOOP; IF NOT OnOverlay[gargoyleData.caret] THEN DrawCaret[gargoyleData.refresh.backgroundContext, gargoyleData.caret, Imager.black]; DrawAnchor[gargoyleData.refresh.backgroundContext, gargoyleData.anchor, Imager.black]; IF gargoyleData.hitTest.linesAlwaysOn.state = on THEN GGGravity.DrawObjectBagRegardless[gargoyleData.refresh.backgroundContext, NARROW[gargoyleData.hitTest.environ], camera, gargoyleData]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; Imager.DoSaveAll[gargoyleData.refresh.backgroundContext, PaintAllButSelected]; }; StoreCluster: PRIVATE PROC [backgroundContext: Imager.Context, cluster: Cluster, gargoyleData: GargoyleData] = { FOR children: LIST OF REF ANY _ cluster.children, children.rest UNTIL children = NIL DO WITH children.first SELECT FROM outline: Outline => { IF OnOverlay[outline] THEN LOOP ELSE DrawOutline[backgroundContext, outline, gargoyleData]; }; cluster: Cluster => StoreCluster[backgroundContext, cluster, gargoyleData]; ENDCASE => ERROR; ENDLOOP; }; PaintDragOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; camera: Camera _ gargoyleData.camera; chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; PaintDragEntitiesAux: PROC = { WorldCoordsContext[chunkingContext, camera]; DrawDragOverlay[chunkingContext, gargoyleData]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; Imager.DoSaveAll[chunkingContext, PaintDragEntitiesAux]; ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; }; DrawDragOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { outline: Outline; IF gargoyleData.hitTest.linesAlwaysOn.state = off THEN GGGravity.DrawObjectBag[dc, NARROW[gargoyleData.hitTest.environ], gargoyleData.camera, gargoyleData]; FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO WITH overlayList.first SELECT FROM outline: Outline => { WITH outline.whyOnOverlay SELECT FROM seq: Sequence => { IF seq.all THEN LOOP; DrawOutlineTransformSeq[dc, outline, seq, gargoyleData.drag.transform, gargoyleData]; }; ENDCASE => {}; }; traj: Traj => DrawJoints[dc, traj, gargoyleData]; caret: Caret => { caret _ NARROW[overlayList.first]; DrawCaret[dc, caret, Imager.black]; }; ENDCASE => ERROR; ENDLOOP; Imager.ConcatT[dc, gargoyleData.drag.transform]; FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO IF ISTYPE[overlayList.first, Outline] THEN { outline _ NARROW[overlayList.first]; WITH outline.whyOnOverlay SELECT FROM seq: Sequence => { IF seq.all THEN DrawOutline[dc, outline, gargoyleData]; }; traj: Traj => ERROR; outline: Outline => DrawOutline[dc, outline, gargoyleData]; cluster: Cluster => DrawCluster[dc, cluster, gargoyleData]; ENDCASE => ERROR; }; ENDLOOP; }; DrawObjects: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { scene: Scene _ gargoyleData.scene; Imager.SetColor[dc, Imager.black]; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM outline: Outline => DrawOutline[dc, outline, gargoyleData]; cluster: Cluster => ERROR; ENDCASE => ERROR; ENDLOOP; }; DrawCaret: PROC [dc: Imager.Context, caret: Caret, color: Imager.Color] = { caretPos: Point _ GGCaret.GetPoint[caret]; IF NOT GGCaret.Exists[caret] THEN RETURN; Imager.SetColor[dc, color]; GGShapes.DrawCaret[dc, caretPos]; }; DrawAnchor: PROC [dc: Imager.Context, caret: Caret, color: Imager.Color] = { caretPos: Point _ GGCaret.GetPoint[caret]; IF NOT GGCaret.Exists[caret] THEN RETURN; Imager.SetColor[dc, color]; GGShapes.DrawAnchor[dc, caretPos]; }; PaintNewAnchor: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; anchorPos: Point _ GGCaret.GetPoint[gargoyleData.anchor]; Imager.SetColor[dc, Imager.black]; WorldCoordsContext[dc, camera]; GGShapes.DrawAnchor[dc, anchorPos]; }; PaintSpot: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; Imager.SetColor[dc, Imager.black]; WorldCoordsContext[dc, camera]; GGShapes.DrawSpot[dc, gargoyleData.refresh.spotPoint]; }; PaintHitLine: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; Imager.SetColor[dc, Imager.black]; WorldCoordsContext[dc, camera]; Imager.MaskVector[dc, [gargoyleData.refresh.spotPoint[1], gargoyleData.refresh.spotPoint[2]], [gargoyleData.refresh.hitPoint[1], gargoyleData.refresh.hitPoint[2]]]; GGShapes.DrawFilledRect[dc, gargoyleData.refresh.spotPoint, 3.0]; }; PaintAlign: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; Imager.SetColor[dc, ImagerColor.ColorFromGray[0.5]]; WorldCoordsContext[dc, camera]; GGGravity.DrawObjectBagRegardless[dc, NARROW[gargoyleData.hitTest.environ], camera, gargoyleData]; }; PaintTouchPoints: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { WorldCoordsContext[dc, gargoyleData.camera]; GGTouch.DrawAllTouchPoints[dc, gargoyleData]; }; PaintBoundBoxes: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { bBoxGen: BoundBoxGenerator; camera: Camera _ gargoyleData.camera; PaintBoundBoxesAux: PROC = { WorldCoordsContext[dc, camera]; bBoxGen _ GGObjects.BoundBoxesInScene[gargoyleData.scene]; FOR box: BoundBox _ GGObjects.NextBox[bBoxGen], GGObjects.NextBox[bBoxGen] UNTIL box = NIL DO GGBoundBox.DrawBoundBox[dc, box]; ENDLOOP; }; Imager.DoSaveAll[dc, PaintBoundBoxesAux]; }; PaintSelectionBox: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; box: BoundBox; PaintSelectionBoxAux: PROC = { WorldCoordsContext[dc, camera]; box _ GGBoundBox.BoundBoxOfSelected[gargoyleData]; GGBoundBox.DrawBoundBox[dc, box]; }; Imager.DoSaveAll[dc, PaintSelectionBoxAux]; }; EraseAll: PROC [dc: Imager.Context] = { rect: Imager.Rectangle; rect _ ImagerBackdoor.GetBounds[dc]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; }; Init[]; END. ZGGRefreshImpl.mesa Last edited by Bier on November 7, 1985 11:42:13 pm PST Contents: All painting actions in Gargoyle are called thru this interface. whatToDo will be an atom describing a painting action such as $EraseControlPoint, $PaintControlPoint, $EraseAllControlPoints, $EraseAll, $PaintEntireScene, or $PaintTrajectory. A pointer to the particular object to be repainted will be stored in gargoyleData for now. We envision a scheme where Dispatch may actually queue up painting jobs and attempt optimizations on the queue. Dragging Debugging Drawing Trajectories This won't work right when outlines have holes. Otherwise, fence.role = open in which case filling is inappropriate. Initialize. DrawTrajTransformSeqClosed: PROC [dc: Imager.Context, traj: Traj, start, end: NAT, transform: ImagerTransformation.Transformation] = { lo, hi: BOOL; seg: Segment; FOR i: INT IN [0..GGObjects.HiSegment[traj]] DO lo _ GGObjects.InMODRegion[i, start, end, traj.segCount]; hi _ GGObjects.InMODRegion[ (i+1) MOD traj.segCount, start, end, traj.segCount]; seg _ GGObjects.FetchSegment[traj, i]; Imager.SetStrokeWidth[dc, seg.strokeWidth]; seg.class.maskStrokeTransform[dc, seg, transform, lo, hi]; ENDLOOP; }; For each segment, we must determine (with respect to selSeq) whether it is: 1) Unselected. (entire = FALSE, lo = FALSE, hi = FALSE) 2) One endpoint selected. (entire = FALSE, lo = TRUE, hi = FALSE) or vice-versa. 3) Both endpoints selected. (entire = FALSE, lo = TRUE, hi = TRUE) 4) Selected in entirety. (entire = TRUE, lo = X, hi = X). The Overlay Plane Painting Commands Do no actual drawing. Send the background bits to the chunking bitmap and wait for a call to PaintDragEntities. Erase viewer first. Draw the objects. Now, dump on the screen. Erase viewer first. Draw the objects. Draw the background. Set up world coordinates and clip. Erase the region first. Draw the objects. Now, dump on the screen. Set up world coordinates and clip. Erase the region first. Draw the objects. Draw all but the overlay objects into a bitmap. Erase the bitmap. Draw most of the scene. Worry about scene objects. Worry about the caret. Worry about alignment lines. PaintOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { Write the foreground shapes onto the chunking bitmap and then dump the chunking bitmap onto the screen. The result is double-buffered motion. chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; camera: Camera _ gargoyleData.camera; chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; PaintOverlayAux: PROC = { WorldCoordsContext[chunkingContext, camera]; DrawOverlay[chunkingContext, gargoyleData]; }; Imager.DoSaveAll[chunkingContext, PaintOverlayAux]; Now, dump on the screen. ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; }; Write the foreground shapes onto the chunking bitmap and then dump the chunking bitmap onto the screen. The result is double-buffered motion. Now, dump on the screen. DrawOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { Simply draw all overlay objects right where they are. FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO WITH overlayList.first SELECT FROM seq: Sequence => {}; traj: Traj => DrawJoints[dc, traj]; outline: Outline => DrawOutline[dc, outline]; cluster: Cluster => DrawCluster[dc, cluster]; caret: Caret => DrawCaret[dc, caret, Imager.black]; ENDCASE => ERROR; ENDLOOP; And also draw object bag if it is "on overlay". IF gargoyleData.hitTest.linesAlwaysOn.state = off THEN GGGravity.DrawObjectBag[dc, NARROW[gargoyleData.hitTest.environ], gargoyleData.camera]; }; This could use some optimizing. Draw object bag if it is "on overlay". Handle rubberbanding first. Draw the outline to which the selected sequence belongs. Within the trajectory of interest, individually transform each of the selected points. Now handle the dragging cases. The common core of PaintEntireScene and InterpressEntireScene. Debugging Draw the boxes. Draw the box. ΚΏ˜Ihead1™J™7J™KJ™šΟk ˜ J˜J˜ J˜J˜J˜ J˜J˜ J˜ Jšœ ˜ J˜ J˜ J˜J˜ J˜ Jšœ˜Jšœ˜J˜ J˜ J˜ J˜J˜Jšœ˜J˜—šœœ˜Jšœ‘˜¨Jšœ ˜—Jš˜J˜Jšœ œ˜'Jšœœ˜6Jšœœ˜#Jšœœ˜%Jšœ œ˜%Jšœœ ˜5Jšœœ!˜3Jšœœ˜!Jšœ œ˜)Jšœœ˜0Jšœ œ˜%Jšœœ˜!Jšœœ˜!Jšœ œ˜%Jšœœ˜4Jšœ œ˜'Jšœœ#˜7Jšœœ˜˜J˜—šΟnœœœ œ!˜aJšœŒ™ŒJšœo™oJšœ ˜Jšœ8˜8šœ;˜;J™—Jšœ˜Jšœ0˜0Jšœ8˜8šœ4˜4J™ —Jšœ*˜*Jšœ0˜0Jšœ8˜8Jšœ,˜,Jšœ6˜6Jšœ:˜:šœ˜ šœ˜šœ7˜7Jšœ˜—Jšœ ˜ —J˜—J˜J˜—šžœœ)˜AIprocšœ$ΟuœŸœ˜HL˜J˜—™J˜—J˜šž œœœG˜_J˜—J˜šž œœœG˜_Jšœ ˜ Jšœ˜šœœ˜Jšœ'˜'J˜—Jšœ"˜"J˜J˜—šžœ œA˜VJ˜ šœœœ ˜/Jšœ&˜&Jšœ+˜+Jšœ˜Jšœ˜—Jšœ˜Jšœ˜Jšœ#˜#J˜J˜—šž œ œD˜]J˜Jšœ+˜+šœ_˜bJšœ+˜+Jšœ˜Jšœ˜—Jšœ˜Jšœ˜Jšœ,˜,J˜J˜—šž œœB˜RJšœ œ˜J˜ šœ1œ˜9šœœœ˜-JšœA˜A—Jšœ˜Jšœ˜J˜—Jšœœ˜7šœœœ˜-Jšœœ˜-Jšœ2œA˜yJšœœ œ:˜N—Jšœ˜J˜J˜—šžœœE˜_Jšœ œ˜J˜ J˜Jšœ+˜+šœ5œ˜=šœœ@œ˜YJšœE˜E—Jšœ˜Jšœ˜J˜—Jšœ!œ˜?šœœ@œ˜YJšœœ#˜1Jšœ2œE˜}Jšœœ œ>˜R—Jšœ˜J˜J˜J˜—šžœœœ>˜Sšœ˜J˜ Jšœ5˜5Jšœ)˜)šœœœ ˜/Jšœ&˜&Jšœ:˜:—Jšœ˜J˜—Jšœ˜Jšœ˜J˜J˜—Jšœœœœ˜(J˜šžœœ‰˜¦J™/Jšœ ˜ Jšœ˜šœœ@˜ZJ™D—š œœœ%œ œ˜KJšœœ,˜MJšœ)˜-—Jšœ˜J˜˜J˜——Jšœ œ˜,Jšœœœ˜)šœœœ˜ Jšœœœœ˜)Jšœœœœ˜%Jšœœœ˜$J˜—Jšœ1˜1J˜Jšœ˜šžœœ˜šœœœ˜Jšœœ˜$—Jšœ˜J˜J˜J˜—šžœœœ˜?Jšœœœ˜(Jšœ"˜"Jšœ$˜$J˜J˜—šžœœ˜2Jšœœœ˜!Jšœ$˜$Jšœ"˜"Jšœ˜Jšœ˜—Jšœ œ˜*šžœœ.˜RJ™ Jšœ&œ˜*J˜Jšœ œœ˜šœœœ'˜6Jšœœ˜Jšœœ˜Jšœœ˜—Jšœ˜š œ œœ)œ œ˜UJšœ˜Jšœ˜šœœœ œ˜4Jšœ>˜>Jšœœ˜J˜—Jšœ@˜@šœdœœ˜€Jšœœ˜$—Jšœ˜šœœœ'œ˜OJšœ˜Jšœœ˜ J˜——Jšœ˜J˜J˜—šžœœf™†Jšœœ™ J™ šœœœ ™/Jšœ:™:Jšœ"œ+™PJšœ&™&Jšœ+™+Jšœ:™:—Jšœ™J™J™—J˜šžœœ[˜uJ™KJ™˜cJ˜JšœA˜Aš œ œœDœ œ˜lJšœ$˜$—Jšœ˜J˜J˜—šžœœœ!˜Ešœœœœœ6œœ˜pJšœœ˜"Jšœ(œ˜.Jšœ-œ˜4JšœΟc˜―Jšœœ˜#—Jšœ˜Jšœ#œ˜'˜J˜——š ž œœœœœ˜IJšœ$œ˜/J˜J˜—š ž œœ œœœœ˜4Jšœœ˜Jšœœ˜.Jšœœ˜3Jšœœ˜J˜J˜—J˜J™J™šž œœ5˜GLšœp™pLšœ%˜%LšœJ˜JLšœG˜GJšœ&œœ˜4Jšœ”˜”J˜J˜—šžœœœ5˜RLšœG˜GLšœL˜LLšœ%˜%Jšœ˜šžœœ˜J™Jšœ1˜1Jšœ/˜/šœ,˜,J™—Lšœ,˜,Jšœ+˜+Jšœ=˜=Jšœ?˜?L˜—Lšœ&œœ˜4šœ.œ˜6šœ7˜7L™—Jšœ›˜›J˜—šœ˜J™Jšœ$˜$Jšœ"˜"šœ˜J™—Lšœ˜Jšœ˜Jšœ0˜0Jšœ2˜2J˜—˜L˜——šžœœœ5˜ULšœG˜GLšœL˜LLšœJ˜JLšœ%˜%Lšœ˜Jšœ˜šžœœ˜ J™šœ”˜”L™"—Lšœ,˜,šœ+˜+J™—Jšœ1˜1Jšœ/˜/šœ,˜,J™—Jšœ+˜+Jšœ=˜=Jšœ?˜?L˜—Lšœ&œœ˜4Lšœ7˜7šœ.œ˜6šœ:˜:L™—Jšœ›˜›J˜—šœ˜šœ‡˜‡L™"—Lšœ˜˜J™—Jšœ$˜$Jšœ"˜"šœ˜J™—Jšœ˜Jšœ0˜0Jšœ2˜2J˜—˜L˜——šžœœœ5˜WLšœ%˜%Lšœ˜Jšœ˜J˜J˜—šžœœœ!˜=J™/šžœœ˜Lšœ%˜%Lšœ"˜"šœ˜J™—JšœH˜HJšœF˜FšœC˜CL™—JšœF˜FšœHŸœŸœ˜lL™—šœ œœœœ.œ œ˜bLšœœ˜˜Lšœœ˜LšœL˜PL˜—Lšœ`˜`Lšœœ˜—šœ˜J™—JšœœœU˜~šœV˜VJ™—šœ5˜5LšœJœ6˜†—L˜—Lšœ&œœ˜4LšœN˜NL˜J˜L˜—šž œ œV˜pšœ œœœœ#œ œ˜WLšœœ˜˜Lšœœ˜Lšœ7˜;L˜—LšœK˜KLšœœ˜—Lšœ˜˜L˜—J™—J˜šž œœ5™GL™ŽLšœL™LLšœ%™%LšœG™Gšžœœ™Lšœ,™,Jšœ+™+J™—šœ3™3L™—Jšœ›™›J™J™—šžœœ5˜KL™ŽLšœL˜LLšœ%˜%LšœG˜Gšžœœ˜Lšœ,˜,Jšœ/˜/J˜—Lšœ&œœ˜4šœ8˜8L™—Jšœ›˜›J˜J˜—J˜šž œœ5™FJ™5šœœœœœ6œœ™pJšœœ™"Jšœ™J™#Jšœ-™-Jšœ-™-J™3Jšœœ™—šœ™J™/—šœ0™6Jšœœ5™W—J™J™—šžœœ5˜JJ™šœ˜J™&—šœ0˜6JšœœC˜eJ™—šœœœœœ6œœ˜pJšœœ˜"šœ˜Jšœœ˜%˜J™J˜Jšœ7Οbœ˜UJ˜—Jšœ˜J˜—Jšœ1˜1šœ˜Jšœœ˜"Jšœ#˜#J˜—Jšœœ˜—šœ˜J™—Lšœ ‘œ˜0šœœœœœ6œœ˜pšœœœ˜,Jšœ œ˜$Jšœœ˜%šœ˜Jšœ œ(˜7Jšœ˜—Jšœœ˜Jšœ;˜;Jšœ;˜;Jšœœ˜J˜——Jšœ˜J˜J˜—šž œœ5˜FJšœžœ™>Lšœ"˜"Jšœ"˜"šœ œœœœ!œ œ˜ULšœœ˜Lšœ;˜;Lšœœ˜Lšœœ˜—Lšœ˜J˜J˜—J™šž œœ<˜KLšœ*˜*Lšœœœœ˜)Jšœ˜Jšœ!˜!J˜—J˜šž œœ<˜LLšœ*˜*Lšœœœœ˜)Jšœ˜Jšœ"˜"J˜J˜—J™J™ J˜šžœœ5˜IJšœ%˜%Jšœ9˜9Jšœ"˜"Lšœ˜Lšœ#˜#L˜L˜—šž œœ5˜DJšœ%˜%Jšœ"˜"Lšœ˜Lšœ6˜6L˜L˜—šž œœ5˜GJšœ%˜%Jšœ"˜"Lšœ˜Lšœ€˜€LšœA˜AL˜L˜—šž œœ5˜EJšœ%˜%Jšœ4˜4Lšœ˜Lšœ&œ6˜bL˜J˜—šžœœ5˜KLšœ,˜,Lšœ-˜-L˜J˜J˜—šžœœ5˜JL˜Lšœ%˜%šžœœ˜J™Lšœ˜Lšœ:˜:šœHœœ˜]Lšœ!˜!—Lšœ˜L˜—Lšœ)˜)L˜L˜—šžœœœ5˜SLšœ%˜%Lšœ˜šžœœ˜J™ Lšœ˜Lšœ2˜2Lšœ!˜!L˜—Lšœ+˜+L˜J˜J˜—J™šžœœ˜'Jšœ˜Jšœ$˜$Jšœ"˜"Jšœ˜J˜J˜—˜J˜—Jšœ˜J˜—…—[Jƒc