home *** CD-ROM | disk | FTP | other *** search
- // Animator.m
- // Object for general timing, animation, and dynamics.
- // Author: R. E. Crandall, Educational Technology Center
- // 10-Apr-88
- // Revised by Bluce Blumberg for 0.8, 29-Sep-88
- // Revised for 1.0 by Ali Ozer, 13-Jun-89
- // Revised for 2.0 by Jayson Adams, 14-Oct-90
- //
- // You may freely copy, distribute and reuse the code in this example.
- // NeXT disclaims any warranty of any kind, expressed or implied, as to its
- // fitness for any particular use.
-
- /*
- * An 'Animator' controls the timing for your action method of choice.
- * The object may function as a general timer object; i.e.
- * graphics are neither expected nor required by the class.
- * When you create an Animator with +newChronon, you specify
- * the time interval between calls, the adaptation time constant (see below),
- * the target to which the method belongs, the action name, whether to
- * automatically start up the timing upon creation, and an event mask (if you
- * plan to break conditionally out of loops within the action method).
- *
- * The Animator has adaptive means for adjusting to harsh operating
- * environments. An adaptation constant d > 0. will invoke dynamical
- * correction of entry times, on-the-fly, so that the desired chronon
- * will be realized in a real-time sense.
- *
- * Functionality and applications are discussed in Report ETC-0008.
- */
-
- #import "Animator.h"
-
- #import <appkit/Application.h>
- #import <sys/time.h>
- #import <objc/objc-runtime.h>
-
-
- @implementation Animator
-
- void timerFunction(teNum, now, self)
- DPSTimedEntry teNum;
- double now;
- Animator *self;
- {
- gettimeofday(&self->entrytime, NULL);
- if (self->howOften > 0.0) {
- [self adapt];
- }
-
- [self->target perform:self->action with:self];
- }
-
- - initChronon:(double)dt /* The time increment desired. */
- adaptation:(double)howoft /* Adaptive time constant (0.deactivates).*/
- target:(id)targ /* Target to whom proc belongs. */
- action:(SEL)act /* The action. */
- autoStart:(int)start /* Automatic start of timed entry? */
- eventMask:(int)eMask /* Mask for optional check in "shouldBreak". */
- {
- [super init];
- ticking = NO;
- desireddt = dt;
- [self setIncrement:dt];
- [self setAdaptation:howoft];
- [self setTarget:targ];
- [self setAction:act];
-
- if (start) {
- [self startEntry];
- }
-
- mask = eMask;
- [self resetRealTime];
-
- return self;
- }
-
- - resetRealTime
- /* After this call, getDoubleRealTime is the real time that ensues. */
- {
- struct timeval realtime;
-
- gettimeofday(&realtime, NULL);
- synctime = realtime.tv_sec + realtime.tv_usec / 1000000.0;
- passcounter = 0;
- t0 = 0.0;
-
- return self;
- }
-
- - (double)getSyncTime
- {
- return synctime;
- }
-
- - (double)getDoubleEntryTime
- /* Returns real time since "resetrealTime". */
- {
- return (- synctime + entrytime.tv_sec + entrytime.tv_usec / 1000000.0);
- }
-
- - (double)getDoubleRealTime
- /* Returns real time since "resetrealTime". */
- {
- struct timeval realtime;
- struct timezone tzone;
-
- gettimeofday(&realtime, &tzone);
- return (- synctime + realtime.tv_sec + realtime.tv_usec / 1000000.0);
- }
-
- - (double)getDouble
- {
- return [self getDoubleRealTime];
- }
-
- - adapt
- /* Adaptive time-step algorithm. */
- {
- double t;
-
- if (!ticking) {
- return self;
- }
-
- ++passcounter;
- t = [self getDoubleEntryTime];
-
- if (t - t0 >= howOften) {
- adapteddt *= desireddt * passcounter / (t - t0);
- [self setIncrement:adapteddt];
- [self startEntry];
- passcounter = 0;
- t0 = t;
- }
- return self;
- }
-
- - setBreakMask:(int)eventMask
- {
- mask = eventMask;
- return self;
- }
-
- - (int)getBreakMask
- {
- return mask;
- }
-
- - (int)isTicking
- {
- return ticking;
- }
-
- - (int)shouldBreak
- /* Call this to see if you want to exit a loop in your action method. */
- {
- NXEvent *e, event;
-
- e = [NXApp peekNextEvent:mask
- into:&event
- waitFor:0.0
- threshold:NX_MODALRESPTHRESHOLD + 1];
-
- return (e ? 1: 0);
- }
-
- - setIncrement:(double)dt
- {
- adapteddt = dt;
- interval = dt;
-
- return self;
- }
-
- - (double)getIncrement
- {
- return adapteddt;
- }
-
- - setAdaptation:(double)oft
- {
- howOften = oft;
- return self;
- }
-
- - setTarget:(id)targ
- {
- target = targ;
- return self;
- }
-
- - setAction:(SEL)aSelector
- {
- action = aSelector;
- return self;
- }
-
- - startEntry
- {
- [self stopEntry];
- teNum = DPSAddTimedEntry(interval, &timerFunction, self,
- NX_MODALRESPTHRESHOLD+1);
- ticking = YES;
-
- return self;
- }
-
- - stopEntry
- {
- if (ticking) {
- DPSRemoveTimedEntry(teNum);
- }
- ticking = NO;
-
- return self;
- }
-
- - free
- {
- if (ticking) {
- DPSRemoveTimedEntry(teNum);
- }
-
- return [super free];
- }
-
- @end
-