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.