Files
GLEGram-iOS/submodules/TelegramUI/Components/SpaceWarpView/STCMeshView/Sources/STCMeshLayer.m
T
Leeksov 4647310322 GLEGram 12.5 — Initial public release
Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
2026-04-06 09:48:12 +03:00

338 lines
9.9 KiB
Objective-C

/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <STCMeshView/STCMeshLayer.h>
static const CFTimeInterval STCMeshLayerTotalInstanceDelay = 10000000.0;
static NSString *const STCMeshLayerBoundsAnimationKey = @"STCMeshLayerBoundsAnimation";
static NSString *const STCMeshLayerTransformAnimationKey = @"STCMeshLayerTransformAnimation";
static NSString *const STCMeshLayerPositionAnimationKey = @"STCMeshLayerPositionAnimation";
static NSString *const STCMeshLayerAnchorPointAnimationKey = @"STCMeshLayerAnchorPointAnimation";
static NSString *const STCMeshLayerInstanceDelayAnimationKey = @"STCMeshLayerInstanceDelayAnimation";
@implementation STCMeshLayer {
CAReplicatorLayer *_wrapperLayer;
CALayer *_contentLayer;
CGRect *_instanceBounds;
CATransform3D *_instanceTransforms;
CGPoint *_instancePositions;
CGPoint *_instanceAnchorPoints;
}
#pragma mark - Lifecycle
- (instancetype)init
{
if ((self = [super init])) {
self.wrapperLayer = [[CAReplicatorLayer alloc] init];
self.contentLayer = [[CALayer alloc] init];
}
return self;
}
- (void)dealloc
{
free(_instanceTransforms);
_instanceTransforms = NULL;
free(_instanceBounds);
_instanceBounds = NULL;
}
- (void)layoutSublayers
{
[super layoutSublayers];
_wrapperLayer.frame = self.bounds;
_contentLayer.frame = _wrapperLayer.bounds;
[self _updateMeshAnimations];
}
#pragma mark - Properties
@dynamic instanceDelay;
@dynamic instanceTransform;
- (void)setInstanceCount:(NSInteger)instanceCount
{
if (instanceCount != self.instanceCount) {
[super setInstanceCount:instanceCount];
free(_instanceTransforms);
_instanceTransforms = NULL;
free(_instanceBounds);
_instanceBounds = NULL;
[self setNeedsLayout];
}
}
- (CATransform3D *)instanceTransforms
{
CATransform3D *instanceTransforms = _instanceTransforms;
return instanceTransforms;
}
- (void)setInstanceTransforms:(CATransform3D *)instanceTransforms
{
free(_instanceTransforms);
_instanceTransforms = NULL;
if (instanceTransforms != NULL) {
_instanceTransforms = calloc(sizeof(CATransform3D), self.instanceCount);
memcpy(_instanceTransforms, instanceTransforms, self.instanceCount * sizeof(CATransform3D));
}
[self setNeedsLayout];
}
- (CGPoint *)instancePositions
{
CGPoint *instancePositions = _instancePositions;
return instancePositions;
}
- (void)setInstancePositions:(CGPoint *)instancePositions
{
free(_instancePositions);
_instancePositions = NULL;
if (instancePositions != NULL) {
_instancePositions = calloc(sizeof(CGPoint), self.instanceCount);
memcpy(_instancePositions, instancePositions, self.instanceCount * sizeof(CGPoint));
}
[self setNeedsLayout];
}
- (CGPoint *)instanceAnchorPoints
{
CGPoint *instanceAnchorPoints = _instanceAnchorPoints;
return instanceAnchorPoints;
}
- (void)setInstanceAnchorPoints:(CGPoint *)instanceAnchorPoints
{
free(_instanceAnchorPoints);
_instanceAnchorPoints = NULL;
if (instanceAnchorPoints != NULL) {
_instanceAnchorPoints = calloc(sizeof(CGPoint), self.instanceCount);
memcpy(_instanceAnchorPoints, instanceAnchorPoints, self.instanceCount * sizeof(CGPoint));
}
[self setNeedsLayout];
}
- (CGRect *)instanceBounds
{
CGRect *instanceBounds = _instanceBounds;
return instanceBounds;
}
- (void)setInstanceBounds:(CGRect *)instanceBounds
{
free(_instanceBounds);
_instanceBounds = NULL;
if (instanceBounds != NULL) {
_instanceBounds = calloc(sizeof(CGRect), self.instanceCount);
memcpy(_instanceBounds, instanceBounds, self.instanceCount * sizeof(CGRect));
}
[self setNeedsLayout];
}
- (CALayer *)contentLayer
{
CALayer *contentLayer = _contentLayer;
return contentLayer;
}
- (void)setContentLayer:(CALayer *)contentLayer
{
if (contentLayer != _contentLayer) {
if (_contentLayer != nil) {
[_contentLayer removeFromSuperlayer];
}
_contentLayer = contentLayer;
if (_contentLayer != nil) {
[_wrapperLayer addSublayer:_contentLayer];
}
}
}
- (CAReplicatorLayer *)wrapperLayer
{
CAReplicatorLayer *wrapperLayer = _wrapperLayer;
return wrapperLayer;
}
- (void)setWrapperLayer:(CAReplicatorLayer *)wrapperLayer
{
if (wrapperLayer != _wrapperLayer) {
if (_contentLayer != nil) {
[_contentLayer removeFromSuperlayer];
}
if (_wrapperLayer != nil) {
[_wrapperLayer removeFromSuperlayer];
}
_wrapperLayer = wrapperLayer;
if (_wrapperLayer != nil) {
_wrapperLayer.masksToBounds = YES;
_wrapperLayer.instanceCount = 2;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef hiddenColor = CGColorCreate(colorSpace, (CGFloat []){ 1.0, 1.0, 1.0, 0.0 });
_wrapperLayer.instanceColor = hiddenColor;
CGColorRelease(hiddenColor);
CGColorSpaceRelease(colorSpace);
_wrapperLayer.instanceAlphaOffset = 1.0;
[self addSublayer:_wrapperLayer];
}
if (_contentLayer != nil) {
[_wrapperLayer addSublayer:_contentLayer];
}
[self setNeedsLayout];
}
}
#pragma mark - Internal Methods
- (CGRect)_boundsAtIndex:(NSUInteger)index
{
CGRect bounds = CGRectZero;
if (_instanceBounds != NULL) {
bounds = _instanceBounds[index];
}
return bounds;
}
- (CATransform3D)_transformAtIndex:(NSUInteger)index
{
CATransform3D transform = CATransform3DIdentity;
if (_instanceTransforms != NULL) {
transform = _instanceTransforms[index];
}
return transform;
}
- (CGPoint)_positionAtIndex:(NSUInteger)index
{
CGPoint position = CGPointZero;
if (_instancePositions != NULL) {
position = _instancePositions[index];
}
return position;
}
- (CGPoint)_anchorPointAtIndex:(NSUInteger)index
{
CGPoint anchorPoint = CGPointMake(0.0, 0.0);
if (_instanceAnchorPoints != NULL) {
anchorPoint = _instanceAnchorPoints[index];
}
return anchorPoint;
}
- (void)_updateMeshAnimations
{
[_wrapperLayer removeAllAnimations];
super.instanceDelay = -STCMeshLayerTotalInstanceDelay / self.instanceCount;
CAKeyframeAnimation *boundsAnimation = [CAKeyframeAnimation animationWithKeyPath:@"bounds"];
boundsAnimation.calculationMode = kCAAnimationDiscrete;
boundsAnimation.duration = STCMeshLayerTotalInstanceDelay;
boundsAnimation.removedOnCompletion = NO;
NSMutableArray *boundsValues = [NSMutableArray array];
for (NSUInteger i = 0; i < self.instanceCount; i++) {
CGRect bounds = [self _boundsAtIndex:i];
NSValue *boundsValue = [NSValue valueWithBytes:&bounds objCType:@encode(CGRect)];
[boundsValues addObject:boundsValue];
}
boundsAnimation.values = boundsValues;
[_wrapperLayer addAnimation:boundsAnimation forKey:STCMeshLayerBoundsAnimationKey];
CAKeyframeAnimation *transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
transformAnimation.calculationMode = kCAAnimationDiscrete;
transformAnimation.duration = STCMeshLayerTotalInstanceDelay;
transformAnimation.removedOnCompletion = NO;
NSMutableArray *transformValues = [NSMutableArray array];
for (NSUInteger i = 0; i < self.instanceCount; i++) {
CATransform3D transform = [self _transformAtIndex:i];
NSValue *transformValue = [NSValue valueWithCATransform3D:transform];
[transformValues addObject:transformValue];
}
transformAnimation.values = transformValues;
[_wrapperLayer addAnimation:transformAnimation forKey:STCMeshLayerTransformAnimationKey];
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
positionAnimation.calculationMode = kCAAnimationDiscrete;
positionAnimation.duration = STCMeshLayerTotalInstanceDelay;
positionAnimation.removedOnCompletion = NO;
NSMutableArray *positionValues = [NSMutableArray array];
for (NSUInteger i = 0; i < self.instanceCount; i++) {
CGPoint position = [self _positionAtIndex:i];
NSValue *positionValue = [NSValue valueWithBytes:&position objCType:@encode(CGPoint)];
[positionValues addObject:positionValue];
}
positionAnimation.values = positionValues;
[_wrapperLayer addAnimation:positionAnimation forKey:STCMeshLayerPositionAnimationKey];
CAKeyframeAnimation *anchorPointAnimation = [CAKeyframeAnimation animationWithKeyPath:@"anchorPoint"];
anchorPointAnimation.calculationMode = kCAAnimationDiscrete;
anchorPointAnimation.duration = STCMeshLayerTotalInstanceDelay;
anchorPointAnimation.removedOnCompletion = NO;
NSMutableArray *anchorPointValues = [NSMutableArray array];
for (NSUInteger i = 0; i < self.instanceCount; i++) {
CGPoint anchorPoint = [self _anchorPointAtIndex:i];
NSValue *anchorPointValue = [NSValue valueWithBytes:&anchorPoint objCType:@encode(CGPoint)];
[anchorPointValues addObject:anchorPointValue];
}
anchorPointAnimation.values = anchorPointValues;
[_wrapperLayer addAnimation:anchorPointAnimation forKey:STCMeshLayerAnchorPointAnimationKey];
CAKeyframeAnimation *timeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"instanceDelay"];
timeAnimation.calculationMode = kCAAnimationDiscrete;
timeAnimation.duration = STCMeshLayerTotalInstanceDelay;
timeAnimation.removedOnCompletion = NO;
NSMutableArray *timeValues = [NSMutableArray array];
for (NSUInteger i = 0; i < self.instanceCount; i++) {
CFTimeInterval delay = -super.instanceDelay * i;
[timeValues addObject:@(delay)];
}
timeAnimation.values = timeValues;
[_wrapperLayer addAnimation:timeAnimation forKey:STCMeshLayerInstanceDelayAnimationKey];
}
@end