(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* by Steve Glassman and Stephen Harrison *) (* Last modified on Wed Jan 13 09:10:11 PST 1993 by steveg *) (* modified on Fri Jul 17 19:10:08 PDT 1992 by harrison *) (* modified on Thu Jul 9 18:35:53 1992 by mhb *) INTERFACE Animate; <* PRAGMA LL *> IMPORT List, MG, MGV, R2, RealPath; TYPE TimeFunction = OBJECT METHODS <* LL = {v.mu} *> map (t: REAL): REAL; (* map range [0.0, 1.0] onto itself *) END; (* A TimeFunction controls the rate of change within an animation. An animation moves uniformly through the values 0.0 to 1.0 for t. TimeFunction.map adjusts t to have a different behaviour. *) TimeDiscrete <: TimeDiscretePublic; TimeDiscretePublic = TimeFunction OBJECT <* LL = {v.mu} *> values: REF ARRAY OF RECORD step : REAL; value: REAL END; END; (* A TimeDiscrete.map(t) returns TimeDiscrete.values[i].value where i is the first TDiscrete.values[i].step >= t. *) TimeStep <: TimeStepPublic; TimeStepPublic = TimeFunction OBJECT <* LL = {v.mu} *> steps := 1; END; (* A TimeState.map(t) returns FLOOR(t * steps) / steps *) VAR tfZero : TimeFunction; (* tfLinear.map(t) returns 0.0 *) tfOne : TimeFunction; (* tfLinear.map(t) returns 1.0 *) tfLinear : TimeFunction; (* tfLinear.map(t) returns t *) tfInverse: TimeFunction; (* tfInverse.map(t) returns 1.0 - t *) TYPE T = MGV.AnimateT; REVEAL T <: TPublic; TYPE TPublic = OBJECT <* LL = {v.mu} *> tf: TimeFunction := NIL; (* NIL => tfLinear *) METHODS <* LL < v.mu *> init (tf: TimeFunction := NIL): T; (* Default assigns tfLinear to "tf" if NIL *) <* LL <= VBT.mu *> start(v: MG.V); end(v: MG.V); length(v: MG.V; mg: MG.T): INTEGER; (* number of animation steps *) <* LL <= VBT.mu *> doStep (time, timePrev: REAL; v: MG.V; mg: MG.T); (* Do a step in the animation from "timePrev" to "time". "time" and "timePrev"have already been transformed by self.tf.map. "time" may be greater than, equal to or less than "timePrev" *) END; TYPE Composite = OBJECT t: T; mg: MG.T END; TYPE Group = MGV.AnimateGroup; REVEAL Group <: GroupPublic; TYPE GroupPublic = T OBJECT elems: List.T := NIL; (* list of "Composite"s *) METHODS (* must call init method *) <* LL = {v.mu} *> add(v: MG.V; composite: Composite); remove(v: MG.V; composite: Composite); iterate(gi: GroupIterator): BOOLEAN; END; TYPE GroupIterator = OBJECT v: MG.V; METHODS proc(comp: Composite): BOOLEAN; END; <* LL < v.mu for following procedures *> PROCEDURE AddToGroup(g: Group; v: MG.V; comp: Composite); PROCEDURE RemoveFromGroup(g: Group; v: MG.V; comp: Composite); PROCEDURE IterateGroup(g: Group; v: MG.V; iter: GroupIterator): BOOLEAN; TYPE (* Animation effects *) Linear <: LinearPublic; LinearPublic = T OBJECT <* LL = {v.mu} *> (* READONLY use methods to set *) vector: R2.T; METHODS (* must call init method *) <* LL = {v.mu} *> setVector(v: MG.V; READONLY vector: R2.T) END; Rotate <: RotatePublic; RotatePublic = T OBJECT <* LL = {v.mu} *> (* READONLY use methods to set *) origin: R2.T; angle: REAL; (* degrees *) METHODS (* must call init method *) <* LL = {v.mu} *> setRotate(v: MG.V; READONLY origin: R2.T; angle: REAL); END; (* rotate "angle" degrees around "origin" clockwise *) Scale <: ScalePublic; ScalePublic = T OBJECT <* LL = {v.mu} *> (* READONLY use methods to set *) wrt: R2.T; factor: R2.T; METHODS (* must call init method *) <* LL = {v.mu} *> setScale(v: MG.V; READONLY wrt, factor: R2.T); END; (* "wrt" remains constant in the animation *) Path = RealPath.T; Translate <: TranslatePublic; TranslatePublic = T OBJECT <* LL = {v.mu} *> (* READONLY use methods to set *) path: Path; METHODS (* must call init method *) <* LL = {v.mu} *> setTranslate(v: MG.V; path: Path); END; Weight <: WeightPublic; WeightPublic = T OBJECT <* LL = {v.mu} *> (* READONLY use methods to set *) delta: REAL; METHODS (* must call init method *) <* LL = {v.mu} *> setWeightDelta(v: MG.V; delta: REAL); END; Highlight <: HighlightPublic; HighlightPublic = T OBJECT (* must call init method *) END; (* length = 30 *) Visibility <: VisibilityPublic; VisibilityPublic = T OBJECT (* must call init method *) END; (* length = 30 *) PROCEDURE Do(t: T; mg: MG.T; v: MG.V; duration := 1.0); (* call t.doStep(t.tf.map(time), v, mg) where time increases (roughly linearly) from 0.0 to 1.0 so that the animation takes duration seconds. If "duration" = 0.0 then only the last scene (time = 1.0) of the animation occurs. t.start is called at the start of the animation and t.end is called at the end. LL <= VBT.mu *) PROCEDURE Undo(t: T; mg: MG.T; v: MG.V; duration := 1.0); (* call t.doStep(t.tf.map(time), v, mg) where time decreases (roughly linearly) from 1.0 to 0.0 so that the animation takes duration seconds. If "duration" = 0.0 then only the last scene (time = 0.0) of the animation occurs. t.start is called at the start of the animation and t.end is called at the end. LL <= VBT.mu *) (* Animations are kept semi-synchronous by maintaining a global "animation time" based on real time. Animation time is the real time that has taken place, scaled by the current animation speed. Each active animation calls "ATime" to determine the current time of the animation to display. Clients should call ResetAnimationTime at appropriate intervals between animations. A call to Animate.Do/Undo without an intervening "ResetATime" will only display the final scene of the animation. Calling ResetATime or SetDuration during an animation will have undefined results. *) <* LL = Arbitrary *> PROCEDURE ATime(): REAL; (* Returns the current animation time. *) PROCEDURE ResetATime(); (* Resets animation time to 0. *) PROCEDURE SetDuration(seconds: REAL); (* Makes 1 second of animation time last "seconds" seconds of real time *) END Animate.