G3dSceneProcsImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Glassner, July 5, 1990 1:48:22 pm PDT
Bloomenthal, July 15, 1992 11:31 pm PDT
DIRECTORY Args, Ascii, Atom, Convert, FileNames, G3dBasic, G3dMatrix, G3dRender, G3dScene, G3dShape, G3dSweep, G3dTimeTrees, G3dVector, IO, Random, Real, Rope;
G3dSceneProcsImpl: CEDAR PROGRAM
IMPORTS Atom, Convert, FileNames, G3dMatrix, G3dScene, G3dShape, G3dRender, G3dTimeTrees, G3dVector, IO, Random, Real, Rope
~ BEGIN
Imported Types
Arg:      TYPE ~ Args.Arg; 
PropList:     TYPE ~ Atom.PropList;
Pair:      TYPE ~ G3dBasic.Pair;
Triple:     TYPE ~ G3dBasic.Triple;
Matrix:     TYPE ~ G3dMatrix.Matrix;
MatrixRep:    TYPE ~ G3dMatrix.MatrixRep;
Shape:     TYPE ~ G3dShape.Shape;
ShapeSequence:   TYPE ~ G3dShape.ShapeSequence;
Context3d:    TYPE ~ G3dRender.Context3d;
RGB:      TYPE ~ G3dRender.RGB;
RenderStyle:    TYPE ~ G3dRender.RenderStyle;
TextureStyle:    TYPE ~ G3dRender.TextureStyle;
ParseState:    TYPE ~ G3dScene.ParseState;
Material:     TYPE ~ G3dScene.Material;
MaterialSequence:  TYPE ~ G3dScene.MaterialSequence;
MaterialSequenceRep: TYPE ~ G3dScene.MaterialSequenceRep;
SceneProc:    TYPE ~ G3dScene.SceneProc;
SurfaceDescription:  TYPE ~ G3dSweep.SurfaceDescription;
SurfaceDescriptionRep: TYPE ~ G3dSweep.SurfaceDescriptionRep;
Variable:     TYPE ~ G3dScene.Variable;
VariableSequence:  TYPE ~ G3dScene.VariableSequence;
VariableSequenceRep: TYPE ~ G3dScene.VariableSequenceRep;
SourceText:    TYPE ~ G3dScene.SourceText;
SourceTextRep:   TYPE ~ G3dScene.SourceTextRep;
InterpolationType:  TYPE ~ G3dTimeTrees.InterpolationType;
STREAM:     TYPE ~ IO.STREAM;
ROPE:      TYPE ~ Rope.ROPE;
Matrix Procedures
StartBranch: SceneProc ~ {
IF ps.inKey THEN {
G3dScene.WriteLog[ps, "ERROR: can't StartBranch from within a key definition"];
RETURN;
};
G3dTimeTrees.SetLocalTransform[ps.timeTree, ps.ctm];
G3dTimeTrees.PushTimeTree[ps.timeTree];
ps.matrixStack ¬ CONS[ps.ctm, ps.matrixStack];
ps.ctm ¬ G3dMatrix.Identity[];
G3dScene.WriteLog[ps, "Starting a new branch"];
ps.timeTree.activeNode.clientData ¬ NEW[SourceTextRep ¬ [ps.fileName, ps.index]];
};
EndBranch: SceneProc ~ {
IF ps.inKey THEN {
G3dScene.WriteLog[ps, "ERROR: can't EndBranch from within a key definition"];
RETURN;
};
G3dTimeTrees.PopTimeTree[ps.timeTree];
ps.ctm ¬ ps.matrixStack.first;
ps.matrixStack ¬ ps.matrixStack.rest;
ps.changes ¬ Atom.PutPropOnList[ps.changes, $transform, $true];
G3dScene.WriteLog[ps, "Ending a branch"];
};
IdentityMatrix: SceneProc ~ {
ps.ctm ¬ G3dMatrix.Identity[];
G3dScene.WriteLog[ps, "Current transformation set to identity"];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $transform, $true];
};
Translate: SceneProc ~ {
t: Triple ¬ [0.0, 0.0, 0.0];
axisA, factorA, yA, zA: Arg;
[axisA, factorA, yA, zA] ¬ G3dScene.GetArgs[ps, args, "%sr[rr"];
SELECT TRUE FROM
Eq[axisA.rope, "X"] => t.x ¬ factorA.real;
Eq[axisA.rope, "Y"] => t.y ¬ factorA.real;
Eq[axisA.rope, "Z"] => t.z ¬ factorA.real;
Eq[axisA.rope, "XYZ"] => IF yA.ok AND zA.ok
THEN t ¬ [factorA.real, yA.real, zA.real]
ELSE G3dScene.ParseError["Translate XYZ requires 3 arguments"];
ENDCASE => G3dScene.ParseError["Translate axis must be X, Y, Z, or XYZ"];
UpdateCtm[G3dMatrix.MakeTranslate[t], ps];
G3dScene.WriteLog[ps, IO.PutFR["Translate by (%g %g %g)", [real[t.x]],[real[t.y]],[real[t.z]]]];
};
Scale: SceneProc ~ {
t: Triple ¬ [1.0, 1.0, 1.0];
axisA, factorA, yA, zA: Arg;
[axisA, factorA, yA, zA] ¬ G3dScene.GetArgs[ps, args, "%sr[rr"];
SELECT TRUE FROM
Eq[axisA.rope, "X"] => t.x ¬ factorA.real;
Eq[axisA.rope, "Y"] => t.y ¬ factorA.real;
Eq[axisA.rope, "Z"] => t.z ¬ factorA.real;
Eq[axisA.rope, "Uniform"] => t.x ¬ t.y ¬ t.z ¬ factorA.real;
Eq[axisA.rope, "XYZ"] => IF yA.ok AND zA.ok
THEN t ¬ [factorA.real, yA.real, zA.real]
ELSE G3dScene.ParseError["Scale XYZ requires 3 arguments"];
ENDCASE => G3dScene.ParseError["Scale axis must be X, Y, Z, or XYZ"];
UpdateCtm[G3dMatrix.MakeScale[t], ps];
G3dScene.WriteLog[ps, IO.PutFR["Scaling by (%g %g %g)", [real[t.x]], [real[t.y]], [real[t.z]]]];
};
Shear: SceneProc ~ {
ReplaceElementMatrix: PROC [x, y: INT, v: REAL] RETURNS [m: Matrix] ~ {
m ¬ G3dMatrix.Identity[];
m[y][x] ¬ v;
};
row, column: INT ¬ 0;
axis1A, axis2A, factorA: Arg;
[axis1A, axis2A, factorA] ¬ G3dScene.GetArgs[ps, args, "%ssr"];
row ¬ SELECT TRUE FROM
Eq[axis1A.rope, "X"] => 0,
Eq[axis1A.rope, "Y"] => 1,
Eq[axis1A.rope, "Z"] => 2,
ENDCASE => G3dScene.ParseError["Shear axis must be X, Y, or Z"];
column ¬ SELECT TRUE FROM
Eq[axis2A.rope, "X"] => 0,
Eq[axis2A.rope, "Y"] => 1,
Eq[axis2A.rope, "Z"] => 2,
ENDCASE => G3dScene.ParseError["Shear axis must be X, Y, or Z"];
UpdateCtm[ReplaceElementMatrix[row, column, factorA.real], ps];
G3dScene.WriteLog[ps, IO.PutFR["Shearing along axis %g with respect to axis %g by %g",
IO.rope[axis1A.rope], IO.rope[axis2A.rope], IO.real[factorA.real]]];
};
Rotate: SceneProc ~ {
axis: Triple ¬ [0.0, 0.0, 0.0];
axisA, thetaA, radiansA, ccwA: Arg;
theta: REAL;
[axisA, thetaA, radiansA, ccwA] ¬ G3dScene.GetArgs[ps, args, "%sr-radians%b-ccw%b"];
axis ¬ SELECT TRUE FROM
Eq[axisA.rope, "X"] => [1.0, 0.0, 0.0],
Eq[axisA.rope, "Y"] => [0.0, 1.0, 0.0],
Eq[axisA.rope, "Z"] => [0.0, 0.0, 1.0],
ENDCASE => G3dScene.ParseError["Rotation axis must be X, Y, or Z"];
theta ¬ thetaA.real;
IF ccwA.ok THEN theta ¬ -theta;
UpdateCtm[G3dMatrix.MakeRotate[axis, theta, NOT radiansA.ok], ps];
G3dScene.WriteLog[ps, IO.PutFR["Rotating around axis (%g %g %g) by %g", IO.real[axis.x], IO.real[axis.y], IO.real[axis.z], IO.real[thetaA.real]]];
};
RotateAxis: SceneProc ~ {
axis: Triple ¬ [0.0, 0.0, 1.0];
base: Triple ¬ [0.0, 0.0, 0.0];
xA, yA, zA, tA, rA, bxA, byA, bzA: Arg;
[xA, yA, zA, tA, rA, bxA, byA, bzA] ¬
G3dScene.GetArgs[ps, args, "-axis%rrr-angle%r-radians%b-base%rrr"];
axis ¬ [xA.real, yA.real, zA.real];
IF bxA.ok THEN base ¬ [bxA.real, byA.real, bzA.real];
UpdateCtm[G3dMatrix.MakeRotateAbout[axis, tA.real, NOT rA.ok, base], ps];
G3dScene.WriteLog[ps, IO.PutFR["Scaling around axis (%g %g %g) by %g",
IO.real[axis.x], IO.real[axis.y], IO.real[axis.z], IO.real[tA.real]]];
};
ExplicitMatrix: SceneProc ~ {
m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33: Arg;
abs: Arg;
m: Matrix ¬ G3dMatrix.Identity[];
[m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33, abs] ¬
G3dScene.GetArgs[ps, args, "%rrrrrrrrrrrrrrrr-absolute%b"];
m[0][0] ¬ m00.real; m[0][1] ¬ m01.real; m[0][2] ¬ m02.real; m[0][3] ¬ m03.real;
m[1][0] ¬ m10.real; m[1][1] ¬ m11.real; m[1][2] ¬ m12.real; m[1][3] ¬ m13.real;
m[2][0] ¬ m20.real; m[2][1] ¬ m21.real; m[2][2] ¬ m22.real; m[2][3] ¬ m23.real;
m[3][0] ¬ m30.real; m[3][1] ¬ m31.real; m[3][2] ¬ m32.real; m[3][3] ¬ m33.real;
IF abs.ok THEN ps.ctm ¬ G3dMatrix.Identity[];
UpdateCtm[m, ps];
G3dScene.WriteLog[ps, "Appended absolute matrix to current transformation"];
};
UpdateCtm: PROC [m: Matrix, ps: ParseState] ~ {
ps.ctm ¬ G3dMatrix.Mul[m, ps.ctm];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $transform, $true];
};
Material Procedures
SaveMaterial: SceneProc ~ {
name: ROPE ¬ GetRope[ps, args];
ps.materials ¬ AddToMaterialSequence[ps.materials, ps.currentMaterial];
ps.materials[ps.materials.length-1].name ¬ name;
G3dScene.WriteLog[ps, IO.PutFR["Saved material %g", IO.rope[name]]];
};
UseMaterial: SceneProc ~ {
name: ROPE ¬ GetRope[ps, args];
FOR i: INT IN [0..ps.materials.length) DO
IF NOT Eq[name, ps.materials[i].name] THEN LOOP;
ps.currentMaterial ¬ ps.materials[i];
G3dScene.WriteLog[ps, IO.PutFR["Using material %g", IO.rope[ps.currentMaterial.name]]];
EXIT;
ENDLOOP;
G3dScene.WriteLog[ps, IO.PutFR["Could not retrieve material %g", IO.rope[name]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $diffuse, $true];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $specular, $true];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $metallicity, $true];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $shininess, $true];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $transmittance, $true];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $color, $true];
};
MaterialBackFacesVisible: SceneProc ~ {
b: BOOL ¬ ps.currentMaterial.backFaces ¬ Convert.BoolFromRope[GetRope[ps, args]];
G3dScene.WriteLog[ps, IO.PutFR["Back faces visible: %g", IO.bool[b]]];
};
MaterialRenderStyle: SceneProc ~ {
style: ROPE ¬ GetRope[ps, args];
ps.currentMaterial.renderStyle ¬ SELECT TRUE FROM
Eq[style, "default"], Eq[style, "faceted"] => faceted,
Eq[style, "smooth"] => smooth,
Eq[style, "lines"] => lines,
Eq[style, "shadedLines"] => shadedLines,
Eq[style, "hiddenLines"] => hiddenLines,
Eq[style, "linesWnormals"] => linesWnormals,
Eq[style, "controlPoints"] => controlPoints,
ENDCASE => G3dScene.ParseError["no such render style"];
G3dScene.WriteLog[ps, Rope.Cat["Material render style set to: ", style]];
};
MaterialColor: SceneProc ~ {
t: Triple;
rA, gA, bA, scaleA: Arg;
[rA, gA, bA, scaleA] ¬ G3dScene.GetArgs[ps, args, "%rrr-scale%b"];
t ¬ [rA.real, gA.real, bA.real];
ps.currentMaterial.color ¬ IF scaleA.ok
THEN G3dVector.MulVectors[ps.currentMaterial.color, t] ELSE t;
G3dScene.WriteLog[ps, IO.PutFR["Color set to (%g, %g, %g)", [real[t.x]],[real[t.y]],[real[t.z]]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $color, $true];
};
MaterialDiffuse: SceneProc ~ {
sA, scaleA: Arg;
[sA, scaleA] ¬ G3dScene.GetArgs[ps, args, "%r-scale%b"];
ps.currentMaterial.diffuseReflectivity ¬
IF scaleA.ok THEN ps.currentMaterial.diffuseReflectivity*sA.real ELSE sA.real;
G3dScene.WriteLog[ps, IO.PutFR["Diffuse Reflectivity set to %g", IO.real[ps.currentMaterial.diffuseReflectivity]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $diffuse, $true];
};
MaterialSpecular: SceneProc ~ {
sA, scaleA: Arg;
[sA, scaleA] ¬ G3dScene.GetArgs[ps, args, "%r-scale%b"];
ps.currentMaterial.specularReflectivity ¬
IF scaleA.ok THEN ps.currentMaterial.specularReflectivity*sA.real ELSE sA.real;
G3dScene.WriteLog[ps, IO.PutFR["Specular Reflectivity set to %g", IO.real[ps.currentMaterial.specularReflectivity]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $specular, $true];
};
MaterialMetallicity: SceneProc ~ {
sA, scaleA: Arg;
[sA, scaleA] ¬ G3dScene.GetArgs[ps, args, "%r-scale%b"];
ps.currentMaterial.metallicity ¬
IF scaleA.ok THEN ps.currentMaterial.metallicity*sA.real ELSE sA.real;
G3dScene.WriteLog[ps, IO.PutFR["Metallicity set to %g", IO.real[ps.currentMaterial.metallicity]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $metallicity, $true];
};
MaterialShininess: SceneProc ~ {
sA, scaleA: Arg;
[sA, scaleA] ¬ G3dScene.GetArgs[ps, args, "%r-scale%b"];
ps.currentMaterial.shininess ¬
IF scaleA.ok THEN ps.currentMaterial.shininess*sA.real ELSE sA.real;
G3dScene.WriteLog[ps, IO.PutFR["Shininess set to %g", IO.real[ps.currentMaterial.shininess]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $shininess, $true];
};
MaterialTransmittance: SceneProc ~ {
sA, scaleA: Arg;
[sA, scaleA] ¬ G3dScene.GetArgs[ps, args, "%r-scale%b"];
ps.currentMaterial.transmittance ¬ IF scaleA.ok
THEN ps.currentMaterial.transmittance*sA.real ELSE sA.real;
G3dScene.WriteLog[ps, IO.PutFR["Transmittance set to %g", IO.real[ps.currentMaterial.transmittance]]];
ps.changes ¬ Atom.PutPropOnList[ps.changes, $transmittance, $true];
};
MaterialVisible: SceneProc ~ {
b: BOOL ¬ ps.currentMaterial.visible ¬ Convert.BoolFromRope[GetRope[ps, args]];
G3dScene.WriteLog[ps, IO.PutFR["Material visibility: %g", IO.bool[b]]];
};
Context3d Procedures
AddProperty: SceneProc ~ {
in: IO.STREAM ¬ IO.RIS[args];
G3dScene.WriteLog[ps, "Adding property"];
ps.context3d.props ¬ Atom.PutPropOnList[ps.context3d.props,IO.GetRefAny[in],IO.GetRefAny[in]];
};
Rendering Procedures
Render: SceneProc ~ {
error: ROPE;
G3dScene.WriteLog[ps, "Render"];
G3dTimeTrees.ReportTimeTree[ps.timeTree];
error ¬ G3dRender.Render[ps.context3d, NIL, FALSE];
IF error # NIL THEN G3dScene.WriteLog[ps, error];
};
AntiAliasing: SceneProc ~ {
in: STREAM ¬ IO.RIS[args];
Skip[in];
G3dScene.WriteLog[ps, "Anti aliasing set"];
G3dRender.SetAntiAliasing[ps.context3d, IO.GetBool[in]];
};
DisplayMode: SceneProc ~ {
mode: ROPE ¬ GetRope[ps, args];
G3dScene.WriteLog[ps, Rope.Cat["Set display mode: ", mode]];
G3dRender.LoadDisplayClass[ps.context3d, SELECT TRUE FROM Eq[mode, "fullColor"] => $FullColor, Eq[mode, "dither"] => $PseudoColor, ENDCASE => $Gray];
};
DepthBuffering: SceneProc ~ {
in: STREAM ¬ IO.RIS[args];
Skip[in];
G3dScene.WriteLog[ps, "Depth Buffering set"];
G3dRenderWithPixels.DepthBuffering[ps.context3d, IO.GetBool[in]];
};
NormalCoding: SceneProc ~ {
in: STREAM ¬ IO.RIS[args];
Skip[in];
G3dScene.WriteLog[ps, "Depth Buffering set"];
G3dRenderWithPixels.NormalBuffering[ps.context3d, IO.GetBool[in]];
};
DisplayRegion: SceneProc ~ {
xy: Pair ¬ GetPair[ps, args];
wh: Pair ¬ GetPair[ps, args];
G3dScene.WriteLog[ps, IO.PutFR["DisplayRegion: [%g, %g, %g, %g]",
IO.real[xy.x], IO.real[xy.y], IO.real[wh.x], IO.real[wh.y]]];
G3dRender.SetWindow[ps.context3d, [xy.x, xy.y, wh.x, wh.y]];
};
Viewport: SceneProc ~ {
xy: Pair ¬ GetPair[ps, args];
wh: Pair ¬ GetPair[ps, args];
G3dScene.WriteLog[ps, IO.PutFR["Viewport: [%g, %g, %g, %g]",
IO.real[xy.x], IO.real[xy.y], IO.real[wh.x], IO.real[wh.y]]];
G3dRender.SetViewport[ps.context3d, [xy.x, xy.y, wh.x, wh.y]];
};
Backgound Procedures
BackgroundColor: SceneProc ~ {
t: Triple ¬ GetTriple[ps, args];
G3dScene.WriteLog[ps, IO.PutFR["Background: (%g, %g, %g)",
[real[t.x]], [real[t.y]], [real[t.z]]]];
G3dRender.SetBackgroundColor[ps.context3d, [t.x, t.y, t.z]];
};
BackgroundImage: SceneProc ~ {
name: ROPE ¬ GetRope[ps, args];
G3dScene.WriteLog[ps, Rope.Cat["Background image: ", name]];
G3dRender.SetBackgroundImage[ps.context3d, name];
};
EnableBackground: SceneProc ~ {
G3dScene.WriteLog[ps, "EnableBackground set"];
G3dRender.EnableClear[ps.context3d, IO.GetBool[IO.RIS[args]]];
};
Camera Procedures
UpdateCamera: SceneProc ~ {
AddRealToMsg: PROC [r: REAL] ~ {msg ¬ Rope.Cat[msg, IO.PutFR["%g", IO.real[r]]]};
AddTripleToMsg: PROC [t: Triple] ~ {
msg ¬ Rope.Cat[msg, IO.PutFR["(%g, %g, %g)", [real[t.x]], [real[t.y]], [real[t.z]]]];
};
msg: ROPE ¬ IO.PutFR["Set camera %g: ", IO.refAny[data]];
ps.shouldRepaint ¬ TRUE;
SELECT data FROM
$FieldOfView => AddRealToMsg[ps.context3d.fieldOfView ¬ GetReal[ps, args]];
$Roll => AddRealToMsg[ps.context3d.rollAngle ¬ GetReal[ps, args]];
ENDCASE => {
t: Triple ¬ GetTriple[ps, args];
AddTripleToMsg[t];
SELECT data FROM
$EyePoint => ps.context3d.eyePoint ¬ t;
$LookAt  => ps.context3d.lookAt ¬ t;
$Up   => ps.context3d.upDirection ¬ t;
ENDCASE;
};
G3dScene.WriteLog[ps, msg];
};
Shape Procedures
ReadShape: SceneProc ~ {
name, instanceName: ROPE ¬ NIL;
nameA, instanceNameA: Arg;
[nameA, instanceNameA] ¬ G3dScene.GetArgs[ps, args, "%s[s"];
name ¬ nameA.rope;
IF instanceNameA.ok THEN instanceName ¬ instanceNameA.rope;
IF instanceName = NIL THEN {
index: INT ¬ IF ps.context3d.shapes # NIL THEN ps.context3d.shapes.length ELSE 0;
instanceName ¬ IO.PutFR["%g.%g", IO.rope[FileNames.GetShortName[name]], IO.int[index]];
};
IF Rope.Find[name, "/"] = -1 AND Rope.Find[name, ">"] = -1
THEN name ¬ Rope.Cat[ps.directory, name];
G3dRender.AddShapeFromFile[ps.context3d, instanceName, name
! G3dShape.Error => G3dScene.ParseError[reason]];
ps.currentShape ¬ ps.context3d.shapes[ps.context3d.shapes.length-1];
G3dScene.AssignCtmToShape[ps, ps.currentShape];
G3dScene.InheritMaterial[ps];
G3dScene.WriteLog[ps, Rope.Cat["Read shape: ", name, " [", instanceName, "]"]];
};
WriteShape: SceneProc ~ {
fileName: ROPE;
shapes: ShapeSequence ¬ ps.context3d.shapes;
shapeNameA, fileNameA, transformA: Arg;
[shapeNameA, fileNameA, transformA] ¬ G3dScene.GetArgs[ps, args, "%s-fileName%s-transform%b"];
fileName ¬ IF fileNameA.ok THEN fileNameA.rope ELSE Rope.Cat[shapeNameA.rope, ".shape"];
FOR i: NAT IN [0..shapes.length) DO
shape: Shape ¬ shapes[i];
IF NOT Eq[shape.name, shapeNameA.rope] THEN LOOP;
shape ¬ G3dShape.CopyShape[shapes[i]];
IF transformA.ok THEN G3dShape.TransformVertices[shape, shape.matrix];
G3dShape.ShapeToFile[fileName, shape, TRUE, FALSE, "shape written from context3d"];
EXIT;
ENDLOOP;
G3dScene.WriteLog[ps, Rope.Cat["Wrote shape ", shapeNameA.rope, " to file ", fileName]];
};
WriteAllShapes: SceneProc ~ {
shapes: ShapeSequence ¬ ps.context3d.shapes;
FOR i: NAT IN [0..shapes.length) DO
fileName: ROPE ¬ Rope.Cat[ps.directory, shapes[i].name];
shape: Shape ¬ G3dShape.CopyShape[shapes[i]];
shape.matrix ¬ shapes[i].matrix;
G3dShape.TransformVertices[shape, shape.matrix];
G3dShape.UnitizeVertexNormals[shape];
G3dShape.ShapeToFile[fileName, shape, TRUE, FALSE, "shape written from context3d"];
ENDLOOP;
G3dScene.WriteLog[ps, "Wrote all shapes to files"];
};
DeleteShape: SceneProc ~ {
shapeName: ROPE ¬ GetRope[ps, args];
G3dRender.DeleteShape[ps.context3d, shapeName];
};
DeleteAllShapes: SceneProc ~ {
G3dRender.DeleteAllShapes[ps.context3d];
};
Shape Processing
InvertNormals: SceneProc ~ {
IF ps.currentShape # NIL THEN {
G3dScene.WriteLog[ps, Rope.Cat["Negate normals of ", ps.currentShape.name]];
G3dShape.NegateVertexNormals[ps.currentShape];
};
};
Triangulate: SceneProc ~ {
G3dScene.WriteLog[ps, Rope.Cat["Triangulate shape: ", ps.currentShape.name]];
G3dShape.Triangulate[ps.currentShape];
};
ReversePolygons: SceneProc ~ {
G3dScene.WriteLog[ps, Rope.Cat["Reverse polygons of ", ps.currentShape.name]];
G3dShape.ReversePolygons[ps.currentShape];
};
OpenContours: SceneProc ~ {
sd: SurfaceDescription ¬ NEW[SurfaceDescriptionRep ¬ []];
sd.open ¬ TRUE;
FOR i: INT IN [0 .. ps.currentShape.surfaces.length) DO
ps.currentShape.surfaces[i].clientData ¬ sd;
ENDLOOP;
G3dScene.WriteLog[ps, Rope.Cat["Making an open surface of ", ps.currentShape.name]];
};
AddAxes: SceneProc ~ {
nReticles: NAT ¬ 20;
size: REAL ¬ 1.0;
scale: Triple ¬ [1, 1, 1];
origin: Triple ¬ [0, 0, 0];
x, y, z, s, sx, sy, sz, n: Arg;
[x, y, z, s, sx, sy, sz, n] ¬
G3dScene.GetArgs[ps, args, "-origin%rrr-size%r-scale%rrr-nReticles%i"];
IF x.ok AND y.ok AND z.ok THEN origin ¬ [x.real, y.real, z.real];
IF sx.ok AND sy.ok AND sz.ok THEN scale ¬ [sx.real, sy.real, sz.real];
IF s.ok THEN size ¬ s.real;
IF n.ok THEN nReticles ¬ n.int;
G3dScene.WriteLog[ps, "Adding axes"];
G3dRender.AddAxes[ps.context3d, origin, size, scale, nReticles];
};
Texturing Procedures
SetTexture: SceneProc ~ {
typeA, filenameA: Arg;
[typeA, filenameA] ¬ G3dScene.GetArgs[ps, args, "%ss"];
SELECT TRUE FROM
Eq[typeA.rope, "intensity"] => ps.currentMaterial.textureIntensityName ¬ filenameA.rope;
Eq[typeA.rope, "color"] => ps.currentMaterial.textureColorName ¬ filenameA.rope;
Eq[typeA.rope, "bump"] => ps.currentMaterial.textureBumpName ¬ filenameA.rope;
ENDCASE => G3dScene.ParseError["Texture type must be intensity, color, or bump"];
G3dScene.WriteLog[ps, Rope.Cat["Enabled texture of type ", typeA.rope, " from file ", filenameA.rope]];
};
DisableAllTextures: SceneProc ~ {
ps.currentMaterial.textureIntensityName ¬ NIL;
ps.currentMaterial.textureColorName ¬ NIL;
ps.currentMaterial.textureBumpName ¬ NIL;
G3dScene.WriteLog[ps, "Disabled all textures"];
};
DisableTexture: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
SELECT TRUE FROM
Eq[type, "intensity"] => ps.currentMaterial.textureIntensityName ¬ NIL;
Eq[type, "color"] => ps.currentMaterial.textureColorName ¬ NIL;
Eq[type, "bump"] => ps.currentMaterial.textureBumpName ¬ NIL;
ENDCASE => G3dScene.ParseError["Texture type must be intensity, color, or bump"];
G3dScene.WriteLog[ps, Rope.Concat["Disabled texture of type ", type]];
};
OffsetTexture: SceneProc ~ {
p: Pair ¬ ps.currentMaterial.textureOffset ¬ GetPair[ps, args];
G3dScene.WriteLog[ps, IO.PutFR["Set texture offset to %g %g", [real[p.x]], [real[p.y]]]];
};
ScaleTexture: SceneProc ~ {
p: Pair ¬ ps.currentMaterial.textureScale ¬ GetPair[ps, args];
G3dScene.WriteLog[ps, IO.PutFR["Set texture scale to %g %g", [real[p.x]], [real[p.y]]]];
};
ScaleBumps: SceneProc ~ {
scale: REAL ¬ Convert.RealFromRope[GetRope[ps, args]];
ps.currentMaterial.bumpScale ¬ scale;
G3dScene.WriteLog[ps, IO.PutFR["Set bump scale to %g", IO.real[scale]]];
};
FilterTexture: SceneProc ~ {
b: BOOL ¬ ps.currentMaterial.textureFiltering ¬ Convert.BoolFromRope[GetRope[ps, args]];
G3dScene.WriteLog[ps, IO.PutFR["Texture filtering set to %b", IO.bool[b]]];
};
Lighting Procedures
AmbientLight: SceneProc ~ {     
t: Triple ¬ GetTriple[ps, args];
G3dRender.SetAmbientLight[ps.context3d, [t.x, t.y, t.z]];
G3dScene.WriteLog[ps, IO.PutFR["Ambient light set to (%g %g %g)",
IO.real[t.x], IO.real[t.y], IO.real[t.z]]];
};
AddLight: SceneProc ~ {
AutoLightName: PROC [context3d: Context3d, type: ROPE] RETURNS [ROPE] ~ {
index: INT ¬ IF context3d.lightSources = NIL THEN 0 ELSE context3d.lightSources.length;
RETURN[IO.PutFR["%g%g", IO.rope[type], IO.int[index]]];
};
name: ROPE ¬ AutoLightName[ps.context3d, "AutoLight"];
nameA, xA, yA, zA, rA, gA, bA: Arg;
rgb: RGB ¬ [1.0, 1.0, 1.0];
[xA, yA, zA, rA, gA, bA, nameA] ¬ G3dScene.GetArgs[ps, args, "-position%rrr-color%rrr-name%s"];
IF nameA.ok THEN name ¬ nameA.rope;
IF rA.ok THEN rgb ¬ [rA.real, gA.real, bA.real];
IF xA.ok AND rA.ok
THEN G3dRender.AddLight[ps.context3d, name, [xA.real, yA.real, zA.real], rgb];
G3dScene.WriteLog[ps, IO.PutFLR["Light %g placed at (%g %g %g) with color (%g %g %g)",
LIST[IO.rope[name], IO.real[xA.real], IO.real[yA.real], IO.real[zA.real],
IO.real[rgb.R], IO.real[rgb.G], IO.real[rgb.B]]]];
};
Variable Procedures
SetVariable: SceneProc ~ {
Translate: Rope.TranslatorType ~ {RETURN[IF old = '\t THEN ' ELSE old]};
v: Variable;
cleanArgs: ROPE ¬ Rope.Translate[StripLeadingBlanks[args],,, Translate];
endOfName: INT ¬ Rope.Find[cleanArgs, " "];
IF endOfName < 0 THEN RETURN;
v.name ¬ Rope.Substr[cleanArgs, 0, endOfName];
v.value ¬ Rope.Substr[cleanArgs, endOfName+1];
v.value ← G3dScene.SubstituteVariables[ps.variables, v.value];
IF ps.variables = NIL THEN {
ps.variables ¬ AddToVariableSequence[NIL, v];
RETURN;
};
FOR i: INT IN [0..ps.variables.length) DO
IF NOT Eq[ps.variables[i].name, v.name] THEN LOOP;
ps.variables[i].value ¬ v.value;
RETURN;
ENDLOOP;
ps.variables ¬ AddToVariableSequence[ps.variables, v];
G3dScene.WriteLog[ps, IO.PutFR["Set variable <%g> to value <%g>",
IO.rope[v.name], IO.rope[v.value]]];
};
UnSetVariable: SceneProc ~ {
key: ROPE ¬ GetRope[ps, args];
IF ps.variables # NIL AND ps.variables.length > 0 THEN
FOR i: INT IN [0..ps.variables.length) DO
IF NOT Eq[ps.variables[i].name, key] THEN LOOP;
FOR j: INT IN [i+1..ps.variables.length) DO ps.variables[j-1] ¬ ps.variables[j]; ENDLOOP;
ps.variables.length ¬ ps.variables.length-1;
EXIT;
ENDLOOP;
G3dScene.WriteLog[ps, Rope.Cat["Unset variable <", key, ">"]];
};
RandomSeed: SceneProc ~ {
seed: INT ¬ GetInt[ps, args];
ps.randomStream ¬ Random.Create[0, seed];
};
Animation Procedures
LockNode: SceneProc ~ {
G3dTimeTrees.LockActiveNode[ps.timeTree];
};
UnlockNode: SceneProc ~ {
G3dTimeTrees.UnlockActiveNode[ps.timeTree];
};
GetInterpolationType: PROC [r: ROPE] RETURNS [InterpolationType] ~ {
SELECT TRUE FROM
Rope.Equal[r, "constant", FALSE] => RETURN[constant];
Rope.Equal[r, "linear", FALSE] => RETURN[linear];
Rope.Equal[r, "smooth", FALSE] => RETURN[smooth];
ENDCASE => RETURN[smooth];
};
DiffuseInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetDiffuseInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
SpecularInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetSpecularInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
MetallicityInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetMetallicityInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
ShininessInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetShininessInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
TransmittanceInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetTransmittanceInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
ColorInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetColorInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
TransformInterpolation: SceneProc ~ {
type: ROPE ¬ GetRope[ps, args];
G3dTimeTrees.SetTransformInterpolationType[ps.timeTree, GetInterpolationType[type]];
};
StartKeys: SceneProc ~ {
IF ps.inKey THEN {
G3dScene.WriteLog[ps, "ERROR: can't StartKey from within a key definition"];
RETURN;
};
G3dScene.MakeTransformNode[ps];
ps.inKey ¬ TRUE;
ps.ctm ¬ G3dMatrix.Identity[];
ps.changes ¬ NIL;
};
EndKeys: SceneProc ~ {
G3dScene.MakeKeysNode[ps];
ps.inKey ¬ FALSE;
ps.changes ¬ NIL;
ps.ctm ¬ G3dMatrix.Identity[];
};
Time: SceneProc ~ {
time: REAL ¬ GetReal[ps, args];
attach the relevant information to the timeTree, based on changes field in ps
IF Atom.GetPropFromList[ps.changes, $diffuse] # NIL THEN
G3dTimeTrees.AssignDiffuse[ps.timeTree, time, ps.currentMaterial.diffuseReflectivity];
IF Atom.GetPropFromList[ps.changes, $specular] # NIL THEN
G3dTimeTrees.AssignSpecular[ps.timeTree, time, ps.currentMaterial.specularReflectivity];
IF Atom.GetPropFromList[ps.changes, $metallicity] # NIL THEN
G3dTimeTrees.AssignMetallicity[ps.timeTree, time, ps.currentMaterial.metallicity];
IF Atom.GetPropFromList[ps.changes, $shininess] # NIL THEN
G3dTimeTrees.AssignShininess[ps.timeTree, time, ps.currentMaterial.shininess];
IF Atom.GetPropFromList[ps.changes, $transmittance] # NIL THEN
G3dTimeTrees.AssignTransmittance[ps.timeTree, time, ps.currentMaterial.transmittance];
IF Atom.GetPropFromList[ps.changes, $color] # NIL THEN
G3dTimeTrees.AssignColor[ps.timeTree, time, ps.currentMaterial.color];
IF Atom.GetPropFromList[ps.changes, $transform] # NIL THEN
G3dTimeTrees.AssignTransform[ps.timeTree, time, ps.ctm];
};
StrobeScene: SceneProc ~ {
time: REAL ¬ GetReal[ps, args];
G3dTimeTrees.StrobeTimeTree[ps.timeTree, time];
};
Support Procedures
Skip: PROC [in: STREAM] ~ {
DO
c: CHAR ¬ IO.PeekChar[in];
IF c=') OR c='( OR c=': OR c=', OR c=Ascii.SP OR c='\t THEN [] ¬ IO.GetChar[in] ELSE EXIT;
ENDLOOP;
};
RealFromStream: PROC [in: STREAM] RETURNS [r: REAL] ~ {Skip[in]; r ¬ IO.GetReal[in]};
IntFromStream: PROC [in: STREAM] RETURNS [i: INT] ~ {Skip[in]; i ¬ IO.GetInt[in]};
GetInt: PROC [ps: ParseState, args: ROPE] RETURNS [i: INT] ~ {
i ¬ IntFromStream[IO.RIS[G3dScene.SubstituteVariables[ps.variables, args]]];
};
GetReal: PROC [ps: ParseState, args: ROPE] RETURNS [r: REAL] ~ {
r ¬ RealFromStream[IO.RIS[G3dScene.SubstituteVariables[ps.variables, args]]];
};
GetPair: PROC [ps: ParseState, args: ROPE] RETURNS [p: Pair] ~ {
in: STREAM ¬ IO.RIS[G3dScene.SubstituteVariables[ps.variables, args]];
p.x ¬ RealFromStream[in]; p.y ¬ RealFromStream[in];
};
GetTriple: PROC [ps: ParseState, args: ROPE] RETURNS [t: Triple] ~ {
in: STREAM ¬ IO.RIS[G3dScene.SubstituteVariables[ps.variables, args]];
t.x ¬ RealFromStream[in]; t.y ¬ RealFromStream[in]; t.z ¬ RealFromStream[in];
};
GetRope: PROC [ps: ParseState, args: ROPE] RETURNS [r: ROPE] ~ {
in: STREAM ¬ IO.RIS[G3dScene.SubstituteVariables[ps.variables, args]];
Skip[in];
r ¬ IO.GetTokenRope[in, IO.IDProc].token;
};
StripLeadingBlanks: PROC [input: ROPE] RETURNS [ROPE] ~ {
RETURN[Rope.Substr[input, IO.SkipWhitespace[IO.RIS[input]]]];
};
Eq: PROC [r1, r2: ROPE] RETURNS [b: BOOL] ~ {b ¬ Rope.Equal[r1, r2, FALSE]};
Sequence Support
AddToVariableSequence: PROC [variables: VariableSequence, variable: Variable]
RETURNS [VariableSequence] ~ {
IF variables = NIL THEN variables ¬ NEW[VariableSequenceRep[1]];
IF variables.length = variables.maxLength THEN variables ¬ LengthenVariables[variables];
variables[variables.length] ¬ variable;
variables.length ¬ variables.length+1;
RETURN[variables];
};
LengthenVariables: PROC [variables: VariableSequence, amount: REAL ¬ 1.3]
RETURNS [new: VariableSequence] ~ {
newLength: NAT ¬ MAX[Real.Ceiling[amount*variables.maxLength], 3];
new ¬ NEW[VariableSequenceRep[newLength]];
FOR i: NAT IN [0..variables.length) DO new[i] ¬ variables[i]; ENDLOOP;
new.length ¬ variables.length;
};
AddToMaterialSequence: PROC [materials: MaterialSequence, material: Material]
RETURNS [MaterialSequence] ~ {
IF materials = NIL THEN materials ¬ NEW[MaterialSequenceRep[1]];
IF materials.length = materials.maxLength THEN materials ¬ LengthenMaterials[materials];
materials[materials.length] ¬ material;
materials.length ¬ materials.length+1;
RETURN[materials];
};
LengthenMaterials: PROC [materials: MaterialSequence, amount: REAL ¬ 1.3]
RETURNS [new: MaterialSequence] ~ {
newLength: NAT ¬ MAX[Real.Ceiling[amount*materials.maxLength], 3];
new ¬ NEW[MaterialSequenceRep[newLength]];
FOR i: NAT IN [0..materials.length) DO new[i] ¬ materials[i]; ENDLOOP;
new.length ¬ materials.length;
};
Initialization
RegisterProcs: PROC ~ {
matrix stack control  
G3dScene.RegisterProc["Identity",       IdentityMatrix];
G3dScene.RegisterProc["StartBranch",      StartBranch];
G3dScene.RegisterProc["{",         StartBranch];
G3dScene.RegisterProc["EndBranch",      EndBranch];
G3dScene.RegisterProc["}",         EndBranch];
translation
G3dScene.RegisterProc["Translate",      Translate];
G3dScene.RegisterProc["T",         Translate];
scaling
G3dScene.RegisterProc["Scale",        Scale];
G3dScene.RegisterProc["S",         Scale];
shearing
G3dScene.RegisterProc["Shear",       Shear];
rotation
G3dScene.RegisterProc["Rotate",       Rotate];
G3dScene.RegisterProc["R",         Rotate];
G3dScene.RegisterProc["RotateAxis",      RotateAxis];
experts
G3dScene.RegisterProc["ExplicitMatrix",     ExplicitMatrix];
lighting control
G3dScene.RegisterProc["AmbientLight",     AmbientLight];
G3dScene.RegisterProc["AddLight",      AddLight];
context3d
G3dScene.RegisterProc["AddProperty",     AddProperty];
rendering
G3dScene.RegisterProc["Render", Render];
G3dScene.RegisterProc["AntiAliasing",     AntiAliasing];
G3dScene.RegisterProc["DisplayMode",     DisplayMode];
G3dScene.RegisterProc["DepthBuffering",     DepthBuffering];
G3dScene.RegisterProc["NormalCoding",     NormalCoding];
G3dScene.RegisterProc["DisplayRegion",     DisplayRegion];
G3dScene.RegisterProc["Viewport",      Viewport];
background
G3dScene.RegisterProc["BackgroundColor",    BackgroundColor];
G3dScene.RegisterProc["BackgroundImage",    BackgroundImage];
G3dScene.RegisterProc["EnableBackground",    EnableBackground];
camera
G3dScene.RegisterProc["FieldOfView",     UpdateCamera, $FieldOfView];
G3dScene.RegisterProc["EyePoint",      UpdateCamera, $EyePoint];
G3dScene.RegisterProc["LookAt",       UpdateCamera, $LookAt];
G3dScene.RegisterProc["Up",        UpdateCamera, $Up];
G3dScene.RegisterProc["Roll",        UpdateCamera, $Roll];
shape io
G3dScene.RegisterProc["ReadShape",      ReadShape];
G3dScene.RegisterProc["WriteShape",      WriteShape];
G3dScene.RegisterProc["WriteAllShapes",     WriteAllShapes];
G3dScene.RegisterProc["DeleteShape",      DeleteShape];
G3dScene.RegisterProc["DeleteAllShapes",    DeleteAllShapes];
shapes
G3dScene.RegisterProc["InvertNormals",     InvertNormals];
G3dScene.RegisterProc["Triangulate",      Triangulate];
G3dScene.RegisterProc["ReversePolygons",    ReversePolygons];
G3dScene.RegisterProc["OpenContours",     OpenContours];
G3dScene.RegisterProc["AddAxes",      AddAxes];
materials
G3dScene.RegisterProc["SaveMaterial",     SaveMaterial];
G3dScene.RegisterProc["UseMaterial",      UseMaterial];
G3dScene.RegisterProc["BackFacesVisible",    MaterialBackFacesVisible];
G3dScene.RegisterProc["RenderStyle",      MaterialRenderStyle];
G3dScene.RegisterProc["Color",        MaterialColor];
G3dScene.RegisterProc["Diffuse",       MaterialDiffuse];
G3dScene.RegisterProc["Specular",       MaterialSpecular];
G3dScene.RegisterProc["Metallicity",      MaterialMetallicity];
G3dScene.RegisterProc["Shininess",      MaterialShininess];
G3dScene.RegisterProc["Transmittance",     MaterialTransmittance];
G3dScene.RegisterProc["Visible",       MaterialVisible];
texturing
G3dScene.RegisterProc["OffsetTexture",     OffsetTexture];
G3dScene.RegisterProc["ScaleTexture",     ScaleTexture];
G3dScene.RegisterProc["ScaleBumps",      ScaleBumps];
G3dScene.RegisterProc["FilterTexture",     FilterTexture];
G3dScene.RegisterProc["SetTexture",      SetTexture];
G3dScene.RegisterProc["DisableTexture",     DisableTexture];
G3dScene.RegisterProc["DisableAllTextures",    DisableAllTextures];
variables
G3dScene.RegisterProc["Set",        SetVariable];
G3dScene.RegisterProc["UnSet",       UnSetVariable];
G3dScene.RegisterProc["RandomSeed",      RandomSeed];
animation
G3dScene.RegisterProc["StartKeys",      StartKeys];
G3dScene.RegisterProc["EndKeys",      EndKeys];
G3dScene.RegisterProc["Time",        Time];
G3dScene.RegisterProc["StrobeScene",      StrobeScene];
G3dScene.RegisterProc["DiffuseInterpolation",   DiffuseInterpolation];
G3dScene.RegisterProc["SpecularInterpolation",   SpecularInterpolation];
G3dScene.RegisterProc["MetallicityInterpolation",  MetallicityInterpolation];
G3dScene.RegisterProc["ShininessInterpolation",   ShininessInterpolation];
G3dScene.RegisterProc["TransmittanceInterpolation", TransmittanceInterpolation];
G3dScene.RegisterProc["ColorInterpolation",    ColorInterpolation];
G3dScene.RegisterProc["TransformInterpolation",   TransformInterpolation];
G3dScene.RegisterProc["LockNode",      LockNode];
G3dScene.RegisterProc["UnlockNode",      UnlockNode];
};
Start Procedures
RegisterProcs[];
END.
..