diff options
Diffstat (limited to 'platform/osx')
| -rw-r--r-- | platform/osx/SCsub | 4 | ||||
| -rw-r--r-- | platform/osx/crash_handler_osx.h | 6 | ||||
| -rw-r--r-- | platform/osx/crash_handler_osx.mm | 16 | ||||
| -rw-r--r-- | platform/osx/detect.py | 18 | ||||
| -rw-r--r-- | platform/osx/dir_access_osx.h | 6 | ||||
| -rw-r--r-- | platform/osx/dir_access_osx.mm | 4 | ||||
| -rw-r--r-- | platform/osx/export/export.cpp | 212 | ||||
| -rw-r--r-- | platform/osx/export/export.h | 4 | ||||
| -rw-r--r-- | platform/osx/godot_main_osx.mm | 4 | ||||
| -rw-r--r-- | platform/osx/joypad_osx.cpp | 4 | ||||
| -rw-r--r-- | platform/osx/joypad_osx.h | 4 | ||||
| -rw-r--r-- | platform/osx/os_osx.h | 31 | ||||
| -rw-r--r-- | platform/osx/os_osx.mm | 338 | ||||
| -rw-r--r-- | platform/osx/platform_config.h | 8 | ||||
| -rw-r--r-- | platform/osx/power_osx.cpp | 20 | ||||
| -rw-r--r-- | platform/osx/power_osx.h | 21 | ||||
| -rw-r--r-- | platform/osx/semaphore_osx.cpp (renamed from platform/osx/sem_osx.cpp) | 11 | ||||
| -rw-r--r-- | platform/osx/semaphore_osx.h (renamed from platform/osx/sem_osx.h) | 14 |
18 files changed, 508 insertions, 217 deletions
diff --git a/platform/osx/SCsub b/platform/osx/SCsub index 5c973c30c2..d2952ebdc0 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -1,8 +1,8 @@ #!/usr/bin/env python -import os Import('env') +import os from platform_methods import run_in_subprocess import platform_osx_builders @@ -10,7 +10,7 @@ files = [ 'crash_handler_osx.mm', 'os_osx.mm', 'godot_main_osx.mm', - 'sem_osx.cpp', + 'semaphore_osx.cpp', 'dir_access_osx.mm', 'joypad_osx.cpp', 'power_osx.cpp', diff --git a/platform/osx/crash_handler_osx.h b/platform/osx/crash_handler_osx.h index 5d93afb22d..6a72ce8ae9 100644 --- a/platform/osx/crash_handler_osx.h +++ b/platform/osx/crash_handler_osx.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -45,4 +45,4 @@ public: ~CrashHandler(); }; -#endif +#endif // CRASH_HANDLER_OSX_H diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index 1664c5ce8e..ed8a955ae5 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -28,9 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "crash_handler_osx.h" + +#include "core/os/os.h" +#include "core/project_settings.h" #include "main/main.h" -#include "os_osx.h" -#include "project_settings.h" #include <string.h> #include <unistd.h> @@ -68,8 +70,9 @@ static uint64_t load_address() { } static void handle_crash(int sig) { - if (OS::get_singleton() == NULL) - return; + if (OS::get_singleton() == NULL) { + abort(); + } void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); @@ -151,6 +154,7 @@ CrashHandler::CrashHandler() { } CrashHandler::~CrashHandler() { + disable(); } void CrashHandler::disable() { diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 8a0883eca3..36a753e683 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -1,5 +1,6 @@ import os import sys +from methods import detect_darwin_sdk_path def is_active(): @@ -23,6 +24,7 @@ def get_opts(): return [ ('osxcross_sdk', 'OSXCross SDK version', 'darwin14'), + ('MACOS_SDK_PATH', 'Path to the macOS SDK', ''), EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False), ] @@ -40,7 +42,7 @@ def configure(env): if (env["target"] == "release"): if (env["optimize"] == "speed"): #optimize for speed (default) - env.Prepend(CCFLAGS=['-O3', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + env.Prepend(CCFLAGS=['-O3', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) else: #optimize for size env.Prepend(CCFLAGS=['-Os','-ftree-vectorize', '-msse2']) @@ -70,7 +72,11 @@ def configure(env): ## Compiler configuration - if "OSXCROSS_ROOT" not in os.environ: # regular native build + # Save this in environment for use by other modules + if "OSXCROSS_ROOT" in os.environ: + env["osxcross"] = True + + if not "osxcross" in env: # regular native build env.Append(CCFLAGS=['-arch', 'x86_64']) env.Append(LINKFLAGS=['-arch', 'x86_64']) if (env["macports_clang"] != 'no'): @@ -84,12 +90,16 @@ def configure(env): env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as" env.Append(CCFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define + detect_darwin_sdk_path('osx', env) + env.Append(CPPFLAGS=['-isysroot', '$MACOS_SDK_PATH']) + env.Append(LINKFLAGS=['-isysroot', '$MACOS_SDK_PATH']) + else: # osxcross build root = os.environ.get("OSXCROSS_ROOT", 0) basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-" ccache_path = os.environ.get("CCACHE") - if ccache_path == None: + if ccache_path is None: env['CC'] = basecmd + "cc" env['CXX'] = basecmd + "c++" else: @@ -116,7 +126,7 @@ def configure(env): env.Append(CPPPATH=['#platform/osx']) env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo']) env.Append(LIBS=['pthread']) env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h index e01ff2fe4d..e1aa038c61 100644 --- a/platform/osx/dir_access_osx.h +++ b/platform/osx/dir_access_osx.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -38,8 +38,8 @@ #include <sys/types.h> #include <unistd.h> +#include "core/os/dir_access.h" #include "drivers/unix/dir_access_unix.h" -#include "os/dir_access.h" /** @author Juan Linietsky <reduzio@gmail.com> diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm index cf66cab060..ada142005b 100644 --- a/platform/osx/dir_access_osx.mm +++ b/platform/osx/dir_access_osx.mm @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 880705b507..5e94bc457b 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -29,18 +29,18 @@ /*************************************************************************/ #include "export.h" +#include "core/io/marshalls.h" +#include "core/io/resource_saver.h" +#include "core/io/zip_io.h" +#include "core/os/file_access.h" +#include "core/os/os.h" +#include "core/project_settings.h" +#include "core/version.h" #include "editor/editor_export.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "io/marshalls.h" -#include "io/resource_saver.h" -#include "io/zip_io.h" -#include "os/file_access.h" -#include "os/os.h" #include "platform/osx/logo.gen.h" -#include "project_settings.h" #include "string.h" -#include "version.h" #include <sys/stat.h> class EditorExportPlatformOSX : public EditorExportPlatform { @@ -74,7 +74,14 @@ public: virtual String get_os_name() const { return "OSX"; } virtual Ref<Texture> get_logo() const { return logo; } - virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const { return use_dmg() ? "dmg" : "zip"; } + virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { + List<String> list; + if (use_dmg()) { + list.push_back("dmg"); + } + list.push_back("zip"); + return list; + } virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; @@ -132,10 +139,76 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false)); } +void _rgba8_to_packbits_encode(int p_ch, int p_size, PoolVector<uint8_t> &p_source, Vector<uint8_t> &p_dest) { + + int src_len = p_size * p_size; + + Vector<uint8_t> result; + result.resize(src_len * 1.25); //temp vector for rle encoded data, make it 25% larger for worst case scenario + int res_size = 0; + + uint8_t buf[128]; + int buf_size = 0; + + int i = 0; + while (i < src_len) { + uint8_t cur = p_source.read()[i * 4 + p_ch]; + + if (i < src_len - 2) { + + if ((p_source.read()[(i + 1) * 4 + p_ch] == cur) && (p_source.read()[(i + 2) * 4 + p_ch] == cur)) { + if (buf_size > 0) { + result.write[res_size++] = (uint8_t)(buf_size - 1); + copymem(&result.write[res_size], &buf, buf_size); + res_size += buf_size; + buf_size = 0; + } + + uint8_t lim = i + 130 >= src_len ? src_len - i - 1 : 130; + bool hit_lim = true; + + for (int j = 3; j <= lim; j++) { + if (p_source.read()[(i + j) * 4 + p_ch] != cur) { + hit_lim = false; + i = i + j - 1; + result.write[res_size++] = (uint8_t)(j - 3 + 0x80); + result.write[res_size++] = cur; + break; + } + } + if (hit_lim) { + result.write[res_size++] = (uint8_t)(lim - 3 + 0x80); + result.write[res_size++] = cur; + i = i + lim; + } + } else { + buf[buf_size++] = cur; + if (buf_size == 128) { + result.write[res_size++] = (uint8_t)(buf_size - 1); + copymem(&result.write[res_size], &buf, buf_size); + res_size += buf_size; + buf_size = 0; + } + } + } else { + buf[buf_size++] = cur; + result.write[res_size++] = (uint8_t)(buf_size - 1); + copymem(&result.write[res_size], &buf, buf_size); + res_size += buf_size; + buf_size = 0; + } + + i++; + } + + int ofs = p_dest.size(); + p_dest.resize(p_dest.size() + res_size); + copymem(&p_dest.write[ofs], result.ptr(), res_size); +} + void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { Ref<ImageTexture> it = memnew(ImageTexture); - int size = 512; Vector<uint8_t> data; @@ -145,32 +218,82 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ data.write[2] = 'n'; data.write[3] = 's'; - const char *name[] = { "ic09", "ic08", "ic07", "icp6", "icp5", "icp4" }; - int index = 0; - - while (size >= 16) { - + struct MacOSIconInfo { + const char *name; + const char *mask_name; + bool is_png; + int size; + }; + + static const MacOSIconInfo icon_infos[] = { + { "ic10", "", true, 1024 }, //1024x1024 32-bit PNG and 512x512@2x 32-bit "retina" PNG + { "ic09", "", true, 512 }, //512×512 32-bit PNG + { "ic14", "", true, 512 }, //256x256@2x 32-bit "retina" PNG + { "ic08", "", true, 256 }, //256×256 32-bit PNG + { "ic13", "", true, 256 }, //128x128@2x 32-bit "retina" PNG + { "ic07", "", true, 128 }, //128x128 32-bit PNG + { "ic12", "", true, 64 }, //32x32@2x 32-bit "retina" PNG + { "ic11", "", true, 32 }, //16x16@2x 32-bit "retina" PNG + { "il32", "l8mk", false, 32 }, //32x32 24-bit RLE + 8-bit uncompressed mask + { "is32", "s8mk", false, 16 } //16x16 24-bit RLE + 8-bit uncompressed mask + }; + + for (unsigned int i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? copy->convert(Image::FORMAT_RGBA8); - copy->resize(size, size); - it->create_from_image(copy); - String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png"); - ResourceSaver::save(path, it); - - FileAccess *f = FileAccess::open(path, FileAccess::READ); - ERR_FAIL_COND(!f); - - int ofs = data.size(); - uint32_t len = f->get_len(); - data.resize(data.size() + len + 8); - f->get_buffer(&data.write[ofs + 8], len); - memdelete(f); - len += 8; - len = BSWAP32(len); - copymem(&data.write[ofs], name[index], 4); - encode_uint32(len, &data.write[ofs + 4]); - index++; - size /= 2; + copy->resize(icon_infos[i].size, icon_infos[i].size); + + if (icon_infos[i].is_png) { + //encode png icon + it->create_from_image(copy); + String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png"); + ResourceSaver::save(path, it); + + FileAccess *f = FileAccess::open(path, FileAccess::READ); + ERR_FAIL_COND(!f); + + int ofs = data.size(); + uint32_t len = f->get_len(); + data.resize(data.size() + len + 8); + f->get_buffer(&data.write[ofs + 8], len); + memdelete(f); + len += 8; + len = BSWAP32(len); + copymem(&data.write[ofs], icon_infos[i].name, 4); + encode_uint32(len, &data.write[ofs + 4]); + } else { + PoolVector<uint8_t> src_data = copy->get_data(); + + //encode 24bit RGB RLE icon + { + int ofs = data.size(); + data.resize(data.size() + 8); + + _rgba8_to_packbits_encode(0, icon_infos[i].size, src_data, data); // encode R + _rgba8_to_packbits_encode(1, icon_infos[i].size, src_data, data); // encode G + _rgba8_to_packbits_encode(2, icon_infos[i].size, src_data, data); // encode B + + int len = data.size() - ofs; + len = BSWAP32(len); + copymem(&data.write[ofs], icon_infos[i].name, 4); + encode_uint32(len, &data.write[ofs + 4]); + } + + //encode 8bit mask uncompressed icon + { + int ofs = data.size(); + int len = copy->get_width() * copy->get_height(); + data.resize(data.size() + len + 8); + + for (int j = 0; j < len; j++) { + data.write[ofs + 8 + j] = src_data.read()[j * 4 + 3]; + } + len += 8; + len = BSWAP32(len); + copymem(&data.write[ofs], icon_infos[i].mask_name, 4); + encode_uint32(len, &data.write[ofs + 4]); + } + } } uint32_t total_len = data.size(); @@ -302,6 +425,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } } + if (!DirAccess::exists(p_path.get_base_dir())) { + return ERR_FILE_BAD_PATH; + } + FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); @@ -334,7 +461,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p io2.opaque = &dst_f; zipFile dst_pkg_zip = NULL; - if (use_dmg()) { + String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip"; + if (export_format == "dmg") { // We're on OSX so we can export to DMG, but first we create our application bundle tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app"); print_line("Exporting to " + tmp_app_path_name); @@ -429,7 +557,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p print_line("ADDING: " + file + " size: " + itos(data.size())); total_size += data.size(); - if (use_dmg()) { + if (export_format == "dmg") { // write it into our application bundle file = tmp_app_path_name + "/" + file; @@ -461,7 +589,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p fi.internal_fa = info.internal_fa; fi.external_fa = info.external_fa; - int zerr = zipOpenNewFileInZip(dst_pkg_zip, + zipOpenNewFileInZip(dst_pkg_zip, file.utf8().get_data(), &fi, NULL, @@ -472,7 +600,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Z_DEFLATED, Z_DEFAULT_COMPRESSION); - zerr = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); + zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); zipCloseFileInZip(dst_pkg_zip); } } @@ -491,7 +619,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (err == OK) { ep.step("Making PKG", 1); - if (use_dmg()) { + if (export_format == "dmg") { String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; Vector<SharedObject> shared_objects; err = save_pack(p_preset, pack_path, &shared_objects); @@ -625,7 +753,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset if (FileAccess::exists(p_preset->get("custom_package/debug"))) { valid = true; } else { - err += "Custom debug package not found.\n"; + err += TTR("Custom debug template not found.") + "\n"; } } @@ -633,7 +761,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset if (FileAccess::exists(p_preset->get("custom_package/release"))) { valid = true; } else { - err += "Custom release package not found.\n"; + err += TTR("Custom release template not found.") + "\n"; } } diff --git a/platform/osx/export/export.h b/platform/osx/export/export.h index 08294fc33c..7e7e697488 100644 --- a/platform/osx/export/export.h +++ b/platform/osx/export/export.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm index 64116fa1e0..79364314aa 100644 --- a/platform/osx/godot_main_osx.mm +++ b/platform/osx/godot_main_osx.mm @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index 365b39c573..fa124dac11 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h index addbefc5ad..255a674f09 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/osx/joypad_osx.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 686e3f8c90..dfe7b27bd0 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -31,20 +31,23 @@ #ifndef OS_OSX_H #define OS_OSX_H +#include "core/os/input.h" #include "crash_handler_osx.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" -#include "drivers/coremidi/core_midi.h" +#include "drivers/coremidi/midi_driver_coremidi.h" #include "drivers/unix/os_unix.h" #include "joypad_osx.h" #include "main/input_default.h" -#include "os/input.h" #include "power_osx.h" #include "servers/audio_server.h" #include "servers/visual/rasterizer.h" #include "servers/visual/visual_server_wrap_mt.h" #include "servers/visual_server.h" + +#include <AppKit/AppKit.h> #include <AppKit/NSCursor.h> #include <ApplicationServices/ApplicationServices.h> +#include <CoreVideo/CoreVideo.h> #undef CursorShape /** @@ -74,8 +77,12 @@ public: IP_Unix *ip_unix; +#ifdef COREAUDIO_ENABLED AudioDriverCoreAudio audio_driver; +#endif +#ifdef COREMIDI_ENABLED MIDIDriverCoreMidi midi_driver; +#endif InputDefault *input; JoypadOSX *joypad_osx; @@ -98,10 +105,13 @@ public: id window_view; id autoreleasePool; id cursor; - id pixelFormat; - id context; + NSOpenGLPixelFormat *pixelFormat; + NSOpenGLContext *context; bool layered_window; + bool waiting_for_vsync; + NSCondition *vsync_condition; + CVDisplayLinkRef displayLink; CursorShape cursor_shape; NSCursor *cursors[CURSOR_MAX]; @@ -120,10 +130,10 @@ public: Point2 im_position; bool im_active; - ImeCallback im_callback; - void *im_target; + String im_text; + Point2 im_selection; - power_osx *power_manager; + PowerOSX *power_manager; CrashHandler crash_handler; @@ -241,7 +251,8 @@ public: virtual void set_ime_active(const bool p_active); virtual void set_ime_position(const Point2 &p_pos); - virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp); + virtual Point2 get_ime_selection() const; + virtual String get_ime_text() const; virtual String get_unique_id() const; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 79d7ec410a..b45d0d80e6 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,15 +30,15 @@ #include "os_osx.h" +#include "core/os/keyboard.h" +#include "core/print_string.h" +#include "core/version_generated.gen.h" #include "dir_access_osx.h" #include "drivers/gles2/rasterizer_gles2.h" #include "drivers/gles3/rasterizer_gles3.h" #include "main/main.h" -#include "os/keyboard.h" -#include "print_string.h" -#include "sem_osx.h" +#include "semaphore_osx.h" #include "servers/visual/visual_server_raster.h" -#include "version_generated.gen.h" #include <mach-o/dyld.h> @@ -76,10 +76,12 @@ #define NSWindowStyleMaskBorderless NSBorderlessWindowMask #endif -static NSRect convertRectToBacking(NSRect contentRect) { - - return [OS_OSX::singleton->window_view convertRectToBacking:contentRect]; -} +#ifndef NSAppKitVersionNumber10_12 +#define NSAppKitVersionNumber10_12 1504 +#endif +#ifndef NSAppKitVersionNumber10_14 +#define NSAppKitVersionNumber10_14 1671 +#endif static void get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> state) { @@ -100,20 +102,34 @@ static void push_to_key_event_buffer(const OS_OSX::KeyEvent &p_event) { static int mouse_x = 0; static int mouse_y = 0; -static int prev_mouse_x = 0; -static int prev_mouse_y = 0; static int button_mask = 0; static bool mouse_down_control = false; -static Vector2 get_mouse_pos(NSEvent *event) { +static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFactor) { const NSRect contentRect = [OS_OSX::singleton->window_view frame]; - const NSPoint p = [event locationInWindow]; - mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); - mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); + const NSPoint p = locationInWindow; + const float s = OS_OSX::singleton->_mouse_scale(backingScaleFactor); + mouse_x = p.x * s; + mouse_y = (contentRect.size.height - p.y) * s; return Vector2(mouse_x, mouse_y); } +// DisplayLinkCallback is called from our DisplayLink OS thread informing us right before +// a screen update is required. We can use it to work around the broken vsync. +static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { + OS_OSX *os = (OS_OSX *)displayLinkContext; + + // Set flag so we know we can output our next frame and signal our conditional lock + // if we're not doing vsync this will be ignored + [os->vsync_condition lock]; + os->waiting_for_vsync = false; + [os->vsync_condition signal]; + [os->vsync_condition unlock]; + + return kCVReturnSuccess; +} + @interface GodotApplication : NSApplication @end @@ -264,14 +280,16 @@ static Vector2 get_mouse_pos(NSEvent *event) { NSWindow *window = (NSWindow *)[notification object]; CGFloat newBackingScaleFactor = [window backingScaleFactor]; CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; - [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + if (OS_OSX::singleton->is_hidpi_allowed()) { + [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + } if (newBackingScaleFactor != oldBackingScaleFactor) { //Set new display scale and window size float newDisplayScale = OS_OSX::singleton->is_hidpi_allowed() ? newBackingScaleFactor : 1.0; const NSRect contentRect = [OS_OSX::singleton->window_view frame]; - const NSRect fbRect = contentRect; //convertRectToBacking(contentRect); + const NSRect fbRect = contentRect; OS_OSX::singleton->window_size.width = fbRect.size.width * newDisplayScale; OS_OSX::singleton->window_size.height = fbRect.size.height * newDisplayScale; @@ -292,7 +310,7 @@ static Vector2 get_mouse_pos(NSEvent *event) { [OS_OSX::singleton->context update]; const NSRect contentRect = [OS_OSX::singleton->window_view frame]; - const NSRect fbRect = contentRect; //convertRectToBacking(contentRect); + const NSRect fbRect = contentRect; float displayScale = OS_OSX::singleton->_display_scale(); OS_OSX::singleton->window_size.width = fbRect.size.width * displayScale; @@ -301,7 +319,9 @@ static Vector2 get_mouse_pos(NSEvent *event) { if (OS_OSX::singleton->main_loop) { Main::force_redraw(); //Event retrieval blocks until resize is over. Call Main::iteration() directly. - Main::iteration(); + if (!Main::is_iterating()) { //avoid cyclic loop + Main::iteration(); + } } /* @@ -330,8 +350,15 @@ static Vector2 get_mouse_pos(NSEvent *event) { - (void)windowDidBecomeKey:(NSNotification *)notification { //_GodotInputWindowFocus(window, GL_TRUE); //_GodotPlatformSetCursorMode(window, window->cursorMode); - if (OS_OSX::singleton->get_main_loop()) + + if (OS_OSX::singleton->get_main_loop()) { + get_mouse_pos( + [OS_OSX::singleton->window_object mouseLocationOutsideOfEventStream], + [OS_OSX::singleton->window_view backingScaleFactor]); + OS_OSX::singleton->input->set_mouse_position(Point2(mouse_x, mouse_y)); + OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN); + } } - (void)windowDidResignKey:(NSNotification *)notification { @@ -361,6 +388,8 @@ static Vector2 get_mouse_pos(NSEvent *event) { bool imeMode; } - (void)cancelComposition; +- (BOOL)wantsUpdateLayer; +- (void)updateLayer; @end @implementation GodotContentView @@ -371,6 +400,14 @@ static Vector2 get_mouse_pos(NSEvent *event) { } } +- (BOOL)wantsUpdateLayer { + return YES; +} + +- (void)updateLayer { + [OS_OSX::singleton->context update]; +} + - (id)init { self = [super init]; trackingArea = nil; @@ -407,11 +444,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; } else { [markedText initWithString:aString]; } - if (OS_OSX::singleton->im_callback) { + if (OS_OSX::singleton->im_active) { imeMode = true; - String ret; - ret.parse_utf8([[markedText mutableString] UTF8String]); - OS_OSX::singleton->im_callback(OS_OSX::singleton->im_target, ret, Point2(selectedRange.location, selectedRange.length)); + OS_OSX::singleton->im_text.parse_utf8([[markedText mutableString] UTF8String]); + OS_OSX::singleton->im_selection = Point2(selectedRange.location, selectedRange.length); + + if (OS_OSX::singleton->get_main_loop()) + OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); } } @@ -423,8 +462,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)unmarkText { imeMode = false; [[markedText mutableString] setString:@""]; - if (OS_OSX::singleton->im_callback) - OS_OSX::singleton->im_callback(OS_OSX::singleton->im_target, "", Point2()); + if (OS_OSX::singleton->im_active) { + OS_OSX::singleton->im_text = String(); + OS_OSX::singleton->im_selection = Point2(); + + if (OS_OSX::singleton->get_main_loop()) + OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); + } } - (NSArray *)validAttributesForMarkedText { @@ -555,12 +599,13 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { Ref<InputEventMouseButton> mb; mb.instance(); - + const CGFloat backingScaleFactor = [[event window] backingScaleFactor]; + const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor); get_key_modifier_state([event modifierFlags], mb); mb->set_button_index(index); mb->set_pressed(pressed); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); + mb->set_position(pos); + mb->set_global_position(pos); mb->set_button_mask(button_mask); if (index == BUTTON_LEFT && pressed) { mb->set_doubleclick([event clickCount] == 2); @@ -596,14 +641,14 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { mm.instance(); mm->set_button_mask(button_mask); - prev_mouse_x = mouse_x; - prev_mouse_y = mouse_y; - const Vector2 pos = get_mouse_pos(event); + const CGFloat backingScaleFactor = [[event window] backingScaleFactor]; + const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor); mm->set_position(pos); mm->set_global_position(pos); + mm->set_speed(OS_OSX::singleton->input->get_last_mouse_speed()); Vector2 relativeMotion = Vector2(); - relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]); - relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]); + relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor); + relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor); mm->set_relative(relativeMotion); get_key_modifier_state([event modifierFlags], mm); @@ -686,7 +731,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { Ref<InputEventMagnifyGesture> ev; ev.instance(); get_key_modifier_state([event modifierFlags], ev); - ev->set_position(get_mouse_pos(event)); + ev->set_position(get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor])); ev->set_factor([event magnification] + 1.0); OS_OSX::singleton->push_input(ev); } @@ -717,9 +762,41 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { [super updateTrackingAreas]; } +static bool isNumpadKey(unsigned int key) { + + static const unsigned int table[] = { + 0x41, /* kVK_ANSI_KeypadDecimal */ + 0x43, /* kVK_ANSI_KeypadMultiply */ + 0x45, /* kVK_ANSI_KeypadPlus */ + 0x47, /* kVK_ANSI_KeypadClear */ + 0x4b, /* kVK_ANSI_KeypadDivide */ + 0x4c, /* kVK_ANSI_KeypadEnter */ + 0x4e, /* kVK_ANSI_KeypadMinus */ + 0x51, /* kVK_ANSI_KeypadEquals */ + 0x52, /* kVK_ANSI_Keypad0 */ + 0x53, /* kVK_ANSI_Keypad1 */ + 0x54, /* kVK_ANSI_Keypad2 */ + 0x55, /* kVK_ANSI_Keypad3 */ + 0x56, /* kVK_ANSI_Keypad4 */ + 0x57, /* kVK_ANSI_Keypad5 */ + 0x58, /* kVK_ANSI_Keypad6 */ + 0x59, /* kVK_ANSI_Keypad7 */ + 0x5b, /* kVK_ANSI_Keypad8 */ + 0x5c, /* kVK_ANSI_Keypad9 */ + 0x5f, /* kVK_JIS_KeypadComma */ + 0x00 + }; + for (int i = 0; table[i] != 0; i++) { + if (key == table[i]) + return true; + } + return false; +} + // Translates a OS X keycode to a Godot keycode // static int translateKey(unsigned int key) { + // Keyboard symbol translation table static const unsigned int table[128] = { /* 00 */ KEY_A, @@ -732,7 +809,7 @@ static int translateKey(unsigned int key) { /* 07 */ KEY_X, /* 08 */ KEY_C, /* 09 */ KEY_V, - /* 0a */ KEY_UNKNOWN, + /* 0a */ KEY_SECTION, /* ISO Section */ /* 0b */ KEY_B, /* 0c */ KEY_Q, /* 0d */ KEY_W, @@ -786,7 +863,7 @@ static int translateKey(unsigned int key) { /* 3d */ KEY_ALT, /* 3e */ KEY_CONTROL, /* 3f */ KEY_UNKNOWN, /* Function */ - /* 40 */ KEY_UNKNOWN, + /* 40 */ KEY_UNKNOWN, /* F17 */ /* 41 */ KEY_KP_PERIOD, /* 42 */ KEY_UNKNOWN, /* 43 */ KEY_KP_MULTIPLY, @@ -794,16 +871,16 @@ static int translateKey(unsigned int key) { /* 45 */ KEY_KP_ADD, /* 46 */ KEY_UNKNOWN, /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */ - /* 48 */ KEY_UNKNOWN, /* VolumeUp */ - /* 49 */ KEY_UNKNOWN, /* VolumeDown */ - /* 4a */ KEY_UNKNOWN, /* Mute */ + /* 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, - /* 50 */ KEY_UNKNOWN, - /* 51 */ KEY_EQUAL, //wtf equal? + /* 4f */ KEY_UNKNOWN, /* F18 */ + /* 50 */ KEY_UNKNOWN, /* F19 */ + /* 51 */ KEY_EQUAL, /* KeypadEqual */ /* 52 */ KEY_KP_0, /* 53 */ KEY_KP_1, /* 54 */ KEY_KP_2, @@ -812,27 +889,27 @@ static int translateKey(unsigned int key) { /* 57 */ KEY_KP_5, /* 58 */ KEY_KP_6, /* 59 */ KEY_KP_7, - /* 5a */ KEY_UNKNOWN, + /* 5a */ KEY_UNKNOWN, /* F20 */ /* 5b */ KEY_KP_8, /* 5c */ KEY_KP_9, - /* 5d */ KEY_UNKNOWN, - /* 5e */ KEY_UNKNOWN, - /* 5f */ KEY_UNKNOWN, + /* 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, + /* 66 */ KEY_UNKNOWN, /* JIS Eisu */ /* 67 */ KEY_F11, - /* 68 */ KEY_UNKNOWN, + /* 68 */ KEY_UNKNOWN, /* JIS Kana */ /* 69 */ KEY_F13, /* 6a */ KEY_F16, /* 6b */ KEY_F14, /* 6c */ KEY_UNKNOWN, /* 6d */ KEY_F10, - /* 6e */ KEY_UNKNOWN, + /* 6e */ KEY_MENU, /* 6f */ KEY_F12, /* 70 */ KEY_UNKNOWN, /* 71 */ KEY_F15, @@ -923,13 +1000,16 @@ static const _KeyCodeMap _keycodes[55] = { static int remapKey(unsigned int key) { + if (isNumpadKey(key)) + return translateKey(key); + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); if (!currentKeyboard) return translateKey(key); CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); if (!layoutData) - return 0; + return translateKey(key); const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); @@ -1047,6 +1127,9 @@ static int remapKey(unsigned int key) { inline void sendScrollEvent(int button, double factor, int modifierFlags) { + unsigned int mask = 1 << (button - 1); + Vector2 mouse_pos = Vector2(mouse_x, mouse_y); + Ref<InputEventMouseButton> sc; sc.instance(); @@ -1054,12 +1137,20 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) { sc->set_button_index(button); sc->set_factor(factor); sc->set_pressed(true); - Vector2 mouse_pos = Vector2(mouse_x, mouse_y); sc->set_position(mouse_pos); sc->set_global_position(mouse_pos); + button_mask |= mask; sc->set_button_mask(button_mask); OS_OSX::singleton->push_input(sc); + + sc.instance(); + sc->set_button_index(button); + sc->set_factor(factor); sc->set_pressed(false); + sc->set_position(mouse_pos); + sc->set_global_position(mouse_pos); + button_mask &= ~mask; + sc->set_button_mask(button_mask); OS_OSX::singleton->push_input(sc); } @@ -1078,6 +1169,8 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) { - (void)scrollWheel:(NSEvent *)event { double deltaX, deltaY; + get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]); + deltaX = [event scrollingDeltaX]; deltaY = [event scrollingDeltaY]; @@ -1113,12 +1206,14 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) { @end -void OS_OSX::set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp) { - im_callback = p_callback; - im_target = p_inp; - if (!im_callback) { - [window_view cancelComposition]; - } +Point2 OS_OSX::get_ime_selection() const { + + return im_selection; +} + +String OS_OSX::get_ime_text() const { + + return im_text; } String OS_OSX::get_unique_id() const { @@ -1146,10 +1241,14 @@ String OS_OSX::get_unique_id() const { } void OS_OSX::set_ime_active(const bool p_active) { + im_active = p_active; + if (!im_active) + [window_view cancelComposition]; } void OS_OSX::set_ime_position(const Point2 &p_pos) { + im_position = p_pos; } @@ -1221,6 +1320,9 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a ERR_FAIL_COND_V(window_object == nil, ERR_UNAVAILABLE); window_view = [[GodotContentView alloc] init]; + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_14) { + [window_view setWantsLayer:TRUE]; + } float displayScale = 1.0; if (is_hidpi_allowed()) { @@ -1318,6 +1420,15 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a [context makeCurrentContext]; + // setup our display link, this will inform us when a refresh is needed + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, this); + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, context.CGLContextObj, pixelFormat.CGLPixelFormatObj); + CVDisplayLinkStart(displayLink); + + // initialise a conditional lock object + vsync_condition = [[NSCondition alloc] init]; + set_use_vsync(p_desired.use_vsync); [NSApp activateIgnoringOtherApps:YES]; @@ -1346,7 +1457,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a RasterizerGLES3::make_current(); break; } else { - if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) { p_video_driver = VIDEO_DRIVER_GLES2; gles3 = false; continue; @@ -1378,7 +1489,6 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a visual_server = memnew(VisualServerRaster); if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { - visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); } @@ -1388,7 +1498,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a input = memnew(InputDefault); joypad_osx = memnew(JoypadOSX); - power_manager = memnew(power_osx); + power_manager = memnew(PowerOSX); _ensure_user_data_dir(); @@ -1402,7 +1512,14 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a void OS_OSX::finalize() { +#ifdef COREMIDI_ENABLED midi_driver.close(); +#endif + + if (displayLink) { + CVDisplayLinkRelease(displayLink); + } + [vsync_condition release]; CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL); CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL); @@ -1452,7 +1569,7 @@ public: switch (p_type) { case ERR_WARNING: - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12) { + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { os_log_info(OS_LOG_DEFAULT, "WARNING: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); @@ -1462,7 +1579,7 @@ public: logf_error("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); break; case ERR_SCRIPT: - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12) { + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { os_log_error(OS_LOG_DEFAULT, "SCRIPT ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); @@ -1472,7 +1589,7 @@ public: logf_error("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); break; case ERR_SHADER: - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12) { + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { os_log_error(OS_LOG_DEFAULT, "SHADER ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); @@ -1483,7 +1600,7 @@ public: break; case ERR_ERROR: default: - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12) { + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { os_log_error(OS_LOG_DEFAULT, "ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); @@ -1569,7 +1686,8 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) { case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break; case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break; case CURSOR_HELP: [[NSCursor arrowCursor] set]; break; - default: {}; + default: { + }; } } @@ -1604,7 +1722,9 @@ void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c } ERR_FAIL_COND(!texture.is_valid()); + ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0); ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); + ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); image = texture->get_data(); @@ -1660,8 +1780,10 @@ void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c [cursors[p_shape] release]; cursors[p_shape] = cursor; - if (p_shape == CURSOR_ARROW) { - [cursor set]; + if (p_shape == cursor_shape) { + if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { + [cursor set]; + } } [imgrep release]; @@ -1669,8 +1791,10 @@ void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c } else { // Reset to default system cursor cursors[p_shape] = NULL; + + CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; - set_cursor_shape(p_shape); + set_cursor_shape(c); } } @@ -1858,28 +1982,30 @@ bool OS_OSX::can_draw() const { void OS_OSX::set_clipboard(const String &p_text) { - NSArray *types = [NSArray arrayWithObjects:NSStringPboardType, nil]; + NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()]; + NSArray *copiedStringArray = [NSArray arrayWithObject:copiedString]; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:types owner:nil]; - [pasteboard setString:[NSString stringWithUTF8String:p_text.utf8().get_data()] - forType:NSStringPboardType]; + [pasteboard clearContents]; + [pasteboard writeObjects:copiedStringArray]; } String OS_OSX::get_clipboard() const { NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSArray *classArray = [NSArray arrayWithObject:[NSString class]]; + NSDictionary *options = [NSDictionary dictionary]; - if (![[pasteboard types] containsObject:NSStringPboardType]) { - return ""; - } + BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options]; - NSString *object = [pasteboard stringForType:NSStringPboardType]; - if (!object) { + if (!ok) { return ""; } - char *utfs = strdup([object UTF8String]); + NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options]; + NSString *string = [objectsToPaste objectAtIndex:0]; + + char *utfs = strdup([string UTF8String]); String ret; ret.parse_utf8(utfs); free(utfs); @@ -1909,6 +2035,17 @@ String OS_OSX::get_locale() const { } void OS_OSX::swap_buffers() { + if (is_vsync_enabled()) { + // Wait until our DisplayLink callback unsets our flag... + [vsync_condition lock]; + while (waiting_for_vsync) + [vsync_condition wait]; + + // Make sure we wait again next frame around + waiting_for_vsync = true; + + [vsync_condition unlock]; + } [context flushBuffer]; } @@ -2146,11 +2283,7 @@ void OS_OSX::set_window_size(const Size2 p_size) { if (menuBarHeight != 0.f) { size.y += menuBarHeight; } else { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 if (floor(NSAppKitVersionNumber) < NSAppKitVersionNumber10_12) { -#else - { -#endif size.y += [[NSStatusBar systemStatusBar] thickness]; } } @@ -2228,7 +2361,8 @@ bool OS_OSX::is_window_maximized() const { void OS_OSX::move_window_to_foreground() { - [window_object orderFrontRegardless]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + [window_object makeKeyAndOrderFront:nil]; } void OS_OSX::set_window_always_on_top(bool p_enabled) { @@ -2432,6 +2566,8 @@ void OS_OSX::process_events() { [autoreleasePool drain]; autoreleasePool = [[NSAutoreleasePool alloc] init]; + + input->flush_accumulated_events(); } void OS_OSX::process_key_events() { @@ -2474,7 +2610,7 @@ void OS_OSX::process_key_events() { void OS_OSX::push_input(const Ref<InputEvent> &p_event) { Ref<InputEvent> ev = p_event; - input->parse_input_event(ev); + input->accumulate_input_event(ev); } void OS_OSX::force_process_input() { @@ -2579,22 +2715,22 @@ Error OS_OSX::move_to_trash(const String &p_path) { } void OS_OSX::_set_use_vsync(bool p_enable) { - CGLContextObj ctx = CGLGetCurrentContext(); + // CGLCPSwapInterval broke in OSX 10.14 and it seems Apple is not interested in fixing + // it as OpenGL is now deprecated and Metal solves this differently. + // Following SDLs example we're working around this using DisplayLink + // When vsync is enabled we set a flag "waiting_for_vsync" to true. + // This flag is set to false when DisplayLink informs us our display is about to refresh. + + /* CGLContextObj ctx = CGLGetCurrentContext(); if (ctx) { GLint swapInterval = p_enable ? 1 : 0; CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - } -} -/* -bool OS_OSX::is_vsync_enabled() const { - GLint swapInterval = 0; - CGLContextObj ctx = CGLGetCurrentContext(); - if (ctx) { - CGLGetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - } - return swapInterval ? true : false; + }*/ + + ///TODO Maybe pause/unpause display link? + waiting_for_vsync = p_enable; } -*/ + OS_OSX *OS_OSX::singleton = NULL; OS_OSX::OS_OSX() { @@ -2606,8 +2742,6 @@ OS_OSX::OS_OSX() { singleton = this; im_active = false; im_position = Point2(); - im_callback = NULL; - im_target = NULL; layered_window = false; autoreleasePool = [[NSAutoreleasePool alloc] init]; @@ -2711,11 +2845,13 @@ OS_OSX::OS_OSX() { [NSApp sendEvent:event]; } +#ifdef COREAUDIO_ENABLED AudioDriverManager::add_driver(&audio_driver); +#endif } bool OS_OSX::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc" || p_feature == "s3tc"; + return p_feature == "pc"; } void OS_OSX::disable_crash_handler() { diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h index 3f72831d77..ddb533cb79 100644 --- a/platform/osx/platform_config.h +++ b/platform/osx/platform_config.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,6 +30,6 @@ #include <alloca.h> -#define GLES3_INCLUDE_H "glad/glad.h" -#define GLES2_INCLUDE_H "glad/glad.h" +#define GLES3_INCLUDE_H "thirdparty/glad/glad/glad.h" +#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h" #define PTHREAD_RENAME_SELF diff --git a/platform/osx/power_osx.cpp b/platform/osx/power_osx.cpp index 22e279dfa7..04d423d8c5 100644 --- a/platform/osx/power_osx.cpp +++ b/platform/osx/power_osx.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -67,7 +67,7 @@ Adapted from corresponding SDL 2.0 code. CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **)v) /* Note that AC power sources also include a laptop battery it is charging. */ -void power_osx::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging) { +void PowerOSX::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging) { CFStringRef strval; /* don't CFRelease() this. */ CFBooleanRef bval; CFNumberRef numval; @@ -169,7 +169,7 @@ void power_osx::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, #undef STRMATCH // CODE CHUNK IMPORTED FROM SDL 2.0 -bool power_osx::GetPowerInfo_MacOSX() { +bool PowerOSX::GetPowerInfo_MacOSX() { CFTypeRef blob = IOPSCopyPowerSourcesInfo(); nsecs_left = -1; @@ -211,14 +211,14 @@ bool power_osx::GetPowerInfo_MacOSX() { return true; /* always the definitive answer on Mac OS X. */ } -bool power_osx::UpdatePowerInfo() { +bool PowerOSX::UpdatePowerInfo() { if (GetPowerInfo_MacOSX()) { return true; } return false; } -OS::PowerState power_osx::get_power_state() { +OS::PowerState PowerOSX::get_power_state() { if (UpdatePowerInfo()) { return power_state; } else { @@ -226,7 +226,7 @@ OS::PowerState power_osx::get_power_state() { } } -int power_osx::get_power_seconds_left() { +int PowerOSX::get_power_seconds_left() { if (UpdatePowerInfo()) { return nsecs_left; } else { @@ -234,7 +234,7 @@ int power_osx::get_power_seconds_left() { } } -int power_osx::get_power_percent_left() { +int PowerOSX::get_power_percent_left() { if (UpdatePowerInfo()) { return percent_left; } else { @@ -242,11 +242,11 @@ int power_osx::get_power_percent_left() { } } -power_osx::power_osx() : +PowerOSX::PowerOSX() : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) { } -power_osx::~power_osx() { +PowerOSX::~PowerOSX() { } diff --git a/platform/osx/power_osx.h b/platform/osx/power_osx.h index 7123e34a03..40d0d40fd4 100644 --- a/platform/osx/power_osx.h +++ b/platform/osx/power_osx.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -28,15 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_OSX_POWER_OSX_H_ -#define PLATFORM_OSX_POWER_OSX_H_ +#ifndef POWER_OSX_H +#define POWER_OSX_H +#include "core/os/file_access.h" +#include "core/os/os.h" #include "dir_access_osx.h" -#include "os/file_access.h" -#include "os/os.h" + #include <CoreFoundation/CoreFoundation.h> -class power_osx { +class PowerOSX { private: int nsecs_left; @@ -47,12 +48,12 @@ private: bool UpdatePowerInfo(); public: - power_osx(); - virtual ~power_osx(); + PowerOSX(); + virtual ~PowerOSX(); OS::PowerState get_power_state(); int get_power_seconds_left(); int get_power_percent_left(); }; -#endif /* PLATFORM_OSX_POWER_OSX_H_ */ +#endif // POWER_OSX_H diff --git a/platform/osx/sem_osx.cpp b/platform/osx/semaphore_osx.cpp index 92f749322e..fe7d19bd9e 100644 --- a/platform/osx/sem_osx.cpp +++ b/platform/osx/semaphore_osx.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* sem_osx.cpp */ +/* semaphore_osx.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "sem_osx.h" +#include "semaphore_osx.h" #include <fcntl.h> #include <unistd.h> @@ -65,7 +65,8 @@ void cgsem_destroy(cgsem_t *cgsem) { close(cgsem->pipefd[0]); } -#include "os/memory.h" +#include "core/os/memory.h" + #include <errno.h> Error SemaphoreOSX::wait() { diff --git a/platform/osx/sem_osx.h b/platform/osx/semaphore_osx.h index ce31e966b7..c8e7c45227 100644 --- a/platform/osx/sem_osx.h +++ b/platform/osx/semaphore_osx.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* sem_osx.h */ +/* semaphore_osx.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SEM_OSX_H -#define SEM_OSX_H +#ifndef SEMAPHORE_OSX_H +#define SEMAPHORE_OSX_H struct cgsem { int pipefd[2]; @@ -37,7 +37,7 @@ struct cgsem { typedef struct cgsem cgsem_t; -#include "os/semaphore.h" +#include "core/os/semaphore.h" class SemaphoreOSX : public Semaphore { @@ -56,4 +56,4 @@ public: ~SemaphoreOSX(); }; -#endif +#endif // SEMAPHORE_OSX_H |