sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_cocoametalview.m (5760B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 /*
     22  * @author Mark Callow, www.edgewise-consulting.com.
     23  *
     24  * Thanks to Alex Szpakowski, @slime73 on GitHub, for his gist showing
     25  * how to add a CAMetalLayer backed view.
     26  */
     27 #include "../../SDL_internal.h"
     28 
     29 #import "SDL_cocoametalview.h"
     30 
     31 #if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL)
     32 
     33 #include "SDL_events.h"
     34 
     35 static int SDLCALL
     36 SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
     37 {
     38     /* Update the drawable size when SDL receives a size changed event for
     39      * the window that contains the metal view. It would be nice to use
     40      * - (void)resizeWithOldSuperviewSize:(NSSize)oldSize and
     41      * - (void)viewDidChangeBackingProperties instead, but SDL's size change
     42      * events don't always happen in the same frame (for example when a
     43      * resizable window exits a fullscreen Space via the user pressing the OS
     44      * exit-space button). */
     45     if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
     46         @autoreleasepool {
     47             SDL_cocoametalview *view = (__bridge SDL_cocoametalview *)userdata;
     48             if (view.sdlWindowID == event->window.windowID) {
     49                 [view updateDrawableSize];
     50             }
     51         }
     52     }
     53     return 0;
     54 }
     55 
     56 @implementation SDL_cocoametalview
     57 
     58 /* Return a Metal-compatible layer. */
     59 + (Class)layerClass
     60 {
     61     return NSClassFromString(@"CAMetalLayer");
     62 }
     63 
     64 /* Indicate the view wants to draw using a backing layer instead of drawRect. */
     65 - (BOOL)wantsUpdateLayer
     66 {
     67     return YES;
     68 }
     69 
     70 /* When the wantsLayer property is set to YES, this method will be invoked to
     71  * return a layer instance.
     72  */
     73 - (CALayer*)makeBackingLayer
     74 {
     75     return [self.class.layerClass layer];
     76 }
     77 
     78 - (instancetype)initWithFrame:(NSRect)frame
     79                       highDPI:(BOOL)highDPI
     80                      windowID:(Uint32)windowID;
     81 {
     82     if ((self = [super initWithFrame:frame])) {
     83         self.highDPI = highDPI;
     84         self.sdlWindowID = windowID;
     85         self.wantsLayer = YES;
     86 
     87         /* Allow resize. */
     88         self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
     89 
     90         SDL_AddEventWatch(SDL_MetalViewEventWatch, self);
     91 
     92         [self updateDrawableSize];
     93     }
     94   
     95     return self;
     96 }
     97 
     98 - (void)dealloc
     99 {
    100     SDL_DelEventWatch(SDL_MetalViewEventWatch, self);
    101     [super dealloc];
    102 }
    103 
    104 - (NSInteger)tag
    105 {
    106     return METALVIEW_TAG;
    107 }
    108 
    109 - (void)updateDrawableSize
    110 {
    111     CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer;
    112     NSSize size = self.bounds.size;
    113     NSSize backingSize = size;
    114 
    115     if (self.highDPI) {
    116         /* Note: NSHighResolutionCapable must be set to true in the app's
    117          * Info.plist in order for the backing size to be high res.
    118          */
    119         backingSize = [self convertSizeToBacking:size];
    120     }
    121 
    122     metalLayer.contentsScale = backingSize.height / size.height;
    123     metalLayer.drawableSize = NSSizeToCGSize(backingSize);
    124 }
    125 
    126 - (NSView *)hitTest:(NSPoint)point {
    127     return nil;
    128 }
    129 
    130 @end
    131 
    132 SDL_MetalView
    133 Cocoa_Metal_CreateView(_THIS, SDL_Window * window)
    134 { @autoreleasepool {
    135     SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
    136     NSView *view = data->nswindow.contentView;
    137     BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
    138     Uint32 windowID = SDL_GetWindowID(window);
    139     SDL_cocoametalview *newview;
    140     SDL_MetalView metalview;
    141 
    142     newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame
    143                                                 highDPI:highDPI
    144                                                 windowID:windowID];
    145     if (newview == nil) {
    146         return NULL;
    147     }
    148 
    149     [view addSubview:newview];
    150 
    151     metalview = (SDL_MetalView)CFBridgingRetain(newview);
    152     [newview release];
    153 
    154     return metalview;
    155 }}
    156 
    157 void
    158 Cocoa_Metal_DestroyView(_THIS, SDL_MetalView view)
    159 { @autoreleasepool {
    160     SDL_cocoametalview *metalview = CFBridgingRelease(view);
    161     [metalview removeFromSuperview];
    162 }}
    163 
    164 void *
    165 Cocoa_Metal_GetLayer(_THIS, SDL_MetalView view)
    166 { @autoreleasepool {
    167     SDL_cocoametalview *cocoaview = (__bridge SDL_cocoametalview *)view;
    168     return (__bridge void *)cocoaview.layer;
    169 }}
    170 
    171 void
    172 Cocoa_Metal_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
    173 { @autoreleasepool {
    174     SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
    175     NSView *view = data->nswindow.contentView;
    176     SDL_cocoametalview* metalview = [view viewWithTag:METALVIEW_TAG];
    177     if (metalview) {
    178         CAMetalLayer *layer = (CAMetalLayer*)metalview.layer;
    179         SDL_assert(layer != NULL);
    180         if (w) {
    181             *w = layer.drawableSize.width;
    182         }
    183         if (h) {
    184             *h = layer.drawableSize.height;
    185         }
    186     } else {
    187         SDL_GetWindowSize(window, w, h);
    188     }
    189 }}
    190 
    191 #endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */
    192 
    193 /* vi: set ts=4 sw=4 expandtab: */