Controls3dImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, February 26, 1987 7:29:59 pm PST
DIRECTORY Controls, Draw2d, Imager, ImagerBackdoor, Matrix3d, Controls3d, Real, ThreeDScenes, Vector3d, ViewerOps;
Controls3dImpl: CEDAR PROGRAM
IMPORTS Controls, Draw2d, ImagerBackdoor, Matrix3d, Real, ThreeDScenes, Vector3d, ViewerOps
EXPORTS Controls3d
~ BEGIN
OPEN Controls3d;
Global Variables
lastAdjustedCamera: Camera ← NIL;
Camera Procedures
CameraControlProc: ControlProc ~ {
c: Camera ~ NARROW[control.data];
c.lastMoused ← control;
lastAdjustedCamera ← c;
IF control.mouse.state = down THEN {
DoubleSet: PROC [control: Control, value: REAL] ~ { -- control.prev𡤌ontrol.value←value
IF control.sliderDialRef # NIL THEN {
Controls.SetSliderDialValue[control, value];
Controls.SetSliderDialValue[control, value];
};
};
IF control # c.xLocal THEN DoubleSet[c.xLocal, 0.0];
IF control # c.yLocal THEN DoubleSet[c.yLocal, 0.0];
IF control # c.zLocal THEN DoubleSet[c.zLocal, 0.0];
};
IF control.mouse.state # up THEN UpdateCamera[c];
IF c.proc # NIL THEN c.proc[control, c.data];
};
InitCamera: PUBLIC PROC [
origin:  Triple ← [0.0, 0.0, 0.0],
globalRotate: Triple ← [0.0, 0.0, 0.0],
localRotate: Triple ← [0.0, 0.0, 0.0],
move:   Triple ← [0.0, 0.0, 0.0],
scale:   REAL ← 1.0,
fieldOfView: REAL ← 0.0,
zDistance: REAL ← 10.0,
screenMove: Pair ← [0.0, 0.0],
proc:   CameraProc ← NIL,
data:   REF ANYNIL]
RETURNS [c: Camera]
~ {
c ← NEW[CameraRep ← [proc: proc, data: data]];
c.matrix ← NEW[Matrix3d.MatrixRep];
c.view ← NEW[Matrix3d.MatrixRep];
c.x ← Controls.NewControl["x", vSlider, c, -10.0, 10.0, origin.x, CameraControlProc];
c.y ← Controls.NewControl["y", vSlider, c, -10.0, 10.0, origin.y, CameraControlProc];
c.z ← Controls.NewControl["z", vSlider, c, -10.0, 10.0, origin.z, CameraControlProc];
c.xGlobal ← Controls.NewControl["xRot", dial, c, 0.0, 360.0, globalRotate.x, CameraControlProc];
c.yGlobal ← Controls.NewControl["yRot", dial, c, 0.0, 360., globalRotate.y, CameraControlProc];
c.zGlobal ← Controls.NewControl["zRot", dial, c, 0.0, 360.0, globalRotate.z, CameraControlProc];
c.xLocal ← Controls.NewControl["xLcl", dial, c, 0.0, 360.0, localRotate.x, CameraControlProc];
c.yLocal ← Controls.NewControl["yLcl", dial, c, 0.0, 360.0, localRotate.y, CameraControlProc];
c.zLocal ← Controls.NewControl["zLcl", dial, c, 0.0, 360.0, localRotate.z, CameraControlProc];
c.xMove ← Controls.NewControl["xMv", vSlider, c, -10.0, 10.0, move.x, CameraControlProc];
c.yMove ← Controls.NewControl["yMv", vSlider, c, -10.0, 10.0, move.y, CameraControlProc];
c.zMove ← Controls.NewControl["zMv", vSlider, c, -10.0, 10.0, move.z, CameraControlProc];
c.scale ← Controls.NewControl["scale", , c, 0, 100, scale, CameraControlProc,,,,,,,,,,,, exp];
c.fieldOfView ← Controls.NewControl["fov", vSlider, c, 0, 100,fieldOfView,CameraControlProc];
c.hScreen ← Controls.NewControl["xScr", vSlider, c, -2, 2, screenMove.x, CameraControlProc];
c.vScreen ← Controls.NewControl["yScr", vSlider, c, -2, 2, screenMove.y, CameraControlProc];
c.zDistance ← Controls.NewControl["zDist", vSlider, c, -2.0, 2., zDistance, CameraControlProc];
UpdateCamera[c];
};
ComputeNewMatrix: PUBLIC PROC [
origin:   Triple ← [0.0, 0.0, 0.0],
rotate:    Triple ← [0.0, 0.0, 0.0],
move:    Triple ← [0.0, 0.0, 0.0],
scale:    REAL ← 0.0,
fieldOfView:  REAL ← 0.0,
zDistance:  REAL ← 0.0,
m:     Matrix ← NIL]
RETURNS [Matrix]
~ {
m ← Matrix3d.Identity[m];
m ← Matrix3d.Translate[m, Vector3d.Negate[origin], m];
m ← Matrix3d.Scale[m, scale, m];
m ← Matrix3d.Rotate[m, xAxis, rotate.x , , , m];
m ← Matrix3d.Rotate[m, yAxis, rotate.y, , , m];
m ← Matrix3d.Rotate[m, zAxis, rotate.z , , , m];
m ← Matrix3d.Translate[m, Vector3d.Add[origin, move], m];
IF fieldOfView # 0.0 AND zDistance # 0.0 THEN {
t: Matrix ← Matrix3d.ObtainMatrix[];
m ← Matrix3d.Mul[m, Matrix3d.MakePerspective[1.0/zDistance, 0.0, fieldOfView, t], m];
Matrix3d.ReleaseMatrix[t];
};
RETURN[m];
};
InitContext: PUBLIC PROC [context: Context, camera: Camera, in: Matrix ← NIL]
RETURNS [Matrix] ~ {
Draw2d.Clear[context];
RETURN[GetViewMatrix[camera, context]];
};
UpdateCamera: PUBLIC PROC [camera: Camera] ~ {
Change: PROC [control: Control] RETURNS [REAL] ~ {
RETURN[control.value-control.valuePrev];
};
c: Camera ← camera;
c.matrix ← SELECT camera.lastMoused FROM
c.xLocal => Matrix3d.LocalRotate[c.matrix, xAxis, Change[c.xLocal], , , c.matrix],
c.yLocal => Matrix3d.LocalRotate[c.matrix, yAxis, Change[c.yLocal], , , c.matrix],
c.zLocal => Matrix3d.LocalRotate[c.matrix, zAxis, Change[c.zLocal], , , c.matrix],
c.hScreen, c.vScreen => c.matrix,
ENDCASE => ComputeNewMatrix[
[c.x.value, c.y.value, c.z.value],
[c.xGlobal.value, c.yGlobal.value, c.zGlobal.value],
[c.xMove.value, c.yMove.value, c.zMove.value],
c.scale.value,
c.fieldOfView.value,
c.zDistance.value,
c.matrix];
};
UpdateControl: PROC [control: Control, value: REAL] ~ {
IF control.sliderDialRef = NIL
THEN control.value ← value
ELSE Controls.SetSliderDialValue[control, value];
};
UpdateGlobalRotates: PUBLIC PROC [camera: Camera, rotates: Triple] ~ {
UpdateControl[camera.xGlobal, rotates.x];
UpdateControl[camera.yGlobal, rotates.y];
UpdateControl[camera.zGlobal, rotates.z];
UpdateCamera[camera];
};
UpdateLocalRotates: PUBLIC PROC [camera: Camera, rotates: Triple] ~ {
UpdateControl[camera.xLocal, rotates.x];
UpdateControl[camera.yLocal, rotates.y];
UpdateControl[camera.zLocal, rotates.z];
UpdateCamera[camera];
};
UpdateOrigin: PUBLIC PROC [camera: Camera, origin: Triple] ~ {
UpdateControl[camera.xMove, origin.x];
UpdateControl[camera.yMove, origin.y];
UpdateControl[camera.zMove, origin.z];
UpdateCamera[camera];
};
UpdateFieldOfView: PUBLIC PROC [camera: Camera, fieldOfView: REAL] ~ {
UpdateControl[camera.fieldOfView, fieldOfView];
UpdateCamera[camera];
};
UpdateScale: PUBLIC PROC [camera: Camera, scale: REAL] ~ {
UpdateControl[camera.scale, scale];
UpdateCamera[camera];
};
UpdateScreen: PUBLIC PROC [camera: Camera, screen: Pair] ~ {
UpdateControl[camera.hScreen, screen.x];
UpdateControl[camera.vScreen, screen.y];
UpdateCamera[camera];
};
UpdateZDistance: PUBLIC PROC [camera: Camera, zDistance: REAL] ~ {
UpdateControl[camera.zDistance, zDistance];
UpdateCamera[camera];
};
GetCameraMatrix: PUBLIC PROC [camera: Camera] RETURNS [Matrix] ~ {
RETURN[camera.matrix];
};
GetViewMatrix: PUBLIC PROC [camera: Camera, context: Context] RETURNS [Matrix] ~ {
m: Matrix ~ Matrix3d.Translate[
camera.matrix, [camera.hScreen.value, camera.vScreen.value, 0.0]];
RETURN[TransformByViewPort[m, context, camera.view]];
};
GetViewPort: PUBLIC PROC [context: Context] RETURNS [ViewPort] ~ {
rectangle: Imager.Rectangle ~ ImagerBackdoor.GetBounds[context];
xo: INTEGER ← Real.RoundI[rectangle.w]/2;
yo: INTEGER ← Real.RoundI[rectangle.h]/2;
s: REAL ← 0.9*Real.Round[MIN[xo, yo]];
RETURN[[xo, yo, s, s]];
};
TransformByViewPort: PUBLIC PROC [in: Matrix, context: Context, out: Matrix ← NIL]
RETURNS [Matrix] ~ {
v: ViewPort ← GetViewPort[context];
Translate and scale to viewport; don't scale z so can compare z with w for near clipping:
RETURN[Matrix3d.Translate[Matrix3d.DiffScale[in, [v.xs, v.ys, 1.0]], [v.xo, v.yo, 0.0], out]];
};
SetContext3dView: PUBLIC PROC [context3d: Context3d, camera: Camera] ~ {
eyePoint, ptOfInterest: Triple;
m: Matrix ← Matrix3d.Identity[];
This needed to accommodate ThreeDWorld:
fov: REAL ~ IF camera.fieldOfView.value = 0.0 THEN 40.0 ELSE camera.fieldOfView.value;
m ← Matrix3d.Rotate[m, [0.0, 1.0, 0.0], camera.yGlobal.value, , , m];
m ← Matrix3d.Rotate[m, [1.0, 0.0, 0.0], camera.xGlobal.value, , , m];
eyePoint ←
Matrix3d.Transform[[0, 0, -camera.zDistance.value/MAX[.001, camera.scale.value]], m];
ptOfInterest ← [camera.xMove.value, camera.yMove.value, camera.zMove.value];
ptOfInterest ← Vector3d.Add[ptOfInterest, [camera.hScreen.value, camera.vScreen.value, 0.0]];
eyePoint ← Vector3d.Add[eyePoint, ptOfInterest];
ThreeDScenes.SetView[
context3d, eyePoint, ptOfInterest, fov, camera.zGlobal.value];
};
LastAdjustedCamera: PUBLIC PROC RETURNS [Camera] ~ {
RETURN[lastAdjustedCamera];
};
Hold Procedures
InitHold: PUBLIC PROC [proc: ControlProc ← NIL, data: REF ANYNIL] 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.lng ← Controls.NewControl["lng", dial, data, 0.0, 360.0, 0.0, proc];
h.lat ← Controls.NewControl["lat", dial, data, 0.0, 360.0, 0.0, proc];
h.mag ← Controls.NewControl["mag", vSlider, data, -2.0, 2.0, 0.0, proc];
};
FocusHold: PUBLIC PROC [vector: Triple, hold: Hold] ~ {
polar: Triple ← Vector3d.PolarFromCartesian[vector];
Controls.SetSliderDialValue[hold.lng, polar.x];
Controls.SetSliderDialValue[hold.lat, polar.y];
Controls.SetSliderDialValue[hold.mag, polar.z];
Controls.SetSliderDialValue[hold.x, 0.0];
Controls.SetSliderDialValue[hold.y, 0.0];
Controls.SetSliderDialValue[hold.z, 0.0];
};
Miscellaneous Procedures
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];
};
ScreenPick: PUBLIC PROC [
points: TripleSequence, pairs: PairSequence, view: Matrix, mouse: Mouse]
RETURNS [pointPicked: INTEGER] ~ {
dist, max: REAL ← 100000.0;
IF pairs.length < points.length THEN RETURN[-1];
IF pairs.maxLength < pairs.length OR points.maxLength < points.length THEN RETURN[-1];
IF mouse.state = down THEN FOR i: NAT IN[0..points.length) DO
pairs[i] ← Matrix3d.TransformD[points[i], view];
ENDLOOP;
pointPicked ← 0;
FOR i: NAT IN[0..points.length) DO
dx: REAL ← mouse.x-pairs[i].x;
dy: REAL ← mouse.y-pairs[i].y;
IF (dist ← dx*dx+dy*dy) < max THEN {max ← dist; pointPicked ← i};
ENDLOOP;
};
END.
..
GetRenderingMatrix: PUBLIC PROC [camera: Camera] RETURNS [Matrix] ~ {
matrix: Matrix ← NEW[Matrix3d.MatrixRep];
matrix ← IF camera.fov.value = 0.0
THEN Matrix3d.Identity[matrix]
ELSE Matrix3d.MakePerspective[0.1, 0.0, camera.fov.value, matrix];
matrix ← Matrix3d.Identity[matrix];
matrix ← Matrix3d.LocalTranslate[
matrix, [camera.x.value, camera.y.value, 10.0+camera.z.value], matrix];
matrix ← Matrix3d.LocalScale[matrix, camera.scale.value, matrix];
matrix ← Matrix3d.LocalRotate[matrix, [0.0, 1.0, 0.0], camera.yRot.value,,, matrix];
matrix ← Matrix3d.LocalRotate[matrix, [0.0, 0.0, 1.0], camera.zRot.value,,, matrix];
matrix ← Matrix3d.LocalRotate[matrix, [1.0, 0.0, 0.0], camera.xRot.value,,, matrix];
RETURN[matrix];
};