Remove macOS Cocoa and Metal backends
This commit is contained in:
parent
71fe041691
commit
4680579899
16 changed files with 7 additions and 2021 deletions
|
@ -22,7 +22,9 @@ endif()
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS)
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS)
|
||||||
message("macOS build detected!")
|
message("macOS build detected!")
|
||||||
|
|
||||||
set(ENABLE_METAL TRUE)
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
set(ENABLE_VULKAN TRUE)
|
||||||
set(ENABLE_DARWIN TRUE)
|
set(ENABLE_DARWIN TRUE)
|
||||||
set(ENABLE_MACOS TRUE)
|
set(ENABLE_MACOS TRUE)
|
||||||
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
set(SRC
|
|
||||||
include/gfx_metal.hpp
|
|
||||||
|
|
||||||
src/gfx_metal.mm
|
|
||||||
src/gfx_metal_buffer.hpp
|
|
||||||
src/gfx_metal_pipeline.hpp
|
|
||||||
src/gfx_metal_texture.hpp
|
|
||||||
src/gfx_metal_framebuffer.hpp
|
|
||||||
src/gfx_metal_renderpass.hpp
|
|
||||||
src/gfx_metal_sampler.hpp)
|
|
||||||
|
|
||||||
add_library(GFXMetal STATIC
|
|
||||||
${SRC})
|
|
||||||
|
|
||||||
set_target_properties(GFXMetal PROPERTIES
|
|
||||||
FRAMEWORK TRUE
|
|
||||||
FRAMEWORK_VERSION OBJC
|
|
||||||
PUBLIC_HEADER "${HEADERS}"
|
|
||||||
)
|
|
||||||
target_link_libraries(GFXMetal PUBLIC
|
|
||||||
GFX
|
|
||||||
Core
|
|
||||||
Log
|
|
||||||
"-framework Metal")
|
|
||||||
target_include_directories(GFXMetal PUBLIC
|
|
||||||
include
|
|
||||||
PRIVATE
|
|
||||||
src)
|
|
||||||
set_engine_properties(GFXMetal)
|
|
|
@ -1,70 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
#include <MetalKit/MetalKit.h>
|
|
||||||
|
|
||||||
#include "gfx.hpp"
|
|
||||||
|
|
||||||
class GFXMetal : public GFX {
|
|
||||||
public:
|
|
||||||
bool is_supported() override;
|
|
||||||
GFXContext required_context() override { return GFXContext::Metal; }
|
|
||||||
ShaderLanguage accepted_shader_language() override { return ShaderLanguage::MSL; }
|
|
||||||
const char* get_name() override;
|
|
||||||
|
|
||||||
bool supports_feature(const GFXFeature feature) override;
|
|
||||||
|
|
||||||
bool initialize(const GFXCreateInfo& createInfo) override;
|
|
||||||
|
|
||||||
void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override;
|
|
||||||
void remove_view(const int identifier) override;
|
|
||||||
|
|
||||||
// buffer operations
|
|
||||||
GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage usage) override;
|
|
||||||
void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override;
|
|
||||||
|
|
||||||
void* get_buffer_contents(GFXBuffer* buffer) override;
|
|
||||||
|
|
||||||
// texture operations
|
|
||||||
GFXTexture* create_texture(const GFXTextureCreateInfo& info) override;
|
|
||||||
void copy_texture(GFXTexture* texture, void* data, GFXSize size) override;
|
|
||||||
void copy_texture(GFXTexture* from, GFXTexture* to) override;
|
|
||||||
void copy_texture(GFXTexture* from, GFXBuffer* to) override;
|
|
||||||
|
|
||||||
// sampler opeations
|
|
||||||
GFXSampler* create_sampler(const GFXSamplerCreateInfo& info) override;
|
|
||||||
|
|
||||||
// framebuffer operations
|
|
||||||
GFXFramebuffer* create_framebuffer(const GFXFramebufferCreateInfo& info) override;
|
|
||||||
|
|
||||||
// render pass operations
|
|
||||||
GFXRenderPass* create_render_pass(const GFXRenderPassCreateInfo& info) override;
|
|
||||||
|
|
||||||
// pipeline operations
|
|
||||||
GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override;
|
|
||||||
GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override;
|
|
||||||
|
|
||||||
GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override;
|
|
||||||
|
|
||||||
void submit(GFXCommandBuffer* command_buffer, const int window = -1) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct NativeMTLView {
|
|
||||||
int identifier = -1;
|
|
||||||
CAMetalLayer* layer = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<NativeMTLView*> nativeViews;
|
|
||||||
|
|
||||||
NativeMTLView* getNativeView(int identifier) {
|
|
||||||
for(auto& view : nativeViews) {
|
|
||||||
if(view->identifier == identifier)
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLDevice> device = nil;
|
|
||||||
id<MTLCommandQueue> command_queue = nil;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,19 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_buffer.hpp"
|
|
||||||
|
|
||||||
class GFXMetalBuffer : public GFXBuffer {
|
|
||||||
public:
|
|
||||||
id<MTLBuffer> handles[3] = {nil, nil, nil};
|
|
||||||
bool dynamicData = false;
|
|
||||||
|
|
||||||
id<MTLBuffer> get(int frameIndex) {
|
|
||||||
if(dynamicData) {
|
|
||||||
return handles[frameIndex];
|
|
||||||
} else {
|
|
||||||
return handles[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "gfx_framebuffer.hpp"
|
|
||||||
|
|
||||||
class GFXMetalTexture;
|
|
||||||
|
|
||||||
class GFXMetalFramebuffer : public GFXFramebuffer {
|
|
||||||
public:
|
|
||||||
std::vector<GFXMetalTexture*> attachments;
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_pipeline.hpp"
|
|
||||||
|
|
||||||
class GFXMetalPipeline : public GFXPipeline {
|
|
||||||
public:
|
|
||||||
std::string label;
|
|
||||||
|
|
||||||
id<MTLRenderPipelineState> handle = nil;
|
|
||||||
id<MTLComputePipelineState> compute_handle = nil;
|
|
||||||
|
|
||||||
MTLSize threadGroupSize;
|
|
||||||
|
|
||||||
id<MTLDepthStencilState> depthStencil = nil;
|
|
||||||
MTLPrimitiveType primitiveType;
|
|
||||||
|
|
||||||
MTLCullMode cullMode;
|
|
||||||
GFXWindingMode winding_mode;
|
|
||||||
|
|
||||||
struct VertexStride {
|
|
||||||
int location, stride;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<VertexStride> vertexStrides;
|
|
||||||
|
|
||||||
int pushConstantSize = 0;
|
|
||||||
int pushConstantIndex = 0;
|
|
||||||
|
|
||||||
bool renderWire = false;
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_renderpass.hpp"
|
|
||||||
|
|
||||||
class GFXMetalRenderPass : public GFXRenderPass {
|
|
||||||
public:
|
|
||||||
std::vector<MTLPixelFormat> attachments;
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_sampler.hpp"
|
|
||||||
|
|
||||||
class GFXMetalSampler : public GFXSampler {
|
|
||||||
public:
|
|
||||||
id<MTLSamplerState> handle = nil;
|
|
||||||
};
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_texture.hpp"
|
|
||||||
|
|
||||||
class GFXMetalTexture : public GFXTexture {
|
|
||||||
public:
|
|
||||||
id<MTLTexture> handle = nil;
|
|
||||||
id<MTLSamplerState> sampler = nil;
|
|
||||||
|
|
||||||
int array_length = 1;
|
|
||||||
bool is_cubemap = false;
|
|
||||||
|
|
||||||
MTLPixelFormat format;
|
|
||||||
};
|
|
|
@ -7,7 +7,7 @@ if(ENABLE_LINUX)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_MACOS)
|
if(ENABLE_MACOS)
|
||||||
add_subdirectory(mac)
|
add_subdirectory(sdl)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_IOS)
|
if(ENABLE_IOS)
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
include(../../cmake/AddPlatformExecutable.cmake)
|
|
||||||
|
|
||||||
add_platform(
|
|
||||||
MAIN_FILE
|
|
||||||
main.mm.in
|
|
||||||
SRC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/file.mm
|
|
||||||
EXECUTABLE_PROPERTIES
|
|
||||||
MACOSX_BUNDLE ON
|
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
|
||||||
LINK_LIBRARIES
|
|
||||||
Core
|
|
||||||
GFXMetal
|
|
||||||
"-framework Cocoa"
|
|
||||||
"-framework QuartzCore"
|
|
||||||
"-framework GameController"
|
|
||||||
COMPILE_OPTIONS
|
|
||||||
-std=c++17
|
|
||||||
)
|
|
||||||
|
|
||||||
function(add_platform_commands target)
|
|
||||||
target_link_options(${target} BEFORE PRIVATE -pagezero_size 10000 -image_base 100000000
|
|
||||||
)
|
|
||||||
if(NOT SKIP_DATA)
|
|
||||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $<TARGET_FILE_DIR:${target}>/../Resources/data)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/../Resources/shaders)
|
|
||||||
endfunction()
|
|
|
@ -1,42 +0,0 @@
|
||||||
#include "file.hpp"
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
|
|
||||||
#include "string_utils.hpp"
|
|
||||||
|
|
||||||
#include "log.hpp"
|
|
||||||
|
|
||||||
inline std::string clean_path(const std::string_view path) {
|
|
||||||
auto p = replace_substring(path, "%20", " ");
|
|
||||||
|
|
||||||
// this is a path returned by an editor, so skip it
|
|
||||||
// TODO: find a better way to do this!! NOO!!
|
|
||||||
if(p.find("file:///") != std::string::npos)
|
|
||||||
return p.substr(7, p.length());
|
|
||||||
else
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void prism::set_domain_path(const prism::domain domain, const prism::path path) {
|
|
||||||
NSBundle* bundle = [NSBundle mainBundle];
|
|
||||||
NSString* resourceFolderPath = [bundle resourcePath];
|
|
||||||
|
|
||||||
std::string s = std::string(path);
|
|
||||||
s = replace_substring(s, "{resource_dir}", [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding]);
|
|
||||||
|
|
||||||
// basically, if we pass a relative path this will convert it to an absolute one, making get_relative_path functional.
|
|
||||||
NSURL * bundleURL = [[bundle bundleURL] URLByDeletingLastPathComponent];
|
|
||||||
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%s", s.c_str()] relativeToURL:bundleURL];
|
|
||||||
|
|
||||||
domain_data[static_cast<int>(domain)] = clean_path([[[url absoluteURL] absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]);
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::path prism::get_writeable_directory() {
|
|
||||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
||||||
NSString* resourceFolderPath = paths[0];
|
|
||||||
|
|
||||||
return [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
}
|
|
|
@ -1,634 +0,0 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#include <GameController/GameController.h>
|
|
||||||
#include <mach/mach_time.h>
|
|
||||||
#include <gfx_metal.hpp>
|
|
||||||
#include <engine.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <file.hpp>
|
|
||||||
#include <string_utils.hpp>
|
|
||||||
|
|
||||||
#include <@APP_INCLUDE@>
|
|
||||||
|
|
||||||
uint64_t last_time = 0;
|
|
||||||
bool is_qutting = false;
|
|
||||||
|
|
||||||
static std::map<InputButton, int> inputToKeyCode = { {
|
|
||||||
{InputButton::C, 8},
|
|
||||||
{InputButton::V, 9},
|
|
||||||
{InputButton::X, 7},
|
|
||||||
{InputButton::Q, 12},
|
|
||||||
{InputButton::Y, 16},
|
|
||||||
{InputButton::Z, 6},
|
|
||||||
{InputButton::Backspace, 51},
|
|
||||||
{InputButton::Enter, 36},
|
|
||||||
{InputButton::Space, 49},
|
|
||||||
{InputButton::Shift, 10},
|
|
||||||
{InputButton::A, 0},
|
|
||||||
{InputButton::W, 13},
|
|
||||||
{InputButton::S, 1},
|
|
||||||
{InputButton::D, 2},
|
|
||||||
{InputButton::Escape, 53},
|
|
||||||
{InputButton::Tab, 48},
|
|
||||||
{InputButton::LeftArrow, 123},
|
|
||||||
{InputButton::RightArrow, 124}
|
|
||||||
}};
|
|
||||||
|
|
||||||
struct NativeWindow;
|
|
||||||
|
|
||||||
const char* platform::get_name() {
|
|
||||||
return "macOS";
|
|
||||||
}
|
|
||||||
|
|
||||||
int platform::get_keycode(InputButton key) {
|
|
||||||
if(inputToKeyCode.count(key))
|
|
||||||
return inputToKeyCode[key];
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
GFX* interface = nullptr;
|
|
||||||
|
|
||||||
@APP_CLASS@* app = nullptr;
|
|
||||||
|
|
||||||
float scrollX = 0.0f, scrollY = 0.0f;
|
|
||||||
|
|
||||||
std::array<bool, 8> inputKeys;
|
|
||||||
|
|
||||||
float rightX = 0.0f, rightY = 0.0f;
|
|
||||||
float leftX = 0.0f, leftY = 0.0f;
|
|
||||||
|
|
||||||
@interface GameView : NSObject<NSWindowDelegate>
|
|
||||||
|
|
||||||
@property NativeWindow *native;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
struct NativeWindow {
|
|
||||||
int index = 0;
|
|
||||||
NSWindow* window;
|
|
||||||
GameView* delegate;
|
|
||||||
CAMetalLayer* layer;
|
|
||||||
bool willCaptureMouse = false;
|
|
||||||
|
|
||||||
int currentWidth = 0, currentHeight = 0;
|
|
||||||
int timeout = 0;
|
|
||||||
|
|
||||||
NSPoint currentMousePos;
|
|
||||||
bool showingCursor = true;
|
|
||||||
bool inFocus = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<NativeWindow*> windows;
|
|
||||||
|
|
||||||
NativeWindow* get_window(const int index) {
|
|
||||||
for(auto& window : windows) {
|
|
||||||
if(window->index == index)
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation GameView
|
|
||||||
|
|
||||||
- (void)gameQuit {
|
|
||||||
engine->prepare_quit();
|
|
||||||
}
|
|
||||||
- (void)gameFocus {
|
|
||||||
if(![self native]->showingCursor)
|
|
||||||
[NSCursor hide];
|
|
||||||
|
|
||||||
[self native]->inFocus = true;
|
|
||||||
}
|
|
||||||
- (void)gameLostFocus {
|
|
||||||
if(![self native]->showingCursor)
|
|
||||||
[NSCursor unhide];
|
|
||||||
|
|
||||||
[self native]->inFocus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double NANOSECONDS_TO_MILLISECONDS = 1.0 / 1000000000.0;
|
|
||||||
|
|
||||||
- (void)update {
|
|
||||||
const bool is_main_window = [self native]->index == 0;
|
|
||||||
|
|
||||||
if(is_main_window) {
|
|
||||||
if([self native]->willCaptureMouse && [self native]->timeout > 5 && [self native]->inFocus) {
|
|
||||||
NSPoint point;
|
|
||||||
point.x = [self native]->window.frame.origin.x + ([self native]->currentWidth / 2);
|
|
||||||
point.y = [NSScreen mainScreen].frame.size.height - ([self native]->window.frame.origin.y + ([self native]->currentHeight / 2));
|
|
||||||
|
|
||||||
CGWarpMouseCursorPosition(point);
|
|
||||||
CGAssociateMouseAndMouseCursorPosition(true);
|
|
||||||
|
|
||||||
[self native]->currentMousePos.x = [self native]->currentWidth / 2;
|
|
||||||
[self native]->currentMousePos.y = [self native]->currentHeight / 2;
|
|
||||||
|
|
||||||
[self native]->timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self native]->timeout++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)render {
|
|
||||||
engine->render([self native]->index);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification *)notification {
|
|
||||||
[self native]->currentWidth = [self native]->window.contentView.frame.size.width;
|
|
||||||
[self native]->currentHeight = [self native]->window.contentView.frame.size.height;
|
|
||||||
|
|
||||||
NSRect bounds = [[self native]->layer bounds];
|
|
||||||
bounds = [[self native]->window convertRectToBacking:bounds];
|
|
||||||
|
|
||||||
[self native]->layer.drawableSize = NSSizeToCGSize(bounds.size);;
|
|
||||||
|
|
||||||
engine->resize([self native]->index, {static_cast<uint32_t>([self native]->currentWidth), static_cast<uint32_t>([self native]->currentHeight)});
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)windowWillClose:(NSNotification *)notification {
|
|
||||||
if([self native]->index == 0)
|
|
||||||
is_qutting = app->should_quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) controllerConnected {
|
|
||||||
GCController* controller = [GCController controllers][0];
|
|
||||||
[[controller extendedGamepad] setValueChangedHandler:^(GCExtendedGamepad * _Nonnull gamepad, GCControllerElement * _Nonnull element) {
|
|
||||||
const auto& handle_element = [element](int index, GCControllerElement* e) {
|
|
||||||
if(element == e)
|
|
||||||
inputKeys[index] = [(GCControllerButtonInput*)e value] == 1.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
handle_element(0, [[controller extendedGamepad] buttonA]);
|
|
||||||
handle_element(1, [[controller extendedGamepad] buttonB]);
|
|
||||||
handle_element(2, [[controller extendedGamepad] buttonX]);
|
|
||||||
handle_element(3, [[controller extendedGamepad] buttonY]);
|
|
||||||
|
|
||||||
if(element == [[controller extendedGamepad] dpad]) {
|
|
||||||
inputKeys[4] = [[[[controller extendedGamepad] dpad] up] value] == 1.0f;
|
|
||||||
inputKeys[5] = [[[[controller extendedGamepad] dpad] down] value] == 1.0f;
|
|
||||||
inputKeys[6] = [[[[controller extendedGamepad] dpad] left] value] == 1.0f;
|
|
||||||
inputKeys[7] = [[[[controller extendedGamepad] dpad] right] value] == 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element == [[controller extendedGamepad] leftThumbstick]) {
|
|
||||||
leftX = [[[[controller extendedGamepad] leftThumbstick] xAxis] value];
|
|
||||||
leftY = [[[[controller extendedGamepad] leftThumbstick] yAxis] value];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element == [[controller extendedGamepad] rightThumbstick]) {
|
|
||||||
rightX = [[[[controller extendedGamepad] rightThumbstick] xAxis] value];
|
|
||||||
rightY = [[[[controller extendedGamepad] rightThumbstick] yAxis] value];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
std::map<int, bool> pressed;
|
|
||||||
NSString* currentCharString = nil;
|
|
||||||
|
|
||||||
bool platform::supports_feature(const PlatformFeature feature) {
|
|
||||||
switch(feature) {
|
|
||||||
case PlatformFeature::Windowing:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool platform::get_key_down(const InputButton key) {
|
|
||||||
if(key == InputButton::ButtonA)
|
|
||||||
return inputKeys[0];
|
|
||||||
|
|
||||||
if(key == InputButton::ButtonB)
|
|
||||||
return inputKeys[1];
|
|
||||||
|
|
||||||
if(key == InputButton::ButtonX)
|
|
||||||
return inputKeys[2];
|
|
||||||
|
|
||||||
if(key == InputButton::ButtonY)
|
|
||||||
return inputKeys[3];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadUp)
|
|
||||||
return inputKeys[4];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadDown)
|
|
||||||
return inputKeys[5];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadLeft)
|
|
||||||
return inputKeys[6];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadRight)
|
|
||||||
return inputKeys[7];
|
|
||||||
|
|
||||||
if(inputToKeyCode.count(key))
|
|
||||||
return pressed[inputToKeyCode[key]];
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* platform::translate_keycode(const unsigned int keycode) {
|
|
||||||
return const_cast<char*>([currentCharString UTF8String]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string clean_path(const std::string_view path) {
|
|
||||||
auto p = replace_substring(path, "%20", " ");
|
|
||||||
|
|
||||||
// this is a path returned by an editor, so skip it
|
|
||||||
// TODO: find a better way to do this!! NOO!!
|
|
||||||
if(p.find("file:///") != std::string::npos)
|
|
||||||
return p.substr(7, p.length());
|
|
||||||
else
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::open_dialog(const bool existing, std::function<void(std::string)> returnFunction, bool openDirectory) {
|
|
||||||
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
|
|
||||||
|
|
||||||
[openDlg setCanChooseFiles:YES];
|
|
||||||
|
|
||||||
[openDlg setAllowsMultipleSelection:NO];
|
|
||||||
|
|
||||||
[openDlg setCanChooseDirectories:openDirectory];
|
|
||||||
|
|
||||||
[openDlg setCanChooseFiles:!openDirectory];
|
|
||||||
|
|
||||||
if([openDlg runModal] == NSModalResponseOK)
|
|
||||||
returnFunction(clean_path([openDlg.URLs[0].absoluteString UTF8String]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::save_dialog(std::function<void(std::string)> returnFunction) {
|
|
||||||
NSSavePanel* openDlg = [NSSavePanel savePanel];
|
|
||||||
|
|
||||||
if ([openDlg runModal] == NSModalResponseOK)
|
|
||||||
returnFunction(clean_path([openDlg.URL.absoluteString UTF8String]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::capture_mouse(const bool capture) {
|
|
||||||
windows[0]->willCaptureMouse = capture;
|
|
||||||
|
|
||||||
if(windows[0]->showingCursor && capture) {
|
|
||||||
[NSCursor hide];
|
|
||||||
windows[0]->showingCursor = false;
|
|
||||||
} else if(!windows[0]->showingCursor && !capture) {
|
|
||||||
[NSCursor unhide];
|
|
||||||
windows[0]->showingCursor = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float platform::get_window_dpi(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
return [window->window backingScaleFactor];
|
|
||||||
}
|
|
||||||
|
|
||||||
float platform::get_monitor_dpi() {
|
|
||||||
return [[NSScreen mainScreen] backingScaleFactor];
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect toTopLeftSpace(NSRect frame) {
|
|
||||||
frame.origin.y = NSMaxY([[NSScreen mainScreen] frame]) - NSMaxY(frame);
|
|
||||||
return NSRectToCGRect(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Rectangle platform::get_monitor_resolution() {
|
|
||||||
auto frame = toTopLeftSpace([[NSScreen mainScreen] frame]);
|
|
||||||
|
|
||||||
return {static_cast<int32_t>(frame.origin.x), static_cast<int32_t>(frame.origin.y), static_cast<uint32_t>(frame.size.width), static_cast<uint32_t>(frame.size.height)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Rectangle platform::get_monitor_work_area() {
|
|
||||||
auto frame = toTopLeftSpace([[NSScreen mainScreen] visibleFrame]);
|
|
||||||
|
|
||||||
return {static_cast<int32_t>(frame.origin.x), static_cast<int32_t>(frame.origin.y), static_cast<uint32_t>(frame.size.width), static_cast<uint32_t>(frame.size.height)};
|
|
||||||
}
|
|
||||||
|
|
||||||
NSPoint get_fixed_cursor_point(NSPoint point) {
|
|
||||||
return {point.x, std::max(windows[0]->currentHeight - point.y, 0.0)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Offset platform::get_cursor_position() {
|
|
||||||
return {static_cast<int32_t>(windows[0]->currentMousePos.x), static_cast<int32_t>(windows[0]->currentMousePos.y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Offset platform::get_screen_cursor_position() {
|
|
||||||
return {static_cast<int32_t>([NSEvent mouseLocation].x), static_cast<int32_t>([[NSScreen mainScreen] frame].size.height - [NSEvent mouseLocation].y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> platform::get_wheel_delta() {
|
|
||||||
return {scrollX, scrollY};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> platform::get_left_stick_position() {
|
|
||||||
return {leftX, leftY};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> platform::get_right_stick_position() {
|
|
||||||
return {rightX, rightY};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Extent platform::get_window_size(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
return {static_cast<uint32_t>(window->currentWidth), static_cast<uint32_t>(window->currentHeight)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Extent platform::get_window_drawable_size(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
return {static_cast<uint32_t>(window->currentWidth * window->window.backingScaleFactor), static_cast<uint32_t>(window->currentHeight * window->window.backingScaleFactor)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Offset platform::get_window_position(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
auto frame = toTopLeftSpace([window->window contentRectForFrameRect:[window->window frame]]);
|
|
||||||
|
|
||||||
return {static_cast<int32_t>(frame.origin.x), static_cast<int32_t>(frame.origin.y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool platform::is_window_focused(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
return [window->window isKeyWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_focused(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
[window->window makeKeyWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool platform::get_mouse_button_down(const int button) {
|
|
||||||
return (button + 1) & [NSEvent pressedMouseButtons];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_position(const int index, const prism::Offset offset) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
NSPoint p;
|
|
||||||
p.x = offset.x;
|
|
||||||
p.y = [[NSScreen mainScreen] frame].size.height - offset.y;
|
|
||||||
|
|
||||||
[window->window setFrameTopLeftPoint:p];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_size(const int index, const prism::Extent extent) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
NSSize size;
|
|
||||||
size.width = extent.width;
|
|
||||||
size.height = extent.height;
|
|
||||||
|
|
||||||
[window->window setContentSize:size];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_title(const int index, const std::string_view title) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
[window->window setTitle:[NSString stringWithUTF8String:title.data()]];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::mute_output() {}
|
|
||||||
void platform::unmute_output() {}
|
|
||||||
|
|
||||||
PlatformTheme platform::get_theme() {
|
|
||||||
auto str = [[[NSApplication sharedApplication] effectiveAppearance] name];
|
|
||||||
|
|
||||||
if(str == NSAppearanceNameAqua)
|
|
||||||
return PlatformTheme::Light;
|
|
||||||
else if(str == NSAppearanceNameDarkAqua)
|
|
||||||
return PlatformTheme::Dark;
|
|
||||||
|
|
||||||
return PlatformTheme::Light;
|
|
||||||
}
|
|
||||||
|
|
||||||
int platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) {
|
|
||||||
NativeWindow* native = new NativeWindow();
|
|
||||||
native->index = windows.size();
|
|
||||||
GameView* del = [[GameView alloc] init];
|
|
||||||
native->delegate = del;
|
|
||||||
windows.push_back(native);
|
|
||||||
|
|
||||||
NSRect nrect = NSMakeRect(rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height);
|
|
||||||
|
|
||||||
NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled
|
|
||||||
| NSWindowStyleMaskClosable
|
|
||||||
| NSWindowStyleMaskMiniaturizable;
|
|
||||||
|
|
||||||
if(flags == WindowFlags::Resizable)
|
|
||||||
windowStyle |= NSWindowStyleMaskResizable;
|
|
||||||
else if(flags == WindowFlags::Borderless)
|
|
||||||
windowStyle = NSWindowStyleMaskBorderless;
|
|
||||||
|
|
||||||
native->window = [[NSWindow alloc]
|
|
||||||
initWithContentRect: nrect
|
|
||||||
styleMask:windowStyle
|
|
||||||
backing: NSBackingStoreBuffered
|
|
||||||
defer: NO];
|
|
||||||
|
|
||||||
native->currentWidth = rect.extent.width;
|
|
||||||
native->currentHeight = rect.extent.height;
|
|
||||||
|
|
||||||
native->layer = [CAMetalLayer layer];
|
|
||||||
|
|
||||||
NSView* view = [[NSView alloc] init];
|
|
||||||
view.wantsLayer = YES;
|
|
||||||
view.layer = native->layer;
|
|
||||||
|
|
||||||
native->layer.contentsScale = [native->window backingScaleFactor];
|
|
||||||
|
|
||||||
engine->add_window(view.layer, native->index, rect.extent);
|
|
||||||
|
|
||||||
[native->window setContentView:view];
|
|
||||||
|
|
||||||
if(native->index == 0)
|
|
||||||
app->initialize_render();
|
|
||||||
|
|
||||||
[native->window setTitle:[NSString stringWithUTF8String:title.data()]];
|
|
||||||
|
|
||||||
[del setNative:native];
|
|
||||||
|
|
||||||
[native->window setDelegate:del];
|
|
||||||
[native->window orderFrontRegardless];
|
|
||||||
|
|
||||||
if(native->index == 0) {
|
|
||||||
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(gameQuit)
|
|
||||||
name:NSApplicationWillTerminateNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(gameFocus)
|
|
||||||
name:NSApplicationDidBecomeActiveNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(gameLostFocus)
|
|
||||||
name:NSApplicationDidResignActiveNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(controllerConnected)
|
|
||||||
name:GCControllerDidConnectNotification
|
|
||||||
object:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
return native->index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::close_window(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
engine->remove_window(window->index);
|
|
||||||
|
|
||||||
[window->window close];
|
|
||||||
|
|
||||||
utility::erase(windows, window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::force_quit() {
|
|
||||||
[NSApp terminate:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
NSApp = [NSApplication sharedApplication];
|
|
||||||
|
|
||||||
engine = new prism::engine(argc, argv);
|
|
||||||
|
|
||||||
app = new @APP_CLASS@();
|
|
||||||
engine->set_app(app);
|
|
||||||
|
|
||||||
GFXCreateInfo createInfo = {};
|
|
||||||
createInfo.api_validation_enabled = true;
|
|
||||||
|
|
||||||
interface = new GFXMetal();
|
|
||||||
if(interface->initialize(createInfo)) {
|
|
||||||
engine->set_gfx(interface);
|
|
||||||
} else {
|
|
||||||
NSLog(@"Failed to create Metal context!");
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
app_main(engine);
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent *event) {
|
|
||||||
pressed[event.keyCode] = true;
|
|
||||||
currentCharString = event.characters;
|
|
||||||
|
|
||||||
engine->process_key_down(event.keyCode);
|
|
||||||
|
|
||||||
return (NSEvent*)nil;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp handler:^(NSEvent *event) {
|
|
||||||
pressed[event.keyCode] = false;
|
|
||||||
|
|
||||||
engine->process_key_up(event.keyCode);
|
|
||||||
|
|
||||||
return (NSEvent*)nil;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved handler:^(NSEvent *event) {
|
|
||||||
windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^(NSEvent *event) {
|
|
||||||
auto point = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
engine->process_mouse_down(0, {static_cast<int32_t>(point.x), static_cast<int32_t>(point.y)});
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDown handler:^(NSEvent *event) {
|
|
||||||
auto point = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
engine->process_mouse_down(1, {static_cast<int32_t>(point.x), static_cast<int32_t>(point.y)});
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDragged handler:^(NSEvent *event) {
|
|
||||||
windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDragged handler:^(NSEvent *event) {
|
|
||||||
windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel handler:^(NSEvent *event) {
|
|
||||||
double wheel_dx = 0.0;
|
|
||||||
double wheel_dy = 0.0;
|
|
||||||
|
|
||||||
wheel_dx = [event scrollingDeltaX];
|
|
||||||
wheel_dy = [event scrollingDeltaY];
|
|
||||||
if ([event hasPreciseScrollingDeltas])
|
|
||||||
{
|
|
||||||
wheel_dx *= 0.1;
|
|
||||||
wheel_dy *= 0.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollX += wheel_dx * 0.1f;
|
|
||||||
scrollY += wheel_dy * 0.1f;
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
last_time = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
|
|
||||||
|
|
||||||
while (!is_qutting) {
|
|
||||||
@autoreleasepool {
|
|
||||||
NSEvent* event = nullptr;
|
|
||||||
do {
|
|
||||||
event = [NSApp nextEventMatchingMask: NSEventMaskAny
|
|
||||||
untilDate: nil
|
|
||||||
inMode: NSDefaultRunLoopMode
|
|
||||||
dequeue: YES];
|
|
||||||
if(event)
|
|
||||||
[NSApp sendEvent: event];
|
|
||||||
} while(event);
|
|
||||||
|
|
||||||
const uint64_t current = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
|
|
||||||
const uint64_t elapsed = current - last_time;
|
|
||||||
|
|
||||||
if(engine->is_quitting())
|
|
||||||
is_qutting = true;
|
|
||||||
|
|
||||||
for(auto& window : windows) {
|
|
||||||
if(window != nullptr)
|
|
||||||
[window->delegate update];
|
|
||||||
}
|
|
||||||
|
|
||||||
engine->update(elapsed * NANOSECONDS_TO_MILLISECONDS);
|
|
||||||
|
|
||||||
engine->begin_frame(elapsed * NANOSECONDS_TO_MILLISECONDS);
|
|
||||||
|
|
||||||
for(auto& window : windows) {
|
|
||||||
if(window != nullptr)
|
|
||||||
[window->delegate render];
|
|
||||||
}
|
|
||||||
|
|
||||||
engine->end_frame();
|
|
||||||
|
|
||||||
scrollX = 0.0f;
|
|
||||||
scrollY = 0.0f;
|
|
||||||
|
|
||||||
last_time = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app->prepare_quit();
|
|
||||||
|
|
||||||
[NSApp release];
|
|
||||||
[pool release];
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -4,6 +4,9 @@ add_platform(
|
||||||
SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
|
SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
|
||||||
MAIN_FILE
|
MAIN_FILE
|
||||||
main.cpp.in
|
main.cpp.in
|
||||||
|
EXECUTABLE_PROPERTIES
|
||||||
|
MACOSX_BUNDLE ON
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
||||||
LINK_LIBRARIES
|
LINK_LIBRARIES
|
||||||
SDL2::Main
|
SDL2::Main
|
||||||
Core
|
Core
|
||||||
|
|
Reference in a new issue