Files
OpenVulkano/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.mm
2023-11-27 09:22:11 +01:00

206 lines
5.8 KiB
Plaintext

/*
* 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 <MoltenVK/mvk_vulkan.h>
#include "Host/GraphicsAppManager.hpp"
#include "Base/UI/IVulkanWindow.hpp"
#import <MetalKit/MTKView.h>
#pragma mark -
#pragma mark OpenVulkanoViewController
using namespace OpenVulkano;
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<VkInstance>(instance), &surfaceCreateInfo, NULL, &surface);
return { surface };
}
std::vector<std::string> GetRequiredInstanceExtensions() override
{
return {};
}
Math::Vector2ui GetSize() override { return windowConf.size;}
void Close() override {}
};
@interface MetalViewDelegate : NSObject<MTKViewDelegate>
- (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<IGraphicsApp> app;
MetalViewDelegate* mtdelegate;
}
-(void*) makeGraphicsApp {
return nullptr;
}
-(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<IGraphicsApp*>(self.makeGraphicsApp);
if (!appPtr) throw std::runtime_error("Failed to create graphics app");
app = std::unique_ptr<IGraphicsApp>(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