yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Simon Kallweitswitch to vkCreateMetalSurfaceEXT and create metal layer in swapchain (#3627)4f03eb9d6

master
15.5 KiB600 linesraw
1#ifdef __APPLE__
2
3#include "../window.h"
4
5#import <Cocoa/Cocoa.h>
6#import <QuartzCore/CAMetalLayer.h>
7
8using namespace Slang;
9using namespace platform;
10
11namespace platform {
12class CocoaPlatformWindow;
13static KeyCode keyCodes[256];
14
15class CocoaAppContext
16{
17public:
18    static Window* mainWindow;
19    static bool isTerminated;
20};
21
22Window* CocoaAppContext::mainWindow;
23bool CocoaAppContext::isTerminated = false;
24}
25
26@interface WindowDelegate : NSObject <NSWindowDelegate>
27{
28    CocoaPlatformWindow* window;
29}
30
31- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow;
32
33@end
34
35@interface ContentView : NSView
36{
37    CocoaPlatformWindow* window;
38    NSTrackingArea* trackingArea;
39    int mouseX, mouseY;
40}
41
42- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow;
43
44@end
45
46namespace platform {
47
48class CocoaPlatformWindow : public Window
49{
50public:
51    NSWindow* window;
52    WindowDelegate* delegate;
53    bool shouldClose = false;
54
55    CocoaPlatformWindow(const WindowDesc& desc);
56    ~CocoaPlatformWindow();
57
58    virtual void setClientSize(uint32_t width, uint32_t height) override;
59    virtual Rect getClientRect() override;
60    virtual void centerScreen() override;
61    virtual void close() override;
62    virtual bool getFocused() override;
63    virtual bool getVisible() override;
64    virtual WindowHandle getNativeHandle() override;
65    virtual void setText(Slang::String text) override;
66    virtual void show() override;
67    virtual void hide() override;
68    virtual int getCurrentDpi() override;
69};
70
71void getMousePosition(NSEvent* event, NSView* view, int& x, int& y)
72{
73    const NSRect contentRect = [view frame];
74    const NSPoint pos = [event locationInWindow];
75    x = (int)pos.x;
76    y = (int)(contentRect.size.height - pos.y);
77}
78
79ButtonState::Enum _addButtonState(ButtonState::Enum val, ButtonState::Enum newState)
80{
81    return (ButtonState::Enum)((int)val | (int)newState);
82}
83
84static ButtonState::Enum getModifierState(NSUInteger flags)
85{
86    ButtonState::Enum result = ButtonState::None;
87
88    if (flags & NSEventModifierFlagShift)
89        result = _addButtonState(result, ButtonState::Shift);
90    if (flags & NSEventModifierFlagControl)
91        result = _addButtonState(result, ButtonState::Control);
92    if (flags & NSEventModifierFlagOption)
93        result = _addButtonState(result, ButtonState::Alt);
94    return result;
95}
96
97static KeyCode getKeyCode(NSUInteger keyCode)
98{
99    return keyCode < 256 ? keyCodes[keyCode] : KeyCode::None;
100}
101
102}
103
104
105@implementation WindowDelegate
106
107- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow
108{
109    self = [super init];
110    if (self)
111    {
112        window = platformWindow;
113    }
114    return self;
115}
116
117- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
118{
119    return YES;
120}
121
122- (BOOL)windowShouldClose:(id)window_
123{
124    window->shouldClose = true;
125    if (CocoaAppContext::mainWindow == window)
126        CocoaAppContext::isTerminated = true;
127    return YES;
128}
129
130- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
131{
132    printf("applicationShouldTerminate\n");
133    return NSTerminateCancel;
134}
135
136- (void)windowDidResize:(NSNotification*)notification
137{
138    window->events.sizeChanged();
139}
140
141- (void)windowDidBecomeKey:(NSNotification*)notification
142{
143    window->events.focus();
144}
145
146- (void)windowDidResignKey:(NSNotification*)notification
147{
148    window->events.lostFocus();
149}
150
151@end
152
153@implementation ContentView
154
155- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow
156{
157    self = [super init];
158    if (self)
159    {
160        window = platformWindow;
161        mouseX = 0;
162        mouseY = 0;
163        [self updateTrackingAreas];
164    }
165    return self;
166}
167
168- (void)updateTrackingAreas
169{
170    if (trackingArea != nil)
171    {
172        [self removeTrackingArea:trackingArea];
173        [trackingArea release];
174    }
175
176    const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
177                                          NSTrackingMouseMoved |
178                                          NSTrackingActiveInKeyWindow |
179                                          NSTrackingEnabledDuringMouseDrag |
180                                          NSTrackingCursorUpdate |
181                                          NSTrackingInVisibleRect |
182                                          NSTrackingAssumeInside;
183
184    trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
185                                                options:options
186                                                  owner:self
187                                               userInfo:nil];
188
189    [self addTrackingArea:trackingArea];
190    [super updateTrackingAreas];
191}
192
193- (BOOL)isOpaque
194{
195    return YES;
196}
197
198- (BOOL)canBecomeKeyView
199{
200    return YES;
201}
202
203- (BOOL)acceptsFirstResponder
204{
205    return YES;
206}
207
208- (BOOL)acceptsFirstMouse:(NSEvent*)event
209{
210    return YES;
211}
212
213- (BOOL)wantsUpdateLayer
214{
215    return YES;
216}
217
218- (void)mouseDown:(NSEvent*)event
219{
220    getMousePosition(event, self, mouseX, mouseY);
221    ButtonState::Enum buttons = ButtonState::LeftButton;
222    buttons = _addButtonState(buttons, getModifierState([event modifierFlags]));
223    window->events.mouseDown(MouseEventArgs{mouseX, mouseY, 0, buttons});
224}
225
226- (void)mouseUp:(NSEvent*)event
227{
228    getMousePosition(event, self, mouseX, mouseY);
229    ButtonState::Enum buttons = ButtonState::LeftButton;
230    buttons = _addButtonState(buttons, getModifierState([event modifierFlags]));
231    window->events.mouseUp(MouseEventArgs{mouseX, mouseY, 0, buttons});
232}
233
234- (void)rightMouseDown:(NSEvent*)event
235{
236    getMousePosition(event, self, mouseX, mouseY);
237    ButtonState::Enum buttons = ButtonState::RightButton;
238    buttons = _addButtonState(buttons, getModifierState([event modifierFlags]));
239    window->events.mouseDown(MouseEventArgs{mouseX, mouseY, 0, buttons});
240}
241
242- (void)rightMouseUp:(NSEvent*)event
243{
244    getMousePosition(event, self, mouseX, mouseY);
245    ButtonState::Enum buttons = ButtonState::RightButton;
246    buttons = _addButtonState(buttons, getModifierState([event modifierFlags]));
247    window->events.mouseUp(MouseEventArgs{mouseX, mouseY, 0, buttons});
248}
249
250- (void)otherMouseDown:(NSEvent *)event
251{
252    if ([event buttonNumber] == 2)
253    {
254        getMousePosition(event, self, mouseX, mouseY);
255        ButtonState::Enum buttons = ButtonState::MiddleButton;
256        buttons = _addButtonState(buttons, getModifierState([event modifierFlags]));
257        window->events.mouseDown(MouseEventArgs{mouseX, mouseY, 0, buttons});
258    }
259}
260
261- (void)otherMouseUp:(NSEvent *)event
262{
263    if ([event buttonNumber] == 2)
264    {
265        getMousePosition(event, self, mouseX, mouseY);
266        ButtonState::Enum buttons = ButtonState::MiddleButton;
267        buttons = _addButtonState(buttons, getModifierState([event modifierFlags]));
268        window->events.mouseUp(MouseEventArgs{mouseX, mouseY, 0, buttons});
269    }
270}
271
272- (void)mouseDragged:(NSEvent*)event
273{
274    [self mouseMoved:event];
275}
276
277- (void)rightMouseDragged:(NSEvent*)event
278{
279    [self mouseMoved:event];
280}
281
282- (void)otherMouseDragged:(NSEvent*)event
283{
284    [self mouseMoved:event];
285}
286
287- (void)mouseMoved:(NSEvent*)event
288{
289    getMousePosition(event, self, mouseX, mouseY);
290    window->events.mouseMove(MouseEventArgs{mouseX, mouseY, 0, getModifierState([event modifierFlags])});
291}
292
293- (void)scrollWheel:(NSEvent *)event
294{
295    double deltaX = [event scrollingDeltaX];
296    double deltaY = [event scrollingDeltaY];
297    if ([event hasPreciseScrollingDeltas])
298    {
299        deltaX *= 0.1;
300        deltaY *= 0.1;
301    }
302
303    int delta = (int)deltaY;
304
305    window->events.mouseWheel(MouseEventArgs{0, 0, delta, getModifierState([event modifierFlags])});
306}
307
308- (void)keyDown:(NSEvent *)event
309{
310    KeyCode key = getKeyCode([event keyCode]);
311    if (key == KeyCode::None)
312        return;
313    KeyEventArgs keyEventArgs = {key, 0, getModifierState([event modifierFlags]), false};
314    window->events.keyDown(keyEventArgs);
315    // if (!keyEventArgs.cancelEvent)
316    //     [self interpretKeyEvents:@[event]];
317}
318
319- (void)keyUp:(NSEvent *)event
320{
321    KeyCode key = getKeyCode([event keyCode]);
322    if (key == KeyCode::None)
323        return;
324    KeyEventArgs keyEventArgs = {key, 0, getModifierState([event modifierFlags]), false};
325    window->events.keyUp(keyEventArgs);
326    // if (!keyEventArgs.cancelEvent)
327    //     [self interpretKeyEvents:@[event]];
328}
329
330- (void)flagsChanged:(NSEvent *)event
331{
332    KeyCode key = getKeyCode([event keyCode]);
333    ButtonState::Enum buttons = getModifierState([event modifierFlags]);
334    ButtonState::Enum button = ButtonState::None;
335    if (key == KeyCode::Shift)
336        button = ButtonState::Shift;
337    else if (key == KeyCode::Ctrl)
338        button = ButtonState::Control;
339    else if (key == KeyCode::Alt)
340        button = ButtonState::Alt;
341    
342    KeyEventArgs keyEventArgs = {key, 0, buttons, false};
343    if (button & buttons) {
344        window->events.keyDown(keyEventArgs);
345    } else {
346        window->events.keyUp(keyEventArgs);
347    }
348}
349
350@end
351
352
353static NSApplication *_application;
354
355
356namespace platform {
357
358void Application::init()
359{
360    _application = [NSApplication sharedApplication];
361    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
362    [NSApp activateIgnoringOtherApps:YES];
363
364    // Setup key translation table.
365    ::memset(keyCodes, (int)KeyCode::None, sizeof(keyCodes));
366
367    keyCodes[0x1D] = KeyCode::Key0;
368    keyCodes[0x12] = KeyCode::Key1;
369    keyCodes[0x13] = KeyCode::Key2;
370    keyCodes[0x14] = KeyCode::Key3;
371    keyCodes[0x15] = KeyCode::Key4;
372    keyCodes[0x17] = KeyCode::Key5;
373    keyCodes[0x16] = KeyCode::Key6;
374    keyCodes[0x1A] = KeyCode::Key7;
375    keyCodes[0x1C] = KeyCode::Key8;
376    keyCodes[0x19] = KeyCode::Key9;
377    keyCodes[0x00] = KeyCode::A;
378    keyCodes[0x0B] = KeyCode::B;
379    keyCodes[0x08] = KeyCode::C;
380    keyCodes[0x02] = KeyCode::D;
381    keyCodes[0x0E] = KeyCode::E;
382    keyCodes[0x03] = KeyCode::F;
383    keyCodes[0x05] = KeyCode::G;
384    keyCodes[0x04] = KeyCode::H;
385    keyCodes[0x22] = KeyCode::I;
386    keyCodes[0x26] = KeyCode::J;
387    keyCodes[0x28] = KeyCode::K;
388    keyCodes[0x25] = KeyCode::L;
389    keyCodes[0x2E] = KeyCode::M;
390    keyCodes[0x2D] = KeyCode::N;
391    keyCodes[0x1F] = KeyCode::O;
392    keyCodes[0x23] = KeyCode::P;
393    keyCodes[0x0C] = KeyCode::Q;
394    keyCodes[0x0F] = KeyCode::R;
395    keyCodes[0x01] = KeyCode::S;
396    keyCodes[0x11] = KeyCode::T;
397    keyCodes[0x20] = KeyCode::U;
398    keyCodes[0x09] = KeyCode::V;
399    keyCodes[0x0D] = KeyCode::W;
400    keyCodes[0x07] = KeyCode::X;
401    keyCodes[0x10] = KeyCode::Y;
402    keyCodes[0x06] = KeyCode::Z;
403
404    keyCodes[0x27] = KeyCode::Quote;
405    keyCodes[0x2A] = KeyCode::Backslash;
406    keyCodes[0x2B] = KeyCode::Comma;
407    keyCodes[0x18] = KeyCode::Plus;
408    keyCodes[0x32] = KeyCode::Tilde;
409    keyCodes[0x21] = KeyCode::LBracket;
410    keyCodes[0x1B] = KeyCode::Minus;
411    keyCodes[0x2F] = KeyCode::Dot;
412    keyCodes[0x1E] = KeyCode::RBracket;
413    keyCodes[0x29] = KeyCode::Semicolon;
414    keyCodes[0x2C] = KeyCode::Slash;
415
416    keyCodes[0x33] = KeyCode::Backspace;
417    keyCodes[0x75] = KeyCode::Delete;
418    keyCodes[0x7D] = KeyCode::Down;
419    keyCodes[0x77] = KeyCode::End;
420    keyCodes[0x24] = KeyCode::Return;
421    keyCodes[0x35] = KeyCode::Escape;
422    keyCodes[0x7A] = KeyCode::F1;
423    keyCodes[0x78] = KeyCode::F2;
424    keyCodes[0x63] = KeyCode::F3;
425    keyCodes[0x76] = KeyCode::F4;
426    keyCodes[0x60] = KeyCode::F5;
427    keyCodes[0x61] = KeyCode::F6;
428    keyCodes[0x62] = KeyCode::F7;
429    keyCodes[0x64] = KeyCode::F8;
430    keyCodes[0x65] = KeyCode::F9;
431    keyCodes[0x6D] = KeyCode::F10;
432    keyCodes[0x67] = KeyCode::F11;
433    keyCodes[0x6F] = KeyCode::F12;
434    keyCodes[0x73] = KeyCode::Home;
435    keyCodes[0x72] = KeyCode::Insert;
436    keyCodes[0x7B] = KeyCode::Left;
437    keyCodes[0x79] = KeyCode::PageDown;
438    keyCodes[0x74] = KeyCode::PageUp;
439    keyCodes[0x7C] = KeyCode::Right;
440    keyCodes[0x31] = KeyCode::Space;
441    keyCodes[0x30] = KeyCode::Tab;
442    keyCodes[0x7E] = KeyCode::Up;
443
444    keyCodes[0x38] = KeyCode::Shift;
445    keyCodes[0x3B] = KeyCode::Ctrl;
446    keyCodes[0x3A] = KeyCode::Alt;
447}
448
449void doEventsImpl(bool waitForEvents)
450{
451    NSEvent *event;
452    do {
453        event = [NSApp nextEventMatchingMask:NSEventMaskAny
454                                   untilDate:waitForEvents ? [NSDate distantFuture] : [NSDate distantPast]
455                                      inMode:NSDefaultRunLoopMode
456                                     dequeue:YES];
457        if (event) {
458            [NSApp sendEvent:event];
459        }
460    } while (!CocoaAppContext::isTerminated && event);
461}
462
463void Application::doEvents()
464{
465    doEventsImpl(false);
466}
467
468void Application::quit()
469{
470    CocoaAppContext::isTerminated = true;
471}
472
473void Application::dispose()
474{
475    CocoaAppContext::mainWindow = nullptr;
476}
477
478void Application::run(Window* mainWindow, bool waitForEvents)
479{
480    if (mainWindow)
481    {
482        CocoaAppContext::mainWindow = mainWindow;
483        mainWindow->show();
484    }
485    while (!CocoaAppContext::isTerminated)
486    {
487        doEventsImpl(waitForEvents);
488        if (CocoaAppContext::isTerminated)
489            break;
490        if (mainWindow)
491        {
492            mainWindow->events.mainLoop();
493        }
494    }
495}
496
497CocoaPlatformWindow::CocoaPlatformWindow(const WindowDesc& desc)
498{
499    // Create a reference rectangle
500    NSRect rect = NSMakeRect(0.0f, 0.0f, desc.width, desc.height);
501
502    // Allocate window
503    window = [[NSWindow alloc] initWithContentRect:rect
504                                         styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable
505                                           backing:NSBackingStoreBuffered
506                                             defer:NO];
507
508    const NSWindowCollectionBehavior behavior
509        = NSWindowCollectionBehaviorFullScreenPrimary | NSWindowCollectionBehaviorManaged;
510    [window setCollectionBehavior:behavior];
511
512    if (desc.style == WindowStyle::Default)
513        [window setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable];
514    else if (desc.style == WindowStyle::FixedSize)
515        [window setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable];
516
517    delegate = [[WindowDelegate alloc] initWithPlatformWindow:this];
518    [window setDelegate:delegate];
519
520    NSString* title = [NSString stringWithUTF8String:desc.title];
521    [window setTitle:title];
522
523    [window center];
524    [window makeKeyAndOrderFront:nil];
525}
526
527CocoaPlatformWindow::~CocoaPlatformWindow()
528{
529    close();
530}
531
532void CocoaPlatformWindow::setClientSize(uint32_t width, uint32_t height)
533{
534    NSSize size = NSMakeSize(width, height);
535    [window setContentSize:size];
536}
537
538Rect CocoaPlatformWindow::getClientRect()
539{
540    NSRect rect = [window contentRectForFrameRect:[window frame]];
541    return { (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height };
542}
543
544void CocoaPlatformWindow::centerScreen()
545{
546    [window center];
547}
548
549void CocoaPlatformWindow::close()
550{
551    [window release];
552    [delegate release];
553
554    window = nil;
555    delegate = nil;
556}
557
558bool CocoaPlatformWindow::getFocused()
559{
560    return [window isKeyWindow];
561}
562
563bool CocoaPlatformWindow::getVisible()
564{
565    return [window isVisible];
566}
567
568WindowHandle CocoaPlatformWindow::getNativeHandle()
569{
570    return WindowHandle::fromNSWindow(window);
571}
572
573void CocoaPlatformWindow::setText(Slang::String text)
574{
575    NSString* title = [NSString stringWithUTF8String:text.begin()];
576    [window setTitle:title];
577}
578
579void CocoaPlatformWindow::show()
580{
581    [window setIsVisible:YES];
582}
583
584void CocoaPlatformWindow::hide()
585{
586    [window setIsVisible:NO];
587}
588
589int CocoaPlatformWindow::getCurrentDpi()
590{
591    // There seems to be no API to get the actual DPI of the screen.
592    return 0;
593}
594
595Window* Application::createWindow(const WindowDesc& desc) { return new CocoaPlatformWindow(desc); }
596
597
598} // namespace platform
599
600#endif // __APPLE__