Files
rive-ios/Source/Renderer/rive_renderer_view.mm
philter 9dc67e3515 Remove files to unblock downstream iOS push
Diffs=
cf89553e9 Remove files to unblock downstream iOS push (#7500)
1adf3dbf4 disable fallback font during artboard rendering (#7480)
6f29a9c0c Miscellaneous Layout UX Fixes (#7491)
09ccc9ebb Add yoga to thumbnail generator build (#7494)
aa390d5dc change how viewmodel instances target their viewmodel (#7468)
e66e242c6 Xxxx databinding add boolean (#7456)
9cd8759a0 Xxxx data binding data context (#7454)
31f5ee5c4 Animation for Layouts (#7426)
a4439ee42 Renames for Yoga and libjpeg (#7446)
97578005c Update LayoutComponentStyle bitfields to be compatible with older C++ versions (#7436)
75823467d databinding (#7341)
ef9ef9fd1 Ios golden test (#7413)

Co-authored-by: Jonathon Copeland <jcopela4@gmail.com>
Co-authored-by: Philip Chung <philterdesign@gmail.com>
2024-06-28 21:33:34 +00:00

293 lines
9.1 KiB
Plaintext

#include "rive_renderer_view.hh"
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
#import "RivePrivateHeaders.h"
#import <RenderContext.h>
#import <RenderContextManager.h>
// We manually need to provide this as our build-time config isn't shared with xcode.
#define WITH_RIVE_AUDIO
#include "rive/audio/audio_engine.hpp"
@implementation RiveRendererView
{
RenderContext* _renderContext;
rive::Renderer* _renderer;
}
- (void)didEnterBackground:(NSNotification*)notification
{
auto engine = rive::AudioEngine::RuntimeEngine(false);
if (engine != nil)
{
engine->stop();
}
}
- (void)didEnterForeground:(NSNotification*)notification
{
auto engine = rive::AudioEngine::RuntimeEngine(false);
if (engine != nil)
{
engine->start();
}
}
- (instancetype)initWithCoder:(NSCoder*)decoder
{
#if TARGET_OS_IPHONE
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
#else
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterBackground:)
name:NSApplicationDidResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterForeground:)
name:NSApplicationWillBecomeActiveNotification
object:nil];
#endif
self = [super initWithCoder:decoder];
_renderContext = [[RenderContextManager shared] getDefaultContext];
assert(_renderContext);
self.device = [_renderContext metalDevice];
[self setDepthStencilPixelFormat:_renderContext.depthStencilPixelFormat];
[self setColorPixelFormat:MTLPixelFormatBGRA8Unorm];
[self setFramebufferOnly:_renderContext.framebufferOnly];
[self setSampleCount:1];
return self;
}
- (instancetype)initWithFrame:(CGRect)frameRect
{
#if TARGET_OS_IPHONE
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
#else
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterBackground:)
name:NSApplicationDidResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterForeground:)
name:NSApplicationWillBecomeActiveNotification
object:nil];
#endif
_renderContext = [[RenderContextManager shared] getDefaultContext];
assert(_renderContext);
auto value = [super initWithFrame:frameRect device:_renderContext.metalDevice];
[self setDepthStencilPixelFormat:_renderContext.depthStencilPixelFormat];
[self setColorPixelFormat:MTLPixelFormatBGRA8Unorm];
[self setFramebufferOnly:_renderContext.framebufferOnly];
[self setSampleCount:1];
return value;
}
- (void)alignWithRect:(CGRect)rect
contentRect:(CGRect)contentRect
alignment:(RiveAlignment)alignment
fit:(RiveFit)fit
{
rive::AABB frame(rect.origin.x,
rect.origin.y,
rect.size.width + rect.origin.x,
rect.size.height + rect.origin.y);
rive::AABB content(contentRect.origin.x,
contentRect.origin.y,
contentRect.size.width + contentRect.origin.x,
contentRect.size.height + contentRect.origin.y);
auto riveFit = [self riveFit:fit];
auto riveAlignment = [self riveAlignment:alignment];
_renderer->align(riveFit, riveAlignment, frame, content);
}
- (void)save
{
assert(_renderer != nil);
_renderer->save();
}
- (void)restore
{
assert(_renderer != nil);
_renderer->restore();
}
- (void)transform:(float)xx xy:(float)xy yx:(float)yx yy:(float)yy tx:(float)tx ty:(float)ty
{
assert(_renderer != nil);
_renderer->transform(rive::Mat2D{xx, xy, yx, yy, tx, ty});
}
- (void)drawWithArtboard:(RiveArtboard*)artboard
{
assert(_renderer != nil);
[artboard artboardInstance]->draw(_renderer);
}
- (void)drawRive:(CGRect)rect size:(CGSize)size
{
// Intended to be overridden.
}
- (bool)isPaused
{
return true;
}
- (void)drawInRect:(CGRect)rect withCompletion:(_Nullable MTLCommandBufferHandler)completionHandler
{
if (![[self currentDrawable] texture])
{
return;
}
_renderer = [_renderContext beginFrame:self];
if (_renderer != nil)
{
_renderer->save();
[self drawRive:rect size:self.drawableSize];
_renderer->restore();
}
[_renderContext endFrame:self withCompletion:completionHandler];
_renderer = nil;
bool paused = [self isPaused];
[self setEnableSetNeedsDisplay:paused];
[self setPaused:paused];
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
[self drawInRect:rect withCompletion:NULL];
}
- (rive::Fit)riveFit:(RiveFit)fit
{
rive::Fit riveFit;
switch (fit)
{
case fill:
riveFit = rive::Fit::fill;
break;
case contain:
riveFit = rive::Fit::contain;
break;
case cover:
riveFit = rive::Fit::cover;
break;
case fitHeight:
riveFit = rive::Fit::fitHeight;
break;
case fitWidth:
riveFit = rive::Fit::fitWidth;
break;
case scaleDown:
riveFit = rive::Fit::scaleDown;
break;
case noFit:
riveFit = rive::Fit::none;
break;
}
return riveFit;
}
- (rive::Alignment)riveAlignment:(RiveAlignment)alignment
{
rive::Alignment riveAlignment = rive::Alignment::center;
switch (alignment)
{
case topLeft:
riveAlignment = rive::Alignment::topLeft;
break;
case topCenter:
riveAlignment = rive::Alignment::topCenter;
break;
case topRight:
riveAlignment = rive::Alignment::topRight;
break;
case centerLeft:
riveAlignment = rive::Alignment::centerLeft;
break;
case center:
riveAlignment = rive::Alignment::center;
break;
case centerRight:
riveAlignment = rive::Alignment::centerRight;
break;
case bottomLeft:
riveAlignment = rive::Alignment::bottomLeft;
break;
case bottomCenter:
riveAlignment = rive::Alignment::bottomCenter;
break;
case bottomRight:
riveAlignment = rive::Alignment::bottomRight;
break;
}
return riveAlignment;
}
- (CGPoint)artboardLocationFromTouchLocation:(CGPoint)touchLocation
inArtboard:(CGRect)artboardRect
fit:(RiveFit)fit
alignment:(RiveAlignment)alignment
{
// Note, we've offset the frame by the frame.origin before
// but in testing our touch location seems to already take this into account
rive::AABB frame(0, 0, self.frame.size.width, self.frame.size.height);
rive::AABB content(artboardRect.origin.x,
artboardRect.origin.y,
artboardRect.size.width + artboardRect.origin.x,
artboardRect.size.height + artboardRect.origin.y);
auto riveFit = [self riveFit:fit];
auto riveAlignment = [self riveAlignment:alignment];
rive::Mat2D forward = rive::computeAlignment(riveFit, riveAlignment, frame, content);
rive::Mat2D inverse = forward.invertOrIdentity();
rive::Vec2D frameLocation(touchLocation.x, touchLocation.y);
rive::Vec2D convertedLocation = inverse * frameLocation;
return CGPointMake(convertedLocation.x, convertedLocation.y);
}
@end