<> <> <> DIRECTORY Atom USING [ GetPropFromList, PutPropOnList, RemPropFromList ], BasicTime USING [ GMT, Period, PulsesToSeconds, GetClockPulses ], FS USING [ FileInfo ], List USING [ Memb ], CedarProcess USING [ Abort, CheckAbort, Process, Fork, ForkableProc ], Commander USING [ CommandProc, Register ], Process USING [ PauseMsec, Yield ], Rope USING [ Equal, Length, ROPE ], Real USING [ Fix, Float, Round ], Random USING [ Create, NextInt, RandomStream ], ViewerTools USING [ GetSelectionContents ], Terminal USING [ GetColorCursorPosition ], Imager USING [ Context ], ThreeDBasics USING [ Context, Create, Error, ImagerProcRec, IntegerPair, LoadDisplayType, Pair, Patch, Pixel, Rectangle, RGB, SetView, ShadingClass, ShapeInstance, ShapeSequence, Triple ], ThreeDViewer USING [ ButtonDesc, DrawInViewer, MakeViewer, MouseProc, SwitchDisplayTo, ViewerUpdate ], ColorDisplayRender USING [ Orbit, StuffBuf, LoadStd8BitClrMap ], ImageTwiddle USING [ SetUpTerrainColors ], AISAnimation USING [ CacheNumberedAISFiles, FrameSequence, GetAIS, GetLogFileName, PutAIS, ShowNextAISCacheFrame ], SurfaceRender USING [ ShowShapes, ValidateContext ], RenderWithImager USING [ MakeInterpressPage ], RenderWithPixels USING [ AntiAliasing, BufferRendering, DepthBuffering, MakeFrame, PolygonTiler, AllocatePixelMemory ], SceneUtilities USING [ AddShapeAt, CopyContextShapes, CopyShapeDirect, GetTmpContext, NameBackgroundColor, OrientShape, RotateShapeLocal, SetAmbientLight, SetColor, SetDull, SetFaceted, SetHiddenLines, SetLight, SetLines, SetNormaledLines, SetShadedLines, SetShiny, SetSmooth, SetTransparent, SetWindow, SetViewPort, StartLog ]; ThreeDDemoImpl: CEDAR MONITOR IMPORTS AISAnimation, Atom, BasicTime, CedarProcess, ColorDisplayRender, Commander, FS, ImageTwiddle, List, Process, Random, Real, RenderWithImager, RenderWithPixels, Rope, SceneUtilities, SurfaceRender, Terminal, ThreeDBasics, ThreeDViewer, ViewerTools ~ BEGIN <> ROPE: TYPE ~ Rope.ROPE; Context: TYPE ~ ThreeDBasics.Context; IntegerPair: TYPE ~ ThreeDBasics.IntegerPair; Pair: TYPE ~ ThreeDBasics.Pair; Pixel: TYPE ~ ThreeDBasics.Pixel; Triple: TYPE ~ ThreeDBasics.Triple; Rectangle: TYPE ~ ThreeDBasics.Rectangle; RGB: TYPE ~ ThreeDBasics.RGB; ShadingClass: TYPE ~ ThreeDBasics.ShadingClass; ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance; ShapeSequence: TYPE ~ ThreeDBasics.ShapeSequence; ImagerProcRec: TYPE ~ ThreeDBasics.ImagerProcRec; LORA: TYPE ~ LIST OF REF ANY; <> context3d, offScreenCtx: REF Context; -- , onScreenCtx currentScene, scene1, scene2, scene3: REF ShapeSequence _ NIL; lastDemoCalled: PROC[makeFrame: BOOLEAN _ FALSE]; frames: REF AISAnimation.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; <> 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: REF 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: REF 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: REF Context, key: ATOM] ~ { context.stopMe^ _ FALSE; -- unstick stop button SELECT key FROM $Jaggy => RenderWithPixels.AntiAliasing[context, FALSE]; $Visible => RenderWithPixels.BufferRendering[context, FALSE]; $Imager => context.preferredRenderMode _ $Imager; $NoJaggy => IF context.class.displayType # $PseudoColor OR ThreeDViewer.SwitchDisplayTo[context, $FullColor] THEN { context.preferredRenderMode _ $Pixels; RenderWithPixels.AntiAliasing[context, TRUE]; }; $Buffered => RenderWithPixels.BufferRendering[context, TRUE]; $Pixels => context.preferredRenderMode _ $Pixels; $ZBuffer => RenderWithPixels.DepthBuffering[context, TRUE]; $Sorted => RenderWithPixels.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: REF 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 => AISAnimation.PutAIS[ context3d, ViewerTools.GetSelectionContents[] ]; $Interpress => InterpressDemo[]; ENDCASE; }; }; ShowMotion: ENTRY PROC[context: REF Context, key: ATOM] ~ { 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]; SetUpMovie[ fileRoot: ViewerTools.GetSelectionContents[] ]; }; $SelectGray => { [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; SetUpMovie[ fileRoot: ViewerTools.GetSelectionContents[] ]; }; $Shapes => { [] _ ThreeDViewer.SwitchDisplayTo[context, $PseudoColor]; SetUpMovie[ fileRoot: "/Pixel/Crow/Animation/StillCloser.ais", numFiles: 40, start: 1 ]; }; $Terrain => { [] _ ThreeDViewer.SwitchDisplayTo[context, $PseudoColor]; SetUpMovie[ fileRoot: "/Cyan/AIS/Animation/LakeSceneTest.ais", numFiles: 64 ]; ImageTwiddle.SetUpTerrainColors[context.terminal]; }; $Web1 => { [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; SetUpMovie[ fileRoot: "/Pixel/Crow/Animation/Paper4Web.ais", numFiles: 40 ]; }; $Web2 => { [] _ ThreeDViewer.SwitchDisplayTo[context, $Gray]; SetUpMovie[ fileRoot: "/Pixel/Crow/Animation/Paper5Web.ais", numFiles: 40 ]; }; ENDCASE; IF key # $Orbit THEN movieProcess _ CedarProcess.Fork[PlayBackbyFrame]; }; }; ShowPicture: ENTRY PROC[context: REF 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 => [] _ AISAnimation.GetAIS[context3d, ViewerTools.GetSelectionContents[] ]; $Spoon => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/Spoon.ais" ]; $Bananas => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/FieldOfBanana.ais" ]; $Compare => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/ComparisonEggs.ais" ]; $Bowl => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/BowlAndSpoon.ais" ]; $TeaPot => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/ZebraBurlTeaPot.ais" ]; $Eggtxtr => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/MultiTxtrdEgg2.ais" ]; $Heart => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/Heart.ais" ]; $Objects => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/TestScene2.ais" ]; $Extents => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/FiveObjWBoxes.ais" ]; $HexTiles => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/HexTiles.ais" ]; $MikHead => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/Lamming6Scene.ais" ]; $MikTrees => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/Lamming7Scene.ais" ]; $BallPage => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/SphereWithPage.ais" ]; $BallPages => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/SphereWithPages.ais" ]; $TeaPages => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/PagedTeaPot.ais" ]; $SolidLines => [] _ AISAnimation.GetAIS[context3d, "/cyan/AIS/Crow/StillLines.ais" ]; ENDCASE }; }; WaitThenShowPicture: CedarProcess.ForkableProc ~ { <> <> list: LORA _ NARROW[data]; context: REF Context _ NARROW[list.first]; key: ATOM _ NARROW[list.rest.first]; WHILE Atom.GetPropFromList[ context.displayProps, $ViewerAdjusted ] # NIL DO Process.PauseMsec[ 500 ]; ENDLOOP; -- wait for viewer paint proc to complete ShowPicture[context, key]; }; StopEverything: PROC[context: REF Context, key: ATOM] ~ { -- panic stop bkgrdContext: REF Context _ NIL; WITH Atom.GetPropFromList[context.props, $BackGround] SELECT FROM bkGrdCtx: REF Context => bkgrdContext _ bkGrdCtx; ENDCASE; context.stopMe^ _ TRUE; WHILE bkgrdContext # NIL DO -- stop chain of background contexts tmpCtx: REF Context _ bkgrdContext; tmpCtx.stopMe^ _ TRUE; bkgrdContext _ NARROW[Atom.GetPropFromList[tmpCtx.props, $BackGround]]; ENDLOOP; IF movieProcess # NIL THEN { Process.Yield[]; CedarProcess.Abort[movieProcess]; movieProcess _ NIL; Process.Yield[]; SceneUtilities.SetViewPort[ context, cachedViewPort ]; }; }; DoReset: PROC [context: REF 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 _ context3d.lightSources _ NIL; ThreeDBasics.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; SceneUtilities.SetLight[context3d, "Default", [-100., -200., 50.] ]; SceneUtilities.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 ]; context3d.class.render[context3d]; -- update everything }; <> ThreeDDemoCommand: Commander.CommandProc ~ { context3d _ ThreeDBasics.Create[]; context3d.preferredRenderMode _ $Pixels; -- $Pixels, Imager; ThreeDViewer.MakeViewer[ context: context3d, displayType: $PseudoColor, -- $Gray, ImagerDithered bannerName: "ThreeDWorld Demonstration", menu: demoMenu, mouseAction: MouseControl, verticalMenu: FALSE ]; SceneUtilities.NameBackgroundColor[ context3d, "Darkish Blue" ]; -- set background color SceneUtilities.SetAmbientLight[ context3d, "Darkish Gray" ]; -- set ambient light SceneUtilities.SetLight[context3d, "Default", [-100., -200., 50.] ]; ThreeDBasics.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; }; Reset: PROCEDURE [] ~ { DoReset[context3d, NIL]; }; InitNoViewer: PROC[] ~ { context3d _ ThreeDBasics.Create[]; ThreeDBasics.LoadDisplayType[context3d, $PseudoColor]; SceneUtilities.NameBackgroundColor[ context3d, "Darkish Blue" ]; -- set background color SceneUtilities.SetAmbientLight[ context3d, "Darkish Gray" ]; -- set ambient light SceneUtilities.SetLight[context3d, "Default", [-100., -200., 50.] ]; ThreeDBasics.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; SetScene1[]; }; 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.ptOfInterest.x; yNow _ (y * ABS[y] / divisor) + context3d.ptOfInterest.y; ThreeDBasics.SetView[ context, [xNow, yNow, zNow], context.ptOfInterest, 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; [] _ SceneUtilities.SetLight[ context, "Default", [xLight, yLight, 50.0] ]; DoCommands[context, $Display]; }; $RightButton, $RightHeld => { zNow _ (y * ABS[y] / divisor) + context3d.ptOfInterest.z; ThreeDBasics.SetView[ context, [xNow, yNow, zNow], context.ptOfInterest, 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: REF Context, width, height: NAT] ~ { offScreenCtx _ SceneUtilities.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] ] ]; RenderWithPixels.AllocatePixelMemory[offScreenCtx]; -- get display memory SceneUtilities.SetViewPort[ offScreenCtx, [0.0, 0.0, Real.Float[width], Real.Float[height]] ]; IF context.antiAliasing THEN RenderWithPixels.AntiAliasing[offScreenCtx];-- get state straight IF context.depthBuffering THEN RenderWithPixels.DepthBuffering[offScreenCtx]; [] _ SceneUtilities.StartLog[offScreenCtx]; FOR i: NAT IN [0..offScreenCtx.shapes.length) DO offScreenCtx.shapes[i].vtcesInValid _ TRUE; ENDLOOP; SurfaceRender.ValidateContext[offScreenCtx]; SurfaceRender.ValidateContext[context]; -- just in case it hasn't been used yet }; GetOnScreenCtx: PROC[context: REF Context, width, height: NAT] ~ { <> onScreenCtx: REF Context _ SceneUtilities.GetTmpContext[context]; SceneUtilities.SetViewPort[ onScreenCtx, [0.0, 0.0, Real.Float[width], Real.Float[height]] ]; onScreenCtx.class.render _ RenderWithPixels.MakeFrame; -- load direct memory procs onScreenCtx.class.displayPolygon _ RenderWithPixels.PolygonTiler; IF context.antiAliasing THEN RenderWithPixels.AntiAliasing[onScreenCtx]; IF context.depthBuffering THEN RenderWithPixels.DepthBuffering[onScreenCtx]; FOR i: NAT IN [0..onScreenCtx.shapes.length) DO onScreenCtx.shapes[i].vtcesInValid _ TRUE; ENDLOOP; SurfaceRender.ValidateContext[onScreenCtx]; SurfaceRender.ValidateContext[context]; -- just in case it hasn't been used yet }; <> DemoErrorMessages: PROCEDURE [] RETURNS[ error: BOOLEAN _ FALSE ] ~ { NoSurfaces: PROCEDURE [shapes: REF ShapeSequence] RETURNS[BOOLEAN]~{ FOR i: NAT IN [0..shapes.length) DO IF shapes[i].surface # 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 IF context3d.shapes[i].surface # NIL THEN SceneUtilities.SetLines[ context3d, context3d.shapes[i].name ]; ENDLOOP; 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 IF context3d.shapes[i].surface # NIL THEN SceneUtilities.SetShadedLines[ context3d, context3d.shapes[i].name ]; ENDLOOP; IF makeFrame THEN context3d.class.render[context3d]; lastDemoCalled _ ShadedLinesDemo; }; HiddenLinesDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { tmpContext: REF Context _ SceneUtilities.GetTmpContext[context3d]; -- get modifiable context IF DemoErrorMessages[] THEN RETURN; SceneUtilities.NameBackgroundColor[ tmpContext, "White" ]; SceneUtilities.CopyContextShapes[tmpContext, context3d]; -- insulate shapes from changes FOR i: NAT IN [0..context3d.shapes.length) DO SceneUtilities.SetColor[ tmpContext, tmpContext.shapes[i].name, [1.0, 1.0, 1.0] ]; IF tmpContext.shapes[i].surface # NIL THEN SceneUtilities.SetHiddenLines[ tmpContext, tmpContext.shapes[i].name ]; ENDLOOP; IF makeFrame THEN tmpContext.class.render[tmpContext]; lastDemoCalled _ HiddenLinesDemo; }; NormaledLinesDemo: PROCEDURE [makeFrame: BOOLEAN _ FALSE] ~ { tmpContext: REF Context _ SceneUtilities.GetTmpContext[context3d]; -- get modifiable context IF DemoErrorMessages[] THEN RETURN; SceneUtilities.NameBackgroundColor[ tmpContext, "White" ]; SceneUtilities.CopyContextShapes[tmpContext, context3d]; -- insulate shapes from changes FOR i: NAT IN [0..context3d.shapes.length) DO SceneUtilities.SetColor[ tmpContext, tmpContext.shapes[i].name, [1.0, 1.0, 1.0] ]; IF tmpContext.shapes[i].surface # NIL THEN SceneUtilities.SetNormaledLines[ tmpContext, tmpContext.shapes[i].name ]; ENDLOOP; 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 IF context3d.shapes[i].surface # NIL THEN SceneUtilities.SetFaceted[ context3d, context3d.shapes[i].name ]; ENDLOOP; 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 IF context3d.shapes[i].surface # NIL THEN SceneUtilities.SetSmooth[context3d, context3d.shapes[i].name]; ENDLOOP; lastDemoCalled _ SmoothDemo; IF makeFrame THEN context3d.class.render[context3d]; }; SetShiny: PROCEDURE [] ~ { FOR i: NAT IN [0..context3d.shapes.length) DO IF context3d.shapes[i].surface # NIL THEN { shininess: REAL _ context3d.shapes[i].shadingClass.shininess; IF shininess <= 0.0 THEN SceneUtilities.SetShiny[ context3d, context3d.shapes[i].name ]; }; ENDLOOP; }; SetDull: PROCEDURE [] ~ { FOR i: NAT IN [0..context3d.shapes.length) DO IF context3d.shapes[i].surface # NIL THEN SceneUtilities.SetDull[ context3d, context3d.shapes[i].name ]; -- no highlights ENDLOOP; }; InterpressDemo: PROCEDURE [] ~ { fileName: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Length[fileName] < 1 THEN { SIGNAL ThreeDBasics.Error[[$MisMatch, "No selection for file name"]]; RETURN; }; IF DemoErrorMessages[] THEN RETURN; IF lastDemoCalled # HiddenLinesDemo AND lastDemoCalled # NormaledLinesDemo THEN RenderWithImager.MakeInterpressPage[context3d, fileName ] ELSE { tmpContext: REF Context _ SceneUtilities.GetTmpContext[context3d]; -- get mod. context SceneUtilities.NameBackgroundColor[ tmpContext, "White" ]; SceneUtilities.CopyContextShapes[tmpContext, context3d]; -- insulate shapes from change FOR i: NAT IN [0..context3d.shapes.length) DO SceneUtilities.SetColor[ tmpContext, tmpContext.shapes[i].name, [1.0, 1.0, 1.0] ]; IF tmpContext.shapes[i].surface # NIL THEN IF lastDemoCalled # NormaledLinesDemo THEN SceneUtilities.SetHiddenLines[ tmpContext, tmpContext.shapes[i].name ] ELSE SceneUtilities.SetNormaledLines[ tmpContext, tmpContext.shapes[i].name ]; ENDLOOP; RenderWithImager.MakeInterpressPage[tmpContext, fileName ] }; }; RandomQuads: PROCEDURE [context: REF 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 ThreeDBasics.Patch _ NEW[ ThreeDBasics.Patch[4] ]; shape: REF ShapeInstance _ NEW[ShapeInstance]; shape.shadingClass _ NEW[ShadingClass]; shape.shadingClass.shadingType _ $Smooth; p.props _ Atom.PutPropOnList[ 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[]; SceneUtilities.AddShapeAt[ context3d, "CheckerBoard", -- internal name "CheckerBoard.shape", -- file name [-8.0, -8.0, -2.0] -- position ]; SceneUtilities.AddShapeAt[ context3d, "Icosahedron", "Icosahedron.shape", [2.0, 0.0, 0.0] ]; SceneUtilities.SetColor[ context3d, "Icosahedron", [1., 1., 1.] ]; SceneUtilities.AddShapeAt[ context3d, "SoccerBall", "SoccerBall.shape", [-2.0, 0.0, 0.0] ]; SceneUtilities.SetColor[ context3d, "SoccerBall", [1., 1., 1.] ]; SceneUtilities.AddShapeAt[ context3d, "CutCube", "CutCube.shape", [0.0, 3.0, 0.0] ]; SceneUtilities.SetColor[ context3d, "CheckerBoard", [.8, .4, .2] ]; -- add shading SceneUtilities.SetColor[ context3d, "CutCube", [.9, .8, .5] ]; scene1 _ NEW[ShapeSequence[context3d.shapes.length]]; FOR i: NAT IN [0..context3d.shapes.length) DO scene1[i] _ SceneUtilities.CopyShapeDirect[ context3d.shapes[i] ]; ENDLOOP; scene1.length _ context3d.shapes.length; } ELSE { FOR i: NAT IN [0..scene1.length) DO context3d.shapes[i] _ SceneUtilities.CopyShapeDirect[ scene1[i] ]; ENDLOOP; context3d.shapes.length _ scene1.length; }; RenderWithPixels.DepthBuffering[context3d, FALSE]; currentScene _ scene1; }; SetScene2: PROCEDURE [] ~ { IF scene2 = NIL THEN { Reset[]; SceneUtilities.AddShapeAt[context3d, "ChampagneGlass", "ChampagneGlass.shape", [2.0, 0.0, 0.0] ]; SceneUtilities.RotateShapeLocal[ context: context3d, shapeName: "ChampagneGlass", theta: 45 ]; SceneUtilities.SetColor[context3d, "ChampagneGlass", [1.,0.,1.] ]; SceneUtilities.SetTransparent[ context3d, "ChampagneGlass" ]; SceneUtilities.AddShapeAt[context3d, "UtahEgg", "UtahEgg.shape", [-2.0, .0, .0] ]; SceneUtilities.OrientShape[ context: context3d, shapeName: "UtahEgg", axis: [-1, 1, 0] ]; SceneUtilities.SetColor[context3d, "UtahEgg", [1.0, .8, .5] ]; SceneUtilities.AddShapeAt[context3d, "Banana", "Banana.shape", [0.0, .0, .0] ]; SceneUtilities.SetColor[context3d, "Banana", [1.0, .9, .1] ]; scene2 _ NEW[ShapeSequence[context3d.shapes.length]]; FOR i: NAT IN [0..context3d.shapes.length) DO scene2[i] _ SceneUtilities.CopyShapeDirect[ context3d.shapes[i] ]; ENDLOOP; scene2.length _ context3d.shapes.length; } ELSE { FOR i: NAT IN [0..scene2.length) DO context3d.shapes[i] _ SceneUtilities.CopyShapeDirect[ scene2[i] ]; ENDLOOP; context3d.shapes.length _ scene2.length; }; RenderWithPixels.DepthBuffering[context3d, FALSE]; currentScene _ scene2; }; SetScene3: PROCEDURE [] ~ { IF scene3 = NIL THEN { Reset[]; SceneUtilities.AddShapeAt[context3d, "TeaPot", "TeaPotWithBot.shape", [0.0, 0.0, -1.25] ]; scene3 _ NEW[ShapeSequence[context3d.shapes.length]]; FOR i: NAT IN [0..context3d.shapes.length) DO scene3[i] _ SceneUtilities.CopyShapeDirect[ context3d.shapes[i] ]; ENDLOOP; scene3.length _ context3d.shapes.length; ThreeDBasics.SetView[context3d, [3.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; } ELSE { FOR i: NAT IN [0..scene3.length) DO context3d.shapes[i] _ SceneUtilities.CopyShapeDirect[ scene3[i] ]; ENDLOOP; context3d.shapes.length _ scene3.length; }; currentScene _ scene3; }; OneShape: PROCEDURE [] ~ { Reset[]; SceneUtilities.AddShapeAt[context3d, "Shape0", ViewerTools.GetSelectionContents[] ]; ThreeDBasics.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 ]; SceneUtilities.SetWindow[ context3d, mouseRectangle^ ]; mouseRectangle _ NIL; mouseWaiting _ NIL; }; $ViewPort => { viewPortStack _ CONS[ context3d.viewPort^, viewPortStack ]; SceneUtilities.SetViewPort[ context3d, mouseRectangle^ ]; mouseRectangle _ NIL; mouseWaiting _ NIL; }; ENDCASE => SIGNAL ThreeDBasics.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 { SceneUtilities.SetWindow[ context3d, windowStack.first ]; windowStack _ windowStack.rest; } ELSE SIGNAL ThreeDBasics.Error[[$MisMatch, "No previous window"]]; }; GetViewPort: PROCEDURE [] ~ { mouseWaiting _ $ViewPort }; RestoreViewPort: PROCEDURE[] ~ { IF viewPortStack # NIL THEN { SceneUtilities.SetViewPort[ context3d, viewPortStack.first ]; viewPortStack _ viewPortStack.rest; } ELSE SIGNAL ThreeDBasics.Error[[$MisMatch, "No previous viewport"]]; }; ShowSinglePatch: PROCEDURE[ shapeNumber, patchNumber: NAT, keep: BOOL _ FALSE ] ~ { context3d.props _ Atom.PutPropOnList[ 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 _ Atom.PutPropOnList[ 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; ColorDisplayRender.Orbit[ context: context3d, lookingFrom: context3d.eyePoint, lookingAt: context3d.ptOfInterest, axis: [0.3, 0.0, 1.0], base: context3d.ptOfInterest, 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 _ [ColorDisplayRender.StuffBuf, NIL]] ]; }; ShowShapes: PROC ~ { SurfaceRender.ShowShapes[context3d ]; -- show shapes without clearing }; movieFileRoot: Rope.ROPE; movieFileLog: Rope.ROPE; movieFileLogTime: BasicTime.GMT; movieNumFiles: NAT; movieStart: NAT; SetUpMovie: PROC[fileRoot: Rope.ROPE, numFiles, start: NAT _ 0] ~ { fileUpdated: BOOLEAN _ FALSE; IF frames # NIL AND Rope.Equal[movieFileRoot, fileRoot] THEN { latestTime: BasicTime.GMT; [created: latestTime] _ FS.FileInfo[ AISAnimation.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[ AISAnimation.GetLogFileName[fileRoot] ]; movieNumFiles _ numFiles; movieStart _ start; frames _ NIL; }; }; frameRate: INTEGER _ 6; -- playback rate in frames/second, negative plays backwards PlayBackbyFrame: CedarProcess.ForkableProc ~ { CleanUp: PROC ~ { SceneUtilities.SetViewPort[ context3d, cachedViewPort ]; IF context3d.class.displayType = $PseudoColor THEN ColorDisplayRender.LoadStd8BitClrMap[context3d.terminal]; }; size, posn: Pair; SurfaceRender.ValidateContext[context3d]; cachedViewPort _ context3d.viewPort^; context3d.class.loadBackground[context3d]; IF frames = NIL THEN { frames _ AISAnimation.CacheNumberedAISFiles[ context3d, movieFileRoot, movieNumFiles, movieStart ]; }; <> 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 ]; SceneUtilities.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[]; }; AISAnimation.ShowNextAISCacheFrame[context3d, frames, frameRate]; CedarProcess.CheckAbort[]; ENDLOOP; }; Commander.Register["ThreeDDemo", ThreeDDemoCommand, "\nDemonstrate ThreeDWorld"]; END.