SVRefreshImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on February 2, 1987
Contents: All painting actions in Solidviews are called thru this interface.
DIRECTORY
Atom, BufferedRefresh, CodeTimer, CoordSys, SVGraphics, DisplayListToTree, Feedback, GList, Imager, ImagerPath, ImagerTransformation, Matrix3d, Preprocess3d, PriorityQueue, Real, Rope, SV2d, SV3d, SVAssembly, SVBasicTypes, SVBoundBox, SVCaret, SVDraw3d, SVFiles, SVImage, SVInterfaceTypes, SVModelTypes, SVRayTypes, SVRefresh, SVScene, SVSceneTypes, SVSelect, SVSelections, SVUtility;
SVRefreshImpl: CEDAR PROGRAM
IMPORTS Atom, BufferedRefresh, CodeTimer, CoordSys, SVGraphics, DisplayListToTree, Feedback, GList, Imager, ImagerTransformation, Matrix3d, Preprocess3d, PriorityQueue, Rope, SVAssembly, SVBoundBox, SVCaret, SVDraw3d, SVFiles, SVImage, SVScene, SVSelect, SVSelections, SVUtility
EXPORTS SVRefresh =
BEGIN
ArtworkToolData: TYPE = SVInterfaceTypes.ArtworkToolData;
Slice: TYPE = SVSceneTypes.Slice;
AssemblyGenerator: TYPE = SVScene.AssemblyGenerator;
SliceList: TYPE = SVSceneTypes.SliceList;
BoundBox: TYPE = SVBasicTypes.BoundBox;
Camera: TYPE = SVModelTypes.Camera;
Color: TYPE = Imager.Color;
CoordSysGenerator: TYPE = SVScene.CoordSysGenerator;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
CSGTree: TYPE = SVRayTypes.CSGTree;
EditToolData: TYPE = SVInterfaceTypes.EditToolData;
FrameBox: TYPE = SVModelTypes.FrameBox;
Matrix4by4: TYPE = SVModelTypes.Matrix4by4;
PlanarSurface: TYPE = SVSceneTypes.PlanarSurface;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
Rectangle: TYPE = Imager.Rectangle;
Sandwich: TYPE = BufferedRefresh.Sandwich;
Scene: TYPE = SVSceneTypes.Scene;
Selection: TYPE = SVInterfaceTypes.Selection;
SelectionClass: TYPE = SVSelect.SelectionClass;
SelectionGenerator: TYPE = SVInterfaceTypes.SelectionGenerator;
SelectionType: TYPE = SVInterfaceTypes.SelectionType; -- {target, movee, plane};
Shape: TYPE = SVSceneTypes.Shape;
SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = SVSceneTypes.SliceDescriptorGenerator;
SliceParts: TYPE = SVSceneTypes.SliceParts;
ToolData: TYPE = SVSceneTypes.ToolData;
SVData: TYPE = SVInterfaceTypes.SVData;
CreateSandwich: PUBLIC PROC [] RETURNS [sandwich: Sandwich] = {
sandwich ← BufferedRefresh.CreateSandwich[LIST[
[$Background, TRUE, RefreshBackground], -- back ...
[$Overlay, FALSE, RefreshOverlay],
[$SelectionPlane, FALSE, RefreshSelectionPlane],
[$SkitterPlane, FALSE, RefreshSkitterPlane]]]; -- ... to front
};
ActionAreaPaint: PUBLIC PROC [screen: Imager.Context, whatHasChanged: ATOM, svData: SVData] = {
DoActionAreaPaint[screen, whatHasChanged, svData];
};
DoActionAreaPaint: PROC [screen: Imager.Context, whatHasChanged: ATOM, svData: SVData] = {
whatHasChanged will be an atom describing some change which has occurred to the viewable scene state, such as $CaretMoved, $OverlayMoved, $ObjectAdded, $SelectionChanged, or $Everything. A pointer to the particular objects to be repainted will be stored in svData for now.
We envision a scheme where Dispatch may actually queue up painting jobs and attempt optimizations on the queue. In this case, the objects to be repainted will have to be stored separately from the svData.
showColors: BOOL;
IF svData.refresh.suppressRefresh THEN RETURN;
showColors ← NOT svData.doubleBuffer;
SELECT whatHasChanged FROM
$None => NULL;
$FrameChanged => PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
$DrawPlane => PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
$PaintEntireScene => PaintEntireScene[screen, svData, showColors];
$ViewersPaintEntireScene => PaintEntireScene[screen, svData, showColors];
$SelectionChanged => SelectionOrCaretChanged[screen, svData, showColors];
$FinishedDragging => FinishedDragging[screen, svData, showColors];
$SkitterMoved => SelectionOrCaretChanged[screen, svData, showColors];
$AnchorAdded => PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
$AnchorRemoved => PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
Dragging
$DuringMotion => PaintDragOverlay[screen, svData, TRUE, showColors];
$DuringSkitterPos => PaintDragOverlay[screen, svData, FALSE, showColors];
$DuringSelect => DuringSelect[screen, svData, showColors];
$ObjectChangedInPlace => ObjectChangedInPlace[screen, svData, normal];
$ObjectChangedBoundBoxProvided => PaintEntireScene[screen, svData, showColors];
$ObjectAdded => PaintEntireScene[screen, svData, showColors];
Debugging and Draw Directly on the Screen
$DrawBlackAndWhite => DrawBlackAndWhite[screen, svData];
$DrawColor => DrawColor[screen, svData];
$DrawCoordSystems => DrawCoordSystems[screen, svData];
$DrawBoundBoxes => DrawBoundBoxes[screen, svData];
$DrawBoundSpheres => DrawBoundSpheres[screen, svData];
$DrawRayCastProgress => DrawRayCastProgress[screen, svData];
$DrawCrossHairs => DrawCrossHairs[screen, svData];
$DrawPt => DrawPt[screen, svData];
$DrawPaint => DrawPaint[screen, svData];
$DrawCatScan => DrawCatScan[screen, svData];
$PaintSpot => PaintSpot[screen, svData];
$PaintHitLine => PaintHitLine[screen, svData];
ENDCASE => {
Feedback.Append[svData.feedback, Rope.Cat["SVRefreshImpl doesn't know how to ", Atom.GetPName[whatHasChanged], "."], oneLiner];
Feedback.Blink[svData.feedback];
};
};
DrawRayCastProgress: PROC [screen: Imager.Context, svData: SVData] = {
camera: Camera ← svData.camera;
width: REAL ← 10;
box: Imager.Rectangle;
lowLeft, upRight: Point2d;
currentY, minX, minY, maxX, maxY: REAL;
currentY ← svData.refresh.currentY;
minX ← svData.refresh.minX;
minY ← svData.refresh.minY;
maxX ← svData.refresh.maxX;
maxY ← svData.refresh.maxY;
lowLeft ← CoordSys.CameraToScreen[[minX, minY], camera.screenCS];
upRight ← CoordSys.CameraToScreen[[maxX, currentY], camera.screenCS];
box ← [lowLeft[1], lowLeft[2], upRight[1] - lowLeft[1], upRight[2] - lowLeft[2]];
Imager.SetColor[screen, Imager.black];
Imager.MaskRectangle[screen, box];
};
PaintEntireScene: PROC [screen: Imager.Context, svData: SVData, showColors: BOOL] = {
sandwich: BufferedRefresh.Sandwich ← svData.refresh.sandwich;
CodeTimer.StartInt[$PaintEntireScene, $Solidviews];
BufferedRefresh.SetLayerOK[sandwich, $Background, FALSE];
BufferedRefresh.SetLayerOK[sandwich, $SkitterPlane, FALSE];
PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
CodeTimer.StopInt[$PaintEntireScene, $Solidviews];
};
PaintAllPlanes: PROC [screen: Imager.Context, svData: SVData, showColors: BOOL, caretIsMoving: BOOL, dragInProgress: BOOL] = {
sandwich: BufferedRefresh.Sandwich ← svData.refresh.sandwich;
clientToViewer, viewerToClient: Imager.Transformation;
ignoreBackingMap: BOOL;
IF svData.refresh.suppressRefresh THEN RETURN;
svData.refresh.caretIsMoving ← caretIsMoving;
svData.refresh.dragInProgress ← dragInProgress;
clientToViewer ← viewerToClient ← ImagerTransformation.Scale[1.0];
ignoreBackingMap ← showColors;
BufferedRefresh.DrawSandwich[sandwich, screen, clientToViewer, viewerToClient, svData, ignoreBackingMap];
};
Single-Plane Commands
RefreshBackground: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
svData: SVData ← NARROW[clientData];
camera: Camera ← svData.camera;
lo, hi: Point2d;
lo ← [boundRect.x, boundRect.y]; -- in screen coords
hi ← [boundRect.x + boundRect.w, boundRect.y + boundRect.h];
lo ← CoordSys.ScreenToCamera[lo, camera.screenCS];
hi ← CoordSys.ScreenToCamera[hi, camera.screenCS];
DrawObjectsFiltered[dc, svData, SVBoundBox.BoundBoxFromValues[lo[1], lo[2], hi[1], hi[2]], FALSE, -Real.LargestNumber];
};
RefreshOverlay: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
This could use some optimizing.
DrawDragOverlayAux: PROC = {
IF svData.refresh.orderedOverlayList=NIL THEN svData.refresh.orderedOverlayList ← OrderOverlayList[svData]; -- update ordered list
SELECT camera.style FROM
wire, normals => {
FOR list: LIST OF SliceDescriptor ← svData.refresh.orderedOverlayList, list.rest UNTIL list = NIL DO
SVAssembly.DrawTransform[list.first, dc, scene, camera, svData.drag.transform];
ENDLOOP;
};
shaded => {
predictedBufferSize: NAT ← CountSurfacesInAssembly[scene.assembly];
polygonBuffer: PriorityQueue.Ref ←
PriorityQueue.Predict[predictedBufferSize, DeeperPlanarPolygon];
FOR list: LIST OF SliceDescriptor ← svData.refresh.orderedOverlayList, list.rest UNTIL list = NIL DO
IF NOT SVBoundBox.OutsideOf[SVAssembly.GetBoundBox[list.first.slice, NIL, camera], filter] THEN SVAssembly.AddPolygonsToBufferTransform[polygonBuffer, list.first, scene, camera, svData.drag.transform];
ENDLOOP;
SVAssembly.DrawBuffer[dc, polygonBuffer, scene, camera];
};
ENDCASE => ERROR;
};
svData: SVData ← NARROW[clientData];
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
filter: BoundBox ← SVBoundBox.BoundBoxFromRectangle[boundRect, camera];
IF svData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[dc, DrawDragOverlayAux];
};
RefreshSelectionPlane: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
svData: SVData ← NARROW[clientData];
camera: Camera ← svData.camera;
scene: Scene ← svData.scene;
caretIsMoving: BOOL ← svData.refresh.caretIsMoving;
dragInProgress: BOOL ← svData.refresh.dragInProgress;
IF svData.refresh.suppressRefresh THEN RETURN;
IF svData.camera.quality#quality THEN
Imager.SetColor[dc, Imager.black];
IF caretIsMoving OR dragInProgress THEN RETURN;
IF svData.showCoordSys THEN
DrawCoordSystems[dc, svData];
DrawAnySelectionsDCAux[dc, movee, svData, scene, camera];
DrawAnySelectionsDCAux[dc, target, svData, scene, camera];
DrawAnySelectionsDCAux[dc, plane, svData, scene, camera];
DrawCpsOfSelectedSlices[dc, scene, camera, dragInProgress, caretIsMoving];
};
RefreshSkitterPlane: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
svData: SVData ← NARROW[clientData];
camera: Camera ← svData.camera;
Imager.SetColor[dc, Imager.black];
DrawSkitter[dc, svData.editToolData, camera];
DrawAnchor[dc, svData, camera];
};
Drawing Utilities
DrawCpsOfSelectedSlices: PROC [dc: Imager.Context, scene: Scene, camera: Camera, dragInProgress, caretIsMoving: BOOL] = {
normalSliceD, hotSliceD: SliceDescriptor;
normalParts, hotParts: SliceParts;
slice: Slice;
IF caretIsMoving OR dragInProgress THEN RETURN;
FOR sList: LIST OF Slice ← AllSelectedSlices[scene], sList.rest UNTIL sList=NIL DO
slice ← sList.first;
normalSliceD ← SVSelect.FindSelectedSlice[slice, scene, normal];
hotSliceD ← SVSelect.FindSelectedSlice[slice, scene, hot];
normalParts ← IF normalSliceD # NIL THEN normalSliceD.parts ELSE NIL;
hotParts ← IF hotSliceD # NIL THEN hotSliceD.parts ELSE NIL;
SVAssembly.DrawSelectionFeedback[slice, normalParts, hotParts, dc, camera, dragInProgress, caretIsMoving, FALSE, caretIsMoving];
ENDLOOP;
};
AllSelectedSlices: PROC [scene: Scene] RETURNS [selectedList: LIST OF Slice ← NIL] = {
Puts all the selected (hot & normal) slices in a list, and returns them
ptr: LIST OF Slice;
sGen: SliceDescriptorGenerator ← SVSelect.SelectedSlices[scene, hot];
[selectedList, ptr] ← SVUtility.StartSliceList[];
FOR sd: SliceDescriptor ← SVSelect.NextSliceDescriptor[sGen], SVSelect.NextSliceDescriptor[sGen] UNTIL sd = NIL DO
[selectedList, ptr] ← SVUtility.AddSlice[sd.slice, selectedList, ptr];
ENDLOOP;
sGen ← SVSelect.SelectedSlices[scene, normal];
FOR sd: SliceDescriptor ← SVSelect.NextSliceDescriptor[sGen], SVSelect.NextSliceDescriptor[sGen] UNTIL sd = NIL DO
IF NOT SVSelect.IsSelectedInPart[sd.slice, scene, hot] THEN [selectedList, ptr] ← SVUtility.AddSlice[sd.slice, selectedList, ptr];
ENDLOOP;
};
DrawAnySelectionsDCAux: PROC [dc: Imager.Context, selType: SelectionType, svData: SVData, scene: Scene, camera: Camera] = {
For each selection, If the selected object is a hook or a floater, complement the jack and then draw the selection. If a coordinate system, just draw selection.
g: SelectionGenerator;
selectionsExist: BOOL;
[g, selectionsExist] ← SVSelections.GetSelectionGenerator[selType];
IF NOT selectionsExist THEN RETURN;
FOR sel: Selection ← SVSelections.NextSelection[g], SVSelections.NextSelection[g] UNTIL sel = NIL DO
IF sel.svData = svData THEN {
DrawSelectionDC[dc, sel, svData];
};
ENDLOOP;
};
DrawSelectionDC: PROC [dc: Imager.Context, sel: Selection, svData: SVData] = {
DrawSelectionDCAux: SAFE PROC = {
Imager.SetColor[dc, Imager.black];
SELECT sel.selectionType FROM
target => {
csCAMERA: Matrix4by4;
csCAMERA ← CoordSys.WRTCamera[sel.coincident.coordSys, camera.coordSys];
SVDraw3d.DrawTargetCoordSys[dc, csCAMERA, camera];
};
movee => SVDraw3d.DrawMovee[dc, sel.coincident.coordSys, camera];
plane => {
toolData: ToolData;
planeAssem: Slice;
planeAssem ← sel.coincident;
IF planeAssem.toolMasterObject = NIL OR planeAssem.toolMasterObject.mainBody = NIL THEN ERROR;
toolData ← NARROW[planeAssem.toolMasterObject.mainBody];
SVDraw3d.DrawPlaneSelection[dc, sel.coincident.coordSys, toolData.plane, camera];
};
ENDCASE => ERROR;
};
camera: Camera;
IF svData # sel.svData THEN RETURN;
camera ← svData.camera;
Imager.DoSave[dc, DrawSelectionDCAux];
};
DrawSkitter: PROC [dc: Imager.Context, editToolData: EditToolData, camera: Camera] = {
skitterWORLD, skitterCAMERA: Matrix4by4;
IF NOT SVSelections.IsAliveSkitter[editToolData] THEN RETURN;
[----, skitterWORLD] ← SVSelections.GetPositionSkitter[editToolData];
skitterCAMERA ← Matrix3d.AInTermsOfB[skitterWORLD, CoordSys.WRTWorld[camera.coordSys]];
SVDraw3d.DrawSkitter[dc, skitterCAMERA, camera];
};
DrawAnchor: PROC [dc: Imager.Context, svData: SVData, camera: Camera] = {
anchorWORLD, anchorCAMERA: Matrix4by4;
scene: Scene ← svData.scene;
IF NOT SVCaret.Exists[scene.anchor] THEN RETURN;
anchorWORLD ← SVCaret.GetPosition[scene.anchor];
anchorCAMERA ← Matrix3d.AInTermsOfB[anchorWORLD, CoordSys.WRTWorld[camera.coordSys]];
SVDraw3d.DrawTargetCoordSys[dc, anchorCAMERA, camera];
};
OutsideOf: PROC [test, bound: SVBoundBox.BoundBox] RETURNS [BOOL] = {
RETURN[ test.hiX < bound.loX OR test.loX > bound.hiX OR test.hiY < bound.loY OR test.loY > bound.hiY ]; -- these tests may have to be <= or >=
};
DeeperPlanarPolygon: PROC [x,y: PriorityQueue.Item, data: REFNIL] RETURNS [BOOL] = {
xS: PlanarSurface ← NARROW[x];
yS: PlanarSurface ← NARROW[y];
RETURN[xS.depth < yS.depth];
};
DrawObjectsFiltered: PROC [dc: Imager.Context, svData: SVData, filter: BoundBox, excludeOverlay: BOOLFALSE, selectedDepth: REAL ← -Real.LargestNumber] = {
Paints those objects in the scene within the filter bounding box, and in front of (and including) overObject (in PriorityOrder) into the display context.
DrawObjectsFilteredAux: PROC = { -- need to clip to filter, then image
g: AssemblyGenerator ← SVScene.PrimAssembliesInScene[scene];
thisSlice: Slice ← SVScene.NextAssembly[g];
IF overObject # NIL THEN {
UNTIL thisSlice = overObject OR thisSlice = NIL DO thisSlice ← SVScene.NextAssembly[g] ENDLOOP;
IF thisSlice = NIL THEN RETURN;
};
Imager.SetColor[dc, Imager.black];
SVBoundBox.Clip[dc: dc, bBox: filter, screen: camera.screenCS];
SELECT camera.style FROM
wire, normals => {
FOR slice: Slice ← thisSlice, SVScene.NextAssembly[g] UNTIL slice = NIL DO
IF excludeOverlay AND slice.onOverlay THEN LOOP;
IF NOT SVBoundBox.OutsideOf[SVAssembly.GetBoundBox[slice, NIL, camera], filter] THEN SVAssembly.DrawParts[slice, NIL, dc, scene, camera, FALSE];
ENDLOOP;
};
shaded => {
predictedBufferSize: NAT ← CountSurfacesInAssembly[scene.assembly];
polygonBuffer: PriorityQueue.Ref ←
PriorityQueue.Predict[predictedBufferSize, DeeperPlanarPolygon];
FOR slice: Slice ← thisSlice, SVScene.NextAssembly[g] UNTIL slice = NIL DO
IF excludeOverlay AND slice.onOverlay THEN LOOP;
IF NOT SVBoundBox.OutsideOf[SVAssembly.GetBoundBox[slice, NIL, camera], filter] THEN SVAssembly.AddPolygonsToBuffer[polygonBuffer, slice, camera];
ENDLOOP;
SVAssembly.DrawBuffer[dc, polygonBuffer, scene, camera];
};
ENDCASE => ERROR;
};
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
IF filter=NIL OR filter.null THEN RETURN;
Imager.DoSaveAll[dc, DrawObjectsFilteredAux];
};
CountSurfacesInAssembly: PROC [assembly: Slice] RETURNS [surfCount: NAT] = {
WITH assembly.shape SELECT FROM
assems: SliceList => surfCount ← CountSurfacesInAssemblyList[assems];
shape: Shape => surfCount ← shape.mo.class.countSurf[shape.mo];
ENDCASE => ERROR;
};
CountSurfacesInAssemblyList: PROC [asl: SliceList] RETURNS [surfCount: NAT] = {
surfCount ← 0;
FOR list: LIST OF Slice ← asl.list, list.rest UNTIL list = NIL DO
surfCount ← surfCount + CountSurfacesInAssembly[list.first];
ENDLOOP;
};
DrawCPFeedback: PROC [dc: Imager.Context, svData: SVData, caretIsMoving, dragInProgress: BOOL] = {
};
SelectionOrCaretChanged: PROC [screen: Imager.Context, svData: SVData, showColors: BOOL] = {
The selection plane or the skitter plane is obsolete. Since these planes have no backing bitmaps, no repairs are needed. Simply redraw the planes.
PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
};
Fixing Planes
DepthOfAssembly: PROC [slice: REF ANY] RETURNS [depth: REAL] = {
depth ← -Real.LargestNumber;
};
ObjectAdded: PROC [screen: Imager.Context, svData: SVData, showColors: BOOL] = {
An object has been added to the scene. All of the changes are confined to the box svData.refresh.startBoundBox. Repair the background plane and refresh the screen.
assembly: Slice ← NARROW[svData.refresh.addedObject];
bBox: BoundBox ← SVBoundBox.BoundBoxOfAssembly[assembly];
bBox: BoundBox ← NIL;
selectedDepth: REAL ← DepthOfAssembly[svData.refresh.addedObject];
RepairBackgroundInBoundBox[svData, bBox, FALSE, selectedDepth, showColors];
PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
};
RepairBackgroundInBoundBox: PROC [svData: SVData, bBox: BoundBox, eraseFirst: BOOLFALSE, selectedDepth: REAL, showColors: BOOL] = {
backgroundContext: Imager.Context ← BufferedRefresh.GetLayerContext[svData.refresh.sandwich, $Background];
IF NOT showColors THEN {
PaintObjectsInBox: PROC = {
IF eraseFirst THEN GGBoundBox.EraseWithinBoundBox[backgroundContext, bBox];
DrawObjectsFiltered[dc: backgroundContext, svData: svData, filter: bBox, selectedDepth: selectedDepth];
};
Imager.DoSaveAll[backgroundContext, PaintObjectsInBox];
BufferedRefresh.SetLayerOK[svData.refresh.sandwich, $Background, TRUE];
};
};
Dynamic
PaintDragOverlay: PROC [screen: Imager.Context, svData: SVData, dragInProgress: BOOL, showColors: BOOL] = {
This routine is called DuringDrag. Write the overlay shapes, selection feedback, and the foreground shapes onto the chunking bitmap and then dump the chunking bitmap onto the screen.
clientToViewer, viewerToClient: Imager.Transformation;
svData.refresh.dragInProgress ← dragInProgress;
svData.refresh.caretIsMoving ← TRUE;
clientToViewer ← viewerToClient ← ImagerTransformation.Scale[1.0];
BufferedRefresh.DrawSandwich[svData.refresh.sandwich, screen, clientToViewer, viewerToClient, svData, showColors];
};
BackmostSelectedDepth: PROC [scene: Scene] RETURNS [selectedDepth: REAL] = {
g: SVScene.AssemblyGenerator;
sliceD: SliceDescriptor;
g ← SVScene.PrimAssembliesInScene[scene];
FOR slice: Slice ← SVScene.NextAssembly[g], SVScene.NextAssembly[g] UNTIL slice = NIL DO
sliceD ← SVSelect.FindSelectedSlice[slice, scene, normal];
IF sliceD # NIL THEN RETURN[slice];
ENDLOOP;
RETURN[-Real.LargestNumber];
};
FinishedDragging: PROC [screen: Imager.Context, svData: SVData, showColors: BOOL] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
selectedDepth: REAL ← BackmostSelectedDepth[scene];
SVBoundBox.EnlargeByBox[svData.refresh.startBoundBox, SVBoundBox.BoundBoxOfMoving[scene, camera]];
MergeBackgroundAndOverlay[svData, svData.refresh.startBoundBox, TRUE, selectedDepth, showColors];
PaintAllPlanes[screen, svData, showColors, FALSE, FALSE];
};
MergeBackgroundAndOverlay: PROC [svData: SVData, bBox: BoundBox, eraseFirst: BOOLFALSE, selectedDepth: REAL, showColors: BOOL] = {
The background and overlay planes are about to be recombined into the background plane, after dragging.
MergeBackgroundAndOverlayAux: PROC = {
IF eraseFirst THEN SVBoundBox.EraseWithinBoundBox[backgroundContext, bBox, camera.screenCS];
DrawObjectsFiltered[dc: backgroundContext, svData: svData, filter: bBox, selectedDepth: selectedDepth];
};
camera: Camera ← svData.camera;
backgroundContext: Imager.Context ← BufferedRefresh.GetLayerContext[svData.refresh.sandwich, $Background];
IF svData.refresh.suppressRefresh THEN RETURN;
IF NOT showColors THEN {
Imager.DoSaveAll[backgroundContext, MergeBackgroundAndOverlayAux];
BufferedRefresh.SetLayerOK[svData.refresh.sandwich, $Background, TRUE];
};
};
DuringSelect: PROC [screen: Imager.Context, svData: SVData, showColors: BOOL] = {
Similar to PaintAllPlanes
IF svData.refresh.suppressRefresh THEN RETURN;
IF NOT showColors THEN {
clientToViewer, viewerToClient: Imager.Transformation;
clientToViewer ← viewerToClient ← ImagerTransformation.Scale[1.0];
BufferedRefresh.DrawSandwich[svData.refresh.sandwich, screen, clientToViewer, viewerToClient, svData, showColors];
}
ELSE {}; -- no feedback in SlowPaint mode
};
SplitBackgroundAndOverlay: PUBLIC PROC [svData: SVData, restoreBox: BoundBox] = {
PaintAllButOverlayed: PROC = {
SVBoundBox.EraseWithinBoundBox[backgroundContext, restoreBox, camera.screenCS];
DrawObjectsFiltered[dc: backgroundContext, svData: svData, filter: restoreBox, excludeOverlay: TRUE, selectedDepth: -Real.LargestNumber];
};
backgroundContext: Imager.Context;
camera: Camera ← svData.camera;
IF svData.refresh.suppressRefresh THEN RETURN;
backgroundContext ← BufferedRefresh.GetLayerContext[svData.refresh.sandwich, $Background];
Imager.DoSaveAll[backgroundContext, PaintAllButOverlayed];
};
Debugging Routines (draw directly on the screen)
DrawColor: PROC [dc: Imager.Context, svData: SVData] = {
scene: Scene ← svData.scene;
resolution: REAL;
boundBox: BoundBox;
minX, minY, maxX, maxY: REAL;
camera: Camera ← svData.camera;
tree: CSGTree;
screenMat: Matrix4by4;
aisRope: Rope.ROPE ← Rope.Concat[SVFiles.FilenameMinusExtension[scene.name], ".ais"];
resolution ← camera.resolution;
tree ← DisplayListToTree.AssemblyToTree[scene.assembly, scene, camera];
[minX, minY, maxX, maxY] ← MinAndMaxFromCameraAndTree[camera, tree];
boundBox ← SVBoundBox.BoundBoxFromValues[minX, minY, maxX, maxY];
screenMat ← CoordSys.GetMat[camera.screenCS];
SVImage.DrawAlignedColorImage[dc, aisRope, resolution, [screenMat[1][4], screenMat[2][4]], boundBox, svData.feedback];
};
DrawBlackAndWhite: PROC [dc: Imager.Context, svData: SVData] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
resolution: REAL;
boundBox: BoundBox;
minX, minY, maxX, maxY: REAL;
tree: CSGTree;
screenMat: Matrix4by4;
aisRope: Rope.ROPE ← Rope.Concat[SVFiles.FilenameMinusExtension[scene.name], ".ais"];
resolution ← camera.resolution;
tree ← DisplayListToTree.AssemblyToTree[scene.assembly, scene, camera];
[minX, minY, maxX, maxY] ← MinAndMaxFromCameraAndTree[camera, tree];
boundBox ← SVBoundBox.BoundBoxFromValues[minX, minY, maxX, maxY];
screenMat ← CoordSys.GetMat[camera.screenCS];
SVImage.DrawAlignedBlackAndWhiteImage[dc, aisRope, resolution, [screenMat[1][4], screenMat[2][4]], boundBox, svData.feedback];
Imager.SetColor[dc, Imager.black];
SVGraphics.DrawFrame [dc, camera];
};
MinAndMaxFromCameraAndTree: PROC [camera: Camera, tree: CSGTree] RETURNS [minX, minY, maxX, maxY: REAL] = {
frame: FrameBox ← camera.frame;
boundBox: BoundBox;
defaultHalfSide: REAL = 100.0;
IF frame.fullScreen THEN {
[boundBox] ← Preprocess3d.PreprocessForInteraction[tree, camera];
IF boundBox = NIL THEN {
minX ← minY ← -defaultHalfSide;
maxX ← maxY ← defaultHalfSide;
}
ELSE {
minX ← boundBox.loX; minY ← boundBox.loY;
maxX ← boundBox.hiX; maxY ← boundBox.hiY;
};
}
ELSE {
minX ← frame.downLeft[1]; minY ← frame.downLeft[2];
maxX ← frame.upRight[1]; maxY ← frame.upRight[2];
};
};
DrawCoordSystems: PROC [dc: Imager.Context, svData: SVData] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
g: CoordSysGenerator ← SVScene.GetCoordSysGenerator[scene];
mat: Matrix4by4;
FOR cs: CoordSystem ← SVScene.NextCoordSys[g], SVScene.NextCoordSys[g]
UNTIL cs = NIL DO
mat ← CoordSys.WRTCamera[cs, camera.coordSys];
Make sure you have up to date coordSys positions.
SVDraw3d.DrawCoordSys[dc, mat, camera];
ENDLOOP;
};
DrawBoundBoxes: PROC [dc: Imager.Context, svData: SVData] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
bBox: BoundBox;
g: SVScene.AssemblyGenerator ← SVScene.PrimAssembliesInScene[scene];
FOR slice: Slice ← SVScene.NextAssembly[g], SVScene.NextAssembly[g] UNTIL slice = NIL DO
bBox ← SVAssembly.GetBoundBox[slice, NIL, camera];
SVBoundBox.DrawBoundBox[dc, bBox, camera.screenCS];
ENDLOOP;
};
DrawBoundSpheres: PROC [dc: Imager.Context, svData: SVData] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
tree: CSGTree;
tree ← DisplayListToTree.AssemblyToTree[scene.assembly, scene, camera]; -- does a TellAboutCameraAndWorld
[] ← Preprocess3d.PreprocessForCatScan[tree, camera]; -- computes the bounding spheres
SVDraw3d.DrawBoundSpheres[dc, tree, camera];
};
DrawCrossHairs: PROC [dc: Imager.Context, svData: SVData] = {
camera: Camera ← svData.camera;
SVDraw3d.Draw2dCoordSys[dc, [0,0], camera];
};
DrawPt: PROC [dc: Imager.Context, svData: SVData] = {
camera: Camera ← svData.camera;
x, y: REAL;
[x, y] ← SVUtility.ReadTwoReals[svData.textSection.xyz];
SVDraw3d.DrawX[dc, [x, y], camera];
};
DrawPaint: PROC [dc: Imager.Context, svData: SVData] = {
OPEN Matrix3d;
camera: Camera ← svData.camera;
skitterWORLD, worldCamera: Matrix4by4;
path: ImagerPath.Trajectory;
editToolData: EditToolData ← svData.editToolData;
artworkToolData: ArtworkToolData ← NARROW[editToolData.artworkTool.data];
paintColor: Color ← artworkToolData.paintColor;
[----, skitterWORLD] ← SVSelections.GetPositionSkitter[editToolData];
worldCamera ← CoordSys.FindWorldInTermsOf[camera.coordSys];
SVGraphics.MoveToAbsolute[path, Update[Update[[-2, -2, 0], skitterWORLD], worldCamera], camera];
SVGraphics.LineToAbsolute[path, Update[Update[[-2, 2, 0], skitterWORLD], worldCamera], camera];
SVGraphics.LineToAbsolute[path, Update[Update[[2, 2, 0], skitterWORLD], worldCamera], camera];
SVGraphics.LineToAbsolute[path, Update[Update[[2, -2, 0], skitterWORLD], worldCamera], camera];
Imager.SetColor[dc, paintColor];
SVGraphics.DrawStroke[dc, path, 1, TRUE];
};
DrawCatScan: PROC [dc: Imager.Context, svData: SVData] = {
catScan: CatScan ← svData.refresh.catScan;
camera: Camera ← svData.camera;
SVCatScan.DrawSlice3d[dc, catScan, camera];
};
PaintSpot: PUBLIC PROC [dc: Imager.Context, svData: SVData] = {
spotPoint: Point2d ← svData.refresh.spotPoint;
camera: Camera ← svData.camera;
SVDraw3d.DrawX[dc, spotPoint, camera];
};
PaintHitLine: PUBLIC PROC [dc: Imager.Context, svData: SVData] = {
spotPoint: Point2d ← svData.refresh.spotPoint; -- in Camera
hitPoint: Point3d ← svData.refresh.hitPoint; -- in WORLD
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
hitPoint ← CoordSys.FromCSToCS[hitPoint, scene.coordSysRoot, camera.coordSys];
SVGraphics.SetCPAbsolute[dc, [spotPoint[1], spotPoint[2], 0.0], camera];
SVGraphics.DrawToAbsolute[dc, hitPoint, camera];
};
For Interpress Masters
InterpressEntireScene: PUBLIC PROC [dc: Imager.Context, svData: SVData] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
lo, hi: Point2d;
lo ← [0,0];
hi ← [8.5*72.0, 11.0*72.0];
lo ← CoordSys.ScreenToCamera[lo, camera.screenCS];
hi ← CoordSys.ScreenToCamera[hi, camera.screenCS];
SVScene.DrawScene[dc, scene, camera];
DrawObjectsFiltered[dc, svData, SVBoundBox.BoundBoxFromValues[lo[1], lo[2], hi[1], hi[2]] ];
};
The Overlay Plane.
OnOverlay: PROC [entity: REF ANY, svData: SVData] RETURNS [BOOL] = {
WITH entity SELECT FROM
slice: Slice => RETURN[slice.onOverlay];
sliceD: SliceDescriptor => RETURN[sliceD.slice.onOverlay];
ENDCASE => ERROR;
};
MoveToOverlay: PUBLIC PROC [entity: REF ANY, svData: SVData] = {
WITH entity SELECT FROM
sliceD: SliceDescriptor => {
IF OnOverlay[sliceD, svData] THEN ERROR;
sliceD.slice.onOverlay ← TRUE;
svData.refresh.overlayList ← CONS[sliceD, svData.refresh.overlayList];
};
ENDCASE => ERROR;
svData.refresh.orderedOverlayList ← NIL;
};
MoveToBackground: PUBLIC PROC [entity: REF ANY, svData: SVData] = {
IF NOT OnOverlay[entity, svData] THEN RETURN;
svData.refresh.overlayList ← NARROW[GList.DRemove[entity, svData.refresh.overlayList]];
WITH entity SELECT FROM
sliceD: SliceDescriptor => sliceD.slice.onOverlay ← FALSE;
ENDCASE => ERROR;
svData.refresh.orderedOverlayList ← NIL;
};
MoveAllSelectedToOverlay: PUBLIC PROC [svData: SVData, selectClass: SelectionClass] = {
sGen: SliceDescriptorGenerator ← SVSelect.SelectedSlices[svData.scene, selectClass];
FOR sliceD: SliceDescriptor ← SVSelect.NextSliceDescriptor[sGen], SVSelect.NextSliceDescriptor[sGen] UNTIL sliceD = NIL DO
MoveToOverlay[sliceD, svData];
ENDLOOP;
};
MoveOverlayToBackground: PUBLIC PROC [svData: SVData] = {
sliceD: SliceDescriptor;
FOR overlayList: LIST OF SliceDescriptor ← svData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO
sliceD ← overlayList.first;
sliceD.slice.onOverlay ← FALSE;
ENDLOOP;
svData.refresh.overlayList ← NIL;
svData.refresh.orderedOverlayList ← NIL;
};
EmptyOverlay: PUBLIC PROC [svData: SVData] RETURNS [BOOL] = {
RETURN[svData.refresh.overlayList = NIL];
};
OrderOverlayList: PROC [svData: SVData] RETURNS [orderedList: LIST OF SliceDescriptor ← NIL] = {
traverse the scene.entities from back to end front.
FindOverlayedD: PROC [slice: REF ANY] RETURNS [sliceD: SliceDescriptor ← NIL] = {
FOR ov: LIST OF SliceDescriptor ← svData.refresh.overlayList, ov.rest UNTIL ov=NIL DO
sliceD ← ov.first;
IF sliceD.slice=slice THEN RETURN[sliceD];
ENDLOOP;
RETURN[NIL];
};
sliceD: SliceDescriptor;
finger: LIST OF SliceDescriptor;
g: SVScene.AssemblyGenerator;
scene: Scene ← svData.scene;
[orderedList, finger] ← SVUtility.StartSliceDescriptorList[];
g ← SVScene.PrimAssembliesInScene[scene];
FOR slice: Slice ← SVScene.NextAssembly[g], SVScene.NextAssembly[g] UNTIL slice = NIL DO
IF OnOverlay[slice, svData] THEN {
sliceD ← FindOverlayedD[slice];
IF sliceD = NIL THEN sliceD ← SVAssembly.NewParts[slice, NIL, [0,0,0], topLevel];
[orderedList, finger] ← SVUtility.AddSliceDescriptor[sliceD, orderedList, finger];
};
ENDLOOP;
};
InitStats: PROC = {
interval: CodeTimer.Interval;
interval ← CodeTimer.CreateInterval[$PaintEntireScene];
CodeTimer.AddInt[interval, $Solidviews];
};
InitStats[];
END.