DIRECTORY Atom, BasicTime, CedarProcess, Commander, FS, G3dAnimationSupport, G3dBasic, G3dColorDisplaySupport, G3dRender, G3dRenderWithImager, G3dRenderWithPixels, G3dShape, G3dSortandDisplay, Imager, ImagerBackdoor, ImagerPixel, 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, Imager, ImagerBackdoor, ImagerPixel, ImageTwiddle, List, Process, Random, Real, Rope, Terminal, ThreeDViewer, ViewerTools ~ BEGIN PropList: TYPE ~ Atom.PropList; ROPE: TYPE ~ Rope.ROPE; Context: TYPE ~ G3dRender.Context; RealSequence: TYPE ~ G3dBasic.RealSequenceRep; 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; ImagerProc: TYPE ~ G3dRender.ImagerProc; 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 ]; }; sumTable: REF RealSequence _ NIL; discreteTable: BOOLEAN _ FALSE; -- TRUE if table made from discrete samples testPatNumStripes, testPatRatio: REAL; MakeCurves: PROC[numStripes: NAT, ratio: REAL] ~ { testPatNumStripes _ numStripes; testPatRatio _ ratio; IF context3d.viewer # NIL THEN { -- do through viewer context3d.class.drawInViewer[context3d, NEW[ImagerProcRec _ [ViewerMakeCurves, NIL]]]; }; }; ViewerMakeCurves: ImagerProc ~ { DoMakeCurves: PROC[pixelMap: ImagerPixel.PixelMap] ~ { Ceiling: PROC[number: REAL] RETURNS[ result: INTEGER ] ~ { result _ Real.RoundI[number]; IF result < number THEN result _ result + 1; }; DrawFilter: PROC[] ~ { IF sumTable # NIL THEN { -- draw convolution filter and pixel fiducials by: NAT _ Real.RoundC[viewPort.h/12.0]; x: NAT _ Real.RoundC[viewPort.w/2.0 - 128.0]; Imager.SetColor[displayContext, Imager.black]; FOR i: NAT IN [0..4] DO -- draw pixel fiducials Imager.MaskVector[displayContext, [ x, by+10 ], [ x, by-10 ]]; Imager.MaskVector[displayContext, [ x+10, by ], [ x-10, by ]]; x _ x + 64; ENDLOOP; FOR i: NAT IN ( 0..sumTable.length ) DO -- draw convolution filter xx: NAT _ Real.RoundC[viewPort.w/2.0 + viewPort.x] + i - sumTable.length/2; yy: INTEGER _ Real.FixI[ (sumTable[i] - sumTable[i-1]) * 35.0 * viewPort.h / 3.0 ]; IF yy # 0.0 AND i # 192 AND i # 64 THEN { IF discreteTable THEN yy _ Real.FixI[ MIN[ .8 * viewPort.h/4.0, yy/15.0 ]]; yy _ by + yy; Imager.MaskVector[displayContext, [ xx-1, by ], [ xx-1, yy ]]; Imager.MaskVector[displayContext, [ xx, by ], [ xx, yy ]]; Imager.MaskVector[displayContext, [ xx+1, by ], [ xx+1, yy ]]; }; ENDLOOP; }; }; numStripes: REAL _ testPatNumStripes; ratio: REAL _ testPatRatio; viewPort: Imager.Rectangle _ ImagerBackdoor.GetBounds[ imagerCtx ]; factor: REAL _ numStripes / viewPort.w; pos: REF RealSequence _ NEW[ RealSequence[numStripes] ]; inc1: REF RealSequence _ NEW[ RealSequence[numStripes] ]; inc2: REF RealSequence _ NEW[ RealSequence[numStripes] ]; line: REF RealSequence _ NEW[ RealSequence[Real.Round[viewPort.w]+4] ]; scanLIne: ImagerPixel.PixelBuffer _ ImagerPixel.NewPixels[ pixelMap, 1, viewPort.w ]; maxValue: REAL _ 255.0; viewPort.h _ viewPort.h * 3.0 / 4.0; -- use just 3/4 of viewport FOR i: NAT IN [ 0..numStripes ) DO -- draw spacing curve pos[i] _ ( 1.0 - ratio/(i+ratio) ) * viewPort.w * 1.0 / (1.0 - ratio / (numStripes+ratio)); inc1[i] _ Real.Float[(numStripes - i)] / numStripes; inc2[i] _ -2 * inc1[i] / viewPort.h; ENDLOOP; Imager.DoSaveAll[imagerCtx, DrawFilter]; FOR y: NAT IN [ Real.RoundC[viewPort.h/3.0] .. Real.RoundC[viewPort.h*4.0/3.0] ) DO lastX, thisX: REAL _ 0; white: BOOLEAN _ TRUE; IF sumTable # NIL THEN FOR i: NAT IN [0..line.length) DO line[i] _ 0.0; ENDLOOP; FOR i: NAT IN [ 0 .. numStripes ) DO pxlValue: CARDINAL; thisX _ pos[i]; IF white THEN pxlValue _ Real.FixC[maxValue] ELSE pxlValue _ 0; IF sumTable = NIL THEN -- no table, output plain FOR x: NAT IN [ Real.FixC[lastX] .. Real.FixC[thisX] ) DO IF x < Real.RoundC[viewPort.w] THEN scanLine[x] _ pxlValue; ENDLOOP ELSE IF sumTable.length = 128 THEN { -- 2-pixel table tX: REAL _ thisX + 2; lX: REAL _ lastX + 2; IF white THEN { lastIndex: NAT _ Real.FixC[lX * 64.0 - (Real.FixC[lX] * 64)]; thisIndex: NAT _ Real.FixC[tX * 64.0 - (Real.FixC[tX] * 64)]; loopStart: NAT _ Real.FixC[lX]-1; loopEnd: NAT _ Real.FixC[tX]; FOR x: NAT IN [ loopStart .. loopEnd ] DO SELECT x FROM loopStart => { line[x] _ line[x] + 1.0 - sumTable[lastIndex+64]; IF loopStart = loopEnd-1 THEN line[x] _ line[x] - (1.0 - sumTable[thisIndex+64]); }; loopStart+1 => { line[x] _ line[x] + 1.0 - sumTable[lastIndex]; IF loopStart = loopEnd-1 THEN line[x] _ line[x] - (1.0 - sumTable[thisIndex]); IF loopStart = loopEnd-2 THEN line[x] _ line[x] - (1.0 - sumTable[thisIndex+64]); }; loopEnd-1 => { line[x] _ line[x] + sumTable[thisIndex+64]; }; loopEnd => { line[x] _ line[x] + sumTable[thisIndex]; }; ENDCASE => line[x] _ 1.0; ENDLOOP; } } ELSE IF sumTable.length = 256 THEN { -- 4-pixel negative lobe table tX: REAL _ thisX + 2; lX: REAL _ lastX + 2; IF white THEN { lastIndex: NAT _ Real.FixC[lX * 64.0 - (Real.FixC[lX] * 64)]; thisIndex: NAT _ Real.FixC[tX * 64.0 - (Real.FixC[tX] * 64)]; loopStart: NAT _ Real.FixC[lX]-2; loopEnd: NAT _ Real.FixC[tX]+1; FOR x: NAT IN [ loopStart .. loopEnd ] DO SELECT x FROM loopStart => { line[x] _ line[x] + sumTable[255] - sumTable[lastIndex+192]; IF loopStart = loopEnd-3 -- start and end in same pixel span THEN line[x] _ line[x] - (sumTable[255] - sumTable[thisIndex+192]); }; loopStart+1 => { line[x] _ line[x] + sumTable[255] + sumTable[191] - sumTable[lastIndex+128]; IF loopStart = loopEnd-3 -- start and end in same pixel span THEN line[x] _ line[x] - ( sumTable[255] + sumTable[191] - sumTable[thisIndex+128] ); IF loopStart = loopEnd-4 -- start and end in adjacent pixel spans THEN line[x] _ line[x] - ( sumTable[255] - sumTable[thisIndex+192] ); }; loopStart+2 => { line[x] _ line[x] + sumTable[255] + sumTable[191] - sumTable[lastIndex+64]; IF loopStart = loopEnd-3 -- start and end in same pixel span THEN line[x] _ line[x] - ( sumTable[255] + sumTable[191] - sumTable[thisIndex+64] ); IF loopStart = loopEnd-4 -- start and end in adjacent pixel spans THEN line[x] _ line[x] - ( sumTable[255] + sumTable[191] - sumTable[thisIndex+128] ); IF loopStart = loopEnd-5 -- start and end in pixels separated by one span THEN line[x] _ line[x] - ( sumTable[255] - sumTable[thisIndex+192] ); }; loopStart+3 => { line[x] _ line[x] + sumTable[255] + sumTable[191] + sumTable[63] - sumTable[lastIndex]; IF loopStart = loopEnd-3 -- start and end in same pixel span THEN line[x] _ line[x] - ( sumTable[255] + sumTable[191] + sumTable[63] - sumTable[thisIndex] ); IF loopStart = loopEnd-4 -- start and end in adjacent pixel spans THEN line[x] _ line[x] - ( sumTable[255] + sumTable[191] - sumTable[thisIndex+64] ); IF loopStart = loopEnd-5 -- start and end in pixels separated by one span THEN line[x] _ line[x] - ( sumTable[255] + sumTable[191] - sumTable[thisIndex+128] ); IF loopStart = loopEnd-6 -- start and end in pixels separated by two spans THEN line[x] _ line[x] - ( sumTable[255] - sumTable[thisIndex+192] ); }; loopEnd-3 => { line[x] _ line[x] + sumTable[63] + sumTable[191] + sumTable[thisIndex+192]; }; loopEnd-2 => { line[x] _ line[x] + sumTable[63] + sumTable[thisIndex+128]; }; loopEnd-1 => { line[x] _ line[x] + sumTable[63] + sumTable[thisIndex+64]; }; loopEnd => { line[x] _ line[x] + sumTable[thisIndex]; }; ENDCASE => line[x] _ 1.0; ENDLOOP; } }; white _ NOT white; pos[i] _ pos[i] + inc1[i]; inc1[i] _ inc1[i] + inc2[i]; lastX _ thisX; ENDLOOP; IF sumTable # NIL THEN FOR i: NAT IN [2..Real.RoundC[viewPort.w]+2) DO pixelValue: INTEGER _ MAX[ 0, Real.FixI[ MIN[maxValue, line[i]*(maxValue)] ] ]; scanLine[i-2] _ pixelValue; ENDLOOP; ImagerPixel.PutPixels[ self: pixelMap, pixels: scanLine, initIndex: [f: xStart, s: y], count: viewPort.w ]; ENDLOOP; }; ImagerBackdoor.AccessBufferRectangle[imagerCtx, DoMakeCurves, context.viewPort^]; }; MakeNilTable: PROC[] ~ { sumTable _ NIL; }; MakeImpulseTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0 .. 64) DO sumTable[i] _ 0.0; ENDLOOP; FOR i: NAT IN [64 .. 128) DO sumTable[i] _ 1.0; ENDLOOP; discreteTable _ TRUE; }; Make2ImpulseTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0 .. 48) DO sumTable[i] _ 0.0; ENDLOOP; FOR i: NAT IN [48 .. 80) DO sumTable[i] _ 0.5; ENDLOOP; FOR i: NAT IN [80 .. 128) DO sumTable[i] _ 1.0; ENDLOOP; discreteTable _ TRUE; }; Make4ImpulseTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0 .. 40) DO sumTable[i] _ 0.0; ENDLOOP; FOR i: NAT IN [40 .. 56) DO sumTable[i] _ 0.25; ENDLOOP; FOR i: NAT IN [56 .. 72) DO sumTable[i] _ 0.50; ENDLOOP; FOR i: NAT IN [72 .. 88) DO sumTable[i] _ 0.75; ENDLOOP; FOR i: NAT IN [88 .. 128) DO sumTable[i] _ 1.0; ENDLOOP; discreteTable _ TRUE; }; Make8ImpulseTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0 .. 36) DO sumTable[i] _ 0.000; ENDLOOP; FOR i: NAT IN [36 .. 44) DO sumTable[i] _ 0.125; ENDLOOP; FOR i: NAT IN [44 .. 52) DO sumTable[i] _ 0.250; ENDLOOP; FOR i: NAT IN [52 .. 60) DO sumTable[i] _ 0.375; ENDLOOP; FOR i: NAT IN [60 .. 68) DO sumTable[i] _ 0.500; ENDLOOP; FOR i: NAT IN [68 .. 76) DO sumTable[i] _ 0.625; ENDLOOP; FOR i: NAT IN [76 .. 84) DO sumTable[i] _ 0.750; ENDLOOP; FOR i: NAT IN [84 .. 92) DO sumTable[i] _ 0.875; ENDLOOP; FOR i: NAT IN [92 .. 128) DO sumTable[i] _ 1.000; ENDLOOP; discreteTable _ TRUE; }; MakeWtd8ImpulseTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0 .. 8) DO sumTable[i] _ 0.0/32.0; ENDLOOP; FOR i: NAT IN [8 .. 24) DO sumTable[i] _ 1.0/32.0; ENDLOOP; FOR i: NAT IN [24 .. 40) DO sumTable[i] _ 4.0/32.0; ENDLOOP; FOR i: NAT IN [40 .. 56) DO sumTable[i] _ 9.0/32.0; ENDLOOP; FOR i: NAT IN [56 .. 72) DO sumTable[i] _ 16.0/32.0; ENDLOOP; FOR i: NAT IN [72 .. 88) DO sumTable[i] _ 23.0/32.0; ENDLOOP; FOR i: NAT IN [88 .. 104) DO sumTable[i] _ 28.0/32.0; ENDLOOP; FOR i: NAT IN [104 .. 120) DO sumTable[i] _ 31.0/32.0; ENDLOOP; FOR i: NAT IN [120 .. 128) DO sumTable[i] _ 32.0/32.0; ENDLOOP; discreteTable _ TRUE; }; MakeWtd16ImpulseTable: PROC[] ~ { sum: REAL _ 0; lastPos: NAT _ 0; thisPos: NAT _ 4; sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0..16) DO j: NAT _ 8 - ABS[8 - i]; IF i > 7 THEN j _ j -1; FOR k: NAT IN [lastPos .. thisPos) DO sumTable[k] _ sum; ENDLOOP; sum _ sum + (j*2 + 1)/128.0; lastPos _ thisPos; thisPos _ thisPos + 8; ENDLOOP; FOR k: NAT IN [lastPos .. 128) DO sumTable[k] _ 1.0; ENDLOOP; discreteTable _ TRUE; }; MakeBoxTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0 .. 32) DO sumTable[i] _ 0.0; ENDLOOP; FOR i: NAT IN [32 .. 96) DO sumTable[i] _ (i-32) / 64.0; ENDLOOP; FOR i: NAT IN [96 .. 128) DO sumTable[i] _ 1.0; ENDLOOP; discreteTable _ FALSE; }; MakeTriangleTable: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0..64) DO t: REAL _ i * 1.0 / 64.0; sumTable[i] _ Sqr[t] / 2.; sumTable[i + 64] _ 1. - Sqr[1. - t] / 2.; ENDLOOP; discreteTable _ FALSE; }; MakeGaussTable: PROC[spread: REAL] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0..64) DO t: REAL _ (i * 1.0 / 64.0); sumTable[64 + i] _ RealFns.Exp[-spread*t*t]; sumTable[63 - i] _ sumTable[64 + i]; ENDLOOP; FOR i: NAT IN (0..128) DO sumTable[i] _ sumTable[i-1] + sumTable[i]; ENDLOOP; FOR i: NAT IN [0..128) DO sumTable[i] _ sumTable[i] / sumTable[127]; ENDLOOP; discreteTable _ FALSE; }; MakeSinc2Table: PROC[] ~ { sumTable _ NEW[ RealSequence[128] ]; FOR i: NAT IN [0..64) DO t: REAL _ (1.0 - i * 1.0 / 64.0) * 3.1416; sumTable[i] _ RealFns.Sin[t] / t; sumTable[127 - i] _ sumTable[i]; ENDLOOP; FOR i: NAT IN (0..128) DO sumTable[i] _ sumTable[i-1] + sumTable[i]; ENDLOOP; FOR i: NAT IN [0..128) DO sumTable[i] _ sumTable[i] / sumTable[127]; ENDLOOP; discreteTable _ FALSE; }; MakeSinc4Table: PROC[weighted, sincWeighting: BOOLEAN _ TRUE] ~ { completeSum: REAL; sumTable _ NEW[ RealSequence[256] ]; FOR i: NAT IN [0..128) DO t: REAL _ (2.0 - i * 1.0 / 64.0) * 3.1416; sumTable[i] _ RealFns.Sin[t] / t; IF weighted THEN IF sincWeighting THEN sumTable[i] _ (RealFns.Sin[t/2.0] / (t/2.0)) * sumTable[i] ELSE sumTable[i] _ (i * 1.0 / 128.0) * sumTable[i]; -- triangle weight sumTable[255 - i] _ sumTable[i]; ENDLOOP; FOR i: NAT IN (0..64) DO sumTable[i] _ sumTable[i-1] + sumTable[i]; sumTable[i+192] _ sumTable[i+192-1] + sumTable[i+192]; ENDLOOP; FOR i: NAT IN (0..128) DO sumTable[i+64] _ sumTable[i+64-1] + sumTable[i+64]; ENDLOOP; completeSum _ sumTable[63] + sumTable[191] + sumTable[255]; FOR i: NAT IN [0..256) DO sumTable[i] _ sumTable[i] / completeSum; ENDLOOP; sumTable[0] _ sumTable[0]; discreteTable _ FALSE; }; 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. "ThreeDDemoImpl.mesa Last Edited by: Crow, December 8, 1989 11:19:46 pm PST 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 Test Patterns for filter evaluation Calculates the integral over the pyramid function, equal to the left half of a parabolic window or B-spline basis function Calculates the integral over the central lobe of the sinc function Calculates the integral over the central lobe of the sinc function Calculates the integral over the inner 3 lobes of the sinc function weighted by the inner lobe stretched by 2 or weighted by a triangle Frame Generation and Animation Construct viewPort from cached frame size Κ/Ύ˜head™J™6Icode™/IdefaultšΟk œΟcœ žœŠ˜Ώ—head2šœœ˜Jšœ¨ž˜±J˜Jšœ˜J˜—head3šΠbi™Mšœ œ˜!Mšœœœ˜Mšœ œ˜$Jšœœ˜.Mšœœ˜+Mšœ œ˜Mšœ œ˜!Mšœ œ˜"Jšœ œ˜'Jšœœ œ˜Mšœ œ˜!Jšœœ˜,Jšœ œ˜ Jšœ œ˜$Jšœœ˜.Jšœœ˜3Jšœ œ˜)Mšœ œ˜)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šœœœž+˜NJšœ!œ˜&J˜—š‘ œœ œ œ˜2Qšœ8˜8 šœœœž˜@Qšœ(œ$œ˜VQ˜—J˜J˜—š‘œ˜ š‘ œœ$˜6 š ‘œœ œœ œ˜:Qšœ˜Qšœœ˜,Q˜— š‘ œœ˜ šœ œœž.˜JQšœœ ˜'Qšœœ'˜-Qšœ.˜. šœœœž˜6Qšœ>˜>Qšœ>˜>Qšœ ˜ Qšœ˜— šœœœž˜DQšœœD˜KQšœœH˜S šœ œ œœ˜)Qšœœœ#˜LQšœ ˜ Qšœ>˜>Qšœ:˜:Qšœ>˜>Q˜—Qšœ˜—Q˜—Q˜Q˜—Qšœ œ œ˜DQšœC˜CQšœœ˜'Jšœœœ˜8Jšœœœ˜9Jšœœœ˜9Jšœœœ+˜GJšœU˜UJšœ œ ˜Jšœ&ž˜AQ˜ š œœœœž˜:Qšœ[˜[Qšœ4˜4Qšœ$˜$Qšœ˜Q˜— šœ(˜(Q˜— šœœœJ˜YQšœœ˜Qšœœœ˜Qšœ œœœœœœœ˜R šœœœ˜$Qšœ œ˜Qšœ˜Qšœœ œ˜? šœ œœž˜2 šœœœ*˜9 šœ˜Qšœ˜—Qš˜—— šœœœž˜6Qšœœ ˜Qšœœ˜ šœœ˜Qšœ œ/˜=Qšœ œ/˜=Qšœ œ˜!Qšœ œ˜ šœœœ˜) šœ˜ šœ˜Qšœ1˜1 šœ˜Qšœ4˜8—Qšœ˜— šœ˜Qšœ.˜. šœ˜Qšœ1˜5— šœ˜Qšœ4˜8Qšœ˜—— šœ˜Qšœ+˜+Q˜— šœ ˜ Qšœ(˜(Qšœ˜—Qšœ˜—Qšœ˜—Qšœ˜—Qšœ˜— šœœœž˜DQšœœ ˜Qšœœ˜ šœœ˜Qšœ œ/˜=Qšœ œ/˜=Qšœ œ˜!Qšœ œ˜ šœœœ˜) šœ˜ šœ˜Qšœ<˜< šœž#˜?Qšœ?˜C—Qšœ˜— šœ˜QšœR˜R šœž#˜?QšœW˜[— šœž(˜DQšœA˜E—Qšœ˜— šœ˜QšœQ˜Q šœž#˜?QšœY˜]— šœž(˜DQšœZ˜^— šœž1˜IQšœA˜E—Qšœ˜— šœ˜Qšœ]˜] šœž#˜?Qšœd˜h— šœž(˜DQšœY˜]— šœž1˜IQšœZ˜^— šœž2˜JQšœA˜E—Qšœ˜— šœ˜QšœQ˜QQ˜— šœ˜Qšœ;˜;Q˜— šœ˜Qšœ:˜:Q˜— šœ ˜ Qšœ(˜(Qšœ˜—Qšœ˜—Qšœ˜—Qšœ˜—Qšœ˜—Qšœœ˜Qšœ˜Qšœ˜Qšœ˜Qšœ˜— š œ œœœœœ ˜FQšœ œœœ#˜OQšœ˜Qšœ˜—Qšœs˜sQšœ˜—Qšœ˜—JšœQ˜QQ˜J˜š‘ œœ˜Jšœ œ˜Jšœ˜J˜—š‘œœ˜Jšœ œ˜$Jš œœœ œœ˜9Jš œœœ œœ˜9Jšœœ˜Jšœ˜J˜—š‘œœ˜Jšœ œ˜$Jš œœœ œœ˜9Jš œœœœœ˜:Jš œœœ œœ˜9Jšœœ˜Jšœ˜J˜—š‘œœ˜Jšœ œ˜$Jš œœœ œœ˜9Jš œœœœœ˜;Jš œœœœœ˜;Jš œœœœœ˜;Jš œœœ œœ˜9Jšœœ˜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šœœ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜$šœœœ œ˜Jš œœœ œœ ˜3Jš œœœœœ˜DJšœ˜Jšœ˜Jšœ˜Jšœ˜—Jš œœœœœ˜@Jšœœ˜Jšœ˜J˜—š‘ œœ˜Jšœ œ˜$Jš œœœ œœ˜9Jš œœœ œœ˜CJš œœœ œœ˜9Jšœœ˜Jšœ˜J˜—š‘œœ˜J™zJšœ œ˜$šœœœ œ˜Jšœœ˜Jšœ˜Jšœ)˜)Jšœ˜—Jšœœ˜J˜J˜—š‘œœ œ˜&J™BJšœ œ˜$šœœœ œ˜Jšœœ˜Jšœ,˜,Jšœ$˜$Jšœ˜—šœœœ œ˜Jšœ*˜*Jšœ˜—šœœœ œ˜Jšœ*˜*Jšœ˜—Jšœœ˜Jšœ˜J˜—š‘œœ˜J™BJšœ œ˜$šœœœ œ˜Jšœœ#˜*Jšœ!˜!Jšœ ˜ Jšœ˜—šœœœ œ˜Jšœ*˜*Jšœ˜—šœœœ œ˜Jšœ*˜*Jšœ˜—Jšœœ˜Jšœ˜J˜—š‘œœœœ˜AJ™‡Jšœ œ˜Jšœ œ˜$šœœœ œ˜Jšœœ#˜*Jšœ!˜!šœ œ˜Jšœœ;˜PJšœœ1ž˜M—Jšœ ˜ Jšœ˜—šœœœ œ˜Jšœ*˜*Jšœ6˜6Jšœ˜—šœœœ œ˜Jšœ3˜3Jšœ˜—Jšœ;˜;šœœœ œ˜Jšœ(˜(Jšœ˜—Jšœ˜Jšœœ˜J˜J˜———š ™š‘œ œ˜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šœ˜——…—Δ.ω