2019-09-04 19:50:30 +00:00
|
|
|
// Copyright 2019 Google LLC.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// This is an example of a minimal iOS application that uses Skia to draw to
|
|
|
|
// a Metal drawable.
|
|
|
|
|
|
|
|
// Much of this code is copied from the default application created by XCode.
|
|
|
|
|
2019-12-11 15:32:59 +00:00
|
|
|
#include "tools/skottie_ios_app/SkMetalViewBridge.h"
|
2019-09-12 16:12:24 +00:00
|
|
|
|
2019-09-04 19:50:30 +00:00
|
|
|
#include "include/core/SkCanvas.h"
|
2022-03-31 19:07:44 +00:00
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkColorSpace.h"
|
2019-09-04 19:50:30 +00:00
|
|
|
#include "include/core/SkPaint.h"
|
|
|
|
#include "include/core/SkSurface.h"
|
|
|
|
#include "include/core/SkTime.h"
|
|
|
|
#include "include/effects/SkGradientShader.h"
|
|
|
|
#include "include/gpu/GrBackendSurface.h"
|
2020-09-23 18:01:58 +00:00
|
|
|
#include "include/gpu/GrDirectContext.h"
|
2019-09-04 19:50:30 +00:00
|
|
|
#include "include/gpu/mtl/GrMtlTypes.h"
|
|
|
|
|
|
|
|
#import <Metal/Metal.h>
|
|
|
|
#import <MetalKit/MetalKit.h>
|
|
|
|
#import <UIKit/UIKit.h>
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2019-09-09 16:00:07 +00:00
|
|
|
static void config_paint(SkPaint* paint) {
|
|
|
|
if (!paint->getShader()) {
|
2019-09-12 16:12:24 +00:00
|
|
|
const SkColor4f colors[2] = {SkColors::kBlack, SkColors::kWhite};
|
|
|
|
const SkPoint points[2] = {{0, -1024}, {0, 1024}};
|
2019-09-09 16:00:07 +00:00
|
|
|
paint->setShader(SkGradientShader::MakeLinear(points, colors, nullptr, nullptr, 2,
|
|
|
|
SkTileMode::kClamp, 0, nullptr));
|
|
|
|
}
|
|
|
|
}
|
2019-09-04 19:50:30 +00:00
|
|
|
|
2019-09-09 16:00:07 +00:00
|
|
|
static void draw_example(SkSurface* surface, const SkPaint& paint, double rotation) {
|
|
|
|
SkCanvas* canvas = surface->getCanvas();
|
|
|
|
canvas->translate(surface->width() * 0.5f, surface->height() * 0.5f);
|
|
|
|
canvas->rotate(rotation);
|
|
|
|
canvas->drawPaint(paint);
|
2019-09-04 19:50:30 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 16:00:07 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2019-09-12 16:12:24 +00:00
|
|
|
@interface AppViewDelegate : NSObject <MTKViewDelegate>
|
2020-09-23 18:01:58 +00:00
|
|
|
@property (assign, nonatomic) GrDirectContext* grContext; // non-owning pointer.
|
2019-10-14 17:42:57 +00:00
|
|
|
@property (assign, nonatomic) id<MTLCommandQueue> metalQueue;
|
2019-09-12 16:12:24 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AppViewDelegate {
|
2019-09-09 16:00:07 +00:00
|
|
|
SkPaint fPaint;
|
2019-09-04 19:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)drawInMTKView:(nonnull MTKView *)view {
|
2019-09-12 16:12:24 +00:00
|
|
|
if (![self grContext] || !view) {
|
2019-09-04 19:50:30 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-09-12 16:12:24 +00:00
|
|
|
// Do as much as possible before creating surface.
|
2019-09-09 16:00:07 +00:00
|
|
|
config_paint(&fPaint);
|
|
|
|
float rotation = (float)(180 * 1e-9 * SkTime::GetNSecs());
|
|
|
|
|
2019-09-04 19:50:30 +00:00
|
|
|
// Create surface:
|
2019-09-12 16:12:24 +00:00
|
|
|
sk_sp<SkSurface> surface = SkMtkViewToSurface(view, [self grContext]);
|
2019-09-04 19:50:30 +00:00
|
|
|
if (!surface) {
|
|
|
|
NSLog(@"error: no sksurface");
|
|
|
|
return;
|
|
|
|
}
|
2019-09-09 16:00:07 +00:00
|
|
|
|
|
|
|
draw_example(surface.get(), fPaint, rotation);
|
|
|
|
|
2019-09-04 19:50:30 +00:00
|
|
|
// Must flush *and* present for this to work!
|
2020-05-19 22:06:26 +00:00
|
|
|
surface->flushAndSubmit();
|
2019-09-12 16:12:24 +00:00
|
|
|
surface = nullptr;
|
2019-10-14 17:42:57 +00:00
|
|
|
|
|
|
|
id<MTLCommandBuffer> commandBuffer = [[self metalQueue] commandBuffer];
|
|
|
|
[commandBuffer presentDrawable:[view currentDrawable]];
|
|
|
|
[commandBuffer commit];
|
2019-09-04 19:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
|
|
|
|
// change anything on size change?
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2019-09-12 16:12:24 +00:00
|
|
|
@interface AppViewController : UIViewController
|
|
|
|
@property (strong, nonatomic) id<MTLDevice> metalDevice;
|
2019-10-14 17:42:57 +00:00
|
|
|
@property (strong, nonatomic) id<MTLCommandQueue> metalQueue;
|
2019-09-12 16:12:24 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AppViewController {
|
2019-12-11 15:32:59 +00:00
|
|
|
GrContextHolder fGrContext;
|
2019-09-09 16:00:07 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 19:50:30 +00:00
|
|
|
- (void)loadView {
|
2019-09-12 16:12:24 +00:00
|
|
|
[self setView:[[MTKView alloc] initWithFrame:[[UIScreen mainScreen] bounds] device:nil]];
|
2019-09-04 19:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)viewDidLoad {
|
|
|
|
[super viewDidLoad];
|
2019-09-09 16:00:07 +00:00
|
|
|
if (!fGrContext) {
|
2019-09-12 16:12:24 +00:00
|
|
|
[self setMetalDevice:MTLCreateSystemDefaultDevice()];
|
2019-10-14 17:42:57 +00:00
|
|
|
[self setMetalQueue:[[self metalDevice] newCommandQueue]];
|
2019-12-11 15:32:59 +00:00
|
|
|
fGrContext = SkMetalDeviceToGrContext([self metalDevice], [self metalQueue]);
|
2019-09-09 16:00:07 +00:00
|
|
|
}
|
2019-09-12 16:12:24 +00:00
|
|
|
if (![self view] || ![self metalDevice]) {
|
2019-09-04 19:50:30 +00:00
|
|
|
NSLog(@"Metal is not supported on this device");
|
|
|
|
self.view = [[UIView alloc] initWithFrame:self.view.frame];
|
|
|
|
return;
|
|
|
|
}
|
2019-09-12 16:12:24 +00:00
|
|
|
MTKView* mtkView = (MTKView*)[self view];
|
|
|
|
[mtkView setDevice:[self metalDevice]];
|
|
|
|
[mtkView setBackgroundColor:[UIColor blackColor]];
|
|
|
|
SkMtkViewConfigForSkia(mtkView);
|
2019-09-09 16:00:07 +00:00
|
|
|
AppViewDelegate* viewDelegate = [[AppViewDelegate alloc] init];
|
2019-09-12 16:12:24 +00:00
|
|
|
[viewDelegate setGrContext:fGrContext.get()];
|
2019-10-14 17:42:57 +00:00
|
|
|
[viewDelegate setMetalQueue:[self metalQueue]];
|
2019-09-12 16:12:24 +00:00
|
|
|
[viewDelegate mtkView:mtkView drawableSizeWillChange:[mtkView bounds].size];
|
|
|
|
[mtkView setDelegate:viewDelegate];
|
2019-09-04 19:50:30 +00:00
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
|
|
|
@property (strong, nonatomic) UIWindow *window;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AppDelegate
|
2019-09-12 16:12:24 +00:00
|
|
|
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary*)opts {
|
2019-09-04 19:50:30 +00:00
|
|
|
// Override point for customization after application launch.
|
2019-09-12 16:12:24 +00:00
|
|
|
[self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]];
|
|
|
|
[[self window] setFrame:[[UIScreen mainScreen] bounds]];
|
|
|
|
[[self window] setRootViewController:[[AppViewController alloc] init]];
|
|
|
|
[[self window] makeKeyAndVisible];
|
2019-09-04 19:50:30 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2019-09-12 16:12:24 +00:00
|
|
|
int main(int argc, char* argv[]) {
|
2019-09-04 19:50:30 +00:00
|
|
|
@autoreleasepool {
|
|
|
|
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
|
|
|
}
|
|
|
|
}
|