DIRECTORY Args, Commander, Controls, Controls3d, Convert, Draw2d, Draw3d, FileNames, FS, Imager, ImagerFont, ImagerInterpress, IO, Matrix3d, Polygons3d, Render3d, Rope, RuntimeError, ThreeDBasics, ThreeDIO, ThreeDMisc, ThreeDScenes, Tilers, Vector3d, ViewerOps; VizerImpl: CEDAR PROGRAM IMPORTS Args, Commander, Controls, Controls3d, Convert, Draw2d, Draw3d, FileNames, FS, Imager, ImagerFont, ImagerInterpress, IO, Polygons3d, Render3d, Rope, RuntimeError, ThreeDMisc, ThreeDScenes, Tilers, Vector3d, ViewerOps ~ BEGIN UserData: TYPE ~ RECORD [o: OuterData, p: ProgramData]; LightInfo: TYPE ~ RECORD [name: ROPE, position: Triple]; ROPE: TYPE ~ Rope.ROPE; Context: TYPE ~ Imager.Context; ClickProc: TYPE ~ Controls.ClickProc; OuterData: TYPE ~ Controls.OuterData; Triple: TYPE ~ Vector3d.Triple; TripleSequence: TYPE ~ Vector3d.TripleSequence; RenderStyle: TYPE ~ Render3d.RenderStyle; Option: TYPE ~ {viewer, backFaces, faceNormals, pointNormals, labels, pendant, autoRender, lines, jaggies, texture, bump}; Options: TYPE ~ ARRAY Option OF BOOL; ProgramData: TYPE ~ REF ProgramDataRep; ProgramDataRep: TYPE ~ RECORD [ file: ROPE _ NIL, cmdOut: IO.STREAM _ NIL, graphics, outer: Controls.Viewer _ NIL, outerData: OuterData _ NIL, cam: Controls3d.Camera _ NIL, lastMoused: Controls.Control _ NIL, vernier: Controls.Control _ NIL, newPairs: BOOL _ TRUE, options: Options _ [TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE], pairs: Vector3d.PairSequence _ NIL, faceCenters: TripleSequence _ NIL, faceNormals: TripleSequence _ NIL, view: Matrix3d.Matrix _ NIL, points: TripleSequence _ NIL, polygons: REF ThreeDIO.NatTable _ NIL, renderStyle: RenderStyle _ smooth, context3d: Render3d.Context3d _ NIL ]; Vizer: Commander.CommandProc ~ { errorMsg: ROPE; p: ProgramData _ NEW[ProgramDataRep]; p.cmdOut _ cmd.out; p.cam _ Controls3d.InitCamera[proc: CameraControl, data: p]; p.vernier _ Controls.NewControl["vernier", dial, p, 2.0, 0.0, 0.0, Vernier, FALSE]; p.context3d _ Render3d.InitContext3d[]; p.outer _ Controls.OuterViewer[ name: Rope.Concat["Vizer ", Args.GetRope[cmd]], buttons: LIST[ ["Viewer-On", Viewer, 2], ["BackFaces-On", BackFaces, 2], ["FaceNormals-Off", FaceNormals, 2], ["PointNormals-Off", PointNormals, 2], ["Labels-Off", Labels, 2], ["Pendant-Off", Pendant, 2], ["Render", Render, 1], ["Abort Render", AbortRender, 1], ["AutoRender-Off", AutoRender, 1], ["Smooth", CycleRenderStyle, 1], ["Lines-Off", Lines, 1], ["Jaggies-On", Jaggies, 1], ["Texture-Off", Texture, 1], ["Bump-Off", Texture, 1], ["New Shape", NewShape, 0], ["Add/Move Light", AddMoveLight, 0], ["Delete Light", DeleteLight, 0], ["List Lights", ListLights, 0], ["Shininess", Shininess, 0], ["IP Out", IPOut, 0], ["Render-IP-Out", RenderIPOut, 0]], controls: LIST[ p.cam.xGlobal, p.cam.yGlobal, p.cam.zGlobal, p.cam.scale, p.cam.hScreen, p.cam.vScreen, p.cam.fieldOfView, p.vernier], graphicsHeight: 400, graphicsShow: GraphicsShow, typeScriptHeight: 18, destroyProc: DestroyProc, data: p]; p.outerData _ NARROW[p.outer.data]; p.graphics _ p.outerData.graphics; IF Args.GetRope[cmd] # NIL THEN { p.file _ FS.ExpandName[Args.GetRope[cmd]].fullFName; IF (errorMsg _ ReadFile[p]) # NIL THEN RETURN[$Failure, errorMsg]; p.newPairs _ TRUE; ViewerOps.PaintViewer[p.graphics, client, FALSE]; }; }; TSWrite: PROC [p: ProgramData, r: ROPE] ~ {Controls.TypeScriptWrite[p.outerData, r]}; ReadFile: PROC [p: ProgramData] RETURNS [errorMsg: ROPE] ~ { Render3d.AddFileShape[p.context3d, "VizerShape", p.file ! FS.Error => {errorMsg _ error.explanation; CONTINUE}]; IF errorMsg = NIL THEN { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[p.context3d.shapes, "VizerShape"]; p.polygons _ Render3d.PolygonsFromShape[shape]; p.points _ Render3d.PointsFromShape[shape, p.points]; p.faceCenters _ Polygons3d.CentersOfPolygons[p.polygons, p.points, p.faceCenters ! RuntimeError.BoundsFault => CONTINUE]; p.faceNormals _ Polygons3d.PolygonNormals[p.polygons, p.points, p.faceNormals ! RuntimeError.BoundsFault => CONTINUE]; IF p.faceNormals # NIL THEN FOR n: NAT IN [0..p.faceNormals.length) DO p.faceNormals[n] _ Vector3d.Negate[Vector3d.Normalize[p.faceNormals[n]]]; ENDLOOP; IF p.faceNormals = NIL THEN TSWrite[p, "File too large, so no normals\n"]; Controls.SetSliderDialValue[p.cam.scale, ObjectScale[p]]; }; }; ObjectScale: PROC [p: ProgramData] RETURNS [REAL] ~ { biggest: REAL _ 0.0; IF p.points = NIL THEN RETURN[1.0]; FOR n: NAT IN [0..p.points.length) DO t: Triple ~ p.points[n]; biggest _ MAX[biggest, ABS[t.x], ABS[t.y]]; ENDLOOP; RETURN[IF biggest # 0.0 THEN 1.0/biggest ELSE 1.0]; }; NewShape: ClickProc ~ { outerData: OuterData ~ NARROW[clientData]; p: ProgramData ~ NARROW[outerData.data]; rope: ROPE _ Controls.TypeScriptReadFileName[outerData]; IF rope # NIL THEN { p.file _ FS.ExpandName[rope].fullFName; IF (rope _ ReadFile[p]) # NIL THEN Controls.TypeScriptWrite[outerData, rope] ELSE ViewerOps.PaintViewer[p.graphics, client, FALSE]; }; }; Texture: ClickProc ~ {SetMap[NARROW[NARROW[clientData, OuterData].data], $Texture]}; Bump: ClickProc ~ {SetMap[NARROW[NARROW[clientData, OuterData].data], $Bump]}; SetMap: PROC [p: ProgramData, atom: ATOM] ~ { IF p.options[bump] OR p.options[texture] THEN { p.options[bump] _ p.options[texture] _ FALSE; Render3d.TurnOffAntiAliasing[p.context3d]; Controls.ButtonReLabel[p.outerData, "Texture-On", "Texture-Off"]; Controls.ButtonReLabel[p.outerData, "Bump-On", "Bump-Off"]; } ELSE { message: ROPE _ NIL; b : ROPE ~ IF atom = $Bump THEN "Bump" ELSE "Texture"; textureType: Render3d.TextureType ~ IF atom = $Bump THEN bump ELSE intensity; shape: REF ThreeDBasics.ShapeInstance _ VizerShape[p]; IF shape = NIL THEN RETURN; IF ThreeDScenes.GetShading[shape, $TextureMap] = NIL THEN { name: ROPE _ Controls.TypeScriptReadFileName[p.outerData]; IF name = NIL THEN RETURN; name _ FileNames.ResolveRelativePath[name]; Render3d.SetTextureMap[p.context3d, "VizerShape", name, textureType ! ThreeDScenes.Error => {message _ reason.explanation; CONTINUE}]; }; IF message # NIL THEN { TSWrite[p, message]; RETURN; }; IF atom = $Bump THEN p.options[bump] _ TRUE ELSE p.options[texture] _ TRUE; Render3d.TurnOnAntiAliasing[p.context3d]; Controls.ButtonToggle[p.outerData, TRUE, Rope.Cat[b, "-On"], Rope.Cat[b, "-Off"]]; }; }; Jaggies: ClickProc ~ { u: UserData _ UserDataFromClientData[clientData]; Tog[clientData, jaggies, "Jaggies", FALSE]; IF u.p.options[jaggies] THEN Render3d.TurnOffAntiAliasing[u.p.context3d] ELSE Render3d.TurnOnAntiAliasing[u.p.context3d]; }; VizerShape: PROC [p: ProgramData] RETURNS [REF ThreeDBasics.ShapeInstance] ~ { RETURN[ThreeDScenes.FindShape[p.context3d.shapes, "VizerShape"]]; }; Vernier: Controls.ControlProc ~ { p: ProgramData ~ NARROW[control.data]; o: OuterData _ NARROW[p.outer.data]; IF p.lastMoused # NIL THEN Controls.Vernier[control, p.lastMoused]; p.newPairs _ TRUE; Controls3d.UpdateCamera[p.cam]; IF control.mouse.button = right THEN ViewerOps.PaintViewer[p.graphics, client, FALSE]; }; DestroyProc: Controls.DestroyProc ~ { p: ProgramData ~ NARROW[NARROW[outerData, OuterData].data]; Render3d.NullifyThreeDContext[p.context3d]; }; Tog: PROC [clientData: REF ANY, option: Option, name: ROPE, repaint: BOOL _ TRUE] ~ { outerData: OuterData ~ NARROW[clientData]; p: ProgramData ~ NARROW[outerData.data]; bool: BOOL ~ p.options[option] _ NOT p.options[option]; Controls.ButtonToggle[outerData, bool, Rope.Concat[name, "-On"], Rope.Concat[name, "-Off"]]; IF repaint THEN ViewerOps.PaintViewer[p.graphics, client, FALSE]; }; BackFaces: ClickProc ~ {Tog[clientData, backFaces, "BackFaces", mouseButton = blue]}; Labels: ClickProc ~ {Tog[clientData, labels, "Labels", mouseButton = blue]}; Pendant: ClickProc ~ {Tog[clientData, pendant, "Pendant", mouseButton = blue]}; FaceNormals: ClickProc ~ {Tog[clientData, faceNormals, "FaceNormals", mouseButton = blue]}; PointNormals: ClickProc ~ {Tog[clientData, pointNormals, "PointNormals", mouseButton=blue]}; AutoRender: ClickProc ~ {Tog[clientData, autoRender, "AutoRender", mouseButton = blue]}; Viewer: ClickProc ~ {Tog[clientData, viewer, "Viewer", mouseButton = blue]}; Lines: ClickProc ~ { p: ProgramData _ NARROW[NARROW[clientData, OuterData].data]; shape: REF ThreeDBasics.ShapeInstance _ VizerShape[p]; Tog[clientData, lines, "Lines", mouseButton = blue]; p.context3d.lineDrawing _ p.options[lines]; IF p.options[lines] THEN ThreeDScenes.PutShading[shape, $Type, $Lines] ELSE SELECT p.renderStyle FROM faceted => ThreeDScenes.PutShading[shape, $Type, $Faceted]; ENDCASE => ThreeDScenes.PutShading[shape, $Type, $Smooth]; }; UserDataFromClientData: PROC [clientData: REF ANY] RETURNS [u: UserData] ~ { u.o _ NARROW[clientData]; u.p _ NARROW[u.o.data]; }; GetLightInfo: PROC [p: ProgramData] RETURNS [lightInfo: LightInfo] ~ { reply: ROPE; TSWrite[p, " : "]; reply _ Controls.TypeScriptRead[p.outerData]; IF reply = NIL THEN TSWrite[p, " . . . aborted.\n"] ELSE { x, y, z: ROPE; n0, n1: INT _ 0; NextRope: PROC RETURNS [ROPE] ~ { IF (n0 _ Rope.SkipOver[reply, n1, " \t"]) = Rope.Length[reply] THEN RETURN[NIL]; n1 _ Rope.SkipTo[reply, n0, " \t"]; RETURN[Rope.Substr[reply, n0, n1-n0]]; }; IF (lightInfo.name _ NextRope[]) = NIL THEN GOTO BadFormat; IF (x _ NextRope[]) = NIL THEN GOTO BadFormat; IF (y _ NextRope[]) = NIL THEN GOTO BadFormat; IF (z _ NextRope[]) = NIL THEN GOTO BadFormat; lightInfo.position _ [ Convert.RealFromRope[x ! Convert.Error => GOTO BadFormat], Convert.RealFromRope[y ! Convert.Error => GOTO BadFormat], Convert.RealFromRope[z ! Convert.Error => GOTO BadFormat]]; }; EXITS BadFormat => { TSWrite[p, "Bad Format\n"]; RETURN[[NIL, [0.0, 0.0, 0.0]]]; }; }; AddMoveLight: ClickProc ~ { p: ProgramData _ NARROW[NARROW[clientData, OuterData].data]; lightInfo: LightInfo ~ GetLightInfo[p]; IF lightInfo.name # NIL THEN [] _ ThreeDScenes.SetLight[p.context3d, lightInfo.name, lightInfo.position]; }; DeleteLight: ClickProc ~ { name: ROPE; u: UserData _ UserDataFromClientData[clientData]; TSWrite[u.p, "Light name: "]; name _ Controls.TypeScriptRead[u.o]; IF name # NIL THEN ThreeDScenes.DeleteLight[u.p.context3d, name]; }; ListLights: ClickProc ~ { p: ProgramData _ NARROW[NARROW[clientData, OuterData].data]; IO.PutRope[p.cmdOut, "Lights: \n"]; FOR n: NAT IN [0..p.context3d.shapes.length) DO shape: REF ThreeDBasics.ShapeInstance _ p.context3d.shapes[n]; IF shape.type = $Light THEN IO.PutF[p.cmdOut, "%g located at [%g, %g, %g]\n", IO.rope[shape.name], IO.real[shape.location.x], IO.real[shape.location.y], IO.real[shape.location.z]]; ENDLOOP; }; GetShininessOfShape: PROC [shape: REF ThreeDBasics.ShapeInstance] RETURNS [REAL] ~ { refAny: REF ANY _ ThreeDScenes.GetShading[shape, $Shininess]; RETURN[IF refAny # NIL THEN NARROW[refAny, REF REAL]^ ELSE 0.0]; }; Shininess: ClickProc ~ { ok: BOOL _ TRUE; p: ProgramData _ NARROW[NARROW[clientData, OuterData].data]; TSWrite[p, IO.PutFR["Shininess (now %g): ", IO.real[GetShininessOfShape[VizerShape[p]]]]]; ThreeDMisc.SetShininess[p.context3d, "VizerShape", Convert.RealFromRope[Controls.TypeScriptRead[p.outerData] ! Convert.Error => {ok _ TRUE; CONTINUE}]]; IF NOT ok THEN TSWrite[p, "Bad Format\n"]; }; CycleRenderStyle: ClickProc ~ { Roper: PROC [renderStyle: RenderStyle] RETURNS [ROPE] ~ { RETURN[SELECT renderStyle FROM smooth => "Smooth", shiny => "Shiny", faceted => "Faceted", ENDCASE => NIL]; }; u: UserData ~ UserDataFromClientData[clientData]; old: RenderStyle ~ u.p.renderStyle; u.p.renderStyle _ IF old = shiny THEN RenderStyle.FIRST ELSE SUCC[old]; Controls.ButtonReLabel[u.o, Roper[old], Roper[u.p.renderStyle]]; IF u.p.renderStyle = shiny THEN Tilers.PhongShadeAllPolygons[] ELSE Tilers.PhongShadeOnlyHighLightedPolygons[]; Render3d.SetRenderStyle[u.p.context3d, "VizerShape", u.p.renderStyle]; }; AbortRender: ClickProc ~ { p: ProgramData _ NARROW[NARROW[clientData, OuterData].data]; p.context3d.stopMe _ TRUE; }; Render: ClickProc ~ { p: ProgramData _ NARROW[NARROW[clientData, OuterData].data]; Render3d.Render[p.context3d, "VizerShape", p.cam]; p.context3d.stopMe _ FALSE; }; RenderIPOut: ClickProc ~ { u: UserData _ UserDataFromClientData[clientData]; filename: ROPE ~ Controls.TypeScriptReadFileName[u.o]; IF filename # NIL THEN ThreeDMisc.MakeInterpressPage[u.p.context3d, filename]; }; CameraControl: Controls3d.CameraProc ~ { p: ProgramData _ NARROW[data]; p.lastMoused _ control; p.newPairs _ TRUE; IF control.mouse.button # right THEN RETURN; IF p.options[viewer] THEN ViewerOps.PaintViewer[p.graphics, client, FALSE]; IF p.options[autoRender] THEN Render3d.Render[p.context3d, "VizerShape", p.cam]; }; GraphicsShow: Controls.GraphicsShow ~ { p: ProgramData ~ NARROW[data]; o: Options ~ p.options; Action: PROC ~ { Controls3d.UpdateCamera[p.cam]; IF whatChanged = NIL THEN p.view _ Controls3d.InitContext[context, p.cam, p.view]; IF p.newPairs THEN p.pairs _ Draw3d.PolygonPairs[p.points, p.view, p.pairs]; p.newPairs _ FALSE; DrawAction[p, context, whatChanged]; }; IF p.points # NIL AND p.polygons # NIL THEN { IF p.polygons.length < 500 AND p.points.length < 1000 THEN Draw2d.DoWithBuffer[context, Action] ELSE Action[]; }; }; DrawAction: PROC [p: ProgramData, context: Context, whatChanged: REF ANY] ~ { o: Options ~ p.options; PolyProc: PROC [i: NAT] ~ { IF o[faceNormals] AND p.faceCenters # NIL AND p.faceNormals # NIL THEN Draw3d.Vector[context, p.faceCenters[i], p.faceNormals[i], p.view, , 0.03]; IF o[pointNormals] THEN { poly: REF ThreeDBasics.NatSequence ~ p.polygons[i]; shades: REF ThreeDBasics.ShadingSequence ~ p.context3d.shapes[1].shade; FOR n: NAT IN [0..poly.length) DO j: NAT ~ poly[n]; point: Triple ~ p.points[j]; shade: REF ThreeDBasics.ShadingValue ~ shades[j]; Draw3d.Vector[context, point, [shade.xn, shade.yn, shade.zn], p.view, , 0.03]; ENDLOOP; }; Draw3d.Polygon[context, p.polygons[i], p.pairs]; }; IF o[backFaces] THEN FOR n: NAT IN [0..p.polygons.length) DO PolyProc[n]; ENDLOOP ELSE Polygons3d.ApplyToFrontFacingPolygons[ PolyProc, p.polygons, p.pairs, p.view, p.faceNormals]; IF o[labels] THEN Draw3d.LabelPairs[context, p.pairs]; IF o[pendant] THEN Draw3d.Pendant[context, p.view, .07, .7, .7, ["x", "y", "z", , , ]]; }; IPOut: ClickProc ~ { outerData: OuterData ~ NARROW[clientData]; p: ProgramData ~ NARROW[outerData.data]; fileName: ROPE _ Controls.TypeScriptReadFileName[outerData]; IF fileName # NIL THEN { ref: ImagerInterpress.Ref _ ImagerInterpress.Create[fileName]; ContextProc: PROC [context: Context] ~ { metersPerPoint: REAL ~ .0254/72.0; Imager.ScaleT[context, metersPerPoint]; Imager.SetStrokeWidth[context, 1.0]; Imager.SetStrokeEnd[context, round]; Imager.SetFont[ context, ImagerFont.Scale[ImagerFont.Find["xerox/pressfonts/helvetica-mrr"], 12.0]]; Imager.TranslateT[context, [0.0, 0.5*11.0*72.0]]; DrawAction[p, context, NIL]; }; ImagerInterpress.DoPage[ref, ContextProc]; ImagerInterpress.Close[ref]; }; }; Commander.Register["///Commands/Vizer", Vizer, "\nUsage: Vizer [FileName]"]; END. €VizerImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, February 24, 1987 5:33:24 pm PST ΚQ˜šœ™Jšœ Οmœ1™<™-J˜—JšΟk œLžœ&žœ„˜…J˜—šΠbl œžœž˜JšžœLžœ(žœa˜ΰ—J˜šœž˜J˜Jšœžœžœ ˜;Jšœžœžœžœ˜;J˜Jšžœžœžœ˜Jšœ žœ˜#Jšœžœ˜(Jšœžœ˜(J˜Jšœ žœ˜#Jšœžœ˜1J˜Jšœžœ˜,J˜šœ žœB˜RJšœ4˜4—Jš œ žœžœžœžœ˜)J˜Jšœ žœžœ˜*šœžœžœ˜!Jšœ žœžœ˜Jšœžœžœžœ˜Jšœ'žœ˜+Jšœžœ˜ Jšœ žœ˜$Jšœ$žœ˜(Jšœ"žœ˜&Jšœ ž œžœ˜šœ˜Jš œ žœžœžœžœžœžœ˜1Jš œ žœžœžœžœžœ˜+—Jšœ&žœ˜*Jšœ#žœ˜'Jšœ#žœ˜'Jšœžœ˜#Jšœžœ˜#Jšœžœžœ˜,Jšœ'˜'Jšœ%ž˜(Jšœ˜—J˜šΟbœ˜ Jšœ žœ˜Jšœžœ˜%Icode˜J˜Jšœ<˜šžœ˜šžœžœ/˜6Jšžœ˜Jšžœ˜Jšžœ˜Jšžœ˜——Jšžœ˜—K˜K˜—š ‘œžœ žœžœžœ˜TJšœžœžœ.˜=Jšžœžœ žœžœžœ žœžœžœ˜@J˜J˜—š  œ˜Jšœžœžœ˜Jšœžœžœ˜˜>š‘ œžœ˜(Kšœžœ˜"Kšœ'˜'K˜$K˜$šœ˜JšœT˜T—J˜1Jšœžœ˜Jšœ˜—Jšœ*˜*Jšœ˜J˜—J˜J˜—JšœL˜LJ˜—šžœ˜J˜—J˜J˜J˜J˜—…—; Kρ