This is Animator.m in view mode; [Download] [Up]
// 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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.