Update macos build

This commit is contained in:
Georg Hagen
2024-07-30 08:13:39 +02:00
parent 6e4dd72b3a
commit d166f825bb
10 changed files with 190 additions and 1 deletions

View File

@@ -0,0 +1,19 @@
/*
* 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/.
*/
#pragma once
#import <Foundation/Foundation.h>
#include "Host/ResourceLoader.hpp"
namespace OpenVulkano
{
class BundledResourceLoaderIOS : public ResourceLoader
{
public:
Array<char> GetResource(const std::string& resourceName) override;
};
}

View File

@@ -0,0 +1,30 @@
/*
* 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/.
*/
#include "BundledResoureLoaderIos.h"
#include "Base/Logger.hpp"
#include "Base/Utils.hpp"
namespace OpenVulkano
{
namespace
{
void* LOADER_HANDLE = ResourceLoader::RegisterResourceLoader(std::move(std::unique_ptr<ResourceLoader>(new BundledResourceLoaderIOS())));
}
Array<char> BundledResourceLoaderIOS::GetResource(const std::string& resourceName)
{
@autoreleasepool
{
auto [fileName, fileType] = Utils::SplitAtLastOccurrence(resourceName, '.');
NSString* filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithUTF8String:fileName.c_str()] ofType:[NSString stringWithUTF8String:fileType.c_str()]];
return Utils::ReadFile(std::string([filePath UTF8String]));
}
Logger::FILESYS->warn("Failed to find resource: '{}' in bundle", resourceName);
return {0};
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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/.
*/
#pragma once
#include "Base/UI/IVulkanWindow.hpp"
namespace OpenVulkano
{
class MetalViewWindow final : public IVulkanWindow
{
WindowConfiguration windowConf;
IWindowHandler* handler = nullptr;
void* caMetalLayer = nullptr;
bool tickHandler = true;
float contentScale = 1;
float orientation = 0;
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
{
//TODO
}
void* GetNativeWindowHandle() override { return caMetalLayer; }
vk::SurfaceKHR CreateSurface(const vk::Instance& instance, const vk::AllocationCallbacks* pAllocator = nullptr) override;
std::vector<std::string> GetRequiredInstanceExtensions() override;
Math::Vector2ui GetSize() override { return windowConf.size; }
void Close() override {}
void OnResize(uint32_t width, uint32_t height);
virtual float GetContentScale() const override { return contentScale; }
virtual float GetInterfaceOrientation() const override { return orientation; }
void SetContentScale(float scale) { contentScale = scale; }
void SetOrientation(float orientation) { this->orientation = orientation; }
void TickHandler();
};
}

View File

