ThreeDDemoImpl.mesa
Last Edited by: Crow, September 21, 1989 9:44:50 am PDT
Bloomenthal, September 26, 1988 12:04:57 pm PDT
DIRECTORY Atom, BasicTime, CedarProcess, Commander, FS, G3dAnimationSupport, G3dColorDisplaySupport, G3dRender, G3dRenderWithImager, G3dRenderWithPixels, G3dShape, G3dSortandDisplay, Imager, ImageTwiddle, List, Process, Random, Real, Rope, Terminal, ThreeDViewer, ViewerTools;
ThreeDDemoImpl:
CEDAR
MONITOR
IMPORTS Atom, BasicTime, CedarProcess, Commander, FS, G3dAnimationSupport, G3dColorDisplaySupport, G3dRender, G3dRenderWithImager, G3dRenderWithPixels, G3dShape, G3dSortandDisplay, ImageTwiddle, List, Process, Random, Real, Rope, Terminal, ThreeDViewer, ViewerTools
~ BEGIN
Types
PropList: TYPE ~ Atom.PropList;
ROPE: TYPE ~ Rope.ROPE;
Context: TYPE ~ G3dRender.Context;
IntegerPair: TYPE ~ G3dRender.IntegerPair;
Pair: TYPE ~ G3dRender.Pair;
Pixel: TYPE ~ G3dRender.Pixel;
Triple: TYPE ~ G3dRender.Triple;
Rectangle: TYPE ~ G3dRender.Rectangle;
RGB: TYPE ~ G3dRender.RGB;
Patch: TYPE ~ G3dRender.Patch;
ShadingClass: TYPE ~ G3dRender.ShadingClass;
Shape: TYPE ~ G3dRender.Shape;
ShapeRep: TYPE ~ G3dShape.ShapeRep;
ShapeSequence: TYPE ~ G3dRender.ShapeSequence;
ShapeSequenceRep: TYPE ~ G3dShape.ShapeSequenceRep;
RenderData: TYPE ~ G3dRender.RenderData;
ImagerProcRec: TYPE ~ G3dRender.ImagerProcRec;
LORA: TYPE ~ LIST OF REF ANY;
Global Variables
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;
Menu and Button Procs
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 ~ {
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
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 ];
};
Context and Interactive Control
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 ~ {
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.
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] ~ {
Makes a new view of the supplied context, useful for using two portions of the screen differently, etc.
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
};
Demos
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 [] ~ {
Remove Highlights
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;
};
Frame Generation and Animation
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
];
};
Construct viewPort from cached frame size
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;
};