1cb93a386Sopenharmony_ci// Copyright 2019 Google LLC.
2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3cb93a386Sopenharmony_ci
4cb93a386Sopenharmony_ci// This is an example of a minimal iOS application that uses Skia to draw to
5cb93a386Sopenharmony_ci// a Metal drawable.
6cb93a386Sopenharmony_ci
7cb93a386Sopenharmony_ci// Much of this code is copied from the default application created by XCode.
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci#include "tools/skottie_ios_app/SkMetalViewBridge.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
12cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
13cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
14cb93a386Sopenharmony_ci#include "include/core/SkTime.h"
15cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h"
16cb93a386Sopenharmony_ci#include "include/gpu/GrBackendSurface.h"
17cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
18cb93a386Sopenharmony_ci#include "include/gpu/mtl/GrMtlTypes.h"
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci#import <Metal/Metal.h>
21cb93a386Sopenharmony_ci#import <MetalKit/MetalKit.h>
22cb93a386Sopenharmony_ci#import <UIKit/UIKit.h>
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cistatic void config_paint(SkPaint* paint) {
27cb93a386Sopenharmony_ci    if (!paint->getShader()) {
28cb93a386Sopenharmony_ci        const SkColor4f colors[2] = {SkColors::kBlack, SkColors::kWhite};
29cb93a386Sopenharmony_ci        const SkPoint points[2] = {{0, -1024}, {0, 1024}};
30cb93a386Sopenharmony_ci        paint->setShader(SkGradientShader::MakeLinear(points, colors, nullptr, nullptr, 2,
31cb93a386Sopenharmony_ci                                                      SkTileMode::kClamp, 0, nullptr));
32cb93a386Sopenharmony_ci    }
33cb93a386Sopenharmony_ci}
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_cistatic void draw_example(SkSurface* surface, const SkPaint& paint, double rotation) {
36cb93a386Sopenharmony_ci    SkCanvas* canvas = surface->getCanvas();
37cb93a386Sopenharmony_ci    canvas->translate(surface->width() * 0.5f, surface->height() * 0.5f);
38cb93a386Sopenharmony_ci    canvas->rotate(rotation);
39cb93a386Sopenharmony_ci    canvas->drawPaint(paint);
40cb93a386Sopenharmony_ci}
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ci@interface AppViewDelegate : NSObject <MTKViewDelegate>
45cb93a386Sopenharmony_ci@property (assign, nonatomic) GrDirectContext* grContext;  // non-owning pointer.
46cb93a386Sopenharmony_ci@property (assign, nonatomic) id<MTLCommandQueue> metalQueue;
47cb93a386Sopenharmony_ci@end
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci@implementation AppViewDelegate {
50cb93a386Sopenharmony_ci    SkPaint fPaint;
51cb93a386Sopenharmony_ci}
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci- (void)drawInMTKView:(nonnull MTKView *)view {
54cb93a386Sopenharmony_ci    if (![self grContext] || !view) {
55cb93a386Sopenharmony_ci        return;
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci    // Do as much as possible before creating surface.
58cb93a386Sopenharmony_ci    config_paint(&fPaint);
59cb93a386Sopenharmony_ci    float rotation = (float)(180 * 1e-9 * SkTime::GetNSecs());
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    // Create surface:
62cb93a386Sopenharmony_ci    sk_sp<SkSurface> surface = SkMtkViewToSurface(view, [self grContext]);
63cb93a386Sopenharmony_ci    if (!surface) {
64cb93a386Sopenharmony_ci        NSLog(@"error: no sksurface");
65cb93a386Sopenharmony_ci        return;
66cb93a386Sopenharmony_ci    }
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    draw_example(surface.get(), fPaint, rotation);
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    // Must flush *and* present for this to work!
71cb93a386Sopenharmony_ci    surface->flushAndSubmit();
72cb93a386Sopenharmony_ci    surface = nullptr;
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    id<MTLCommandBuffer> commandBuffer = [[self metalQueue] commandBuffer];
75cb93a386Sopenharmony_ci    [commandBuffer presentDrawable:[view currentDrawable]];
76cb93a386Sopenharmony_ci    [commandBuffer commit];
77cb93a386Sopenharmony_ci}
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
80cb93a386Sopenharmony_ci    // change anything on size change?
81cb93a386Sopenharmony_ci}
82cb93a386Sopenharmony_ci@end
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci@interface AppViewController : UIViewController
87cb93a386Sopenharmony_ci@property (strong, nonatomic) id<MTLDevice> metalDevice;
88cb93a386Sopenharmony_ci@property (strong, nonatomic) id<MTLCommandQueue> metalQueue;
89cb93a386Sopenharmony_ci@end
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci@implementation AppViewController {
92cb93a386Sopenharmony_ci    GrContextHolder fGrContext;
93cb93a386Sopenharmony_ci}
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci- (void)loadView {
96cb93a386Sopenharmony_ci    [self setView:[[MTKView alloc] initWithFrame:[[UIScreen mainScreen] bounds] device:nil]];
97cb93a386Sopenharmony_ci}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci- (void)viewDidLoad {
100cb93a386Sopenharmony_ci    [super viewDidLoad];
101cb93a386Sopenharmony_ci    if (!fGrContext) {
102cb93a386Sopenharmony_ci        [self setMetalDevice:MTLCreateSystemDefaultDevice()];
103cb93a386Sopenharmony_ci        [self setMetalQueue:[[self metalDevice] newCommandQueue]];
104cb93a386Sopenharmony_ci        fGrContext = SkMetalDeviceToGrContext([self metalDevice], [self metalQueue]);
105cb93a386Sopenharmony_ci    }
106cb93a386Sopenharmony_ci    if (![self view] || ![self metalDevice]) {
107cb93a386Sopenharmony_ci        NSLog(@"Metal is not supported on this device");
108cb93a386Sopenharmony_ci        self.view = [[UIView alloc] initWithFrame:self.view.frame];
109cb93a386Sopenharmony_ci        return;
110cb93a386Sopenharmony_ci    }
111cb93a386Sopenharmony_ci    MTKView* mtkView = (MTKView*)[self view];
112cb93a386Sopenharmony_ci    [mtkView setDevice:[self metalDevice]];
113cb93a386Sopenharmony_ci    [mtkView setBackgroundColor:[UIColor blackColor]];
114cb93a386Sopenharmony_ci    SkMtkViewConfigForSkia(mtkView);
115cb93a386Sopenharmony_ci    AppViewDelegate* viewDelegate = [[AppViewDelegate alloc] init];
116cb93a386Sopenharmony_ci    [viewDelegate setGrContext:fGrContext.get()];
117cb93a386Sopenharmony_ci    [viewDelegate setMetalQueue:[self metalQueue]];
118cb93a386Sopenharmony_ci    [viewDelegate mtkView:mtkView drawableSizeWillChange:[mtkView bounds].size];
119cb93a386Sopenharmony_ci    [mtkView setDelegate:viewDelegate];
120cb93a386Sopenharmony_ci}
121cb93a386Sopenharmony_ci@end
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci@interface AppDelegate : UIResponder <UIApplicationDelegate>
126cb93a386Sopenharmony_ci@property (strong, nonatomic) UIWindow *window;
127cb93a386Sopenharmony_ci@end
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci@implementation AppDelegate
130cb93a386Sopenharmony_ci- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary*)opts {
131cb93a386Sopenharmony_ci    // Override point for customization after application launch.
132cb93a386Sopenharmony_ci    [self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]];
133cb93a386Sopenharmony_ci    [[self window] setFrame:[[UIScreen mainScreen] bounds]];
134cb93a386Sopenharmony_ci    [[self window] setRootViewController:[[AppViewController alloc] init]];
135cb93a386Sopenharmony_ci    [[self window] makeKeyAndVisible];
136cb93a386Sopenharmony_ci    return YES;
137cb93a386Sopenharmony_ci}
138cb93a386Sopenharmony_ci@end
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ciint main(int argc, char* argv[]) {
143cb93a386Sopenharmony_ci    @autoreleasepool {
144cb93a386Sopenharmony_ci        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci}
147