LOTRenderGroup.m 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //
  2. // LOTRenderGroup.m
  3. // Lottie
  4. //
  5. // Created by brandon_withrow on 6/27/17.
  6. // Copyright © 2017 Airbnb. All rights reserved.
  7. //
  8. #import "LOTRenderGroup.h"
  9. #import "LOTModels.h"
  10. #import "LOTPathAnimator.h"
  11. #import "LOTFillRenderer.h"
  12. #import "LOTStrokeRenderer.h"
  13. #import "LOTNumberInterpolator.h"
  14. #import "LOTTransformInterpolator.h"
  15. #import "LOTCircleAnimator.h"
  16. #import "LOTRoundedRectAnimator.h"
  17. #import "LOTTrimPathNode.h"
  18. #import "LOTShapeStar.h"
  19. #import "LOTPolygonAnimator.h"
  20. #import "LOTPolystarAnimator.h"
  21. #import "LOTShapeGradientFill.h"
  22. #import "LOTGradientFillRender.h"
  23. #import "LOTRepeaterRenderer.h"
  24. #import "LOTShapeRepeater.h"
  25. @implementation LOTRenderGroup {
  26. LOTAnimatorNode *_rootNode;
  27. LOTBezierPath *_outputPath;
  28. LOTBezierPath *_localPath;
  29. BOOL _rootNodeHasUpdate;
  30. LOTNumberInterpolator *_opacityInterpolator;
  31. LOTTransformInterpolator *_transformInterpolator;
  32. }
  33. - (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode * _Nullable)inputNode
  34. contents:(NSArray * _Nonnull)contents
  35. keyname:(NSString * _Nullable)keyname {
  36. self = [super initWithInputNode:inputNode keyName:keyname];
  37. if (self) {
  38. _containerLayer = [CALayer layer];
  39. _containerLayer.actions = @{@"transform": [NSNull null],
  40. @"opacity": [NSNull null]};
  41. [self buildContents:contents];
  42. }
  43. return self;
  44. }
  45. - (NSDictionary *)valueInterpolators {
  46. if (_opacityInterpolator && _transformInterpolator) {
  47. return @{@"Opacity" : _opacityInterpolator,
  48. @"Position" : _transformInterpolator.positionInterpolator,
  49. @"Scale" : _transformInterpolator.scaleInterpolator,
  50. @"Rotation" : _transformInterpolator.scaleInterpolator,
  51. @"Anchor Point" : _transformInterpolator.anchorInterpolator,
  52. // Deprecated
  53. @"Transform.Opacity" : _opacityInterpolator,
  54. @"Transform.Position" : _transformInterpolator.positionInterpolator,
  55. @"Transform.Scale" : _transformInterpolator.scaleInterpolator,
  56. @"Transform.Rotation" : _transformInterpolator.scaleInterpolator,
  57. @"Transform.Anchor Point" : _transformInterpolator.anchorInterpolator
  58. };
  59. }
  60. return nil;
  61. }
  62. - (void)buildContents:(NSArray *)contents {
  63. LOTAnimatorNode *previousNode = nil;
  64. LOTShapeTransform *transform;
  65. for (id item in contents) {
  66. if ([item isKindOfClass:[LOTShapeFill class]]) {
  67. LOTFillRenderer *fillRenderer = [[LOTFillRenderer alloc] initWithInputNode:previousNode
  68. shapeFill:(LOTShapeFill *)item];
  69. [self.containerLayer insertSublayer:fillRenderer.outputLayer atIndex:0];
  70. previousNode = fillRenderer;
  71. } else if ([item isKindOfClass:[LOTShapeStroke class]]) {
  72. LOTStrokeRenderer *strokRenderer = [[LOTStrokeRenderer alloc] initWithInputNode:previousNode
  73. shapeStroke:(LOTShapeStroke *)item];
  74. [self.containerLayer insertSublayer:strokRenderer.outputLayer atIndex:0];
  75. previousNode = strokRenderer;
  76. } else if ([item isKindOfClass:[LOTShapePath class]]) {
  77. LOTPathAnimator *pathAnimator = [[LOTPathAnimator alloc] initWithInputNode:previousNode
  78. shapePath:(LOTShapePath *)item];
  79. previousNode = pathAnimator;
  80. } else if ([item isKindOfClass:[LOTShapeRectangle class]]) {
  81. LOTRoundedRectAnimator *rectAnimator = [[LOTRoundedRectAnimator alloc] initWithInputNode:previousNode
  82. shapeRectangle:(LOTShapeRectangle *)item];
  83. previousNode = rectAnimator;
  84. } else if ([item isKindOfClass:[LOTShapeCircle class]]) {
  85. LOTCircleAnimator *circleAnimator = [[LOTCircleAnimator alloc] initWithInputNode:previousNode
  86. shapeCircle:(LOTShapeCircle *)item];
  87. previousNode = circleAnimator;
  88. } else if ([item isKindOfClass:[LOTShapeGroup class]]) {
  89. LOTShapeGroup *shapeGroup = (LOTShapeGroup *)item;
  90. LOTRenderGroup *renderGroup = [[LOTRenderGroup alloc] initWithInputNode:previousNode contents:shapeGroup.items keyname:shapeGroup.keyname];
  91. [self.containerLayer insertSublayer:renderGroup.containerLayer atIndex:0];
  92. previousNode = renderGroup;
  93. } else if ([item isKindOfClass:[LOTShapeTransform class]]) {
  94. transform = (LOTShapeTransform *)item;
  95. } else if ([item isKindOfClass:[LOTShapeTrimPath class]]) {
  96. LOTTrimPathNode *trim = [[LOTTrimPathNode alloc] initWithInputNode:previousNode trimPath:(LOTShapeTrimPath *)item];
  97. previousNode = trim;
  98. } else if ([item isKindOfClass:[LOTShapeStar class]]) {
  99. LOTShapeStar *star = (LOTShapeStar *)item;
  100. if (star.type == LOTPolystarShapeStar) {
  101. LOTPolystarAnimator *starAnimator = [[LOTPolystarAnimator alloc] initWithInputNode:previousNode shapeStar:star];
  102. previousNode = starAnimator;
  103. }
  104. if (star.type == LOTPolystarShapePolygon) {
  105. LOTPolygonAnimator *polygonAnimator = [[LOTPolygonAnimator alloc] initWithInputNode:previousNode shapePolygon:star];
  106. previousNode = polygonAnimator;
  107. }
  108. } else if ([item isKindOfClass:[LOTShapeGradientFill class]]) {
  109. LOTGradientFillRender *gradientFill = [[LOTGradientFillRender alloc] initWithInputNode:previousNode shapeGradientFill:(LOTShapeGradientFill *)item];
  110. previousNode = gradientFill;
  111. [self.containerLayer insertSublayer:gradientFill.outputLayer atIndex:0];
  112. } else if ([item isKindOfClass:[LOTShapeRepeater class]]) {
  113. LOTRepeaterRenderer *repeater = [[LOTRepeaterRenderer alloc] initWithInputNode:previousNode shapeRepeater:(LOTShapeRepeater *)item];
  114. previousNode = repeater;
  115. [self.containerLayer insertSublayer:repeater.outputLayer atIndex:0];
  116. }
  117. }
  118. if (transform) {
  119. _opacityInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:transform.opacity.keyframes];
  120. _transformInterpolator = [[LOTTransformInterpolator alloc] initWithPosition:transform.position.keyframes
  121. rotation:transform.rotation.keyframes
  122. anchor:transform.anchor.keyframes
  123. scale:transform.scale.keyframes];
  124. }
  125. _rootNode = previousNode;
  126. }
  127. - (BOOL)needsUpdateForFrame:(NSNumber *)frame {
  128. return ([_opacityInterpolator hasUpdateForFrame:frame] ||
  129. [_transformInterpolator hasUpdateForFrame:frame] ||
  130. _rootNodeHasUpdate);
  131. }
  132. - (BOOL)updateWithFrame:(NSNumber *)frame withModifierBlock:(void (^ _Nullable)(LOTAnimatorNode * _Nonnull))modifier forceLocalUpdate:(BOOL)forceUpdate {
  133. indentation_level = indentation_level + 1;
  134. _rootNodeHasUpdate = [_rootNode updateWithFrame:frame withModifierBlock:modifier forceLocalUpdate:forceUpdate];
  135. indentation_level = indentation_level - 1;
  136. BOOL update = [super updateWithFrame:frame withModifierBlock:modifier forceLocalUpdate:forceUpdate];
  137. return update;
  138. }
  139. - (void)performLocalUpdate {
  140. if (_opacityInterpolator) {
  141. self.containerLayer.opacity = [_opacityInterpolator floatValueForFrame:self.currentFrame];
  142. }
  143. if (_transformInterpolator) {
  144. CATransform3D xform = [_transformInterpolator transformForFrame:self.currentFrame];
  145. self.containerLayer.transform = xform;
  146. CGAffineTransform appliedXform = CATransform3DGetAffineTransform(xform);
  147. _localPath = [_rootNode.outputPath copy];
  148. [_localPath LOT_applyTransform:appliedXform];
  149. } else {
  150. _localPath = [_rootNode.outputPath copy];
  151. }
  152. }
  153. - (void)rebuildOutputs {
  154. if (self.inputNode) {
  155. _outputPath = [self.inputNode.outputPath copy];
  156. [_outputPath LOT_appendPath:self.localPath];
  157. } else {
  158. _outputPath = self.localPath;
  159. }
  160. }
  161. - (void)setPathShouldCacheLengths:(BOOL)pathShouldCacheLengths {
  162. [super setPathShouldCacheLengths:pathShouldCacheLengths];
  163. _rootNode.pathShouldCacheLengths = pathShouldCacheLengths;
  164. }
  165. - (LOTBezierPath *)localPath {
  166. return _localPath;
  167. }
  168. - (LOTBezierPath *)outputPath {
  169. return _outputPath;
  170. }
  171. - (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
  172. [self.inputNode searchNodesForKeypath:keypath];
  173. if ([keypath pushKey:self.keyname]) {
  174. // Matches self. Dig deeper.
  175. // Check interpolators
  176. if ([keypath pushKey:@"Transform"]) {
  177. // Matches a Transform interpolator!
  178. if (self.valueInterpolators[keypath.currentKey] != nil) {
  179. [keypath pushKey:keypath.currentKey];
  180. [keypath addSearchResultForCurrentPath:self];
  181. [keypath popKey];
  182. }
  183. [keypath popKey];
  184. }
  185. if (keypath.endOfKeypath) {
  186. // We have a match!
  187. [keypath addSearchResultForCurrentPath:self];
  188. }
  189. // Check child nodes
  190. [_rootNode searchNodesForKeypath:keypath];
  191. [keypath popKey];
  192. }
  193. }
  194. - (void)setValueDelegate:(id<LOTValueDelegate> _Nonnull)delegate
  195. forKeypath:(LOTKeypath * _Nonnull)keypath {
  196. if ([keypath pushKey:self.keyname]) {
  197. // Matches self. Dig deeper.
  198. // Check interpolators
  199. if ([keypath pushKey:@"Transform"]) {
  200. // Matches a Transform interpolator!
  201. LOTValueInterpolator *interpolator = self.valueInterpolators[keypath.currentKey];
  202. if (interpolator) {
  203. // We have a match!
  204. [interpolator setValueDelegate:delegate];
  205. }
  206. [keypath popKey];
  207. }
  208. // Check child nodes
  209. [_rootNode setValueDelegate:delegate forKeypath:keypath];
  210. [keypath popKey];
  211. }
  212. // Check upstream
  213. [self.inputNode setValueDelegate:delegate forKeypath:keypath];
  214. }
  215. @end