<<>> <> <> <> <<3d Tool: User Interaction>> DIRECTORY Commander, Controls, G2dBasic, G2dVector, G3dBasic, G3dControl, G3dLight, G3dMatrix, G3dPlane, G3dShape, G3dTimeTrees, G3dTool, G3dVector, ImagerSample, Real, ViewerClasses, ViewerOps; G3dToolControlImpl: CEDAR PROGRAM IMPORTS G2dVector, G3dControl, G3dMatrix, G3dPlane, G3dShape, G3dTool, G3dVector, ViewerOps EXPORTS G3dTool ~ BEGIN <> ControlProc: TYPE ~ Controls.ControlProc; MouseProc: TYPE ~ Controls.MouseProc; Box2d: TYPE ~ G2dBasic.Box; IntegerPair: TYPE ~ G3dBasic.IntegerPair; Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; CameraControl: TYPE ~ G3dControl.CameraControl; Light: TYPE ~ G3dLight.Light; Matrix: TYPE ~ G3dMatrix.Matrix; Shape: TYPE ~ G3dShape.Shape; Client: TYPE ~ G3dTool.Client; ScreenSequence: TYPE ~ G3dTool.ScreenSequence; Tool: TYPE ~ G3dTool.Tool; View: TYPE ~ G3dTool.View; ViewProc: TYPE ~ G3dTool.ViewProc; TTNode: TYPE ~ G3dTimeTrees.Node; <> Mouse: PUBLIC MouseProc ~ { SaveState: PROC ~ { Save: ViewProc ~ {G3dControl.SaveState[t.camera, view.camera]}; G3dTool.DoWithViews[t, Save]; }; t: Tool ¬ NARROW[clientData]; v: View ¬ G3dTool.GetView[viewer, t]; whatChanged: REF ANY ¬ NIL; mousePos: Pair ¬ [mouse.pos.x, mouse.pos.y]; IF v = NIL THEN RETURN; G3dTool.SetActiveTool[t]; IF mouse.state # up THEN SELECT TRUE FROM mouse.pos.x IN [0..20] AND mouse.pos.y IN [0..20] => { -- button (non-graphical) <> IF t.camera.use = view THEN SaveState[]; IF mouse.controlKey THEN FOR l: LIST OF NAT ¬ t.activeViews, l.rest WHILE l # NIL DO IF l.first = v.index THEN EXIT; REPEAT FINISHED => t.activeViews ¬ CONS[v.index, t.activeViews]; ENDLOOP ELSE t.activeViews ¬ LIST[v.index]; SetControllerToView[t]; whatChanged ¬ $View; }; t.client.mouse # NIL OR -- clients supercede selection or querying (t = G3dTool.GetActiveTool[] AND G3dTool.GetActiveClients[] # NIL) => { IF t.client.mouse # NIL THEN t.client.mouse[mouse, viewer, t.client.data]; IF t = G3dTool.GetActiveTool[] THEN FOR c: LIST OF Client ¬ G3dTool.GetActiveClients[], c.rest WHILE c # NIL DO IF c.first.mouse # NIL THEN c.first.mouse[mouse, viewer, c.first.data]; ENDLOOP; }; mouse.controlKey AND mouse.shiftKey => { -- control+shift: move Sprite SELECT mouse.state FROM down => { <> <> <> <> n: G3dBasic.Quad ¬ G3dMatrix.TransformH[[0., 0., 1.], v.camera.matrix]; p: G3dPlane.Plane ¬ G3dPlane.FromPointAndNormal[t.sprite, [n.x, n.y, n.z], TRUE]; t.spritePlane ¬ [p.x, p.y, p.z, p.w]; }; held => t.sprite ¬ G3dMatrix.TripleFromScreenAndPlane[[mouse.pos.x, mouse.pos.y], t.spritePlane, v.camera.matrix]; ENDCASE; IF t.drawSprite THEN whatChanged ¬ $Sprite; }; mouse.shiftKey AND NOT mouse.controlKey => -- shift only: query vertex IF t.queryVertices AND v.screens # NIL THEN { sp: G3dTool.ShapePoint ¬ G3dTool.ScreenPick[t, viewer, mouse.pos]; IF sp # [] THEN {t.selectedShape ¬ sp.shape; t.selectedVertex ¬ sp.point}; whatChanged ¬ $Vertex; }; ENDCASE => { -- select light or shape IF t.camera.use = view THEN SaveState[]; { -- what is all this? hitLight: Light ¬ NIL; hitShape: Shape ¬ NIL; IF mouse.controlKey THEN { IF t.hitList # NIL AND (t.hitList.rest = NIL OR t.selectedShape < 0) THEN hitShape ¬ t.shapes[t.hitList.first] ELSE FOR s: LIST OF NAT ¬ t.hitList, s.rest WHILE s # NIL DO IF t.shapes[s.first] # t.shapes[t.selectedShape] THEN LOOP; hitShape ¬ t.shapes[IF s.rest # NIL THEN s.rest.first ELSE t.hitList.first]; EXIT; ENDLOOP; } ELSE { InBox: PROC [p: Pair, b: Box2d] RETURNS [BOOL] ~ { RETURN[p.x IN [b.min.x..b.max.x] AND p.y IN [b.min.y..b.max.y]]; }; min: REAL ¬ Real.LargestNumber; t.hitList ¬ NIL; t.selectedShape ¬ t.selectedLight ¬ -1; FOR n: NAT IN [0..v.screens.length) DO IF NOT v.screens[n].extentValid THEN G3dShape.SetExtent[v.screens[n]]; IF InBox[mousePos, v.screens[n].extent] THEN t.hitList ¬ CONS[n, t.hitList]; ENDLOOP; FOR s: LIST OF NAT ¬ t.hitList, s.rest WHILE s # NIL DO screens: ScreenSequence ¬ v.screens[s.first]; p: IntegerPair ¬ screens[G3dControl.ScreenPick[screens, mouse.pos]].intPos; d: IntegerPair ¬ [mouse.pos.x-p.x, mouse.pos.y-p.y]; sq: INTEGER ¬ d.x*d.x+d.y*d.y; IF sq < min THEN {min ¬ sq; hitShape ¬ t.shapes[s.first]}; ENDLOOP; IF t.lights # NIL THEN FOR i: INTEGER IN [0..t.lights.length) DO d: REAL ¬ G2dVector.SquareDistance[t.lights[i].screen, mousePos]; IF d < min THEN {min ¬ d; hitLight ¬ t.lights[i]}; ENDLOOP; }; IF hitShape # NIL THEN { whatChanged ¬ $SelectShape; IF mouse.button = right AND hitShape.hierarchyData # NIL THEN hitShape ¬ NARROW[G3dTool.ParentObjectNode[NARROW[hitShape.hierarchyData]].object]; FOR n: NAT IN [0..t.shapes.length) DO t.shapes[n].selected ¬ FALSE; ENDLOOP; SelectShape[t, hitShape, mouse.button]; -- set .selected of s and/or children }; IF hitLight # NIL THEN { whatChanged ¬ $SelectLight; SelectLight[t, hitLight]; }; }; }; IF mouse.state # up AND whatChanged # NIL THEN G3dTool.Repaint[t, whatChanged]; }; Controller: PUBLIC ControlProc ~ { t: Tool ¬ NARROW[clientData]; G3dTool.SetActiveTool[t]; IF t.camera.use # view AND control = t.camera.fieldOfView THEN SetControllerToView[t] -- probably want to control the view ELSE { s: Shape; l: Light; reset: BOOL ¬ control.mouse.state = up AND control.whatChanged = $ArcBallReset; IF control.mouse.state = down THEN { SaveController[t]; -- enable undo and shape transform accumulation IF control = t.camera.arcBall.rotate.control OR control = t.camera.arcBall.translate.control THEN RETURN; } ELSE IF reset THEN RestoreController[t]; -- undo SELECT TRUE FROM control.mouse.state = up AND NOT reset => { IF t.camera.use = shape THEN SetCameraToIdentity[t.camera]; IF t.camera.use = view THEN { <> IF t.autoRender THEN G3dTool.Render[t]; }; }; control.mouse.state # up OR reset OR control.whatChanged = $TypedIn => SELECT t.camera.use FROM view => G3dTool.Repaint[t, $Camera]; -- draw active view with new transform shape => IF (s ¬ G3dTool.GetSelectedShape[t]) # NIL THEN { -- control shape(s) n: TTNode ¬ IF s.hierarchyData#NIL THEN NARROW[s.hierarchyData] ELSE NIL; m: Matrix ¬ IF n # NIL THEN n.localTransform ELSE s.matrix; IF NOT reset THEN [] ¬ IF t.camera.arcBall.originBody THEN G3dMatrix.Mul[t.camera.matrix, t.camera.miscMatrix, m] ELSE G3dMatrix.Mul[t.camera.miscMatrix, t.camera.matrix, m]; IF n # NIL THEN G3dTool.PropagateShapeMatrices[n]; G3dTool.InvalidateVertexScreens[t, selectedOnly]; G3dTool.Repaint[t, $Pose]; }; light => IF (l ¬ G3dTool.GetSelectedLight[t]) # NIL THEN { IF NOT reset THEN { m: Matrix ¬ t.camera.matrix; l.direction ¬ G3dMatrix.TransformVec[t.camera.miscVector, m]; l.position ¬ G3dVector.Add[t.camera.miscPosition, [m[3][0],m[3][1],m[3][2]]]; }; G3dTool.Repaint[t, $Pose]; }; ENDCASE; ENDCASE; }; IF t.client.camera # NIL THEN t.client.camera[control, t.client.data]; }; SetControllerToView: PROC [t: Tool] ~ { Restore: ViewProc ~ {G3dControl.RestoreState[t.camera, view.camera]}; t.camera.use ¬ view; ClearArcBall[t.camera.arcBall]; G3dTool.DoWithViews[t, Restore]; }; RestoreController: PROC [t: Tool] ~ { ClearArcBall[t.camera.arcBall]; SELECT t.camera.use FROM view => G3dControl.RestoreState[t.camera, t.camera.save]; shape => { m: Matrix ¬ GetSelectedShapeTransform[t]; IF m # NIL THEN [] ¬ G3dMatrix.CopyMatrix[t.camera.miscMatrix, m]; SetCameraToIdentity[t.camera]; }; light => { l: Light ¬ G3dTool.GetSelectedLight[t]; IF l # NIL THEN l.direction ¬ t.camera.miscVector; IF l # NIL THEN l.position ¬ t.camera.miscPosition; SetCameraToIdentity[t.camera]; }; ENDCASE; }; SaveController: PROC [t: Tool] ~ { SELECT t.camera.use FROM view => G3dControl.SaveState[t.camera, t.camera.save]; shape => t.camera.miscMatrix ¬ G3dMatrix.CopyMatrix[GetSelectedShapeTransform[t], t.camera.miscMatrix]; light => { l: Light ¬ G3dTool.GetSelectedLight[t]; IF l # NIL THEN t.camera.miscVector ¬ l.direction; IF l # NIL THEN t.camera.miscPosition ¬ l.position; }; ENDCASE; }; GetSelectedShapeTransform: PROC [t: Tool] RETURNS [m: Matrix] ~ { s: Shape ¬ G3dTool.GetSelectedShape[t]; IF s # NIL THEN m ¬ IF s.hierarchyData # NIL THEN NARROW[s.hierarchyData, TTNode].localTransform ELSE s.matrix; }; SelectLight: PROC [t: Tool, l: Light] ~ { t.camera.use ¬ light; IF t.lights # NIL THEN FOR i: INTEGER IN [0..t.lights.length) DO IF t.lights[i] = l THEN {t.selectedLight ¬ i; EXIT}; ENDLOOP; t.camera.miscPosition ¬ l.position; t.camera.miscVector ¬ l.direction; SetCameraToIdentity[t.camera]; }; SelectShape: PUBLIC PROC [t: Tool, s: Shape, mb: Controls.MouseButton ¬ none] ~ { node: TTNode ¬ IF s.hierarchyData # NIL THEN NARROW[s.hierarchyData] ELSE NIL; m: Matrix ¬ IF node # NIL THEN node.localTransform ELSE s.matrix; IF node # NIL THEN { traversal: G3dTool.Traversal ¬ IF mb = left THEN selfOnly ELSE selfAndChildren; IF m = NIL THEN m ¬ node.localTransform ¬ G3dMatrix.Identity[]; G3dTool.SelectNodeShapes[t.timeTree.activeNode ¬ t.focusNode ¬ node, traversal]; } ELSE { s.selected ¬ TRUE; t.focusNode ¬ NIL; FOR n: NAT IN [0..t.shapes.length) DO IF t.shapes[n] = s THEN {t.selectedShape ¬ n; EXIT}; ENDLOOP; }; t.camera.use ¬ shape; t.camera.miscMatrix ¬ G3dMatrix.CopyMatrix[m, t.camera.miscMatrix]; SetCameraToIdentity[t.camera]; }; SetCameraToIdentity: PUBLIC PROC [camera: CameraControl] ~ { G3dControl.SetTripleControls[camera.par.xRot, camera.par.yRot, camera.par.zRot, []]; G3dControl.SetTripleControls[camera.par.xMov, camera.par.yMov, camera.par.zMov, []]; G3dControl.UpdateControl[camera, camera.scale, 1.0]; }; ClearArcBall: PROC [arcBall: G3dControl.ArcBall] ~ { ViewerOps.PaintViewer[arcBall.rotate.control.viewer, client, FALSE, $ClearArc]; ViewerOps.PaintViewer[arcBall.translate.control.viewer, client, FALSE, $ClearArc]; }; END.