Copyright © 1984 by Xerox Corporation. All rights reserved.
Last Edited by: Crow, February 8, 1988 5:03:07 pm PST
Bloomenthal, September 14, 1988 1:05:33 pm PDT
DIRECTORY
Atom USING [ GetPropFromList, PropList, PutPropOnList ],
Real USING [ Fix, Float ],
Rope USING [ ROPE ],
G3dMatrix USING [ Transform, MakeRotate ],
G3dSpline USING [ CoeffsSequence, Interpolate, InterpolateCyclic, Position ],
ThreeDBasics USING [ Context, Error, Pair, PairSequence, ShapeInstance, ShapeProc,
Triple, TripleSequence, VertexInfoProc ],
SceneUtilities USING [ FindShape ],
Animation3D USING [ ViewProc ];
Animation3DImpl:
CEDAR
PROGRAM
IMPORTS Atom, G3dMatrix, G3dSpline, Real, SceneUtilities, ThreeDBasics
Basic Types
Context: TYPE ~ ThreeDBasics.Context;
Pair: TYPE ~ ThreeDBasics.Pair;
PairSequence: TYPE ~ ThreeDBasics.PairSequence;
Triple: TYPE ~ ThreeDBasics.Triple; -- RECORD [ x, y, z: REAL];
TripleSequence: TYPE ~ ThreeDBasics.TripleSequence;
ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance;
ViewProc: TYPE ~ Animation3D.ViewProc;
LORA: TYPE ~ LIST OF REF ANY;
Renamed Procedures
GetProp: PROC [propList: Atom.PropList, prop: REF ANY] RETURNS [REF ANY] ~
Atom.GetPropFromList;
PutProp: PROC [propList: Atom.PropList, prop: REF ANY, val: REF ANY]
RETURNS [Atom.PropList] ~ Atom.PutPropOnList;
Procedures for Animation
MoveEyePointInOrbit:
PUBLIC
PROC[ context:
REF Context,
eyePt, lookingAt, axis, base: Triple,
displayProc: ViewProc,
framesPerRev:
NAT, startAt, endAt:
NAT ← 0 ] ~ {
theta: REAL ← 360. / framesPerRev;
currentEyePt: Triple;
FOR i:
NAT
IN [startAt .. endAt]
DO
IF context.stopMe^ THEN RETURN[];
currentEyePt ← G3dMatrix.Transform[
eyePt,
G3dMatrix.MakeRotate[
axis: axis,
theta: theta * i,
base: base
]
];
Call display procedure
context.frameNumber ← i;
displayProc[ context, currentEyePt, lookingAt, context.frameNumber ];
ENDLOOP;
context.frameNumber ← 0;
};
MoveCtrOfInterestInOrbit:
PUBLIC
PROC[ context:
REF Context,
eyePt, lookingAt, axis, base: Triple,
displayProc: ViewProc,
framesPerRev:
NAT,
startAt, endAt:
NAT ← 0 ] ~ {
theta: REAL ← 360. / framesPerRev;
currentLookingAt: Triple;
FOR i:
NAT
IN [startAt .. endAt]
DO
IF context.stopMe^ THEN RETURN[];
currentLookingAt ← G3dMatrix.Transform[
lookingAt,
G3dMatrix.MakeRotate[
axis: axis,
theta: theta * i,
base: base
]
];
Call display procedure
context.frameNumber ← i;
displayProc[ context, eyePt, currentLookingAt, context.frameNumber ];
ENDLOOP;
context.frameNumber ← 0;
};
MoveOnLine:
PUBLIC
PROC[ context:
REF Context,
eyePt, lookingAt, toEyePt, toLookingAt: Triple,
displayProc: ViewProc,
framesOnLine:
NAT, startAt, endAt:
NAT ← 0 ] ~ {
currentEyePt, currentLookingAt: Triple;
FOR i:
NAT
IN [startAt .. endAt]
DO
IF context.stopMe^ THEN RETURN[];
currentEyePt.x ← eyePt.x + (toEyePt.x - eyePt.x) * i / (framesOnLine-1);
currentEyePt.y ← eyePt.y + (toEyePt.y - eyePt.y) * i / (framesOnLine-1);
currentEyePt.z ← eyePt.z + (toEyePt.z - eyePt.z) * i / (framesOnLine-1);
currentLookingAt.x ← lookingAt.x + (toLookingAt.x - lookingAt.x) * i / (framesOnLine-1);
currentLookingAt.y ← lookingAt.y + (toLookingAt.y - lookingAt.y) * i /(framesOnLine-1);
currentLookingAt.z ← lookingAt.z + (toLookingAt.z - lookingAt.z) * i / (framesOnLine-1);
context.frameNumber ← i;
displayProc[ context, currentEyePt, currentLookingAt, context.frameNumber ];
ENDLOOP;
context.frameNumber ← 0;
};
MoveOnOpenCurve:
PUBLIC
PROC[ context:
REF Context,
eyePts, lookingAts:
REF TripleSequence,
displayProc: ViewProc,
framesOnCurve:
NAT, startAt, endAt:
NAT ← 0 ] ~ {
currentEyePt, currentLookingAt: REF TripleSequence;
epCoeffs: G3dSpline.CoeffsSequence ← G3dSpline.Interpolate[eyePts];
ciCoeffs: G3dSpline.CoeffsSequence ← G3dSpline.Interpolate[lookingAts];
currentEyePt ← ExpandCurve[epCoeffs, framesOnCurve];
currentLookingAt ← ExpandCurve[ciCoeffs, framesOnCurve];
IF context.stopMe^ THEN RETURN[];
FOR i:
NAT
IN [startAt .. endAt]
DO
j: NAT ← i MOD framesOnCurve;
context.frameNumber ← i;
displayProc[ context, currentEyePt[j], currentLookingAt[j], context.frameNumber ];
ENDLOOP;
context.frameNumber ← 0;
};
MoveOnClosedCurve:
PUBLIC
PROC[ context:
REF Context,
eyePts, lookingAts:
REF TripleSequence,
displayProc: ViewProc,
framesOnCurve:
NAT, startAt, endAt:
NAT ← 0 ] ~ {
currentEyePt, currentLookingAt: REF TripleSequence;
epCoeffs: G3dSpline.CoeffsSequence ← G3dSpline.InterpolateCyclic[eyePts];
ciCoeffs: G3dSpline.CoeffsSequence ← G3dSpline.InterpolateCyclic[lookingAts];
currentEyePt ← ExpandCurve[epCoeffs, framesOnCurve];
currentLookingAt ← ExpandCurve[ciCoeffs, framesOnCurve];
FOR i:
NAT
IN [startAt .. endAt]
DO
j: NAT ← i MOD framesOnCurve;
IF context.stopMe^ THEN RETURN[];
context.frameNumber ← i;
displayProc[ context, currentEyePt[j], currentLookingAt[j], context.frameNumber ];
ENDLOOP;
context.frameNumber ← 0;
};
ExpandCurve:
PROC[coeffs: G3dSpline.CoeffsSequence, numFrames:
NAT]
RETURNS[
REF TripleSequence] ~ {
points: REF TripleSequence ← NEW[TripleSequence[numFrames]];
framesPerSeg: REAL ← Real.Float[numFrames - 1] / (coeffs.length);
FOR i:
NAT
IN [0..numFrames - 1)
DO
t: REAL ← i / framesPerSeg; -- distance, in segments, along curve
seg: NAT ← Real.Fix[t]; -- segment
t ← t - seg; -- position in segment
points[i] ← G3dSpline.Position[coeffs[seg], t];
ENDLOOP;
points[numFrames - 1] ← G3dSpline.Position[coeffs[coeffs.length - 1], 1.0];
points.length ← numFrames;
RETURN[points];
};
Procedures for Viewing Trajectories
ShowOpenCurve:
PUBLIC PROC[ context: Context, eyePts, lookingAts:
REF TripleSequence,
numFrames:
NAT, startAt:
NAT ← 0
] ~ {
SIGNAL ThreeDBasics.Error[[$Unimplemented, "Sorry, ask Frank for an implementation"]];
};
ShowClosedCurve:
PUBLIC PROC[ context: Context, eyePts, lookingAts:
REF TripleSequence,
numFrames:
NAT, startAt:
NAT ← 0
] ~ {
SIGNAL ThreeDBasics.Error[[$Unimplemented, "Sorry, ask Frank for an implementation"]];
};
ShowOrbit:
PUBLIC PROC[ context: Context, startPt, axis, base: Triple, framesPerRev:
NAT ] ~ {
Adds description of path to data for current scene, will be displayed just like any other shape. "Trajectory" is name given to resulting ShapeInstance.
SIGNAL ThreeDBasics.Error[[$Unimplemented, "Sorry, ask Frank for an implementation"]];
};
Procedures for Texture Animation
SetTxtrTranslation:
PUBLIC
PROC[ context:
REF Context, shapeName: Rope.
ROPE,
translation: Pair, frames:
NAT ] ~{
Sets up translation by [translation.x, translation.y] over "frames" frames
shape: REF ShapeInstance ← SceneUtilities.FindShape[context, shapeName];
translation.x ← translation.x / frames;
translation.y ← translation.y / frames;
shape.shadingProps ← PutProp[
shape.shadingProps, $TxtrTranslation, NEW[Pair ← translation]
];
shape.shadingClass.loadVtxAux ← LoadTranslatedTxtrCoords;
};
LoadTranslatedTxtrCoords: ThreeDBasics.VertexInfoProc ~ {
-- load aux field in vtx
PROC[ context: REF Context, vtx: REF VertexInfo, data: REF ANY ← NIL ] RETURNS[REF VertexInfo];
frameNumber: NAT ← context.frameNumber;
shape: REF ShapeInstance ← NARROW[ Atom.GetPropFromList[vtx.props, $Shape] ];
txtrIncr: REF Pair ← NARROW[GetProp[shape.shadingProps, $TxtrTranslation] ];
vtxAux: REF Pair ← NEW[Pair];
WITH data
SELECT
FROM
input:
LORA => {
auxInfo: REF PairSequence ← NARROW[ input.first ];
index: INTEGER ← NARROW[ input.rest.first, REF INTEGER ]^;
vtxAux.x ← auxInfo[index].x + txtrIncr.x * frameNumber; -- texture coords
vtxAux.y ← auxInfo[index].y + txtrIncr.y * frameNumber;
};
txtr:
REF Pair => {
vtxAux.x ← txtr.x + txtrIncr.x * frameNumber;
vtxAux.y ← txtr.y + txtrIncr.y * frameNumber;
};
ENDCASE => SIGNAL ThreeDBasics.Error[[$Unimplemented, "Unrecognized type"]];
vtx.aux ← vtxAux;
RETURN[ vtx ];
};
Procedures for Shape Interpolation
SetShapeInterpolation:
PUBLIC
PROC[ context:
REF Context, shapeName: Rope.
ROPE,
begin, end:
REF ShapeInstance, frames:
NAT ] ~{
Sets up translation by [translation.x, translation.y] over "frames" frames
shape: REF ShapeInstance ← SceneUtilities.FindShape[context, shapeName];
shape.shadingProps ← PutProp[
shape.shadingProps, $ShapeLerp,
NEW[LORA ← LIST[ begin, end, NEW[ NAT ← frames] ] ]
];
shape.class.doBeforeFrame ← CONS[LerpShape, shape.class.doBeforeFrame];
};
LerpShape: ThreeDBasics.ShapeProc ~ {
PROC[context: REF Context, shape: REF ShapeInstance, data: REF ANY ← NIL] RETURNS[REF ShapeInstance]
Translates texture coordinates over sequence of frames
frameNumber: NAT ← context.frameNumber;
list: LORA ← NARROW[GetProp[shape.shadingProps, $ShapeLerp] ];
begin: REF ShapeInstance ← NARROW[list.first];
end: REF ShapeInstance ← NARROW[list.rest.first];
lastFrame: NAT ← NARROW[list.rest.rest.first, REF NAT]^;
alpha: REAL ← 1.0 * frameNumber / lastFrame;
FOR i:
NAT
IN [0..shape.vertex.length)
DO
shape.vertex[i].x ← begin.vertex[i].x + alpha * (end.vertex[i].x -begin.vertex[i].x);
shape.vertex[i].y ← begin.vertex[i].y + alpha * (end.vertex[i].y -begin.vertex[i].y);
shape.vertex[i].z ← begin.vertex[i].z + alpha * (end.vertex[i].z -begin.vertex[i].z);
ENDLOOP;
FOR i:
NAT
IN [0..shape.shade.length)
DO
shape.shade[i].r ← begin.shade[i].r + alpha * (end.shade[i].r -begin.shade[i].r);
shape.shade[i].g ← begin.shade[i].g + alpha * (end.shade[i].g -begin.shade[i].g);
shape.shade[i].b ← begin.shade[i].b + alpha * (end.shade[i].b -begin.shade[i].b);
ENDLOOP;
shape.shadingInValid ← TRUE;
RETURN[shape];
};
Procedure for Registering Shape Manipulation Procedures for Animation
SetShapeManipulation:
PUBLIC
PROC[ context:
REF Context, shapeName: Rope.
ROPE,
prop, propVal:
REF
ANY,
proc: ThreeDBasics.ShapeProc ] ~ {
Way of registering procedure to be called to modify shape before each frame
shape: REF ShapeInstance ← SceneUtilities.FindShape[context, shapeName];
shape.shadingProps ← PutProp[ shape.shadingProps, prop, propVal ];
shape.class.doBeforeFrame ← CONS[ proc, NIL ];
};
AddShapeManipulation:
PUBLIC
PROC[ context:
REF Context, shapeName: Rope.
ROPE,
prop, propVal:
REF
ANY,
proc: ThreeDBasics.ShapeProc ] ~ {
Way of registering procedure to be called to modify shape before each frame
shape: REF ShapeInstance ← SceneUtilities.FindShape[context, shapeName];
shape.shadingProps ← PutProp[ shape.shadingProps, prop, propVal ];
shape.class.doBeforeFrame ← CONS[ proc, shape.class.doBeforeFrame ];
};