diff options
Diffstat (limited to 'platform/osx')
-rw-r--r-- | platform/osx/SCsub | 2 | ||||
-rw-r--r-- | platform/osx/context_gl_osx.mm | 161 | ||||
-rw-r--r-- | platform/osx/detect.py | 16 | ||||
-rw-r--r-- | platform/osx/display_server_osx.h | 18 | ||||
-rw-r--r-- | platform/osx/display_server_osx.mm | 450 | ||||
-rw-r--r-- | platform/osx/export/export_plugin.cpp | 82 | ||||
-rw-r--r-- | platform/osx/gl_manager_osx.h (renamed from platform/osx/context_gl_osx.h) | 74 | ||||
-rw-r--r-- | platform/osx/gl_manager_osx.mm | 233 | ||||
-rw-r--r-- | platform/osx/joypad_osx.cpp | 8 | ||||
-rw-r--r-- | platform/osx/joypad_osx.h | 1 | ||||
-rw-r--r-- | platform/osx/os_osx.h | 5 | ||||
-rw-r--r-- | platform/osx/os_osx.mm | 123 | ||||
-rw-r--r-- | platform/osx/platform_config.h | 1 |
13 files changed, 738 insertions, 436 deletions
diff --git a/platform/osx/SCsub b/platform/osx/SCsub index 46c13d8550..8ba106d1c2 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -13,7 +13,7 @@ files = [ "dir_access_osx.mm", "joypad_osx.cpp", "vulkan_context_osx.mm", - "context_gl_osx.mm", + "gl_manager_osx.mm", ] prog = env.add_program("#bin/godot", files) diff --git a/platform/osx/context_gl_osx.mm b/platform/osx/context_gl_osx.mm deleted file mode 100644 index 88db1a296e..0000000000 --- a/platform/osx/context_gl_osx.mm +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************/ -/* context_gl_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "context_gl_osx.h" - -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -void ContextGL_OSX::release_current() { - [NSOpenGLContext clearCurrentContext]; -} - -void ContextGL_OSX::make_current() { - [context makeCurrentContext]; -} - -void ContextGL_OSX::update() { - [context update]; -} - -void ContextGL_OSX::set_opacity(GLint p_opacity) { - [context setValues:&p_opacity forParameter:NSOpenGLCPSurfaceOpacity]; -} - -int ContextGL_OSX::get_window_width() { - return OS::get_singleton()->get_video_mode().width; -} - -int ContextGL_OSX::get_window_height() { - return OS::get_singleton()->get_video_mode().height; -} - -void ContextGL_OSX::swap_buffers() { - [context flushBuffer]; -} - -void ContextGL_OSX::set_use_vsync(bool p_use) { - CGLContextObj ctx = CGLGetCurrentContext(); - if (ctx) { - GLint swapInterval = p_use ? 1 : 0; - CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - use_vsync = p_use; - } -} - -bool ContextGL_OSX::is_using_vsync() const { - return use_vsync; -} - -Error ContextGL_OSX::initialize() { - framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - ERR_FAIL_COND_V(!framework, ERR_CANT_CREATE); - - unsigned int attributeCount = 0; - - // OS X needs non-zero color size, so set reasonable values - int colorBits = 32; - - // Fail if a robustness strategy was requested - -#define ADD_ATTR(x) \ - { attributes[attributeCount++] = x; } -#define ADD_ATTR2(x, y) \ - { \ - ADD_ATTR(x); \ - ADD_ATTR(y); \ - } - - // Arbitrary array size here - NSOpenGLPixelFormatAttribute attributes[40]; - - ADD_ATTR(NSOpenGLPFADoubleBuffer); - ADD_ATTR(NSOpenGLPFAClosestPolicy); - - if (!opengl_3_context) { - ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy); - } else { - //we now need OpenGL 3 or better, maybe even change this to 3_3Core ? - ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); - } - - ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); - - /* - if (fbconfig->alphaBits > 0) - ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); -*/ - - ADD_ATTR2(NSOpenGLPFADepthSize, 24); - - ADD_ATTR2(NSOpenGLPFAStencilSize, 8); - - /* - if (fbconfig->stereo) - ADD_ATTR(NSOpenGLPFAStereo); -*/ - - /* - if (fbconfig->samples > 0) { - ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); - ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); - } -*/ - - // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB - // framebuffer, so there's no need (and no way) to request it - - ADD_ATTR(0); - -#undef ADD_ATTR -#undef ADD_ATTR2 - - pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - ERR_FAIL_COND_V(pixelFormat == nil, ERR_CANT_CREATE); - - context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; - - ERR_FAIL_COND_V(context == nil, ERR_CANT_CREATE); - - [context setView:window_view]; - - [context makeCurrentContext]; - - return OK; -} - -ContextGL_OSX::ContextGL_OSX(id p_view, bool p_opengl_3_context) { - opengl_3_context = p_opengl_3_context; - window_view = p_view; - use_vsync = false; -} - -ContextGL_OSX::~ContextGL_OSX() {} - -#endif diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 6b25daf05d..6bd79c7d4f 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -31,6 +31,7 @@ def get_opts(): BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False), BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), + BoolVariable("use_coverage", "Use instrumentation codes in the binary (e.g. for code coverage)", False), ] @@ -57,13 +58,11 @@ def configure(env): env.Prepend(CCFLAGS=["-O2"]) elif env["optimize"] == "size": # optimize for size env.Prepend(CCFLAGS=["-Os"]) - env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) if env["debug_symbols"]: env.Prepend(CCFLAGS=["-g2"]) elif env["target"] == "debug": env.Prepend(CCFLAGS=["-g3"]) - env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"]) ## Architecture @@ -96,7 +95,6 @@ def configure(env): env["AR"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar" env["RANLIB"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib" env["AS"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as" - env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define else: env["CC"] = "clang" env["CXX"] = "clang++" @@ -124,7 +122,6 @@ def configure(env): env["AR"] = basecmd + "ar" env["RANLIB"] = basecmd + "ranlib" env["AS"] = basecmd + "as" - env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]: env.extra_suffix += "s" @@ -146,6 +143,10 @@ def configure(env): env.Append(CCFLAGS=["-fsanitize=thread"]) env.Append(LINKFLAGS=["-fsanitize=thread"]) + if env["use_coverage"]: + env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"]) + env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"]) + ## Dependencies if env["builtin_libtheora"]: @@ -182,10 +183,13 @@ def configure(env): ) env.Append(LIBS=["pthread", "z"]) + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"]) + env.Append(CCFLAGS=["-Wno-deprecated-declarations"]) # Disable deprecation warnings + env.Append(LINKFLAGS=["-framework", "OpenGL"]) + if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"]) if not env["use_volk"]: env.Append(LINKFLAGS=["-L$VULKAN_SDK_PATH/MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/", "-lMoltenVK"]) - - # env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED']) diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 06b14f1c14..c45b470078 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -36,9 +36,8 @@ #include "core/input/input.h" #include "servers/display_server.h" -#if defined(OPENGL_ENABLED) -#include "context_gl_osx.h" -//TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) +#include "gl_manager_osx.h" #endif #if defined(VULKAN_ENABLED) @@ -64,12 +63,12 @@ public: NSMenu *_get_dock_menu() const; void _menu_callback(id p_sender); -#if defined(OPENGL_ENABLED) - ContextGL_OSX *context_gles2; +#if defined(GLES3_ENABLED) + GLManager_OSX *gl_manager = nullptr; #endif #if defined(VULKAN_ENABLED) - VulkanContextOSX *context_vulkan; - RenderingDeviceVulkan *rendering_device_vulkan; + VulkanContextOSX *context_vulkan = nullptr; + RenderingDeviceVulkan *rendering_device_vulkan = nullptr; #endif const NSMenu *_get_menu_root(const String &p_menu_root) const; @@ -109,9 +108,6 @@ public: Vector<Vector2> mpath; -#if defined(OPENGL_ENABLED) - ContextGL_OSX *context_gles2 = nullptr; -#endif Point2i mouse_pos; Size2i min_size; @@ -287,6 +283,7 @@ public: virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; @@ -305,6 +302,7 @@ public: virtual void keyboard_set_current_layout(int p_index) override; virtual String keyboard_get_layout_language(int p_index) const override; virtual String keyboard_get_layout_name(int p_index) const override; + virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; virtual void process_events() override; virtual void force_process_and_drop_events() override; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index f037d75fbd..03301af0af 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -45,8 +45,8 @@ #include <IOKit/hid/IOHIDKeys.h> #include <IOKit/hid/IOHIDLib.h> -#if defined(OPENGL_ENABLED) -//TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" #import <AppKit/NSOpenGLView.h> #endif @@ -166,9 +166,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left. } -#if defined(OPENGL_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (DS_OSX->rendering_driver == "opengl3") { + DS_OSX->gl_manager->window_destroy(window_id); } #endif #ifdef VULKAN_ENABLED @@ -271,9 +271,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { layer.contentsScale = scale; } -#if defined(OPENGL_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (DS_OSX->rendering_driver == "opengl3") { + DS_OSX->gl_manager->window_resize(window_id, wd.size.width, wd.size.height); } #endif #if defined(VULKAN_ENABLED) @@ -289,14 +289,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { Callable::CallError ce; wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); } - - if (OS_OSX::get_singleton()->get_main_loop()) { - Main::force_redraw(); - //Event retrieval blocks until resize is over. Call Main::iteration() directly. - if (!Main::is_iterating()) { //avoid cyclic loop - Main::iteration(); - } - } } - (void)windowDidMove:(NSNotification *)notification { @@ -377,7 +369,12 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { /* GodotContentView */ /*************************************************************************/ +#if defined(GLES3_ENABLED) +@interface GodotContentView : NSOpenGLView <NSTextInputClient> { +#else @interface GodotContentView : NSView <NSTextInputClient> { +#endif + DisplayServerOSX::WindowID window_id; NSTrackingArea *trackingArea; NSMutableAttributedString *markedText; @@ -405,12 +402,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (CALayer *)makeBackingLayer { -#if defined(OPENGL_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - CALayer *layer = [[NSOpenGLLayer class] layer]; - return layer; - } -#endif #if defined(VULKAN_ENABLED) if (DS_OSX->rendering_driver == "vulkan") { CALayer *layer = [[CAMetalLayer class] layer]; @@ -421,10 +412,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)updateLayer { -#if defined(OPENGL_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - [super updateLayer]; - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (DS_OSX->rendering_driver == "opengl3") { + DS_OSX->gl_manager->window_update(window_id); } #endif #if defined(VULKAN_ENABLED) @@ -930,146 +920,155 @@ static bool isNumpadKey(unsigned int key) { return false; } +// Keyboard symbol translation table +static const Key _osx_to_godot_table[128] = { + /* 00 */ KEY_A, + /* 01 */ KEY_S, + /* 02 */ KEY_D, + /* 03 */ KEY_F, + /* 04 */ KEY_H, + /* 05 */ KEY_G, + /* 06 */ KEY_Z, + /* 07 */ KEY_X, + /* 08 */ KEY_C, + /* 09 */ KEY_V, + /* 0a */ KEY_SECTION, /* ISO Section */ + /* 0b */ KEY_B, + /* 0c */ KEY_Q, + /* 0d */ KEY_W, + /* 0e */ KEY_E, + /* 0f */ KEY_R, + /* 10 */ KEY_Y, + /* 11 */ KEY_T, + /* 12 */ KEY_1, + /* 13 */ KEY_2, + /* 14 */ KEY_3, + /* 15 */ KEY_4, + /* 16 */ KEY_6, + /* 17 */ KEY_5, + /* 18 */ KEY_EQUAL, + /* 19 */ KEY_9, + /* 1a */ KEY_7, + /* 1b */ KEY_MINUS, + /* 1c */ KEY_8, + /* 1d */ KEY_0, + /* 1e */ KEY_BRACERIGHT, + /* 1f */ KEY_O, + /* 20 */ KEY_U, + /* 21 */ KEY_BRACELEFT, + /* 22 */ KEY_I, + /* 23 */ KEY_P, + /* 24 */ KEY_ENTER, + /* 25 */ KEY_L, + /* 26 */ KEY_J, + /* 27 */ KEY_APOSTROPHE, + /* 28 */ KEY_K, + /* 29 */ KEY_SEMICOLON, + /* 2a */ KEY_BACKSLASH, + /* 2b */ KEY_COMMA, + /* 2c */ KEY_SLASH, + /* 2d */ KEY_N, + /* 2e */ KEY_M, + /* 2f */ KEY_PERIOD, + /* 30 */ KEY_TAB, + /* 31 */ KEY_SPACE, + /* 32 */ KEY_QUOTELEFT, + /* 33 */ KEY_BACKSPACE, + /* 34 */ KEY_UNKNOWN, + /* 35 */ KEY_ESCAPE, + /* 36 */ KEY_META, + /* 37 */ KEY_META, + /* 38 */ KEY_SHIFT, + /* 39 */ KEY_CAPSLOCK, + /* 3a */ KEY_ALT, + /* 3b */ KEY_CTRL, + /* 3c */ KEY_SHIFT, + /* 3d */ KEY_ALT, + /* 3e */ KEY_CTRL, + /* 3f */ KEY_UNKNOWN, /* Function */ + /* 40 */ KEY_UNKNOWN, /* F17 */ + /* 41 */ KEY_KP_PERIOD, + /* 42 */ KEY_UNKNOWN, + /* 43 */ KEY_KP_MULTIPLY, + /* 44 */ KEY_UNKNOWN, + /* 45 */ KEY_KP_ADD, + /* 46 */ KEY_UNKNOWN, + /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */ + /* 48 */ KEY_VOLUMEUP, /* VolumeUp */ + /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */ + /* 4a */ KEY_VOLUMEMUTE, /* Mute */ + /* 4b */ KEY_KP_DIVIDE, + /* 4c */ KEY_KP_ENTER, + /* 4d */ KEY_UNKNOWN, + /* 4e */ KEY_KP_SUBTRACT, + /* 4f */ KEY_UNKNOWN, /* F18 */ + /* 50 */ KEY_UNKNOWN, /* F19 */ + /* 51 */ KEY_EQUAL, /* KeypadEqual */ + /* 52 */ KEY_KP_0, + /* 53 */ KEY_KP_1, + /* 54 */ KEY_KP_2, + /* 55 */ KEY_KP_3, + /* 56 */ KEY_KP_4, + /* 57 */ KEY_KP_5, + /* 58 */ KEY_KP_6, + /* 59 */ KEY_KP_7, + /* 5a */ KEY_UNKNOWN, /* F20 */ + /* 5b */ KEY_KP_8, + /* 5c */ KEY_KP_9, + /* 5d */ KEY_YEN, /* JIS Yen */ + /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */ + /* 5f */ KEY_COMMA, /* JIS KeypadComma */ + /* 60 */ KEY_F5, + /* 61 */ KEY_F6, + /* 62 */ KEY_F7, + /* 63 */ KEY_F3, + /* 64 */ KEY_F8, + /* 65 */ KEY_F9, + /* 66 */ KEY_UNKNOWN, /* JIS Eisu */ + /* 67 */ KEY_F11, + /* 68 */ KEY_UNKNOWN, /* JIS Kana */ + /* 69 */ KEY_F13, + /* 6a */ KEY_F16, + /* 6b */ KEY_F14, + /* 6c */ KEY_UNKNOWN, + /* 6d */ KEY_F10, + /* 6e */ KEY_MENU, + /* 6f */ KEY_F12, + /* 70 */ KEY_UNKNOWN, + /* 71 */ KEY_F15, + /* 72 */ KEY_INSERT, /* Really Help... */ + /* 73 */ KEY_HOME, + /* 74 */ KEY_PAGEUP, + /* 75 */ KEY_DELETE, + /* 76 */ KEY_F4, + /* 77 */ KEY_END, + /* 78 */ KEY_F2, + /* 79 */ KEY_PAGEDOWN, + /* 7a */ KEY_F1, + /* 7b */ KEY_LEFT, + /* 7c */ KEY_RIGHT, + /* 7d */ KEY_DOWN, + /* 7e */ KEY_UP, + /* 7f */ KEY_UNKNOWN, +}; + // Translates a OS X keycode to a Godot keycode -// static Key translateKey(unsigned int key) { - // Keyboard symbol translation table - static const Key table[128] = { - /* 00 */ KEY_A, - /* 01 */ KEY_S, - /* 02 */ KEY_D, - /* 03 */ KEY_F, - /* 04 */ KEY_H, - /* 05 */ KEY_G, - /* 06 */ KEY_Z, - /* 07 */ KEY_X, - /* 08 */ KEY_C, - /* 09 */ KEY_V, - /* 0a */ KEY_SECTION, /* ISO Section */ - /* 0b */ KEY_B, - /* 0c */ KEY_Q, - /* 0d */ KEY_W, - /* 0e */ KEY_E, - /* 0f */ KEY_R, - /* 10 */ KEY_Y, - /* 11 */ KEY_T, - /* 12 */ KEY_1, - /* 13 */ KEY_2, - /* 14 */ KEY_3, - /* 15 */ KEY_4, - /* 16 */ KEY_6, - /* 17 */ KEY_5, - /* 18 */ KEY_EQUAL, - /* 19 */ KEY_9, - /* 1a */ KEY_7, - /* 1b */ KEY_MINUS, - /* 1c */ KEY_8, - /* 1d */ KEY_0, - /* 1e */ KEY_BRACERIGHT, - /* 1f */ KEY_O, - /* 20 */ KEY_U, - /* 21 */ KEY_BRACELEFT, - /* 22 */ KEY_I, - /* 23 */ KEY_P, - /* 24 */ KEY_ENTER, - /* 25 */ KEY_L, - /* 26 */ KEY_J, - /* 27 */ KEY_APOSTROPHE, - /* 28 */ KEY_K, - /* 29 */ KEY_SEMICOLON, - /* 2a */ KEY_BACKSLASH, - /* 2b */ KEY_COMMA, - /* 2c */ KEY_SLASH, - /* 2d */ KEY_N, - /* 2e */ KEY_M, - /* 2f */ KEY_PERIOD, - /* 30 */ KEY_TAB, - /* 31 */ KEY_SPACE, - /* 32 */ KEY_QUOTELEFT, - /* 33 */ KEY_BACKSPACE, - /* 34 */ KEY_UNKNOWN, - /* 35 */ KEY_ESCAPE, - /* 36 */ KEY_META, - /* 37 */ KEY_META, - /* 38 */ KEY_SHIFT, - /* 39 */ KEY_CAPSLOCK, - /* 3a */ KEY_ALT, - /* 3b */ KEY_CTRL, - /* 3c */ KEY_SHIFT, - /* 3d */ KEY_ALT, - /* 3e */ KEY_CTRL, - /* 3f */ KEY_UNKNOWN, /* Function */ - /* 40 */ KEY_UNKNOWN, /* F17 */ - /* 41 */ KEY_KP_PERIOD, - /* 42 */ KEY_UNKNOWN, - /* 43 */ KEY_KP_MULTIPLY, - /* 44 */ KEY_UNKNOWN, - /* 45 */ KEY_KP_ADD, - /* 46 */ KEY_UNKNOWN, - /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */ - /* 48 */ KEY_VOLUMEUP, /* VolumeUp */ - /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */ - /* 4a */ KEY_VOLUMEMUTE, /* Mute */ - /* 4b */ KEY_KP_DIVIDE, - /* 4c */ KEY_KP_ENTER, - /* 4d */ KEY_UNKNOWN, - /* 4e */ KEY_KP_SUBTRACT, - /* 4f */ KEY_UNKNOWN, /* F18 */ - /* 50 */ KEY_UNKNOWN, /* F19 */ - /* 51 */ KEY_EQUAL, /* KeypadEqual */ - /* 52 */ KEY_KP_0, - /* 53 */ KEY_KP_1, - /* 54 */ KEY_KP_2, - /* 55 */ KEY_KP_3, - /* 56 */ KEY_KP_4, - /* 57 */ KEY_KP_5, - /* 58 */ KEY_KP_6, - /* 59 */ KEY_KP_7, - /* 5a */ KEY_UNKNOWN, /* F20 */ - /* 5b */ KEY_KP_8, - /* 5c */ KEY_KP_9, - /* 5d */ KEY_YEN, /* JIS Yen */ - /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */ - /* 5f */ KEY_COMMA, /* JIS KeypadComma */ - /* 60 */ KEY_F5, - /* 61 */ KEY_F6, - /* 62 */ KEY_F7, - /* 63 */ KEY_F3, - /* 64 */ KEY_F8, - /* 65 */ KEY_F9, - /* 66 */ KEY_UNKNOWN, /* JIS Eisu */ - /* 67 */ KEY_F11, - /* 68 */ KEY_UNKNOWN, /* JIS Kana */ - /* 69 */ KEY_F13, - /* 6a */ KEY_F16, - /* 6b */ KEY_F14, - /* 6c */ KEY_UNKNOWN, - /* 6d */ KEY_F10, - /* 6e */ KEY_MENU, - /* 6f */ KEY_F12, - /* 70 */ KEY_UNKNOWN, - /* 71 */ KEY_F15, - /* 72 */ KEY_INSERT, /* Really Help... */ - /* 73 */ KEY_HOME, - /* 74 */ KEY_PAGEUP, - /* 75 */ KEY_DELETE, - /* 76 */ KEY_F4, - /* 77 */ KEY_END, - /* 78 */ KEY_F2, - /* 79 */ KEY_PAGEDOWN, - /* 7a */ KEY_F1, - /* 7b */ KEY_LEFT, - /* 7c */ KEY_RIGHT, - /* 7d */ KEY_DOWN, - /* 7e */ KEY_UP, - /* 7f */ KEY_UNKNOWN, - }; - if (key >= 128) { return KEY_UNKNOWN; } - return table[key]; + return _osx_to_godot_table[key]; +} + +// Translates a Godot keycode back to a OSX keycode +static unsigned int unmapKey(Key key) { + for (int i = 0; i <= 126; i++) { + if (_osx_to_godot_table[i] == key) { + return i; + } + } + return 127; } struct _KeyCodeMap { @@ -2577,8 +2576,8 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled //TODO - implement transparency for Vulkan } #endif -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { //TODO - reimplement OpenGLES } #endif @@ -2596,15 +2595,15 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled //TODO - implement transparency for Vulkan } #endif -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { //TODO - reimplement OpenGLES } #endif wd.layered_window = false; } -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { //TODO - reimplement OpenGLES } #endif @@ -3005,7 +3004,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape ERR_FAIL_COND(!image.is_valid()); NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:NULL + initWithBitmapDataPlanes:nullptr pixelsWide:int(texture_size.width) pixelsHigh:int(texture_size.height) bitsPerSample:8 @@ -3200,6 +3199,17 @@ String DisplayServerOSX::keyboard_get_layout_name(int p_index) const { return kbd_layouts[p_index].name; } +Key DisplayServerOSX::keyboard_get_keycode_from_physical(Key p_keycode) const { + if (p_keycode == KEY_PAUSE) { + return p_keycode; + } + + unsigned int modifiers = p_keycode & KEY_MODIFIER_MASK; + unsigned int keycode_no_mod = p_keycode & KEY_CODE_MASK; + unsigned int osx_keycode = unmapKey((Key)keycode_no_mod); + return (Key)(remapKey(osx_keycode, 0) | modifiers); +} + void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) { Ref<InputEvent> ev = p_event; Input::get_singleton()->parse_input_event(ev); @@ -3398,7 +3408,7 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { img = img->duplicate(); img->convert(Image::FORMAT_RGBA8); NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:NULL + initWithBitmapDataPlanes:nullptr pixelsWide:img->get_width() pixelsHigh:img->get_height() bitsPerSample:8 @@ -3435,18 +3445,31 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + gl_manager->swap_buffers(); + } +#endif #if defined(VULKAN_ENABLED) - context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + if (rendering_driver == "vulkan") { + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + } #endif } DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + return (gl_manager->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED); + } +#endif #if defined(VULKAN_ENABLED) - return context_vulkan->get_vsync_mode(p_window); -#else - return DisplayServer::VSYNC_ENABLED; + if (rendering_driver == "vulkan") { + return context_vulkan->get_vsync_mode(p_window); + } #endif + return DisplayServer::VSYNC_ENABLED; } Vector<String> DisplayServerOSX::get_rendering_drivers_func() { @@ -3455,13 +3478,19 @@ Vector<String> DisplayServerOSX::get_rendering_drivers_func() { #if defined(VULKAN_ENABLED) drivers.push_back("vulkan"); #endif -#if defined(OPENGL_ENABLED) - drivers.push_back("opengl_es"); +#if defined(GLES3_ENABLED) + drivers.push_back("opengl3"); #endif return drivers; } +void DisplayServerOSX::gl_window_make_current(DisplayServer::WindowID p_window_id) { +#if defined(GLES3_ENABLED) + gl_manager->window_make_current(p_window_id); +#endif +} + Point2i DisplayServerOSX::ime_get_selection() const { return im_selection; } @@ -3502,7 +3531,7 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { - OS::get_singleton()->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver"); + OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver"); } return ds; } @@ -3559,9 +3588,12 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V } } #endif -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + if (gl_manager) { + Error err = gl_manager->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height); + ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context"); + } } #endif id = window_id_counter++; @@ -3580,9 +3612,9 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V layer.contentsScale = scale; } -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + gl_manager->window_resize(id, wd.size.width, wd.size.height); } #endif #if defined(VULKAN_ENABLED) @@ -3634,15 +3666,15 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { } void DisplayServerOSX::release_rendering_thread() { - //TODO - reimplement OpenGLES } void DisplayServerOSX::make_rendering_thread() { - //TODO - reimplement OpenGLES } void DisplayServerOSX::swap_buffers() { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + gl_manager->swap_buffers(); +#endif } void DisplayServerOSX::console_set_visible(bool p_enabled) { @@ -3730,17 +3762,20 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode [main_menu setSubmenu:apple_menu forItem:menu_item]; //!!!!!!!!!!!!!!!!!!!!!!!!!! - //TODO - do Vulkan and GLES2 support checks, driver selection and fallback + //TODO - do Vulkan and OpenGL support checks, driver selection and fallback rendering_driver = p_rendering_driver; -#ifndef _MSC_VER -#warning Forcing vulkan rendering driver because OpenGL not implemented yet -#endif - rendering_driver = "vulkan"; - -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + GLManager_OSX::ContextType opengl_api_type = GLManager_OSX::GLES_3_0_COMPATIBLE; + gl_manager = memnew(GLManager_OSX(opengl_api_type)); + if (gl_manager->initialize() != OK) { + memdelete(gl_manager); + gl_manager = nullptr; + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize OpenGL"); + return; + } } #endif #if defined(VULKAN_ENABLED) @@ -3767,9 +3802,9 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode } show_window(MAIN_WINDOW_ID); -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + RasterizerGLES3::make_current(); } #endif #if defined(VULKAN_ENABLED) @@ -3800,21 +3835,22 @@ DisplayServerOSX::~DisplayServerOSX() { } //destroy drivers -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + if (gl_manager) { + memdelete(gl_manager); + gl_manager = nullptr; } #endif #if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - if (rendering_device_vulkan) { - rendering_device_vulkan->finalize(); - memdelete(rendering_device_vulkan); - } + if (rendering_device_vulkan) { + rendering_device_vulkan->finalize(); + memdelete(rendering_device_vulkan); + rendering_device_vulkan = nullptr; + } - if (context_vulkan) { - memdelete(context_vulkan); - } + if (context_vulkan) { + memdelete(context_vulkan); + context_vulkan = nullptr; } #endif diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 54a3104482..a88f7bb332 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -95,6 +95,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array())); r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); @@ -324,11 +325,11 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset } /** - If we're running the OSX version of the Godot editor we'll: - - export our application bundle to a temporary folder - - attempt to code sign it - - and then wrap it up in a DMG -**/ + * If we're running the OSX version of the Godot editor we'll: + * - export our application bundle to a temporary folder + * - attempt to code sign it + * - and then wrap it up in a DMG + */ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) { #ifdef OSX_ENABLED @@ -535,6 +536,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = ERR_CANT_CREATE; } + Array helpers = p_preset->get("codesign/entitlements/app_sandbox/helper_executables"); + // Create our folder structure. if (err == OK) { print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); @@ -546,6 +549,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks"); } + if ((err == OK) && helpers.size() > 0) { + print_line("Creating " + tmp_app_path_name + "/Contents/Helpers"); + err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Helpers"); + } + if (err == OK) { print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); @@ -553,7 +561,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p // Now process our template. bool found_binary = false; - int total_size = 0; Vector<String> dylibs_found; while (ret == UNZ_OK && err == OK) { @@ -641,7 +648,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } print_line("ADDING: " + file + " size: " + itos(data.size())); - total_size += data.size(); // Write it into our application bundle. file = tmp_app_path_name.plus_file(file); @@ -688,6 +694,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p bool sign_enabled = p_preset->get("codesign/enable"); String ent_path = p_preset->get("codesign/entitlements/custom_file"); + String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements"); if (sign_enabled && (ent_path == "")) { ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements"); @@ -819,10 +826,43 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } else { err = ERR_CANT_CREATE; } + + if ((err == OK) && helpers.size() > 0) { + ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE); + if (ent_f) { + ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); + ent_f->store_line("<plist version=\"1.0\">"); + ent_f->store_line("<dict>"); + ent_f->store_line("<key>com.apple.security.app-sandbox</key>"); + ent_f->store_line("<true/>"); + ent_f->store_line("<key>com.apple.security.inherit</key>"); + ent_f->store_line("<true/>"); + ent_f->store_line("</dict>"); + ent_f->store_line("</plist>"); + + ent_f->close(); + memdelete(ent_f); + } else { + err = ERR_CANT_CREATE; + } + } + } + + if ((err == OK) && helpers.size() > 0) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + for (int i = 0; i < helpers.size(); i++) { + String hlp_path = helpers[i]; + err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file()); + if (err == OK && sign_enabled) { + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path); + } + FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); + } } if (err == OK) { - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < shared_objects.size(); i++) { String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); if (da->dir_exists(src_path)) { @@ -842,7 +882,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path); } } - memdelete(da); } if (sign_enabled) { @@ -903,6 +942,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = _notarize(p_preset, p_path); } + // Clean up temporary entitlements files. + DirAccess::remove_file_or_error(hlp_ent_path); + // Clean up temporary .app dir. tmp_app_dir->change_dir(tmp_app_path_name); tmp_app_dir->erase_contents_recursive(); @@ -916,7 +958,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { String dir = p_root_path.plus_file(p_folder); - DirAccess *da = DirAccess::open(dir); + DirAccessRef da = DirAccess::open(dir); da->list_dir_begin(); String f; while ((f = da->get_next()) != "") { @@ -967,7 +1009,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String } else if (da->current_is_dir()) { _zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name); } else { - bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)); + bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers"); OS::Time time = OS::get_singleton()->get_time(); OS::Date date = OS::get_singleton()->get_date(); @@ -1006,13 +1048,25 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions 0); - Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f)); - zipWriteInFileInZip(p_zip, array.ptr(), array.size()); + FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); + if (!fa) { + ERR_FAIL_MSG("Can't open file to read from path '" + String(dir.plus_file(f)) + "'."); + } + const int bufsize = 16384; + uint8_t buf[bufsize]; + + while (true) { + uint64_t got = fa->get_buffer(buf, bufsize); + if (got == 0) { + break; + } + zipWriteInFileInZip(p_zip, buf, got); + } + zipCloseFileInZip(p_zip); } } da->list_dir_end(); - memdelete(da); } bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { diff --git a/platform/osx/context_gl_osx.h b/platform/osx/gl_manager_osx.h index ac45559217..f86bc805c1 100644 --- a/platform/osx/context_gl_osx.h +++ b/platform/osx/gl_manager_osx.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* context_gl_osx.h */ +/* gl_manager_osx.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,47 +28,79 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONTEXT_GL_OSX_H -#define CONTEXT_GL_OSX_H +#ifndef GL_MANAGER_OSX_H +#define GL_MANAGER_OSX_H -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) +#if defined(OSX_ENABLED) && defined(GLES3_ENABLED) #include "core/error/error_list.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "servers/display_server.h" #include <AppKit/AppKit.h> #include <ApplicationServices/ApplicationServices.h> #include <CoreVideo/CoreVideo.h> -class ContextGL_OSX { - bool opengl_3_context; - bool use_vsync; +class GLManager_OSX { +public: + enum ContextType { + GLES_3_0_COMPATIBLE, + }; + +private: + struct GLWindow { + GLWindow() { in_use = false; } + bool in_use; + + DisplayServer::WindowID window_id; + int width; + int height; + + id window_view; + NSOpenGLContext *context; + }; + + LocalVector<GLWindow> _windows; + + NSOpenGLContext *_shared_context = nullptr; + GLWindow *_current_window; + + Error _create_context(GLWindow &win); + void _internal_set_current_window(GLWindow *p_win); - void *framework; - id window_view; - NSOpenGLPixelFormat *pixelFormat; - NSOpenGLContext *context; + GLWindow &get_window(unsigned int id) { return _windows[id]; } + const GLWindow &get_window(unsigned int id) const { return _windows[id]; } + + bool use_vsync; + ContextType context_type; public: - void release_current(); + Error window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height); + void window_destroy(DisplayServer::WindowID p_window_id); + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); + + // get directly from the cached GLWindow + int window_get_width(DisplayServer::WindowID p_window_id = 0); + int window_get_height(DisplayServer::WindowID p_window_id = 0); + void release_current(); void make_current(); - void update(); + void swap_buffers(); - void set_opacity(GLint p_opacity); + void window_make_current(DisplayServer::WindowID p_window_id); - int get_window_width(); - int get_window_height(); - void swap_buffers(); + void window_update(DisplayServer::WindowID p_window_id); Error initialize(); void set_use_vsync(bool p_use); bool is_using_vsync() const; - ContextGL_OSX(id p_view, bool p_opengl_3_context); - ~ContextGL_OSX(); + GLManager_OSX(ContextType p_context_type); + ~GLManager_OSX(); }; -#endif -#endif +#endif // defined(OSX_ENABLED) && defined(GLES3_ENABLED) + +#endif // GL_MANAGER_OSX_H diff --git a/platform/osx/gl_manager_osx.mm b/platform/osx/gl_manager_osx.mm new file mode 100644 index 0000000000..cce58530ee --- /dev/null +++ b/platform/osx/gl_manager_osx.mm @@ -0,0 +1,233 @@ +/*************************************************************************/ +/* gl_manager_osx.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gl_manager_osx.h" + +#ifdef OSX_ENABLED +#ifdef GLES3_ENABLED + +#include <stdio.h> +#include <stdlib.h> + +Error GLManager_OSX::_create_context(GLWindow &win) { + NSOpenGLPixelFormatAttribute attributes[] = { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAClosestPolicy, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFAColorSize, 32, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAStencilSize, 8, + 0 + }; + + NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + ERR_FAIL_COND_V(pixel_format == nil, ERR_CANT_CREATE); + + win.context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:_shared_context]; + ERR_FAIL_COND_V(win.context == nil, ERR_CANT_CREATE); + if (_shared_context == nullptr) { + _shared_context = win.context; + } + + [win.context setView:win.window_view]; + [win.context makeCurrentContext]; + + return OK; +} + +Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) { + if (p_window_id >= (int)_windows.size()) { + _windows.resize(p_window_id + 1); + } + + GLWindow &win = _windows[p_window_id]; + win.in_use = true; + win.window_id = p_window_id; + win.width = p_width; + win.height = p_height; + win.window_view = p_view; + + if (_create_context(win) != OK) { + _windows.remove(_windows.size() - 1); + return FAILED; + } + + window_make_current(_windows.size() - 1); + + return OK; +} + +void GLManager_OSX::_internal_set_current_window(GLWindow *p_win) { + _current_window = p_win; +} + +void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { + if (p_window_id == -1) { + return; + } + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) { + return; + } + + win.width = p_width; + win.height = p_height; + + GLint dim[2]; + dim[0] = p_width; + dim[1] = p_height; + CGLSetParameter((CGLContextObj)[win.context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]); + CGLEnable((CGLContextObj)[win.context CGLContextObj], kCGLCESurfaceBackingSize); + if (OS::get_singleton()->is_hidpi_allowed()) { + [win.window_view setWantsBestResolutionOpenGLSurface:YES]; + } else { + [win.window_view setWantsBestResolutionOpenGLSurface:NO]; + } + + [win.context update]; +} + +int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { + return get_window(p_window_id).width; +} + +int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { + return get_window(p_window_id).height; +} + +void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { + GLWindow &win = get_window(p_window_id); + win.in_use = false; + + if (_current_window == &win) { + _current_window = nullptr; + } +} + +void GLManager_OSX::release_current() { + if (!_current_window) { + return; + } + + [NSOpenGLContext clearCurrentContext]; +} + +void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { + if (p_window_id == -1) { + return; + } + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) { + return; + } + + if (&win == _current_window) { + return; + } + + [win.context makeCurrentContext]; + + _internal_set_current_window(&win); +} + +void GLManager_OSX::make_current() { + if (!_current_window) { + return; + } + if (!_current_window->in_use) { + WARN_PRINT("current window not in use!"); + return; + } + [_current_window->context makeCurrentContext]; +} + +void GLManager_OSX::swap_buffers() { + // NO NEED TO CALL SWAP BUFFERS for each window... + // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml + + if (!_current_window) { + return; + } + if (!_current_window->in_use) { + WARN_PRINT("current window not in use!"); + return; + } + [_current_window->context flushBuffer]; +} + +void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { + if (p_window_id == -1) { + return; + } + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) { + return; + } + + if (&win == _current_window) { + return; + } + + [win.context update]; +} + +Error GLManager_OSX::initialize() { + return OK; +} + +void GLManager_OSX::set_use_vsync(bool p_use) { + use_vsync = p_use; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) { + GLint swapInterval = p_use ? 1 : 0; + CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); + use_vsync = p_use; + } +} + +bool GLManager_OSX::is_using_vsync() const { + return use_vsync; +} + +GLManager_OSX::GLManager_OSX(ContextType p_context_type) { + context_type = p_context_type; + use_vsync = false; + _current_window = nullptr; +} + +GLManager_OSX::~GLManager_OSX() { + release_current(); +} + +#endif // GLES3_ENABLED +#endif // OSX diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index e67d2b0e91..46ed651384 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -336,10 +336,10 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { } // Xbox controller hat values start at 1 rather than 0. p_joy->offset_hat = vendor == 0x45e && - (product_id == 0x0b05 || - product_id == 0x02e0 || - product_id == 0x02fd || - product_id == 0x0b13); + (product_id == 0x0b05 || + product_id == 0x02e0 || + product_id == 0x02fd || + product_id == 0x0b13); return true; } diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h index c060c3d523..3048ecf39e 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/osx/joypad_osx.h @@ -106,7 +106,6 @@ private: int get_joy_ref(IOHIDDeviceRef p_device) const; void poll_joypads() const; - void setup_joypad_objects(); void config_hid_manager(CFArrayRef p_matching_array) const; void joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index df41ccd892..7e02f4e154 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -57,6 +57,8 @@ class OS_OSX : public OS_Unix { MainLoop *main_loop; + static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context); + public: String open_with_filename; @@ -82,6 +84,7 @@ public: virtual String get_data_path() const override; virtual String get_cache_path() const override; virtual String get_bundle_resource_dir() const override; + virtual String get_bundle_icon_path() const override; virtual String get_godot_dir_name() const override; virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override; @@ -91,6 +94,8 @@ public: String get_locale() const override; virtual String get_executable_path() const override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; virtual String get_unique_id() const override; //++ diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index c6e35fee83..45a81be80a 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -178,7 +178,7 @@ class OSXTerminalLogger : public StdLogger { public: - virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR) { + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type = ERR_ERROR) { if (!should_log(true)) { return; } @@ -314,17 +314,27 @@ String OS_OSX::get_name() const { return "macOS"; } +_FORCE_INLINE_ String _get_framework_executable(const String p_path) { + // Append framework executable name, or return as is if p_path is not a framework. + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) { + return p_path.plus_file(p_path.get_file().get_basename()); + } else { + return p_path; + } +} + Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { - String path = p_path; + String path = _get_framework_executable(p_path); if (!FileAccess::exists(path)) { - //this code exists so gdnative can load .dylib files from within the executable path - path = get_executable_path().get_base_dir().plus_file(p_path.get_file()); + // This code exists so gdnative can load .dylib files from within the executable path. + path = _get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file())); } if (!FileAccess::exists(path)) { - //this code exists so gdnative can load .dylib files from a standard macOS location - path = get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file()); + // This code exists so gdnative can load .dylib files from a standard macOS location. + path = _get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file())); } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); @@ -379,14 +389,26 @@ String OS_OSX::get_cache_path() const { } String OS_OSX::get_bundle_resource_dir() const { + String ret; + NSBundle *main = [NSBundle mainBundle]; - NSString *resourcePath = [main resourcePath]; + if (main) { + NSString *resourcePath = [main resourcePath]; + ret.parse_utf8([resourcePath UTF8String]); + } + return ret; +} - char *utfs = strdup([resourcePath UTF8String]); +String OS_OSX::get_bundle_icon_path() const { String ret; - ret.parse_utf8(utfs); - free(utfs); + NSBundle *main = [NSBundle mainBundle]; + if (main) { + NSString *iconPath = [[main infoDictionary] objectForKey:@"CFBundleIconFile"]; + if (iconPath) { + ret.parse_utf8([iconPath UTF8String]); + } + } return ret; } @@ -469,14 +491,89 @@ String OS_OSX::get_executable_path() const { } } +Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { + // If executable is bundled, always execute editor instances as an app bundle to ensure app window is registered and activated correctly. + NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + if (nsappname != nil) { + String path; + path.parse_utf8([[[NSBundle mainBundle] bundlePath] UTF8String]); + return create_process(path, p_arguments, r_child_id); + } else { + return create_process(get_executable_path(), p_arguments, r_child_id); + } +} + +Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { + if (@available(macOS 10.15, *)) { + // Use NSWorkspace if path is an .app bundle. + NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; + NSBundle *bundle = [NSBundle bundleWithURL:url]; + if (bundle) { + NSMutableArray *arguments = [[NSMutableArray alloc] init]; + for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) { + [arguments addObject:[NSString stringWithUTF8String:E->get().utf8().get_data()]]; + } + NSWorkspaceOpenConfiguration *configuration = [[NSWorkspaceOpenConfiguration alloc] init]; + [configuration setArguments:arguments]; + [configuration setCreatesNewApplicationInstance:YES]; + __block dispatch_semaphore_t lock = dispatch_semaphore_create(0); + __block Error err = ERR_TIMEOUT; + __block pid_t pid = 0; + [[NSWorkspace sharedWorkspace] openApplicationAtURL:url + configuration:configuration + completionHandler:^(NSRunningApplication *app, NSError *error) { + if (error) { + err = ERR_CANT_FORK; + NSLog(@"Failed to execute: %@", error.localizedDescription); + } else { + pid = [app processIdentifier]; + err = OK; + } + dispatch_semaphore_signal(lock); + }]; + dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, 20000000000)); // 20 sec timeout, wait for app to launch. + dispatch_release(lock); + + if (err == OK) { + if (r_child_id) { + *r_child_id = (ProcessID)pid; + } + } + + return err; + } else { + return OS_Unix::create_process(p_path, p_arguments, r_child_id); + } + } else { + return OS_Unix::create_process(p_path, p_arguments, r_child_id); + } +} + +void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { + // Prevent main loop from sleeping and redraw window during resize / modal popups. + + if (get_singleton()->get_main_loop()) { + Main::force_redraw(); + if (!Main::is_iterating()) { // Avoid cyclic loop. + Main::iteration(); + } + } + + CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping. +} + void OS_OSX::run() { force_quit = false; - if (!main_loop) + if (!main_loop) { return; + } main_loop->initialize(); + CFRunLoopObserverRef pre_wait_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, &pre_wait_observer_cb, nullptr); + CFRunLoopAddObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); + bool quit = false; while (!force_quit && !quit) { @try { @@ -492,6 +589,10 @@ void OS_OSX::run() { ERR_PRINT("NSException: " + String([exception reason].UTF8String)); } }; + + CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); + CFRelease(pre_wait_observer); + main_loop->finalize(); } diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h index 2d0fd872dc..7bfa466b97 100644 --- a/platform/osx/platform_config.h +++ b/platform/osx/platform_config.h @@ -30,4 +30,5 @@ #include <alloca.h> +#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h" #define PTHREAD_RENAME_SELF |