2017-08-04 16:10:11 -07:00

157 lines
6.2 KiB
Objective-C

//
// LOTGradientFillRender.m
// Lottie
//
// Created by brandon_withrow on 7/27/17.
// Copyright © 2017 Airbnb. All rights reserved.
//
#import "LOTGradientFillRender.h"
#import "LOTArrayInterpolator.h"
#import "LOTPointInterpolator.h"
#import "LOTNumberInterpolator.h"
#import "CGGeometry+LOTAdditions.h"
#import "LOTHelpers.h"
#import "LOTRadialGradientLayer.h"
@implementation LOTGradientFillRender {
BOOL _evenOddFillRule;
CALayer *centerPoint_DEBUG;
CAShapeLayer *_maskShape;
LOTRadialGradientLayer *_gradientOpacityLayer;
LOTRadialGradientLayer *_gradientLayer;
NSInteger _numberOfPositions;
CGPoint _startPoint;
CGPoint _endPoint;
LOTArrayInterpolator *_gradientInterpolator;
LOTPointInterpolator *_startPointInterpolator;
LOTPointInterpolator *_endPointInterpolator;
LOTNumberInterpolator *_opacityInterpolator;
}
- (instancetype _Nonnull )initWithInputNode:(LOTAnimatorNode *_Nonnull)inputNode
shapeGradientFill:(LOTShapeGradientFill *_Nonnull)fill {
self = [super initWithInputNode:inputNode keyName:fill.keyname];
if (self) {
_gradientInterpolator = [[LOTArrayInterpolator alloc] initWithKeyframes:fill.gradient.keyframes];
_startPointInterpolator = [[LOTPointInterpolator alloc] initWithKeyframes:fill.startPoint.keyframes];
_endPointInterpolator = [[LOTPointInterpolator alloc] initWithKeyframes:fill.endPoint.keyframes];
_opacityInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:fill.opacity.keyframes];
_numberOfPositions = fill.numberOfColors.integerValue;
_evenOddFillRule = fill.evenOddFillRule;
CALayer *wrapperLayer = [CALayer new];
_maskShape = [CAShapeLayer new];
_maskShape.fillRule = _evenOddFillRule ? @"even-odd" : @"non-zero";
_maskShape.fillColor = [UIColor whiteColor].CGColor;
_maskShape.actions = @{@"path": [NSNull null]};
_gradientOpacityLayer = [LOTRadialGradientLayer new];
_gradientOpacityLayer.isRadial = (fill.type == LOTGradientTypeRadial);
_gradientOpacityLayer.actions = @{@"startPoint" : [NSNull null],
@"endPoint" : [NSNull null],
@"opacity" : [NSNull null],
@"locations" : [NSNull null],
@"colors" : [NSNull null],
@"bounds" : [NSNull null],
@"anchorPoint" : [NSNull null],
@"isRadial" : [NSNull null]};
_gradientOpacityLayer.mask = _maskShape;
[wrapperLayer addSublayer:_gradientOpacityLayer];
_gradientLayer = [LOTRadialGradientLayer new];
_gradientLayer.isRadial = (fill.type == LOTGradientTypeRadial);
_gradientLayer.mask = wrapperLayer;
_gradientLayer.actions = [_gradientOpacityLayer.actions copy];
[self.outputLayer addSublayer:_gradientLayer];
centerPoint_DEBUG = [CALayer layer];
centerPoint_DEBUG.bounds = CGRectMake(0, 0, 20, 20);
if (ENABLE_DEBUG_SHAPES) {
[self.outputLayer addSublayer:centerPoint_DEBUG];
}
}
return self;
}
- (NSDictionary *)valueInterpolators {
return @{@"Start Point" : _startPointInterpolator,
@"End Point" : _endPointInterpolator,
@"Opacity" : _opacityInterpolator};
}
- (BOOL)needsUpdateForFrame:(NSNumber *)frame {
return ([_gradientInterpolator hasUpdateForFrame:frame] ||
[_startPointInterpolator hasUpdateForFrame:frame] ||
[_endPointInterpolator hasUpdateForFrame:frame] ||
[_opacityInterpolator hasUpdateForFrame:frame]);
}
- (void)performLocalUpdate {
centerPoint_DEBUG.backgroundColor = [UIColor magentaColor].CGColor;
centerPoint_DEBUG.borderColor = [UIColor lightGrayColor].CGColor;
centerPoint_DEBUG.borderWidth = 2.f;
_startPoint = [_startPointInterpolator pointValueForFrame:self.currentFrame];
_endPoint = [_endPointInterpolator pointValueForFrame:self.currentFrame];
self.outputLayer.opacity = [_opacityInterpolator floatValueForFrame:self.currentFrame];
NSArray *numberArray = [_gradientInterpolator numberArrayForFrame:self.currentFrame];
NSMutableArray *colorArray = [NSMutableArray array];
NSMutableArray *locationsArray = [NSMutableArray array];
NSMutableArray *opacityArray = [NSMutableArray array];
NSMutableArray *opacitylocationsArray = [NSMutableArray array];
for (int i = 0; i < _numberOfPositions; i++) {
int ix = i * 4;
NSNumber *location = numberArray[ix];
NSNumber *r = numberArray[(ix + 1)];
NSNumber *g = numberArray[(ix + 2)];
NSNumber *b = numberArray[(ix + 3)];
[locationsArray addObject:location];
UIColor *color = [UIColor colorWithRed:r.floatValue green:g.floatValue blue:b.floatValue alpha:1];
[colorArray addObject:(id)(color.CGColor)];
}
for (NSInteger i = (_numberOfPositions * 4); i < numberArray.count; i = i + 2) {
NSNumber *opacityLocation = numberArray[i];
[opacitylocationsArray addObject:opacityLocation];
NSNumber *opacity = numberArray[i + 1];
UIColor *opacityColor = [UIColor colorWithWhite:1 alpha:opacity.floatValue];
[opacityArray addObject:(id)(opacityColor.CGColor)];
}
if (opacityArray.count == 0) {
_gradientOpacityLayer.backgroundColor = [UIColor whiteColor].CGColor;
} else {
_gradientOpacityLayer.startPoint = _startPoint;
_gradientOpacityLayer.endPoint = _endPoint;
_gradientOpacityLayer.locations = opacitylocationsArray;
_gradientOpacityLayer.colors = opacityArray;
}
_gradientLayer.startPoint = _startPoint;
_gradientLayer.endPoint = _endPoint;
_gradientLayer.locations = locationsArray;
_gradientLayer.colors = colorArray;
}
- (void)rebuildOutputs {
CGRect frame = [self.inputNode.outputPath bounds];
CGPoint modifiedAnchor = CGPointMake(-frame.origin.x / frame.size.width,
-frame.origin.y / frame.size.height);
_maskShape.path = self.inputNode.outputPath.CGPath;
_gradientOpacityLayer.bounds = frame;
_gradientOpacityLayer.anchorPoint = modifiedAnchor;
_gradientLayer.bounds = frame;
_gradientLayer.anchorPoint = modifiedAnchor;
}
- (NSDictionary *)actionsForRenderLayer {
return @{@"backgroundColor": [NSNull null],
@"fillColor": [NSNull null],
@"opacity" : [NSNull null]};
}
@end