<> <> <> 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 <> 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; <> Item: TYPE ~ RECORD [name: ROPE, value: REAL]; WriteInfo: TYPE ~ RECORD [ writer: Writer _ NIL, fileName: ROPE _ NIL, stream: STREAM _ NIL, 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: ROPE _ NIL] ~ { 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: ROPE _ NIL] ~ { 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]; }; <> ReadInfo: TYPE ~ RECORD [operations: ROPE, v: Viewer, sel: SelPos, fileName: ROPE _ NIL]; 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: STREAM _ NIL] 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[]; }; <> ParseError: PUBLIC ERROR [position: NAT, fileName: ROPE, viewer: Viewer] = CODE; Parse: PUBLIC PROC [ context: Context, operation: ROPE, cmdOut: STREAM _ NIL, log: LogProc _ NIL, showErrors: BOOL _ TRUE, fileName: ROPE _ NIL, viewerSelection: ViewerSelection _ [NIL, NIL]] RETURNS [shouldRepaint: BOOL _ FALSE] ~ { s: Shape _ NIL; -- the current shape c: Context _ context; in: STREAM _ IO.RIS[operation]; cmdHandle: Commander.Handle _ NIL; directory: ROPE _ FileNames.CurrentWorkingDirectory[]; indent: NAT _ 0; { ENABLE { IO.EndOfStream => CONTINUE; IO.Error => { position: INT _ IO.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: 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; }; 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 <> 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]]; }; <> 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[]]; }; <> OpEq["CameraFieldOfView"] => UpdateCamera["fieldOfView"]; OpEq["CameraEyePoint"] => UpdateCamera["eyePoint"]; OpEq["CameraLookAt"] => UpdateCamera["lookAt"]; OpEq["CameraUp"] => UpdateCamera["up"]; OpEq["CameraRoll"] => UpdateCamera["roll"]; <> 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]; }; <> 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]; }; <> 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.