ThreeDDemoImpl.mesa
Last Edited by: Crow, May 30, 1986 3:00:05 pm PDT
DIRECTORY
Atom USING [ GetPropFromList, PutPropOnList, RemPropFromList ],
List USING [ Memb ],
CedarProcess USING [ ForkableProc, Process, Fork, Join, Abort, CheckAbort ],
Terminal USING [ Virtual, Current ],
Commander USING [ PrependWorkingDir ],
Rope USING [ ROPE, Substr, Length ],
Real USING [ FixI, Float ],
Imager USING [ Context, Rectangle ],
ImagerColor USING [ RGB ],
ImagerColorMap USING [SetStandardColorMap],
QuickViewer USING [ BuildViewer, Reset, QuickView ],
ViewerOps USING [ ChangeColumn ],
ViewerClasses USING [ Viewer ],
Vector3d USING [ Triple ],
Pixels USING [ PixelBuffer ],
ThreeDScenes USING [ Context, Create, FindShape, SetLight, SetView,
FillInBackGround, SetViewPort, ShapeInstance, ShapeSequence,
GetFromImagerContext, GetShading, PutShading,
SetWindow, WindowFromViewPort ],
ThreeDSurfaces USING [ EnableDisplay, StopDisplay ],
ThreeDMisc USING [ AddShapeAt, CloseLog, CopyContextData, GetImagerContext,
GetPolygonColors, LoadColorRamp, LoadStd8BitClrMap,
MakeFrame, OrbitEye, PutPixel, SetBackground,
SetFacetedColor, SetNamedColor, SetShininess, SetSmoothColor,
SetTransmittance, SetViewPortFromImager, ShowRope,
ShowShapes, StartLog ],
AISAnimation USING [ FrameSequence, ShowNextAISCacheFrame,
CacheAISFiles, CacheNumberedAISFiles, StopDisplay ];
Global Variables
context3d, offScreenCtx: REF ThreeDScenes.Context;
currentScene, scene1, scene2, scene3: REF ThreeDScenes.ShapeSequence ← NIL;
frames: REF AISAnimation.FrameSequence;
xNow, yNow, zNow: REAL ← 3.0;
xOrigin, yOrigin: REAL ← 100.0;
movie, gallery, noReDraw, buttonsEnabled: BOOLEAN ← FALSE;
cachedViewPort: Imager.Rectangle;
currentProcess: CedarProcess.Process ← NIL;
Context and Interactive Control
Init:
PROC[] ~ {
viewer: ViewerClasses.Viewer ← NIL;
imagerCtx: Imager.Context;
wDir: Rope.ROPE ← Commander.PrependWorkingDir[" "]; -- working dir plus (needed) space
wDir ← Rope.Substr[ base: wDir, len: Rope.Length[wDir] - 1 ]; -- drop space
buttonsEnabled ← FALSE;
imagerCtx ← QuickViewer.BuildViewer[
LIST[$Help, $NewScene, $Lines, $Facets, $Smooth, $Shiny, $Orbit, $STOP, $Movie, $Gallery, $Jaggy, $NoJaggy, $Reset],
ReDraw,
ShutDown,
MenuHit,
"ThreeDDemo",
TRUE -- shut off scrolling and extra buttons
];
viewer ← NARROW[imagerCtx.data, QuickViewer.QuickView].viewer.parent;
IF viewer.column # color THEN ViewerOps.ChangeColumn[viewer, color];
noReDraw ← TRUE; -- stop recursion through ReDraw
context3d ← ThreeDScenes.GetFromImagerContext[ imagerCtx ];
context3d.props ← Atom.PutPropOnList[context3d.props, $WDir, wDir]; -- keep directory
ThreeDMisc.SetBackground[ context3d, "Darkish Blue" ]; -- set background color
[] ← ThreeDScenes.SetLight[context3d, "Initial", [-100., -200., 50.] ];
SetScene1[];
ThreeDScenes.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ];
noReDraw ← FALSE;
buttonsEnabled ← TRUE;
};
This resets the clipper, transformation, scene, etc. to the unused state
Reset:
PROCEDURE [] ~ {
imagerCtx: Imager.Context ← ThreeDMisc.GetImagerContext[context3d];
buttonsEnabled ← FALSE;
QuickViewer.Reset[ imagerCtx ];
ThreeDSurfaces.EnableDisplay[]; -- get stop flag unstuck, if necessary
ThreeDMisc.SetViewPortFromImager[ context3d, imagerCtx ];
ThreeDScenes.SetWindow[context3d,ThreeDScenes.WindowFromViewPort[context3d.viewPort]];
context3d.shapes ← context3d.lights; -- delete all the objects
ThreeDScenes.SetView[ context3d, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ];
movie ← FALSE;
buttonsEnabled ← TRUE;
currentScene ← NIL;
};
This will be called when the viewer is changed
ReDraw:
PROCEDURE [imagerCtx: Imager.Context] ~ {
newContext: REF ThreeDScenes.Context;
oldCtx: Imager.Context;
IF noReDraw THEN RETURN; -- Don't do anything during Init sequence
buttonsEnabled ← FALSE;
noReDraw ← TRUE; -- stop recursion from viewers
oldCtx ← ThreeDMisc.GetImagerContext[context3d];
IF oldCtx # NIL THEN imagerCtx ← oldCtx; -- use original context
newContext ← ThreeDScenes.GetFromImagerContext[
imagerCtx, context3d.alphaBuffer, context3d.depthBuffer
];
context3d.display ← newContext.display;
context3d.alphaBuffer ← newContext.alphaBuffer;
context3d.depthBuffer ← newContext.depthBuffer;
context3d.renderMode ← newContext.renderMode;
context3d.viewPort ← newContext.viewPort;
SetViewPort[ context3d.viewPort ];
noReDraw ← FALSE;
buttonsEnabled ← TRUE;
};
This will be called when the viewer is destroyed
ShutDown:
PROCEDURE [] ~ {
buf: Pixels.PixelBuffer; -- zeroed buffer
context3d.display ← buf;
IF offScreenCtx # NIL THEN offScreenCtx.display ← buf;
buttonsEnabled ← FALSE;
frames ← NIL; -- free frame storage for garbage colection
pictures ← NIL; -- free image storage for garbage collection
ThreeDMisc.CloseLog[context3d];
};
GetOffScreenCtx:
PUBLIC
PROC[context:
REF ThreeDScenes.Context, width, height:
NAT] ~ {
offScreenCtx ← ThreeDScenes.Create[
width,
height,
context.renderMode,
context.alphaBuffer
];
ThreeDMisc.CopyContextData[dstCtx: offScreenCtx, srcCtx: context];
offScreenCtx.viewPort ← [ x: 0.0, y: 0.0, w: Real.Float[width], h: Real.Float[height] ];
[] ← ThreeDMisc.StartLog[offScreenCtx];
FOR i:
NAT
IN [0..offScreenCtx.shapes.length)
DO
offScreenCtx.shapes[i].vtcesInValid ← TRUE;
ENDLOOP;
};
This will be called whenever the mouse is moved or a button is pushed.
All atomic operations must occur in here.
MenuHit:
ENTRY PROCEDURE[bttn:
ATOM, x, y:
REAL, ctrl, shift:
BOOL] ~ {
DoIt: CedarProcess.ForkableProc ~ { [] ← NARROW[ data, REF PROC]^[]; }; -- call the procedure
ForkAndWait:
PROC [ proc:
PROC ] ~ {
IF currentProcess #
NIL
AND currentProcess.status = busy
OR gallery
THEN
RETURN;
fork process for safe remote aborting
currentProcess ← CedarProcess.Fork[DoIt, NEW[ PROC ← proc] ];
[] ← CedarProcess.Join[currentProcess]; -- await termination
currentProcess ← NIL;
};
ForkAndGo:
PROC [ proc:
PROC ] ~ {
IF currentProcess #
NIL
AND currentProcess.status = busy
OR gallery
THEN
RETURN;
fork process for safe remote aborting, then proceeed so buttons may be caught
currentProcess ← CedarProcess.Fork[DoIt, NEW[ PROC ← proc] ];
};
StopEverything:
PROC ~ {
ThreeDSurfaces.StopDisplay[];
AISAnimation.StopDisplay[];
IF currentProcess # NIL THEN CedarProcess.Abort[currentProcess]; -- kill it
[] ← CedarProcess.Join[currentProcess]; -- await termination
currentProcess ← NIL;
IF gallery THEN ClearGallery[];
IF movie
THEN {
movie ← FALSE;
SetViewPort[ cachedViewPort ]; -- restore viewport
};
};
IF buttonsEnabled
THEN
SELECT bttn
FROM
$Help => ForkAndGo[ HelpMessage ];
$NewScene =>
IF currentScene = scene1
THEN ForkAndGo[ SetScene2 ]
ELSE
IF currentScene = scene2
THEN ForkAndGo[ SetScene3 ]
ELSE ForkAndGo[ SetScene1 ];
$Lines => ForkAndGo[ LinesDemo ];
$Facets => ForkAndGo[ FacetedDemo ];
$Smooth => ForkAndGo[ SmoothDemo ];
$Shiny => ForkAndGo[ ShinyDemo ];
$Orbit => ForkAndGo[ Orbit ];
$STOP => StopEverything[];
$Movie => ForkAndGo[ PlayBackbyFrame ];
$Gallery => ForkAndGo[ LoadGallery ];
$Jaggy => ForkAndGo[ SetAliased ];
$NoJaggy => ForkAndGo[ SetAntiAliased ];
$Reset => { StopEverything[]; Reset[]; };
$LeftButton, $LeftHeld =>
IF movie
THEN frameRate ← Real.FixI[x / 10.]
ELSE IF gallery THEN ShowNextPicture[]
ELSE
IF currentProcess =
NIL
OR currentProcess.status # busy
THEN {
xNow ← x / 15.0;
yNow ← y / 15.0;
ThreeDScenes.SetView[ context3d, [xNow, yNow, zNow], context3d.ptOfInterest ];
ForkAndGo[MakeFrame];
};
$MiddleButton, $MiddleHeld =>
IF currentProcess =
NIL
OR currentProcess.status # busy
THEN {
xLight: REAL ← x * 1.0;
yLight: REAL ← y * 1.0;
[] ← ThreeDScenes.SetLight[ context3d, "Initial", [xLight, yLight, 50.0] ];
IF NOT context3d.lineDrawing THEN ForkAndGo[MakeFrame];
};
$RightButton, $RightHeld =>
IF gallery THEN ShowLastPicture[]
ELSE
IF currentProcess =
NIL
OR currentProcess.status # busy
THEN {
zNow ← y / 15.0;
ThreeDScenes.SetView[ context3d, [xNow, yNow, zNow], context3d.ptOfInterest ];
ForkAndGo[MakeFrame];
};
ENDCASE;
};
HelpMessage:
PROCEDURE [] ~ {
ThreeDMisc.SetNamedColor[context3d, "Vivid Green" ];
ThreeDMisc.ShowRope[context3d, 60.0, 360.0,
"Scene1 - Select Scene with Polyhedra on Checkerboard." ];
ThreeDMisc.ShowRope[context3d, 60.0, 330.0,
"Scene2 - Select Scene with Egg, banana, and Glass." ];
ThreeDMisc.ShowRope[context3d, 60.0, 300.0,
"Lines, Facets, Smooth, Shiny - Make image as specified." ];
ThreeDMisc.ShowRope[context3d, 60.0, 270.0,
"Orbit - Make images following elliptical path around scene." ];
ThreeDMisc.ShowRope[context3d, 60.0, 240.0,
"Movie - Play back a precalculated sequence."];
ThreeDMisc.ShowRope[context3d, 60.0, 210.0,
"Jaggy/NoJaggy - turn antialiasing off/on (NoJaggy is slow!)." ];
ThreeDMisc.ShowRope[context3d, 60.0, 180.0,
"Buttoning in the image makes a new image with:" ];
ThreeDMisc.ShowRope[context3d, 60.0, 150.0,
" Left Button determining eyepoint position in x-y plane," ];
ThreeDMisc.ShowRope[context3d, 60.0, 120.0,
" Right Button determining eyepoint height," ];
ThreeDMisc.ShowRope[context3d, 60.0, 90.0,
" Middle Button determining light source x-y." ];
ThreeDMisc.ShowRope[context3d, 60.0, 60.0,
"STOP - stops long operations, Reset - recovers from trouble."];
};
SetViewPort:
PROC [ size: Imager.Rectangle ] ~ {
ThreeDScenes.SetViewPort[ context3d, size ];
-- set clippers etc.
! ThreeDScenes.ThreeDScenesError => IF reason = $NullClipper THEN RESUME
FOR i:
NAT
IN [0..context3d.shapes.length)
DO
context3d.shapes[i].vtcesInValid ← TRUE;
context3d.shapes[i].shadingInValid ← TRUE;
ENDLOOP;
ThreeDScenes.SetView[
-- get new screen dimensions into transformations
context: context3d,
eyePoint: context3d.eyePoint,
ptOfInterest: context3d.ptOfInterest,
fieldOfView: context3d.fieldOfView,
rollAngle: context3d.rollAngle,
upDirection: context3d.upDirection,
hitherLimit: context3d.hitherLimit,
yonLimit: context3d.yonLimit
];
};
ChangeRenderMode:
PROC [ mode:
ATOM ] ~ {
-- for {$Dithered, $PseudoClr, $Grey}
SELECT mode
FROM
$Dithered => ImagerColorMap.SetStandardColorMap[ Terminal.Current[] ];
$PseudoClr => ThreeDMisc.LoadStd8BitClrMap[ Terminal.Current[] ];
$Grey =>
ThreeDMisc.LoadColorRamp[ Terminal.Current[], [0.,0.,0.], [1.,1.,1.], [.43, .43, .43] ];
ENDCASE => SIGNAL ThreeDDemoError[$CantHackThatMode];
context3d.renderMode ← mode;
};
Demos
SetDepthBuffer:
PROCEDURE [] ~ {
context: REF ThreeDScenes.Context;
IF context3d.depthBuffer = TRUE THEN RETURN[];
context ← ThreeDScenes.GetFromImagerContext[
NARROW[Atom.GetPropFromList[ context3d.display.props, $ImagerContext], Imager.Context],
FALSE, TRUE
];
context3d.display ← context.display;
context3d.alphaBuffer ← FALSE; context3d.depthBuffer ← TRUE;
context3d.renderMode ← context.renderMode;
SetViewPort[context.viewPort];
};
NoDepthBuffer:
PROCEDURE [] ~ {
context: REF ThreeDScenes.Context;
IF context3d.depthBuffer = FALSE THEN RETURN[];
context ← ThreeDScenes.GetFromImagerContext[
NARROW[Atom.GetPropFromList[ context3d.display.props, $ImagerContext], Imager.Context],
context3d.alphaBuffer
];
context3d.display ← context.display;
context3d.depthBuffer ← FALSE;
context3d.renderMode ← context.renderMode;
SetViewPort[context.viewPort];
};
SetAliased:
PROCEDURE [] ~ {
context:
REF ThreeDScenes.Context ← ThreeDScenes.GetFromImagerContext[
NARROW[Atom.GetPropFromList[ context3d.display.props, $ImagerContext], Imager.Context],
FALSE, context3d.depthBuffer
];
context3d.display ← context.display;
context3d.alphaBuffer ← FALSE;
context3d.renderMode ← context.renderMode;
SetViewPort[context.viewPort];
};
SetAntiAliased:
PROCEDURE [] ~ {
context:
REF ThreeDScenes.Context ← ThreeDScenes.GetFromImagerContext[
NARROW[Atom.GetPropFromList[ context3d.display.props, $ImagerContext], Imager.Context],
TRUE
];
context3d.display ← context.display;
context3d.alphaBuffer ← TRUE; context3d.depthBuffer ← FALSE;
context3d.renderMode ← context.renderMode;
SetViewPort[context.viewPort];
};
DemoErrorMessages:
PROCEDURE []
RETURNS[ error:
BOOLEAN ←
FALSE] ~ {
NoSurfaces:
PROCEDURE [shapes:
REF ThreeDScenes.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 {
ThreeDMisc.SetNamedColor[context3d, "Vivid Green"];
ThreeDMisc.ShowRope[context3d, 60.0, 340.0, "No objects, nothing to display"];
error ← TRUE;
};
IF context3d.alphaBuffer
AND NOT List.Memb[ context3d.renderMode, LIST[$Grey, $FullClr, $Dorado24] ]
THEN {
ThreeDMisc.SetNamedColor[context3d, "Vivid Green"];
ThreeDMisc.ShowRope[context3d, 60.0, 300.0, "NoJaggy needs GreyScale or 24-bit Color"];
error ← TRUE;
};
};
LinesDemo:
PROCEDURE [] ~ {
context3d.lineDrawing ← TRUE;
IF DemoErrorMessages[] THEN RETURN;
IF
NOT context3d.alphaBuffer
THEN MakeFrame[]
ELSE {
FOR i:
NAT
IN [0..context3d.shapes.length)
DO
IF context3d.shapes[i].surface #
NIL
THEN ThreeDScenes.PutShading[context3d.shapes[i], $Type, $Lines ];
ENDLOOP;
MakeFrame[];
};
};
FacetedDemo:
PROCEDURE [] ~ {
context3d.lineDrawing ← FALSE;
IF DemoErrorMessages[] THEN RETURN;
FOR i:
NAT
IN [0..context3d.shapes.length)
DO
IF context3d.shapes[i].surface #
NIL
THEN {
context3d.shapes[i].shadingProps ← Atom.RemPropFromList[
-- no highlights
context3d.shapes[i].shadingProps,
$Shininess
];
ThreeDScenes.PutShading[context3d.shapes[i], $Type, $Faceted ];
IF ThreeDScenes.GetShading[context3d.shapes[i], $PatchColors ] =
NIL
THEN {
rgb: RGB ← NARROW[ThreeDScenes.GetShading[context3d.shapes[i], $Color], REF RGB ]^;
ThreeDMisc.SetFacetedColor[context3d, context3d.shapes[i].name, rgb];
};
};
ENDLOOP;
MakeFrame[];
};
SmoothDemo:
PROCEDURE [] ~ {
context3d.lineDrawing ← FALSE;
IF DemoErrorMessages[] THEN RETURN;
FOR i:
NAT
IN [0..context3d.shapes.length)
DO
IF context3d.shapes[i].surface #
NIL
THEN {
context3d.shapes[i].shadingProps ← Atom.RemPropFromList[
-- no highlights
context3d.shapes[i].shadingProps,
$Shininess
];
ThreeDScenes.PutShading[context3d.shapes[i], $Type, $Smooth ];
};
ENDLOOP;
MakeFrame[];
};
ShinyDemo:
PROCEDURE [] ~ {
context3d.lineDrawing ← FALSE;
IF DemoErrorMessages[] THEN RETURN;
FOR i:
NAT
IN [0..context3d.shapes.length)
DO
IF context3d.shapes[i].surface #
NIL
THEN {
shininess:
REF
REAL ←
NARROW[
ThreeDScenes.GetShading[context3d.shapes[i], $Shininess]
];
IF shininess =
NIL
THEN {
shininess ← NEW[REAL ← 50.0];
ThreeDMisc.SetShininess[ context3d, context3d.shapes[i].name, shininess^ ];
};
IF
NARROW[ ThreeDScenes.GetShading[context3d.shapes[i], $Type],
ATOM ] = $Lines
THEN ThreeDScenes.PutShading[context3d.shapes[i], $Type, $Smooth ];
};
ENDLOOP;
MakeFrame[];
};
Orbit:
PROCEDURE [] ~ {
IF DemoErrorMessages[] THEN RETURN;
ThreeDSurfaces.EnableDisplay[]; -- get stop flag unstuck, if necessary
ThreeDMisc.OrbitEye[
context: context3d,
lookingFrom: context3d.eyePoint,
lookingAt: context3d.ptOfInterest,
axis: [0.3, 0.0, 1.0],
framesPerRev: 53
];
};
SetScene1:
PROCEDURE [] ~ {
IF scene1 =
NIL
THEN {
context3d.shapes ← context3d.lights; -- don't change the lighting
ThreeDMisc.AddShapeAt[ context3d,
"CheckerBoard", -- internal name
"CheckerBoard.shape", -- file name
[-8.0, -8.0, -2.0], -- position
$ConvexPolygon, TRUE -- not a closed shape (TRUE allows backfacing polys)
];
ThreeDMisc.AddShapeAt[ context3d, "Icosahedron", "Icosahedron.shape", [2.0, 0.0, 0.0] ];
ThreeDMisc.AddShapeAt[ context3d, "SoccerBall", "SoccerBall.shape", [-2.0, 0.0, 0.0] ];
ThreeDMisc.AddShapeAt[ context3d, "CutCube", "CutCube.shape", [0.0, 3.0, 0.0] ];
ThreeDMisc.SetFacetedColor[ context3d, "CheckerBoard", [.8, .4, .2] ]; -- add shading
ThreeDMisc.SetSmoothColor[ context3d, "CheckerBoard", [.8, .4, .2] ];
ThreeDMisc.SetFacetedColor[ context3d, "SoccerBall", [.7, .7, .6] ];
ThreeDMisc.SetSmoothColor[ context3d, "SoccerBall", [1.0, .8, .8] ];
ThreeDMisc.SetFacetedColor[ context3d, "Icosahedron", [.1, .9, .1] ];
ThreeDMisc.SetSmoothColor[ context3d, "Icosahedron", [.8, 1.0, .8] ];
ThreeDMisc.SetFacetedColor[ context3d, "CutCube", [.9, .3, .1] ];
ThreeDMisc.SetSmoothColor[ context3d, "CutCube", [.9, .3, .1] ];
ThreeDMisc.GetPolygonColors[ context3d, "Icosahedron", "IcosahedronPolyColors.vtces" ];
ThreeDMisc.GetPolygonColors[ context3d, "SoccerBall", "SoccerBallPolyColors.vtces" ];
scene1 ← NEW[ThreeDScenes.ShapeSequence[context3d.shapes.length] ← context3d.shapes^];
}
ELSE context3d.shapes ← scene1;
NoDepthBuffer[];
currentScene ← scene1;
};
SetScene2:
PROCEDURE [] ~ {
IF scene2 =
NIL THEN {
context3d.shapes ← context3d.lights; -- don't change the lighting;
ThreeDMisc.AddShapeAt[context3d, "ChampagneGlass",
"ChampagneGlass.shape",
[2.0, 0.0, 0.0],
$ConvexPolygon, TRUE ]; -- TRUE allows the inside to be seen
ThreeDMisc.AddShapeAt[context3d, "UtahEgg", "UtahEgg.shape", [-2.0, .0, .0] ];
ThreeDMisc.AddShapeAt[context3d, "Banana", "Banana.shape", [0.0, .0, .0] ];
ThreeDScenes.FindShape[ context3d.shapes, "UtahEgg" ].orientation ← [-1., 1., 0.];
ThreeDScenes.FindShape[ context3d.shapes, "UtahEgg" ].rotation ← 90.0;
ThreeDScenes.FindShape[ context3d.shapes, "ChampagneGlass" ].orientation ← [0., 0., 1.];
ThreeDScenes.FindShape[ context3d.shapes, "ChampagneGlass" ].rotation ← 45.0;
ThreeDMisc.SetFacetedColor[context3d, "ChampagneGlass", [1.,0.,1.] ];
ThreeDMisc.SetSmoothColor[context3d, "ChampagneGlass", [1.,0.,1.] ];
ThreeDMisc.SetTransmittance[context3d, "ChampagneGlass", .8 ];
ThreeDMisc.SetFacetedColor[context3d, "UtahEgg", [1.0, .8, .5] ];
ThreeDMisc.SetSmoothColor[context3d, "UtahEgg", [1.0, .8, .5] ];
ThreeDMisc.SetFacetedColor[context3d, "Banana", [1.0, .9, .1] ];
ThreeDMisc.SetSmoothColor[context3d, "Banana", [1.0, .9, .1] ];
scene2 ← NEW[ThreeDScenes.ShapeSequence[context3d.shapes.length] ← context3d.shapes^];
}
ELSE context3d.shapes ← scene2;
NoDepthBuffer[];
currentScene ← scene2;
};
SetScene3:
PROCEDURE [] ~ {
IF scene3 =
NIL THEN {
context3d.shapes ← context3d.lights; -- don't change the lighting;
ThreeDMisc.AddShapeAt[context3d, "TeaPot", "TeaPotWithBot.bezier",
[0.0, 0.0, -1.25], $Bezier ];
scene3 ← NEW[ThreeDScenes.ShapeSequence[context3d.shapes.length] ← context3d.shapes^];
ThreeDScenes.SetView[context3d, [3.0, -10.0, 3.0], [0.0, 0.0, 0.0] ];
}
ELSE context3d.shapes ← scene3;
SetDepthBuffer[];
currentScene ← scene3;
};
PutPixel:
PROCEDURE[x, y:
NAT, clr:
RGB] ~ {
ThreeDMisc.PutPixel[context3d, x, y, clr];
};
Frame Generation and Animation
MakeFrame:
PROC ~ {
ThreeDSurfaces.EnableDisplay[]; -- get stop flag unstuck, if necessary
ThreeDMisc.MakeFrame[context3d ]; -- clear and make new frame
};
ShowShapes:
PROC ~ {
ThreeDSurfaces.EnableDisplay[]; -- get stop flag unstuck, if necessary
ThreeDMisc.ShowShapes[context3d ]; -- show shapes without clearing
};
movieFileRoot: Rope.ROPE ← "/Cyan/AIS/Animation/StillLife.ais";
movieViewPort: Imager.Rectangle ← [120.0, 90.0, 400.0, 300.0];
movieNumFiles: NAT ← 30;
movieStart: NAT ← 1;
SetUpMovie:
PROC[fileRoot: Rope.
ROPE, viewPort: Imager.Rectangle, numFiles, start:
NAT] ~ {
ChangeRenderMode[$PseudoClr];
movieFileRoot ← fileRoot;
movieViewPort ← viewPort;
movieNumFiles ← numFiles;
movieStart ← start;
frames ← NIL;
};
frameRate: INTEGER ← 6; -- playback rate in frames/second, negative plays backwards
PlayBackbyFrame:
PROC ~ {
cachedViewPort ← context3d.viewPort;
ThreeDMisc.SetNamedColor[context3d, "Vivid Green" ];
IF context3d.renderMode # $PseudoClr
THEN {
ThreeDMisc.ShowRope[context3d, 140.0, 50.0, "Change to 8-bit pseudocolor, please!"];
RETURN[];
};
ThreeDScenes.FillInBackGround[context3d];
ThreeDMisc.ShowRope[context3d, 140.0, 50.0, "Control frame rate using left button"];
movie ← TRUE;
SetViewPort[ movieViewPort ];
IF frames =
NIL
THEN {
pictures ← NIL; -- avoid using up all the VM
frames ← AISAnimation.CacheNumberedAISFiles[
context3d, movieFileRoot, movieNumFiles, movieStart
];
};
WHILE movie
DO
AISAnimation.ShowNextAISCacheFrame[context3d, frames, frameRate];
CedarProcess.CheckAbort[];
ENDLOOP;
SetViewPort[ cachedViewPort ];
};
pictureFile: Rope.ROPE ← "/Cyan/AIS/Crow/PrettyPictures.txt";
pictures: REF AISAnimation.FrameSequence;
LoadGallery:
PROC ~ {
ThreeDMisc.SetNamedColor[context3d, "Vivid Green" ];
IF context3d.renderMode # $Dorado24
THEN {
ThreeDMisc.ShowRope[context3d, 140.0, 50.0, "Change to 24-bit color, please!"];
RETURN[];
};
ThreeDScenes.FillInBackGround[context3d];
ThreeDMisc.ShowRope[context3d, 140.0, 50.0, "Left button, ahead - Right button, back"];
gallery ← TRUE;
SetAliased[];
IF pictures = NIL THEN pictures ← NEW[AISAnimation.FrameSequence[16]];
pictures ← AISAnimation.CacheAISFiles[context3d, pictureFile, pictures];
};
ShowNextPicture:
PROC ~ {
-- display next picture in sequence
IF pictures #
NIL
AND pictures.length > 0
-- make sure frame ready and no wraparound
AND ((pictures.currentFrame + 1)
MOD pictures.length) >= pictures.currentFrame
THEN AISAnimation.ShowNextAISCacheFrame[context3d, pictures, 10];
};
ShowLastPicture:
PROC ~ {
-- display previous picture in sequence
IF pictures #
NIL
AND pictures.currentFrame > 0
THEN AISAnimation.ShowNextAISCacheFrame[context3d, pictures, -10];
};
ClearGallery:
PROC ~ {
IF pictures #
NIL
THEN FOR i: NAT IN [0..pictures.length) DO pictures[i].pixels ← NIL; ENDLOOP;
gallery ← FALSE;
};