G3dSceneImpl.mesa
Copyright © 1988 by Xerox Corporation. All rights reserved.
Bloomenthal, March 12, 1989 9:03:00 pm PST
DIRECTORY Ascii, Atom, Commander, CommandTool, FileNames, FS, G3dBasic, G3dRender, G3dShape, G3dScene, G3dVector, IO, MessageWindow, Rope, RopeFile, TiogaAccess, TiogaMenuOps, TiogaOps, ViewerOps, ViewerTools;
G3dSceneImpl: CEDAR PROGRAM
IMPORTS Atom, CommandTool, FileNames, FS, G3dRender, G3dShape, G3dVector, IO, MessageWindow, Rope, RopeFile, TiogaAccess, TiogaMenuOps, TiogaOps, ViewerOps, ViewerTools
EXPORTS G3dScene
~ BEGIN
Type Declarations
Pair:    TYPE ~ G3dBasic.Pair;
Triple:   TYPE ~ G3dBasic.Triple;
RGB:    TYPE ~ G3dRender.RGB;
Context:   TYPE ~ G3dRender.Context;
RenderData:  TYPE ~ G3dRender.RenderData;
RenderStyle:  TYPE ~ G3dRender.RenderStyle;
TextureStyle:  TYPE ~ G3dRender.TextureStyle;
TextureInfo:  TYPE ~ G3dRender.TextureInfo;
LogProc:   TYPE ~ G3dScene.LogProc;
ViewerSelection: TYPE ~ G3dScene.ViewerSelection;
Shape:   TYPE ~ G3dShape.Shape;
STREAM:   TYPE ~ IO.STREAM;
ROPE:    TYPE ~ Rope.ROPE;
Writer:   TYPE ~ TiogaAccess.Writer;
SelPos:   TYPE ~ ViewerTools.SelPos;
Viewer:   TYPE ~ ViewerTools.Viewer;
Write Scene Descriptions to a Viewer
Item:     TYPE ~ RECORD [name: ROPE, value: REAL];
WriteInfo:  TYPE ~ RECORD [
writer:     Writer NIL,
fileName:     ROPE NIL,
stream:     STREAMNIL,
ok:       BOOL TRUE];
GetWriteInfo: PROC RETURNS [i: WriteInfo] ~ {
v: Viewer ← ViewerTools.GetSelectedViewer[];
i.writer ← TiogaAccess.Create[];
IF Rope.Length[ViewerTools.GetSelectionContents[]] # 0
THEN i.fileName ← FileNames.ResolveRelativePath[ViewerTools.GetSelectionContents[]]
ELSE i.ok v # NIL AND (v.class.flavor = $Text OR v.class.flavor = $Typescript);
IF NOT i.ok THEN Blink["Make primary selection"];
};
PutWriter: PROC [i: WriteInfo] ~ {
WriteToViewer: PROC [root: TiogaOps.Ref] ~ {
TiogaAccess.WriteSelection[i.writer ! TiogaAccess.Error => {Blink[expl]; CONTINUE}];
};
SELECT TRUE FROM
i.stream # NIL =>
TiogaAccess.WriteOpenFile[i.writer, FS.OpenFileFromStream[i.stream]
! FS.Error => {Blink[error.explanation]; CONTINUE}];
i.fileName # NIL =>
TiogaAccess.WriteFile[i.writer, i.fileName
! FS.Error => {Blink[error.explanation]; CONTINUE}]
ENDCASE => TiogaOps.CallWithLocks[WriteToViewer];
};
Nest: PROC [w: Writer] ~ {TiogaAccess.Nest[w, 1]};
UnNest: PROC [w: Writer] ~ {TiogaAccess.Nest[w, -1]};
WriteNode: PROC [w: Writer, rope: ROPE, looks: ROPENIL] ~ {
tc: TiogaAccess.TiogaChar ← [charSet: 0, char: '\000, looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: FALSE, deltaLevel: 0, propList: NIL];
FOR n: INT IN [0..Rope.Length[looks]) DO
c: CHAR ← Rope.Fetch[looks, n];
IF c IN TiogaAccess.Look THEN tc.looks[c] ← TRUE;
ENDLOOP;
FOR n: INT IN [0..Rope.Length[rope]) DO
tc.char ← Rope.Fetch[rope, n];
TiogaAccess.Put[w, tc];
ENDLOOP;
tc.endOfNode ← TRUE;
TiogaAccess.Put[w, tc];
};
WriteItem: PROC [w: Writer, item: Item] ~ {WriteReal[w, item.name, item.value]};
WriteBool: PROC [w: Writer, name: ROPE, bool: BOOL] ~ {
WriteNode[w, Rope.Cat[name, ":\t", IF bool THEN "True" ELSE "False"]];
};
WriteReal: PROC [w: Writer, name: ROPE, value: REAL] ~ {
WriteNode[w, IO.PutFR["%g:\t%g", IO.rope[name], IO.real[value]]];
};
WritePair: PROC [w: Writer, name: ROPE, p: Pair] ~ {
WriteNode[w, IO.PutFR["%g:\t%g, %g", IO.rope[name], IO.real[p.x], IO.real[p.y]]];
};
WriteTriple: PROC [w: Writer, name: ROPE, t: Triple] ~ {
WriteNode[w, IO.PutFR["%g:\t(%g, %g, %g)",
IO.rope[name], IO.real[t.x], IO.real[t.y], IO.real[t.z]]];
};
WriteRGB: PROC [w: Writer, name: ROPE, rgb: RGB] ~ {
WriteTriple[w, name, [rgb.R, rgb.G, rgb.B]];
};
WriteFour: PROC [w: Writer, name: ROPE, v1, v2, v3, v4: REAL] ~ {
WriteNode[w, IO.PutFR["%g:\t(%g, %g, %g, %g)",
IO.rope[name], IO.real[v1], IO.real[v2], IO.real[v3], IO.real[v4]]];
};
WriteTitle: PROC [w: Writer, title: ROPE] ~ {
WriteNode[w, title, "b"];
Nest[w];
};
WriteBlock: PROC [w: Writer, title: ROPE, items: LIST OF Item] ~ {
WriteTitle[w, title];
FOR l: LIST OF Item ← items, l.rest WHILE l # NIL DO WriteItem[w, l.first]; ENDLOOP;
UnNest[w];
};
WriteShape: PROC [w: Writer, s: Shape] ~ {
shade: REF G3dRender.ShadingClass ← G3dRender.ShadingClassFromShape[s];
WriteTitle[w, Rope.Cat["ShapeRead ", s.name]];
WriteBool[w, "ShapeBackFaces", s.showBackfaces];
WriteNode[w, Rope.Cat["ShapeRenderStyle: ", Atom.GetPName[shade.type]]];
WriteRGB[w, "ShapeColor", shade.color];
WriteReal[w, "ShapeShininess", shade.shininess];
IF shade.transmittance # 0.0 THEN WriteReal[w, "ShapeTransmittance", shade.transmittance];
WriteTriple[w, "ShapePosition", s.position];
WritePair[w, "ShapeTextureScale", shade.textureScale];
WriteReal[w, "ShapeBumpScale", shade.bumpScale];
FOR l: LIST OF TextureInfo ← G3dRender.GetTextureInfo[s], l.rest WHILE l # NIL DO
WriteNode[w, IO.PutFR["Shape%gMap %g, ShapeTextureFiltering: ",
IO.rope[G3dRender.RopeFromTextureStyle[l.first.type]],
IO.rope[l.first.name],
IO.rope[IF l.first.filtered THEN "True" ELSE "False"]]];
ENDLOOP;
UnNest[w];
};
WriteLight: PROC [w: Writer, s: Shape] ~ {
shade: REF G3dRender.ShadingClass ← G3dRender.ShadingClassFromShape[s];
WriteNode[w, IO.PutFLR["%g: %g, (%g, %g, %g), (%g, %g, %g)", LIST[
IO.rope["LightAdd"],
IO.rope[s.name],
IO.real[s.position.x], IO.real[s.position.y], IO.real[s.position.z],
IO.real[shade.color.R], IO.real[shade.color.G], IO.real[shade.color.B]]]];
};
WriteCamera: PROC [context: Context, w: Writer] ~ {
WriteTitle[w, "Camera Parameters"];
WriteReal[w, "CameraFieldOfView", context.fieldOfView];
WriteTriple[w, "CameraEyePoint", context.eyePoint];
WriteTriple[w, "CameraLookAt", context.lookAt];
WriteTriple[w, "CameraUp", context.upDirection];
WriteReal[w, "CameraRoll", context.rollAngle];
UnNest[w];
};
WriteCameraParameters: PUBLIC PROC [context: Context] ~ {
i: WriteInfo ← GetWriteInfo[];
IF NOT i.ok THEN RETURN;
WriteCamera[context, i.writer];
WriteNode[i.writer, NIL];
UnNest[i.writer];
PutWriter[i];
};
WriteParameters: PUBLIC PROC [context: Context, fileName: ROPENIL] ~ {
i: WriteInfo ← IF fileName = NIL THEN GetWriteInfo[] ELSE [TiogaAccess.Create[], fileName];
WriteParametersToWriter[context, i];
};
WriteParametersToStream: PUBLIC PROC [context: Context, out: STREAM] ~ {
WriteParametersToWriter[context, [writer: TiogaAccess.Create[], stream: out]];
};
WriteParametersToWriter: PUBLIC PROC [c: Context, i: WriteInfo] ~ {
w: Writer ← i.writer;
IF NOT i.ok OR c = NIL THEN RETURN;
WriteNode[w, "3d Context Parameters", "bz"];
Nest[w];
WriteCamera[c, w];
WriteTitle[w, "Image Parameters"];
WriteNode[w, Rope.Cat["DisplayMode: ",
G3dRender.RopeFromDisplayMode[G3dRender.GetDisplayMode[c]]]];
IF c.window # NIL
THEN WriteFour[w, "DisplayRegion", c.window.x, c.window.y, c.window.w, c.window.h];
IF c.preferredViewPort # [0.0, 0.0, 65536.0, 65536.0]
THEN WriteFour[w, "Viewport: ",
c.preferredViewPort.x, c.preferredViewPort.y,
c.preferredViewPort.w, c.preferredViewPort.h];
WriteRGB[w, "Background", G3dRender.GetBackgroundColor[c]];
IF G3dRender.GetBackgroundImage[c] # NIL
THEN WriteNode[w, Rope.Cat["BackgroundImage", G3dRender.GetBackgroundImage[c]]];
WriteBool[w, "AntiAliasing", c.antiAliasing];
UnNest[w];
WriteTitle[w, "Lights"];
FOR n: NAT IN [0..c.shapes.length) DO
IF G3dRender.ShadingClassFromShape[c.shapes[n]].type = $Light
THEN WriteLight[w, c.shapes[n]];
ENDLOOP;
WriteTitle[w, "Shapes"];
FOR n: NAT IN [0..c.shapes.length) DO
IF G3dRender.ShadingClassFromShape[c.shapes[n]].type # $Light
THEN WriteShape[w, c.shapes[n]];
ENDLOOP;
WriteRGB[w, "LightAmbience", G3dRender.GetAmbientLight[c]];
UnNest[w];
WriteNode[w, NIL];
UnNest[w];
UnNest[w];
PutWriter[i];
};
Read Scene Descriptions from a Viewer or a File
ReadInfo: TYPE ~ RECORD [operations: ROPE, v: Viewer, sel: SelPos, fileName: ROPENIL];
GetReaderInfo: PROC RETURNS [i: ReadInfo] ~ {
i.operations ← ViewerTools.GetSelectionContents[];
IF Rope.Length[i.operations] = 0 THEN RETURN[[NIL, NIL, NIL]];
IF Rope.Length[i.operations] < 100
THEN {
i.fileName ← FileNames.ResolveRelativePath[i.operations];
i.fileName FS.FileInfo[i.fileName
! FS.Error => {i.fileName NIL; CONTINUE}].fullFName;
IF i.fileName # NIL THEN i.operations ← RopeFile.Create[i.fileName];
}
ELSE i.sel ← ViewerTools.GetSelection[i.v ← ViewerTools.GetSelectedViewer[]];
};
MakeFrameFromFile: PUBLIC PROC [context: Context, fileName: ROPE] ~ {
GetPut: PROC [a: ATOM] ~ {
temp.props ← Atom.PutPropOnList[temp.props, a, Atom.GetPropFromList[context.props, a]];
};
temp: Context ← G3dRender.Create[];
temp.pixels ← context.pixels;
temp.viewer ← context.viewer;
temp.terminal ← context.terminal;
temp.class ← context.class;
temp.antiAliasing ← context.antiAliasing;
GetPut[$WDir];
GetPut[$Log];
[] ← ReadParameters[temp, fileName];
temp.class.render[temp];
temp ← NIL;
};
ReadParameters: PUBLIC PROC [context: Context, fileName: ROPE NIL, cmdOut: STREAMNIL]
RETURNS [shouldRepaint: BOOL] ~ {
i: ReadInfo ← IF fileName = NIL
THEN GetReaderInfo[]
ELSE [RopeFile.Create[fileName], NIL, NIL, fileName];
RETURN[Parse[context, i.operations, cmdOut,, TRUE, i.fileName, [i.v, i.sel]
! ParseError => CONTINUE]];
};
Blink: PROC [r: ROPE] ~ {
MessageWindow.Append[Rope.Concat["\t\t", r], TRUE];
MessageWindow.Blink[];
};
Parsing a Scene Description
ParseError: PUBLIC ERROR [position: NAT, fileName: ROPE, viewer: Viewer] = CODE;
Parse: PUBLIC PROC [
context: Context,
operation: ROPE,
cmdOut: STREAMNIL,
log: LogProc ← NIL,
showErrors: BOOLTRUE,
fileName: ROPENIL,
viewerSelection: ViewerSelection ← [NIL, NIL]]
RETURNS [shouldRepaint: BOOLFALSE]
~ {
s: Shape ← NIL;  -- the current shape
c: Context ← context;
in: STREAMIO.RIS[operation];
cmdHandle: Commander.Handle ← NIL;
directory: ROPE ← FileNames.CurrentWorkingDirectory[];
indent: NAT ← 0;
{
ENABLE {
IO.EndOfStream => CONTINUE;
IO.Error => {
position: INTIO.GetIndex[in];
IF viewerSelection.viewer # NIL AND viewerSelection.selection # NIL
THEN {
position ← position+viewerSelection.selection.start;
viewerSelection.selection^ ← [position, 10];
ViewerTools.SetSelection[viewerSelection.viewer, viewerSelection.selection];
Blink["Error during read"];
}
ELSE {
Blink[IO.PutFR["Error during read, file position = %g", IO.int[position]]];
IF fileName # NIL THEN {
v: Viewer ← ViewerOps.FindViewer[fileName];
IF v = NIL THEN {
v ← ViewerOps.CreateViewer[flavor: $Text, paint: FALSE, info: [iconic: TRUE, column: right, openHeight: 140]];
TiogaMenuOps.Load[v, fileName];
};
ViewerOps.OpenIcon[icon: v, bottom: FALSE, paint: FALSE];
TiogaAccess.SetPosition[TiogaAccess.FromViewer[v], position];
};
};
ParseError[position, fileName, viewerSelection.viewer];
};
};
GetRope:  PROC RETURNS [r: ROPE]  ~ {
BreakProc: IO.BreakProc ~ { -- as default IO.TokenProc except '/, '], '[ aren't separators
RETURN[SELECT char FROM
IN [Ascii.NUL..Ascii.SP], ',, ':, '; => sepr,
'[, '], '(, '), '{, '}, '", '+, '-, '*, '@, '← => break,
ENDCASE => other];
};
Test[];
r ← IO.GetTokenRope[in, BreakProc].token;
};
GetBool:  PROC RETURNS [b: BOOL] ~ {Test[]; b ← IO.GetBool[in]};
GetReal:  PROC RETURNS [r: REAL]  ~ {Test[]; r ← IO.GetReal[in]};
GetInt:  PROC RETURNS [i: INTEGER] ~ {Test[]; i ← IO.GetInt[in]};
GetPair:  PROC RETURNS [p: Pair]  ~ {p.x ← GetReal[]; p.y ← GetReal[]};
GetTriple: PROC RETURNS [t: Triple] ~ {t.x ← GetReal[]; t.y ← GetReal[]; t.z ← GetReal[]};
GetRGB:  PROC RETURNS [t: RGB]  ~ {t.R ← GetReal[]; t.G ← GetReal[]; t.B ← GetReal[]};
Test: PROC ~ {
DO
c: CHARIO.PeekChar[in];
IF c = ') OR c = '( OR c = ': OR c = ', OR c = Ascii.SP OR c = '\t
THEN [] ← IO.GetChar[in]
ELSE EXIT;
ENDLOOP;
};
DO
Eq: PROC [r1, r2: ROPE] RETURNS [BOOL] ~ {RETURN[Rope.Equal[r1, r2, FALSE]]};
OpEq: PROC [r: ROPE] RETURNS [BOOL] ~ {RETURN[Eq[op, r]]};
ShapeOk: PROC RETURNS [BOOL] ~ {
IF s # NIL THEN RETURN[TRUE];
Blink[Rope.Cat["No shape to perform: ", op]];
RETURN[FALSE];
};
Log: PROC [r: ROPE] ~ {
IF log = NIL THEN RETURN;
THROUGH [0..indent) DO r ← Rope.Concat["*", r]; ENDLOOP;
log[r];
};
UpdateCamera: PROC [function: ROPE] ~ {
shouldRepaint ← TRUE;
SELECT TRUE FROM
Eq[function, "fieldOfView"] =>
Log[IO.PutFR["Set camera roll: %g", IO.real[context.fieldOfView ← GetReal[]]]];
Eq[function, "roll"] =>
Log[IO.PutFR["Set camera roll: %g", IO.real[context.rollAngle ← GetReal[]]]];
ENDCASE => {
t: Triple ← GetTriple[];
Log[IO.PutFR["Set camera %g: (%g, %g, %g)",
IO.rope[function], IO.real[t.x], IO.real[t.y], IO.real[t.z]]];
SELECT TRUE FROM
Eq[function, "eyePoint"] => context.eyePoint ← t;
Eq[function, "lookAt"]  => context.lookAt ← t;
Eq[function, "up"]   => context.upDirection ← t;
ENDCASE;
};
};
SetRenderStyle: PROC ~ {
Set: PROC [r: RenderStyle] ~ {
Log[Rope.Cat["Set style of ", s.name, " to: ", word]];
G3dRender.SetRenderStyle[s, r];
};
word: ROPE ← GetRope[];
SELECT TRUE FROM
Eq[word, "faceted"]   => Set[faceted];
Eq[word, "smooth"]   => Set[smooth];
Eq[word, "lines"]   => Set[lines];
Eq[word, "shadedLines"] => Set[shadedLines];
Eq[word, "hiddenLines"] => Set[hiddenLines];
ENDCASE => Blink["No such render style"];
};
SetTextureMap: PROC [t: TextureStyle] ~ {
IF t = none
THEN [] ← G3dRender.SetTextureMap[c, s.name, NIL, none]
ELSE {
Log[Rope.Cat["Set texture map to: ", name ← GetRope[]]];
IF (err ← G3dRender.SetTextureMap[c, s.name, name, t]) # NIL THEN Blink[err];
};
};
err, name: ROPE;
op: ROPE ← GetRope[];
SELECT TRUE FROM
Miscellaneous Operations:
OpEq["ReadScene"] => {
localShouldRepaint: BOOL;
indent ← indent+1;
Log[Rope.Cat["Reading scene: ", name ← GetRope[]]];
localShouldRepaint Parse[c, name, cmdOut, log];
shouldRepaint ← shouldRepaint OR localShouldRepaint;
indent ← indent-1;
};
OpEq["Command"] => {
result: REF;
IF cmdHandle = NIL THEN {
cmdHandle ← NEW[Commander.CommandObject];
CommandTool.AddSearchRule[cmdHandle, directory];
CommandTool.AddSearchRule[cmdHandle, "///7.0/Commands/"];
CommandTool.AddSearchRule[cmdHandle, "///7.0/System/"];
cmdHandle.err ← cmdHandle.out ← cmdOut;
};
Log[IO.PutFR["Command: %g\n%l", IO.rope[name ← GetRope[]], IO.rope["i"]]];
Log[IO.PutFR["%l", IO.rope["I"]]];
result ← CommandTool.DoCommand[name, cmdHandle];
IF result # NIL THEN Log[IO.PutFR["(%g)", IO.refAny[result]]];
};
OpEq["AddProperty"] => {
Log[Rope.Cat["Adding property"]];
c.props ← Atom.PutPropOnList[c.props, IO.GetRefAny[in], IO.GetRefAny[in]];
};
Line-Drawing and Rendering:
OpEq["DisplayMode"] => {
r: ROPE ← GetRope[];
Log[Rope.Cat["Set display mode: ", r]];
G3dRender.LoadDisplayClass[c, SELECT TRUE FROM Eq[r, "fullColor"] => $FullColor, Eq[r, "dither"] => $PseudoColor, ENDCASE => $Gray];
};
OpEq["DisplayRegion"] => {
x: REAL ← GetReal[];
y: REAL ← GetReal[];
w: REAL ← GetReal[];
h: REAL ← GetReal[];
Log[IO.PutFR["DisplayRegion %g, %g, %g, %g",
IO.real[x], IO.real[y], IO.real[w], IO.real[h]]];
G3dRender.SetViewPort[c, [x, y, w, h]];
};
OpEq["Viewport"] => {
xy: Pair ← GetPair[];
wh: Pair ← GetPair[];
Log[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[c, [xy.x, xy.y, wh.x, wh.y]];
};
OpEq["BackgroundEnable"] => {
Log["EnableBackground set"];
G3dRender.EnableBackground[context, GetBool[]];
};
OpEq["Background"] => {
v: RGB ← GetRGB[];
Log[IO.PutFR["Background: (%g, %g, %g)", IO.real[v.R], IO.real[v.G], IO.real[v.B]]];
G3dRender.SetBackgroundColor[c, v];
};
OpEq["BackgroundImage"] => {
Log[Rope.Cat["Background image: ", name ← GetRope[]]];
G3dRender.SetBackgroundImage[c, name];
};
OpEq["AntiAliasing"] => {
Log["Anti aliasing set"];
G3dRender.SetAntiAliasing[c, GetBool[]];
};
Camera Operations:
OpEq["CameraFieldOfView"] =>
UpdateCamera["fieldOfView"];
OpEq["CameraEyePoint"] =>
UpdateCamera["eyePoint"];
OpEq["CameraLookAt"] =>
UpdateCamera["lookAt"];
OpEq["CameraUp"] =>
UpdateCamera["up"];
OpEq["CameraRoll"] =>
UpdateCamera["roll"];
Shape Operations:
OpEq["ShapeRead"] => {
Log[Rope.Cat["Read shape: ", name ← GetRope[]]];
IF Rope.Find[name, "/"] = -1 AND Rope.Find[name, ">"] = -1
THEN name ← Rope.Cat[FileNames.CurrentWorkingDirectory[], name];
G3dRender.AddShapeFromFile[c, FileNames.GetShortName[name], name
! G3dShape.Error => {Blink[reason]; name ← NIL; CONTINUE}];
IF name # NIL THEN s ← c.shapes[c.shapes.length-1]
};
OpEq["ShapeName"] => {
Log[Rope.Cat["Set shape: ", name ← GetRope[]]];
s ← G3dRender.FindShape[c, name];
};
OpEq["ShapeBackFaces"] =>
IF ShapeOk[] THEN {
Log[Rope.Cat["Set back faces: ", s.name]];
IF (s.showBackfaces ← GetBool[])
THEN G3dRender.SetVisible[s]
ELSE G3dRender.SetInvisible[s];
};
OpEq["ShapeRenderStyle"] =>
IF ShapeOk[] THEN SetRenderStyle[];
OpEq["ShapeColor"] => IF ShapeOk[] THEN {
color: RGB ← GetRGB[];
G3dRender.SetColor[s, color];
Log[IO.PutFR["Set color of %g to (%g, %g, %g)",
IO.rope[s.name], IO.real[color.R], IO.real[color.G], IO.real[color.B]]];
};
OpEq["ShapeShininess"] => IF ShapeOk[] THEN {
shininess: REAL ← GetReal[];
Log[IO.PutFR["Set shininess of %g to %g", IO.rope[s.name], IO.real[shininess]]];
G3dRender.SetShininess[s, shininess];
};
OpEq["ShapeTransmittance"] => IF ShapeOk[] THEN {
transmit: REAL ← GetReal[];
Log[IO.PutFR["Set transmittance of %g to %g", IO.rope[s.name], IO.real[transmit]]];
G3dRender.SetTransmittance[s, transmit];
};
OpEq["ShapeScale"] => IF ShapeOk[] THEN {
scale: REAL ← GetReal[];
Log[IO.PutFR["Set scale of %g to %g", IO.rope[s.name], IO.real[scale]]];
G3dShape.TransformShape[shape: s, scale: scale];
};
OpEq["ShapeTranslate"] => IF ShapeOk[] THEN {
trans: Triple ← GetTriple[];
Log[IO.PutFR["%g trans: (%g, %g, %g)",
IO.rope[s.name], IO.real[trans.x], IO.real[trans.y], IO.real[trans.z]]];
G3dShape.TransformShape[shape: s, translate: trans];
};
OpEq["ShapeRotate"] => IF ShapeOk[] THEN {
p0: Triple ← GetTriple[];
p1: Triple ← GetTriple[];
r: REAL ← GetReal[];
Log[IO.PutFR["%g rotate: %g", IO.rope[s.name], IO.real[r]]];
Log[Rope.Cat["Rotate ", s.name]];
G3dShape.TransformShape[shape: s, axis: [p0, G3dVector.Sub[p1, p0]], rotation: r];
};
OpEq["ShapeDelete"] => {
Log[Rope.Cat["Delete ", name ← GetRope[]]];
G3dRender.DeleteShape[c, name];
};
OpEq["ShapeTextureOffset"] => IF ShapeOk[] THEN {
i: Pair ← GetPair[];
Log[IO.PutFR["%g texture offset: (%g, %g)", IO.rope[s.name], IO.real[i.x], IO.real[i.y]]];
G3dRender.OffsetTextureCoords[s, i];
};
OpEq["ShapeTextureScale"] => IF ShapeOk[] THEN {
p: Pair ← GetPair[];
Log[IO.PutFR["%g texture scale: (%g, %g)",
IO.rope[s.name], IO.real[p.x], IO.real[p.y]]];
G3dRender.SetTextureScale[s, p];
};
OpEq["ShapeBumpScale"] => IF ShapeOk[] THEN {
scale: REAL ← GetReal[];
Log[IO.PutFR["%g bump scale: %g", IO.rope[s.name], IO.real[scale]]];
G3dRender.SetBumpScale[s, scale];
};
OpEq["ShapeTextureFiltering"] => {
Log[Rope.Cat["Set texture filtering for ", s.name]];
G3dRender.SetTextureFiltering[c, s, GetBool[]];
};
OpEq["ShapeNoMapping"] =>
SetTextureMap[none];
OpEq["ShapeIntensityMap"] =>
SetTextureMap[intensity];
OpEq["ShapeColorMap"] =>
SetTextureMap[color];
OpEq["ShapeBumpMap"] =>
SetTextureMap[bump];
OpEq["ShapeInvertNormals"] => IF ShapeOk[] THEN {
Log[Rope.Cat["Negate normals of ", s.name]];
G3dShape.NegateVertexNormals[s];
};
Polygon Operations:
OpEq["PolygonTriangulate"] => {
Log[Rope.Cat["Triangulate shape: ", s.name]];
G3dShape.Triangulate[s];
};
OpEq["PolygonReverse"] => IF ShapeOk[] THEN {
Log[Rope.Cat["Reverse polygons of ", s.name]];
G3dShape.ReversePolygons[s];
};
Light Operations:
OpEq["LightAdd"] => {
name: ROPE ← GetRope[];
pos: Triple ← GetTriple[];
rgb: RGB ← GetRGB[];
Log[Rope.Cat["Add light: ", name]];
G3dRender.AddLight[c, name, G3dVector.Normalize[pos], rgb];
};
OpEq["LightDelete"] => {
Log[Rope.Cat["Delete light: ", name ← GetRope[]]];
G3dRender.DeleteLight[c, name];
};
OpEq["LightAmbience"] => {
rgb: RGB ← GetRGB[];
Log[IO.PutFR["Ambient light: (%g, %g, %g)",
IO.real[rgb.R], IO.real[rgb.G], IO.real[rgb.B]]];
G3dRender.SetAmbientLight[c, rgb];
};
ENDCASE;
ENDLOOP;
};
};
END.