<<>> <> <> <> <> <> DIRECTORY Controls, Draw2d, G3dBasic, G3dControl, G3dDraw, G3dMatrix, G3dPlane, G3dShape, G3dVector, G3dView, Imager, ImagerColor, IO, KeyNames, KeyTypes, MessageWindow, Real, Rope, UserInputOps, ViewerOps, ViewersWorld, ViewersWorldInstance, ViewersWorldRefType, ViewerTools; G3dControlImpl: CEDAR PROGRAM IMPORTS Controls, Draw2d, G3dControl, G3dDraw, G3dMatrix, G3dPlane, G3dVector, G3dView, Imager, ImagerColor, IO, KeyNames, MessageWindow, Real, Rope, UserInputOps, ViewerOps, ViewersWorld, ViewersWorldInstance, ViewerTools EXPORTS G3dControl ~ BEGIN <> Viewer: TYPE ~ Controls.Viewer; Mouse: TYPE ~ Controls.Mouse; Control: TYPE ~ Controls.Control; ControlProc: TYPE ~ Controls.ControlProc; ControlType: TYPE ~ Controls.ControlType; ControlList: TYPE ~ Controls.ControlList; DrawType: TYPE ~ Draw2d.DrawType; Triple: TYPE ~ G3dBasic.Triple; TripleSequence: TYPE ~ G3dBasic.TripleSequence; Pair: TYPE ~ G3dBasic.Pair; PairSequence: TYPE ~ G3dBasic.PairSequence; ArcBall: TYPE ~ G3dControl.ArcBall; Method: TYPE ~ G3dControl.Method; ProxyMode: TYPE ~ G3dControl.ProxyMode; CameraControl: TYPE ~ G3dControl.CameraControl; CameraControlRep: TYPE ~ G3dControl.CameraControlRep; Hold: TYPE ~ G3dControl.Hold; HoldRep: TYPE ~ G3dControl.HoldRep; Slice: TYPE ~ G3dControl.Slice; SliceRep: TYPE ~ G3dControl.SliceRep; Pick: TYPE ~ G3dControl.Pick; Matrix: TYPE ~ G3dMatrix.Matrix; MatrixRep: TYPE ~ G3dMatrix.MatrixRep; Viewport: TYPE ~ G3dMatrix.Viewport; Plane: TYPE ~ G3dPlane.Plane; ScreenSequence: TYPE ~ G3dShape.ScreenSequence; Camera: TYPE ~ G3dView.Camera; CameraRep: TYPE ~ G3dView.CameraRep; Context: TYPE ~ Imager.Context; ROPE: TYPE ~ Rope.ROPE; xAxis: Triple ~ G3dBasic.xAxis; yAxis: Triple ~ G3dBasic.yAxis; zAxis: Triple ~ G3dBasic.zAxis; <> lastAdjustedCamera: CameraControl _ NIL; alwaysUpdate: BOOL _ TRUE; -- = TRUE: attempt to fix sync problem <> <> <> SetCameraControlMethod: PUBLIC PROC [camera: CameraControl, method: Method] ~ { camera.method _ method; }; CameraControlOrientation: PUBLIC PROC [ camera: CameraControl, eyePoint, lookAt, up: Triple, roll: REAL] ~ { camera.method _ geometry; camera.eyePoint _ eyePoint; camera.lookAt _ lookAt; camera.roll _ roll; }; InitCameraControl: PUBLIC PROC [ proc: ControlProc _ NIL, clientData: REF ANY _ NIL, proxyMode: ProxyMode _ wor, fieldOfView: REAL _ 60.0, scale: REAL _ 1.0, move: Triple _ [0.0, 2.0, 0.0], rotate: Triple _ [0.0, 0.0, 0.0], moveRange: REAL _ 10.0] RETURNS [c: CameraControl] ~ { NewControl: PROC [ name: Rope.ROPE, type: ControlType, taper: Controls.SliderTaper _ lin, min, max, init: REAL _ 0.0, col: Triple ¬ [0, 0, 1]] RETURNS [ctrl: Control] ~ { ctrl _ Controls.NewControl[ name: name, type: type, clientData: c, min: min, max: max, init: init, proc: CameraControlProc, taper: taper, color: ImagerColor.ColorFromRGB[[col.x, col.y, col.z]]]; <> }; r: REAL _ moveRange; c _ NEW[CameraControlRep]; IF move = [0.0, 2.0, 0.0] THEN move _ [0.0, 0.0, 2.0]; c.proc _ proc; c.clientData _ clientData; c.matrix _ NEW[MatrixRep]; c.view _ NEW[MatrixRep]; c.save _ NEW[CameraRep]; c.incr _ NEW[MatrixRep]; c.proxyMode _ proxyMode; c.proxySelect _ Controls.NewControl[NameFromProxyMode[proxyMode],, c,, 2, SELECT proxyMode FROM par => 0, wor => 1, ENDCASE => 2, ProxyProc, FALSE, 0,,,,,,,, LIST[[1, .5]]]; c.par.xMov _ NewControl["X", vSlider, , -r, r, move.x]; c.par.yMov _ NewControl["Y", vSlider, , -r, r, move.y]; c.par.zMov _ NewControl["Z", vSlider, , -r, r, move.z]; c.par.xRot _ NewControl["Xrot", dial, , 0.0, 360.0, rotate.x]; c.par.yRot _ NewControl["Yrot", dial, , 0.0, 360.0, rotate.y]; c.par.zRot _ NewControl["Zrot", dial, , 0.0, 360.0, rotate.z]; c.wor.xMov _ NewControl["WX", vSlider, , -r, r, 0.0]; c.wor.yMov _ NewControl["WY", vSlider, , -r, r, 0.0]; c.wor.zMov _ NewControl["WZ", vSlider, , -r, r, 0.0]; c.wor.xRot _ NewControl["WXrot", dial, , 0.0, 360.0, 0.0]; c.wor.yRot _ NewControl["WYrot", dial, , 0.0, 360.0, 0.0]; c.wor.zRot _ NewControl["WZrot", dial, , 0.0, 360.0, 0.0]; c.eye.xMov _ NewControl["EX", vSlider, , -r, r, 0.0]; c.eye.yMov _ NewControl["EY", vSlider, , -r, r, 0.0]; c.eye.zMov _ NewControl["EZ", vSlider, , -r, r, 0.0]; c.eye.xRot _ NewControl["Pitch", dial, , 0.0, 360.0, 0.0]; c.eye.yRot _ NewControl["Roll", dial, , 0.0, 360.0, 0.0]; c.eye.zRot _ NewControl["Yaw", dial, , 0.0, 360.0, 0.0]; c.proxy.xMov _ NewControl["X", vSlider, , -r, r, move.x]; c.proxy.yMov _ NewControl["Y", vSlider, , -r, r, move.y]; c.proxy.zMov _ NewControl["Z", vSlider, , -r, r, move.z]; c.proxy.xRot _ NewControl["Xrot", dial, , 0.0, 360.0, rotate.x]; c.proxy.yRot _ NewControl["Yrot", dial, , 0.0, 360.0, rotate.y]; c.proxy.zRot _ NewControl["Zrot", dial, , 0.0, 360.0, rotate.z]; c.scale _ NewControl["Scale", vSlider, exp, 0.0, 100.0, scale]; c.fieldOfView _ NewControl["Fov", vSlider, , 0.0, 180.0, fieldOfView, [1, 0, 0]]; c.hScreen _ NewControl["Xscr", vSlider, , -2.0, 2.0, 0.0]; c.vScreen _ NewControl["Yscr", vSlider, , -2.0, 2.0, 0.0]; c.arcBall _ G3dControl.InitArcBall[c, proc, clientData]; UpdateCameraControl[c]; }; AddCameraControl: PUBLIC PROC [ controls: ControlList, camera: CameraControl, useArcBalls: BOOL] RETURNS [ret: ControlList] ~ { ret _ CONS[camera.fieldOfView, controls]; IF useArcBalls THEN { ret _ CONS[camera.scale, ret]; ret _ CONS[camera.arcBall.translate.control, ret]; ret _ CONS[camera.arcBall.rotate.control, ret]; camera.fieldOfView.h _ camera.scale.h _ camera.arcBall.translate.control.h; camera.proxyMode _ par; } ELSE { ret _ CONS[camera.scale, ret]; ret _ CONS[camera.proxy.zMov, ret]; ret _ CONS[camera.proxy.yMov, ret]; ret _ CONS[camera.proxy.xMov, ret]; ret _ CONS[camera.proxy.zRot, ret]; ret _ CONS[camera.proxy.yRot, ret]; ret _ CONS[camera.proxy.xRot, ret]; ret _ CONS[camera.proxySelect, ret]; }; }; NameFromProxyMode: PROC [proxyMode: ProxyMode] RETURNS [r: ROPE] ~ { r _ SELECT proxyMode FROM par => "Par", wor => "Wor", ENDCASE => "Cam"; }; ProxyProc: ControlProc ~ { c: CameraControl ~ NARROW[control.clientData]; c.proxyMode _ SELECT control.value FROM 0 => par, 1 => wor, ENDCASE => eye; ViewerTools.SetContents[c.proxySelect.title, NameFromProxyMode[c.proxyMode]]; SELECT c.proxyMode FROM par => { Controls.SetSliderDialValue[c.proxy.xMov, c.par.xMov.value]; Controls.SetSliderDialValue[c.proxy.yMov, c.par.yMov.value]; Controls.SetSliderDialValue[c.proxy.zMov, c.par.zMov.value]; Controls.SetSliderDialValue[c.proxy.xRot, c.par.xRot.value]; Controls.SetSliderDialValue[c.proxy.yRot, c.par.yRot.value]; Controls.SetSliderDialValue[c.proxy.zRot, c.par.zRot.value]; }; ENDCASE => FOR l: ControlList _ LIST[c.proxy.xMov, c.proxy.yMov, c.proxy.zMov, c.proxy.xRot, c.proxy.yRot, c.proxy.zRot], l.rest WHILE l # NIL DO Benign[l.first]; ENDLOOP; }; InitContext: PUBLIC PROC [ context: Context, camera: CameraControl, viewer: Viewer _ NIL, clear: BOOL _ TRUE, out: Matrix _ NIL] RETURNS [Matrix] ~ { IF clear THEN Draw2d.Clear[context]; SetViewMatrix[camera]; IF viewer # NIL THEN camera.view _ G3dView.TransformByViewport[viewer, camera.view, camera.view]; RETURN[G3dMatrix.CopyMatrix[camera.view, out]]; }; <<>> CameraControlProc: ControlProc ~ { <> <> <> <> <> <> <<};>> <> c: CameraControl ~ NARROW[control.clientData]; IF control = c.par.yRot AND (control.value = 90.0 OR control.value = 180.0 OR control.value = 270.0) THEN RETURN; -- this year's great kluge IF -- NOT Ignore[] -- control.mouse.state # up THEN { -- else user surprised by change c.current _ control; lastAdjustedCamera _ c; IF control.whatChanged = $InputKilled THEN MessageWindow.Append["InputKilled..."]; IF NOT alwaysUpdate THEN { <> IF control.mouse.state = down THEN SELECT CameraAction[c] FROM $Par, $Ignore => NULL; ENDCASE => { c.initval _ c.current.value; -- just zero the eye or wor control RETURN; -- maybe returning causes the update problem? }; }; UpdateCameraControl[c]; -- update the camera parameters and camera.matrix IF c.graphics # NIL THEN ViewerOps.PaintViewer[c.graphics, client, FALSE, control.whatChanged]; }; IF control.mouse.state = up THEN c.inverse _ G3dMatrix.Invert[c.matrix, c.inverse]; IF c.proc # NIL THEN c.proc[control, c.clientData]; -- call client proc, if any IF EverythingUp[] THEN SELECT CameraAction[c] FROM -- if missed up during draw $Par, $Proxy, $Ignore => NULL; ENDCASE => Benign[control]; }; UpdateCameraControl: PUBLIC PROC [camera: CameraControl] ~ { IF alwaysUpdate THEN DoUpdateCamera[camera] -- update based on current control ELSE { <> <> <> curr: Control _ camera.current; cleanupPrev: BOOL _ camera.prev # NIL AND camera.prev.mouse.state # up AND curr # camera.prev; slidIntoCurrent: BOOL _ camera.prev # curr AND curr.mouse.state # down; IF cleanupPrev THEN { -- enter new slider with no prev up, simulate prev up camera.prev.mouse.state _ up; -- camera.prev has its own mouse record camera.current _ camera.prev; DoUpdateCamera[camera]; -- clean up prev camera.current _ curr; }; IF slidIntoCurrent THEN curr.mouse.state _ down; -- simulate current down DoUpdateCamera[camera]; -- update for current control camera.prev _ curr; }; }; UpdateControl: PUBLIC PROC [camera: CameraControl, control: Control, value: REAL] ~ { IF control = NIL THEN RETURN; IF control.sliderDialRef = NIL THEN control.value _ value ELSE Controls.SetSliderDialValue[control, value]; IF camera.proxyMode = par THEN Controls.SetSliderDialValue[ProxyFromPar[camera, control], value]; IF NOT alwaysUpdate THEN { control.mouse.state _ up; -- so incremental controls will be absorbed into camera.par camera.current _ control; -- so Delta is properly computed <> }; DoUpdateCamera[camera]; -- as opposed to UpdateCameraControl }; ProxyFromPar: PROC [camera: CameraControl, control: Control] RETURNS [Control] ~ { RETURN[SELECT control FROM camera.par.xMov => camera.proxy.xMov, camera.par.yMov => camera.proxy.yMov, camera.par.zMov => camera.proxy.zMov, camera.par.xRot => camera.proxy.xRot, camera.par.yRot => camera.proxy.yRot, camera.par.zRot => camera.proxy.zRot, ENDCASE => NIL]; }; viewersWorld: ViewersWorldRefType.Ref ¬ ViewersWorldInstance.GetWorld[]; userInput: UserInputOps.Handle ¬ ViewersWorld.GetInputHandle[viewersWorld]; leftMouse: KeyTypes.KeySym ¬ KeyNames.KeySymFromName["LeftMouse"]; middleMouse: KeyTypes.KeySym ¬ KeyNames.KeySymFromName["MiddleMouse"]; rightMouse: KeyTypes.KeySym ¬ KeyNames.KeySymFromName["RightMouse"]; EverythingUp: PROC RETURNS [allUp: BOOL] ~ { allUp ¬ UserInputOps.GetLatestKeySymState[userInput, leftMouse] = up AND UserInputOps.GetLatestKeySymState[userInput, middleMouse] = up AND UserInputOps.GetLatestKeySymState[userInput, rightMouse] = up; }; Benign: PROC [control: Control] ~ { -- make control seem 'benign.' Controls.SetSliderDialValue[control, 0.0]; }; SetCameraControlGraphics: PUBLIC PROC [camera: CameraControl, graphics: Viewer] ~ { camera.graphics _ graphics; }; CameraAction: PROC [c: CameraControl] RETURNS [ATOM] ~ { mode: ProxyMode _ c.proxyMode; RETURN[SELECT c.current FROM -- meaning of c.current c.hScreen, c.vScreen => $Ignore, c.wor.xMov => $WorXMv, c.wor.yMov => $WorYMv, c.wor.zMov => $WorZMv, c.wor.xRot => $WorXRot, c.wor.yRot => $WorYRot, c.wor.zRot => $WorZRot, c.eye.xMov => $EyeXMv, c.eye.yMov => $EyeZMv, -- switch y and z so the user won't get confused c.eye.zMov => $EyeYMv, -- i.e., we're in eye-space (LHS), but pretend otherwise to user c.eye.xRot => $EyeXRot, c.eye.yRot => $EyeZRot, -- switch y and z so the user won't get confused c.eye.zRot => $EyeYRot, -- i.e., we're in eye-space (LHS), but pretend otherwise to user c.proxy.xMov => SELECT mode FROM par=>$Proxy, eye=>$EyeXMv, ENDCASE=>$WorXMv, <> c.proxy.yMov => SELECT mode FROM par=>$Proxy, eye=>$EyeZMv, ENDCASE=>$WorYMv, c.proxy.zMov => SELECT mode FROM par=>$Proxy, eye=>$EyeYMv, ENDCASE=>$WorZMv, c.proxy.xRot => SELECT mode FROM par=>$Proxy, eye=>$EyeXRot, ENDCASE=>$WorXRot, <> c.proxy.yRot => SELECT mode FROM par=>$Proxy, eye=>$EyeZRot, ENDCASE=>$WorYRot, c.proxy.zRot => SELECT mode FROM par=>$Proxy, eye=>$EyeYRot, ENDCASE=>$WorZRot, ENDCASE => $Par]; }; DoUpdateCamera: PROC [camera: CameraControl] ~ { <> <> Delta: PROC RETURNS [REAL] ~ { IF alwaysUpdate THEN RETURN[Controls.GetSliderDialDeltaValue[c.current]] ELSE RETURN[c.current.value-c.initval]; }; c: CameraControl _ camera; incrSpace: {world, eye, none} _ none; -- which space are incremental xforms in? action: ATOM _ CameraAction[c]; SELECT action FROM $WorXMv => {incrSpace _ world; [] _ G3dMatrix.MakeTranslate[[Delta[], 0, 0], c.incr]}; $WorYMv => {incrSpace _ world; [] _ G3dMatrix.MakeTranslate[[0, Delta[], 0], c.incr]}; $WorZMv => {incrSpace _ world; [] _ G3dMatrix.MakeTranslate[[0, 0, Delta[]], c.incr]}; $WorXRot => {incrSpace _ world; [] _ G3dMatrix.MakeRotate[xAxis, Delta[],, c.incr]}; $WorYRot => {incrSpace _ world; [] _ G3dMatrix.MakeRotate[yAxis, Delta[],,c.incr]}; $WorZRot => {incrSpace _ world; [] _ G3dMatrix.MakeRotate[zAxis, Delta[],, c.incr]}; $EyeXMv => {incrSpace _ eye; [] _ G3dMatrix.MakeTranslate[[Delta[], 0, 0], c.incr]}; $EyeYMv => {incrSpace _ eye; [] _ G3dMatrix.MakeTranslate[[0, Delta[], 0], c.incr]}; $EyeZMv => {incrSpace _ eye; [] _ G3dMatrix.MakeTranslate[[0, 0, Delta[]], c.incr]}; $EyeXRot => {incrSpace _ eye; [] _ G3dMatrix.MakeRotate[xAxis, Delta[],, c.incr]}; $EyeYRot => {incrSpace _ eye; [] _ G3dMatrix.MakeRotate[yAxis, Delta[],, c.incr]}; $EyeZRot => {incrSpace _ eye; [] _ G3dMatrix.MakeRotate[zAxis, Delta[],, c.incr]}; $Ignore => RETURN; ENDCASE; IF action # $Par AND action # $Proxy AND (alwaysUpdate OR c.current.mouse.state = up) THEN { <> ParameterizeIncrementalTransform[c, action]; incrSpace _ none; }; IF action = $Proxy THEN { -- update the corresponding par control parControl: Control _ SELECT c.current FROM c.proxy.xMov => c.par.xMov, c.proxy.yMov => c.par.yMov, c.proxy.zMov => c.par.zMov, c.proxy.xRot => c.par.xRot, c.proxy.yRot => c.par.yRot, ENDCASE => c.par.zRot; Controls.SetSliderDialValue[parControl, c.current.value]; }; c.matrix _ G3dView.MakeCameraMatrix[ IF incrSpace = world THEN c.incr ELSE NIL, c.scale.value, [c.par.xMov.value, c.par.yMov.value, c.par.zMov.value], [c.par.xRot.value, c.par.yRot.value, c.par.zRot.value], IF incrSpace = eye THEN c.incr ELSE NIL, IF c.use = shape THEN 0.0 ELSE c.fieldOfView.value, FALSE, -- c.use = view, FAREWELL TO FRANK's COORDINATE SYSTEM c.matrix]; IF c.mouse.state = up OR c.mouse.state = none THEN [c.eyePoint, c.lookAt, c.up] _ G3dView.FromScaleMovesRots[ c.scale.value, [c.par.xMov.value, c.par.yMov.value, c.par.zMov.value], [c.par.xRot.value, c.par.yRot.value, c.par.zRot.value] ! G3dMatrix.singular => CONTINUE]; }; ParameterizeIncrementalTransform: PROC [c: CameraControl, action: ATOM] ~ { <<>> <> <> rotateMode: {body, world} _ world; -- former default was body <> oldrot: Matrix _ G3dMatrix.Identity[G3dMatrix.ObtainMatrix[]]; oldrot _ G3dMatrix.Rotate[oldrot, xAxis, c.par.xRot.value,,, oldrot]; oldrot _ G3dMatrix.Rotate[oldrot, yAxis, c.par.yRot.value,,, oldrot]; oldrot _ G3dMatrix.Rotate[oldrot, zAxis, c.par.zRot.value,,, oldrot]; <> SELECT action FROM $WorXMv, $WorYMv, $WorZMv => { -- merge world move into standard move t: Triple _ [c.par.xMov.value, c.par.yMov.value, c.par.zMov.value]; ti: Triple _ G3dVector.Mul[ [c.incr[3][0], c.incr[3][1], c.incr[3][2]], c.scale.value ]; IF rotateMode = world THEN { rInv: Matrix _ G3dMatrix.Transpose[oldrot, G3dMatrix.ObtainMatrix[]]; -- = inverse t _ G3dVector.Add[t, G3dMatrix.Transform[ti, rInv]]; G3dMatrix.ReleaseMatrix[rInv]; } ELSE t _ G3dVector.Add[t, ti]; Controls.SetSliderDialValue[c.par.xMov, t.x]; Controls.SetSliderDialValue[c.par.yMov, t.y]; Controls.SetSliderDialValue[c.par.zMov, t.z]; }; $WorXRot, $WorYRot, $WorZRot => { -- merge world rotate into standard rotate and move r: Matrix _ G3dMatrix.ObtainMatrix[]; rRot: Matrix _ G3dMatrix.ObtainMatrix[]; parMov: Triple _ [c.par.xMov.value, c.par.yMov.value, c.par.zMov.value]; t: Triple; IF rotateMode = world THEN [] _ G3dMatrix.Mul[oldrot, c.incr, r] -- newer rotate matrix ELSE [] _ G3dMatrix.Mul[c.incr, oldrot, r]; -- new rotate matrix t _ G3dMatrix.ExtractRotate[r]; Controls.SetSliderDialValue[c.par.xRot, t.x]; Controls.SetSliderDialValue[c.par.yRot, t.y]; Controls.SetSliderDialValue[c.par.zRot, t.z]; IF rotateMode = world THEN { rRot: Matrix _ G3dMatrix.Transpose[r, G3dMatrix.ObtainMatrix[]]; t _ G3dMatrix.Transform[parMov, oldrot]; t _ G3dMatrix.Transform[t, rRot]; G3dMatrix.ReleaseMatrix[rRot]; } ELSE { [] _ G3dMatrix.Transpose[c.incr, r]; -- r now holds inverse of incremental rotate t _ G3dMatrix.Transform[parMov, r]; }; Controls.SetSliderDialValue[c.par.xMov, t.x]; Controls.SetSliderDialValue[c.par.yMov, t.y]; Controls.SetSliderDialValue[c.par.zMov, t.z]; G3dMatrix.ReleaseMatrix[r]; }; $EyeXMv, $EyeYMv, $EyeZMv => { -- merge eye move (dolly) into standard move rInv: Matrix _ G3dMatrix.Transpose[oldrot, G3dMatrix.ObtainMatrix[]]; -- = inverse parMov: Triple _ [c.par.xMov.value, c.par.yMov.value, c.par.zMov.value]; eyeMov: Triple _ [c.incr[3][0], c.incr[3][1], c.incr[3][2]]; -- 2 out of 3 are zero <> eyeMov _ [eyeMov.x, eyeMov.z, eyeMov.y]; <> parMov _ G3dVector.Add[parMov, G3dMatrix.Transform[eyeMov, rInv]]; Controls.SetSliderDialValue[c.par.xMov, parMov.x]; Controls.SetSliderDialValue[c.par.yMov, parMov.y]; Controls.SetSliderDialValue[c.par.zMov, parMov.z]; G3dMatrix.ReleaseMatrix[rInv]; }; $EyeXRot, $EyeYRot, $EyeZRot => { -- merge eye rotate (gimbal) into standard rotate t: Triple; <
> <> r: Matrix _ G3dMatrix.ObtainMatrix[]; swap: Matrix _ G3dMatrix.ObtainMatrix[]; <> swap^ _ [[1., 0., 0., 0.], [0., 0., 1., 0.], [0., 1., 0., 0.], [0., 0., 0., 1.]]; [] _ G3dMatrix.Mul[oldrot, swap, r]; [] _ G3dMatrix.Mul[r, c.incr, r]; [] _ G3dMatrix.Mul[r, swap, r]; -- RXRiX t _ G3dMatrix.ExtractRotate[r]; Controls.SetSliderDialValue[c.par.xRot, t.x]; Controls.SetSliderDialValue[c.par.yRot, t.y]; Controls.SetSliderDialValue[c.par.zRot, t.z]; G3dMatrix.ReleaseMatrix[r]; G3dMatrix.ReleaseMatrix[swap]; }; ENDCASE => NULL; G3dMatrix.ReleaseMatrix[oldrot]; }; GetCameraControlMatrix: PUBLIC PROC [camera: CameraControl] RETURNS [Matrix] ~ { RETURN[camera.matrix]; }; GetViewMatrix: PUBLIC PROC [camera: CameraControl, out: Matrix] RETURNS [Matrix] ~ { SetViewMatrix[camera]; RETURN[G3dMatrix.CopyMatrix[camera.view, out]]; }; <<>> SetViewMatrix: PROC [c: CameraControl] ~ { c.view _ G3dMatrix.Translate[c.matrix, [c.hScreen.value, c.vScreen.value, 0.0], c.view]; }; <<>> EyeViewFromCameraControl: PUBLIC PROC [camera: CameraControl] RETURNS [Triple] ~ { eyePoint, lookAt: Triple; [eyePoint, lookAt, []] _ G3dView.FromScaleMovesRots[ camera.scale.value, [camera.par.xMov.value, camera.par.yMov.value, camera.par.zMov.value], [camera.par.xRot.value, camera.par.yRot.value, camera.par.zRot.value]]; RETURN[G3dVector.Sub[lookAt, eyePoint]]; }; SaveState: PUBLIC PROC [camera: CameraControl, state: Camera] ~ { ab: ArcBall _ camera.arcBall; state^ _ [ move: [camera.par.xMov.value, camera.par.yMov.value, camera.par.zMov.value], rotate: [camera.par.xRot.value, camera.par.yRot.value, camera.par.zRot.value], scale: camera.scale.value, fieldOfView: camera.fieldOfView.value, roll: camera.roll, eyePoint: camera.eyePoint, lookAt: camera.lookAt, up: camera.up, matrix: G3dMatrix.CopyMatrix[camera.matrix, state.matrix]]; }; RestoreState: PUBLIC PROC [camera: CameraControl, state: Camera] ~ { ab: ArcBall _ camera.arcBall; Controls.SetSliderDialValue[camera.par.xMov, state.move.x]; Controls.SetSliderDialValue[camera.par.yMov, state.move.y]; Controls.SetSliderDialValue[camera.par.zMov, state.move.z]; Controls.SetSliderDialValue[camera.par.xRot, state.rotate.x]; Controls.SetSliderDialValue[camera.par.yRot, state.rotate.y]; Controls.SetSliderDialValue[camera.par.zRot, state.rotate.z]; Controls.SetSliderDialValue[camera.scale, state.scale]; Controls.SetSliderDialValue[camera.fieldOfView, state.fieldOfView]; camera.roll _ state.roll; camera.eyePoint _ state.eyePoint; camera.lookAt _ state.lookAt; camera.up _ state.up; camera.matrix _ G3dMatrix.CopyMatrix[state.matrix, camera.matrix]; }; LastAdjustedCameraControl: PUBLIC PROC RETURNS [CameraControl] ~ { RETURN[lastAdjustedCamera]; }; CameraControlMessage: PUBLIC PROC [camera: CameraControl] RETURNS [out: ROPE] ~ { Add: PROC [r: ROPE] ~ {IF r#NIL THEN out_Rope.Cat[out,IF out=NIL THEN NIL ELSE "; ",r]}; Ok: PROC [c: Control] RETURNS [b: BOOL] ~ {b _ c.viewer # NIL AND c.value # 0.0}; Val: PROC [c: Control, id: ROPE] RETURNS [o: ROPE] ~ { IF Ok[c] THEN o _ IO.PutFR["%g%g", IO.real[Real.Round[1000*c.value]/1000], IO.rope[id]]; }; Val3: PROC [header: ROPE, c1, c2, c3: Control, id1, id2, ig3d: ROPE] RETURNS [out: ROPE] ~ { Inner: PROC [c: Control, id: ROPE] ~ { IF NOT Ok[c] THEN RETURN; IF once THEN out _ Rope.Concat[out, ", "]; once _ TRUE; out _ IO.PutFR["%g%g", IO.rope[out], IO.rope[Val[c, id]]]; }; once: BOOL _ FALSE; Inner[c1, id1]; Inner[c2, id2]; Inner[c3, ig3d]; IF once THEN out _ Rope.Cat[header, ": ", out]; }; c: CameraControl _ camera; Add[Val[c.scale, "scale"]]; Add[Val3["move", c.par.xMov, c.par.yMov, c.par.zMov, "x", "y", "z"]]; Add[Val3["rot", c.par.xRot, c.par.yRot, c.par.zRot, "x", "y", "z"]]; Add[Val[c.fieldOfView, "fov"]]; }; <> InitSlice: PUBLIC PROC [data: REF ANY _ NIL, proc: Controls.ControlProc _ NIL] RETURNS [slice: Slice] ~ { slice _ NEW[SliceRep]; slice.x _ Controls.NewControl["x", vSlider, data, -1.0, 1.0, 0.0, proc]; slice.y _ Controls.NewControl["y", vSlider, data, -1.0, 1.0, 0.0, proc]; slice.z _ Controls.NewControl["z", vSlider, data, -1.0, 1.0, 0.0, proc]; slice.phi _ Controls.NewControl["phi", dial, data, 0.0, 360.0, 90.0, proc]; slice.theta _ Controls.NewControl["theta", dial, data, 0.0, 360.0, 0.0, proc]; slice.size _ Controls.NewControl["size", vSlider, data, 0.0, 1.0, 0.1, proc]; UpdateSlice[slice]; }; SetSlice: PUBLIC PROC [slice: Slice, plane: Plane, size: REAL _ 1.0] ~ { o: Triple _ G3dPlane.CenterOfPlane[plane]; t: Triple _ G3dVector.PolarFromCartesian[[plane.x, plane.y, plane.z]]; SetTripleControls[slice.x, slice.y, slice.z, o]; SetTripleControls[slice.phi, slice.theta, slice.size, [t.x, t.y, size]]; UpdateSlice[slice]; }; UpdateSlice: PUBLIC PROC [slice: Slice] ~ { o: Triple ~ [slice.x.value, slice.y.value, slice.z.value]; z: Triple ~ G3dVector.CartesianFromPolar[[slice.phi.value, slice.theta.value, 1.0]]; x: Triple ~ G3dVector.Unit[G3dVector.Cross[IF z # zAxis THEN zAxis ELSE yAxis, z]]; y: Triple ~ G3dVector.Unit[G3dVector.Cross[x, z]]; slice.plane _ G3dPlane.FromPointAndNormal[o, z]; slice.matrix _ G3dMatrix.MakeFromTriad[x, y, z, o, FALSE, slice.matrix]; slice.matrix _ G3dMatrix.LocalScale[slice.matrix, slice.size.value, slice.matrix]; }; DrawSlice: PUBLIC PROC [ context: Context, slice: Slice, view: Matrix, viewport: Viewport _ [], drawType: DrawType _ solid] ~ { zip: Draw2d.Zip _ Draw2d.GetZip[context]; IF slice # NIL AND slice.matrix # NIL THEN { m: Matrix ~ G3dMatrix.Mul[slice.matrix, view]; p: Triple ~ [-slice.plane.x, -slice.plane.y, -slice.plane.z]; q: ARRAY [0..4) OF Pair _ [[-1.0, 1.0], [1.0, 1.0], [1.0, -1.0], [-1.0, -1.0]]; a: ARRAY [0..4) OF Pair; c: Triple _ G3dMatrix.TransformPair[[0.0, 0.0], slice.matrix]; FOR i: NAT IN [0..4) DO a[i] _ G3dMatrix.TransformPairD[q[i], m]; ENDLOOP; FOR i: NAT IN [0..4) DO Draw2d.Line[context, a[i], a[(i+1) MOD 4], drawType, zip]; ENDLOOP; G3dDraw.Vector[context, c, p, view, viewport,, 0.1]; }; }; MoveSliceInY: PUBLIC PROC [slice: Slice, amount: REAL] ~ { v: Triple ~ G3dMatrix.TransformVec[yAxis, slice.matrix]; o: Triple _ G3dVector.Combine[[slice.x.value, slice.y.value, slice.z.value], 1., v, amount]; Controls.SetSliderDialValue[slice.x, o.x]; Controls.SetSliderDialValue[slice.y, o.y]; Controls.SetSliderDialValue[slice.z, o.z]; UpdateSlice[slice]; }; MoveSliceInZ: PUBLIC PROC [slice: Slice, amount: REAL] ~ { v: Triple ~ G3dMatrix.TransformVec[zAxis, slice.matrix]; o: Triple _ G3dVector.Combine[[slice.x.value, slice.y.value, slice.z.value], 1., v, amount]; Controls.SetSliderDialValue[slice.x, o.x]; Controls.SetSliderDialValue[slice.y, o.y]; Controls.SetSliderDialValue[slice.z, o.z]; UpdateSlice[slice]; }; <> InitHold: PUBLIC PROC [proc: ControlProc _ NIL, data: REF ANY _ NIL] RETURNS [h: Hold] ~ { h _ NEW[HoldRep]; h.x _ Controls.NewControl["ptx", vSlider, data, -1.0, 1.0, 0.0, proc]; h.y _ Controls.NewControl["pty", vSlider, data, -1.0, 1.0, 0.0, proc]; h.z _ Controls.NewControl["ptz", vSlider, data, -1.0, 1.0, 0.0, proc]; h.pitch _ Controls.NewControl["pitch", dial, data, 0.0, 360.0, 0.0, proc]; h.yaw _ Controls.NewControl["yaw", dial, data, 0.0, 360.0, 0.0, proc]; h.roll _ Controls.NewControl["roll", dial, data, 0.0, 360.0, 0.0, proc]; h.mag _ Controls.NewControl["mag", vSlider, data, -2.0, 2.0, 1.0, proc]; }; <<>> SetHold: PUBLIC PROC [hold: Hold, position, tangent: Triple _ [0.0, 0.0, 0.0]] ~ { polar: Triple _ G3dVector.PolarFromCartesian[tangent]; Controls.SetSliderDialValue[hold.pitch, polar.x]; Controls.SetSliderDialValue[hold.yaw, polar.y]; Controls.SetSliderDialValue[hold.mag, polar.z]; Controls.SetSliderDialValue[hold.x, position.x]; Controls.SetSliderDialValue[hold.y, position.y]; Controls.SetSliderDialValue[hold.z, position.z]; }; PositionFromHold: PUBLIC PROC [hold: Hold] RETURNS [Triple] ~ { RETURN[[hold.x.value, hold.y.value, hold.z.value]]; }; VectorFromHold: PUBLIC PROC [hold: Hold] RETURNS [t: Triple] ~ { t _ G3dVector.CartesianFromPolar[[hold.yaw.value, hold.pitch.value, hold.mag.value]]; }; <> ScreenPick: PUBLIC PROC [screens: ScreenSequence, screen: G3dBasic.IntegerPair] RETURNS [picked: INTEGER _ -1] ~ { IF screens # NIL THEN { dist, max: INTEGER _ 1000000; FOR n: NAT IN [0..screens.length) DO p: G3dBasic.IntegerPair _ screens[n].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; picked _ n}; ENDLOOP; }; }; PointPick: PUBLIC PROC [ points: TripleSequence, pairs: PairSequence, view: Matrix, mouse: Mouse] RETURNS [pointPicked: INTEGER] ~ { ln: NAT _ IF points # NIL THEN points.length ELSE IF pairs # NIL THEN pairs.length ELSE 0; dist, max: REAL _ 100000.0; IF pairs = NIL THEN RETURN[-1]; IF points # NIL THEN { IF pairs.maxLength < points.length THEN RETURN[-2]; IF mouse.state = down OR mouse.state = held THEN FOR n: NAT IN [0..points.length) DO pairs[n] _ G3dMatrix.TransformD[points[n], view]; ENDLOOP; }; pointPicked _ 0; FOR i: NAT IN [0..ln) DO dx: REAL _ mouse.pos.x-pairs[i].x; dy: REAL _ mouse.pos.y-pairs[i].y; IF (dist _ dx*dx+dy*dy) < max THEN {max _ dist; pointPicked _ i}; ENDLOOP; }; PickMovePoint: PUBLIC PROC [ points: TripleSequence, pairs: PairSequence _ NIL, view: Matrix, viewport: Viewport, mouse: Mouse, pick: Pick] RETURNS [Pick] ~ { persp: BOOL _ G3dMatrix.HasPerspective[view]; SELECT mouse.state FROM down => { min: REAL _ 1000000.0; FOR n: NAT IN [0..points.length) DO screen: Pair _ G3dMatrix.GetScreen[points[n], view, persp, viewport].pos; dif: Pair _ [mouse.pos.x-screen.x, mouse.pos.y-screen.y]; r: REAL _ dif.x*dif.x+dif.y*dif.y; IF r < min THEN {min _ r; pick _ [dif, n]}; ENDLOOP; }; held => { screen: Pair _ [mouse.pos.x-pick.offset.x, mouse.pos.y-pick.offset.y]; <> <> plane: Plane _ IF persp THEN G3dPlane.FromPointAndNormal[ points[pick.selected], G3dVector.Negate[points[pick.selected]]] ELSE [0.0, 0.0, 1.0, -points[pick.selected].z]; points[pick.selected] _ G3dMatrix.TripleFromScreenAndPlane[ screen, [plane.x, plane.y, plane.z, plane.w], view ! G3dPlane.Error => GOTO BadView]; IF pairs # NIL THEN pairs[pick.selected] _ [mouse.pos.x, mouse.pos.y]; }; ENDCASE; RETURN[pick]; EXITS BadView => { MessageWindow.Append[" bad view-"]; RETURN[pick]; }; }; <> PaintControls: PUBLIC PROC [c1, c2, c3, c4, c5, c6: Control _ NIL] ~ { IF c1 # NIL THEN ViewerOps.PaintViewer[c1.viewer, client, FALSE, c1]; IF c2 # NIL THEN ViewerOps.PaintViewer[c2.viewer, client, FALSE, c2]; IF c3 # NIL THEN ViewerOps.PaintViewer[c3.viewer, client, FALSE, c2]; IF c4 # NIL THEN ViewerOps.PaintViewer[c3.viewer, client, FALSE, c2]; IF c5 # NIL THEN ViewerOps.PaintViewer[c3.viewer, client, FALSE, c2]; IF c6 # NIL THEN ViewerOps.PaintViewer[c3.viewer, client, FALSE, c2]; }; SetTripleControls: PUBLIC PROC [x, y, z: Control _ NIL, triple: Triple, repaint: BOOL _ TRUE] ~ { IF x # NIL THEN Controls.SetSliderDialValue[x, triple.x, repaint]; IF y # NIL THEN Controls.SetSliderDialValue[y, triple.y, repaint]; IF z # NIL THEN Controls.SetSliderDialValue[z, triple.z, repaint]; }; END.