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 {
Animate.SetSliderDialValue[control, value];
Animate.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 ANY ← NIL]
RETURNS [c: Camera]
~ {
c ← NEW[CameraRec ← [proc: proc, data: data]];
c.matrix ← NEW[Matrix3d.MatrixRec];
c.view ← NEW[Matrix3d.MatrixRec];
c.x ← Animate.NewControl["x", vSlider, c, -10.0, 10.0, origin.x, CameraControlProc];
c.y ← Animate.NewControl["y", vSlider, c, -10.0, 10.0, origin.y, CameraControlProc];
c.z ← Animate.NewControl["z", vSlider, c, -10.0, 10.0, origin.z, CameraControlProc];
c.xGlobal ← Animate.NewControl["xRot", dial, c, 0.0, 360.0, globalRotate.x, CameraControlProc];
c.yGlobal ← Animate.NewControl["yRot", dial, c, 0.0, 360., globalRotate.y, CameraControlProc];
c.zGlobal ← Animate.NewControl["zRot", dial, c, 0.0, 360.0, globalRotate.z, CameraControlProc];
c.xLocal ← Animate.NewControl["xLcl", dial, c, 0.0, 360.0, localRotate.x, CameraControlProc];
c.yLocal ← Animate.NewControl["yLcl", dial, c, 0.0, 360.0, localRotate.y, CameraControlProc];
c.zLocal ← Animate.NewControl["zLcl", dial, c, 0.0, 360.0, localRotate.z, CameraControlProc];
c.xMove ← Animate.NewControl["xMv", vSlider, c, -10.0, 10.0, move.x, CameraControlProc];
c.yMove ← Animate.NewControl["yMv", vSlider, c, -10.0, 10.0, move.y, CameraControlProc];
c.zMove ← Animate.NewControl["zMv", vSlider, c, -10.0, 10.0, move.z, CameraControlProc];
c.scale ← Animate.NewControl["scale", , c, 0, 100, scale, CameraControlProc,,,,,,,,,,,, exp];
c.fieldOfView ← Animate.NewControl["fov", vSlider, c, 0, 100,fieldOfView,CameraControlProc];
c.hScreen ← Animate.NewControl["xScr", vSlider, c, -2, 2, screenMove.x, CameraControlProc];
c.vScreen ← Animate.NewControl["yScr", vSlider, c, -2, 2, screenMove.y, CameraControlProc];
c.zDistance ← Animate.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 Animate.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
ANY ←
NIL]
RETURNS [h: Hold] ~ {
h ← NEW[HoldRec];
h.x ← Animate.NewControl["ptx", vSlider, data, -1.0, 1.0, 0.0, proc];
h.y ← Animate.NewControl["pty", vSlider, data, -1.0, 1.0, 0.0, proc];
h.z ← Animate.NewControl["ptz", vSlider, data, -1.0, 1.0, 0.0, proc];
h.lng ← Animate.NewControl["lng", dial, data, 0.0, 360.0, 0.0, proc];
h.lat ← Animate.NewControl["lat", dial, data, 0.0, 360.0, 0.0, proc];
h.mag ← Animate.NewControl["mag", vSlider, data, -2.0, 2.0, 0.0, proc];
};
FocusHold:
PUBLIC
PROC [vector: Triple, hold: Hold] ~ {
polar: Triple ← Vector3d.PolarFromCartesian[vector];
Animate.SetSliderDialValue[hold.lng, polar.x];
Animate.SetSliderDialValue[hold.lat, polar.y];
Animate.SetSliderDialValue[hold.mag, polar.z];
Animate.SetSliderDialValue[hold.x, 0.0];
Animate.SetSliderDialValue[hold.y, 0.0];
Animate.SetSliderDialValue[hold.z, 0.0];
};
..