bzr branch
/browse/iphone/common
| Line | Revision | Contents |
| 1 | 25 | // |
| 2 | // ElAnimation.m |
|
| 3 | // Jigs |
|
| 4 | // |
|
| 5 | // Created by döme on 11.08.2009. |
|
| 6 | // Copyright 2009 __MyCompanyName__. All rights reserved. |
|
| 7 | // |
|
| 8 | ||
| 9 | #import "ElAnimation.h" |
|
| 10 | ||
| 11 | #import <mach/mach_time.h> |
|
| 12 | #import "geometry.h" |
|
| 13 | ||
| 14 | float linearInterpolation(float a, float b, float t) |
|
| 15 | { |
|
| 16 | return a + t*(b-a); |
|
| 17 | } |
|
| 18 | ||
| 19 | float easyOutInterpolation(float a, float b, float t) |
|
| 20 | { |
|
| 21 | return a + t*t*(b-a); |
|
| 22 | } |
|
| 23 | ||
| 24 | float easyInInterpolation(float a, float b, float t) |
|
| 25 | { |
|
| 26 | float x = t-1.0f; |
|
| 27 | return a + (1.0f - x*x)*(b-a); |
|
| 28 | } |
|
| 29 | ||
| 30 | float smoothInterpolation(float a, float b, float t) |
|
| 31 | { |
|
| 32 | return a + (3*t*t - 2*t*t*t)*(b-a); |
|
| 33 | } |
|
| 34 | ||
| 35 | @interface ElAnimationController : NSObject |
|
| 36 | { |
|
| 37 | 27 | NSMutableDictionary* queuedAnimations; |
| 38 | 25 | NSTimeInterval lastTime; |
| 39 | 27 | |
| 40 | 25 | mach_timebase_info_data_t timebase; |
| 41 | uint64_t machTimingStart; |
|
| 42 | } |
|
| 43 | + (ElAnimationController*) sharedController; |
|
| 44 | ||
| 45 | 27 | - (void) queueAnimation: (ElAnimation*) anim forKey: (id) key atBeginning: (BOOL) atBegin cancelPending: (BOOL) cancelPending; |
| 46 | 25 | - (NSTimeInterval) now; |
| 47 | ||
| 48 | @end; |
|
| 49 | ||
| 50 | ||
| 51 | @implementation ElAnimation |
|
| 52 | ||
| 53 | 27 | - (void) queueForKey: (NSString*) key atBeginning: (BOOL) atBeginning cancelPending: (BOOL) cancelPending; |
| 54 | 25 | { |
| 55 | 27 | [[ElAnimationController sharedController] queueAnimation: self forKey: key atBeginning: atBeginning cancelPending: cancelPending]; |
| 56 | 25 | } |
| 57 | ||
| 58 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) deltaTime |
|
| 59 | { |
|
| 60 | if (time > startTime + duration) |
|
| 61 | return NO; |
|
| 62 | else |
|
| 63 | return YES; |
|
| 64 | } |
|
| 65 | ||
| 66 | + (NSTimeInterval) now |
|
| 67 | { |
|
| 68 | return [[ElAnimationController sharedController] now]; |
|
| 69 | } |
|
| 70 | ||
| 71 | 27 | - (void) setStartTime: (NSTimeInterval) time |
| 72 | { |
|
| 73 | startTime = time; |
|
| 74 | } |
|
| 75 | - (NSTimeInterval) startTime |
|
| 76 | { |
|
| 77 | return startTime; |
|
| 78 | } |
|
| 79 | ||
| 80 | + (ElAnimation*) delayedAnimationWithDelay: (float) seconds |
|
| 81 | { |
|
| 82 | ElAnimation* anim = [[[ElAnimation alloc] init] autorelease]; |
|
| 83 | [anim setDuration: seconds]; |
|
| 84 | return anim; |
|
| 85 | } |
|
| 86 | ||
| 87 | @synthesize duration, interpolation; |
|
| 88 | 25 | |
| 89 | @end |
|
| 90 | ||
| 91 | @implementation ElFloatAnimation |
|
| 92 | ||
| 93 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 94 | { |
|
| 95 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 96 | ||
| 97 | double t = fclamp((time - startTime)/duration, 0.0, 1.0); |
|
| 98 | |
|
| 99 | float y = 0.0; |
|
| 100 | switch (interpolation) |
|
| 101 | { |
|
| 102 | case kElLinearInterpolation: |
|
| 103 | y = linearInterpolation(startValue, endValue, t); |
|
| 104 | break; |
|
| 105 | case kElEaseInInterpolation: |
|
| 106 | y = easyInInterpolation(startValue, endValue, t); |
|
| 107 | break; |
|
| 108 | case kElEaseOutInterpolation: |
|
| 109 | y = easyOutInterpolation(startValue, endValue, t); |
|
| 110 | break; |
|
| 111 | case kElSmoothInterpolation: |
|
| 112 | y = smoothInterpolation(startValue, endValue, t); |
|
| 113 | break; |
|
| 114 | } |
|
| 115 | |
|
| 116 | [target setValue: [NSNumber numberWithFloat: y] forKey: property]; |
|
| 117 | ||
| 118 | return result; |
|
| 119 | } |
|
| 120 | ||
| 121 | 27 | - (void) dealloc |
| 122 | { |
|
| 123 | [target release]; |
|
| 124 | [super dealloc]; |
|
| 125 | } |
|
| 126 | 25 | |
| 127 | @synthesize startValue, endValue, target, property; |
|
| 128 | ||
| 129 | @end |
|
| 130 | ||
| 131 | 43 | @implementation ElV3Animation |
| 132 | ||
| 133 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 134 | { |
|
| 135 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 136 | ||
| 137 | double t = fclamp((time - startTime)/duration, 0.0, 1.0); |
|
| 138 | |
|
| 139 | v3 y = vcreate(0.0f, 0.0f, 0.0f); |
|
| 140 | switch (interpolation) |
|
| 141 | { |
|
| 142 | case kElLinearInterpolation: |
|
| 143 | y.v.x = linearInterpolation(startv.v.x, endv.v.x, t); |
|
| 144 | y.v.y = linearInterpolation(startv.v.y, endv.v.y, t); |
|
| 145 | y.v.z = linearInterpolation(startv.v.z, endv.v.z, t); |
|
| 146 | break; |
|
| 147 | case kElEaseInInterpolation: |
|
| 148 | y.v.x = easyInInterpolation(startv.v.x, endv.v.x, t); |
|
| 149 | y.v.y = easyInInterpolation(startv.v.y, endv.v.y, t); |
|
| 150 | y.v.z = easyInInterpolation(startv.v.z, endv.v.z, t); |
|
| 151 | break; |
|
| 152 | case kElEaseOutInterpolation: |
|
| 153 | y.v.x = easyOutInterpolation(startv.v.x, endv.v.x, t); |
|
| 154 | y.v.y = easyOutInterpolation(startv.v.y, endv.v.y, t); |
|
| 155 | y.v.z = easyOutInterpolation(startv.v.z, endv.v.z, t); |
|
| 156 | break; |
|
| 157 | case kElSmoothInterpolation: |
|
| 158 | y.v.x = smoothInterpolation(startv.v.x, endv.v.x, t); |
|
| 159 | y.v.y = smoothInterpolation(startv.v.y, endv.v.y, t); |
|
| 160 | y.v.z = smoothInterpolation(startv.v.z, endv.v.z, t); |
|
| 161 | break; |
|
| 162 | } |
|
| 163 | |
|
| 164 | [target performSelector: setter withObject: (void*)&y]; |
|
| 165 | ||
| 166 | return result; |
|
| 167 | } |
|
| 168 | ||
| 169 | - (void) dealloc |
|
| 170 | { |
|
| 171 | [target release]; |
|
| 172 | [super dealloc]; |
|
| 173 | } |
|
| 174 | ||
| 175 | @synthesize startv, endv, target, setter; |
|
| 176 | ||
| 177 | @end |
|
| 178 | ||
| 179 | ||
| 180 | 25 | @implementation ElAnimationController |
| 181 | ||
| 182 | - (id) init |
|
| 183 | { |
|
| 184 | if (!(self = [super init])) |
|
| 185 | return nil; |
|
| 186 | ||
| 187 | 27 | queuedAnimations = [[NSMutableDictionary alloc] init]; |
| 188 | 25 | |
| 189 | mach_timebase_info(&timebase); |
|
| 190 | machTimingStart = mach_absolute_time(); |
|
| 191 | ||
| 192 | return self; |
|
| 193 | } |
|
| 194 | ||
| 195 | - (NSTimeInterval) currentTime |
|
| 196 | { |
|
| 197 | uint64_t mtime = mach_absolute_time(); |
|
| 198 | |
|
| 199 | uint64_t elapsed = mtime - machTimingStart; |
|
| 200 | |
|
| 201 | return (NSTimeInterval)((elapsed*timebase.numer)/timebase.denom)*1e-9; |
|
| 202 | } |
|
| 203 | ||
| 204 | + (id) sharedController |
|
| 205 | { |
|
| 206 | static ElAnimationController* sharedController = nil; |
|
| 207 | if (!sharedController) |
|
| 208 | sharedController = [[ElAnimationController alloc] init]; |
|
| 209 | return sharedController; |
|
| 210 | } |
|
| 211 | ||
| 212 | - (void) timerCallback |
|
| 213 | { |
|
| 214 | NSTimeInterval time = [self currentTime]; |
|
| 215 | NSTimeInterval delta = time - lastTime; |
|
| 216 | |
|
| 217 | // NSLog(@"%f %f", time, delta); |
|
| 218 | |
|
| 219 | 27 | NSMutableArray* keysToRemove = [NSMutableArray array]; |
| 220 | for (id key in queuedAnimations) |
|
| 221 | 25 | { |
| 222 | 27 | NSMutableArray* animArray = [queuedAnimations objectForKey: key]; |
| 223 | if (![animArray count]) |
|
| 224 | { |
|
| 225 | [keysToRemove addObject: key]; |
|
| 226 | continue; |
|
| 227 | } |
|
| 228 | |
|
| 229 | ElAnimation* anim = [animArray objectAtIndex: 0]; |
|
| 230 | |
|
| 231 | if ([anim startTime] == 0.0) |
|
| 232 | [anim setStartTime: lastTime]; |
|
| 233 | |
|
| 234 | [anim animateForTime: time delta: delta]; |
|
| 235 | ||
| 236 | if ([anim startTime] + [anim duration] < time) |
|
| 237 | { |
|
| 238 | [animArray removeObjectAtIndex: 0]; |
|
| 239 | //NSLog(@"dequeued animation"); |
|
| 240 | } |
|
| 241 | 25 | } |
| 242 | 27 | [queuedAnimations removeObjectsForKeys: keysToRemove]; |
| 243 | 25 | lastTime = time; |
| 244 | } |
|
| 245 | ||
| 246 | 27 | - (void) queueAnimation: (ElAnimation*) anim forKey: (id) key atBeginning: (BOOL) atBeginning cancelPending: (BOOL) cancelPending |
| 247 | 25 | { |
| 248 | static NSTimer* animationTimer = nil; |
|
| 249 | if (!animationTimer) |
|
| 250 | { |
|
| 251 | animationTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(timerCallback) userInfo: nil repeats: YES]; |
|
| 252 | lastTime = [self currentTime]; |
|
| 253 | } |
|
| 254 | |
|
| 255 | 27 | if (!key) |
| 256 | key = [NSNull null]; |
|
| 257 | |
|
| 258 | NSMutableArray* animArray = [queuedAnimations objectForKey: key]; |
|
| 259 | if (!animArray) |
|
| 260 | { |
|
| 261 | animArray = [NSMutableArray array]; |
|
| 262 | [queuedAnimations setObject: animArray forKey: key]; |
|
| 263 | } |
|
| 264 | |
|
| 265 | if (!cancelPending && !atBeginning) |
|
| 266 | [animArray addObject: anim]; |
|
| 267 | else if (cancelPending && !atBeginning) |
|
| 268 | { |
|
| 269 | if ([animArray count] > 1) |
|
| 270 | [animArray removeObjectsInRange: (NSRange){1, [animArray count]-1}]; |
|
| 271 | [animArray addObject: anim]; |
|
| 272 | } |
|
| 273 | else if (!cancelPending && atBeginning) |
|
| 274 | { |
|
| 275 | if ([animArray count]) |
|
| 276 | [animArray replaceObjectAtIndex: 0 withObject: anim]; |
|
| 277 | else |
|
| 278 | [animArray addObject: anim]; |
|
| 279 | } |
|
| 280 | else |
|
| 281 | { |
|
| 282 | [animArray removeAllObjects]; |
|
| 283 | [animArray addObject: anim]; |
|
| 284 | } |
|
| 285 | 25 | } |
| 286 | ||
| 287 | - (NSTimeInterval) now |
|
| 288 | { |
|
| 289 | return lastTime; |
|
| 290 | } |
|
| 291 | ||
| 292 | @end |
|
| 293 | ||
| 294 | 28 | NSString* AnimationAbsoluteTimeKey = @"animationAbsoluteTime"; |
| 295 | NSString* AnimationPassedTimeKey = @"animationPassedTime"; |
|
| 296 | NSString* AnimationDeltaTimeKey = @"animationDeltaTime"; |
|
| 297 | NSString* AnimationUserInfoKey = @"animationUserInfo"; |
|
| 298 | ||
| 299 | @implementation ElCallbackAnimation |
|
| 300 | ||
| 301 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 302 | { |
|
| 303 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 304 | ||
| 305 | NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithDouble: time], AnimationAbsoluteTimeKey, [NSNumber numberWithDouble: time - startTime], AnimationPassedTimeKey, [NSNumber numberWithDouble: delta], AnimationDeltaTimeKey, userInfo, AnimationUserInfoKey, nil]; |
|
| 306 | ||
| 307 | |
|
| 308 | [target performSelector: callback withObject: dict]; |
|
| 309 | ||
| 310 | return result; |
|
| 311 | } |
|
| 312 | ||
| 313 | - (void) dealloc |
|
| 314 | { |
|
| 315 | [target release]; |
|
| 316 | [userInfo release]; |
|
| 317 | [super dealloc]; |
|
| 318 | } |
|
| 319 | ||
| 320 | @synthesize target, userInfo, callback; |
|
| 321 | ||
| 322 | @end |
Loggerhead 1.17 is a web-based interface for Bazaar branches