#include #include #include #import "QuartzCore/QuartzCore.hpp" #import #include #include <@APP_INCLUDE@> @APP_CLASS@* app = nullptr; int maxFPS = 60; std::array inputKeys; float rightX = 0.0f, rightY = 0.0f; float leftX = 0.0f, leftY = 0.0f; @interface GameView : UIView @end @implementation GameView + (Class) layerClass { return [CAMetalLayer class]; } - (void)draw { engine->update(1.0f / (float)maxFPS); engine->begin_frame(1.0f / (float)maxFPS); engine->render((void*)1); engine->end_frame(); } - (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 @interface GameViewController : UIViewController @end float mouse_x = 0.0f, mouse_y = 0.0f; bool mouse_down = false; @interface GameViewController () { GameView* view; } @end @implementation GameViewController - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView: self.view]; mouse_x = touchPoint.x; mouse_y = touchPoint.y; mouse_down = true; engine->process_mouse_down(0, {static_cast(touchPoint.x), static_cast(touchPoint.y)}); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView: self.view]; mouse_x = touchPoint.x; mouse_y = touchPoint.y; mouse_down = false; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView: self.view]; mouse_x = touchPoint.x; mouse_y = touchPoint.y; } int width, height; int drawable_width, drawable_height; CAMetalLayer* layer; - (void)viewDidLoad { [super viewDidLoad]; view = (GameView*)self.view; view.userInteractionEnabled = true; layer = (CAMetalLayer*)view.layer; CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:view selector:@selector(draw)]; displayLink.preferredFramesPerSecond = [UIScreen mainScreen].maximumFramesPerSecond; maxFPS = [UIScreen mainScreen].maximumFramesPerSecond; [displayLink addToRunLoop:NSRunLoop.mainRunLoop forMode:NSDefaultRunLoopMode]; width = [view frame].size.width; height = [view frame].size.height; drawable_width = [view frame].size.width * [view contentScaleFactor]; drawable_height = [view frame].size.height * [view contentScaleFactor]; engine = new prism::engine(0, nullptr); app = new @APP_CLASS@(); engine->set_app(app); GFXCreateInfo createInfo = {}; createInfo.api_validation_enabled = true; GFXMetal* gfx = new GFXMetal(); gfx->initialize(createInfo); engine->set_gfx(gfx); app_main(engine); engine->add_window((void*)CFBridgingRetain([view layer]), (void*)1, {static_cast(width), static_cast(height)}); app->initialize_render(); NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; [nc addObserver:view selector:@selector(controllerConnected) name:GCControllerDidConnectNotification object:nil]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(bool)prefersStatusBarHidden { return YES; } @end void platform::capture_mouse(const bool capture) { } // TODO: unimplemented PlatformTheme platform::get_theme() { return PlatformTheme::Light; } void platform::begin_text_input() { // TODO: stub } void platform::end_text_input() { // TODO: stub } void* platform::create_native_surface(platform::window_ptr index, void* instance) { /*VkMetalSurfaceCreateInfoEXT surfaceInfo = {}; surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; surfaceInfo.pNext = 0; surfaceInfo.flags = 0; surfaceInfo.pLayer = layer; VkSurfaceKHR surface; vkCreateMetalSurfaceEXT((VkInstance)instance, &surfaceInfo, nullptr, &surface); return surface;*/ return nullptr; } unsigned int platform::initialize_metal_layer(platform::window_ptr index, void* device) { layer.device = (__bridge id)device; layer.allowsNextDrawableTimeout = true; return (unsigned int)layer.pixelFormat; } void* platform::get_next_drawable(window_ptr window) { return (__bridge CA::MetalDrawable*)[layer nextDrawable]; } bool platform::is_main_window(platform::window_ptr index) { return true; } std::vector platform::get_native_surface_extension() { //return {VK_EXT_METAL_SURFACE_EXTENSION_NAME}; return {}; } void platform::show_window(const platform::window_ptr index) { } bool platform::supports_feature(const PlatformFeature feature) { return false; } prism::Offset platform::get_cursor_position() { return {static_cast(mouse_x), static_cast(mouse_y)}; } std::tuple platform::get_right_stick_position() { return {rightX, rightY}; } std::tuple platform::get_left_stick_position() { return {leftX, leftY}; } bool platform::get_key_down(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]; return false; } platform::window_ptr platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) { return (void*)1; } void platform::set_window_title(const platform::window_ptr index, const std::string_view title) { } bool platform::is_window_focused(const platform::window_ptr index) { } void platform::set_window_focused(const platform::window_ptr index) { } prism::Extent platform::get_window_size(const platform::window_ptr index) { return {static_cast(width), static_cast(height)}; } prism::Extent platform::get_window_drawable_size(const platform::window_ptr index) { return {static_cast(drawable_width), static_cast(drawable_height)}; } prism::Offset platform::get_window_position(const platform::window_ptr index) { } void platform::set_window_size(const platform::window_ptr index, const prism::Extent extent) { } void platform::set_window_position(const platform::window_ptr index, const prism::Offset offset) { } void platform::close_window(const platform::window_ptr index) { } int platform::get_keycode(const InputButton button) { } prism::Rectangle platform::get_monitor_resolution() { } prism::Rectangle platform::get_monitor_work_area() { } prism::Offset platform::get_screen_cursor_position() { } bool platform::get_mouse_button_down(const int index) { return mouse_down; } float platform::get_monitor_dpi() { return 2.0f; } std::tuple platform::get_wheel_delta() { } const char* platform::get_name() { return "iOS"; }