<<>> <> <> <> <> <> <> <<3d Tool: Creation and Miscellany>> DIRECTORY BasicTime, CedarProcess, Commander, CommanderOps, Controls, Cursors, FS, FileNames, G2dBasic, G3dBasic, G3dControl, G3dLight, G3dMatrix, G3dRender, G3dTimeTrees, G3dTool, G3dView, Icons, ImagerSample, IO, Process, ProcessProps, RawViewers, Real, Rope, TEditSelection, TiogaMenuOps, UnixSpawnTCP, ViewerClasses, ViewerOps, ViewerSpecs, ViewersWorldInstance; G3dToolViewerImpl: CEDAR PROGRAM IMPORTS BasicTime, CedarProcess, CommanderOps, Controls, Cursors, FileNames, FS, G3dControl, G3dLight, G3dMatrix, G3dRender, G3dTool, G3dView, Icons, ImagerSample, IO, Process, ProcessProps, RawViewers, Rope, TEditSelection, TiogaMenuOps, UnixSpawnTCP, ViewerOps, ViewerSpecs, ViewersWorldInstance EXPORTS G3dTool ~ BEGIN <> ForkableProc: TYPE ~ CedarProcess.ForkableProc; ButtonList: TYPE ~ Controls.ButtonList; ClickProc: TYPE ~ Controls.ClickProc; ControlList: TYPE ~ Controls.ControlList; ControlProc: TYPE ~ Controls.ControlProc; ControlSizes: TYPE ~ Controls.ControlSizes; DestroyProc: TYPE ~ Controls.DestroyProc; GraphicsData: TYPE ~ Controls.GraphicsData; MouseProc: TYPE ~ Controls.MouseProc; Viewer: TYPE ~ Controls.Viewer; Box2d: TYPE ~ G2dBasic.Box; Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; CameraControl: TYPE ~ G3dControl.CameraControl; Matrix: TYPE ~ G3dMatrix.Matrix; Viewport: TYPE ~ G3dMatrix.Viewport; Context3d: TYPE ~ G3dRender.Context3d; Client: TYPE ~ G3dTool.Client; NamedBuffer: TYPE ~ G3dTool.NamedBuffer; Operations: TYPE ~ G3dTool.Operations; ScreenSequence: TYPE ~ G3dTool.ScreenSequence; Tool: TYPE ~ G3dTool.Tool; ToolRep: TYPE ~ G3dTool.ToolRep; View: TYPE ~ G3dTool.View; ViewProc: TYPE ~ G3dTool.ViewProc; ViewRep: TYPE ~ G3dTool.ViewRep; ViewSequence: TYPE ~ G3dTool.ViewSequence; TTNode: TYPE ~ G3dTimeTrees.Node; Camera: TYPE ~ G3dView.Camera; CameraRep: TYPE ~ G3dView.CameraRep; SampleMap: TYPE ~ ImagerSample.SampleMap; ROPE: TYPE ~ Rope.ROPE; IconFlavor: TYPE ~ ViewerClasses.IconFlavor; <> defaultIcon: IconFlavor ¬ Icons.NewIconFromFile["G3dUser.icons", 0]; MakeTool: PUBLIC PROC [ name: ROPE, extraButtons: ButtonList ¬ NIL, extraControls: ControlList ¬ NIL, controlSizes: ControlSizes ¬ [], ops: Operations ¬ [], client: Client ¬ [], nViews: NAT ¬ 1, noOpen: BOOL ¬ FALSE, useArcBalls: BOOL ¬ TRUE, arcBallSize: INTEGER ¬ 136, graphicsHeight: INTEGER ¬ 475, icon: IconFlavor ¬ document, useExistingTool: BOOL ¬ FALSE, camera: CameraRep ¬ [[0.0, 2.0, 0.0], [], 1.0, 60.0], background: Triple ¬ [1.0, 1.0, 1.0], typescriptHeight: INT ¬ 36, toolSettings: ToolRep ¬ []] RETURNS [t: Tool] ~ { IF useExistingTool AND activeTool # NIL THEN { t ¬ NEW[ToolRep ¬ activeTool^]; t.outerData ¬ Controls.OuterViewer[name: name, column: left, buttons: extraButtons, controls: extraControls, controlSizes: controlSizes, destroyProc: OuterDestroy, icon: icon]; IF client # [] THEN { activeClients ¬ CONS[client, activeClients]; ViewerOps.AddProp[t.outerData.parent, $ToolClient, NEW[Client ¬ client]]; }; IF NOT noOpen THEN ViewerOps.OpenIcon[t.outerData.parent]; } ELSE { Enumerate: ViewerOps.EnumProc ~ {ViewerOps.PaintViewer[v, caption]}; NewButton: PROC [name: ROPE, proc: ClickProc, guarded: BOOL ¬ FALSE] ~ { t.buttons ¬ CONS[Controls.ClickButton[name, proc, t, 0,,,,,, guarded], t.buttons]; }; RawViewers.SetColorWorld[ViewersWorldInstance.GetWorld[], $dense]; ViewerOps.EnumerateViewers[Enumerate]; -- fix up caption and icon colors SetActiveTool[t ¬ NEW[ToolRep ¬ toolSettings]]; IF t.ipStrokeWidth = 2.0 THEN t.ipStrokeWidth ¬ 1.0; -- better default <<(actually, add another field: strokeWidth, for use with screen display)>> t.activeViews ¬ LIST[0]; t.ops ¬ ops; t.client ¬ client; IF t.cmd = NIL THEN t.cmd ¬ NARROW[ProcessProps.GetProp[$CommanderHandle], Commander.Handle]; IF NOT Rope.IsEmpty[name] THEN t.name ¬ name; t.camera ¬ G3dControl.InitCameraControl[ proc: G3dTool.Controller, clientData: t, fieldOfView: camera.fieldOfView, proxyMode: eye, scale: camera.scale, move: camera.move, rotate: camera.rotate]; G3dControl.SetArcBallSize[t.camera.arcBall, arcBallSize]; Context3dOk[t]; t.background ¬ background; t.buttons ¬ extraButtons; IF ops.io THEN NewButton["IO", G3dTool.IOOpsButton]; IF ops.lines THEN NewButton["Draw", G3dTool.DrawOpsButton]; IF ops.light THEN NewButton["Light", G3dTool.LightOpsButton]; IF ops.shape THEN NewButton["Shapes", G3dTool.ShapeOpsButton]; IF ops.render THEN NewButton["Render", G3dTool.RenderOpsButton]; <> <> <> <> <> <> IF ops.stop THEN NewButton["STOP", G3dTool.StopButton, TRUE]; t.controls ¬ G3dControl.AddCameraControl[extraControls, t.camera, useArcBalls]; IF nViews > 0 THEN { t.outerData ¬ Controls.OuterViewer[ name: name, column: left, buttons: t.buttons, controls: t.controls, controlSizes: controlSizes, typescriptHeight: typescriptHeight, graphicsHeight: graphicsHeight, mouseProc: G3dTool.Mouse, destroyProc: Destroy, drawProc: DoDraw, noOpen: TRUE, icon: IF icon # document THEN icon ELSE defaultIcon, clientData: t]; t.outer ¬ t.outerData.parent; t.outer.label ¬ name; t.typescript ¬ t.outerData.typescript; t.graphics ¬ t.outerData.graphics; t.views ¬ MakeViews[t, nViews]; IF NOT noOpen THEN [] ¬ CedarProcess.Fork[OpenViewer, t]; <> <> }; }; t.directory ¬ FileNames.CurrentWorkingDirectory[]; }; DoDraw: Controls.DrawProc ~ { t: Tool ¬ NARROW[clientData]; v: G3dTool.View ¬ G3dTool.GetView[viewer, t]; G3dTool.Draw[context, viewer, whatChanged, v.camera.matrix, v.viewport, v, t, t]; }; OpenViewer: ForkableProc ~ { Process.PauseMsec[250]; -- should be plenty ViewerOps.OpenIcon[NARROW[data, Tool].outer]; }; OuterDestroy: Controls.DestroyProc ~ { ref: REF ANY ¬ ViewerOps.FetchProp[viewer, $ToolClient]; IF ref # NIL THEN { client: Client ¬ NARROW[ref, REF Client]^; IF activeClients.first = client THEN activeClients ¬ activeClients.rest ELSE FOR c: LIST OF Client ¬ activeClients, c.rest WHILE c.rest # NIL DO IF c.rest.first = client THEN {c.rest ¬ c.rest.rest; EXIT}; ENDLOOP; }; }; Destroy: Controls.DestroyProc ~ { t: Tool ¬ NARROW[clientData]; IF t = NIL THEN RETURN; IF t.unixSpawn # NIL THEN UnixSpawnTCP.Kill[t.unixSpawn]; IF t.client.destroy # NIL THEN t.client.destroy[viewer, $ToolKilled, t.client.data]; IF t = activeTool THEN { FOR c: LIST OF Client ¬ activeClients, c.rest WHILE c # NIL DO IF c.first.destroy # NIL THEN c.first.destroy[viewer, $ToolKilled, c.first.data]; IF c.first.change # NIL THEN c.first.change[activeTool, NIL, c.first.data]; ENDLOOP; activeTool ¬ NIL; }; IF t.views # NIL THEN FOR i: INTEGER IN [0..t.views.length) DO FOR l: LIST OF G3dTool.NamedBuffer ¬ t.views[i].idBuffer, l.rest WHILE l # NIL DO ImagerSample.ReleaseScratchMap[l.first.map]; ENDLOOP; ENDLOOP; }; Context3dOk: PUBLIC PROC [tool: Tool] ~ { IF tool.context3d = NIL THEN { tool.context3d ¬ G3dRender.Create[]; tool.lights ¬ G3dLight.AddLight[tool.lights, "Light1", [-.2, .2, .3], [.2, -.2, -.3]]; G3dTool.SetRenderView[tool.context3d, tool.camera]; }; }; activeTool, previousTool: Tool; activeClients: LIST OF Client ¬ NIL; SetActiveTool: PUBLIC PROC [tool: Tool] ~ { IF tool = activeTool THEN RETURN; previousTool ¬ activeTool; activeTool ¬ tool; FOR c: LIST OF Client ¬ activeClients, c.rest WHILE c # NIL DO IF c.first.change # NIL THEN c.first.change[previousTool, activeTool, c.first.data]; ENDLOOP; }; GetActiveTool: PUBLIC PROC RETURNS [Tool] ~ {RETURN[activeTool]}; GetActiveClients: PUBLIC PROC RETURNS [LIST OF Client] ~ {RETURN[activeClients]}; ToolBusy: PUBLIC PROC [tool: Tool] RETURNS [BOOL] ~ { RETURN[tool.process # NIL AND CedarProcess.GetStatus[tool.process] = busy]; }; ForceFork: PUBLIC PROC [tool: Tool, proc: ForkableProc] ~ { IF ToolBusy[tool] THEN Stop[tool, NIL, TRUE]; tool.process ¬ CedarProcess.Fork[proc, tool, [background, TRUE]] }; MaybeFork: PUBLIC PROC [tool: Tool, proc: ForkableProc, data: REF ANY ¬ NIL] RETURNS [forked: BOOL] ~ { IF (forked ¬ NOT ToolBusy[tool]) THEN tool.process ¬ CedarProcess.Fork[proc, IF data = NIL THEN tool ELSE data, [background, TRUE]] ELSE TSWrite[tool, "Tool is busy!\n"]; }; Stop: PUBLIC PROC [tool: Tool, reason: ROPE ¬ NIL, waitTilAborted: BOOL ¬ FALSE] ~ { IF tool.unixSpawn # NIL THEN { UnixSpawnTCP.Kill[tool.unixSpawn]; tool.unixSpawn ¬ NIL; }; IF tool.process # NIL AND NOT tool.process.abortRequested THEN { CedarProcess.Abort[tool.process]; IF waitTilAborted THEN [] ¬ CedarProcess.Join[tool.process]; IF tool.client.stop # NIL THEN tool.client.stop[tool.client.data, reason]; }; IF reason # NIL THEN TSWrite[tool, reason]; }; <> MakeViews: PUBLIC PROC [tool: Tool, nViews: NAT] RETURNS [views: ViewSequence] ~ { g: Viewer ¬ tool.graphics; w: NAT ¬ SELECT g.column FROM left => ViewerSpecs.openLeftWidth, right => ViewerSpecs.openRightWidth, ENDCASE => ViewerSpecs.colorScreenWidth; views ¬ NEW[G3dTool.ViewSequenceRep[nViews]]; ViewerOps.AddProp[g, $Width, NEW[INTEGER ¬ w]]; -- redundant over ControlsOuter ViewerOps.AddProp[g, $Height, NEW[INTEGER ¬ g.ch]]; FOR n: NAT IN [0..nViews) DO MakeViewer: PROC [x, y, w, h: NAT] RETURNS [vwr: Viewer] ~ { data: GraphicsData ¬ NEW[Controls.GraphicsDataRep ¬ NARROW[g.data, GraphicsData]^]; vwr ¬ data.viewer ¬ ViewerOps.CreateViewer[flavor: $Graphics, paint: FALSE, info: [wx: x, wy: y, ww: w, wh: h, data: data, scrollable: FALSE, border: nViews > 1, parent: g]]; ViewerOps.AddProp[vwr, $View, v]; -- property not there on initial opening!? ViewerOps.AddProp[vwr, $CreatedInOuterViewer, $True]; -- avoid Controls.AdjustProc }; v: View ¬ views[n] ¬ NEW[ViewRep]; v.screens ¬ NEW[G3dTool.ShapeScreensRep[10]]; v.tool ¬ tool; v.index ¬ n; IF nViews = 1 THEN v.viewer ¬ MakeViewer[0, 0, w, g.ch] ELSE { miniW: NAT ¬ w/MIN[nViews, 3]; v.viewer ¬ MakeViewer[n*miniW, 0, miniW, g.wh] }; G3dControl.SaveState[tool.camera, v.camera ¬ NEW[CameraRep]]; ENDLOOP; }; DoWithViews: PUBLIC PROC [tool: Tool, action: ViewProc, activeOnly: BOOL ¬ TRUE] ~ { IF tool = NIL THEN RETURN; IF activeOnly THEN FOR l: LIST OF NAT ¬ tool.activeViews, l.rest WHILE l # NIL DO IF NOT action[tool.views[l.first]] THEN EXIT; ENDLOOP ELSE FOR i: NAT IN [0..tool.views.length) DO IF NOT action[tool.views[i]] THEN EXIT; ENDLOOP; }; GetFirstActiveView: PUBLIC PROC [tool: Tool] RETURNS [v: View] ~ { IF tool # NIL AND tool.views # NIL AND tool.activeViews # NIL THEN v ¬ tool.views[tool.activeViews.first]; }; GetView: PUBLIC PROC [viewer: Viewer, tool: Tool ¬ NIL] RETURNS [v: View] ~ { IF viewer # NIL THEN { ref: REF ¬ ViewerOps.FetchProp[viewer, $View]; IF ref # NIL THEN v ¬ NARROW[ref]; }; IF v = NIL AND tool # NIL THEN v ¬ tool.views[tool.activeViews.first]; IF viewer = NIL AND v # NIL THEN viewer ¬ v.viewer; IF v # NIL THEN v.viewport ¬ G3dView.GetViewport[viewer]; }; GetViewTransform: PUBLIC PROC [ viewer: Viewer ¬ NIL, tool: Tool ¬ NIL, out: Matrix ¬ NIL] RETURNS [m: Matrix] ~ { v: View ¬ GetView[viewer, tool]; IF v # NIL THEN m ¬ G3dMatrix.CopyMatrix[v.camera.matrix, out]; }; GetBufferedSampleMap: PUBLIC PROC [view: View, id: ATOM ¬ $Frame] RETURNS [map: SampleMap] ~ { IF view # NIL THEN FOR l: LIST OF NamedBuffer ¬ view.idBuffer, l.rest WHILE l # NIL DO IF l.first.id = id THEN RETURN[l.first.map]; ENDLOOP; }; SetBufferedSampleMap: PUBLIC PROC [map: SampleMap, view: View, id: ATOM ¬ $Frame]~ { nb: NamedBuffer ¬ [id, map]; IF view = NIL THEN RETURN; FOR l: LIST OF NamedBuffer ¬ view.idBuffer, l.rest WHILE l # NIL DO IF l.first.id = id THEN {l.first ¬ nb; RETURN}; ENDLOOP; view.idBuffer ¬ CONS[nb, view.idBuffer]; }; InvalidateViewScreens: PUBLIC PROC [view: View] ~ { IF view # NIL AND view.screens # NIL THEN FOR i: INTEGER IN [0..view.screens.length) DO view.screens[i].screensValid ¬ FALSE; ENDLOOP; }; <> FinishButton: PUBLIC ClickProc ~ { t: Tool ¬ NARROW[clientData]; IF t.cmd = NIL THEN G3dTool.TSWrite[t, "No command handle!\n"] ELSE { prompt: ROPE ¬ "When done with a forked process, do: "; IF t.command # NIL THEN prompt ¬ Rope.Cat[prompt, "(presently ", t.command, ") "]; t.command ¬ Controls.TypescriptRead[t.typescript, prompt]; }; }; Finish: PUBLIC PROC [tool: Tool, reason: ROPE] ~ { IF tool.client.stop # NIL THEN tool.client.stop[tool.client.data, reason]; IF tool.command # NIL AND tool.cmd # NIL THEN [] ¬ CommanderOps.DoCommand[tool.command, tool.cmd]; }; HelpButton: PUBLIC ClickProc ~ {OpenHelp["A tool for line drawings or shaded images"]}; StopButton: PUBLIC ClickProc ~ {Stop[NARROW[clientData], " . . . aborted\n"]}; <> doc: ROPE ¬ "Graphics3dDoc.tioga"; docProp: REF ROPE ¬ NEW[ROPE ¬ "Yo!"]; OpenHelp: PUBLIC PROC [key: ROPE] ~ { name: ROPE ¬ doc; vHelp: Viewer; PropProc: ViewerOps.EnumProc ~ { WITH ViewerOps.FetchProp[v, $G3dHelp] SELECT FROM r: REF ROPE => IF r = docProp THEN {vHelp ¬ v; RETURN[FALSE]}; ENDCASE => RETURN[TRUE]; }; name ¬ FileNames.StripVersionNumber[FS.FileInfo[doc ! FS.Error => CONTINUE].fullFName]; vHelp ¬ ViewerOps.FindViewer[name]; IF vHelp = NIL THEN ViewerOps.EnumerateViewers[PropProc]; IF vHelp # NIL THEN {IF vHelp.column # right THEN ViewerOps.ChangeColumn[vHelp, right]} ELSE { vHelp ¬ ViewerOps.CreateViewer[ flavor: $Text, paint: FALSE, info: [iconic: TRUE, column: right, openHeight: 140]]; TiogaMenuOps.Load[viewer: vHelp, fileName: doc]; ViewerOps.AddProp[viewer: vHelp, prop: $G3dHelp, val: docProp]; }; ViewerOps.SetOpenHeight[viewer: vHelp, clientHeight: 140]; ViewerOps.OpenIcon[icon: vHelp, bottom: FALSE, paint: FALSE]; -- must do Open before Top ViewerOps.TopViewer[viewer: vHelp, paint: FALSE]; ViewerOps.ComputeColumn[right]; TEditSelection.FindRope[vHelp, key]; }; SetCursor: PUBLIC PROC [tool: Tool, waiting: BOOL] ~ { IF waiting THEN Cursors.SetCursor[tool.outer.class.cursor ¬ tool.graphics.class.cursor ¬ hourGlass] ELSE Cursors.SetCursor[tool.outer.class.cursor ¬ tool.graphics.class.cursor ¬ textPointer]; }; StartTimer: PUBLIC PROC [tool: Tool] ~ { tool.clock ¬ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]]; }; ElapsedTime: PUBLIC PROC [tool: Tool] RETURNS [seconds: REAL] ~ { RETURN[BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]]-tool.clock]; }; PrintElapsedTime: PUBLIC PROC [tool: Tool, elapsedTime: REAL ¬ 0.0, action: ROPE ¬ NIL] ~ { IF action = NIL THEN action ¬ "elapsed"; IF elapsedTime = 0.0 THEN elapsedTime ¬ ElapsedTime[tool]; TSWrite[tool, IO.PutFR["%g time: %6.3f seconds.", IO.rope[action], IO.real[elapsedTime]]] }; TSWrite: PUBLIC PROC [tool: Tool, message: ROPE] ~ { IF tool.outer # NIL THEN Controls.TypescriptWrite[tool.typescript, Rope.Concat[message, "\n"]] ELSE IO.PutRope[tool.cmd.out, message]; }; END.