Animation3DImpl.mesa
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
EXPORTS Animation3D
~ BEGIN
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 ANYNIL ] 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: INTEGERNARROW[ 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[LORALIST[ 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 ANYNIL] RETURNS[REF ShapeInstance]
Translates texture coordinates over sequence of frames
frameNumber: NAT ← context.frameNumber;
list: LORANARROW[GetProp[shape.shadingProps, $ShapeLerp] ];
begin: REF ShapeInstance ← NARROW[list.first];
end: REF ShapeInstance ← NARROW[list.rest.first];
lastFrame: NATNARROW[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 ];
};
END.