@@ -0,0 +1,53 @@
/*
* 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/.
*/
// Makre usre the Molten include is first!
#include <MoltenVK/mvk_vulkan.h>
#include "MetalViewWindow.h"
#include "Base/Logger.hpp"
#include "Host/GraphicsAppManager.hpp"
#import <MetalKit/MTKView.h>
namespace OpenVulkano
{
vk::SurfaceKHR MetalViewWindow::CreateSurface(const vk::Instance& instance, const vk::AllocationCallbacks* pAllocator)
{
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> MetalViewWindow::GetRequiredInstanceExtensions()
{
return {}; //TODO
}
void MetalViewWindow::OnResize(uint32_t newWidth, uint32_t newHeight)
{
Logger::WINDOW->debug("Window (id: {0}) resized (width: {1}, height: {2})", GetWindowId(), newWidth, newHeight);
if (handler)
handler->OnWindowResize(this, newWidth, newHeight);
}
void MetalViewWindow::TickHandler()
{
if (tickHandler)
{
if (auto graphApp = dynamic_cast<GraphicsAppManager*>(handler))
{
graphApp->LoopTick();
}
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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/.
*/
#pragma once
#include "Base/Event.hpp"
namespace OpenVulkano
{
class NamedEventProcessor final : public INamedEventProcessor
{
std::vector<std::string> m_classNamePrefixes, m_classNameSuffixes;
bool m_useClassNameAsEventName;
public:
NamedEventProcessor(bool classNameAsEventName = false)
: m_classNamePrefixes({ "", "Event" })
, m_classNameSuffixes({ "Event", "" })
, m_useClassNameAsEventName(classNameAsEventName)
{}
void RegisterClassNamePrefix(const std::string& prefix) { m_classNamePrefixes.push_back(prefix); }
void RegisterClassNameSuffix(const std::string& suffix) { m_classNameSuffixes.push_back(suffix); }
void Notify(const std::string& eventName, const std::vector<Parameters>& parameters) const override;
};
}

View File

@@ -0,0 +1,171 @@
/*
* 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/.
*/
#include "NamedEventProcessor.h"
#include "Base/Logger.hpp"
#include <map>
#include <typeindex>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
namespace OpenVulkano
{
namespace
{
NamedEventProcessor appleNotificationNamedEventProcessor;
constexpr int LONGEST_TYPE_NAME = std::max({ sizeof(@encode(NSString*)), sizeof(@encode(BOOL)), sizeof(@encode(int)), sizeof(@encode(float)), sizeof(@encode(double)) });
std::map<std::type_index, std::string> TYPE_NAME_MAP = {
{ std::type_index(typeid(std::string)), @encode(NSString*) },
{ std::type_index(typeid(bool)), @encode(BOOL) },
{ std::type_index(typeid(int)), @encode(int) },
{ std::type_index(typeid(float)), @encode(float) },
{ std::type_index(typeid(double)), @encode(double) },
{ std::type_index(typeid(UUID)), @encode(NSUUID*) }
};
// Keep this in sync with INamedEventProcessor! synctag: NamedEventProcessor_Parameters_SYNC_TAG
union ParameterValue
{
NSString* string;
BOOL boolean;
int integer;
float fp32;
double fp64;
NSUUID* uuid;
};
std::string BuildTypeName(const std::vector<INamedEventProcessor::Parameters>& parameters)
{
std::string typeName("@:");
typeName.reserve(2 + parameters.size() * (LONGEST_TYPE_NAME + 2));
for(const auto& parameter : parameters)
{
typeName.append(std::visit([](auto&& arg) {
return TYPE_NAME_MAP.find(typeid(std::decay_t<decltype(arg)>))->second;
}, parameter));
}
return typeName;
}
template <typename T>
ParameterValue CreateValue(const T& parameter)
{
ParameterValue value;
reinterpret_cast<T&>(value) = parameter;
return value;
}
ParameterValue CreateValue(const std::string& parameter)
{
ParameterValue value;
value.string = [NSString stringWithUTF8String:parameter.c_str()];
return value;
}
ParameterValue CreateValue(const UUID& parameter)
{
ParameterValue value;
auto uuidData = parameter.binary();
value.uuid = [[NSUUID alloc] initWithUUIDBytes:uuidData.data()];
return value;
}
std::string SelectorType(Method m)
{
std::string sig;
for (auto i = 0u, count = method_getNumberOfArguments(m); i < count; ++i)
{
auto argType = method_copyArgumentType(m, i);
sig += std::string(argType);
free(argType);
}
return sig;
}
SEL GetInitForClass(Class c, const std::string &initType)
{
SEL init = nullptr;
for (auto clazz = c; !init && clazz; clazz = class_getSuperclass(clazz))
{
if (Method *methods = class_copyMethodList(clazz, nullptr))
{
for (int i = 0; methods[i]; i++)
{
const std::string name = sel_getName(method_getName(methods[i]));
const std::string type = SelectorType(methods[i]);
if (0 == name.find("init") && type == initType)
{
init = method_getName(methods[i]);
break;
}
}
free(methods);
}
}
return init;
}
Class FindGenericEventClass(const std::vector<std::string>& prefixes,
const std::vector<std::string>& suffixes,
const std::string& eventName)
{ // Searching for class with all registered prefix/suffix combinations
for (const std::string& suffix : suffixes)
{
for (const std::string& prefix: prefixes)
{
NSString* eventClassName = [NSString stringWithUTF8String:(prefix + eventName + suffix).c_str()];
if (Class eventClass = NSClassFromString(eventClassName))
{
return eventClass;
}
}
}
return nullptr;
}
}
void NamedEventProcessor::Notify(const std::string& eventName, const std::vector<Parameters>& parameters) const
{
@autoreleasepool
{
if (Class eventClass = FindGenericEventClass(m_classNamePrefixes, m_classNameSuffixes, eventName))
{
if (SEL init = GetInitForClass(eventClass, BuildTypeName(parameters)))
{
NSObject* event = [eventClass alloc];
auto inv = [NSInvocation invocationWithMethodSignature:[event methodSignatureForSelector:init]];
[inv setTarget:event];
[inv setSelector:init];
for (int i = 0; i < parameters.size(); i++)
{
auto arg = std::visit([](auto&& arg) { return CreateValue(arg); }, parameters[i]);
[inv setArgument:&arg atIndex:(i + 2)];
}
[inv invoke];
for (Class clazz = eventClass; clazz && clazz != NSObject.class; clazz = class_getSuperclass(clazz))
{
NSString* notificationName;
if (m_useClassNameAsEventName) notificationName = NSStringFromClass(clazz);
else notificationName = [NSString stringWithUTF8String:eventName.c_str()];
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:event userInfo:nil];
}
[event release];
}
else
{
Logger::MANAGER->error("Cannot find constructor for named event %s", eventName);
}
}
else
{
Logger::MANAGER->debug("Cannot find implementation for named event %s", eventName);
}
}
}
}