123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- //
- // LOTRenderGroup.m
- // Lottie
- //
- // Created by brandon_withrow on 6/27/17.
- // Copyright © 2017 Airbnb. All rights reserved.
- //
- #import "LOTRenderGroup.h"
- #import "LOTModels.h"
- #import "LOTPathAnimator.h"
- #import "LOTFillRenderer.h"
- #import "LOTStrokeRenderer.h"
- #import "LOTNumberInterpolator.h"
- #import "LOTTransformInterpolator.h"
- #import "LOTCircleAnimator.h"
- #import "LOTRoundedRectAnimator.h"
- #import "LOTTrimPathNode.h"
- #import "LOTShapeStar.h"
- #import "LOTPolygonAnimator.h"
- #import "LOTPolystarAnimator.h"
- #import "LOTShapeGradientFill.h"
- #import "LOTGradientFillRender.h"
- #import "LOTRepeaterRenderer.h"
- #import "LOTShapeRepeater.h"
- @implementation LOTRenderGroup {
- LOTAnimatorNode *_rootNode;
- LOTBezierPath *_outputPath;
- LOTBezierPath *_localPath;
- BOOL _rootNodeHasUpdate;
- LOTNumberInterpolator *_opacityInterpolator;
- LOTTransformInterpolator *_transformInterpolator;
- }
- - (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode * _Nullable)inputNode
- contents:(NSArray * _Nonnull)contents
- keyname:(NSString * _Nullable)keyname {
- self = [super initWithInputNode:inputNode keyName:keyname];
- if (self) {
- _containerLayer = [CALayer layer];
- _containerLayer.actions = @{@"transform": [NSNull null],
- @"opacity": [NSNull null]};
- [self buildContents:contents];
- }
- return self;
- }
- - (NSDictionary *)valueInterpolators {
- if (_opacityInterpolator && _transformInterpolator) {
- return @{@"Opacity" : _opacityInterpolator,
- @"Position" : _transformInterpolator.positionInterpolator,
- @"Scale" : _transformInterpolator.scaleInterpolator,
- @"Rotation" : _transformInterpolator.scaleInterpolator,
- @"Anchor Point" : _transformInterpolator.anchorInterpolator,
- // Deprecated
- @"Transform.Opacity" : _opacityInterpolator,
- @"Transform.Position" : _transformInterpolator.positionInterpolator,
- @"Transform.Scale" : _transformInterpolator.scaleInterpolator,
- @"Transform.Rotation" : _transformInterpolator.scaleInterpolator,
- @"Transform.Anchor Point" : _transformInterpolator.anchorInterpolator
- };
- }
- return nil;
- }
- - (void)buildContents:(NSArray *)contents {
- LOTAnimatorNode *previousNode = nil;
- LOTShapeTransform *transform;
- for (id item in contents) {
- if ([item isKindOfClass:[LOTShapeFill class]]) {
- LOTFillRenderer *fillRenderer = [[LOTFillRenderer alloc] initWithInputNode:previousNode
- shapeFill:(LOTShapeFill *)item];
- [self.containerLayer insertSublayer:fillRenderer.outputLayer atIndex:0];
- previousNode = fillRenderer;
- } else if ([item isKindOfClass:[LOTShapeStroke class]]) {
- LOTStrokeRenderer *strokRenderer = [[LOTStrokeRenderer alloc] initWithInputNode:previousNode
- shapeStroke:(LOTShapeStroke *)item];
- [self.containerLayer insertSublayer:strokRenderer.outputLayer atIndex:0];
- previousNode = strokRenderer;
- } else if ([item isKindOfClass:[LOTShapePath class]]) {
- LOTPathAnimator *pathAnimator = [[LOTPathAnimator alloc] initWithInputNode:previousNode
- shapePath:(LOTShapePath *)item];
- previousNode = pathAnimator;
- } else if ([item isKindOfClass:[LOTShapeRectangle class]]) {
- LOTRoundedRectAnimator *rectAnimator = [[LOTRoundedRectAnimator alloc] initWithInputNode:previousNode
- shapeRectangle:(LOTShapeRectangle *)item];
- previousNode = rectAnimator;
- } else if ([item isKindOfClass:[LOTShapeCircle class]]) {
- LOTCircleAnimator *circleAnimator = [[LOTCircleAnimator alloc] initWithInputNode:previousNode
- shapeCircle:(LOTShapeCircle *)item];
- previousNode = circleAnimator;
- } else if ([item isKindOfClass:[LOTShapeGroup class]]) {
- LOTShapeGroup *shapeGroup = (LOTShapeGroup *)item;
- LOTRenderGroup *renderGroup = [[LOTRenderGroup alloc] initWithInputNode:previousNode contents:shapeGroup.items keyname:shapeGroup.keyname];
- [self.containerLayer insertSublayer:renderGroup.containerLayer atIndex:0];
- previousNode = renderGroup;
- } else if ([item isKindOfClass:[LOTShapeTransform class]]) {
- transform = (LOTShapeTransform *)item;
- } else if ([item isKindOfClass:[LOTShapeTrimPath class]]) {
- LOTTrimPathNode *trim = [[LOTTrimPathNode alloc] initWithInputNode:previousNode trimPath:(LOTShapeTrimPath *)item];
- previousNode = trim;
- } else if ([item isKindOfClass:[LOTShapeStar class]]) {
- LOTShapeStar *star = (LOTShapeStar *)item;
- if (star.type == LOTPolystarShapeStar) {
- LOTPolystarAnimator *starAnimator = [[LOTPolystarAnimator alloc] initWithInputNode:previousNode shapeStar:star];
- previousNode = starAnimator;
- }
- if (star.type == LOTPolystarShapePolygon) {
- LOTPolygonAnimator *polygonAnimator = [[LOTPolygonAnimator alloc] initWithInputNode:previousNode shapePolygon:star];
- previousNode = polygonAnimator;
- }
- } else if ([item isKindOfClass:[LOTShapeGradientFill class]]) {
- LOTGradientFillRender *gradientFill = [[LOTGradientFillRender alloc] initWithInputNode:previousNode shapeGradientFill:(LOTShapeGradientFill *)item];
- previousNode = gradientFill;
- [self.containerLayer insertSublayer:gradientFill.outputLayer atIndex:0];
- } else if ([item isKindOfClass:[LOTShapeRepeater class]]) {
- LOTRepeaterRenderer *repeater = [[LOTRepeaterRenderer alloc] initWithInputNode:previousNode shapeRepeater:(LOTShapeRepeater *)item];
- previousNode = repeater;
- [self.containerLayer insertSublayer:repeater.outputLayer atIndex:0];
- }
- }
- if (transform) {
- _opacityInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:transform.opacity.keyframes];
- _transformInterpolator = [[LOTTransformInterpolator alloc] initWithPosition:transform.position.keyframes
- rotation:transform.rotation.keyframes
- anchor:transform.anchor.keyframes
- scale:transform.scale.keyframes];
- }
- _rootNode = previousNode;
- }
- - (BOOL)needsUpdateForFrame:(NSNumber *)frame {
- return ([_opacityInterpolator hasUpdateForFrame:frame] ||
- [_transformInterpolator hasUpdateForFrame:frame] ||
- _rootNodeHasUpdate);
- }
- - (BOOL)updateWithFrame:(NSNumber *)frame withModifierBlock:(void (^ _Nullable)(LOTAnimatorNode * _Nonnull))modifier forceLocalUpdate:(BOOL)forceUpdate {
- indentation_level = indentation_level + 1;
- _rootNodeHasUpdate = [_rootNode updateWithFrame:frame withModifierBlock:modifier forceLocalUpdate:forceUpdate];
- indentation_level = indentation_level - 1;
- BOOL update = [super updateWithFrame:frame withModifierBlock:modifier forceLocalUpdate:forceUpdate];
- return update;
- }
- - (void)performLocalUpdate {
- if (_opacityInterpolator) {
- self.containerLayer.opacity = [_opacityInterpolator floatValueForFrame:self.currentFrame];
- }
- if (_transformInterpolator) {
- CATransform3D xform = [_transformInterpolator transformForFrame:self.currentFrame];
- self.containerLayer.transform = xform;
-
- CGAffineTransform appliedXform = CATransform3DGetAffineTransform(xform);
- _localPath = [_rootNode.outputPath copy];
- [_localPath LOT_applyTransform:appliedXform];
- } else {
- _localPath = [_rootNode.outputPath copy];
- }
- }
- - (void)rebuildOutputs {
- if (self.inputNode) {
- _outputPath = [self.inputNode.outputPath copy];
- [_outputPath LOT_appendPath:self.localPath];
- } else {
- _outputPath = self.localPath;
- }
- }
- - (void)setPathShouldCacheLengths:(BOOL)pathShouldCacheLengths {
- [super setPathShouldCacheLengths:pathShouldCacheLengths];
- _rootNode.pathShouldCacheLengths = pathShouldCacheLengths;
- }
- - (LOTBezierPath *)localPath {
- return _localPath;
- }
- - (LOTBezierPath *)outputPath {
- return _outputPath;
- }
- - (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
- [self.inputNode searchNodesForKeypath:keypath];
- if ([keypath pushKey:self.keyname]) {
- // Matches self. Dig deeper.
- // Check interpolators
- if ([keypath pushKey:@"Transform"]) {
- // Matches a Transform interpolator!
- if (self.valueInterpolators[keypath.currentKey] != nil) {
- [keypath pushKey:keypath.currentKey];
- [keypath addSearchResultForCurrentPath:self];
- [keypath popKey];
- }
- [keypath popKey];
- }
- if (keypath.endOfKeypath) {
- // We have a match!
- [keypath addSearchResultForCurrentPath:self];
- }
- // Check child nodes
- [_rootNode searchNodesForKeypath:keypath];
- [keypath popKey];
- }
- }
- - (void)setValueDelegate:(id<LOTValueDelegate> _Nonnull)delegate
- forKeypath:(LOTKeypath * _Nonnull)keypath {
- if ([keypath pushKey:self.keyname]) {
- // Matches self. Dig deeper.
- // Check interpolators
- if ([keypath pushKey:@"Transform"]) {
- // Matches a Transform interpolator!
- LOTValueInterpolator *interpolator = self.valueInterpolators[keypath.currentKey];
- if (interpolator) {
- // We have a match!
- [interpolator setValueDelegate:delegate];
- }
- [keypath popKey];
- }
- // Check child nodes
- [_rootNode setValueDelegate:delegate forKeypath:keypath];
- [keypath popKey];
- }
- // Check upstream
- [self.inputNode setValueDelegate:delegate forKeypath:keypath];
- }
- @end
|