/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #import "OpenVulkanoViewController.h" #include #include "Host/GraphicsAppManager.hpp" #include "ExampleApps/CubesExampleApp.hpp" #include "Base/UI/IVulkanWindow.hpp" #pragma mark - #pragma mark OpenVulkanoViewController using namespace openVulkanoCpp; class ViewWindow final : public IVulkanWindow { WindowConfiguration windowConf; IWindowHandler* handler = nullptr; void* caMetalLayer = nullptr; public: void Init(RenderAPI::RenderApi renderApi) override {} void Init(void* metalLayer, Math::Vector2ui size) { caMetalLayer = metalLayer; windowConf.size = size; } void SetMetalLayer(void* metalLayer) { caMetalLayer = metalLayer; } bool HasTitle() override { return false; } const std::string& GetTitle() override { return windowConf.title; } void SetTitle(const std::string& title) override {} WindowMode GetWindowMode() override { return FULLSCREEN; } void SetWindowMode(WindowMode) override {} const WindowConfiguration & GetWindowConfiguration() override { return windowConf; } void SetSize(uint32_t width, uint32_t height) override { windowConf.size = { width, height }; } void SetSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight) override {} Math::Vector2i GetPosition() override { return { 0,0 }; } void SetPosition(int posX, int posY) override {} void Show() override {} void Hide() override {} void Show(bool show) override {} IWindowHandler * GetWindowHandler() override { return handler; } void SetWindowHandler(IWindowHandler *handler) override { this->handler = handler; } uint32_t GetWindowId() const override { return 0; } IOpenGlWindow * GetOpenGlWindow() override { return nullptr; } IVulkanWindow * GetVulkanWindow() override { return this; } bool WindowHasBeenDestroyed() const override { return false; } void SetWindowHasBeenDestroyed() override {} void* GetNativeWindowHandle() override { return caMetalLayer; } vk::SurfaceKHR CreateSurface(const vk::Instance &instance, const vk::AllocationCallbacks *pAllocator = nullptr) override { VkMetalSurfaceCreateInfoEXT surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; surfaceCreateInfo.pNext = NULL; surfaceCreateInfo.flags = 0; surfaceCreateInfo.pLayer = (CAMetalLayer*)caMetalLayer; VkSurfaceKHR surface; auto err = vkCreateMetalSurfaceEXT(static_cast(instance), &surfaceCreateInfo, NULL, &surface); return { surface }; } std::vector GetRequiredInstanceExtensions() override { return {}; } Math::Vector2ui GetSize() override { return windowConf.size;} void Close() override {} }; @interface MetalViewDelegate : NSObject - (id)initWithGAM:(GraphicsAppManager*)gam; - (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size; - (void) drawInMTKView:(MTKView *) view; @end @implementation MetalViewDelegate { GraphicsAppManager* manager; IWindow* window; } - (id)initWithGAM:(GraphicsAppManager*)gam win:(IWindow*)win { manager = gam; window = win; return self; } - (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size { manager->OnWindowResize(window, size.width, size.height); } - (void) drawInMTKView:(MTKView *) view { @autoreleasepool { manager->LoopTick(); } } @end @implementation OpenVulkanoViewController { CADisplayLink* _displayLink; GraphicsAppManager* manager; ViewWindow window; std::unique_ptr app; MetalViewDelegate* mtdelegate; } -(void*) makeGraphicsApp { return CubesExampleApp::Create(); } -(void) dealloc { manager->ShutDown(); [_displayLink release]; [super dealloc]; } /** Since this is a single-view app, init Vulkan when the view is loaded. */ -(void) viewDidLoad { [super viewDidLoad]; self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale / 1.5f; auto size = self.view.bounds.size; auto sizeX = size.width * self.view.contentScaleFactor; auto sizeY = size.height * self.view.contentScaleFactor; window.Init(self.view.layer, {sizeX, sizeY}); //TODO check if type is correct IGraphicsApp* appPtr = static_cast(self.makeGraphicsApp); if (!appPtr) throw std::runtime_error("Failed to create graphics app"); app = std::unique_ptr(appPtr); manager = new GraphicsAppManager(app.get(), &window); manager->StartUp(); if ([self.view isKindOfClass:[MTKView class]]) { MTKView* mtkView = (MTKView*)(self.view); mtdelegate = [[MetalViewDelegate alloc] initWithGAM:manager win:&window]; [mtkView setDelegate:mtdelegate]; mtkView.preferredFramesPerSecond = 60; } else { _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderLoop)]; [_displayLink setPreferredFramesPerSecond: 60]; [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; } } -(void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale / 1.5f; auto size = self.view.bounds.size; auto sizeX = size.width * self.view.contentScaleFactor; auto sizeY = size.height * self.view.contentScaleFactor; manager->OnWindowResize(&window, sizeX, sizeY); } -(void) viewDidDisappear:(BOOL)animated { [_displayLink release]; _displayLink = nil; [super viewDidDisappear:animated]; } -(void) viewDidUnload { [_displayLink release]; _displayLink = nil; [super viewDidUnload]; } -(void) renderLoop { manager->LoopTick(); } // Allow device rotation to resize the swapchain -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; manager->OnWindowResize(&window, size.width, size.height); } - (BOOL)prefersHomeIndicatorAutoHidden { return true; } @end #pragma mark - #pragma mark OpenVulkanoView @implementation OpenVulkanoView /** Returns a Metal-compatible layer. */ +(Class) layerClass { return [CAMetalLayer class]; } @end