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 | 65 | - (NSTimeInterval) currentTime; |
| 48 | 25 | |
| 49 | @end; |
|
| 50 | ||
| 51 | ||
| 52 | @implementation ElAnimation |
|
| 53 | ||
| 54 | 27 | - (void) queueForKey: (NSString*) key atBeginning: (BOOL) atBeginning cancelPending: (BOOL) cancelPending; |
| 55 | 25 | { |
| 56 | 27 | [[ElAnimationController sharedController] queueAnimation: self forKey: key atBeginning: atBeginning cancelPending: cancelPending]; |
| 57 | 25 | } |
| 58 | ||
| 59 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) deltaTime |
|
| 60 | { |
|
| 61 | if (time > startTime + duration) |
|
| 62 | return NO; |
|
| 63 | else |
|
| 64 | return YES; |
|
| 65 | } |
|
| 66 | ||
| 67 | + (NSTimeInterval) now |
|
| 68 | { |
|
| 69 | return [[ElAnimationController sharedController] now]; |
|
| 70 | } |
|
| 71 | ||
| 72 | 65 | + (NSTimeInterval) currentTime |
| 73 | { |
|
| 74 | return [[ElAnimationController sharedController] currentTime]; |
|
| 75 | } |
|
| 76 | ||
| 77 | 27 | - (void) setStartTime: (NSTimeInterval) time |
| 78 | { |
|
| 79 | startTime = time; |
|
| 80 | } |
|
| 81 | - (NSTimeInterval) startTime |
|
| 82 | { |
|
| 83 | return startTime; |
|
| 84 | } |
|
| 85 | ||
| 86 | + (ElAnimation*) delayedAnimationWithDelay: (float) seconds |
|
| 87 | { |
|
| 88 | 94 | ElAnimation* anim = [[ElAnimation alloc] init]; |
| 89 | 27 | [anim setDuration: seconds]; |
| 90 | return anim; |
|
| 91 | } |
|
| 92 | ||
| 93 | @synthesize duration, interpolation; |
|
| 94 | 25 | |
| 95 | @end |
|
| 96 | ||
| 97 | @implementation ElFloatAnimation |
|
| 98 | ||
| 99 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 100 | { |
|
| 101 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 102 | ||
| 103 | double t = fclamp((time - startTime)/duration, 0.0, 1.0); |
|
| 104 | |
|
| 105 | float y = 0.0; |
|
| 106 | switch (interpolation) |
|
| 107 | { |
|
| 108 | case kElLinearInterpolation: |
|
| 109 | y = linearInterpolation(startValue, endValue, t); |
|
| 110 | break; |
|
| 111 | case kElEaseInInterpolation: |
|
| 112 | y = easyInInterpolation(startValue, endValue, t); |
|
| 113 | break; |
|
| 114 | case kElEaseOutInterpolation: |
|
| 115 | y = easyOutInterpolation(startValue, endValue, t); |
|
| 116 | break; |
|
| 117 | case kElSmoothInterpolation: |
|
| 118 | y = smoothInterpolation(startValue, endValue, t); |
|
| 119 | break; |
|
| 120 | } |
|
| 121 | |
|
| 122 | [target setValue: [NSNumber numberWithFloat: y] forKey: property]; |
|
| 123 | ||
| 124 | return result; |
|
| 125 | } |
|
| 126 | ||
| 127 | @synthesize startValue, endValue, target, property; |
|
| 128 | ||
| 129 | @end |
|
| 130 | ||
| 131 | 94 | |
| 132 | ||
| 133 | 43 | @implementation ElV3Animation |
| 134 | ||
| 135 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 136 | { |
|
| 137 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 138 | ||
| 139 | double t = fclamp((time - startTime)/duration, 0.0, 1.0); |
|
| 140 | |
|
| 141 | v3 y = vcreate(0.0f, 0.0f, 0.0f); |
|
| 142 | switch (interpolation) |
|
| 143 | { |
|
| 144 | case kElLinearInterpolation: |
|
| 145 | y.v.x = linearInterpolation(startv.v.x, endv.v.x, t); |
|
| 146 | y.v.y = linearInterpolation(startv.v.y, endv.v.y, t); |
|
| 147 | y.v.z = linearInterpolation(startv.v.z, endv.v.z, t); |
|
| 148 | break; |
|
| 149 | case kElEaseInInterpolation: |
|
| 150 | y.v.x = easyInInterpolation(startv.v.x, endv.v.x, t); |
|
| 151 | y.v.y = easyInInterpolation(startv.v.y, endv.v.y, t); |
|
| 152 | y.v.z = easyInInterpolation(startv.v.z, endv.v.z, t); |
|
| 153 | break; |
|
| 154 | case kElEaseOutInterpolation: |
|
| 155 | y.v.x = easyOutInterpolation(startv.v.x, endv.v.x, t); |
|
| 156 | y.v.y = easyOutInterpolation(startv.v.y, endv.v.y, t); |
|
| 157 | y.v.z = easyOutInterpolation(startv.v.z, endv.v.z, t); |
|
| 158 | break; |
|
| 159 | case kElSmoothInterpolation: |
|
| 160 | y.v.x = smoothInterpolation(startv.v.x, endv.v.x, t); |
|
| 161 | y.v.y = smoothInterpolation(startv.v.y, endv.v.y, t); |
|
| 162 | y.v.z = smoothInterpolation(startv.v.z, endv.v.z, t); |
|
| 163 | break; |
|
| 164 | } |
|
| 165 | |
|
| 166 | 94 | assert(0); |
| 167 | // [target performSelector: setter withObject: (void*)&y]; |
|
| 168 | 43 | |
| 169 | return result; |
|
| 170 | } |
|
| 171 | ||
| 172 | ||
| 173 | @synthesize startv, endv, target, setter; |
|
| 174 | ||
| 175 | @end |
|
| 176 | ||
| 177 | 65 | @interface NSObject (ElCGPositionAnimation) |
| 178 | - (void) setPosition: (CGPoint) p; |
|
| 179 | @end |
|
| 180 | ||
| 181 | @implementation ElCGPositionAnimation |
|
| 182 | ||
| 183 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 184 | { |
|
| 185 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 186 | ||
| 187 | double t = fclamp((time - startTime)/duration, 0.0, 1.0); |
|
| 188 | |
|
| 189 | CGPoint y = CGPointZero; |
|
| 190 | switch (interpolation) |
|
| 191 | { |
|
| 192 | case kElLinearInterpolation: |
|
| 193 | y.x = linearInterpolation(startPoint.x, endPoint.x, t); |
|
| 194 | y.y = linearInterpolation(startPoint.y, endPoint.y, t); |
|
| 195 | break; |
|
| 196 | case kElEaseInInterpolation: |
|
| 197 | y.x = easyInInterpolation(startPoint.x, endPoint.x, t); |
|
| 198 | y.y = easyInInterpolation(startPoint.y, endPoint.y, t); |
|
| 199 | break; |
|
| 200 | case kElEaseOutInterpolation: |
|
| 201 | y.x = easyOutInterpolation(startPoint.x, endPoint.x, t); |
|
| 202 | y.y = easyOutInterpolation(startPoint.y, endPoint.y, t); |
|
| 203 | break; |
|
| 204 | case kElSmoothInterpolation: |
|
| 205 | y.x = smoothInterpolation(startPoint.x, endPoint.x, t); |
|
| 206 | y.y = smoothInterpolation(startPoint.y, endPoint.y, t); |
|
| 207 | break; |
|
| 208 | } |
|
| 209 | |
|
| 210 | [target setPosition: y]; |
|
| 211 | ||
| 212 | return result; |
|
| 213 | } |
|
| 214 | ||
| 215 | @synthesize startPoint, endPoint, target; |
|
| 216 | ||
| 217 | @end |
|
| 218 | ||
| 219 | 43 | |
| 220 | 25 | @implementation ElAnimationController |
| 221 | ||
| 222 | - (id) init |
|
| 223 | { |
|
| 224 | if (!(self = [super init])) |
|
| 225 | return nil; |
|
| 226 | ||
| 227 | 27 | queuedAnimations = [[NSMutableDictionary alloc] init]; |
| 228 | 25 | |
| 229 | mach_timebase_info(&timebase); |
|
| 230 | machTimingStart = mach_absolute_time(); |
|
| 231 | ||
| 232 | return self; |
|
| 233 | } |
|
| 234 | ||
| 235 | - (NSTimeInterval) currentTime |
|
| 236 | { |
|
| 237 | uint64_t mtime = mach_absolute_time(); |
|
| 238 | |
|
| 239 | uint64_t elapsed = mtime - machTimingStart; |
|
| 240 | |
|
| 241 | return (NSTimeInterval)((elapsed*timebase.numer)/timebase.denom)*1e-9; |
|
| 242 | } |
|
| 243 | ||
| 244 | + (id) sharedController |
|
| 245 | { |
|
| 246 | static ElAnimationController* sharedController = nil; |
|
| 247 | if (!sharedController) |
|
| 248 | sharedController = [[ElAnimationController alloc] init]; |
|
| 249 | return sharedController; |
|
| 250 | } |
|
| 251 | ||
| 252 | - (void) timerCallback |
|
| 253 | { |
|
| 254 | NSTimeInterval time = [self currentTime]; |
|
| 255 | NSTimeInterval delta = time - lastTime; |
|
| 256 | |
|
| 257 | // NSLog(@"%f %f", time, delta); |
|
| 258 | |
|
| 259 | 27 | NSMutableArray* keysToRemove = [NSMutableArray array]; |
| 260 | for (id key in queuedAnimations) |
|
| 261 | 25 | { |
| 262 | 27 | NSMutableArray* animArray = [queuedAnimations objectForKey: key]; |
| 263 | if (![animArray count]) |
|
| 264 | { |
|
| 265 | [keysToRemove addObject: key]; |
|
| 266 | continue; |
|
| 267 | } |
|
| 268 | |
|
| 269 | ElAnimation* anim = [animArray objectAtIndex: 0]; |
|
| 270 | |
|
| 271 | if ([anim startTime] == 0.0) |
|
| 272 | [anim setStartTime: lastTime]; |
|
| 273 | |
|
| 274 | [anim animateForTime: time delta: delta]; |
|
| 275 | ||
| 276 | if ([anim startTime] + [anim duration] < time) |
|
| 277 | { |
|
| 278 | [animArray removeObjectAtIndex: 0]; |
|
| 279 | //NSLog(@"dequeued animation"); |
|
| 280 | } |
|
| 281 | 25 | } |
| 282 | 27 | [queuedAnimations removeObjectsForKeys: keysToRemove]; |
| 283 | 25 | lastTime = time; |
| 284 | } |
|
| 285 | ||
| 286 | 27 | - (void) queueAnimation: (ElAnimation*) anim forKey: (id) key atBeginning: (BOOL) atBeginning cancelPending: (BOOL) cancelPending |
| 287 | 25 | { |
| 288 | static NSTimer* animationTimer = nil; |
|
| 289 | if (!animationTimer) |
|
| 290 | { |
|
| 291 | animationTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(timerCallback) userInfo: nil repeats: YES]; |
|
| 292 | lastTime = [self currentTime]; |
|
| 293 | } |
|
| 294 | |
|
| 295 | 27 | if (!key) |
| 296 | key = [NSNull null]; |
|
| 297 | |
|
| 298 | NSMutableArray* animArray = [queuedAnimations objectForKey: key]; |
|
| 299 | if (!animArray) |
|
| 300 | { |
|
| 301 | animArray = [NSMutableArray array]; |
|
| 302 | [queuedAnimations setObject: animArray forKey: key]; |
|
| 303 | } |
|
| 304 | |
|
| 305 | if (!cancelPending && !atBeginning) |
|
| 306 | [animArray addObject: anim]; |
|
| 307 | else if (cancelPending && !atBeginning) |
|
| 308 | { |
|
| 309 | if ([animArray count] > 1) |
|
| 310 | [animArray removeObjectsInRange: (NSRange){1, [animArray count]-1}]; |
|
| 311 | [animArray addObject: anim]; |
|
| 312 | } |
|
| 313 | else if (!cancelPending && atBeginning) |
|
| 314 | { |
|
| 315 | if ([animArray count]) |
|
| 316 | [animArray replaceObjectAtIndex: 0 withObject: anim]; |
|
| 317 | else |
|
| 318 | [animArray addObject: anim]; |
|
| 319 | } |
|
| 320 | else |
|
| 321 | { |
|
| 322 | [animArray removeAllObjects]; |
|
| 323 | [animArray addObject: anim]; |
|
| 324 | } |
|
| 325 | 25 | } |
| 326 | ||
| 327 | - (NSTimeInterval) now |
|
| 328 | { |
|
| 329 | return lastTime; |
|
| 330 | } |
|
| 331 | ||
| 332 | @end |
|
| 333 | ||
| 334 | 28 | NSString* AnimationAbsoluteTimeKey = @"animationAbsoluteTime"; |
| 335 | NSString* AnimationPassedTimeKey = @"animationPassedTime"; |
|
| 336 | NSString* AnimationDeltaTimeKey = @"animationDeltaTime"; |
|
| 337 | NSString* AnimationUserInfoKey = @"animationUserInfo"; |
|
| 338 | ||
| 339 | @implementation ElCallbackAnimation |
|
| 340 | ||
| 341 | - (BOOL) animateForTime: (NSTimeInterval) time delta: (NSTimeInterval) delta |
|
| 342 | { |
|
| 343 | BOOL result = [super animateForTime: time delta: delta]; |
|
| 344 | ||
| 345 | NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithDouble: time], AnimationAbsoluteTimeKey, [NSNumber numberWithDouble: time - startTime], AnimationPassedTimeKey, [NSNumber numberWithDouble: delta], AnimationDeltaTimeKey, userInfo, AnimationUserInfoKey, nil]; |
|
| 346 | ||
| 347 | |
|
| 348 | [target performSelector: callback withObject: dict]; |
|
| 349 | ||
| 350 | return result; |
|
| 351 | } |
|
| 352 | ||
| 353 | ||
| 354 | @synthesize target, userInfo, callback; |
|
| 355 | ||
| 356 | @end |
Loggerhead 1.17 is a web-based interface for Bazaar branches