DIRECTORY Controls, FileNames, G3dBasic, G3dControl, G3dIO, G3dMatrix, G3dRender, G3dShape, G3dTimeTrees, G3dTool, G3dVector, IO, MessageWindow, PFS, Rope; G3dToolShapeImpl: CEDAR PROGRAM IMPORTS Controls, FileNames, G3dControl, G3dIO, G3dMatrix, G3dRender, G3dShape, G3dTimeTrees, G3dTool, G3dVector, IO, MessageWindow, PFS, Rope EXPORTS G3dTool ~ BEGIN ClickProc: TYPE ~ Controls.ClickProc; Request: TYPE ~ Controls.Request; RealSequence: TYPE ~ G3dBasic.RealSequence; Triple: TYPE ~ G3dBasic.Triple; Context3d: TYPE ~ G3dRender.Context3d; RGB: TYPE ~ G3dRender.RGB; RenderStyle: TYPE ~ G3dRender.RenderStyle; Shape: TYPE ~ G3dShape.Shape; ShapeProc: TYPE ~ G3dShape.ShapeProc; ShapeSequence: TYPE ~ G3dShape.ShapeSequence; KeyHead: TYPE ~ G3dTimeTrees.KeyHead; TTNode: TYPE ~ G3dTimeTrees.Node; ShapePoint: TYPE ~ G3dTool.ShapePoint; Tool: TYPE ~ G3dTool.Tool; View: TYPE ~ G3dTool.View; ViewProc: TYPE ~ G3dTool.ViewProc; Traversal: TYPE ~ G3dTool.Traversal; ROPE: TYPE ~ Rope.ROPE; PromptProc: TYPE ~ PROC [shape: Shape] RETURNS [prompt: ROPE]; ReadFromShapeFile: PUBLIC PROC [tool: Tool, name: ROPE, autoScale: BOOL ¬ FALSE] RETURNS [err: ROPE ¬ NIL] ~ { s: Shape; G3dTool.StartTimer[tool]; s ¬ G3dShape.ShapeFromFile[name ! PFS.Error => {err ¬ error.explanation; GOTO Bad}; G3dIO.Error => {err ¬ reason; GOTO Bad}]; IF s = NIL THEN RETURN["Can't read shape"]; IF s.vertices = NIL OR s.vertices.length = 0 OR s.surfaces = NIL OR s.surfaces.length = 0 THEN RETURN["Bad shape"]; G3dTool.PrintElapsedTime[tool, 0.0, "ShapeFromFile"]; AddShape[tool, s]; IF autoScale AND tool.shapes.length = 1 AND tool.camera # NIL THEN { G3dControl.UpdateControl[tool.camera, tool.camera.scale, G3dShape.ObjectScale[s]]; G3dTool.Repaint[tool, $Camera]; }; EXITS Bad => RETURN; }; AddShape: PUBLIC PROC [tool: Tool, shape: Shape] ~ { DeleteShape[tool, shape.name]; -- try to prevent infinite accumulation! G3dRender.SetRenderStyle[shape, lines]; tool.shapes ¬ G3dShape.AddToShapeSequence[tool.shapes, shape]; IF shape.hierarchyData = NIL THEN { IF tool.timeTree = NIL THEN { tool.timeTree ¬ G3dTimeTrees.CreateTimeTree[]; G3dTimeTrees.InitializeGraphicsTimeTree[tool.timeTree]; tool.focusNode ¬ tool.timeTree.root; }; G3dTimeTrees.PushTimeTree[tool.timeTree]; shape.hierarchyData ¬ G3dTimeTrees.SetNodeObject[tool.timeTree, shape]; G3dTimeTrees.PopTimeTree[tool.timeTree]; }; PrepareForDrawing[tool]; }; PrepareForDrawing: PUBLIC PROC [tool: Tool] ~ { CheckView: ViewProc ~ { IF view.screens = NIL OR view.screens.maxLength < tool.shapes.length THEN { save: G3dTool.ShapeScreens ¬ view.screens; view.screens ¬ NEW[G3dTool.ShapeScreensRep[tool.shapes.length]]; FOR n: NAT IN [0..save.length) DO view.screens[n] ¬ save[n]; ENDLOOP; }; FOR n: NAT IN [0..view.screens.length ¬ tool.shapes.length) DO IF view.screens[n] = NIL THEN view.screens[n] ¬ NEW[G3dShape.ScreenSequenceRep[0]]; ENDLOOP; }; tool.nVerticesAndPolys ¬ G3dShape.NumberOfVertices[tool.shapes]+G3dShape.NumberOfPolygons[tool.shapes]; IF tool.nVerticesAndPolys = 0 THEN RETURN; FOR n: NAT IN [0..tool.shapes.length) DO s: Shape ¬ tool.shapes[n]; IF s.matrix = NIL THEN s.matrix ¬ G3dMatrix.Identity[]; IF s.edges = NIL THEN s.edges ¬ G3dShape.MakeEdges[s]; ENDLOOP; G3dTool.DoWithViews[tool, CheckView, FALSE]; }; GetShape: PUBLIC PROC [t: Tool, name: ROPE] RETURNS [s: Shape ¬ NIL] ~ { IF t.shapes # NIL THEN FOR n: NAT IN [0..t.shapes.length) DO IF Rope.Equal[t.shapes[n].name, name, FALSE] THEN RETURN[t.shapes[n]]; ENDLOOP; }; GetSelectedShape: PUBLIC PROC [t: Tool] RETURNS [s: Shape] ~ { s ¬ SELECT TRUE FROM t.focusNode # NIL AND t.focusNode.object # NIL => NARROW[t.focusNode.object], t.selectedShape # -1 AND t.shapes # NIL => t.shapes[t.selectedShape], ENDCASE => NIL; }; ShapeDo: PROC [shapes: ShapeSequence, title: ROPE, action: ShapeProc, prompt: PromptProc ¬ NIL] ~ { pops: LIST OF Controls.Request; IF shapes = NIL OR shapes.length = 0 THEN RETURN; IF shapes.length = 1 THEN {[] ¬ action[shapes[0]]; RETURN}; FOR n: NAT DECREASING IN [0..shapes.length) DO s: Shape ¬ shapes[n]; rope: ROPE ¬ IF prompt # NIL THEN Rope.Concat["now ", prompt[s]] ELSE NIL; pops ¬ CONS[[FileNames.GetShortName[s.name], rope], pops]; ENDLOOP; pops ¬ CONS[["All"], pops]; DoWithSelectedShapes[shapes, action, Controls.PopUpRequest[[title], pops]-2]; }; ChooseShape: PUBLIC PROC [t: Tool, header: ROPE ¬ NIL] RETURNS [choice: INT] ~ { popUps: LIST OF Controls.Request; IF t = NIL OR t.shapes = NIL OR t.shapes.length = 0 THEN RETURN[-2]; IF t.shapes.length = 1 THEN RETURN[0]; FOR n: NAT DECREASING IN [0..t.shapes.length) DO popUps ¬ CONS[[FileNames.GetShortName[t.shapes[n].name]], popUps]; ENDLOOP; popUps ¬ CONS[["All"], popUps]; choice ¬ MAX[-2, Controls.PopUpRequest[[header], popUps]-2]; }; DoWithSelectedShapes: PUBLIC PROC [shapes: ShapeSequence, proc: ShapeProc, choice: INT] ~ { SELECT choice FROM -2 => RETURN; -1 => FOR i: NAT IN [0..shapes.length) DO IF NOT proc[shapes[i]] THEN EXIT; ENDLOOP; ENDCASE => [] ¬ proc[shapes[choice]]; }; SelectNodeShapes: PUBLIC PROC [node: TTNode, traversal: Traversal ¬ selfAndChildren] ~ { Deselect: ShapeProc ~ {shape.selected ¬ FALSE}; Select: ShapeProc ~ {shape.selected ¬ TRUE}; DoWithShape[node.timeTree.root, Deselect, selfAndChildren]; DoWithShape[node, Select, traversal]; }; PropagateShapeMatrices: PUBLIC PROC [node: TTNode] ~ { PropagateNode: PROC [n: TTNode] ~ { IF n = NIL THEN RETURN; IF n.localTransform = NIL THEN n.localTransform ¬ G3dMatrix.Identity[]; n.globalTransform ¬ IF n.parent # NIL THEN G3dMatrix.Mul[n.localTransform, n.parent.globalTransform, n.globalTransform] ELSE G3dMatrix.CopyMatrix[n.localTransform, n.globalTransform]; IF n.object # NIL THEN { s: Shape ¬ NARROW[n.object]; s.matrix ¬ G3dMatrix.CopyMatrix[n.globalTransform, s.matrix]; }; IF n.children # NIL THEN FOR i: INT IN [0..n.children.length) DO PropagateNode[n.children[i]]; ENDLOOP; }; IF node.localTransform = NIL OR node.globalTransform = NIL THEN node ¬ node.timeTree.root; G3dTimeTrees.SetTransformDirty[node, TRUE]; PropagateNode[node]; }; DoWithShape: PUBLIC PROC [ node: TTNode, action: ShapeProc, traversal: G3dTool.Traversal ¬ selfAndChildren] ~ { Inner: PROC [node: TTNode] RETURNS [continue: BOOL ¬ TRUE] ~ { IF node.object # NIL AND NOT action[NARROW[node.object]] THEN RETURN[FALSE]; IF node.children # NIL THEN FOR n: NAT IN [0..node.children.length) DO IF NOT Inner[node.children[n]] THEN RETURN[FALSE]; ENDLOOP; }; SELECT traversal FROM selfOnly => IF node.object # NIL THEN [] ¬ action[NARROW[node.object]]; childrenOnly => IF node.children # NIL THEN FOR n: NAT IN [0..node.children.length) DO IF NOT Inner[node.children[n]] THEN EXIT; ENDLOOP; ENDCASE => [] ¬ Inner[node]; }; ScreenPick: PUBLIC PROC [tool: Tool, viewer: Controls.Viewer, screen: G3dBasic.IntegerPair] RETURNS [sp: ShapePoint ¬ []] ~ { dist, max: INTEGER ¬ 1000000; view: View ¬ G3dTool.GetView[viewer]; IF tool.shapes # NIL THEN FOR i: INTEGER IN [0..tool.shapes.length) DO screens: G3dShape.ScreenSequence ¬ view.screens[i]; index: INTEGER ¬ G3dControl.ScreenPick[screens, screen]; IF index # -1 THEN { p: G3dBasic.IntegerPair ¬ screens[index].intPos; d: G3dBasic.IntegerPair ¬ [screen.x-p.x, screen.y-p.y]; IF (dist ¬ d.x*d.x+d.y*d.y) < max THEN {max ¬ dist; sp ¬ [i, index]}; }; ENDLOOP; }; ShapeOpsButton: PUBLIC ClickProc ~ { t: Tool ¬ NARROW[clientData]; IF t = NIL THEN Blink["No shapes!"] ELSE { Doc: PROC [state: BOOL, true, false: ROPE] RETURNS [r: ROPE] ~ { r ¬ IO.PutFR1["now %g", IO.rope[IF state THEN true ELSE false]]; }; s: Shape ¬ IF t.shapes # NIL AND t.shapes.length = 1 THEN t.shapes[0] ELSE NIL; d: G3dRender.RenderData ¬ G3dRender.RenderDataFrom[s]; renderStyle: ROPE ¬ GetRenderStyleRope[s]; choice: INT ¬ Controls.PopUpRequest[["Shape Ops"], LIST[ -- 1 -- ["Toggle Back Face Visibility", IF s = NIL THEN NIL ELSE Doc[s.showBackfaces, "visible", "not visible"]], -- 2 -- ["Negate Vertex Normals", IF s = NIL THEN NIL ELSE Doc[s.normalsNegated, "negated", "positive"]], -- 3 -- ["Reverse Polygon Order", IF s = NIL THEN NIL ELSE Doc[s.surfacesReversed, "reversed", "normal"]], -- 4 -- ["Transform Vertices by Shape.matrix"], -- 5 -- ["Set Shape.matrix to Identity"], -- 6 -- ["Scale Shape"], -- 7 -- ["Set Faceted RenderStyle", renderStyle], -- 8 -- ["Set Smooth RenderStyle", renderStyle], -- 9 -- ["Set Lines RenderStyle", renderStyle], -- 10 -- ["Set ShadedLines RenderStyle", renderStyle], -- 11 -- ["Set HiddenLines RenderStyle", renderStyle], -- 12 -- ["Set Shininess", IF d = NIL THEN NIL ELSE IO.PutFR["now %g%g", IO.real[d.shininess], IO.rope[IF d.shininess = 0 THEN " (dull)" ELSE NIL]]], -- 13 -- ["Set Color", IF d = NIL THEN NIL ELSE IO.PutFR["now (%g, %g, %g)", IO.real[d.color.R], IO.real[d.color.G], IO.real[d.color.B]]], -- 14 -- ["Set Transmittance", IF d = NIL THEN NIL ELSE IO.PutFR1["now %g", IO.real[d.transmittance]]], -- 15 -- ["Toggle Visibility", IF s = NIL THEN NIL ELSE Doc[s.visible, "visible", "invisible"]], -- 16 -- ["Scale Normals"], -- 17 -- ["Delete Shape"], -- 18 -- ["Select Shape"], -- 19 -- ["Make Texture Coords From Normals"]]]; G3dTool.SetCursor[t, TRUE]; IF t.shapes = NIL OR t.shapes.length = 0 THEN Blink["No shapes!"] ELSE { SELECT choice FROM 1 => ToggleBackFaces[t]; 2 => ToggleNormals[t]; 3 => TogglePolygons[t]; 4 => TransformShape[t]; 5 => SetShapeMatrixToIdentity[t]; 6 => SetShapeScale[t]; 7 => SetRenderStyle[t, faceted]; 8 => SetRenderStyle[t, smooth]; 9 => SetRenderStyle[t, lines]; 10 => SetRenderStyle[t, shadedLines]; 11 => SetRenderStyle[t, hiddenLines]; 12 => SetShapeShininess[t]; 13 => SetShapeColor[t]; 14 => SetShapeTransmittance[t]; 15 => ToggleVisibility[t]; 16 => ScaleNormals[t]; 17 => RemoveShape[t]; 18 => SetSelectedShape[t]; 19 => MakeTextureCoords[t]; ENDCASE; G3dTool.SetCursor[t, FALSE]; IF Controls.GetPopUpButton[] = right AND choice < 19 THEN G3dTool.Repaint[t, $ShapeOps]; }; }; }; ToggleBackFaces: PROC [t: Tool] ~ { Action: ShapeProc ~ { IF shape.showBackfaces THEN G3dRender.HideBackfaces[shape] ELSE G3dRender.ShowBackfaces[shape]; }; Prompt: PromptProc ~ {prompt ¬ IF shape.showBackfaces THEN "visible" ELSE "not visible"}; ShapeDo[t.shapes, "BackFace Visibility", Action, Prompt]; }; NegateNormals: PUBLIC PROC [tool: Tool, shape: Shape] ~ { G3dShape.NegateVertexNormals[shape]; G3dShape.NegateFaceNormals[shape]; }; ToggleNormals: PROC [t: Tool] ~ { Action: ShapeProc ~ {NegateNormals[t, shape]}; Prompt: PromptProc ~ {prompt¬ IF shape.normalsNegated THEN "negated" ELSE "not negated"}; ShapeDo[t.shapes, "Negate Shape Normals", Action, Prompt]; }; TogglePolygons: PROC [t: Tool] ~ { Action: ShapeProc ~ {G3dShape.ReversePolygons[shape]}; P: PromptProc ~ {prompt ¬ IF shape.surfacesReversed THEN "reversed" ELSE "not reversed"}; ShapeDo[t.shapes, "Reverse Polygons", Action, P]; }; GetRenderStyleRope: PROC [s: Shape] RETURNS [r: ROPE ¬ NIL] ~ { d: G3dRender.RenderData ¬ G3dRender.RenderDataFrom[s]; IF d # NIL THEN r ¬ G3dRender.RopeFromRenderStyle[d.renderStyle]; }; SetRenderStyle: PROC [t: Tool, style: RenderStyle] ~ { Action: ShapeProc ~ {G3dRender.SetRenderStyle[shape, style]}; Prompt: PromptProc ~ {prompt ¬ GetRenderStyleRope[shape]}; title: ROPE ¬ Rope.Cat["Set ", G3dRender.RopeFromRenderStyle[style], " Render"]; ShapeDo[t.shapes, title, Action, Prompt]; }; MakeTextureCoords: PROC [t: Tool] ~ { Action: ShapeProc ~ {--G3dMappedAndSolidTexture.MakeTxtrCoordsFromNormals[shape]--}; ShapeDo[t.shapes, "Make texture coordinates", Action]; }; SetShapeShininess: PROC [t: Tool] ~ { Action: ShapeProc ~ {G3dRender.SetShininess[shape, shininess]}; shininess: REAL ¬ 20.0; choice: INT ¬ ChooseShape[t, "Set Shininess of Shape"]; IF choice = -2 THEN RETURN; IF choice # -1 THEN shininess ¬ G3dRender.RenderDataFrom[t.shapes[choice]].shininess; shininess ¬ Controls.TypescriptReadValue[t.typescript, "shininess (0 = dull)", shininess]; DoWithSelectedShapes[t.shapes, Action, choice]; }; SetShapeColor: PROC [t: Tool] ~ { Action: ShapeProc ~ {G3dRender.SetColor[shape, [r[0], r[1], r[2]]]}; r: RealSequence; rgb: RGB ¬ [0.5, 0.5, 0.5]; choice: INT ¬ ChooseShape[t, "Set Color of Shape"]; IF choice = -2 THEN RETURN; IF choice # -1 THEN rgb ¬ G3dRender.RenderDataFrom[t.shapes[choice]].color; r ¬ Controls.TypescriptReadValues[t.typescript,, LIST[["R", rgb.R], ["G", rgb.G], ["B", rgb.B]]]; IF r = NIL THEN {G3dTool.TSWrite[t, " . . . aborted."]; RETURN}; DoWithSelectedShapes[t.shapes, Action, choice]; }; ToggleVisibility: PROC [t: Tool] ~ { Action: ShapeProc ~ {shape.visible ¬ NOT shape.visible}; Prompt: PromptProc ~ {prompt ¬ IF shape.visible THEN "visible" ELSE "invisible"}; ShapeDo[t.shapes, "Toggle visibility", Action, Prompt]; }; ScaleNormals: PROC [t: Tool] ~ { choice: INT ¬ ChooseShape[t, "Set Normal Lengths of Shape"]; IF choice # -2 THEN { Action: ShapeProc ~ { FOR i: INT IN [0..shape.vertices.length) DO shape.vertices[i].normal ¬ G3dVector.SetVectorLength[shape.vertices[i].normal, len]; ENDLOOP; IF shape.faces # NIL THEN FOR i: INT IN [0..shape.faces.length) DO shape.faces[i].normal ¬ G3dVector.SetVectorLength[shape.faces[i].normal, len]; ENDLOOP; }; len: REAL ¬ Controls.TypescriptReadValue[t.typescript, "normal length (1.0 = unit) ", 1.0]; DoWithSelectedShapes[t.shapes, Action, choice]; }; }; SetShapeTransmittance: PROC [t: Tool] ~ { Action: ShapeProc ~ {G3dRender.SetTransmittance[shape, trans]}; trans: REAL ¬ 0.5; choice: INT ¬ ChooseShape[t, "Set Transmittance of Shape"]; IF choice = -2 THEN RETURN; IF choice # -1 THEN trans ¬ G3dRender.RenderDataFrom[t.shapes[choice]].transmittance; trans ¬ Controls.TypescriptReadValue[t.typescript, "transmittance", trans]; DoWithSelectedShapes[t.shapes, Action, choice]; }; TransformShape: PROC [t: Tool] ~ { Action: ShapeProc ~ { G3dShape.TransformVertices[shape, shape.matrix]; shape.matrix ¬ G3dMatrix.Identity[shape.matrix]; }; choice: INT ¬ ChooseShape[t, "Transform Shape Vertices by .matrix"]; IF choice # -2 THEN DoWithSelectedShapes[t.shapes, Action, choice]; }; SetShapeMatrixToIdentity: PROC [t: Tool] ~ { Action: ShapeProc ~ {shape.matrix ¬ G3dMatrix.Identity[shape.matrix]}; choice: INT ¬ ChooseShape[t, "Transform Shape Vertices by .matrix"]; IF choice # -2 THEN DoWithSelectedShapes[t.shapes, Action, choice]; }; SetShapeScale: PROC [t: Tool] ~ { choice: INT ¬ ChooseShape[t, "Set Scale of Shape"]; IF choice # -2 THEN { Action: ShapeProc ~ {G3dShape.TransformShape[shape: shape, scale: scale]}; scale: REAL ¬ Controls.GetReal[t.typescript, "scale", 1.0]; DoWithSelectedShapes[t.shapes, Action, choice]; }; }; SetSelectedShape: PROC [t: Tool] ~ { choice: INT ¬ ChooseShape[t, "Select Shape"]; IF choice = -2 THEN RETURN; FOR i: INTEGER IN [0..t.shapes.length) DO t.shapes[i].selected ¬ (i = choice OR choice = -1); ENDLOOP; }; RemoveShape: PROC [t: Tool] ~ { choice: INT ¬ ChooseShape[t, "Delete Shape(s)"]; IF choice = -1 AND t # NIL AND t.shapes # NIL THEN FOR i: NAT IN [0..t.shapes.length) DO DeleteShapeEntry[t, i]; ENDLOOP; IF choice >= 0 THEN DeleteShapeEntry[t, choice]; }; DeleteShape: PUBLIC PROC [tool: Tool, name: ROPE] ~ { IF tool.shapes # NIL THEN FOR n: NAT IN [0..tool.shapes.length) DO IF NOT Rope.Equal[tool.shapes[n].name, name, FALSE] THEN LOOP; DeleteShapeEntry[tool, n]; EXIT; ENDLOOP; }; DeleteShapeEntry: PUBLIC PROC [tool: Tool, shapeID: NAT] ~ { IF tool.shapes # NIL AND tool.shapes.length > 0 THEN { Delete: ViewProc ~ { FOR i: NAT IN [shapeID..view.screens.length-1) DO view.screens[i] ¬ view.screens[i+1]; ENDLOOP; view.screens.length ¬ view.screens.length-1; }; s: Shape ¬ tool.shapes[shapeID]; IF s.hierarchyData # NIL THEN G3dTimeTrees.ClearNodeObject[s.hierarchyData]; FOR i: NAT IN [shapeID..tool.shapes.length-1) DO tool.shapes[i] ¬ tool.shapes[i+1]; ENDLOOP; tool.shapes.length ¬ tool.shapes.length-1; G3dTool.DoWithViews[tool, Delete, FALSE]; }; }; ChangeShapeFromMenu: PUBLIC PROC [t: Tool, s: Shape] ~ { IF s # NIL AND s.hierarchyData # NIL THEN { node: TTNode ¬ NARROW[s.hierarchyData]; rlist: LIST OF Request ¬ NIL; choice: INT ¬ 0; FOR k: LIST OF KeyHead ¬ node.keyHeads, k.rest UNTIL k=NIL DO rlist ¬ CONS[[k.first.flavorInfo.name, " "], rlist]; ENDLOOP; choice ¬ Controls.PopUpRequest[["Change Shape"], rlist]; IF choice >= 0 THEN { keyHead: KeyHead ¬ NIL; index: INT ¬ 0; G3dTool.SetCursor[t, TRUE]; FOR k: LIST OF KeyHead ¬ node.keyHeads, k.rest UNTIL keyHead # NIL OR k=NIL DO IF index = choice THEN keyHead ¬ k.first; index ¬ index + 1; ENDLOOP; IF keyHead # NIL THEN ProcessKeyHead[t, keyHead, s]; G3dTool.SetCursor[t, FALSE]; }; }; }; ChangeTriple: PROC [t: Tool, name: ROPE, v: Triple] RETURNS [Triple] ~ { r: RealSequence; r ¬ Controls.TypescriptReadValues[t.typescript, name, LIST[["X", v.x], ["Y", v.y], ["Z", v.z]]]; RETURN[IF r = NIL THEN [v.x, v.y, v.z] ELSE [r[0], r[1], r[2]]]; }; ChangeReal: PROC [t: Tool, name: ROPE, val: REAL] RETURNS [REAL] ~ { RETURN[Controls.TypescriptReadValue[t.typescript, name, val]]; }; CleanAllShapes: PUBLIC PROC [t: Tool] ~ { IF t.shapes # NIL THEN FOR i: INT IN [0..t.shapes.length) DO CleanShape[t.shapes[i]]; ENDLOOP; }; LeftRight: TYPE ~ G3dTool.LeftRight; CleanShape: PUBLIC PROC [s: Shape] ~ { }; Sibling: PUBLIC PROC [node: TTNode, which: LeftRight] RETURNS [TTNode] ~ { nKids: NAT ¬ node.parent.children.length; IF nKids = 1 THEN RETURN[NIL]; FOR n: NAT IN [0..nKids) DO test: TTNode ¬ node.parent.children[(IF which = left THEN n+1 ELSE n-1) MOD nKids]; IF test = node THEN RETURN[node.parent.children[n]]; ENDLOOP; RETURN[node]; }; ParentObjectNode: PUBLIC PROC [node: TTNode] RETURNS [parent: TTNode] ~ { FOR parent ¬ node.parent, parent.parent WHILE parent # NIL DO IF parent.object # NIL THEN RETURN; ENDLOOP; }; LatchAllShapes: PUBLIC PROC [t: Tool] ~ { IF t.shapes # NIL THEN FOR i: INT IN [0..t.shapes.length) DO LatchShape[t.shapes[i]]; ENDLOOP; }; LatchShape: PUBLIC PROC [s: Shape] ~ { MapProc: PROC [atom: ATOM] ~ { }; }; ProcessKeyHead: PROC [t: Tool, keyHead: KeyHead, s: Shape] ~ { flavor: G3dTimeTrees.FlavorInfo ¬ keyHead.flavorInfo; SELECT flavor.type FROM real => { newReal: REAL ¬ ChangeReal[t, flavor.name, NARROW[keyHead.strobe, REF REAL]^]; keyHead.strobe ¬ NEW[REAL ¬ newReal]; }; triple => { newTriple: Triple ¬ ChangeTriple[t, flavor.name, NARROW[keyHead.strobe, REF Triple]^]; keyHead.strobe ¬ NEW[Triple ¬ newTriple]; }; matrix => RETURN; unknown => RETURN; ENDCASE; }; Blink: PROC [r: ROPE] ~ { MessageWindow.Append[Rope.Concat["\t\t", r], TRUE]; MessageWindow.Blink[]; }; END. .. Ϊ G3dToolShapeImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, July 22, 1992 3:22 pm PDT Glassner, July 18, 1990 4:58:46 pm PDT 3d Tool: Shape Operations Imported Types Shapes Return 0 if only one shape; return -2 if no user choice, -1 if all, shape index otherwise: Shape Ops Shape Modification s.changes ¬ NIL; IF s.changes # NIL THEN Atom.MapAtoms[MapProc]; Support ChangePatchesFromNormals: PROC [t: Tool] ~ { Action: ShapeProc ~ { shapeClass: REF ShapeClass ¬ G3dRender.ShapeClassFrom[shape]; G3dRender.LoadShapeClass[shape, IF shapeClass.type = $PolygonWithNormals THEN $ConvexPolygon ELSE $PolygonWithNormals]; }; Prompt: PromptProc ~ { shadingClass: REF ShadingClass ¬ G3dRender.ShadingClassFrom[shape]; prompt ¬ IF shadingClass.type = $ConvexPolygon THEN "now convex polygons, change to polygons with normals" ELSE "now polygons with normals, change to convex polygons"; }; ShapeDo[t.shapes, "Change surface type", Action, Prompt]; }; ΚB•NewlineDelimiter ™™Jšœ Οmœ1™J˜—š ΟnœŸœŸœŸœ ŸœŸœ˜PJšŸœŸœŸœ˜J˜J˜ J˜˜!JšŸœ$Ÿœ˜1JšœŸœ˜)—JšŸœŸœŸœŸœ˜+š ŸœŸœŸœŸœŸœŸœ˜YJšŸœŸœ˜—J˜5J˜š Ÿœ ŸœŸœŸœŸœ˜DJ˜RJ˜J˜—JšŸœŸœ˜J˜J˜—š‘œŸœŸœ˜4JšœΟc(˜GJ˜'J˜>šŸœŸœŸœ˜#šŸœŸœŸœ˜J˜.J˜7J˜$J˜—J˜)J˜GJ˜(J˜—J˜J˜J˜—š‘œŸœŸœ˜/š‘ œ˜šŸœŸœŸœ-Ÿœ˜KJ˜*JšœŸœ.˜@Jš ŸœŸœŸœŸœŸœ˜EJ˜—šŸœŸœŸœ/Ÿ˜>Jš ŸœΟsœŸœŸœŸœ ˜SJšŸœ˜—J˜—J˜gKšŸœŸœŸœ˜*šŸœŸœŸœŸ˜(J˜JšŸœ ŸœŸœ!˜7JšŸœ ŸœŸœ!˜6KšŸœ˜—Jšœ%Ÿœ˜,J˜J˜—š ‘œŸœŸœŸœŸœ Ÿœ˜Hš Ÿœ ŸœŸœŸœŸœŸœŸ˜šœŸœŸœŸ˜Jš œŸœŸœŸœŸœ˜MJšœŸœ Ÿœ˜EJšŸœŸœ˜—J˜J˜—š‘œ£Ÿ£œ£œ£œ£Ÿœ£œ£œ £œ£œ £œ£Ÿœ˜_J˜JšœŸœŸœ˜Jš Ÿœ ŸœŸœŸœŸœ˜1JšŸœŸœŸœ˜;š ŸœŸœŸ œŸœŸ˜.J˜Jš œŸœŸœ ŸœŸœ ŸœŸœ˜JJšœŸœ/˜:JšŸœ˜—JšœŸœ˜J˜MJ˜J˜—š‘ œŸœŸœŸœŸœŸœ Ÿœ˜PJ™ZJšœŸœŸœ˜!JšŸœŸœŸœ ŸœŸœŸœŸœ˜DJšŸœŸœŸœ˜&š ŸœŸœŸ œŸœŸ˜0Jšœ Ÿœ5˜BJšŸœ˜—Jšœ Ÿœ˜Jšœ Ÿœ0˜JšŸœŸœŸœŸœŸœŸœŸœŸœ˜LšŸœŸœŸ˜šŸœŸœŸœŸ˜*Jš ŸœŸœ€œŸœŸœŸœ˜2JšŸœ˜——J˜—šŸœ Ÿ˜Jš œ ŸœŸœŸœ Ÿœ˜GšœŸœŸœŸ˜+šŸœŸœŸœŸ˜*JšŸœŸœŸœŸœ˜)JšŸœ˜——JšŸœ˜—J˜J˜—š‘ œŸœŸœD˜[JšŸœ˜Jšœ˜Jšœ Ÿœ ˜J˜%šŸœŸœŸ˜šŸœŸœŸœŸ˜,J˜3JšœŸœ*˜8šŸœ Ÿœ˜J˜0J˜7JšŸœ Ÿœ˜EJ˜—JšŸœ˜——J˜——šž ™ š‘œŸœ˜$Jšœ Ÿœ ˜šŸœŸ˜ JšŸœ˜šŸœ˜š ‘œŸœ ŸœŸœŸœŸœ˜@Jš œ£œŸœŸœŸœŸœŸœ ˜@J˜—Jš œ Ÿœ ŸœŸœŸœ ŸœŸœ˜OJ˜6Jšœ Ÿœ˜*šœŸœ(Ÿœ˜8š ’œ!ŸœŸœŸœŸœŸ˜AJ˜2—š ’œŸœŸœŸœŸœŸ˜;J˜0—š ’œŸœŸœŸœŸœŸ˜;J˜1—Jš’œ(˜0Jš’œ"˜*Jš’œ˜Jš’œ*˜2Jš’œ)˜1Jš’œ(˜0Jš’œ.˜6Jš’œ.˜6š’œŸœŸœŸœŸœŸœŸœ˜HJš œŸœŸœŸœŸœ ŸœŸœ˜N—š’œŸœŸœŸœŸœŸœŸœ˜LJš œŸœœŸœœŸœ˜?—š ’œŸœŸœŸœŸœŸ˜7JšœŸœŸœ˜1—š ’œŸœŸœŸœŸœŸ˜7J˜*—Jš’œ˜Jš’œ˜Jš’œ˜Jš’œ(˜0—JšœŸœ˜šŸœ ŸœŸœ˜(JšŸœ˜šŸœ˜šŸœŸ˜J˜J˜J˜J˜J˜"J˜J˜!J˜ J˜J˜%J˜%J˜J˜J˜J˜J˜J˜J˜J˜JšŸœ˜—JšœŸœ˜šŸœ#Ÿœ ˜4JšŸœ˜#—J˜——J˜——J˜J˜—š‘œŸœ˜#š‘œ˜šŸœ˜JšŸœ Ÿœ ˜H—J˜—Jš‘œŸœŸœ Ÿœ˜YJ˜9J˜J˜—š‘ œŸœŸœ˜9J˜$J˜"J˜J˜—š‘ œŸœ˜!Jš‘œ(˜.Jš‘œ£œ £œ£œ£Ÿ£œ£Ÿ£œ £Ÿ£œ£œ ˜YJ˜:J˜J˜—š‘œŸœ˜"Jš‘œ0˜6Jš‘œ£œŸœ£Ÿ£œ £Ÿ£œ£œ ˜YJ˜1J˜J˜—š ‘œŸœ ŸœŸœŸœ˜?J˜6JšŸœŸœŸœ2˜AJ˜J˜—š‘œŸœ"˜6Jš‘œ7˜=Jš‘œ4˜:JšœŸœE˜PJ˜)J˜J˜—š‘œŸœ˜%Jš‘œ’=œ˜TJ˜6J˜J˜—š‘œŸœ˜%Jš‘œ9˜?Jšœ Ÿœ˜JšœŸœ,˜7JšŸœ ŸœŸœ˜JšŸœ ŸœB˜UJ˜ZJ˜/J˜J˜—š‘ œŸœ˜!Jš‘œ>˜DJ˜JšœŸœ˜JšœŸœ(˜3JšŸœ ŸœŸœ˜JšŸœ Ÿœ8˜KJšœ1Ÿœ,˜aJšŸœŸœŸœ)Ÿœ˜@J˜/J˜J˜—š‘œŸœ˜$Jš‘œŸœ˜8Jš‘œŸœŸœ Ÿœ˜QJ˜7J˜J˜—š‘ œŸœ˜ JšœŸœ1˜<šŸœ Ÿœ˜š‘œ˜šŸœŸœŸœŸ˜+J˜TJšŸœ˜—šŸœŸœŸ˜šŸœŸœŸœŸ˜(J˜NJšŸœ˜——J˜—JšœŸœR˜[J˜/J˜—J˜J˜—š‘œŸœ˜)Jš‘œ9˜?JšœŸœ˜JšœŸœ0˜;JšŸœ ŸœŸœ˜JšŸœ ŸœB˜UJ˜KJ˜/J˜J˜—š‘œŸœ˜"š‘œ˜Jšœ0˜0J˜0J˜—JšœŸœ9˜DJšŸœ Ÿœ0˜CJ˜J˜—š‘œŸœ˜,Jš‘œ@˜FJšœŸœ9˜DJšŸœ Ÿœ0˜CJ˜J˜—š‘ œŸœ˜!JšœŸœ(˜3šŸœ Ÿœ˜Jš‘œD˜JJšœŸœ0˜;J˜/J˜—J˜J˜—š‘œŸœ˜$JšœŸœ"˜-JšŸœ ŸœŸœ˜šŸœŸœŸœŸ˜)Jšœ#Ÿœ˜3JšŸœ˜—J˜J˜—š‘ œŸœ˜JšœŸœ%˜0š Ÿœ ŸœŸœŸœ ŸœŸ˜2Jš ŸœŸœŸœŸœŸœ˜F—JšŸœ Ÿœ˜0J˜J˜—š‘ œŸœŸœŸœ˜5šŸœŸœŸ˜šŸœŸœŸœŸ˜(Jš ŸœŸœ'ŸœŸœŸœ˜>Jšœ˜JšŸœ˜JšŸœ˜——J˜J˜—š‘œŸ œŸœ˜<šŸœŸœŸœŸœ˜6š‘œ˜šŸœŸœŸœ"Ÿ˜1J˜$JšŸœ˜—J˜,J˜—J˜ JšŸœŸœŸœ/˜LšŸœŸœŸœ!Ÿ˜0J˜"JšŸœ˜—J˜*Jšœ"Ÿœ˜)J˜—J˜——šž™š‘œŸœŸœ˜8š ŸœŸœŸœŸœŸœ˜+JšœŸœ˜'JšœŸœŸœ Ÿœ˜JšœŸœ˜š ŸœŸœŸœ!ŸœŸœŸ˜=JšœŸœ(˜4JšŸœ˜—J˜8šŸœ Ÿœ˜JšœŸœ˜JšœŸœ˜JšœŸœ˜šŸœŸœŸœ!Ÿœ ŸœŸœŸœŸ˜NJšŸœŸœ˜)J˜JšŸœ˜—JšŸœ ŸœŸœ˜4JšœŸœ˜J˜—J˜—J˜J˜—š‘ œŸœŸœ Ÿœ ˜HJ˜Jšœ6Ÿœ&˜`Jš ŸœŸœŸœŸœŸœ˜@J˜J˜—š ‘ œŸœŸœŸœŸœŸœ˜DJšŸœ8˜>J˜J˜—š‘œŸœŸœ˜)šŸœ ŸœŸ˜Jš ŸœŸœŸœŸœŸœ˜G—J˜J˜—šœ Ÿœ˜$J˜—š‘ œŸœŸœ˜&Jšœ Ÿœ™J˜J˜—š‘œŸœŸœ"Ÿœ ˜JJšœŸœ˜)JšŸœ ŸœŸœŸœ˜šŸœŸœŸœ Ÿ˜Jš œ%ŸœŸœŸœŸœ˜SJšŸœ ŸœŸœ˜4JšŸœ˜—JšŸœ˜ J˜J˜—š‘œŸœŸœŸœ˜IšŸœ%Ÿœ ŸœŸ˜=JšŸœŸœŸœŸœ˜#JšŸœ˜—J˜J˜—š‘œŸœŸœ˜)šŸœ ŸœŸ˜Jš ŸœŸœŸœŸœŸœ˜G—J˜J˜—š‘ œŸœŸœ˜&š‘œŸœŸœ˜J˜—JšŸœ ŸœŸœ™/J˜J˜—š‘œŸœ*˜>J˜5šŸœ Ÿ˜˜ Jš œ ŸœŸœŸœŸœ˜NJšœŸœŸœ ˜%J˜—˜ Jšœ1ŸœŸœ ˜WJšœŸœ˜)J˜—Jšœ Ÿœ˜Jšœ Ÿœ˜JšŸœ˜—J˜——šž™š‘œŸœŸœ˜Jšœ-Ÿœ˜3J˜J˜——J˜šŸœ˜J˜J˜š‘œŸœ™,š‘œ™Jšœ Ÿœ.™=šœ Ÿœ&™HJšŸœŸœ™.—J™—š‘œ™JšœŸœ2™Cšœ Ÿœ#™.JšŸœ7™;JšŸœ8™