G3dToolShapeImpl.mesa
Copyright © 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
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
Imported Types
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;
Shapes
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] ~ {
Return 0 if only one shape; return -2 if no user choice, -1 if all, shape index otherwise:
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;
};
Shape Ops
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];
};
};
Shape Modification
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] ~ {
s.changes ¬ NIL;
};
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] ~ {
};
IF s.changes # NIL THEN Atom.MapAtoms[MapProc];
};
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;
};
Support
Blink: PROC [r: ROPE] ~ {
MessageWindow.Append[Rope.Concat["\t\t", r], TRUE];
MessageWindow.Blink[];
};
END.
..
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];
};