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 <sys/time.h> #import <objc/objc-runtime.h> @interface Animator(private_methods) - (void)_timerFunction:(NSTimer *)theTimer; @end @implementation Animator - (void)_timerFunction:(NSTimer *)theTimer { gettimeofday(&entrytime, NULL); if (howOften > 0.0) { [self adapt]; } [target performSelector:action withObject: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. */ { NSEvent *e, *event; e = (event = [NSApp nextEventMatchingMask:mask untilDate:[NSDate dateWithTimeIntervalSinceNow:0.0] inMode:NSEventTrackingRunLoopMode dequeue:NO]); return (e ? 1: 0); } - setIncrement:(double)dt { adapteddt = dt; interval = dt; return self; } - (double)getIncrement { return adapteddt; } - setAdaptation:(double)oft { howOften = oft; return self; } - (void)setTarget:(id)targ { target = targ; } - (void)setAction:(SEL)aSelector { action = aSelector; } - startEntry { [self stopEntry]; teNum = [[NSTimer timerWithTimeInterval:interval target:self selector:@selector(_timerFunction:) userInfo:nil repeats:YES] retain]; [[NSRunLoop currentRunLoop] addTimer:teNum forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:teNum forMode:NSModalPanelRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:teNum forMode:NSEventTrackingRunLoopMode]; ticking = YES; return self; } - stopEntry { if (ticking) { [teNum invalidate]; [teNum release]; teNum = nil; } ticking = NO; return self; } - (void)dealloc { if (ticking) { [teNum invalidate]; [teNum release]; teNum = nil; } [super dealloc]; return; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.