diff --git a/LotteAnimator.xcodeproj/project.pbxproj b/LotteAnimator.xcodeproj/project.pbxproj index 512322fbfa..f81ee8bb5a 100644 --- a/LotteAnimator.xcodeproj/project.pbxproj +++ b/LotteAnimator.xcodeproj/project.pbxproj @@ -17,10 +17,8 @@ 4804B3191C1F6DEA00DA8AF7 /* LAComposition.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B3181C1F6DEA00DA8AF7 /* LAComposition.m */; }; 4804B31E1C1F757600DA8AF7 /* UIColor+Expanded.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B31D1C1F757600DA8AF7 /* UIColor+Expanded.m */; }; 4804B3211C1F761800DA8AF7 /* BWMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B3201C1F761800DA8AF7 /* BWMath.m */; }; - 48372A471C1F8B4C00AD0293 /* LAPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A461C1F8B4C00AD0293 /* LAPath.m */; }; 48372A4A1C1F8D7D00AD0293 /* LAMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A491C1F8D7D00AD0293 /* LAMask.m */; }; - 48372A4F1C1F99C600AD0293 /* LAShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A4E1C1F99C600AD0293 /* LAShape.m */; }; - 48372A521C20973300AD0293 /* LAShapeItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A511C20973300AD0293 /* LAShapeItem.m */; }; + 48372A4F1C1F99C600AD0293 /* LAShapeGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */; }; 48372A551C209A5F00AD0293 /* LAShapePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A541C209A5F00AD0293 /* LAShapePath.m */; }; 48372A581C209A6C00AD0293 /* LAShapeStroke.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A571C209A6C00AD0293 /* LAShapeStroke.m */; }; 48372A5B1C209A7A00AD0293 /* LAShapeFill.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A5A1C209A7A00AD0293 /* LAShapeFill.m */; }; @@ -76,6 +74,10 @@ 620A565F1D1C81750030EBFB /* LAAnimatablePointValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620A565E1D1C81750030EBFB /* LAAnimatablePointValue.m */; }; 620A56621D1C81850030EBFB /* LAAnimatableNumberValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */; }; 620A56651D1C81930030EBFB /* LAAnimatableShapeValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */; }; + 620CD7CD1D3415F000055AD1 /* LAAnimatableRectValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */; }; + 620CD7D01D343A2500055AD1 /* LAAnimatableScaleValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */; }; + 620CD7D11D35AB9C00055AD1 /* LALayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B32B1C1F835F00DA8AF7 /* LALayerView.m */; }; + 620CD7D21D35AB9F00055AD1 /* LACompView.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A431C1F84D700AD0293 /* LACompView.m */; }; 629737DF1D25D7FC007B4AC9 /* allHold_KeyTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 629737DB1D25D7FC007B4AC9 /* allHold_KeyTest.json */; }; 629737E01D25D7FC007B4AC9 /* firstHold_KeyTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 629737DC1D25D7FC007B4AC9 /* firstHold_KeyTest.json */; }; 629737E11D25D7FC007B4AC9 /* lastHold_KeyTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 629737DD1D25D7FC007B4AC9 /* lastHold_KeyTest.json */; }; @@ -109,14 +111,10 @@ 4804B32B1C1F835F00DA8AF7 /* LALayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LALayerView.m; sourceTree = ""; }; 48372A421C1F84D700AD0293 /* LACompView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LACompView.h; sourceTree = ""; }; 48372A431C1F84D700AD0293 /* LACompView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LACompView.m; sourceTree = ""; }; - 48372A451C1F8B4C00AD0293 /* LAPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAPath.h; sourceTree = ""; }; - 48372A461C1F8B4C00AD0293 /* LAPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAPath.m; sourceTree = ""; }; 48372A481C1F8D7D00AD0293 /* LAMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAMask.h; sourceTree = ""; }; 48372A491C1F8D7D00AD0293 /* LAMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAMask.m; sourceTree = ""; }; - 48372A4D1C1F99C600AD0293 /* LAShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShape.h; sourceTree = ""; }; - 48372A4E1C1F99C600AD0293 /* LAShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShape.m; sourceTree = ""; }; - 48372A501C20973300AD0293 /* LAShapeItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeItem.h; sourceTree = ""; }; - 48372A511C20973300AD0293 /* LAShapeItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapeItem.m; sourceTree = ""; }; + 48372A4D1C1F99C600AD0293 /* LAShapeGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeGroup.h; sourceTree = ""; }; + 48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapeGroup.m; sourceTree = ""; }; 48372A531C209A5F00AD0293 /* LAShapePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapePath.h; sourceTree = ""; }; 48372A541C209A5F00AD0293 /* LAShapePath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapePath.m; sourceTree = ""; }; 48372A561C209A6C00AD0293 /* LAShapeStroke.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeStroke.h; sourceTree = ""; }; @@ -176,7 +174,6 @@ 4872BEDB1D146D850028E0B3 /* animatedTransformHold.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = animatedTransformHold.json; sourceTree = ""; }; 4872BEDD1D146D850028E0B3 /* animatedTransform.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = animatedTransform.json; sourceTree = ""; }; 488990EC1D08A2A400425189 /* curve.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = curve.json; sourceTree = ""; }; - 620A56451D1B2D3D0030EBFB /* LAAnimatableValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = LAAnimatableValue.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 620A56481D1B3B150030EBFB /* FullLayerModel_Animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = FullLayerModel_Animation.json; sourceTree = ""; }; 620A565A1D1C81610030EBFB /* LAAnimatableColorValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableColorValue.h; sourceTree = ""; }; 620A565B1D1C81610030EBFB /* LAAnimatableColorValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableColorValue.m; sourceTree = ""; }; @@ -186,6 +183,10 @@ 620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableNumberValue.m; sourceTree = ""; }; 620A56631D1C81930030EBFB /* LAAnimatableShapeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableShapeValue.h; sourceTree = ""; }; 620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableShapeValue.m; sourceTree = ""; }; + 620CD7CB1D3415F000055AD1 /* LAAnimatableRectValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableRectValue.h; sourceTree = ""; }; + 620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableRectValue.m; sourceTree = ""; }; + 620CD7CE1D343A2500055AD1 /* LAAnimatableScaleValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableScaleValue.h; sourceTree = ""; }; + 620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableScaleValue.m; sourceTree = ""; }; 629737DB1D25D7FC007B4AC9 /* allHold_KeyTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = allHold_KeyTest.json; sourceTree = ""; }; 629737DC1D25D7FC007B4AC9 /* firstHold_KeyTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = firstHold_KeyTest.json; sourceTree = ""; }; 629737DD1D25D7FC007B4AC9 /* lastHold_KeyTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = lastHold_KeyTest.json; sourceTree = ""; }; @@ -281,14 +282,10 @@ 4804B3181C1F6DEA00DA8AF7 /* LAComposition.m */, 4804B3141C1F5B2000DA8AF7 /* LALayer.h */, 4804B3151C1F5B2000DA8AF7 /* LALayer.m */, - 48372A451C1F8B4C00AD0293 /* LAPath.h */, - 48372A461C1F8B4C00AD0293 /* LAPath.m */, 48372A481C1F8D7D00AD0293 /* LAMask.h */, 48372A491C1F8D7D00AD0293 /* LAMask.m */, - 48372A4D1C1F99C600AD0293 /* LAShape.h */, - 48372A4E1C1F99C600AD0293 /* LAShape.m */, - 48372A501C20973300AD0293 /* LAShapeItem.h */, - 48372A511C20973300AD0293 /* LAShapeItem.m */, + 48372A4D1C1F99C600AD0293 /* LAShapeGroup.h */, + 48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */, 48372A561C209A6C00AD0293 /* LAShapeStroke.h */, 48372A571C209A6C00AD0293 /* LAShapeStroke.m */, 48372A591C209A7A00AD0293 /* LAShapeFill.h */, @@ -371,7 +368,6 @@ 62F683871D26EF420088C015 /* AnimatableProperties */ = { isa = PBXGroup; children = ( - 620A56451D1B2D3D0030EBFB /* LAAnimatableValue.h */, 620A565A1D1C81610030EBFB /* LAAnimatableColorValue.h */, 620A565B1D1C81610030EBFB /* LAAnimatableColorValue.m */, 620A565D1D1C81750030EBFB /* LAAnimatablePointValue.h */, @@ -380,6 +376,10 @@ 620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */, 620A56631D1C81930030EBFB /* LAAnimatableShapeValue.h */, 620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */, + 620CD7CB1D3415F000055AD1 /* LAAnimatableRectValue.h */, + 620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */, + 620CD7CE1D343A2500055AD1 /* LAAnimatableScaleValue.h */, + 620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */, ); name = AnimatableProperties; sourceTree = ""; @@ -563,28 +563,30 @@ buildActionMask = 2147483647; files = ( 4804B31E1C1F757600DA8AF7 /* UIColor+Expanded.m in Sources */, + 620CD7D21D35AB9F00055AD1 /* LACompView.m in Sources */, 4804B2FF1C1F55E600DA8AF7 /* ViewController.m in Sources */, 48372A641C20A91C00AD0293 /* LAJSONExplorerViewController.m in Sources */, 620A56651D1C81930030EBFB /* LAAnimatableShapeValue.m in Sources */, 4804B3191C1F6DEA00DA8AF7 /* LAComposition.m in Sources */, 4804B2FC1C1F55E600DA8AF7 /* AppDelegate.m in Sources */, 4804B3211C1F761800DA8AF7 /* BWMath.m in Sources */, - 48372A471C1F8B4C00AD0293 /* LAPath.m in Sources */, 48372AB41C20C13700AD0293 /* CGGeometryAdditions.m in Sources */, 620A565F1D1C81750030EBFB /* LAAnimatablePointValue.m in Sources */, 48372A4A1C1F8D7D00AD0293 /* LAMask.m in Sources */, 4804B3161C1F5B2000DA8AF7 /* LALayer.m in Sources */, - 48372A521C20973300AD0293 /* LAShapeItem.m in Sources */, - 48372A4F1C1F99C600AD0293 /* LAShape.m in Sources */, + 48372A4F1C1F99C600AD0293 /* LAShapeGroup.m in Sources */, 48372A581C209A6C00AD0293 /* LAShapeStroke.m in Sources */, + 620CD7D11D35AB9C00055AD1 /* LALayerView.m in Sources */, 48372ABA1C20D98200AD0293 /* LAShapeRectangle.m in Sources */, 48372A5B1C209A7A00AD0293 /* LAShapeFill.m in Sources */, 4804B2F91C1F55E600DA8AF7 /* main.m in Sources */, 620A56621D1C81850030EBFB /* LAAnimatableNumberValue.m in Sources */, 48372A551C209A5F00AD0293 /* LAShapePath.m in Sources */, 48372AB71C20D97200AD0293 /* LAShapeCircle.m in Sources */, + 620CD7CD1D3415F000055AD1 /* LAAnimatableRectValue.m in Sources */, 620A565C1D1C81610030EBFB /* LAAnimatableColorValue.m in Sources */, 48372A5E1C209A8900AD0293 /* LAShapeTransform.m in Sources */, + 620CD7D01D343A2500055AD1 /* LAAnimatableScaleValue.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate index e89383cce6..b42005273b 100644 Binary files a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate and b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index b6306184fd..2123de9320 100644 --- a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -29,22 +29,6 @@ landmarkType = "5"> - - - - @interface LAAnimatableColorValue : NSObject - (instancetype)initWithColorValues:(NSDictionary *)colorValues; -- (void)prepareAnimationsForKeyPath:(NSString *)keyPath frameRate:(NSNumber *)frameRate; - @property (nonatomic, readonly) UIColor *initialColor; -@property (nonatomic, readonly) NSString *keyPath; -@property (nonatomic, readonly) CAKeyframeAnimation *animation; + +@property (nonatomic, readonly) NSArray *colorKeyframes; +@property (nonatomic, readonly) NSArray *keyTimes; +@property (nonatomic, readonly) NSArray *timingFunctions; +@property (nonatomic, readonly) NSNumber *startFrame; +@property (nonatomic, readonly) NSNumber *durationFrames; @end diff --git a/LotteAnimator/LAAnimatableColorValue.m b/LotteAnimator/LAAnimatableColorValue.m index 5acc3f6434..5e3edce884 100644 --- a/LotteAnimator/LAAnimatableColorValue.m +++ b/LotteAnimator/LAAnimatableColorValue.m @@ -9,21 +9,16 @@ #import "LAAnimatableColorValue.h" @implementation LAAnimatableColorValue -@synthesize animation = _animation; -@synthesize keyPath = _keyPath; -- (instancetype)initWithColorValues:(NSDictionary *)colorValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate { +- (instancetype)initWithColorValues:(NSDictionary *)colorValues { self = [super init]; if (self) { - _keyPath = [keyPath copy]; NSArray *value = colorValues[@"k"]; if ([value isKindOfClass:[NSArray class]] && [[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] && [(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) { //Keframes - [self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate]; + [self _buildAnimationForKeyframes:value]; } else { //Single Value, no animation _initialColor = [[self _colorValueFromArray:value] copy]; @@ -32,23 +27,19 @@ return self; } -- (void)_buildAnimationForKeyframes:(NSArray *)keyframes - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate { +- (void)_buildAnimationForKeyframes:(NSArray *)keyframes { NSMutableArray *keyTimes = [NSMutableArray array]; NSMutableArray *timingFunctions = [NSMutableArray array]; NSMutableArray *colorValues = [NSMutableArray array]; - NSNumber *startFrame = keyframes.firstObject[@"t"]; + _startFrame = keyframes.firstObject[@"t"]; NSNumber *endFrame = keyframes.lastObject[@"t"]; - NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue), + NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue), @"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes"); - // Calculate time bounds - NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue; - NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue); - NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue; + // Calculate time duration + _durationFrames = @(endFrame.floatValue - _startFrame.floatValue); BOOL addStartValue = YES; BOOL addTimePadding = NO; @@ -59,11 +50,11 @@ NSNumber *frame = keyframe[@"t"]; // Calculate percentage value for keyframe. //CA Animations accept time values of 0-1 as a percentage of animation completed. - NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue); + NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue); if (outColor) { //add out value - [colorValues addObject:(id)[[outColor copy] CGColor]]; + [colorValues addObject:[outColor copy]]; [timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; outColor = nil; } @@ -75,7 +66,7 @@ if (keyframe == keyframes.firstObject) { _initialColor = startColor; } - [colorValues addObject:(id)[[startColor copy] CGColor]]; + [colorValues addObject:[startColor copy]]; if (timingFunctions.count) { [timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; } @@ -93,7 +84,7 @@ // add end value if present for keyframe UIColor *endColor = [self _colorValueFromArray:keyframe[@"e"]]; if (endColor) { - [colorValues addObject:(id)[[endColor copy] CGColor]]; + [colorValues addObject:[endColor copy]]; /* * Timing Function for time interpolations between keyframes * Should be n-1 where n is the number of keyframes @@ -126,13 +117,9 @@ } } - _animation = [CAKeyframeAnimation animationWithKeyPath:keyPath]; - _animation.values = colorValues; - _animation.keyTimes = keyTimes; - _animation.timingFunctions = timingFunctions; - _animation.beginTime = beginTime; - _animation.duration = durationTime; - _animation.fillMode = kCAFillModeForwards; + _colorKeyframes = colorValues; + _keyTimes = keyTimes; + _timingFunctions = timingFunctions; } - (UIColor *)_colorValueFromArray:(NSArray *)colorArray { diff --git a/LotteAnimator/LAAnimatableNumberValue.h b/LotteAnimator/LAAnimatableNumberValue.h index 5c380870f3..da28fff1d6 100644 --- a/LotteAnimator/LAAnimatableNumberValue.h +++ b/LotteAnimator/LAAnimatableNumberValue.h @@ -6,17 +6,17 @@ // Copyright © 2016 Brandon Withrow. All rights reserved. // -#import "LAAnimatableValue.h" #import @interface LAAnimatableNumberValue : NSObject -- (instancetype)initWithNumberValues:(NSDictionary *)numberValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate; +- (instancetype)initWithNumberValues:(NSDictionary *)numberValues; @property (nonatomic, readonly) NSNumber *initialValue; -@property (nonatomic, readonly) NSString *keyPath; -@property (nonatomic, readonly) CAKeyframeAnimation *animation; +@property (nonatomic, readonly) NSArray *valueKeyframes; +@property (nonatomic, readonly) NSArray *keyTimes; +@property (nonatomic, readonly) NSArray *timingFunctions; +@property (nonatomic, readonly) NSNumber *startFrame; +@property (nonatomic, readonly) NSNumber *durationFrames; @end diff --git a/LotteAnimator/LAAnimatableNumberValue.m b/LotteAnimator/LAAnimatableNumberValue.m index 220528c4a6..921c490a84 100644 --- a/LotteAnimator/LAAnimatableNumberValue.m +++ b/LotteAnimator/LAAnimatableNumberValue.m @@ -10,18 +10,15 @@ @implementation LAAnimatableNumberValue -- (instancetype)initWithNumberValues:(NSDictionary *)numberValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate { +- (instancetype)initWithNumberValues:(NSDictionary *)numberValues { self = [super init]; if (self) { - _keyPath = [keyPath copy]; id value = numberValues[@"k"]; if ([value isKindOfClass:[NSArray class]] && [[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] && [(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) { //Keframes - [self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate]; + [self _buildAnimationForKeyframes:value]; } else { //Single Value, no animation _initialValue = [[self _numberValueFromObject:value] copy]; @@ -30,23 +27,21 @@ return self; } -- (void)_buildAnimationForKeyframes:(NSArray *)keyframes - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate { +- (void)_buildAnimationForKeyframes:(NSArray *)keyframes { + NSMutableArray *keyTimes = [NSMutableArray array]; NSMutableArray *timingFunctions = [NSMutableArray array]; NSMutableArray *numberValues = [NSMutableArray array]; - NSNumber *startFrame = keyframes.firstObject[@"t"]; + _startFrame = keyframes.firstObject[@"t"]; NSNumber *endFrame = keyframes.lastObject[@"t"]; - NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue), + NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue), @"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes"); - // Calculate time bounds in second-time. - NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue; - NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue); - NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue; + // Calculate time duration + _durationFrames = @(endFrame.floatValue - _startFrame.floatValue); + BOOL addStartValue = YES; BOOL addTimePadding = NO; @@ -57,7 +52,7 @@ NSNumber *frame = keyframe[@"t"]; // Calculate percentage value for keyframe. //CA Animations accept time values of 0-1 as a percentage of animation completed. - NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue); + NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue); if (outValue) { //add out value @@ -123,14 +118,9 @@ addTimePadding = YES; } } - - _animation = [CAKeyframeAnimation animationWithKeyPath:keyPath]; - _animation.values = numberValues; - _animation.keyTimes = keyTimes; - _animation.timingFunctions = timingFunctions; - _animation.beginTime = beginTime; - _animation.duration = durationTime; - _animation.fillMode = kCAFillModeForwards; + _valueKeyframes = numberValues; + _keyTimes = keyTimes; + _timingFunctions = timingFunctions; } - (NSNumber *)_numberValueFromObject:(id)valueObject { diff --git a/LotteAnimator/LAAnimatablePointValue.h b/LotteAnimator/LAAnimatablePointValue.h index 843af062b5..b560c8b4fb 100644 --- a/LotteAnimator/LAAnimatablePointValue.h +++ b/LotteAnimator/LAAnimatablePointValue.h @@ -6,17 +6,17 @@ // Copyright © 2016 Brandon Withrow. All rights reserved. // -#import "LAAnimatableValue.h" #import @interface LAAnimatablePointValue : NSObject -- (instancetype)initWithPointValues:(NSDictionary *)pointValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate; +- (instancetype)initWithPointValues:(NSDictionary *)pointValues; @property (nonatomic, readonly) CGPoint initialPoint; -@property (nonatomic, readonly) NSString *keyPath; -@property (nonatomic, readonly) CAKeyframeAnimation *animation; +@property (nonatomic, readonly) UIBezierPath *animationPath; +@property (nonatomic, readonly) NSArray *keyTimes; +@property (nonatomic, readonly) NSArray *timingFunctions; +@property (nonatomic, readonly) NSNumber *startFrame; +@property (nonatomic, readonly) NSNumber *durationFrames; @end diff --git a/LotteAnimator/LAAnimatablePointValue.m b/LotteAnimator/LAAnimatablePointValue.m index 5b2c75bdb4..ed8ac4bbf0 100644 --- a/LotteAnimator/LAAnimatablePointValue.m +++ b/LotteAnimator/LAAnimatablePointValue.m @@ -9,21 +9,16 @@ #import "LAAnimatablePointValue.h" @implementation LAAnimatablePointValue -@synthesize animation = _animation; -@synthesize keyPath = _keyPath; -- (instancetype)initWithPointValues:(NSDictionary *)pointValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate { +- (instancetype)initWithPointValues:(NSDictionary *)pointValues { self = [super init]; if (self) { - _keyPath = [keyPath copy]; NSArray *value = pointValues[@"k"]; if ([value isKindOfClass:[NSArray class]] && [[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] && [(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) { //Keframes - [self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate]; + [self _buildAnimationForKeyframes:value]; } else { //Single Value, no animation _initialPoint = [self _pointFromValueArray:value]; @@ -32,23 +27,19 @@ return self; } -- (void)_buildAnimationForKeyframes:(NSArray *)keyframes - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate { +- (void)_buildAnimationForKeyframes:(NSArray *)keyframes { NSMutableArray *keyTimes = [NSMutableArray array]; NSMutableArray *timingFunctions = [NSMutableArray array]; UIBezierPath *motionPath = [UIBezierPath new]; - NSNumber *startFrame = keyframes.firstObject[@"t"]; + _startFrame = keyframes.firstObject[@"t"]; NSNumber *endFrame = keyframes.lastObject[@"t"]; - NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue), + NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue), @"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes"); - // Calculate time bounds - NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue; - NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue); - NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue; + // Calculate time duration + _durationFrames = @(endFrame.floatValue - _startFrame.floatValue); BOOL addStartValue = YES; BOOL addTimePadding = NO; @@ -59,7 +50,7 @@ NSNumber *frame = keyframe[@"t"]; // Calculate percentage value for keyframe. //CA Animations accept time values of 0-1 as a percentage of animation completed. - NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue); + NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue); if (outPoint) { //add out value @@ -138,13 +129,9 @@ } } - _animation = [CAKeyframeAnimation animationWithKeyPath:keyPath]; - _animation.path = motionPath.CGPath; - _animation.keyTimes = keyTimes; - _animation.timingFunctions = timingFunctions; - _animation.beginTime = beginTime; - _animation.duration = durationTime; - _animation.fillMode = kCAFillModeForwards; + _animationPath = motionPath; + _keyTimes = keyTimes; + _timingFunctions = timingFunctions; } - (CGPoint)_pointFromValueArray:(NSArray *)values { diff --git a/LotteAnimator/LAAnimatableRectValue.h b/LotteAnimator/LAAnimatableRectValue.h new file mode 100644 index 0000000000..41cd79a07d --- /dev/null +++ b/LotteAnimator/LAAnimatableRectValue.h @@ -0,0 +1,23 @@ +// +// LAAnimatableSizeValue.h +// LotteAnimator +// +// Created by brandon_withrow on 7/11/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import + +@interface LAAnimatableRectValue : NSObject + +- (instancetype)initWithRectValues:(NSDictionary *)rectValues; + +@property (nonatomic, readonly) CGRect initialRect; +@property (nonatomic, readonly) NSArray *rectKeyframes; +@property (nonatomic, readonly) NSArray *keyTimes; +@property (nonatomic, readonly) NSArray *timingFunctions; +@property (nonatomic, readonly) NSNumber *startFrame; +@property (nonatomic, readonly) NSNumber *durationFrames; + + +@end diff --git a/LotteAnimator/LAAnimatableRectValue.m b/LotteAnimator/LAAnimatableRectValue.m new file mode 100644 index 0000000000..573aaa65d4 --- /dev/null +++ b/LotteAnimator/LAAnimatableRectValue.m @@ -0,0 +1,21 @@ +// +// LAAnimatableSizeValue.m +// LotteAnimator +// +// Created by brandon_withrow on 7/11/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import "LAAnimatableRectValue.h" + +@implementation LAAnimatableRectValue + +- (instancetype)initWithRectValues:(NSDictionary *)rectValues { + self = [super init]; + if (self) { + + } + return self; +} + +@end diff --git a/LotteAnimator/LAAnimatableScaleValue.h b/LotteAnimator/LAAnimatableScaleValue.h new file mode 100644 index 0000000000..2e3b916da3 --- /dev/null +++ b/LotteAnimator/LAAnimatableScaleValue.h @@ -0,0 +1,15 @@ +// +// LAAnimatableScaleValue.h +// LotteAnimator +// +// Created by brandon_withrow on 7/11/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import + +@interface LAAnimatableScaleValue : NSObject + +- (instancetype)initWithScaleValues:(NSDictionary *)scaleValues; + +@end diff --git a/LotteAnimator/LAAnimatableScaleValue.m b/LotteAnimator/LAAnimatableScaleValue.m new file mode 100644 index 0000000000..4139f3f717 --- /dev/null +++ b/LotteAnimator/LAAnimatableScaleValue.m @@ -0,0 +1,21 @@ +// +// LAAnimatableScaleValue.m +// LotteAnimator +// +// Created by brandon_withrow on 7/11/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import "LAAnimatableScaleValue.h" + +@implementation LAAnimatableScaleValue + +- (instancetype)initWithScaleValues:(NSDictionary *)scaleValues { + self = [super init]; + if (self) { + + } + return self; +} + +@end diff --git a/LotteAnimator/LAAnimatableShapeValue.h b/LotteAnimator/LAAnimatableShapeValue.h index 06e2e9ff9c..f97d1951ef 100644 --- a/LotteAnimator/LAAnimatableShapeValue.h +++ b/LotteAnimator/LAAnimatableShapeValue.h @@ -6,18 +6,18 @@ // Copyright © 2016 Brandon Withrow. All rights reserved. // -#import "LAAnimatableValue.h" #import @interface LAAnimatableShapeValue : NSObject -- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate - closedPath:(BOOL)closedPath; +- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues closed:(BOOL)closed; @property (nonatomic, readonly) UIBezierPath *initialShape; -@property (nonatomic, readonly) NSString *keyPath; -@property (nonatomic, readonly) CAKeyframeAnimation *animation; + +@property (nonatomic, readonly) NSArray *shapeKeyframes; +@property (nonatomic, readonly) NSArray *keyTimes; +@property (nonatomic, readonly) NSArray *timingFunctions; +@property (nonatomic, readonly) NSNumber *startFrame; +@property (nonatomic, readonly) NSNumber *durationFrames; @end diff --git a/LotteAnimator/LAAnimatableShapeValue.m b/LotteAnimator/LAAnimatableShapeValue.m index bcecf37dad..21c6204512 100644 --- a/LotteAnimator/LAAnimatableShapeValue.m +++ b/LotteAnimator/LAAnimatableShapeValue.m @@ -9,76 +9,65 @@ #import "LAAnimatableShapeValue.h" @implementation LAAnimatableShapeValue -@synthesize animation = _animation; -@synthesize keyPath = _keyPath; -- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate - closedPath:(BOOL)closedPath { +- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues closed:(BOOL)closed { self = [super init]; if (self) { - _keyPath = [keyPath copy]; id value = shapeValues[@"k"]; if ([value isKindOfClass:[NSArray class]] && [[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] && [(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) { //Keframes - [self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate closedPath:closedPath]; - } else { + [self _buildAnimationForKeyframes:value closed:closed]; + } else if ([value isKindOfClass:[NSDictionary class]]) { //Single Value, no animation - _initialShape = [self _bezierShapeFromValue:value closedPath:closedPath]; + _initialShape = [self _bezierShapeFromValue:value closed:closed]; } } return self; } -- (void)_buildAnimationForKeyframes:(NSArray *)keyframes - keyPath:(NSString *)keyPath - frameRate:(NSNumber *)frameRate - closedPath:(BOOL)closedPath { +- (void)_buildAnimationForKeyframes:(NSArray *)keyframes closed:(BOOL)closed { NSMutableArray *keyTimes = [NSMutableArray array]; NSMutableArray *timingFunctions = [NSMutableArray array]; - NSMutableArray *shapeValues = [NSMutableArray array]; + NSMutableArray *shapeValues = [NSMutableArray array]; - NSNumber *startFrame = keyframes.firstObject[@"t"]; + _startFrame = keyframes.firstObject[@"t"]; NSNumber *endFrame = keyframes.lastObject[@"t"]; - NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue), + NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue), @"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes"); - // Calculate time bounds - NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue; - NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue); - NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue; + // Calculate time duration + _durationFrames = @(endFrame.floatValue - _startFrame.floatValue); BOOL addStartValue = YES; BOOL addTimePadding = NO; - UIBezierPath *outShape = nil; + NSDictionary *outShape = nil; for (NSDictionary *keyframe in keyframes) { // Get keyframe time value NSNumber *frame = keyframe[@"t"]; // Calculate percentage value for keyframe. //CA Animations accept time values of 0-1 as a percentage of animation completed. - NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue); + NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue); if (outShape) { //add out value - [shapeValues addObject:(id)[[outShape copy] CGPath]]; + [shapeValues addObject:[self _bezierShapeFromValue:outShape closed:closed]]; [timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; outShape = nil; } - UIBezierPath *startShape = [self _bezierShapeFromValue:keyframe[@"s"] closedPath:closedPath]; + NSDictionary *startShape = keyframe[@"s"]; if (addStartValue) { // Add start value if (startShape) { if (keyframe == keyframes.firstObject) { - _initialShape = startShape; + _initialShape = [self _bezierShapeFromValue:startShape closed:closed]; } - [shapeValues addObject:(id)[[startShape copy] CGPath]]; + [shapeValues addObject:[self _bezierShapeFromValue:startShape closed:closed]]; if (timingFunctions.count) { [timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; } @@ -94,9 +83,9 @@ } // add end value if present for keyframe - UIBezierPath *endShape = [self _bezierShapeFromValue:keyframe[@"e"] closedPath:closedPath]; + NSDictionary *endShape = keyframe[@"e"]; if (endShape) { - [shapeValues addObject:(id)[[endShape copy] CGColor]]; + [shapeValues addObject:[self _bezierShapeFromValue:endShape closed:closed]]; /* * Timing Function for time interpolations between keyframes * Should be n-1 where n is the number of keyframes @@ -128,17 +117,13 @@ addTimePadding = YES; } } - - _animation = [CAKeyframeAnimation animationWithKeyPath:keyPath]; - _animation.values = shapeValues; - _animation.keyTimes = keyTimes; - _animation.timingFunctions = timingFunctions; - _animation.beginTime = beginTime; - _animation.duration = durationTime; - _animation.fillMode = kCAFillModeForwards; + + _shapeKeyframes = shapeValues; + _keyTimes = keyTimes; + _timingFunctions = timingFunctions; } -- (UIBezierPath *)_bezierShapeFromValue:(id)value closedPath:(BOOL)closedPath { +- (UIBezierPath *)_bezierShapeFromValue:(id)value closed:(BOOL)closedPath { NSDictionary *pointsData = nil; if ([value isKindOfClass:[NSArray class]] && [[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] && diff --git a/LotteAnimator/LAAnimatableValue.h b/LotteAnimator/LAAnimatableValue.h deleted file mode 100644 index f0f6f91419..0000000000 --- a/LotteAnimator/LAAnimatableValue.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// LAAnimatableProperty.h -// LotteAnimator -// -// Created by brandon_withrow on 6/22/16. -// Copyright © 2016 Brandon Withrow. All rights reserved. -// - -#import - -@protocol LAAnimatableValue - -@property (nonatomic, readonly) NSString *keyPath; -@property (nonatomic, readonly) CAKeyframeAnimation *animation; - -@end diff --git a/LotteAnimator/LACompView.h b/LotteAnimator/LACompView.h index 29bf703d68..0f2ab8ee49 100644 --- a/LotteAnimator/LACompView.h +++ b/LotteAnimator/LACompView.h @@ -10,9 +10,9 @@ @interface LACompView : UIView -- (instancetype)initWithModel:(LAScene *)model; +- (instancetype)initWithModel:(LAComposition *)model; -@property (nonatomic, strong) LAScene *sceneModel; +@property (nonatomic, strong) LAComposition *sceneModel; @property (nonatomic, assign) BOOL debugModeOn; @end diff --git a/LotteAnimator/LACompView.m b/LotteAnimator/LACompView.m index 4ed7166818..1cc054f04c 100644 --- a/LotteAnimator/LACompView.m +++ b/LotteAnimator/LACompView.m @@ -10,8 +10,8 @@ @implementation LACompView -- (instancetype)initWithModel:(LAScene *)model { - self = [super initWithFrame:CGRectMake(0, 0, model.compWidth.floatValue, model.compHeight.floatValue)]; +- (instancetype)initWithModel:(LAComposition *)model { + self = [super initWithFrame:model.compBounds]; if (self) { _sceneModel = model; for (LALayer *layer in model.layers) { diff --git a/LotteAnimator/LAComposition.h b/LotteAnimator/LAComposition.h index b38f05df14..67690dcc92 100644 --- a/LotteAnimator/LAComposition.h +++ b/LotteAnimator/LAComposition.h @@ -6,16 +6,18 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "MTLModel.h" +#import @class LALayer; -@interface LAComposition : MTLModel +@interface LAComposition : NSObject -@property (nonatomic, strong) NSArray *layers; -@property (nonatomic, strong) NSNumber *compWidth; -@property (nonatomic, strong) NSNumber *compHeight; -@property (nonatomic, strong) NSNumber *startFrame; -@property (nonatomic, strong) NSNumber *endFrame; -@property (nonatomic, strong) NSNumber *framerate; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary; + +@property (nonatomic, readonly) NSArray *layers; +@property (nonatomic, readonly) CGRect compBounds; +@property (nonatomic, readonly) NSNumber *startFrame; +@property (nonatomic, readonly) NSNumber *endFrame; +@property (nonatomic, readonly) NSNumber *framerate; +@property (nonatomic, readonly) NSTimeInterval timeDuration; @end diff --git a/LotteAnimator/LAComposition.m b/LotteAnimator/LAComposition.m index d49ff86c4a..a806da7b39 100644 --- a/LotteAnimator/LAComposition.m +++ b/LotteAnimator/LAComposition.m @@ -11,18 +11,39 @@ @implementation LAComposition -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"compWidth" : @"w", - @"compHeight" : @"h", - @"framerate" : @"fr", - @"startFrame" : @"ip", - @"endFrame" : @"op", - @"layers" : @"layers"}; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary]; + } + return self; } -+ (NSValueTransformer *)layersJSONTransformer { - // tell Mantle to populate diaAttributes property with an array of MDAttribute objects - return [MTLJSONAdapter arrayTransformerWithModelClass:[LALayer class]]; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary { + NSNumber *width = jsonDictionary[@"w"]; + NSNumber *height = jsonDictionary[@"h"]; + if (width && height) { + CGRect bounds = CGRectMake(0, 0, width.floatValue, height.floatValue); + _compBounds = bounds; + } + + _startFrame = [jsonDictionary[@"ip"] copy]; + _endFrame = [jsonDictionary[@"op"] copy]; + _framerate = [jsonDictionary[@"fr"] copy]; + + if (_startFrame && _endFrame && _framerate) { + NSInteger frameDuration = _endFrame.integerValue - _startFrame.integerValue; + NSTimeInterval timeDuration = frameDuration / _framerate.floatValue; + _timeDuration = timeDuration; + } + + NSArray *layersJSON = jsonDictionary[@"layers"]; + NSMutableArray *layers = [NSMutableArray array]; + for (NSDictionary *layerJSON in layersJSON) { + LALayer *layer = [[LALayer alloc] initWithJSON:layerJSON frameRate:_framerate]; + [layers addObject:layer]; + } + _layers = layers; } @end diff --git a/LotteAnimator/LALayer.h b/LotteAnimator/LALayer.h index c1a67a16b2..8d981c7d58 100644 --- a/LotteAnimator/LALayer.h +++ b/LotteAnimator/LALayer.h @@ -6,17 +6,18 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "MTLModel.h" +#import #import -@class LALayerView; -@class LAShape; +@class LAShapeGroup; @class LAMask; @class LAAnimatableColorValue; @class LAAnimatablePointValue; @class LAAnimatableNumberValue; +@class LAAnimatableRectValue; +@class LAAnimatableScaleValue; -typedef enum : NSUInteger { +typedef enum : NSInteger { LALayerTypeNone, LALayerTypeSolid, LALayerTypeUnknown, @@ -24,25 +25,27 @@ typedef enum : NSUInteger { LALayerTypeShape } LALayerType; -@interface LALayer : MTLModel +@interface LALayer : NSObject -@property (nonatomic, copy) NSString *layerName; -@property (nonatomic, copy) NSNumber *layerID; -@property (nonatomic, assign) LALayerType layerType; -@property (nonatomic, copy) NSNumber *parentID; -@property (nonatomic, copy) NSNumber *inPoint; -@property (nonatomic, copy) NSNumber *outPoint; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; -@property (nonatomic, copy) NSArray *shapes; -@property (nonatomic, copy) NSArray *masks; -@property (nonatomic, copy) LAAnimatableNumberValue *solidWidth; -@property (nonatomic, copy) LAAnimatableNumberValue *solidHeight; -@property (nonatomic, copy) LAAnimatableColorValue *solidColor; +@property (nonatomic, readonly) NSString *layerName; +@property (nonatomic, readonly) NSNumber *layerID; +@property (nonatomic, readonly) LALayerType layerType; +@property (nonatomic, readonly) NSNumber *parentID; +@property (nonatomic, readonly) NSNumber *inFrame; +@property (nonatomic, readonly) NSNumber *outFrame; -@property (nonatomic, copy) LAAnimatableNumberValue *opacity; -@property (nonatomic, copy) LAAnimatableNumberValue *rotation; -@property (nonatomic, copy) LAAnimatablePointValue *position; -@property (nonatomic, copy) LAAnimatablePointValue *anchor; -//@property (nonatomic, copy) LAAnimatableProperty *scale; //TODO Make This +@property (nonatomic, readonly) NSArray *shapes; +@property (nonatomic, readonly) NSArray *masks; + +@property (nonatomic, readonly) LAAnimatableRectValue *solidBounds; +@property (nonatomic, readonly) LAAnimatableColorValue *solidColor; + +@property (nonatomic, readonly) LAAnimatableNumberValue *opacity; +@property (nonatomic, readonly) LAAnimatableNumberValue *rotation; +@property (nonatomic, readonly) LAAnimatablePointValue *position; +@property (nonatomic, readonly) LAAnimatablePointValue *anchor; +@property (nonatomic, readonly) LAAnimatableScaleValue *scale; @end diff --git a/LotteAnimator/LALayer.m b/LotteAnimator/LALayer.m index 526d4cf218..25214a6e3b 100644 --- a/LotteAnimator/LALayer.m +++ b/LotteAnimator/LALayer.m @@ -10,143 +10,77 @@ #import "LAAnimatableColorValue.h" #import "LAAnimatablePointValue.h" #import "LAAnimatableNumberValue.h" +#import "LAAnimatableScaleValue.h" +#import "LAShapeGroup.h" @implementation LALayer -+ (NSDictionary *)JSONKeyPathsByPropertyKey -{ - // model_property_name : json_field_name - return @{ - @"layerName" : @"layerName", - @"layerID" : @"ind", - @"layerType" : @"ty", - @"parentID" : @"parent", - @"inPoint" : @"ip", - @"outPoint" : @"op", - - @"rotation" : @"ks.r", - @"position" : @"ks.p", - @"anchor" : @"ks.a", -// @"scale" : @"ks.s", - @"opacity" : @"ks.o", - - @"solidWidth" : @"sw", - @"solidHeight" : @"sh", - @"solidColor" : @"sc", -// @"masks" : @"masksProperties", -// @"shapes" : @"shapes" - }; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; } -+ (NSValueTransformer *)shapesJSONTransformer { - return [MTLJSONAdapter arrayTransformerWithModelClass:[LAShape class]]; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + _layerName = [jsonDictionary[@"nm"] copy]; + _layerID = [jsonDictionary[@"ind"] copy]; + + NSNumber *layerType = jsonDictionary[@"ty"]; + if (layerType.integerValue <= LALayerTypeShape) { + _layerType = layerType.integerValue; + } else { + _layerType = LALayerTypeUnknown; + } + + _parentID = [jsonDictionary[@"parent"] copy]; + _inFrame = [jsonDictionary[@"ip"] copy]; + _outFrame = [jsonDictionary[@"op"] copy]; + + if (_layerType == LALayerTypeSolid) { + // TODO Solids. + + } + + NSDictionary *opacity = jsonDictionary[@"ks.o"]; + if (opacity) { + _opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity]; + } + + NSDictionary *rotation = jsonDictionary[@"ks.r"]; + if (rotation) { + _rotation = [[LAAnimatableNumberValue alloc] initWithNumberValues:rotation]; + } + + NSDictionary *position = jsonDictionary[@"ks.p"]; + if (position) { + _position = [[LAAnimatablePointValue alloc] initWithPointValues:position]; + } + + NSDictionary *anchor = jsonDictionary[@"ks.a"]; + if (anchor) { + _anchor = [[LAAnimatablePointValue alloc] initWithPointValues:anchor]; + } + + NSDictionary *scale = jsonDictionary[@"ks.s"]; + if (scale) { + _scale = [[LAAnimatableScaleValue alloc] initWithScaleValues:scale]; + } + + NSMutableArray *masks = [NSMutableArray array]; + for (NSDictionary *maskJSON in jsonDictionary[@"masksProperties"]) { + LAMask *mask = [[LAMask alloc] initWithJSON:maskJSON frameRate:frameRate]; + [masks addObject:mask]; + } + _masks = masks; + + NSMutableArray *shapes = [NSMutableArray array]; + for (NSDictionary *shapeJSON in jsonDictionary[@"shapes"]) { + LAShapeGroup *group = [[LAShapeGroup alloc] initWithJSON:shapeJSON frameRate:frameRate]; + [shapes addObject:group]; + } + _shapes = shapes; } -+ (NSValueTransformer *)masksJSONTransformer { - return [MTLJSONAdapter arrayTransformerWithModelClass:[LAMask class]]; -} - -+ (NSValueTransformer *)rotationJSONTransformer { - return [MTLValueTransformer transformerUsingForwardBlock:^id(NSDictionary *value, BOOL *success, NSError *__autoreleasing *error) { - if (value == nil) { - return nil; - } - if (![value isKindOfClass:NSDictionary.class]) { - if (error != NULL) { - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Could not convert JSON dictionary to model object", @""), - NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:NSLocalizedString(@"Expected an NSDictionary, got: %@", @""), value], - MTLTransformerErrorHandlingInputValueErrorKey : value - }; - - *error = [NSError errorWithDomain:MTLTransformerErrorHandlingErrorDomain code:MTLTransformerErrorHandlingErrorInvalidInput userInfo:userInfo]; - } - *success = NO; - return nil; - } - LAAnimatableNumberValue *numvalue = [[LAAnimatableNumberValue alloc] initWithNumberValues:<#(NSDictionary *)#> keyPath:<#(NSString *)#> frameRate:<#(NSNumber *)#>] - }]; -} - -//+ (NSValueTransformer *)rotationJSONTransformer { -// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"rotation"]; -//} -// -//+ (NSValueTransformer *)positionJSONTransformer { -// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"position"]; -//} -// -//+ (NSValueTransformer *)anchorJSONTransformer { -// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"anchor"]; -//} -// -//+ (NSValueTransformer *)scaleJSONTransformer { -// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"scale"]; -//} -// -//+ (NSValueTransformer *)opacityJSONTransformer { -// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"opacity"]; -//} - -//- (UIColor *)bgColor { -// if (!self.color) { -// return [UIColor clearColor]; -// } -// NSString *hexString = [self.color copy]; -// hexString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""]; -// -// return [UIColor colorWithHexString:hexString]; -//} -// -//- (CGPoint)position { -// if (!self.positionArray) { -// return CGPointZero; -// } -// CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]); -// if (self.anchorPointArray) { -// aePosition.x -= [self.anchorPointArray[0] floatValue]; -// aePosition.y -= [self.anchorPointArray[1] floatValue]; -// } -// return aePosition; -//} -// -//- (CGPoint)anchorPoint { -// if (!self.anchorPointArray) { -// return CGPointZero; -// } -// CGPoint aeAnchorPoint = CGPointMake([self.anchorPointArray[0] floatValue], [self.anchorPointArray[1] floatValue]); -// CGPoint uikitAnchorPoint = CGPointMake(aeAnchorPoint.x / self.size.width, -// aeAnchorPoint.y / self.size.height); -// return uikitAnchorPoint; -//} -// -//- (CGSize)size { -// if (!self.width && !self.height) { -// return CGSizeZero; -// } -// return CGSizeMake(self.width.floatValue, self.height.floatValue); -//} -// -//- (CGSize)scale { -// if (!self.scaleArray) { -// return CGSizeZero; -// } -// return CGSizeMake([self.scaleArray[0] floatValue] / 100.f, [self.scaleArray[1] floatValue] / 100.f); -//} -// -//- (CGFloat)alpha { -// if (!self.opacity) { -// return 1; -// } -// return self.opacity.floatValue / 100.f; -//} -// -//- (CGRect)frameRect { -// return CGRectMake(self.position.x, self.position.y, self.size.width, self.size.height); -//} -// -//- (CGAffineTransform)transform { -// return CGAffineTransformRotate(CGAffineTransformMakeScale(self.scale.width, self.scale.height), DegreesToRadians(self.rotation ? self.rotation.floatValue : 0.f)); -//} - @end diff --git a/LotteAnimator/LAMask.h b/LotteAnimator/LAMask.h index 3354a82ec7..ccb82a31ee 100644 --- a/LotteAnimator/LAMask.h +++ b/LotteAnimator/LAMask.h @@ -6,13 +6,25 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "MTLModel.h" +#import +@class LAAnimatableShapeValue; +@class LAAnimatableNumberValue; -@interface LAMask : MTLModel +typedef enum : NSUInteger { + LAMaskModeAdd, + LAMaskModeSubtract, + LAMaskModeIntersect, + LAMaskModeUnknown +} LAMaskMode; -@property (nonatomic, getter=isClosed) BOOL closed; -@property (nonatomic, getter=isInverted) BOOL inverted; -@property (nonatomic, strong) LAPath *maskPath; -@property (nonatomic, copy) NSNumber *opacity; +@interface LAMask : NSObject + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) BOOL closed; +@property (nonatomic, readonly) BOOL inverted; +@property (nonatomic, readonly) LAMaskMode maskMode; +@property (nonatomic, readonly) LAAnimatableShapeValue *maskPath; +@property (nonatomic, readonly) LAAnimatableNumberValue *opacity; @end diff --git a/LotteAnimator/LAMask.m b/LotteAnimator/LAMask.m index 73b74d5143..3d3dc38c56 100644 --- a/LotteAnimator/LAMask.m +++ b/LotteAnimator/LAMask.m @@ -7,27 +7,46 @@ // #import "LAMask.h" +#import "LAAnimatableShapeValue.h" +#import "LAAnimatableNumberValue.h" @implementation LAMask -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"closed" : @"cl", - @"inverted" : @"inv", - @"maskPath" : @"pt", - @"opacity" : @"o"}; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; } -+ (NSValueTransformer *)maskPathJSONTransformer { - // tell Mantle to populate diaAttributes property with an array of MDAttribute objects - return [MTLJSONAdapter dictionaryTransformerWithModelClass:[LAPath class]]; -} - -+ (NSValueTransformer *)closedJSONTransformer { - return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName]; -} - -+ (NSValueTransformer *)invertedJSONTransformer { - return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName]; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSNumber *closed = jsonDictionary[@"cl"]; + _closed = closed.boolValue; + + NSNumber *inverted = jsonDictionary[@"inv"]; + _inverted = inverted.boolValue; + + NSString *mode = jsonDictionary[@"mode"]; + if ([mode isEqualToString:@"a"]) { + _maskMode = LAMaskModeAdd; + } else if ([mode isEqualToString:@"s"]) { + _maskMode = LAMaskModeSubtract; + } else if ([mode isEqualToString:@"i"]) { + _maskMode = LAMaskModeIntersect; + } else { + _maskMode = LAMaskModeUnknown; + } + + NSDictionary *maskshape = jsonDictionary[@"pt"]; + if (maskshape) { + _maskPath = [[LAAnimatableShapeValue alloc] initWithShapeValues:maskshape closed:_closed]; + } + + NSDictionary *opacity = jsonDictionary[@"o"]; + if (opacity) { + _opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity]; + } } @end diff --git a/LotteAnimator/LAModels.h b/LotteAnimator/LAModels.h index 9b6c1408b3..b6741fb122 100644 --- a/LotteAnimator/LAModels.h +++ b/LotteAnimator/LAModels.h @@ -9,12 +9,10 @@ #ifndef LAModels_h #define LAModels_h -#import "LAPath.h" #import "LAMask.h" #import "LAComposition.h" #import "LALayer.h" -#import "LAShape.h" -#import "LAShapeItem.h" +#import "LAShapeGroup.h" #import "LAShapePath.h" #import "LAShapeStroke.h" #import "LAShapeFill.h" diff --git a/LotteAnimator/LAPath.h b/LotteAnimator/LAPath.h deleted file mode 100644 index 31724fb897..0000000000 --- a/LotteAnimator/LAPath.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// LABezierPath.h -// LotteAnimator -// -// Created by Brandon Withrow on 12/14/15. -// Copyright © 2015 Brandon Withrow. All rights reserved. -// - -#import "MTLModel.h" - -@interface LAPath : MTLModel - -@property (nonatomic, strong) NSArray *points; -@property (nonatomic, strong) NSArray *inTangents; -@property (nonatomic, strong) NSArray *outTangents; - -- (UIBezierPath *)bezierPath:(BOOL)closedPath; - -@end diff --git a/LotteAnimator/LAPath.m b/LotteAnimator/LAPath.m deleted file mode 100644 index 435ee56710..0000000000 --- a/LotteAnimator/LAPath.m +++ /dev/null @@ -1,54 +0,0 @@ -// -// LABezierPath.m -// LotteAnimator -// -// Created by Brandon Withrow on 12/14/15. -// Copyright © 2015 Brandon Withrow. All rights reserved. -// - -#import "LAPath.h" - -@implementation LAPath - -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"points" : @"v", - @"inTangents" : @"i", - @"outTangents" : @"o"}; -} - -- (UIBezierPath *)bezierPath:(BOOL)closedPath { - if (!self.points.count) { - return nil; - } - UIBezierPath *path = [UIBezierPath bezierPath]; - - [path moveToPoint:[self _vertexAtIndex:0]]; - for (int i = 1; i < self.points.count; i ++) { - [path addCurveToPoint:[self _vertexAtIndex:i] controlPoint1:[self _outTangentAtIndex:i - 1] controlPoint2:[self _inTangentAtIndex:i]]; - } - - if (closedPath) { - [path addCurveToPoint:[self _vertexAtIndex:0] controlPoint1:[self _outTangentAtIndex:self.points.count - 1] controlPoint2:[self _inTangentAtIndex:0]]; - [path closePath]; - } - - return path; -} - -- (CGPoint)_vertexAtIndex:(NSInteger)idx { - NSArray *pointArray = self.points[idx]; - return CGPointMake([pointArray[0] floatValue], [pointArray[1] floatValue]); -} - -- (CGPoint)_outTangentAtIndex:(NSInteger)idx { - NSArray *outArray = self.outTangents[idx]; - CGPoint vertex = [self _vertexAtIndex:idx]; - return CGPointMake([outArray[0] floatValue] + vertex.x, [outArray[1] floatValue] + vertex.y); -} - -- (CGPoint)_inTangentAtIndex:(NSInteger)idx { - NSArray *inArray = self.inTangents[idx]; - CGPoint vertex = [self _vertexAtIndex:idx]; - return CGPointMake([inArray[0] floatValue] + vertex.x, [inArray[1] floatValue] + vertex.y); -} -@end diff --git a/LotteAnimator/LAShape.h b/LotteAnimator/LAShape.h deleted file mode 100644 index 3b91fd6a4b..0000000000 --- a/LotteAnimator/LAShape.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// LAShape.h -// LotteAnimator -// -// Created by Brandon Withrow on 12/14/15. -// Copyright © 2015 Brandon Withrow. All rights reserved. -// - -#import "MTLModel.h" - -@interface LAShape : MTLModel - -@property (nonatomic, copy) NSArray *shapeItems; -// TODO Map these items more efficiently for use in LALayerView -// This is extremely inefficient and unsafe. -@property (nonatomic, readonly) NSArray *paths; -@property (nonatomic, readonly) NSArray *strokes; -@property (nonatomic, readonly) NSArray *fills; -@property (nonatomic, readonly) NSArray *transforms; - -@end diff --git a/LotteAnimator/LAShape.m b/LotteAnimator/LAShape.m deleted file mode 100644 index 956c71b98d..0000000000 --- a/LotteAnimator/LAShape.m +++ /dev/null @@ -1,85 +0,0 @@ -// -// LAShape.m -// LotteAnimator -// -// Created by Brandon Withrow on 12/14/15. -// Copyright © 2015 Brandon Withrow. All rights reserved. -// - -#import "LAShape.h" -#import "LAShapeItem.h" - -@implementation LAShape - -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"shapeItems" : @"it"}; -} - -+ (NSValueTransformer *)shapeItemsJSONTransformer { - // tell Mantle to populate diaAttributes property with an array of MDAttribute objects - return [MTLJSONAdapter arrayTransformerWithModelClass:[LAShapeItem class]]; -} - -- (NSArray *)paths { - if (!self.shapeItems) { - return @[]; - } - NSMutableArray *paths = [NSMutableArray array]; - - for (LAShapeItem *item in self.shapeItems) { - if ([item.itemType isEqualToString:LAShapeItemType.Path] || - [item.itemType isEqualToString:LAShapeItemType.Circle] || - [item.itemType isEqualToString:LAShapeItemType.Rectangle]) { - [paths addObject:item]; - } - } - - return paths; -} - -- (NSArray *)strokes { - if (!self.shapeItems) { - return @[]; - } - NSMutableArray *strokes = [NSMutableArray array]; - - for (LAShapeItem *item in self.shapeItems) { - if ([item.itemType isEqualToString:LAShapeItemType.Stroke]) { - [strokes addObject:item]; - } - } - - return strokes; -} - -- (NSArray *)fills { - if (!self.shapeItems) { - return @[]; - } - NSMutableArray *fills = [NSMutableArray array]; - - for (LAShapeItem *item in self.shapeItems) { - if ([item.itemType isEqualToString:LAShapeItemType.Fill]) { - [fills addObject:item]; - } - } - - return fills; -} - -- (NSArray *)transforms { - if (!self.shapeItems) { - return @[]; - } - NSMutableArray *transforms = [NSMutableArray array]; - - for (LAShapeItem *item in self.shapeItems) { - if ([item.itemType isEqualToString:LAShapeItemType.Transform]) { - [transforms addObject:item]; - } - } - - return transforms; -} - -@end diff --git a/LotteAnimator/LAShapeCircle.h b/LotteAnimator/LAShapeCircle.h index 0dfe616a54..8421f50b6d 100644 --- a/LotteAnimator/LAShapeCircle.h +++ b/LotteAnimator/LAShapeCircle.h @@ -6,14 +6,10 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "LAShapeItem.h" +#import -@interface LAShapeCircle : LAShapeItem +@interface LAShapeCircle : NSObject -@property (nonatomic, copy) NSArray *positionArray; -@property (nonatomic, copy) NSArray *sizeArray; - -@property (nonatomic, readonly) CGPoint position; -@property (nonatomic, readonly) CGSize size; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; @end diff --git a/LotteAnimator/LAShapeCircle.m b/LotteAnimator/LAShapeCircle.m index 4672c34b2b..ef4ec4168f 100644 --- a/LotteAnimator/LAShapeCircle.m +++ b/LotteAnimator/LAShapeCircle.m @@ -10,30 +10,16 @@ @implementation LAShapeCircle -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty", - @"positionArray" : @"p", - @"sizeArray" : @"s"}; -} - -- (CGPoint)position { - if (!self.positionArray) { - return CGPointZero; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; } - CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]); - - return aePosition; + return self; } -- (CGSize)size { - if (!self.sizeArray) { - return CGSizeZero; - } - return CGSizeMake([self.sizeArray[0] floatValue], [self.sizeArray[1] floatValue]); +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + } -- (UIBezierPath *)path { - CGRect circleBounds = CGRectMake(self.size.width * -0.5, self.size.height * -0.5, self.size.width, self.size.height); - return [UIBezierPath bezierPathWithOvalInRect:circleBounds]; -} @end diff --git a/LotteAnimator/LAShapeFill.h b/LotteAnimator/LAShapeFill.h index 72cb5d0fd4..e72eacd4c6 100644 --- a/LotteAnimator/LAShapeFill.h +++ b/LotteAnimator/LAShapeFill.h @@ -6,14 +6,17 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "LAShapeItem.h" +#import -@interface LAShapeFill : LAShapeItem +@class LAAnimatableColorValue; +@class LAAnimatableNumberValue; -@property (nonatomic, getter=isFillEnabled) BOOL fillEnabled; -@property (nonatomic, copy) NSArray *colorElements; -@property (nonatomic, copy) NSNumber *opacity; +@interface LAShapeFill : NSObject + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) BOOL fillEnabled; +@property (nonatomic, readonly) LAAnimatableColorValue *color; +@property (nonatomic, readonly) LAAnimatableNumberValue *opacity; -@property (nonatomic, readonly) UIColor *color; -@property (nonatomic, readonly) CGFloat alpha; @end diff --git a/LotteAnimator/LAShapeFill.m b/LotteAnimator/LAShapeFill.m index e779f5086f..212d80b97b 100644 --- a/LotteAnimator/LAShapeFill.m +++ b/LotteAnimator/LAShapeFill.m @@ -7,35 +7,32 @@ // #import "LAShapeFill.h" +#import "LAAnimatableNumberValue.h" +#import "LAAnimatableColorValue.h" @implementation LAShapeFill -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty", - @"fillEnabled" : @"fillEnabled", - @"colorElements" : @"c", - @"opacity" : @"o"}; -} - -+ (NSValueTransformer *)fillEnabledJSONTransformer { - return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName]; -} - -- (CGFloat)alpha { - if (!self.opacity) { - return 1; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; } - return self.opacity.floatValue / 100.f; + return self; } -- (UIColor *)color { - if (!self.colorElements) { - return [UIColor clearColor]; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSDictionary *color = jsonDictionary[@"c"]; + if (color) { + _color = [[LAAnimatableColorValue alloc] initWithColorValues:color]; } - return [UIColor colorWithRed:([self.colorElements[0] floatValue]/255.f) - green:([self.colorElements[1] floatValue]/255.f) - blue:([self.colorElements[2] floatValue]/255.f) - alpha:([self.colorElements[3] floatValue]/255.f)]; + + NSDictionary *opacity = jsonDictionary[@"o"]; + if (opacity) { + _opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity]; + } + + NSNumber *fillEnabled = jsonDictionary[@"fillEnabled"]; + _fillEnabled = fillEnabled.boolValue; } @end diff --git a/LotteAnimator/LAShapeGroup.h b/LotteAnimator/LAShapeGroup.h new file mode 100644 index 0000000000..aa7eb4418f --- /dev/null +++ b/LotteAnimator/LAShapeGroup.h @@ -0,0 +1,17 @@ +// +// LAShape.h +// LotteAnimator +// +// Created by Brandon Withrow on 12/14/15. +// Copyright © 2015 Brandon Withrow. All rights reserved. +// + +#import + +@interface LAShapeGroup : NSObject + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) NSArray *items; + +@end diff --git a/LotteAnimator/LAShapeGroup.m b/LotteAnimator/LAShapeGroup.m new file mode 100644 index 0000000000..305f5ec73e --- /dev/null +++ b/LotteAnimator/LAShapeGroup.m @@ -0,0 +1,59 @@ +// +// LAShape.m +// LotteAnimator +// +// Created by Brandon Withrow on 12/14/15. +// Copyright © 2015 Brandon Withrow. All rights reserved. +// + +#import "LAShapeGroup.h" +#import "LAShapeFill.h" +#import "LAShapePath.h" +#import "LAShapeCircle.h" +#import "LAShapeStroke.h" +#import "LAShapeTransform.h" +#import "LAShapeRectangle.h" + +@implementation LAShapeGroup + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; +} + +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSArray *itemsJSON = jsonDictionary[@"it"]; + NSMutableArray *items = [NSMutableArray array]; + for (NSDictionary *itemJSON in itemsJSON) { + NSString *type = itemJSON[@"ty"]; + + if ([type isEqualToString:@"gr"]) { + LAShapeGroup *group = [[LAShapeGroup alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:group]; + } else if ([type isEqualToString:@"st"]) { + LAShapeStroke *stroke = [[LAShapeStroke alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:stroke]; + } else if ([type isEqualToString:@"fl"]) { + LAShapeFill *fill = [[LAShapeFill alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:fill]; + } else if ([type isEqualToString:@"tr"]) { + LAShapeTransform *transform = [[LAShapeTransform alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:transform]; + } else if ([type isEqualToString:@"sh"]) { + LAShapePath *path = [[LAShapePath alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:path]; + } else if ([type isEqualToString:@"el"]) { + LAShapeCircle *circle = [[LAShapeCircle alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:circle]; + } else if ([type isEqualToString:@"rc"]) { + LAShapeRectangle *rectangle = [[LAShapeRectangle alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:rectangle]; + } + } + _items = items; +} + +@end diff --git a/LotteAnimator/LAShapeItem.h b/LotteAnimator/LAShapeItem.h deleted file mode 100644 index 338391e04a..0000000000 --- a/LotteAnimator/LAShapeItem.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// LAShapeItem.h -// LotteAnimator -// -// Created by Brandon Withrow on 12/15/15. -// Copyright © 2015 Brandon Withrow. All rights reserved. -// - -#import "MTLModel.h" - -struct LAShapeItemType { - __unsafe_unretained NSString * const Path; - __unsafe_unretained NSString * const Stroke; - __unsafe_unretained NSString * const Fill; - __unsafe_unretained NSString * const Transform; - __unsafe_unretained NSString * const Circle; - __unsafe_unretained NSString * const Rectangle; -}; - -extern const struct LAShapeItemType LAShapeItemType; - -@interface LAShapeItem : MTLModel - -@property (nonatomic, copy) NSString *itemType; - -@property (nonatomic, readonly) UIBezierPath *path; - -@end diff --git a/LotteAnimator/LAShapeItem.m b/LotteAnimator/LAShapeItem.m deleted file mode 100644 index 7728aa76a9..0000000000 --- a/LotteAnimator/LAShapeItem.m +++ /dev/null @@ -1,54 +0,0 @@ -// -// LAShapeItem.m -// LotteAnimator -// -// Created by Brandon Withrow on 12/15/15. -// Copyright © 2015 Brandon Withrow. All rights reserved. -// - -#import "LAShapeItem.h" - -const struct LAShapeItemType LAShapeItemType = { - .Path = @"sh", - .Stroke = @"st", - .Fill = @"fl", - .Transform = @"tr", - .Circle = @"el", - .Rectangle = @"rc" -}; - -@implementation LAShapeItem - -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty"}; -} - -+ (Class)classForParsingJSONDictionary:(NSDictionary *)JSONDictionary { - if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Path]) { - return LAShapePath.class; - } - - if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Stroke]) { - return LAShapeStroke.class; - } - - if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Fill]) { - return LAShapeFill.class; - } - - if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Transform]) { - return LAShapeTransform.class; - } - - if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Circle]) { - return LAShapeCircle.class; - } - - if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Rectangle]) { - return LAShapeRectangle.class; - } - - return self; -} - -@end diff --git a/LotteAnimator/LAShapePath.h b/LotteAnimator/LAShapePath.h index 5410460dfe..5d8e8cf77a 100644 --- a/LotteAnimator/LAShapePath.h +++ b/LotteAnimator/LAShapePath.h @@ -6,11 +6,16 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "LAShapeItem.h" +#import -@interface LAShapePath : LAShapeItem +@class LAAnimatableShapeValue; -@property (nonatomic, getter=isClosed) BOOL closed; -@property (nonatomic, strong) LAPath *shapePath; +@interface LAShapePath : NSObject + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) BOOL closed; +@property (nonatomic, readonly) NSNumber *index; +@property (nonatomic, readonly) LAAnimatableShapeValue *shapePath; @end diff --git a/LotteAnimator/LAShapePath.m b/LotteAnimator/LAShapePath.m index 8b811ff2c5..942fb69ae5 100644 --- a/LotteAnimator/LAShapePath.m +++ b/LotteAnimator/LAShapePath.m @@ -7,25 +7,25 @@ // #import "LAShapePath.h" +#import "LAAnimatableShapeValue.h" @implementation LAShapePath -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty", - @"closed" : @"closed", - @"shapePath" : @"ks"}; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; } -+ (NSValueTransformer *)shapePathJSONTransformer { - // tell Mantle to populate diaAttributes property with an array of MDAttribute objects - return [MTLJSONAdapter dictionaryTransformerWithModelClass:[LAPath class]]; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + _index = jsonDictionary[@"ind"]; + _closed = [jsonDictionary[@"closed"] boolValue]; + NSDictionary *shape = jsonDictionary[@"ks"]; + if (shape) { + _shapePath = [[LAAnimatableShapeValue alloc] initWithShapeValues:shape closed:_closed]; + } } -+ (NSValueTransformer *)closedJSONTransformer { - return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName]; -} - -- (UIBezierPath *)path { - return [self.shapePath bezierPath:self.isClosed]; -} @end diff --git a/LotteAnimator/LAShapeRectangle.h b/LotteAnimator/LAShapeRectangle.h index 1c4d69bfd4..2298e9f667 100644 --- a/LotteAnimator/LAShapeRectangle.h +++ b/LotteAnimator/LAShapeRectangle.h @@ -6,15 +6,10 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "LAShapeItem.h" +#import -@interface LAShapeRectangle : LAShapeItem +@interface LAShapeRectangle : NSObject -@property (nonatomic, copy) NSArray *positionArray; -@property (nonatomic, copy) NSArray *sizeArray; -@property (nonatomic, copy) NSNumber *cornerRadius; - -@property (nonatomic, readonly) CGPoint position; -@property (nonatomic, readonly) CGSize size; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; @end diff --git a/LotteAnimator/LAShapeRectangle.m b/LotteAnimator/LAShapeRectangle.m index 14723985a5..4ac342e836 100644 --- a/LotteAnimator/LAShapeRectangle.m +++ b/LotteAnimator/LAShapeRectangle.m @@ -10,38 +10,16 @@ @implementation LAShapeRectangle -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty", - @"positionArray" : @"p", - @"sizeArray" : @"s", - @"cornerRadius" : @"r"}; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; } -- (CGPoint)position { - if (!self.positionArray) { - return CGPointZero; - } - CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]); +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { - return aePosition; -} - -- (CGSize)size { - if (!self.sizeArray) { - return CGSizeZero; - } - return CGSizeMake([self.sizeArray[0] floatValue], [self.sizeArray[1] floatValue]); -} - -- (UIBezierPath *)path { - CGRect rectBounds = CGRectMake(self.size.width * -0.5, self.size.height * -0.5, self.size.width, self.size.height); - UIBezierPath *path; - if (self.cornerRadius && self.cornerRadius.floatValue > 0.0) { - path = [UIBezierPath bezierPathWithRoundedRect:rectBounds cornerRadius:self.cornerRadius.floatValue]; - } else { - path = [UIBezierPath bezierPathWithRect:rectBounds]; - } - return path; } @end diff --git a/LotteAnimator/LAShapeStroke.h b/LotteAnimator/LAShapeStroke.h index 49d01f4de7..f795df4cae 100644 --- a/LotteAnimator/LAShapeStroke.h +++ b/LotteAnimator/LAShapeStroke.h @@ -6,16 +6,18 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "LAShapeItem.h" +#import -@interface LAShapeStroke : LAShapeItem +@class LAAnimatableColorValue; +@class LAAnimatableNumberValue; -@property (nonatomic, getter=isFillEnabled) BOOL fillEnabled; -@property (nonatomic, copy) NSArray *colorElements; -@property (nonatomic, copy) NSNumber *opacity; -@property (nonatomic, copy) NSNumber *width; +@interface LAShapeStroke : NSObject -@property (nonatomic, readonly) UIColor *color; -@property (nonatomic, readonly) CGFloat alpha; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) BOOL fillEnabled; +@property (nonatomic, readonly) LAAnimatableColorValue *color; +@property (nonatomic, readonly) LAAnimatableNumberValue *opacity; +@property (nonatomic, readonly) LAAnimatableNumberValue *width; @end diff --git a/LotteAnimator/LAShapeStroke.m b/LotteAnimator/LAShapeStroke.m index d0ddb31c87..30a8815e53 100644 --- a/LotteAnimator/LAShapeStroke.m +++ b/LotteAnimator/LAShapeStroke.m @@ -7,36 +7,37 @@ // #import "LAShapeStroke.h" +#import "LAAnimatableNumberValue.h" +#import "LAAnimatableColorValue.h" @implementation LAShapeStroke -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty", - @"fillEnabled" : @"fillEnabled", - @"colorElements" : @"c", - @"opacity" : @"o", - @"width" : @"w"}; -} - -+ (NSValueTransformer *)fillEnabledJSONTransformer { - return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName]; -} - -- (CGFloat)alpha { - if (!self.opacity) { - return 1; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; } - return self.opacity.floatValue / 100.f; + return self; } -- (UIColor *)color { - if (!self.colorElements) { - return [UIColor clearColor]; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSDictionary *color = jsonDictionary[@"c"]; + if (color) { + _color = [[LAAnimatableColorValue alloc] initWithColorValues:color]; } - return [UIColor colorWithRed:([self.colorElements[0] floatValue]/255.f) - green:([self.colorElements[1] floatValue]/255.f) - blue:([self.colorElements[2] floatValue]/255.f) - alpha:([self.colorElements[3] floatValue]/255.f)]; + + NSDictionary *width = jsonDictionary[@"w"]; + if (width) { + _width = [[LAAnimatableNumberValue alloc] initWithNumberValues:width]; + } + + NSDictionary *opacity = jsonDictionary[@"o"]; + if (opacity) { + _opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity]; + } + + NSNumber *fillEnabled = jsonDictionary[@"fillEnabled"]; + _fillEnabled = fillEnabled.boolValue; } @end diff --git a/LotteAnimator/LAShapeTransform.h b/LotteAnimator/LAShapeTransform.h index 60a5393220..b217aaaff6 100644 --- a/LotteAnimator/LAShapeTransform.h +++ b/LotteAnimator/LAShapeTransform.h @@ -6,20 +6,20 @@ // Copyright © 2015 Brandon Withrow. All rights reserved. // -#import "LAShapeItem.h" +#import -@interface LAShapeTransform : LAShapeItem +@class LAAnimatableNumberValue; +@class LAAnimatablePointValue; +@class LAAnimatableScaleValue; -@property (nonatomic, copy) NSArray *positionArray; -@property (nonatomic, copy) NSArray *anchorPointArray; -@property (nonatomic, copy) NSArray *scaleArray; -@property (nonatomic, copy) NSNumber *rotation; -@property (nonatomic, copy) NSNumber *opacity; +@interface LAShapeTransform : NSObject -@property (nonatomic, readonly) CGPoint position; -@property (nonatomic, readonly) CGPoint anchorPoint; -@property (nonatomic, readonly) CGSize scale; -@property (nonatomic, readonly) CGFloat alpha; -@property (nonatomic, readonly) CGAffineTransform transform; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) LAAnimatablePointValue *position; +@property (nonatomic, readonly) LAAnimatablePointValue *anchor; +@property (nonatomic, readonly) LAAnimatableScaleValue *scale; +@property (nonatomic, readonly) LAAnimatableNumberValue *rotation; +@property (nonatomic, readonly) LAAnimatableNumberValue *opacity; @end diff --git a/LotteAnimator/LAShapeTransform.m b/LotteAnimator/LAShapeTransform.m index ad347f2cc3..b0f33c549a 100644 --- a/LotteAnimator/LAShapeTransform.m +++ b/LotteAnimator/LAShapeTransform.m @@ -7,61 +7,45 @@ // #import "LAShapeTransform.h" +#import "LAAnimatableNumberValue.h" +#import "LAAnimatablePointValue.h" +#import "LAAnimatableScaleValue.h" @implementation LAShapeTransform -+ (NSDictionary *)JSONKeyPathsByPropertyKey { - return @{@"itemType" : @"ty", - @"positionArray" : @"p", - @"anchorPointArray" : @"a", - @"scaleArray" : @"s", - @"rotation" : @"r", - @"opacity" : @"o"}; +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; } -- (CGPoint)position { - if (!self.positionArray) { - return CGPointZero; +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSDictionary *position = jsonDictionary[@"p"]; + if (position) { + _position = [[LAAnimatablePointValue alloc] initWithPointValues:position]; } - CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]); - if (self.anchorPointArray) { - aePosition.x -= [self.anchorPointArray[0] floatValue]; - aePosition.y -= [self.anchorPointArray[1] floatValue]; + + NSDictionary *anchor = jsonDictionary[@"a"]; + if (anchor) { + _anchor = [[LAAnimatablePointValue alloc] initWithPointValues:anchor]; } - return aePosition; -} - -- (CGPoint)anchorPoint { - if (!self.anchorPointArray) { - return CGPointZero; + + NSDictionary *scale = jsonDictionary[@"s"]; + if (scale) { + _scale = [[LAAnimatableScaleValue alloc] initWithScaleValues:scale]; } - CGPoint aeAnchorPoint = CGPointMake([self.anchorPointArray[0] floatValue], [self.anchorPointArray[1] floatValue]); -// CGPoint uikitAnchorPoint = CGPointMake(aeAnchorPoint.x / self.size.width, -// aeAnchorPoint.y / self.size.height); - // TODO Figure out this crazy thing - return aeAnchorPoint; -} - -// TODO Permanently Unwrap these arrays for efficency -- (CGSize)scale { - if (!self.scaleArray) { - return CGSizeZero; + + NSDictionary *rotation = jsonDictionary[@"r"]; + if (rotation) { + _rotation = [[LAAnimatableNumberValue alloc] initWithNumberValues:rotation]; } - return CGSizeMake([self.scaleArray[0] floatValue] / 100.f, [self.scaleArray[1] floatValue] / 100.f); -} - -- (CGFloat)alpha { - if (!self.opacity) { - return 1; + + NSDictionary *opacity = jsonDictionary[@"o"]; + if (opacity) { + _opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity]; } - return self.opacity.floatValue / 100.f; -} - -- (CGAffineTransform)transform { - CGAffineTransform translate = CGAffineTransformMakeTranslation(self.position.x, self.position.y); - CGAffineTransform scale = CGAffineTransformScale(translate, self.scale.width, self.scale.height); - CGAffineTransform rotate = CGAffineTransformRotate(scale, DegreesToRadians(self.rotation ? self.rotation.floatValue : 0.f)); - return rotate; } @end diff --git a/LotteAnimator/ViewController.m b/LotteAnimator/ViewController.m index b91dd7c35c..f34ceb1831 100644 --- a/LotteAnimator/ViewController.m +++ b/LotteAnimator/ViewController.m @@ -33,7 +33,7 @@ NSData *jsonData = [[NSData alloc] initWithContentsOfFile:filePath]; NSDictionary *JSONObject = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; - LAComposition *laScene = [MTLJSONAdapter modelOfClass:[LAComposition class] fromJSONDictionary:JSONObject error:&error]; + LAComposition *laScene = [[LAComposition alloc] initWithJSON:JSONObject]; }