DIRECTORY Atom, BasicTime, CedarProcess, Commander, FS, G3dAnimationSupport, G3dColorDisplaySupport, G3dRender, G3dRenderWithImager, G3dRenderWithPixels, G3dShape, G3dSortandDisplay, Imager, ImageTwiddle, List, Process, Random, Real, Rope, Terminal, ThreeDViewer, ViewerTools; ThreeDDemoImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, CedarProcess, Commander, FS, G3dAnimationSupport, G3dColorDisplaySupport, G3dRender, G3dRenderWithImager, G3dRenderWithPixels, G3dShape, G3dSortandDisplay, ImageTwiddle, List, Process, Random, Real, Rope, Terminal, ThreeDViewer, ViewerTools ~ BEGIN PropList: TYPE ~ Atom.PropList; ROPE: TYPE ~ Rope.ROPE; Context: TYPE ~ G3dRender.Context; IntegerPair: TYPE ~ G3dRender.IntegerPair; Pair: TYPE ~ G3dRender.Pair; Pixel: TYPE ~ G3dRender.Pixel; Triple: TYPE ~ G3dRender.Triple; Rectangle: TYPE ~ G3dRender.Rectangle; RGB: TYPE ~ G3dRender.RGB; Patch: TYPE ~ G3dRender.Patch; ShadingClass: TYPE ~ G3dRender.ShadingClass; Shape: TYPE ~ G3dRender.Shape; ShapeRep: TYPE ~ G3dShape.ShapeRep; ShapeSequence: TYPE ~ G3dRender.ShapeSequence; ShapeSequenceRep: TYPE ~ G3dShape.ShapeSequenceRep; RenderData: TYPE ~ G3dRender.RenderData; ImagerProcRec: TYPE ~ G3dRender.ImagerProcRec; LORA: TYPE ~ LIST OF REF ANY; context3d, offScreenCtx: Context; -- , onScreenCtx currentScene, scene1, scene2, scene3: ShapeSequence _ NIL; lastDemoCalled: PROC[makeFrame: BOOLEAN _ FALSE]; frames: REF G3dAnimationSupport.FrameSequence; xNow, yNow, zNow: REAL _ 3.0; xPosition, yPosition: REAL _ 0.0; cursorRange: REAL _ 64.0; quadTime: REAL; animation: BOOLEAN _ FALSE; movieProcess: CedarProcess.Process _ NIL; cachedViewPort: Rectangle _ [0.0, 0.0, 0.0, 0.0]; windowStack, viewPortStack: LIST OF Rectangle _ NIL; mouseWaiting: ATOM _ NIL; mouseRectangle: REF Rectangle _ NIL; FindShape: PROC [context: Context, shapeName: ROPE] RETURNS [Shape] ~ G3dRender.FindShape; GetAIS: PROC[ context: Context, fileRoot: ROPE, xOffset, yOffset: INTEGER _ 0, center: BOOLEAN _ TRUE, labeled: BOOLEAN _ FALSE ] RETURNS[ xSize, ySize: INTEGER] ~ G3dColorDisplaySupport.GetAIS; GetProp: PROC [propList: PropList, prop: REF ANY] RETURNS [REF ANY] ~ Atom.GetPropFromList; PutProp: PROC [propList: PropList, prop: REF ANY, val: REF ANY] RETURNS [PropList] ~ Atom.PutPropOnList; demoMenu: LIST OF ThreeDViewer.ButtonDesc ~ LIST [ [ proc: SetScene, -- Select Scene choices: LIST[ [$Scene1, "Polyhedra on Checkerboard"], -- left mouse button [$Scene2, "Glass, Banana and Egg"], -- middle mouse button [$Scene3, "Bezier Teapot"], -- right mouse button [$OneShape, "Show One Shape (name from selection)"], -- shift left [NIL, NIL], -- shift middle [NIL, NIL], -- shift right [$Window, "2 Clicks in image define part of scene to display"], -- control left [$ViewPort, "2 Clicks in image define new screen area"], -- control middle [NIL, NIL], -- control right [$RestoreW, "Restore previous window"], -- control shift left [$RestoreVP, "Restore previous viewport"] -- control shift middle ], label: "Select Shapes", purpose: "Chooses scene to manipulate" ], [ proc: SetShading, -- Shading Style choices: LIST[ [$Lines, "Line Drawing"], -- left mouse button [$Facets, "Faceted Shading"], -- middle mouse button [$Smooth, "Smooth Shading"], -- right mouse button [$Hidden, "Hidden Line Drawing"], -- shift left [$Shiny, "Faceted Shading with Highlights"], -- shift middle [$Hilights, "Smooth Shading with Highlights"], -- shift right [$SmoLines, "Smooth Shading on Lines"], -- control left [$Normals, "Line drawing with normal vectors"] -- control middle ], label: "Shading Style", purpose: "Chooses shading for surfaces in current scene" ], [ proc: SetRenderingStyle, -- Rendering Style choices: LIST[ [$Jaggy, "Aliased"], -- left mouse button [$NoJaggy, "AntiAliased"], -- middle mouse button [NIL, NIL], -- right mouse button [$Visible, "Build Image On Display"], -- shift left [$Buffered, "Double Buffer Image"], -- shift middle [NIL, NIL], -- shift right [$Imager, "Use Imager (faceted only)"], -- control left [$Pixels, "Use fancier tiler/shaders"], -- control middle [NIL, NIL], -- control right [$ZBuffer, "Use depth buffer for hidden surfaces"], -- control shift left [$Sorted, "Use sorting for hidden surfaces"], -- control shift middle [NIL, NIL], -- control shift right [$PseudoClr, "8-bit mapped color"], [$Gray, "8-bit grayscale"], [$FullClr, "24-bit full color"] ], label: "Rendering Style", purpose: "Chooses display type, antialising, and double buffering" ], [ proc: DoCommands, -- Commands choices: LIST[ [$Display, "Make a frame with the current scene"], -- left mouse button [$StoreImage, "Store image in file (name from selection)"], -- middle mouse button [$Interpress, "Interpress file (name from selection)"] -- right mouse button ], label: "Do It", purpose: "Make/Store images" ], [ proc: ShowMotion, -- Animation choices: LIST[ [$Orbit, "Orbit about scene computing frames on the fly"], -- left mouse button [$SelectDthr, "Take 8-bit dithered sequence name from selection"], -- middle button [$SelectGray, "Take 8-bit grayscale sequence name from selection"], -- right button [$Shapes, "Play back Banana, Glass, Egg scene"], -- shift left [$Terrain, "Play back Terrain flyover"], -- shift middle [NIL, NIL], -- shift right [$Web1, "Play back front view Paper web"], -- control left [$Web2, "Play back top view Paper web"], -- control middle ], label: "Animation", purpose: "Chooses various animations" ], [ proc: ShowPicture, -- Gallery choices: LIST[ [$SelectColor, "Take rgb file name from selection"], -- left mouse button [$SelectDthr, "Take 8-bit dithered file name from selection"], -- middle mouse button [$SelectGray, "Take 8-bit grayscale file name from selection"], -- right mouse button [$Spoon, "Newell's Bezier patch spoon"], -- shift left [$Bananas, "A field of bananas"], -- shift middle [$Compare, "Shading Comparison on Eggs"], -- shift right [$Bowl, "Sugar bowl with spoon"], -- control left [$TeaPot, "Teapot with Perlin texture"], -- control middle [$Eggtxtr, "Multi-textured Egg"], -- control right [$Heart, "Heart from two Bezier patches"], -- control shift left [$Objects, "Five objects on a checkerboard"], -- control shift middle [$Extents, "Five objects with bounding boxes"], -- control shift right [$HexTiles, "Objects on hex-tiled plane"], [$MikHead, "Mik leers over the curvaceous glass"], [$MikTrees, "Mik leers over scanned-in trees"], [$BallPage, "A sphere with a page of text"], [$BallPages, "A sphere with many pages of text"], [$TeaPages, "Teapot with pages of text"], [$SolidLines, "Drawing with fat lines"] ], label: "Gallery", purpose: "Chooses a pretty picture to display" ], [ proc: StopEverything, -- STOP! button choices: LIST[], -- No Choices, just calls proc label: "STOP!", purpose: "Panic button, stops all 3D activity" ], [ proc: DoReset, -- Reset button choices: LIST[], -- No Choices, just calls proc label: "Reset", purpose: "Reset button, can often get things unwedged" ] ]; SetScene: ENTRY PROC[context: Context, key: ATOM] ~ { context.stopMe^ _ FALSE; -- unstick stop button { ENABLE UNWIND => NULL; -- get out and release lock if error, etc. SELECT key FROM $Scene1 => SetScene1[]; $Scene2 => SetScene2[]; $Scene3 => SetScene3[]; $OneShape => OneShape[]; $Window => GetWindow[]; $ViewPort => GetViewPort[]; $RestoreW => RestoreWindow[]; $RestoreVP => RestoreViewPort[]; ENDCASE; }; }; SetShading: ENTRY PROC[context: Context, key: ATOM] ~ { context.stopMe^ _ FALSE; -- unstick stop button { ENABLE UNWIND => NULL; SELECT key FROM $Lines => LinesDemo[]; $Facets => { SetDull[]; FacetedDemo[]; }; $Smooth => { SetDull[]; SmoothDemo[]; }; $Hidden => HiddenLinesDemo[]; $Shiny => { SetShiny[]; FacetedDemo[]; }; $Hilights => { SetShiny[]; SmoothDemo[]; }; $SmoLines => IF context.class.displayType # $PseudoColor OR ThreeDViewer.SwitchDisplayTo[context, $FullColor] THEN { -- only for $Gray and $FullColor context.preferredRenderMode _ $Pixels; ShadedLinesDemo[]; }; $Normals => NormaledLinesDemo[]; ENDCASE; }; }; SetRenderingStyle: ENTRY PROC[context: Context, key: ATOM] ~ { context.stopMe^ _ FALSE; -- unstick stop button SELECT key FROM $Jaggy => G3dRenderWithPixels.AntiAliasing[context, FALSE]; $Visible => G3dRenderWithPixels.BufferRendering[context, FALSE]; $Imager => context.preferredRenderMode _ $Imager; $NoJaggy => IF context.class.displayType # $PseudoColor OR ThreeDViewer.SwitchDisplayTo[context, $FullColor] THEN { context.preferredRenderMode _ $Pixels; G3dRenderWithPixels.AntiAliasing[context, TRUE]; }; $Buffered => G3dRenderWithPixels.BufferRendering[context, TRUE]; $Pixels => context.preferredRenderMode _ $Pixels; $ZBuffer => G3dRenderWithPixels.DepthBuffering[context, TRUE]; $Sorted => G3dRenderWithPixels.DepthBuffering[context, FALSE]; $PseudoClr => [] _ ThreeDViewer.SwitchDisplayTo[context, $PseudoColor]; $Gray => [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; $FullClr => [] _ ThreeDViewer.SwitchDisplayTo[context, $FullColor]; ENDCASE; { ENABLE UNWIND => NULL; ThreeDViewer.DrawInViewer[context, NIL]; }; }; DoCommands: ENTRY PROC[context: Context, key: ATOM] ~ { context.stopMe^ _ FALSE; -- unstick stop button { ENABLE UNWIND => NULL; SELECT key FROM $Display => { IF DemoErrorMessages[] THEN RETURN; SELECT lastDemoCalled FROM LinesDemo => MakeFrame[]; ShadedLinesDemo => MakeFrame[]; HiddenLinesDemo => HiddenLinesDemo[TRUE]; NormaledLinesDemo => NormaledLinesDemo[TRUE]; FacetedDemo => MakeFrame[]; SmoothDemo => MakeFrame[]; ENDCASE => MakeFrame[]; }; $StoreImage => G3dColorDisplaySupport.PutAIS[ context3d, ViewerTools.GetSelectionContents[] ]; $Interpress => InterpressDemo[]; ENDCASE; }; }; ShowMotion: ENTRY PROC[context: Context, key: ATOM] ~ { SetSingleBuffer: PROC[] ~ { G3dRenderWithPixels.AntiAliasing[context, FALSE]; G3dRenderWithPixels.DepthBuffering[context, FALSE]; }; context.stopMe^ _ FALSE; -- unstick stop button { ENABLE UNWIND => NULL; IF key = $Orbit OR context.class.displayType # $FullColor OR ThreeDViewer.SwitchDisplayTo[context, $PseudoColor] -- ensure 8-bit display THEN SELECT key FROM $Orbit => Orbit[]; $SelectDthr => { [] _ ThreeDViewer.SwitchDisplayTo[context, $PseudoColor]; SetSingleBuffer[]; SetUpMovie[ fileRoot: ViewerTools.GetSelectionContents[] ]; }; $SelectGray => { [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; SetSingleBuffer[]; SetUpMovie[ fileRoot: ViewerTools.GetSelectionContents[] ]; }; $Shapes => { [] _ ThreeDViewer.SwitchDisplayTo[context, $PseudoColor]; SetSingleBuffer[]; SetUpMovie[ fileRoot: "/Pixel/Crow/Animation/StillCloser.ais", numFiles: 40, start: 1 ]; }; $Terrain => { [] _ ThreeDViewer.SwitchDisplayTo[context, $PseudoColor]; SetSingleBuffer[]; SetUpMovie[ fileRoot: "/Cyan/AIS/Animation/LakeSceneTest.ais", numFiles: 64 ]; ImageTwiddle.SetUpTerrainColors[context.terminal]; }; $Web1 => { [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; SetSingleBuffer[]; SetUpMovie[ fileRoot: "/Pixel/Crow/Animation/Paper4Web.ais", numFiles: 40 ]; }; $Web2 => { [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; SetSingleBuffer[]; SetUpMovie[ fileRoot: "/Pixel/Crow/Animation/Paper5Web.ais", numFiles: 40 ]; }; ENDCASE; IF key # $Orbit THEN movieProcess _ CedarProcess.Fork[PlayBackbyFrame]; }; }; ShowPicture: ENTRY PROC[context: Context, key: ATOM] ~ { context.stopMe^ _ FALSE; -- unstick stop button { ENABLE UNWIND => NULL; SELECT key FROM $SelectDthr => IF context.class.displayType # $PseudoColor THEN IF ThreeDViewer.SwitchDisplayTo[context, $PseudoColor] THEN -- switch to dithered { [] _ CedarProcess.Fork[ WaitThenShowPicture, LIST[context, key] ]; RETURN; }; $SelectGray => IF context.class.displayType # $Gray THEN IF ThreeDViewer.SwitchDisplayTo[context, $Gray] THEN -- switch to 8-bit gray { [] _ CedarProcess.Fork[ WaitThenShowPicture, LIST[context, key] ]; RETURN; }; ENDCASE => IF context.class.displayType # $FullColor THEN IF ThreeDViewer.SwitchDisplayTo[context, $FullColor] THEN -- switch to full color { [] _ CedarProcess.Fork[ WaitThenShowPicture, LIST[context, key] ]; RETURN; }; SELECT key FROM $SelectDthr, $SelectGray, $SelectColor => [] _ GetAIS[context3d, ViewerTools.GetSelectionContents[] ]; $Spoon => [] _ GetAIS[context3d, "/cyan/AIS/Crow/Spoon.ais" ]; $Bananas => [] _ GetAIS[context3d, "/cyan/AIS/Crow/FieldOfBanana.ais" ]; $Compare => [] _ GetAIS[context3d, "/cyan/AIS/Crow/ComparisonEggs.ais" ]; $Bowl => [] _ GetAIS[context3d, "/cyan/AIS/Crow/BowlAndSpoon.ais" ]; $TeaPot => [] _ GetAIS[context3d, "/cyan/AIS/Crow/ZebraBurlTeaPot.ais" ]; $Eggtxtr => [] _ GetAIS[context3d, "/cyan/AIS/Crow/MultiTxtrdEgg2.ais" ]; $Heart => [] _ GetAIS[context3d, "/cyan/AIS/Crow/Heart.ais" ]; $Objects => [] _ GetAIS[context3d, "/cyan/AIS/Crow/TestScene2.ais" ]; $Extents => [] _ GetAIS[context3d, "/cyan/AIS/Crow/FiveObjWBoxes.ais" ]; $HexTiles => [] _ GetAIS[context3d, "/cyan/AIS/Crow/HexTiles.ais" ]; $MikHead => [] _ GetAIS[context3d, "/cyan/AIS/Crow/Lamming6Scene.ais" ]; $MikTrees => [] _ GetAIS[context3d, "/cyan/AIS/Crow/Lamming7Scene.ais" ]; $BallPage => [] _ GetAIS[context3d, "/cyan/AIS/Crow/SphereWithPage.ais" ]; $BallPages => [] _ GetAIS[context3d, "/cyan/AIS/Crow/SphereWithPages.ais" ]; $TeaPages => [] _ GetAIS[context3d, "/cyan/AIS/Crow/PagedTeaPot.ais" ]; $SolidLines => [] _ GetAIS[context3d, "/cyan/AIS/Crow/StillLines.ais" ]; ENDCASE }; }; WaitThenShowPicture: CedarProcess.ForkableProc ~ { list: LORA _ NARROW[data]; context: Context _ NARROW[list.first]; key: ATOM _ NARROW[list.rest.first]; WHILE GetProp[ context.displayProps, $ViewerAdjusted ] # NIL DO Process.PauseMsec[ 500 ]; ENDLOOP; -- wait for viewer paint proc to complete ShowPicture[context, key]; }; StopEverything: PROC[context: Context, key: ATOM] ~ { -- panic stop bkgrdContext: Context _ NIL; WITH GetProp[context.props, $BackGround] SELECT FROM bkGrdCtx: Context => bkgrdContext _ bkGrdCtx; ENDCASE; context.stopMe^ _ TRUE; WHILE bkgrdContext # NIL DO -- stop chain of background contexts tmpCtx: Context _ bkgrdContext; tmpCtx.stopMe^ _ TRUE; bkgrdContext _ NARROW[GetProp[tmpCtx.props, $BackGround]]; ENDLOOP; IF movieProcess # NIL THEN { Process.Yield[]; CedarProcess.Abort[movieProcess]; movieProcess _ NIL; Process.Yield[]; G3dRender.SetViewPort[ context, cachedViewPort ]; }; }; DoReset: PROC [context: Context, key: ATOM] ~ { -- get out of stuckness, start over StopEverything[context, NIL]; Process.PauseMsec[ 3000 ]; -- wait 3 seconds for processes to stop context3d.stopMe^ _ FALSE; -- get stop flag unstuck, if necessary context3d.window _ NIL; context3d.shapes _ context3d.visibleShapes _ NIL; context3d.lightSources _ NIL; G3dRender.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; G3dRender.AddLight[context3d, "Light0", [-100., -200., 50.] ]; G3dRender.SetViewPort[context3d, [0.0, 0.0, 65536.0, 65536.0] ]; windowStack _ viewPortStack _ NIL; mouseWaiting _ NIL; mouseRectangle _ NIL; currentScene _ NIL; frames _ NIL; context3d.props _ Atom.RemPropFromList[ context3d.props, $SinglePatch ]; context3d.props _ Atom.RemPropFromList[ context3d.props, $SingleVtx ]; }; ThreeDDemoCommand: Commander.CommandProc ~ { context3d _ G3dRender.Create[]; context3d.preferredRenderMode _ $Pixels; -- $Pixels, Imager; ThreeDViewer.MakeViewer[ context: context3d, displayType: $PseudoColor, -- $Gray, ImagerDithered bannerName: "ThreeDWorld Demonstration", menu: demoMenu, mouseAction: MouseControl, verticalMenu: FALSE ]; G3dRender.NameBackgroundColor[ context3d, "Darkish Blue" ]; -- set background color G3dRender.NameAmbientLight[ context3d, "Darkish Gray" ]; -- set ambient light G3dRender.AddLight[context3d, "Light0", [-100., -200., 50.] ]; G3dRender.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; }; InitNoDisplay: PROC[] ~ { context3d _ G3dRender.Create[]; G3dRender.NameBackgroundColor[ context3d, "Darkish Blue" ]; -- set background color G3dRender.NameAmbientLight[ context3d, "Darkish Gray" ]; -- set ambient light G3dRender.AddLight[context3d, "Light0", [-100., -200., 50.] ]; G3dRender.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; }; InitNoViewer: PROC[] ~ { context3d _ G3dRender.Create[]; G3dRender.LoadDisplayClass[context3d, $PseudoColor]; G3dRender.NameBackgroundColor[ context3d, "Darkish Blue" ]; -- set background color G3dRender.NameAmbientLight[ context3d, "Darkish Gray" ]; -- set ambient light G3dRender.AddLight[context3d, "Light0", [-100., -200., 50.] ]; G3dRender.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; }; InitNoViewerFullColor: PROC[] ~ { context3d _ G3dRender.Create[]; G3dRender.LoadDisplayClass[context3d, $FullColor]; G3dRender.NameBackgroundColor[ context3d, "Darkish Blue" ]; -- set background color G3dRender.NameAmbientLight[ context3d, "Darkish Gray" ]; -- set ambient light G3dRender.AddLight[context3d, "Light0", [-100., -200., 50.] ]; G3dRender.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; }; Reset: PROCEDURE [] ~ { DoReset[context3d, NIL]; }; MouseControl: ThreeDViewer.MouseProc ~ { width, height: INTEGER; divisor: REAL; IF mouseWaiting # NIL THEN { IF bttn = $LeftButton THEN GetMouseRectangle[x, y]; RETURN; }; IF context.viewer # NIL THEN { width _ context.viewer.ww; height _ context.viewer.wh; } ELSE { width _ context.pixels.box.max.f - context.pixels.box.min.f; height _ context.pixels.box.max.s - context.pixels.box.min.s; }; divisor _ ((width/2.0) * (width/2.0)) / cursorRange; x _ x - width / 2.0; -- center mouse coords y _ y - height / 2.0; SELECT bttn FROM $LeftButton, $LeftHeld => IF movieProcess # NIL THEN frameRate _ INTEGER[Real.Fix[x / 10.]] ELSE { xNow _ (x * ABS[x] / divisor) + context3d.lookAt.x; yNow _ (y * ABS[y] / divisor) + context3d.lookAt.y; G3dRender.SetView[ context, [xNow, yNow, zNow], context.lookAt, context.fieldOfView, context.rollAngle, context.upDirection, context.hitherLimit, context.yonLimit ]; DoCommands[context, $Display]; }; $MiddleButton, $MiddleHeld => { xLight: REAL _ x * 1.0; -- roughly plus or minus 300-500 yLight: REAL _ y * 1.0; [] _ G3dRender.AddLight[ context, "Light0", [xLight, yLight, 50.0] ]; DoCommands[context, $Display]; }; $RightButton, $RightHeld => { zNow _ (y * ABS[y] / divisor) + context3d.lookAt.z; G3dRender.SetView[ context, [xNow, yNow, zNow], context.lookAt, context.fieldOfView, context.rollAngle, context.upDirection, context.hitherLimit, context.yonLimit ]; DoCommands[context, $Display]; }; ENDCASE; }; MoveToCursor: PROC[] ~ { width, height, offset: INTEGER; sPos: IntegerPair; IF context3d.viewer # NIL THEN { width _ context3d.viewer.ww; height _ context3d.viewer.wh; offset _ 28; } ELSE { width _ context3d.pixels.box.max.f - context3d.pixels.box.min.f; height _ context3d.pixels.box.max.s - context3d.pixels.box.min.s; offset _ context3d.pixels.box.min.s }; [[sPos.x, sPos.y]] _ Terminal.GetColorCursorPosition[context3d.terminal]; xPosition _ 1.0 * sPos.x / width; yPosition _ 1.0 * (height - sPos.y + offset) / height; }; DrawToCursor: PROC[ color: RGB _ [1.0,1.0,1.0] ] ~ { width, height, offset: INTEGER; sPos: IntegerPair; newPos: Pair; clrPxl: Pixel _ [Real.Fix[color.R*255], Real.Fix[color.G*255], Real.Fix[color.B*255], 0, 0]; IF context3d.viewer # NIL THEN { width _ context3d.viewer.ww; height _ context3d.viewer.wh; offset _ 28; } ELSE { width _ context3d.pixels.box.max.f - context3d.pixels.box.min.f; height _ context3d.pixels.box.max.s - context3d.pixels.box.min.s; offset _ context3d.pixels.box.min.s }; [[sPos.x, sPos.y]] _ Terminal.GetColorCursorPosition[context3d.terminal]; newPos _ [1.0 * sPos.x / width, 1.0 * (height - sPos.y + offset) / height]; context3d.class.draw2DLine[ context3d, [xPosition, yPosition], newPos, clrPxl ]; xPosition _ newPos.x; yPosition _ newPos.y; }; TextAtCursor: PROC[ rope: ROPE, color: RGB _ [1.0,1.0,1.0], size: REAL _ 20.0, font: ROPE _ NIL ] ~ { sPos: IntegerPair; pos: Pair; width, height, offset: INTEGER; clrPxl: Pixel _ [Real.Fix[color.R*255], Real.Fix[color.G*255], Real.Fix[color.B*255], 0, 0]; IF context3d.viewer # NIL THEN { width _ context3d.viewer.ww; height _ context3d.viewer.wh; offset _ 28; } ELSE { width _ context3d.pixels.box.max.f - context3d.pixels.box.min.f; height _ context3d.pixels.box.max.s - context3d.pixels.box.min.s; offset _ context3d.pixels.box.min.s }; [[sPos.x, sPos.y]] _ Terminal.GetColorCursorPosition[context3d.terminal]; pos _ [1.0 * sPos.x / width, 1.0 * (height - sPos.y + offset) / height]; IF font = NIL THEN font _ "Xerox/Pressfonts/TimesRoman-MRR"; context3d.class.draw2DRope[context3d, rope, pos, clrPxl, size, font]; }; GetOffScreenCtx: PROC[context: Context, width, height: NAT] ~ { offScreenCtx _ G3dRender.GetTmpContext[context]; offScreenCtx.viewer _ NIL; offScreenCtx.viewPort _ NEW[ -- set viewport directly to define pixelMap size Rectangle _ [ x: 0.0, y: 0.0, w: Real.Float[width], h: Real.Float[height] ] ]; G3dRenderWithPixels.AllocatePixelMemory[offScreenCtx]; -- get display memory G3dRender.SetViewPort[ offScreenCtx, [0.0, 0.0, Real.Float[width], Real.Float[height]] ]; IF context.antiAliasing THEN G3dRenderWithPixels.AntiAliasing[offScreenCtx];-- get state straight IF context.depthBuffering THEN G3dRenderWithPixels.DepthBuffering[offScreenCtx]; [] _ G3dRender.StartLog[offScreenCtx]; offScreenCtx.changed _ TRUE; G3dSortandDisplay.ValidateContext[offScreenCtx]; G3dSortandDisplay.ValidateContext[context]; -- just in case it hasn't been used yet }; GetOnScreenCtx: PROC[context: Context, width, height: NAT] ~ { onScreenCtx: Context _ G3dRender.GetTmpContext[context]; G3dRender.SetViewPort[ onScreenCtx, [0.0, 0.0, Real.Float[width], Real.Float[height]] ]; onScreenCtx.class.render _ G3dRenderWithPixels.MakeFrame; -- load direct memory procs onScreenCtx.class.displayPolygon _ G3dRenderWithPixels.PolygonTiler; IF context.antiAliasing THEN G3dRenderWithPixels.AntiAliasing[onScreenCtx]; IF context.depthBuffering THEN G3dRenderWithPixels.DepthBuffering[onScreenCtx]; onScreenCtx.changed _ TRUE; G3dSortandDisplay.ValidateContext[onScreenCtx]; G3dSortandDisplay.ValidateContext[context]; -- just in case it hasn't been used yet }; DemoErrorMessages: PROCEDURE [] RETURNS[ error: BOOLEAN _ FALSE ] ~ { NoSurfaces: PROCEDURE [shapes: ShapeSequence] RETURNS[BOOLEAN]~{ FOR i: NAT IN [0..shapes.length) DO IF shapes[i].vertices # NIL AND shapes[i].surfaces # NIL THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; IF context3d.shapes = NIL OR NoSurfaces[context3d.shapes] THEN SetScene1[]; IF context3d.shapes = NIL OR NoSurfaces[context3d.shapes] THEN { context3d.class.draw2DRope[context3d, "No objects, nothing to display", [60, 340] ]; error _ TRUE; }; IF context3d.antiAliasing AND NOT List.Memb[ context3d.class.displayType, LIST[$Gray, $FullColor] ] THEN { context3d.class.draw2DRope[context3d, "NoJaggy needs GrayScale or 24-bit Color", [60, 300] ]; error _ TRUE; }; }; LinesDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { IF DemoErrorMessages[] THEN RETURN; FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetRenderStyle[ FindShape[context3d, context3d.shapes[i].name], lines ]; ENDLOOP; context3d.changed _ TRUE; IF makeFrame THEN context3d.class.render[context3d]; lastDemoCalled _ LinesDemo; }; ShadedLinesDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { IF DemoErrorMessages[] THEN RETURN; FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetRenderStyle[ FindShape[context3d, context3d.shapes[i].name], shadedLines ]; ENDLOOP; context3d.changed _ TRUE; IF makeFrame THEN context3d.class.render[context3d]; lastDemoCalled _ ShadedLinesDemo; }; HiddenLinesDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { tmpContext: Context _ G3dRender.GetTmpContext[context3d]; -- get modifiable context IF DemoErrorMessages[] THEN RETURN; G3dRender.NameBackgroundColor[ tmpContext, "White" ]; G3dRender.CopyContextShapes[tmpContext, context3d]; -- insulate shapes from changes FOR i: NAT IN [0..tmpContext.shapes.length) DO G3dRender.SetRenderStyle[ FindShape[tmpContext, tmpContext.shapes[i].name], hiddenLines ]; ENDLOOP; context3d.changed _ TRUE; IF makeFrame THEN tmpContext.class.render[tmpContext]; lastDemoCalled _ HiddenLinesDemo; }; NormaledLinesDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { tmpContext: Context _ G3dRender.GetTmpContext[context3d]; -- get modifiable context IF DemoErrorMessages[] THEN RETURN; G3dRender.NameBackgroundColor[ tmpContext, "White" ]; G3dRender.CopyContextShapes[tmpContext, context3d]; -- insulate shapes from changes FOR i: NAT IN [0..tmpContext.shapes.length) DO G3dRender.SetColor[ FindShape[tmpContext, tmpContext.shapes[i].name], [1.0, 1.0, 1.0] ]; G3dRender.SetRenderStyle[ FindShape[tmpContext, tmpContext.shapes[i].name], hiddenLines ]; ENDLOOP; context3d.changed _ TRUE; IF makeFrame THEN tmpContext.class.render[tmpContext]; lastDemoCalled _ NormaledLinesDemo; }; FacetedDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { IF DemoErrorMessages[] THEN RETURN; FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetRenderStyle[ FindShape[context3d, context3d.shapes[i].name], faceted ]; ENDLOOP; context3d.changed _ TRUE; IF makeFrame THEN context3d.class.render[context3d]; lastDemoCalled _ FacetedDemo; }; SmoothDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { IF DemoErrorMessages[] THEN RETURN; FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetRenderStyle[ FindShape[context3d, context3d.shapes[i].name], smooth ]; ENDLOOP; context3d.changed _ TRUE; lastDemoCalled _ SmoothDemo; IF makeFrame THEN context3d.class.render[context3d]; }; SetShiny: PROCEDURE [] ~ { FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetShininess[ FindShape[context3d, context3d.shapes[i].name], 50.0 ]; ENDLOOP; context3d.changed _ TRUE; }; SetDull: PROCEDURE [] ~ { FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetShininess[ FindShape[context3d, context3d.shapes[i].name], 0.0 ]; ENDLOOP; context3d.changed _ TRUE; }; InterpressDemo: PROCEDURE [] ~ { fileName: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Length[fileName] < 1 THEN { SIGNAL G3dRender.Error[$MisMatch, "No selection for file name"]; RETURN; }; IF DemoErrorMessages[] THEN RETURN; IF lastDemoCalled # HiddenLinesDemo AND lastDemoCalled # NormaledLinesDemo THEN G3dRenderWithImager.MakeInterpressPage[context3d, fileName ] ELSE { tmpContext: Context _ G3dRender.GetTmpContext[context3d]; -- get mod. context context3d.changed _ TRUE; G3dRender.NameBackgroundColor[ tmpContext, "White" ]; G3dRender.CopyContextShapes[tmpContext, context3d]; -- insulate shapes from change FOR i: NAT IN [0..context3d.shapes.length) DO G3dRender.SetColor[ FindShape[tmpContext, tmpContext.shapes[i].name], [1.0,1.0,1.0] ]; IF G3dRender.ShapeClassFrom[tmpContext.shapes[i]].type # $Light -- avoid lights THEN IF lastDemoCalled # NormaledLinesDemo THEN G3dRender.SetRenderStyle[ FindShape[tmpContext, tmpContext.shapes[i].name], hiddenLines ] ELSE G3dRender.SetRenderStyle[ FindShape[tmpContext, tmpContext.shapes[i].name], linesWnormals ]; ENDLOOP; G3dRenderWithImager.MakeInterpressPage[tmpContext, fileName ] }; }; RandomQuads: PROCEDURE [context: Context] ~ { x, y: REAL; time: REAL _ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]]; width: REAL _ context.viewPort.w; height: REAL _ context.viewPort.h; aspectRatio: REAL _ height / width; rs: Random.RandomStream _ Random.Create[Real.Round[width]]; -- limit to display width p: REF Patch _ NEW[ Patch[4] ]; shape: Shape _ NEW[ShapeRep]; renderData: REF RenderData _ G3dRender.RenderDataFrom[shape]; renderData.shadingClass _ NEW[ShadingClass]; renderData.shadingClass.renderMethod _ $Smooth; p.props _ PutProp[ p.props, $Shape, shape ]; p.nVtces _ 4; FOR i: NAT IN [0..1000) DO IF context.stopMe^ THEN EXIT; x _ Random.NextInt[rs]; y _ Random.NextInt[rs] * aspectRatio; FOR j: NAT IN [0..4) DO xSgn, ySgn: INTEGER; xSgn _ IF j < 1 OR j > 3 THEN -1 ELSE 1; ySgn _ IF j < 2 THEN 1 ELSE -1; p[j].coord.sx _ MAX[0, MIN[ width-1, x + xSgn * Random.NextInt[rs] * 0.1]]; p[j].coord.sy _ MAX[0, MIN[ height-1, y+ySgn * Random.NextInt[rs] *0.1 *aspectRatio]]; p[j].shade.er _ Random.NextInt[rs] / width; p[j].shade.eg _ Random.NextInt[rs] / width; p[j].shade.eb _ Random.NextInt[rs] / width; ENDLOOP; [] _ context.class.displayPolygon[context, p]; ENDLOOP; quadTime _ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] - time; }; SetScene1: PROCEDURE [] ~ { IF scene1 = NIL THEN { Reset[]; G3dRender.AddShapeFromFile[ context3d, "CheckerBoard", -- internal name "CheckerBoard.shape", -- file name [-8.0, -8.0, -2.0] -- position ]; G3dRender.SetColor[ FindShape[context3d, "CheckerBoard"], [.8, .4, .2] ]; -- add shading G3dRender.AddShapeFromFile[ context3d, "Icosahedron", "Icosahedron.shape", [2.0, 0.0, 0.0] ]; G3dRender.SetColor[ FindShape[context3d, "Icosahedron"], [1., 1., 1.] ]; G3dRender.AddShapeFromFile[ context3d, "SoccerBall", "SoccerBall.shape", [-2.0, 0.0, 0.0] ]; G3dRender.SetColor[ FindShape[context3d, "SoccerBall"], [1., 1., 1.] ]; G3dRender.AddShapeFromFile[ context3d, "CutCube", "CutCube.shape", [0.0, 3.0, 0.0] ]; G3dRender.SetColor[ FindShape[context3d, "CutCube"], [.9, .8, .5] ]; scene1 _ NEW[ShapeSequenceRep[context3d.shapes.length]]; FOR i: NAT IN [0..context3d.shapes.length) DO scene1[i] _ context3d.shapes[i]; ENDLOOP; scene1.length _ context3d.shapes.length; } ELSE { context3d.shapes _ NEW[ShapeSequenceRep[scene1.length]]; FOR i: NAT IN [0..scene1.length) DO context3d.shapes[i] _ scene1[i]; ENDLOOP; context3d.shapes.length _ scene1.length; }; G3dRenderWithPixels.DepthBuffering[context3d, FALSE]; currentScene _ scene1; }; SetScene2: PROCEDURE [] ~ { IF scene2 = NIL THEN { Reset[]; G3dRender.AddShapeFromFile[context3d, "ChampagneGlass", "ChampagneGlass.shape", [2.0, 0.0, 0.0] ]; G3dRender.SetColor[ FindShape[context3d, "ChampagneGlass"], [1.,0.,1.] ]; G3dRender.SetTransmittance[ FindShape[context3d, "ChampagneGlass"], 0.8 ]; G3dRender.AddShapeFromFile[context3d, "UtahEgg", "UtahEgg.shape" ]; G3dShape.TransformShape[ shape: FindShape[context3d, "UtahEgg"], translate: [-2.,.0,.0], axis: [[0.0, 0.0, 0.0], [1.0, 1.0, 0.0]], rotation: 90.0 ]; G3dRender.SetColor[ FindShape[context3d, "UtahEgg"], [1.0, .8, .5] ]; G3dRender.AddShapeFromFile[context3d, "Banana", "Banana.shape" ]; G3dRender.SetColor[ FindShape[context3d, "Banana"], [1.0, .9, .1] ]; scene2 _ NEW[ShapeSequenceRep[context3d.shapes.length]]; FOR i: NAT IN [0..context3d.shapes.length) DO scene2[i] _ context3d.shapes[i]; ENDLOOP; scene2.length _ context3d.shapes.length; } ELSE { context3d.shapes _ NEW[ShapeSequenceRep[scene2.length]]; FOR i: NAT IN [0..scene2.length) DO context3d.shapes[i] _ scene2[i]; ENDLOOP; context3d.shapes.length _ scene2.length; }; G3dRenderWithPixels.DepthBuffering[context3d, FALSE]; currentScene _ scene2; }; SetScene3: PROCEDURE [] ~ { IF scene3 = NIL THEN { Reset[]; G3dRender.AddShapeFromFile[context3d, "TeaPot", "TeaPotWithBot.shape", [0.0, 0.0, -1.25]]; scene3 _ NEW[ShapeSequenceRep[context3d.shapes.length]]; FOR i: NAT IN [0..context3d.shapes.length) DO scene3[i] _ context3d.shapes[i]; ENDLOOP; scene3.length _ context3d.shapes.length; G3dRender.SetView[context3d, [3.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; } ELSE { context3d.shapes _ NEW[ShapeSequenceRep[scene3.length]]; FOR i: NAT IN [0..scene3.length) DO context3d.shapes[i] _ scene3[i]; ENDLOOP; context3d.shapes.length _ scene3.length; }; currentScene _ scene3; }; OneShape: PROCEDURE [] ~ { Reset[]; G3dRender.AddShapeFromFile[context3d, "Shape0", ViewerTools.GetSelectionContents[] ]; G3dRender.SetView[context3d, [0.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; }; GetMouseRectangle: PROCEDURE[x, y: REAL] ~ { IF mouseRectangle # NIL THEN { mouseRectangle.w _ x - mouseRectangle.x; IF mouseRectangle.w < 0.0 THEN { mouseRectangle.x _ mouseRectangle.x + mouseRectangle.w; mouseRectangle.w _ -mouseRectangle.w; }; mouseRectangle.h _ y - mouseRectangle.y; IF mouseRectangle.h < 0.0 THEN { mouseRectangle.y _ mouseRectangle.y + mouseRectangle.h; mouseRectangle.h _ -mouseRectangle.h; }; SELECT mouseWaiting FROM $Window => { mouseRectangle.x _ mouseRectangle.x - context3d.viewPort.x; mouseRectangle.y _ mouseRectangle.y - context3d.viewPort.y; mouseRectangle.w _ MIN[mouseRectangle.w, context3d.viewPort.w]; mouseRectangle.x _ 2.0 * (mouseRectangle.x / context3d.viewPort.w - 0.5); -- center mouseRectangle.y _ 2.0 * (mouseRectangle.y - context3d.viewPort.h/2.0) / context3d.viewPort.w; mouseRectangle.w _ 2.0 * mouseRectangle.w / context3d.viewPort.w; mouseRectangle.h _ mouseRectangle.w * context3d.viewPort.h/context3d.viewPort.w; windowStack _ CONS[ context3d.window^, windowStack ]; G3dRender.SetWindow[ context3d, mouseRectangle^ ]; mouseRectangle _ NIL; mouseWaiting _ NIL; }; $ViewPort => { viewPortStack _ CONS[ context3d.viewPort^, viewPortStack ]; G3dRender.SetViewPort[ context3d, mouseRectangle^ ]; mouseRectangle _ NIL; mouseWaiting _ NIL; }; ENDCASE => SIGNAL G3dRender.Error[$MisMatch, "Unknown Mouse Atom"]; } ELSE mouseRectangle _ NEW[ Rectangle _ [x, y, 0.0, 0.0] ]; }; GetWindow: PROCEDURE[] ~ { mouseWaiting _ $Window }; RestoreWindow: PROCEDURE[] ~ { IF windowStack # NIL THEN { G3dRender.SetWindow[ context3d, windowStack.first ]; windowStack _ windowStack.rest; } ELSE SIGNAL G3dRender.Error[$MisMatch, "No previous window"]; }; GetViewPort: PROCEDURE [] ~ { mouseWaiting _ $ViewPort }; RestoreViewPort: PROCEDURE[] ~ { IF viewPortStack # NIL THEN { G3dRender.SetViewPort[ context3d, viewPortStack.first ]; viewPortStack _ viewPortStack.rest; } ELSE SIGNAL G3dRender.Error[$MisMatch, "No previous viewport"]; }; ShowSinglePatch: PROCEDURE[ shapeNumber, patchNumber: NAT, keep: BOOL _ FALSE ] ~ { context3d.props _ PutProp[ context3d.props, $SinglePatch, NEW[ IntegerPair _ [shapeNumber, patchNumber] ] ]; DoCommands[context3d, $Display]; IF NOT keep THEN context3d.props _ Atom.RemPropFromList[ context3d.props, $SinglePatch ]; }; ShowPatchesOnVtx: PROCEDURE[ shapeNumber, vtxNumber: NAT, keep: BOOL _ FALSE ] ~ { context3d.props _ PutProp[ context3d.props, $SingleVtx, NEW[ IntegerPair _ [shapeNumber, vtxNumber] ] ]; DoCommands[context3d, $Display]; IF NOT keep THEN context3d.props _ Atom.RemPropFromList[ context3d.props, $SingleVtx ]; }; Orbit: PROCEDURE [] ~ { IF DemoErrorMessages[] THEN RETURN; animation _ TRUE; G3dAnimationSupport.Orbit[ context: context3d, lookingFrom: context3d.eyePoint, lookingAt: context3d.lookAt, axis: [0.3, 0.0, 1.0], base: context3d.lookAt, framesPerRev: 53 ! UNWIND => animation _ FALSE ]; animation _ FALSE; }; MakeFrame: PROC ~ { context3d.class.render[context3d ]; -- clear and make new frame }; ShowPixels: PROC ~ { context3d.class.drawInViewer[ context3d, NEW[ImagerProcRec _ [G3dColorDisplaySupport.StuffBuf, NIL]] ]; }; ShowShapes: PROC ~ { G3dSortandDisplay.ShowShapes[context3d ]; -- show shapes without clearing }; movieFileRoot: Rope.ROPE; movieFileLog: Rope.ROPE; movieFileLogTime: BasicTime.GMT; movieNumFiles: NAT; movieStart: NAT; movieLabeledFrames: BOOLEAN; SetUpMovie: PROC[fileRoot: Rope.ROPE, numFiles, start: NAT _ 0, labels: BOOLEAN _ FALSE] ~ { fileUpdated: BOOLEAN _ FALSE; IF frames # NIL AND Rope.Equal[movieFileRoot, fileRoot] THEN { latestTime: BasicTime.GMT; [created: latestTime] _ FS.FileInfo[ G3dRender.GetLogFileName[fileRoot] ]; IF BasicTime.Period[from: movieFileLogTime, to: latestTime] > 0 THEN fileUpdated _ TRUE; } ELSE frames _ NIL; IF frames = NIL OR fileUpdated THEN { movieFileRoot _ fileRoot; [fullFName: movieFileLog, created: movieFileLogTime] _ FS.FileInfo[ G3dRender.GetLogFileName[fileRoot] ]; movieNumFiles _ numFiles; movieStart _ start; movieLabeledFrames _ labels; frames _ NIL; }; }; frameRate: INTEGER _ 6; -- playback rate in frames/second, negative plays backwards PlayBackbyFrame: CedarProcess.ForkableProc ~ { CleanUp: PROC ~ { G3dRender.SetViewPort[ context3d, cachedViewPort ]; IF context3d.class.displayType = $PseudoColor THEN G3dColorDisplaySupport.LoadStd8BitClrMap[context3d.terminal]; }; size, posn: Pair; G3dSortandDisplay.ValidateContext[context3d]; cachedViewPort _ context3d.viewPort^; context3d.class.loadBackground[context3d]; IF frames = NIL THEN { frames _ G3dAnimationSupport.CacheNumberedAISFiles[ context3d, movieFileRoot, movieNumFiles, movieStart, movieLabeledFrames ]; }; IF context3d.stopMe^ THEN { CleanUp[]; RETURN[]; }; size _ [frames[0].box.max.f - frames[0].box.min.f, frames[0].box.max.s - frames[0].box.min.s]; posn _ IF context3d.viewer # NIL THEN [ context3d.viewer.cx + (context3d.viewer.cw/2 - size.x/2), context3d.viewer.cy + (context3d.viewer.ch/2 - size.y/2) ] ELSE [ context3d.pixels.box.max.f/2 - size.x/2, context3d.pixels.box.max.s/2 - size.y/2 ]; G3dRender.SetViewPort[ context3d, [ posn.x, posn.y, size.x, size.y ] ]; IF context3d.viewer # NIL THEN ThreeDViewer.ViewerUpdate[context3d]; -- install viewport context3d.class.draw2DRope[context3d, "Control frame rate using left button", [140, 50] ]; WHILE TRUE DO ENABLE UNWIND => CleanUp[]; IF context3d.stopMe^ THEN { CleanUp[]; RETURN[]; }; G3dAnimationSupport.ShowNextAISCacheFrame[context3d, frames, frameRate]; CedarProcess.CheckAbort[]; ENDLOOP; }; Commander.Register["ThreeDDemo", ThreeDDemoCommand, "\nDemonstrate ThreeDWorld"]; END. vThreeDDemoImpl.mesa Last Edited by: Crow, September 21, 1989 9:44:50 am PDT Bloomenthal, September 26, 1988 12:04:57 pm PDT Types Global Variables Renamed Procedures Menu and Button Procs PROC [data: REF] RETURNS [results: REF _ NIL]; Forking this process frees button, reducing likelihood of deadlocks, at least I think that's why this is done this way Context and Interactive Control PROC[context: Context, bttn, ctlShft: ATOM, x, y: REAL] bttn in { $LeftButton, $LeftHeld, $MiddleButton, $MiddleHeld, $RightButton, $RightHeld } ctlShft in { NIL, $Shift, $Control, $ControlShift } This will be called whenever the mouse is moved or a mouse button is pushed. Makes a new view of the supplied context, useful for using two portions of the screen differently, etc. Demos Remove Highlights Scene Definition Frame Generation and Animation Construct viewPort from cached frame size Κ z˜head™J™7Icode™/IdefaultšΟk œΟcœ žœγ˜˜—head2šœœ˜Jšœƒž˜ŒJ˜Jšœ˜J˜—head3šΠbi™Mšœ œ˜!Mšœœœ˜Mšœ œ˜$Mšœœ˜+Mšœ œ˜Mšœ œ˜!Mšœ œ˜"Jšœ œ˜'Jšœœ œ˜Mšœ œ˜!Jšœœ˜,Jšœ œ˜ Jšœ œ˜$Jšœœ˜.Jšœœ˜3Jšœ œ˜)Mšœœ˜.Mš œœœœœœ˜ —šΟb™Jšœœž˜4Jšœ6œ˜:Jšœœ œœ˜1Jšœœ#˜.Jšœœ˜Jšœœ˜!Jšœ œ˜Jšœ œ˜Jšœ œœ˜Mšœ%œ˜)M˜1Mšœœœ œ˜5Mšœœœ˜Jšœœ ˜$—š ™šΟn œœœœ ˜DJšœ˜—š‘œœœœœœ œœœœ‘˜¬Jš‘œ˜!—š‘œΟsœ ’œ ’œ’’œ’’œ’œ˜CJšœ˜J˜—š‘œœœœœœœ ˜RJšœ˜——š ™defualtšœ œœœ˜2šœž˜-šœ œ˜Pšœ.ž˜BPšœ+ž˜APšœ%ž˜:Pšœ6ž ˜CPšœœœž˜)Pšœœœž˜(PšœBž˜QPšœ<ž˜MPšœœœž˜,Pšœ.ž˜CPšœ0ž˜GP˜—P˜P˜&P˜—šœž˜/šœ œ˜Pšœ!ž˜5Pšœ%ž˜;Pšœ#ž˜8Pšœ"ž˜3Pšœ/ž˜>Pšœ0ž˜>Pšœ+ž˜:Pšœ0ž˜AP˜—P˜P˜8P˜—šœ$ž˜6šœ œ˜Pšœž˜3Pšœž˜8Pšœœœž˜-Pšœ+ž ˜8Pšœ*ž˜9Pšœœœž˜&Pšœ-ž˜Pšœœœž˜(Pšœ5ž˜JPšœ1ž˜HPšœœœž˜.P˜#P˜P˜!P˜—P˜P˜BP˜—šœž ˜*šœ œ˜Pšœ6ž˜JPšœ=ž˜SPšœ7ž˜OP˜—P˜P˜P˜—šœž ˜+šœ œ˜Pšœ<ž˜PPšœDž˜TPšœEž˜TPšœ5ž ˜BPšœ/ž˜>Pšœœœž˜(Pšœ/ž˜>Pšœ/ž˜@P˜—P˜P˜%P˜—šœ ž ˜*šœ œ˜Pšœ9ž˜MPšœ@ž˜VPšœ@ž˜UPšœ,ž ˜9Pšœ'ž˜6Pšœ,ž˜:Pšœ'ž˜6Pšœ-ž˜>Pšœ(ž˜8Pšœ.ž˜CPšœ0ž˜GPšœ1ž˜GP˜*P˜2P˜/P˜,P˜1P˜+P˜)P˜—P˜P˜.P˜—šœ"ž˜1Pšœ œ ž˜4P˜P˜.P˜—šœž˜,Pšœ œ ž˜4P˜P˜6P˜—P˜—š‘œ œ œœ˜5Jšœœž˜4šœœœœž*˜Dšœ˜J˜J˜J˜Jšœ˜P˜P˜P˜P˜ Jšœ˜—J˜—J˜—š‘ œ œ œœ˜7Jšœœž˜4šœœœœ˜šœ˜J˜J˜0J˜/J˜J˜0J˜2šœ œ)˜8šœ3˜5šœ ž ˜-J˜&J˜J˜———P˜ Jšœ˜—J˜—J˜—š‘œœœœ˜>Jšœœž˜4šœ˜Jšœ5œ˜Mšœ8œ˜?M˜GM˜=M˜DJšœ˜—šœœœœ˜Jšœ#œ˜(J˜—J˜—š‘ œ œ œœ˜7Jšœœž˜4šœœœœ˜šœ˜˜ Jšœœœ˜#šœ˜J˜J˜Jšœ#œ˜)Jšœ'œ˜-J˜J˜Jšœ˜—J˜—J˜jM˜ Jšœ˜—J˜—J˜—š‘ œœœœ˜7š‘œœ˜Jšœ*œ˜1Jšœ,œ˜3L˜—Jšœœž˜4šœœœœ˜šœœ(˜:Jšœ5ž˜Nšœœ˜J˜˜JšœO˜OJšœ;˜;J˜—˜JšœH˜HJ˜;J˜—˜ JšœO˜O˜ J˜IJ˜—J˜—˜ JšœO˜OJšœ+Οf œ˜NJ˜2J˜—˜ JšœH˜HJ˜LJ˜—˜ JšœH˜HJ˜LJ˜—Jšœ˜——Jšœœ3˜GJ˜—J˜—š‘ œ œ œœ˜8Mšœœž˜4šœœœœ˜šœ˜šœœ*˜Ašœ5œž˜QMšœ/œœ˜P——šœœ#˜9šœ.œž˜LMšœ/œœ˜P——šœœ(˜:šœ2œž˜QMšœ/œœ˜P———šœ˜M˜oM˜@MšœK˜KMšœL˜LMšœG˜GMšœL˜LMšœJ˜JMšœ@˜@MšœG˜GMšœJ˜JMšœF˜FMšœI˜IMšœJ˜JMšœL˜LMšœN˜NMšœH˜HMšœI˜IMš˜—M˜—M˜—š‘œ˜2Mš œœœ œœ™.M™vMšœœœ˜Mšœ œœ ˜&Mšœœœ˜$šœ4œ˜?Mšœœž)˜P—M˜M˜—š ‘œœ œœ ž ˜FMšœœ˜šœ%œ˜4Mšœ œ˜-Mšœ˜ —Mšœœ˜šœœœž$˜DMšœœ˜Mšœœ˜Mšœœ%˜:Mšœ˜ —šœœœ˜Mšœ˜Mšœ!˜!Mšœœ˜Mšœ˜M˜1M˜—M˜—š ‘œœ œœž$˜SJšœœ˜Jšœ!ž'˜HJšœœž&˜GJšœœ˜Jšœ-œ˜2Jšœœ˜JšœC˜CJ˜?J˜AJšœœ˜"Jšœœ˜Jšœ˜Jšœœ˜Jšœ œ˜ J˜HJ˜FJ˜L˜——š ™š‘œ˜,Jšœ˜Iašœ*ž˜=˜J˜Jšœž˜6J˜)J˜J˜Jšœ˜J˜—Jšœ<ž˜SJšœ9ž˜MJ˜?JšœC˜CJ˜—š‘ œœ˜Jšœ˜Jšœ<ž˜SJšœ9ž˜MJ˜?JšœC˜CJ˜—š‘ œœ˜Jšœ˜Jšœ4˜4Jšœ<ž˜SJšœ9ž˜MJ˜?JšœC˜CJ˜—š‘œœ˜!Jšœ˜Jšœ2˜2Jšœ<ž˜SJšœ9ž˜MJ˜?JšœC˜CJ˜—š‘œ œ˜Jšœœ˜J˜—š‘ œ˜(Mšœ œœœ™7J™XJ™3J™LJšœœ˜Jšœ œ˜šœœ˜Jšœœœœ˜J—šœœ˜JšœB˜FJšœB˜FJ˜F—J˜4Jšœž˜.J˜šœ˜šœœœ˜0Jšœ œ˜+šœ˜Jšœ œ$˜3Jšœ œ$˜3Jšœ₯˜₯J˜J˜——˜Jšœœž ˜:Jšœœ ˜J˜EJ˜J˜—˜Jšœ œ$˜3Jšœ₯˜₯J˜J˜—Jšœ˜—J˜J™—š‘ œœ˜Jšœœ˜J˜šœœ˜šœ˜J˜LJ˜—šœ˜ J˜AJ˜AJ˜%J˜——J˜IJ˜"J˜7J˜—š‘ œœ œ˜4Jšœœ˜J˜J˜ J˜\šœœ˜šœ˜J˜LJ˜—šœ˜ J˜AJ˜AJ˜%J˜——J˜IJ˜MJ˜PJ˜J˜J˜—š‘ œœœ œœœœ˜nJ˜J˜ Jšœœ˜J˜\šœœ˜šœ˜J˜LJ˜—šœ˜ J˜AJ˜AJ˜%J˜——J˜IJ˜JJšœœœ*˜Q™gQšœ œ$˜8Q˜XQšœ;ž˜VQšœD˜DQšœœ/˜KQšœœ1˜OQšœœ˜Jšœ/˜/Jšœ.ž'˜UJ˜——š ™š ‘œ œœ œœ˜Fš‘ œ œœœ˜Ašœœœ˜%Jšœœœœœœœ˜NJš˜—Jšœœ˜ J˜—Jšœœœœ ˜Kšœœœœ˜@J˜TJšœœ˜ J˜—šœ˜Jšœœ)œ˜Išœ˜˜&J˜?—Jšœœ˜ J˜——J˜—š‘ œ œ œœ˜8Jšœœœ˜#šœœœœ˜.JšœR˜RJšœ˜—Jšœœ˜Jšœ œ%˜6J˜J˜—š‘œ œ œœ˜>Jšœœœ˜#šœœœœ˜.JšœX˜XJšœ˜—Jšœœ˜Jšœ œ%˜6J˜!J˜—š‘œ œ œœ˜>Jšœ:ž˜SJšœœœ˜#J˜5Jšœ4ž˜Sšœœœœ˜/šœ˜Jšœ>˜>Jšœ˜—Jšœ˜—Jšœœ˜Jšœ œ'˜8J˜!J˜—š‘œ œ œœ˜@Jšœ œ'ž˜SJšœœœ˜#J˜5Jšœ4ž˜Sšœœœœ˜/J˜Xšœ˜Jšœ>˜>Jšœ˜—Jšœ˜—Jšœœ˜Jšœ œ'˜8J˜#J˜—š‘ œ œ œœ˜:Jšœœœ˜#šœœœ˜-JšœT˜TJšœ˜—Jšœœ˜Jšœ œ%˜6J˜J˜—š‘ œ œ œœ ˜;Jšœœœ˜#šœœœœ˜.JšœS˜SJšœ˜—Jšœœ˜J˜Jšœ œ%˜6J˜—š‘œ œ ˜!šœœœ˜-JšœO˜OJšœ˜—Jšœœ˜J˜—š‘œ œ ˜ J™šœœœœ˜.JšœN˜NJšœ˜—Jšœœ˜J˜—š‘œ œ ˜#Jšœœ&˜9šœœ˜%Jšœ:˜@Jšœ˜ J˜—Jšœœœ˜#šœ"œ#˜Jšœ˜J˜<—šœ˜Jšœ œ'ž˜MJšœœ˜J˜5Jšœ3ž˜Ršœœœœ˜.J˜Všœ?ž˜Pšœœ#˜*šœ˜JšœB˜B—šœ˜JšœF˜F———Jšœ˜—J˜=J˜——J˜J˜—š‘ œ œ œ˜.Jšœœ˜ Jšœœ9˜CJšœœ"œ˜GLšœ œ˜#Lšœ=ž˜VJšœœ œ ˜Jšœœ ˜Jšœ œ.˜=Jšœœ˜-Jšœ/˜/Jšœ,˜,Jšœ ˜ šœœœ œ˜Jšœœœ˜Jšœ@˜@šœœœ˜Jšœ œ˜Jšœœœœœœ œœ˜NJšœœœ1˜KJšœœœ<˜VJšœ/˜/Jšœ/˜/Jšœ+˜+Jšœ˜—Jšœ.˜.Jšœ˜—JšœI˜IJšœ˜——š ™š‘ œ œ ˜šœ œœ˜J˜šœ&˜&Jšœž˜'Jšœž ˜(Jšœž ˜%J˜—JšœJž˜YJšœi˜iJšœI˜IJšœ\˜\JšœH˜HJšœU˜UJšœE˜EJšœ œ,˜8šœœœœ˜/J˜"Jšœ˜—J˜(J˜—šœ˜Jšœœ"˜8šœœœœ˜$J˜ Jšœ˜—J˜(J˜—Jšœ.œ˜5J˜J˜—š‘ œ œ ˜šœ œ˜J˜šœy˜yJšœI˜IJšœJ˜J—šœC˜CJšœŸ˜ŸJšœE˜E—šœA˜AJšœD˜D—Jšœ œ,˜9šœœœœ˜/J˜"Jšœ˜—J˜(J˜—šœ˜Jšœœ"˜8šœœœœ˜$J˜ Jšœ˜—J˜(J˜—Jšœ.œ˜5J˜J˜—š‘ œ œ ˜šœ œ˜J˜JšœZ˜ZJšœ œ,˜9šœœœœ˜/J˜"Jšœ˜—J˜(JšœB˜BJ˜—šœ˜Jšœœ"˜8šœœœœ˜$J˜ Jšœ˜—J˜(J˜—J˜J˜—š‘œ œ ˜J˜JšœU˜UJšœB˜BJ˜—š‘œ œœ˜-šœœ˜šœ˜P˜)šœœ˜ P˜;P˜&P˜—P˜)šœœ˜ P˜;P˜&P˜—šœ˜˜ P˜;P˜;Pšœœ)˜?JšœJž ˜S˜J˜K—J˜AP˜PP˜Pšœœ#˜5P˜2Pšœœ˜Pšœœ˜P˜—˜Pšœœ'˜;P˜4Pšœœ˜Pšœœ˜P˜—Pšœœ2˜C—P˜—Pšœœ!˜:—P˜—š‘ œ œ˜P˜P˜—š‘ œ œ˜šœœ˜šœ˜P˜4P˜P˜—Pšœœ2˜=—P˜—š‘ œ œ˜P˜P˜—š‘œ œ˜!šœœ˜šœ˜P˜8P˜#P˜—Pšœœ4˜?—P˜—š ‘œ œœœœ˜Tšœ˜Pšœœ-˜OP˜—P˜ PšœœœI˜YP˜—š ‘œ œœœœ˜Sšœ˜Pšœœ+˜KP˜—P˜ PšœœœG˜WP˜——š ™š‘œ œ˜Jšœœœ˜#Jšœ œ˜˜J˜J˜ Jšœ˜J˜Jšœ˜J˜Jšœœ˜J˜—Jšœ œ˜J˜J˜—š‘ œœ˜Jšœ*ž˜EJ˜—š‘ œœ˜Jšœ)œ3œ˜‚J˜—š‘ œœ˜Jšœ/ž˜NJ˜Jšœœ˜Jšœœ˜Jšœœ˜ Jšœœ˜Jšœ œ˜Jšœœ˜—š ‘ œœœœœœ˜\Qšœ œœ˜ šœ œœ%˜8 šœ˜Jšœœ˜Jšœœ0˜J šœ>˜@Qšœœ˜—Q˜—Qšœ œ˜—šœ œœ œ˜&J˜šœ7œ ˜CJšœ#˜#J˜—J˜J˜Jšœ˜Jšœ œ˜ J˜—J˜Qšœ œž;˜T— š‘œ˜.š‘œœ˜Jšœ3˜3šœ,˜.Jšœ>˜B—J˜—J˜J˜-M˜%J˜* šœ œœ˜šœ3˜3JšœG˜GJ˜—Q˜Q™)—Jšœœœ˜8Q˜^ šœœœ˜!Qšœ€˜„QšœW˜[—QšœG˜GMšœœœ'ž˜YJ˜Zšœœ˜ Jšœœ˜Jšœœœ˜9JšœH˜HJ˜Jšœ˜—Q˜—Q˜—šœQ˜QJ˜Jšœ˜——…—”’Έ’