parent
6743ca8e09
commit
8324a85339
|
@ -13,6 +13,11 @@ if(WIN32)
|
||||||
target_sources(dolphin-nogui PRIVATE PlatformWin32.cpp)
|
target_sources(dolphin-nogui PRIVATE PlatformWin32.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
target_sources(dolphin-nogui PRIVATE PlatformMacos.mm)
|
||||||
|
target_compile_options(dolphin-nogui PRIVATE -fobjc-arc)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
target_sources(dolphin-nogui PRIVATE PlatformFBDev.cpp)
|
target_sources(dolphin-nogui PRIVATE PlatformFBDev.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
@ -26,6 +31,15 @@ PRIVATE
|
||||||
cpp-optparse
|
cpp-optparse
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
target_link_libraries(dolphin-nogui
|
||||||
|
PRIVATE
|
||||||
|
${APPKIT_LIBRARY}
|
||||||
|
${COREFOUNDATION_LIBRARY}
|
||||||
|
${IOK_LIBRARY}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# Add precompiled header
|
# Add precompiled header
|
||||||
target_link_libraries(dolphin-nogui PRIVATE use_pch)
|
target_link_libraries(dolphin-nogui PRIVATE use_pch)
|
||||||
|
|
|
@ -168,6 +168,10 @@ static std::unique_ptr<Platform> GetPlatform(const optparse::Values& options)
|
||||||
if (platform_name == "win32" || platform_name.empty())
|
if (platform_name == "win32" || platform_name.empty())
|
||||||
return Platform::CreateWin32Platform();
|
return Platform::CreateWin32Platform();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (platform_name == "macos" || platform_name.empty())
|
||||||
|
return Platform::CreateMacOSPlatform();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (platform_name == "headless" || platform_name.empty())
|
if (platform_name == "headless" || platform_name.empty())
|
||||||
return Platform::CreateHeadlessPlatform();
|
return Platform::CreateHeadlessPlatform();
|
||||||
|
@ -198,6 +202,10 @@ int main(int argc, char* argv[])
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
,
|
,
|
||||||
"win32"
|
"win32"
|
||||||
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
,
|
||||||
|
"macos"
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@ public:
|
||||||
static std::unique_ptr<Platform> CreateWin32Platform();
|
static std::unique_ptr<Platform> CreateWin32Platform();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static std::unique_ptr<Platform> CreateMacOSPlatform();
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void UpdateRunningFlag();
|
void UpdateRunningFlag();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,425 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "DolphinNoGUI/Platform.h"
|
||||||
|
|
||||||
|
#include "Common/MsgHandler.h"
|
||||||
|
#include "Core/Config/MainSettings.h"
|
||||||
|
#include "Core/Core.h"
|
||||||
|
#include "Core/State.h"
|
||||||
|
#include "VideoCommon/Present.h"
|
||||||
|
#include "VideoCommon/RenderBase.h"
|
||||||
|
|
||||||
|
#include <AppKit/AppKit.h>
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
#include <Foundation/Foundation.h>
|
||||||
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
@interface Application : NSApplication
|
||||||
|
@property Platform* platform;
|
||||||
|
- (void)shutdown;
|
||||||
|
- (void)togglePause;
|
||||||
|
- (void)saveScreenShot;
|
||||||
|
- (void)loadLastSaved;
|
||||||
|
- (void)undoLoadState;
|
||||||
|
- (void)undoSaveState;
|
||||||
|
- (void)loadState:(id)sender;
|
||||||
|
- (void)saveState:(id)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation Application
|
||||||
|
- (void)shutdown;
|
||||||
|
{
|
||||||
|
[self platform]->RequestShutdown();
|
||||||
|
[self stop:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)togglePause
|
||||||
|
{
|
||||||
|
if (Core::GetState() == Core::State::Running)
|
||||||
|
Core::SetState(Core::State::Paused);
|
||||||
|
else
|
||||||
|
Core::SetState(Core::State::Running);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveScreenShot
|
||||||
|
{
|
||||||
|
Core::SaveScreenShot();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadLastSaved
|
||||||
|
{
|
||||||
|
State::LoadLastSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)undoLoadState
|
||||||
|
{
|
||||||
|
State::UndoLoadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)undoSaveState
|
||||||
|
{
|
||||||
|
State::UndoSaveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadState:(id)sender
|
||||||
|
{
|
||||||
|
State::Load([sender tag]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveState:(id)sender
|
||||||
|
{
|
||||||
|
State::Save([sender tag]);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||||
|
|
||||||
|
@property(readonly) Platform* platform;
|
||||||
|
|
||||||
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender;
|
||||||
|
- (id)initWithPlatform:(Platform*)platform;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithPlatform:(Platform*)platform
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_platform = platform;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface WindowDelegate : NSObject <NSWindowDelegate>
|
||||||
|
|
||||||
|
- (void)windowDidResize:(NSNotification*)notification;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation WindowDelegate
|
||||||
|
|
||||||
|
- (void)windowDidResize:(NSNotification*)notification
|
||||||
|
{
|
||||||
|
if (g_presenter)
|
||||||
|
g_presenter->ResizeSurface();
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class PlatformMacOS : public Platform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~PlatformMacOS() override;
|
||||||
|
|
||||||
|
bool Init() override;
|
||||||
|
void SetTitle(const std::string& title) override;
|
||||||
|
void MainLoop() override;
|
||||||
|
|
||||||
|
WindowSystemInfo GetWindowSystemInfo() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ProcessEvents();
|
||||||
|
void UpdateWindowPosition();
|
||||||
|
void HandleSaveStates(NSUInteger key, NSUInteger flags);
|
||||||
|
void SetupMenu();
|
||||||
|
|
||||||
|
NSRect m_window_rect;
|
||||||
|
NSWindow* m_window;
|
||||||
|
NSMenu* menuBar;
|
||||||
|
AppDelegate* m_app_delegate;
|
||||||
|
WindowDelegate* m_window_delegate;
|
||||||
|
|
||||||
|
int m_window_x = Config::Get(Config::MAIN_RENDER_WINDOW_XPOS);
|
||||||
|
int m_window_y = Config::Get(Config::MAIN_RENDER_WINDOW_YPOS);
|
||||||
|
unsigned int m_window_width = Config::Get(Config::MAIN_RENDER_WINDOW_WIDTH);
|
||||||
|
unsigned int m_window_height = Config::Get(Config::MAIN_RENDER_WINDOW_HEIGHT);
|
||||||
|
bool m_window_fullscreen = Config::Get(Config::MAIN_FULLSCREEN);
|
||||||
|
};
|
||||||
|
|
||||||
|
PlatformMacOS::~PlatformMacOS()
|
||||||
|
{
|
||||||
|
[m_window close];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformMacOS::Init()
|
||||||
|
{
|
||||||
|
[Application sharedApplication];
|
||||||
|
|
||||||
|
m_app_delegate = [[AppDelegate alloc] initWithPlatform:this];
|
||||||
|
[NSApp setDelegate:m_app_delegate];
|
||||||
|
|
||||||
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
|
[NSApp setPlatform:this];
|
||||||
|
[Application.sharedApplication finishLaunching];
|
||||||
|
|
||||||
|
unsigned long styleMask =
|
||||||
|
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
|
||||||
|
|
||||||
|
m_window_rect = CGRectMake(m_window_x, m_window_y, m_window_width, m_window_height);
|
||||||
|
m_window = [NSWindow alloc];
|
||||||
|
m_window = [m_window initWithContentRect:m_window_rect
|
||||||
|
styleMask:styleMask
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:NO];
|
||||||
|
m_window_delegate = [[WindowDelegate alloc] init];
|
||||||
|
[m_window setDelegate:m_window_delegate];
|
||||||
|
|
||||||
|
NSNotificationCenter* c = [NSNotificationCenter defaultCenter];
|
||||||
|
[c addObserver:NSApp
|
||||||
|
selector:@selector(shutdown)
|
||||||
|
name:NSWindowWillCloseNotification
|
||||||
|
object:m_window];
|
||||||
|
|
||||||
|
if (m_window == nil)
|
||||||
|
{
|
||||||
|
NSLog(@"Window is %@\n", m_window);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config::Get(Config::MAIN_SHOW_CURSOR) == Config::ShowCursor::Never)
|
||||||
|
[NSCursor hide];
|
||||||
|
|
||||||
|
if (Config::Get(Config::MAIN_FULLSCREEN))
|
||||||
|
{
|
||||||
|
m_window_fullscreen = true;
|
||||||
|
[m_window toggleFullScreen:m_window];
|
||||||
|
}
|
||||||
|
|
||||||
|
[m_window makeKeyAndOrderFront:NSApp];
|
||||||
|
[m_window makeMainWindow];
|
||||||
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
[m_window setTitle:@"Dolphin-emu-nogui"];
|
||||||
|
|
||||||
|
SetupMenu();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMacOS::SetTitle(const std::string& title)
|
||||||
|
{
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
NSWindow* window = m_window;
|
||||||
|
NSString* str = [NSString stringWithUTF8String:title.c_str()];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[window setTitle:str];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMacOS::MainLoop()
|
||||||
|
{
|
||||||
|
while (IsRunning())
|
||||||
|
{
|
||||||
|
UpdateRunningFlag();
|
||||||
|
Core::HostDispatchJobs();
|
||||||
|
ProcessEvents();
|
||||||
|
UpdateWindowPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowSystemInfo PlatformMacOS::GetWindowSystemInfo() const
|
||||||
|
{
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
WindowSystemInfo wsi;
|
||||||
|
wsi.type = WindowSystemType::MacOS;
|
||||||
|
wsi.render_window = (void*)CFBridgingRetain([m_window contentView]);
|
||||||
|
wsi.render_surface = wsi.render_window;
|
||||||
|
return wsi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMacOS::ProcessEvents()
|
||||||
|
{
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
NSDate* expiration = [NSDate dateWithTimeIntervalSinceNow:1];
|
||||||
|
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
||||||
|
untilDate:expiration
|
||||||
|
inMode:NSDefaultRunLoopMode
|
||||||
|
dequeue:YES];
|
||||||
|
|
||||||
|
[NSApp sendEvent:event];
|
||||||
|
|
||||||
|
// Need to update if m_window becomes fullscreen
|
||||||
|
m_window_fullscreen = [m_window styleMask] & NSWindowStyleMaskFullScreen;
|
||||||
|
|
||||||
|
if ([m_window isMainWindow])
|
||||||
|
{
|
||||||
|
m_window_focus = true;
|
||||||
|
if (Config::Get(Config::MAIN_SHOW_CURSOR) == Config::ShowCursor::Never &&
|
||||||
|
Core::GetState() != Core::State::Paused)
|
||||||
|
[NSCursor unhide];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_window_focus = false;
|
||||||
|
if (Config::Get(Config::MAIN_SHOW_CURSOR) == Config::ShowCursor::Never)
|
||||||
|
[NSCursor hide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMacOS::UpdateWindowPosition()
|
||||||
|
{
|
||||||
|
if (m_window_fullscreen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NSRect win = [m_window frame];
|
||||||
|
m_window_x = win.origin.x;
|
||||||
|
m_window_y = win.origin.y;
|
||||||
|
m_window_width = win.size.width;
|
||||||
|
m_window_height = win.size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMacOS::SetupMenu()
|
||||||
|
{
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
menuBar = [NSMenu new];
|
||||||
|
|
||||||
|
NSMenu* appMenu = [NSMenu new];
|
||||||
|
NSMenu* stateMenu = [[NSMenu alloc] initWithTitle:@"States"];
|
||||||
|
NSMenu* loadStateMenu = [[NSMenu alloc] initWithTitle:@"Load"];
|
||||||
|
NSMenu* saveStateMenu = [[NSMenu alloc] initWithTitle:@"Save"];
|
||||||
|
NSMenu* miscMenu = [[NSMenu alloc] initWithTitle:@"Misc"];
|
||||||
|
|
||||||
|
NSMenuItem* appMenuItem = [NSMenuItem new];
|
||||||
|
NSMenuItem* miscMenuItem = [NSMenuItem new];
|
||||||
|
NSMenuItem* stateMenuItem = [NSMenuItem new];
|
||||||
|
NSMenuItem* loadStateItem = [[NSMenuItem alloc] initWithTitle:@"Load"
|
||||||
|
action:nil
|
||||||
|
keyEquivalent:@""];
|
||||||
|
NSMenuItem* saveStateItem = [[NSMenuItem alloc] initWithTitle:@"Save"
|
||||||
|
action:nil
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[menuBar addItem:appMenuItem];
|
||||||
|
[menuBar addItem:stateMenuItem];
|
||||||
|
[menuBar addItem:miscMenuItem];
|
||||||
|
|
||||||
|
// Quit
|
||||||
|
NSString* quitTitle = [@"Quit " stringByAppendingString:@"dolphin-emu-nogui"];
|
||||||
|
NSMenuItem* quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle
|
||||||
|
action:@selector(shutdown)
|
||||||
|
keyEquivalent:@"q"];
|
||||||
|
|
||||||
|
// Fullscreen
|
||||||
|
NSString* fullScreenItemTitle = @"Toggle Fullscreen";
|
||||||
|
NSMenuItem* fullScreenItem = [[NSMenuItem alloc] initWithTitle:fullScreenItemTitle
|
||||||
|
action:@selector(toggleFullScreen:)
|
||||||
|
keyEquivalent:@"f"];
|
||||||
|
[fullScreenItem setKeyEquivalentModifierMask:NSEventModifierFlagFunction];
|
||||||
|
|
||||||
|
// Screenshot
|
||||||
|
NSString* ScreenShotTitle = @"Take Screenshot";
|
||||||
|
unichar c = NSF9FunctionKey;
|
||||||
|
NSString* f9 = [NSString stringWithCharacters:&c length:1];
|
||||||
|
NSMenuItem* ScreenShotItem = [[NSMenuItem alloc] initWithTitle:ScreenShotTitle
|
||||||
|
action:@selector(saveScreenShot)
|
||||||
|
keyEquivalent:f9];
|
||||||
|
[ScreenShotItem setKeyEquivalentModifierMask:NSEventModifierFlagFunction];
|
||||||
|
|
||||||
|
// Pause game
|
||||||
|
NSString* pauseTitle = @"Toggle pause";
|
||||||
|
c = NSF10FunctionKey;
|
||||||
|
NSString* f10 = [NSString stringWithCharacters:&c length:1];
|
||||||
|
NSMenuItem* pauseItem = [[NSMenuItem alloc] initWithTitle:pauseTitle
|
||||||
|
action:@selector(togglePause)
|
||||||
|
keyEquivalent:f10];
|
||||||
|
[pauseItem setKeyEquivalentModifierMask:NSEventModifierFlagFunction];
|
||||||
|
|
||||||
|
// Load last save
|
||||||
|
NSString* loadLastTitle = @"Load Last Saved";
|
||||||
|
c = NSF11FunctionKey;
|
||||||
|
NSString* f11 = [NSString stringWithCharacters:&c length:1];
|
||||||
|
NSMenuItem* loadLastItem = [[NSMenuItem alloc] initWithTitle:loadLastTitle
|
||||||
|
action:@selector(loadLastSaved)
|
||||||
|
keyEquivalent:f11];
|
||||||
|
[loadLastItem setKeyEquivalentModifierMask:NSEventModifierFlagFunction];
|
||||||
|
|
||||||
|
// Undo Load State
|
||||||
|
NSString* undoLoadTitle = @"Undo Load";
|
||||||
|
c = NSF12FunctionKey;
|
||||||
|
NSString* f12 = [NSString stringWithCharacters:&c length:1];
|
||||||
|
NSMenuItem* undoLoadItem = [[NSMenuItem alloc] initWithTitle:undoLoadTitle
|
||||||
|
action:@selector(undoLoadState)
|
||||||
|
keyEquivalent:f12];
|
||||||
|
[undoLoadItem setKeyEquivalentModifierMask:NSEventModifierFlagShift];
|
||||||
|
|
||||||
|
// Undo Save State
|
||||||
|
NSString* undoSaveTitle = @"Undo Save";
|
||||||
|
NSMenuItem* undoSaveItem = [[NSMenuItem alloc] initWithTitle:undoSaveTitle
|
||||||
|
action:@selector(undoSaveState)
|
||||||
|
keyEquivalent:f12];
|
||||||
|
[undoSaveItem setKeyEquivalentModifierMask:NSEventModifierFlagFunction];
|
||||||
|
|
||||||
|
// Load and Save States
|
||||||
|
for (unichar i = NSF1FunctionKey; i <= NSF8FunctionKey; i++)
|
||||||
|
{
|
||||||
|
NSInteger stateNum = i - NSF1FunctionKey + 1;
|
||||||
|
NSString* lstateTitle = [NSString stringWithFormat:@"Load State %ld", (long)stateNum];
|
||||||
|
c = i;
|
||||||
|
NSString* t = [NSString stringWithCharacters:&c length:1];
|
||||||
|
NSMenuItem* lstateItem = [[NSMenuItem alloc] initWithTitle:lstateTitle
|
||||||
|
action:@selector(loadState:)
|
||||||
|
keyEquivalent:t];
|
||||||
|
[lstateItem setTag:stateNum];
|
||||||
|
[lstateItem setKeyEquivalentModifierMask:NSEventModifierFlagFunction];
|
||||||
|
[loadStateMenu addItem:lstateItem];
|
||||||
|
|
||||||
|
NSString* sstateTitle = [NSString stringWithFormat:@"Save State %ld", (long)stateNum];
|
||||||
|
c = i;
|
||||||
|
NSMenuItem* sstateItem = [[NSMenuItem alloc] initWithTitle:sstateTitle
|
||||||
|
action:@selector(saveState:)
|
||||||
|
keyEquivalent:t];
|
||||||
|
[sstateItem setKeyEquivalentModifierMask:NSEventModifierFlagShift];
|
||||||
|
[sstateItem setTag:stateNum];
|
||||||
|
[saveStateMenu addItem:sstateItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
// App Main menu
|
||||||
|
[appMenu addItem:quitMenuItem];
|
||||||
|
|
||||||
|
// State Menu
|
||||||
|
[loadStateItem setSubmenu:loadStateMenu];
|
||||||
|
[saveStateItem setSubmenu:saveStateMenu];
|
||||||
|
|
||||||
|
[stateMenu addItem:loadLastItem];
|
||||||
|
[stateMenu addItem:undoLoadItem];
|
||||||
|
[stateMenu addItem:undoSaveItem];
|
||||||
|
[stateMenu addItem:loadStateItem];
|
||||||
|
[stateMenu addItem:saveStateItem];
|
||||||
|
|
||||||
|
// Misc Menu
|
||||||
|
[miscMenu addItem:fullScreenItem];
|
||||||
|
[miscMenu addItem:ScreenShotItem];
|
||||||
|
[miscMenu addItem:pauseItem];
|
||||||
|
|
||||||
|
[appMenuItem setSubmenu:appMenu];
|
||||||
|
[stateMenuItem setSubmenu:stateMenu];
|
||||||
|
[miscMenuItem setSubmenu:miscMenu];
|
||||||
|
|
||||||
|
[NSApp setMainMenu:menuBar];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Platform> Platform::CreateMacOSPlatform()
|
||||||
|
{
|
||||||
|
return std::make_unique<PlatformMacOS>();
|
||||||
|
}
|
Loading…
Reference in New Issue