aboutsummaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/audio_driver_jandroid.cpp2
-rw-r--r--platform/android/detect.py150
-rw-r--r--platform/android/export/export.cpp77
-rw-r--r--platform/android/globals/global_defaults.cpp4
-rw-r--r--platform/android/godot_android.cpp8
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java2
-rw-r--r--platform/android/java_glue.cpp16
-rw-r--r--platform/android/os_android.cpp8
-rw-r--r--platform/android/os_android.h1
-rw-r--r--platform/haiku/audio_driver_media_kit.cpp2
-rw-r--r--platform/haiku/detect.py51
-rw-r--r--platform/haiku/os_haiku.cpp5
-rw-r--r--platform/haiku/os_haiku.h2
-rw-r--r--platform/iphone/SCsub9
-rw-r--r--platform/iphone/app_delegate.mm17
-rw-r--r--platform/iphone/detect.py178
-rw-r--r--platform/iphone/export/export.cpp366
-rw-r--r--platform/iphone/export/export.h30
-rw-r--r--platform/iphone/gl_view.mm4
-rw-r--r--platform/iphone/globals/global_defaults.cpp4
-rw-r--r--platform/iphone/ios.mm2
-rw-r--r--platform/iphone/os_iphone.cpp26
-rw-r--r--platform/iphone/os_iphone.h1
-rw-r--r--platform/javascript/SCsub41
-rw-r--r--platform/javascript/detect.py62
-rw-r--r--platform/javascript/export/export.cpp12
-rw-r--r--platform/javascript/godot_shell.html6
-rw-r--r--platform/javascript/os_javascript.cpp128
-rw-r--r--platform/javascript/os_javascript.h2
-rw-r--r--platform/osx/audio_driver_osx.cpp175
-rw-r--r--platform/osx/audio_driver_osx.h8
-rw-r--r--platform/osx/detect.py70
-rw-r--r--platform/osx/export/export.cpp363
-rw-r--r--platform/osx/os_osx.h8
-rw-r--r--platform/osx/os_osx.mm360
-rw-r--r--platform/server/detect.py78
-rw-r--r--platform/uwp/detect.py107
-rw-r--r--platform/uwp/export/export.cpp2135
-rw-r--r--platform/uwp/os_uwp.cpp9
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/windows/detect.py283
-rw-r--r--platform/windows/export/export.cpp1
-rw-r--r--platform/windows/os_windows.cpp141
-rw-r--r--platform/windows/os_windows.h6
-rw-r--r--platform/x11/detect.py151
-rw-r--r--platform/x11/export/export.cpp1
-rw-r--r--platform/x11/godot_x11.cpp3
-rw-r--r--platform/x11/key_mapping_x11.cpp1
-rw-r--r--platform/x11/os_x11.cpp247
-rw-r--r--platform/x11/os_x11.h9
-rw-r--r--platform/x11/power_x11.cpp11
51 files changed, 2694 insertions, 2691 deletions
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index 7b2127a21..d293f3ed3 100644
--- a/platform/android/audio_driver_jandroid.cpp
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "audio_driver_jandroid.h"
-#include "global_config.h"
#include "os/os.h"
+#include "project_settings.h"
#include "thread_jandroid.h"
#ifndef ANDROID_NATIVE_ACTIVITY
diff --git a/platform/android/detect.py b/platform/android/detect.py
index ce44ffbf7..fae1df3f2 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -14,22 +14,17 @@ def get_name():
def can_build():
- import os
- if (not os.environ.has_key("ANDROID_NDK_ROOT")):
- return False
-
- return True
+ return (os.environ.has_key("ANDROID_NDK_ROOT"))
def get_opts():
return [
- ('ANDROID_NDK_ROOT', 'the path to Android NDK',
- os.environ.get("ANDROID_NDK_ROOT", 0)),
- ('ndk_platform', 'compile for platform: (android-<api> , example: android-18)', "android-18"),
- ('android_arch', 'select compiler architecture: (armv7/armv6/x86)', "armv7"),
- ('android_neon', 'enable neon (armv7 only)', "yes"),
- ('android_stl', 'enable STL support in android port (for modules)', "no")
+ ('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"),
+ ('android_arch', 'Target architecture (armv7/armv6/x86)', "armv7"),
+ ('android_neon', 'Enable NEON support (armv7 only)', "yes"),
+ ('android_stl', 'Enable Android STL support (for modules)', "no")
]
@@ -41,6 +36,7 @@ def get_flags():
def create(env):
+
tools = env['TOOLS']
if "mingw" in tools:
tools.remove('mingw')
@@ -54,7 +50,6 @@ def configure(env):
# Workaround for MinGW. See:
# http://www.scons.org/wiki/LongCmdLinesOnWin32
- import os
if (os.name == "nt"):
import subprocess
@@ -92,35 +87,29 @@ def configure(env):
env['SPAWN'] = mySpawn
- ndk_platform = env['ndk_platform']
+ ## Architecture
if env['android_arch'] not in ['armv7', 'armv6', 'x86']:
env['android_arch'] = 'armv7'
- if env['android_arch'] == 'x86':
- env["x86_libtheora_opt_gcc"] = True
-
- if env['PLATFORM'] == 'win32':
- env.Tool('gcc')
- env['SHLIBSUFFIX'] = '.so'
-
neon_text = ""
if env["android_arch"] == "armv7" and env['android_neon'] == 'yes':
- neon_text = " (with neon)"
- print("Godot Android!!!!! (" + env['android_arch'] + ")" + neon_text)
-
- env.Append(CPPPATH=['#platform/android'])
+ neon_text = " (with NEON)"
+ print("Building for Android (" + env['android_arch'] + ")" + neon_text)
+ can_vectorize = True
if env['android_arch'] == 'x86':
env.extra_suffix = ".x86" + env.extra_suffix
target_subpath = "x86-4.9"
abi_subpath = "i686-linux-android"
arch_subpath = "x86"
+ env["x86_libtheora_opt_gcc"] = True
elif env['android_arch'] == 'armv6':
env.extra_suffix = ".armv6" + env.extra_suffix
target_subpath = "arm-linux-androideabi-4.9"
abi_subpath = "arm-linux-androideabi"
arch_subpath = "armeabi"
+ can_vectorize = False
elif env["android_arch"] == "armv7":
target_subpath = "arm-linux-androideabi-4.9"
abi_subpath = "arm-linux-androideabi"
@@ -130,6 +119,28 @@ def configure(env):
else:
env.extra_suffix = ".armv7" + env.extra_suffix
+ ## Build type
+
+ if (env["target"].startswith("release")):
+ env.Append(LINKFLAGS=['-O2'])
+ env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer'])
+ if (can_vectorize):
+ env.Append(CPPFLAGS=['-ftree-vectorize'])
+ if (env["target"] == "release_debug"):
+ env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
+ elif (env["target"] == "debug"):
+ env.Append(LINKFLAGS=['-O0'])
+ env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED',
+ '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info'])
+
+ ## Compiler configuration
+
+ env['SHLIBSUFFIX'] = '.so'
+
+ if env['PLATFORM'] == 'win32':
+ env.Tool('gcc')
+ env.use_windows_spawn_fix()
+
mt_link = True
if (sys.platform.startswith("linux")):
host_subpath = "linux-x86_64"
@@ -142,10 +153,8 @@ def configure(env):
mt_link = False
host_subpath = "windows"
- compiler_path = env["ANDROID_NDK_ROOT"] + \
- "/toolchains/llvm/prebuilt/" + host_subpath + "/bin"
- gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + \
- "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath
+ compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin"
+ gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath
tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin"
# For Clang to find NDK tools in preference of those system-wide
@@ -162,31 +171,28 @@ def configure(env):
else:
env['ARCH'] = 'arch-arm'
- sysroot = env["ANDROID_NDK_ROOT"] + \
- "/platforms/" + ndk_platform + "/" + env['ARCH']
+ sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path]
+ ## Compile flags
+
env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
- env.Append(CPPFLAGS=string.split(
- '-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'))
- env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED'))
+ env.Append(CPPFLAGS=string.split('-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'))
+ env.Append(CPPFLAGS=string.split('-DNO_STATVFS -DGLES2_ENABLED'))
env['neon_enabled'] = False
if env['android_arch'] == 'x86':
- can_vectorize = True
target_opts = ['-target', 'i686-none-linux-android']
# The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least
env.Append(CPPFLAGS=['-mstackrealign'])
+
elif env["android_arch"] == "armv6":
- can_vectorize = False
target_opts = ['-target', 'armv6-none-linux-androideabi']
- env.Append(CPPFLAGS=string.split(
- '-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp'))
+ env.Append(CPPFLAGS=string.split('-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp'))
+
elif env["android_arch"] == "armv7":
- can_vectorize = True
target_opts = ['-target', 'armv7-none-linux-androideabi']
- env.Append(CPPFLAGS=string.split(
- '-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp'))
+ env.Append(CPPFLAGS=string.split('-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp'))
if env['android_neon'] == 'yes':
env['neon_enabled'] = True
env.Append(CPPFLAGS=['-mfpu=neon', '-D__ARM_NEON__'])
@@ -196,21 +202,20 @@ def configure(env):
env.Append(CPPFLAGS=target_opts)
env.Append(CPPFLAGS=common_opts)
- env.Append(LIBS=['OpenSLES'])
- env.Append(LIBS=['EGL', 'OpenSLES', 'android'])
- env.Append(LIBS=['log', 'GLESv1_CM', 'GLESv2', 'GLESv3','z'])
+ if (env['android_stl'] == 'yes'):
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath])
+ env.Append(LIBS=["gnustl_static"])
+ else:
+ env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST'])
- if (sys.platform.startswith("darwin")):
- env['SHLIBSUFFIX'] = '.so'
+ ## Link flags
- env['LINKFLAGS'] = ['-shared', '--sysroot=' +
- sysroot, '-Wl,--warn-shared-textrel']
- env.Append(LINKFLAGS=string.split(
- '-Wl,--fix-cortex-a8'))
- env.Append(LINKFLAGS=string.split(
- '-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'))
- env.Append(LINKFLAGS=string.split(
- '-Wl,-soname,libgodot_android.so -Wl,--gc-sections'))
+ env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel']
+ env.Append(LINKFLAGS=string.split('-Wl,--fix-cortex-a8'))
+ env.Append(LINKFLAGS=string.split('-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'))
+ env.Append(LINKFLAGS=string.split('-Wl,-soname,libgodot_android.so -Wl,--gc-sections'))
if mt_link:
env.Append(LINKFLAGS=['-Wl,--threads'])
env.Append(LINKFLAGS=target_opts)
@@ -221,45 +226,12 @@ def configure(env):
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] +
'/toolchains/arm-linux-androideabi-4.9/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib'])
- if (env["target"].startswith("release")):
- env.Append(LINKFLAGS=['-O2'])
- env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math',
- '-funsafe-math-optimizations', '-fomit-frame-pointer'])
- if (can_vectorize):
- env.Append(CPPFLAGS=['-ftree-vectorize'])
- if (env["target"] == "release_debug"):
- env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
- elif (env["target"] == "debug"):
- env.Append(LINKFLAGS=['-O0'])
- env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED',
- '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info'])
-
- env.Append(CPPFLAGS=['-DANDROID_ENABLED',
- '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT'])
+ env.Append(CPPPATH=['#platform/android'])
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT'])
+ env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z'])
# TODO: Move that to opus module's config
if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"):
if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"):
env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
env.opus_fixed_point = "yes"
-
- if (env['android_stl'] == 'yes'):
- env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] +
- "/sources/cxx-stl/gnu-libstdc++/4.9/include"])
- env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] +
- "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"])
- env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] +
- "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath])
- env.Append(LIBS=["gnustl_static"])
- else:
- env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST'])
-
- import methods
- env.Append(BUILDERS={'GLSL120': env.Builder(
- action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(
- action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(
- action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
-
- env.use_windows_spawn_fix()
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index a72e8aa90..a722cd1b8 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -31,13 +31,13 @@
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
-#include "global_config.h"
#include "io/marshalls.h"
#include "io/zip_io.h"
#include "os/file_access.h"
#include "os/os.h"
#include "platform/android/logo.gen.h"
#include "platform/android/run_icon.gen.h"
+#include "project_settings.h"
#include "version.h"
#include <string.h>
#if 0
@@ -554,9 +554,9 @@ void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) {
} else {
String lang = str.substr(str.find_last("-")+1,str.length()).replace("-","_");
- String prop = "application/name_"+lang;
- if (GlobalConfig::get_singleton()->has(prop)) {
- str = GlobalConfig::get_singleton()->get(prop);
+ String prop = "application/config/name_"+lang;
+ if (ProjectSettings::get_singleton()->has(prop)) {
+ str = ProjectSettings::get_singleton()->get(prop);
} else {
str = get_project_name();
}
@@ -628,7 +628,7 @@ String EditorExportPlatformAndroid::get_project_name() const {
if (this->name!="") {
aname=this->name;
} else {
- aname = GlobalConfig::get_singleton()->get("application/name");
+ aname = ProjectSettings::get_singleton()->get("application/config/name");
}
@@ -1144,7 +1144,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
if (!found) {
- String appicon = GlobalConfig::get_singleton()->get("application/icon");
+ String appicon = ProjectSettings::get_singleton()->get("application/config/icon");
if (appicon!="" && appicon.ends_with(".png")) {
FileAccess*f = FileAccess::open(appicon,FileAccess::READ);
if (f) {
@@ -1763,7 +1763,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) {
String EditorExportPlatformAndroid::get_package_name() {
String pname = package;
- String basename = GlobalConfig::get_singleton()->get("application/name");
+ String basename = ProjectSettings::get_singleton()->get("application/config/name");
basename=basename.to_lower();
String name;
@@ -2050,6 +2050,7 @@ class EditorExportAndroid : public EditorExportPlatform {
String id;
String name;
String description;
+ int release;
};
struct APKExportData {
@@ -2123,6 +2124,7 @@ class EditorExportAndroid : public EditorExportPlatform {
if (ea->devices[j].id == ldevices[i]) {
d.description = ea->devices[j].description;
d.name = ea->devices[j].name;
+ d.release = ea->devices[j].release;
}
}
@@ -2143,6 +2145,7 @@ class EditorExportAndroid : public EditorExportPlatform {
String vendor;
String device;
d.description + "Device ID: " + d.id + "\n";
+ d.release = 0;
for (int j = 0; j < props.size(); j++) {
String p = props[j];
@@ -2153,7 +2156,9 @@ class EditorExportAndroid : public EditorExportPlatform {
} else if (p.begins_with("ro.build.display.id=")) {
d.description += "Build: " + p.get_slice("=", 1).strip_edges() + "\n";
} else if (p.begins_with("ro.build.version.release=")) {
- d.description += "Release: " + p.get_slice("=", 1).strip_edges() + "\n";
+ const String release_str = p.get_slice("=", 1).strip_edges();
+ d.description += "Release: " + release_str + "\n";
+ d.release = release_str.to_int();
} else if (p.begins_with("ro.product.cpu.abi=")) {
d.description += "CPU: " + p.get_slice("=", 1).strip_edges() + "\n";
} else if (p.begins_with("ro.product.manufacturer=")) {
@@ -2208,7 +2213,7 @@ class EditorExportAndroid : public EditorExportPlatform {
if (p_name != "") {
aname = p_name;
} else {
- aname = GlobalConfig::get_singleton()->get("application/name");
+ aname = ProjectSettings::get_singleton()->get("application/config/name");
}
if (aname == "") {
@@ -2221,7 +2226,7 @@ class EditorExportAndroid : public EditorExportPlatform {
String get_package_name(const String &p_package) {
String pname = p_package;
- String basename = GlobalConfig::get_singleton()->get("application/name");
+ String basename = ProjectSettings::get_singleton()->get("application/config/name");
basename = basename.to_lower();
String name;
@@ -2537,6 +2542,10 @@ class EditorExportAndroid : public EditorExportPlatform {
}*/
}
+ if (tname == "uses-feature" && /*nspace=="android" &&*/ attrname == "glEsVersion") {
+ print_line("version number: " + itos(decode_uint32(&p_manifest[iofs + 16])));
+ }
+
if (tname == "uses-permission" && /*nspace=="android" &&*/ attrname == "name") {
if (value.begins_with("godot.custom")) {
@@ -2750,9 +2759,9 @@ class EditorExportAndroid : public EditorExportPlatform {
} else {
String lang = str.substr(str.find_last("-") + 1, str.length()).replace("-", "_");
- String prop = "application/name_" + lang;
- if (GlobalConfig::get_singleton()->has(prop)) {
- str = GlobalConfig::get_singleton()->get(prop);
+ String prop = "application/config/name_" + lang;
+ if (ProjectSettings::get_singleton()->has(prop)) {
+ str = ProjectSettings::get_singleton()->get(prop);
} else {
str = get_project_name(package_name);
}
@@ -2826,11 +2835,17 @@ public:
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- r_features->push_back("etc");
+ int api = p_preset->get("graphics/api");
+ if (api == 0)
+ r_features->push_back("etc");
+ else
+ r_features->push_back("etc2");
}
virtual void get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/api", PROPERTY_HINT_ENUM, "OpenGL ES 2.0,OpenGL ES 3.0"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "apk"), ""));
@@ -2843,7 +2858,6 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architecture/arm"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architecture/x86"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/use_32_bits_view"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
@@ -2875,6 +2889,11 @@ public:
virtual String get_name() const {
return "Android";
}
+
+ virtual String get_os_name() const {
+ return "Android";
+ }
+
virtual Ref<Texture> get_logo() const {
return logo;
}
@@ -2991,15 +3010,19 @@ public:
if (use_adb_over_usb) {
args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
args.push_back("reverse");
args.push_back("--remove-all");
err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
- int port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
args.push_back("reverse");
- args.push_back("tcp:" + itos(port));
- args.push_back("tcp:" + itos(port));
+ args.push_back("tcp:" + itos(dbg_port));
+ args.push_back("tcp:" + itos(dbg_port));
err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
print_line("Reverse result: " + itos(rv));
@@ -3007,6 +3030,8 @@ public:
int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
args.push_back("reverse");
args.push_back("tcp:" + itos(fs_port));
args.push_back("tcp:" + itos(fs_port));
@@ -3022,7 +3047,10 @@ public:
args.push_back("shell");
args.push_back("am");
args.push_back("start");
- args.push_back("--user 0");
+ if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].release >= 17) { // Multi-user introduced in Android 17
+ args.push_back("--user");
+ args.push_back("0");
+ }
args.push_back("-a");
args.push_back("android.intent.action.MAIN");
args.push_back("-n");
@@ -3030,7 +3058,7 @@ public:
err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
if (err || rv != 0) {
- EditorNode::add_io_error("Could not execute ondevice.");
+ EditorNode::add_io_error("Could not execute on device.");
device_lock->unlock();
return ERR_CANT_CREATE;
}
@@ -3219,7 +3247,7 @@ public:
if (!found) {
- String appicon = GlobalConfig::get_singleton()->get("application/icon");
+ String appicon = ProjectSettings::get_singleton()->get("application/config/icon");
if (appicon != "" && appicon.ends_with(".png")) {
FileAccess *f = FileAccess::open(appicon, FileAccess::READ);
if (f) {
@@ -3527,6 +3555,12 @@ public:
return OK;
}
+ virtual void get_platform_features(List<String> *r_features) {
+
+ r_features->push_back("mobile");
+ r_features->push_back("Android");
+ }
+
EditorExportAndroid() {
Ref<Image> img = memnew(Image(_android_logo));
@@ -3566,6 +3600,7 @@ void register_android_exporter() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "keystore"));
EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey");
EDITOR_DEF("export/android/debug_keystore_pass", "android");
+ EDITOR_DEF("export/android/force_system_user", false);
EDITOR_DEF("export/android/timestamping_authority_url", "");
EDITOR_DEF("export/android/use_remote_debug_over_adb", false);
diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp
index f708ad5dd..6bdc6b337 100644
--- a/platform/android/globals/global_defaults.cpp
+++ b/platform/android/globals/global_defaults.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "global_defaults.h"
-#include "global_config.h"
+#include "project_settings.h"
void register_android_global_defaults() {
@@ -37,6 +37,6 @@ void register_android_global_defaults() {
GLOBAL_DEF("display.Android/driver","GLES2");
//GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false);
- GlobalConfig::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2"));
+ ProjectSettings::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2"));
*/
}
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
index 3a21f9212..71db03049 100644
--- a/platform/android/godot_android.cpp
+++ b/platform/android/godot_android.cpp
@@ -36,9 +36,9 @@
#include <GLES2/gl2.h>
#include "file_access_android.h"
-#include "global_config.h"
#include "main/main.h"
#include "os_android.h"
+#include "project_settings.h"
#include <android/log.h>
#include <android/sensor.h>
#include <android/window.h>
@@ -623,7 +623,7 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
#else
Error err = Main::setup("apk", 0, NULL);
- String modules = GlobalConfig::get_singleton()->get("android/modules");
+ String modules = ProjectSettings::get_singleton()->get("android/modules");
Vector<String> mods = modules.split(",", false);
mods.push_back("GodotOS");
__android_log_print(ANDROID_LOG_INFO, "godot", "mod count: %i", mods.size());
@@ -859,7 +859,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv
s->set_instance(env->NewGlobalRef(p_object));
jni_singletons[singname] = s;
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname, s));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton(singname, s));
}
static Variant::Type get_jni_type(const String &p_type) {
@@ -926,7 +926,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv *env
String js = env->GetStringUTFChars(path, NULL);
- return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data());
+ return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index 88928089b..d620b2b9c 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -273,7 +273,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this);
layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
- setKeepScreenOn(GodotLib.getGlobal("display/keep_screen_on").equals("True"));
+ setKeepScreenOn(GodotLib.getGlobal("display/driver/keep_screen_on").equals("True"));
edittext.setView(mView);
io.setEdit(edittext);
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index d4bd44368..0508989d2 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -36,11 +36,11 @@
#include "dir_access_jandroid.h"
#include "file_access_android.h"
#include "file_access_jandroid.h"
-#include "global_config.h"
#include "java_class_wrapper.h"
#include "main/input_default.h"
#include "main/main.h"
#include "os_android.h"
+#include "project_settings.h"
#include "thread_jandroid.h"
#include <unistd.h>
@@ -883,7 +883,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
__android_log_print(ANDROID_LOG_INFO, "godot", "*****SETUP OK");
//video driver is determined here, because once initialized, it can't be changed
- String vd = GlobalConfig::get_singleton()->get("display/driver");
+ String vd = ProjectSettings::get_singleton()->get("display/driver");
env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean) true);
@@ -930,12 +930,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, job
static void _initialize_java_modules() {
- if (!GlobalConfig::get_singleton()->has("android/modules")) {
+ if (!ProjectSettings::get_singleton()->has("android/modules")) {
print_line("ANDROID MODULES: Nothing to load, aborting");
return;
}
- String modules = GlobalConfig::get_singleton()->get("android/modules");
+ String modules = ProjectSettings::get_singleton()->get("android/modules");
modules = modules.strip_edges();
if (modules == String()) {
return;
@@ -1005,7 +1005,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
// because of the way android forces you to do everything with threads
java_class_wrapper = memnew(JavaClassWrapper(_godot_instance));
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("JavaClassWrapper", java_class_wrapper));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper));
_initialize_java_modules();
Main::setup2();
@@ -1504,8 +1504,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env
s->set_instance(env->NewGlobalRef(p_object));
jni_singletons[singname] = s;
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname, s));
- GlobalConfig::get_singleton()->set(singname, s);
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton(singname, s));
+ ProjectSettings::get_singleton()->set(singname, s);
}
static Variant::Type get_jni_type(const String &p_type) {
@@ -1578,7 +1578,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *
String js = env->GetStringUTFChars(path, NULL);
- return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data());
+ return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 9010b9e7d..ad46ceb43 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "os_android.h"
-#include "core/global_config.h"
#include "core/io/file_access_buffered_fa.h"
+#include "core/project_settings.h"
#include "drivers/gles3/rasterizer_gles3.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
@@ -677,7 +677,7 @@ String OS_Android::get_data_dir() const {
}
return ".";
- //return GlobalConfig::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
+ //return ProjectSettings::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
}
void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
@@ -741,6 +741,10 @@ String OS_Android::get_joy_guid(int p_device) const {
return input->get_joy_guid_remapped(p_device);
}
+bool OS_Android::_check_internal_feature_support(const String &p_feature) {
+ return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected
+}
+
OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) {
use_apk_expansion = p_use_apk_expansion;
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 897c71a7d..393bc68d8 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -243,6 +243,7 @@ public:
virtual String get_joy_guid(int p_device) const;
void joy_connection_changed(int p_device, bool p_connected, String p_name);
+ virtual bool _check_internal_feature_support(const String &p_feature);
OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion);
~OS_Android();
};
diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp
index 9c4f6d3ab..93351e079 100644
--- a/platform/haiku/audio_driver_media_kit.cpp
+++ b/platform/haiku/audio_driver_media_kit.cpp
@@ -31,7 +31,7 @@
#ifdef MEDIA_KIT_ENABLED
-#include "global_config.h"
+#include "project_settings.h"
int32_t *AudioDriverMediaKit::samples_in = NULL;
diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py
index 54e227cd1..c0e003a3d 100644
--- a/platform/haiku/detect.py
+++ b/platform/haiku/detect.py
@@ -11,57 +11,58 @@ def get_name():
def can_build():
- if (os.name != "posix"):
- return False
- if (sys.platform == "darwin"):
+ if (os.name != "posix" or sys.platform == "darwin"):
return False
return True
def get_opts():
+
return [
('debug_release', 'Add debug symbols to release version', 'no')
]
def get_flags():
+
return [
]
def configure(env):
- is64 = sys.maxsize > 2**32
-
- if (env["bits"] == "default"):
- if (is64):
- env["bits"] = "64"
- else:
- env["bits"] = "32"
-
- env.Append(CPPPATH=['#platform/haiku'])
- env["CC"] = "gcc-x86"
- env["CXX"] = "g++-x86"
+ ## Build type
if (env["target"] == "release"):
if (env["debug_release"] == "yes"):
- env.Append(CCFLAGS=['-g2'])
+ env.Prepend(CCFLAGS=['-g2'])
else:
- env.Append(CCFLAGS=['-O3', '-ffast-math'])
+ env.Prepend(CCFLAGS=['-O3', '-ffast-math'])
+
elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
+
elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+
+ ## Architecture
+
+ is64 = sys.maxsize > 2**32
+ if (env["bits"] == "default"):
+ env["bits"] = "64" if is64 else "32"
+
+ ## Compiler configuration
+ env["CC"] = "gcc-x86"
+ env["CXX"] = "g++-x86"
+
+ ## Flags
+
+ env.Append(CPPPATH=['#platform/haiku'])
+ env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
+ env.Append(CPPFLAGS=['-DMEDIA_KIT_ENABLED'])
# env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
env.Append(CPPFLAGS=['-DPTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np
- env.Append(CPPFLAGS=['-DOPENGL_ENABLED', '-DMEDIA_KIT_ENABLED'])
- env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
env.Append(LIBS=['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL'])
-
- import methods
- env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index 3131f2bf1..e897d4c38 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -331,3 +331,8 @@ void OS_Haiku::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) c
String OS_Haiku::get_executable_path() const {
return OS::get_executable_path();
}
+
+bool OS_Haiku::_check_internal_feature_support(const String &p_feature) {
+
+ return p_feature == "pc" || p_feature == "s3tc";
+}
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index 83e44734a..256c9eecf 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -120,6 +120,8 @@ public:
virtual PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
+
+ virtual bool _check_internal_feature_support(const String &p_feature);
};
#endif
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index 466b8241d..998d0a3f0 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -17,17 +17,8 @@ iphone_lib = [
'ios.mm',
]
-# env.Depends('#core/math/vector3.h', 'vector3_psp.h')
-
-#iphone_lib = env.Library('iphone', iphone_lib)
-
env_ios = env.Clone()
-
-if env['ios_gles22_override'] == "yes":
- env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE'])
-
-
obj = env_ios.Object('godot_iphone.cpp')
prog = None
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index 1f81f0f86..da6dfcf53 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -29,11 +29,11 @@
/*************************************************************************/
#import "app_delegate.h"
-#include "core/global_config.h"
+#include "audio_driver_iphone.h"
+#include "core/project_settings.h"
#import "gl_view.h"
#include "main/main.h"
#include "os_iphone.h"
-#include "audio_driver_iphone.h"
#ifdef MODULE_FACEBOOKSCORER_IOS_ENABLED
#include "modules/FacebookScorer_ios/FacebookScorer.h"
@@ -449,14 +449,14 @@ static int frame_count = 0;
NSString *str = (NSString *)value;
String uval = String::utf8([str UTF8String]);
- GlobalConfig::get_singleton()->set("Info.plist/" + ukey, uval);
+ ProjectSettings::get_singleton()->set("Info.plist/" + ukey, uval);
} else if ([value isKindOfClass:[NSNumber class]]) {
NSNumber *n = (NSNumber *)value;
double dval = [n doubleValue];
- GlobalConfig::get_singleton()->set("Info.plist/" + ukey, dval);
+ ProjectSettings::get_singleton()->set("Info.plist/" + ukey, dval);
};
// do stuff
}
@@ -615,7 +615,7 @@ static int frame_count = 0;
view_controller.view = glView;
window.rootViewController = view_controller;
- _set_keep_screen_on(bool(GLOBAL_DEF("display/keep_screen_on", true)) ? YES : NO);
+ _set_keep_screen_on(bool(GLOBAL_DEF("display/window/keep_screen_on", true)) ? YES : NO);
glView.useCADisplayLink =
bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO;
printf("cadisaplylink: %d", glView.useCADisplayLink);
@@ -645,10 +645,10 @@ static int frame_count = 0;
#ifdef MODULE_GAME_ANALYTICS_ENABLED
printf("********************* didFinishLaunchingWithOptions\n");
- if (!GlobalConfig::get_singleton()->has("mobileapptracker/advertiser_id")) {
+ if (!ProjectSettings::get_singleton()->has("mobileapptracker/advertiser_id")) {
return;
}
- if (!GlobalConfig::get_singleton()->has("mobileapptracker/conversion_key")) {
+ if (!ProjectSettings::get_singleton()->has("mobileapptracker/conversion_key")) {
return;
}
@@ -673,7 +673,6 @@ static int frame_count = 0;
isAdvertisingTrackingEnabled]];
#endif
-
};
- (void)applicationWillTerminate:(UIApplication *)application {
@@ -737,7 +736,7 @@ static int frame_count = 0;
};
// Fixed audio can not resume if it is interrupted cause by an incoming phone call
- if(AudioDriverIphone::get_singleton() != NULL)
+ if (AudioDriverIphone::get_singleton() != NULL)
AudioDriverIphone::get_singleton()->start();
}
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index c20d8e90f..1d802ff28 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -1,4 +1,5 @@
import os
+import string
import sys
@@ -12,8 +13,6 @@ def get_name():
def can_build():
- import sys
- import os
if sys.platform == 'darwin' or os.environ.has_key("OSXCROSS_IOS"):
return True
@@ -23,13 +22,12 @@ def can_build():
def get_opts():
return [
- ('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'),
- ('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
- ('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${IPHONEPLATFORM}.platform/Developer/SDKs/${IPHONEPLATFORM}.sdk/'),
+ ('IPHONEPLATFORM', 'Name of the iPhone platform', 'iPhoneOS'),
+ ('IPHONEPATH', 'Path to iPhone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
+ ('IPHONESDK', 'Path to the iPhone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${IPHONEPLATFORM}.platform/Developer/SDKs/${IPHONEPLATFORM}.sdk/'),
('game_center', 'Support for game center', 'yes'),
('store_kit', 'Support for in-app store', 'yes'),
('icloud', 'Support for iCloud', 'yes'),
- ('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
('ios_exceptions', 'Enable exceptions', 'no'),
('ios_triple', 'Triple for ios toolchain', ''),
('ios_sim', 'Build simulator binary', 'no'),
@@ -45,95 +43,92 @@ def get_flags():
def configure(env):
- env.Append(CPPPATH=['#platform/iphone'])
+ ## Build type
- env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
+ if (env["target"].startswith("release")):
+ env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1'])
+ env.Append(CPPFLAGS=['-O2', '-flto', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations'])
+ env.Append(LINKFLAGS=['-O2', '-flto'])
- env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang'
- env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++'
- env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar'
- env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib'
+ if env["target"] == "release_debug":
+ env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
+
+ elif (env["target"] == "debug"):
+ env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+
+ ## Architecture
- import string
if (env["ios_sim"] == "yes" or env["arch"] == "x86"): # i386, simulator
env["arch"] = "x86"
env["bits"] = "32"
- env.Append(CCFLAGS=string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"'))
elif (env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32"): # arm
env["arch"] = "arm"
env["bits"] = "32"
- env.Append(CCFLAGS=string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies'))
else: # armv64
env["arch"] = "arm64"
env["bits"] = "64"
+
+ ## Compiler configuration
+
+ env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
+
+ env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang'
+ env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++'
+ env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar'
+ env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib'
+ env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc'
+
+ ## Compile flags
+
+ if (env["arch"] == "x86"):
+ env['IPHONEPLATFORM'] = 'iPhoneSimulator'
+ env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
+ env.Append(CCFLAGS=string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"'))
+ elif (env["arch"] == "arm"):
+ env.Append(CCFLAGS=string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies'))
+ elif (env["arch"] == "arm64"):
env.Append(CCFLAGS=string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=9.0 -isysroot $IPHONESDK'))
env.Append(CPPFLAGS=['-DNEED_LONG_INT'])
env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON'])
+ if env['ios_exceptions'] == 'yes':
+ env.Append(CPPFLAGS=['-fexceptions'])
+ else:
+ env.Append(CPPFLAGS=['-fno-exceptions'])
+
+ ## Link flags
+
if (env["arch"] == "x86"):
- env['IPHONEPLATFORM'] = 'iPhoneSimulator'
env.Append(LINKFLAGS=['-arch', 'i386', '-mios-simulator-version-min=4.3',
'-isysroot', '$IPHONESDK',
- #'-mmacosx-version-min=10.6',
'-Xlinker',
'-objc_abi_version',
'-Xlinker', '2',
- '-framework', 'AudioToolbox',
- '-framework', 'AVFoundation',
- '-framework', 'CoreAudio',
- '-framework', 'CoreGraphics',
- '-framework', 'CoreMedia',
- '-framework', 'CoreMotion',
- '-framework', 'Foundation',
- '-framework', 'Security',
- '-framework', 'UIKit',
- '-framework', 'MediaPlayer',
- '-framework', 'OpenGLES',
- '-framework', 'QuartzCore',
- '-framework', 'SystemConfiguration',
- '-framework', 'GameController',
'-F$IPHONESDK',
])
- elif (env["arch"] == "arm64"):
- env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0',
- '-isysroot', '$IPHONESDK',
- #'-stdlib=libc++',
- '-framework', 'Foundation',
- '-framework', 'UIKit',
- '-framework', 'CoreGraphics',
- '-framework', 'OpenGLES',
- '-framework', 'QuartzCore',
- '-framework', 'CoreAudio',
- '-framework', 'AudioToolbox',
- '-framework', 'SystemConfiguration',
- '-framework', 'Security',
- #'-framework', 'AdSupport',
- '-framework', 'MediaPlayer',
- '-framework', 'AVFoundation',
- '-framework', 'CoreMedia',
- '-framework', 'CoreMotion',
- '-framework', 'GameController',
- ])
- else:
- env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0',
- '-isysroot', '$IPHONESDK',
- '-framework', 'Foundation',
- '-framework', 'UIKit',
- '-framework', 'CoreGraphics',
- '-framework', 'OpenGLES',
- '-framework', 'QuartzCore',
- '-framework', 'CoreAudio',
- '-framework', 'AudioToolbox',
- '-framework', 'SystemConfiguration',
- '-framework', 'Security',
- #'-framework', 'AdSupport',
- '-framework', 'MediaPlayer',
- '-framework', 'AVFoundation',
- '-framework', 'CoreMedia',
- '-framework', 'CoreMotion',
- '-framework', 'GameController',
- ])
+ elif (env["arch"] == "arm"):
+ env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0'])
+ if (env["arch"] == "arm64"):
+ env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0'])
+
+ env.Append(LINKFLAGS=['-isysroot', '$IPHONESDK',
+ '-framework', 'AudioToolbox',
+ '-framework', 'AVFoundation',
+ '-framework', 'CoreAudio',
+ '-framework', 'CoreGraphics',
+ '-framework', 'CoreMedia',
+ '-framework', 'CoreMotion',
+ '-framework', 'Foundation',
+ '-framework', 'GameController',
+ '-framework', 'MediaPlayer',
+ '-framework', 'OpenGLES',
+ '-framework', 'QuartzCore',
+ '-framework', 'Security',
+ '-framework', 'SystemConfiguration',
+ '-framework', 'UIKit',
+ ])
+ # Feature options
if env['game_center'] == 'yes':
env.Append(CPPFLAGS=['-DGAME_CENTER_ENABLED'])
env.Append(LINKFLAGS=['-framework', 'GameKit'])
@@ -145,45 +140,20 @@ def configure(env):
if env['icloud'] == 'yes':
env.Append(CPPFLAGS=['-DICLOUD_ENABLED'])
- env.Append(CPPPATH=['$IPHONESDK/usr/include', '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers'])
+ env.Append(CPPPATH=['$IPHONESDK/usr/include',
+ '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers',
+ '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers',
+ ])
- if (env["target"].startswith("release")):
-
- env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1'])
- env.Append(CPPFLAGS=['-O2', '-flto', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations'])
- env.Append(LINKFLAGS=['-O2', '-flto'])
-
- if env["target"] == "release_debug":
- env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
-
- elif (env["target"] == "debug"):
-
- env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED'])
- env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ENABLED'])
-
- if (env["ios_sim"] == "yes"): # TODO: Check if needed?
- env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
+
+ env.Append(CPPPATH=['#platform/iphone'])
env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DMPC_FIXED_POINT'])
# TODO: Move that to opus module's config
if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"):
env.opus_fixed_point = "yes"
- if env["arch"] == "x86":
- pass
- elif(env["arch"] == "arm64"):
- env.Append(CFLAGS=["-DOPUS_ARM64_OPT"])
- else:
+ if (env["arch"] == "arm"):
env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
-
- if env['ios_exceptions'] == 'yes':
- env.Append(CPPFLAGS=['-fexceptions'])
- else:
- env.Append(CPPFLAGS=['-fno-exceptions'])
- # env['neon_enabled']=True
- env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc'
-
- import methods
- env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
+ elif (env["arch"] == "arm64"):
+ env.Append(CFLAGS=["-DOPUS_ARM64_OPT"])
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
new file mode 100644
index 000000000..6ae2a0692
--- /dev/null
+++ b/platform/iphone/export/export.cpp
@@ -0,0 +1,366 @@
+/*************************************************************************/
+/* export.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 "export.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 EditorExportPlatformIOS : public EditorExportPlatform {
+
+ GDCLASS(EditorExportPlatformIOS, EditorExportPlatform);
+
+ int version_code;
+
+ Ref<ImageTexture> logo;
+
+ void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary);
+
+protected:
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
+ virtual void get_export_options(List<ExportOption> *r_options);
+
+public:
+ virtual String get_name() const { return "iOS"; }
+ virtual String get_os_name() const { return "iOS"; }
+ virtual Ref<Texture> get_logo() const { return logo; }
+
+ virtual String get_binary_extension() const { return "xcodeproj"; }
+ 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;
+
+ virtual void get_platform_features(List<String> *r_features) {
+
+ r_features->push_back("mobile");
+ r_features->push_back("iOS");
+ }
+
+ EditorExportPlatformIOS();
+ ~EditorExportPlatformIOS();
+};
+
+void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+
+ if (p_preset->get("texture_format/s3tc")) {
+ r_features->push_back("s3tc");
+ }
+ if (p_preset->get("texture_format/etc")) {
+ r_features->push_back("etc");
+ }
+ if (p_preset->get("texture_format/etc2")) {
+ r_features->push_back("etc2");
+ }
+}
+
+void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) {
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
+ // r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier"), "org.godotengine.iosgame"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "godotiosgame"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 1));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true));
+
+ /* probably need some more info */
+}
+
+void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary) {
+
+ String str;
+ String strnew;
+ str.parse_utf8((const char *)pfile.ptr(), pfile.size());
+ Vector<String> lines = str.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ if (lines[i].find("$binary") != -1) {
+ strnew += lines[i].replace("$binary", p_binary) + "\n";
+ } else if (lines[i].find("$name") != -1) {
+ strnew += lines[i].replace("$name", p_name) + "\n";
+ } else if (lines[i].find("$info") != -1) {
+ strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
+ } else if (lines[i].find("$identifier") != -1) {
+ strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\n";
+ } else if (lines[i].find("$short_version") != -1) {
+ strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
+ } else if (lines[i].find("$version") != -1) {
+ strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
+ } else if (lines[i].find("$signature") != -1) {
+ strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
+ } else if (lines[i].find("$copyright") != -1) {
+ strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
+ } else {
+ strnew += lines[i] + "\n";
+ }
+ }
+
+ // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero...
+ // should apply the same fix in our OSX export.
+ CharString cs = strnew.utf8();
+ pfile.resize(cs.size() - 1);
+ for (int i = 0; i < cs.size() - 1; i++) {
+ pfile[i] = cs[i];
+ }
+}
+
+Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ String src_pkg_name;
+ String dest_dir = p_path.get_base_dir() + "/";
+ String binary_name = p_path.get_file().get_basename();
+
+ EditorProgress ep("export", "Exporting for iOS", 3);
+
+ if (p_debug)
+ src_pkg_name = p_preset->get("custom_package/debug");
+ else
+ src_pkg_name = p_preset->get("custom_package/release");
+
+ if (src_pkg_name == "") {
+ String err;
+ src_pkg_name = find_export_template("iphone.zip", &err);
+ if (src_pkg_name == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ FileAccess *src_f = NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ ep.step("Creating app", 0);
+
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
+
+ EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(src_pkg_zip);
+
+ String binary_to_use = "godot.iphone." + String(p_debug ? "debug" : "release") + ".";
+ int bits_mode = p_preset->get("application/bits_mode");
+ binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "arm64" : "armv7");
+
+ print_line("binary: " + binary_to_use);
+ String pkg_name;
+ if (p_preset->get("application/name") != "")
+ pkg_name = p_preset->get("application/name"); // app_name
+ else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "")
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ else
+ pkg_name = "Unnamed";
+
+ DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir);
+ ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE)
+
+ /* Now process our template */
+ bool found_binary = false;
+ int total_size = 0;
+
+ while (ret == UNZ_OK) {
+ bool is_execute = false;
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
+
+ String file = fname;
+
+ print_line("READ: " + file);
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
+
+ //write
+
+ file = file.replace_first("iphone/", "");
+
+ if (file == "godot_ios.xcodeproj/project.pbxproj") {
+ print_line("parse pbxproj");
+ _fix_config_file(p_preset, data, pkg_name, binary_name);
+ } else if (file == "godot_ios/godot_ios-Info.plist") {
+ print_line("parse plist");
+ _fix_config_file(p_preset, data, pkg_name, binary_name);
+ } else if (file.begins_with("godot.iphone")) {
+ if (file != binary_to_use) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; //ignore!
+ }
+ found_binary = true;
+ is_execute = true;
+ file = "godot_ios.iphone";
+ }
+
+ ///@TODO need to parse logo files
+
+ if (data.size() > 0) {
+ file = file.replace("godot_ios", binary_name);
+
+ print_line("ADDING: " + file + " size: " + itos(data.size()));
+ total_size += data.size();
+
+ /* write it into our folder structure */
+ file = dest_dir + file;
+
+ /* make sure this folder exists */
+ String dir_name = file.get_base_dir();
+ if (!tmp_app_path->dir_exists(dir_name)) {
+ print_line("Creating " + dir_name);
+ Error dir_err = tmp_app_path->make_dir_recursive(dir_name);
+ if (dir_err) {
+ ERR_PRINTS("Can't create '" + dir_name + "'.");
+ unzClose(src_pkg_zip);
+ return ERR_CANT_CREATE;
+ }
+ }
+
+ /* write the file */
+ FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
+ if (!f) {
+ ERR_PRINTS("Can't write '" + file + "'.");
+ unzClose(src_pkg_zip);
+ return ERR_CANT_CREATE;
+ };
+ f->store_buffer(data.ptr(), data.size());
+ f->close();
+ memdelete(f);
+
+#ifdef OSX_ENABLED
+ if (is_execute) {
+ // we need execute rights on this file
+ chmod(file.utf8().get_data(), 0755);
+ }
+#endif
+ }
+
+ ret = unzGoToNextFile(src_pkg_zip);
+ }
+
+ /* we're done with our source zip */
+ unzClose(src_pkg_zip);
+
+ if (!found_binary) {
+ ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
+ unzClose(src_pkg_zip);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ep.step("Making PKG", 1);
+
+ String pack_path = dest_dir + binary_name + ".pck";
+ Error err = save_pack(p_preset, pack_path);
+
+ if (err) {
+ return err;
+ }
+
+#ifdef OSX_ENABLED
+ /* and open up xcode with our new project.... */
+ List<String> args;
+ args.push_back(p_path);
+ err = OS::get_singleton()->execute("/usr/bin/open", args, false);
+ ERR_FAIL_COND_V(err, err);
+
+#endif
+
+ return OK;
+}
+
+bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+
+ bool valid = true;
+ String err;
+
+ if (!exists_export_template("iphone.zip", &err)) {
+ valid = false;
+ }
+
+ if (p_preset->get("custom_package/debug") != "" && !FileAccess::exists(p_preset->get("custom_package/debug"))) {
+ valid = false;
+ err += "Custom debug package not found.\n";
+ }
+
+ if (p_preset->get("custom_package/release") != "" && !FileAccess::exists(p_preset->get("custom_package/release"))) {
+ valid = false;
+ err += "Custom release package not found.\n";
+ }
+
+ if (!err.empty())
+ r_error = err;
+
+ return valid;
+}
+
+EditorExportPlatformIOS::EditorExportPlatformIOS() {
+
+ ///@TODO need to create the correct logo
+ // Ref<Image> img = memnew(Image(_iphone_logo));
+ Ref<Image> img = memnew(Image(_osx_logo));
+ logo.instance();
+ logo->create_from_image(img);
+}
+
+EditorExportPlatformIOS::~EditorExportPlatformIOS() {
+}
+
+void register_iphone_exporter() {
+
+ Ref<EditorExportPlatformIOS> platform;
+ platform.instance();
+
+ EditorExport::get_singleton()->add_export_platform(platform);
+}
diff --git a/platform/iphone/export/export.h b/platform/iphone/export/export.h
new file mode 100644
index 000000000..6e9324aed
--- /dev/null
+++ b/platform/iphone/export/export.h
@@ -0,0 +1,30 @@
+/*************************************************************************/
+/* export.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+void register_iphone_exporter();
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
index 6270fa85f..f2778e816 100644
--- a/platform/iphone/gl_view.mm
+++ b/platform/iphone/gl_view.mm
@@ -29,8 +29,8 @@
/*************************************************************************/
#import "gl_view.h"
-#include "core/global_config.h"
#include "core/os/keyboard.h"
+#include "core/project_settings.h"
#include "os_iphone.h"
#include "servers/audio_server.h"
@@ -77,7 +77,7 @@ void _hide_keyboard() {
};
bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
- p_path = GlobalConfig::get_singleton()->globalize_path(p_path);
+ p_path = ProjectSettings::get_singleton()->globalize_path(p_path);
NSString *file_path = [[[NSString alloc] initWithUTF8String:p_path.utf8().get_data()] autorelease];
diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp
index b320be2f8..aa4662302 100644
--- a/platform/iphone/globals/global_defaults.cpp
+++ b/platform/iphone/globals/global_defaults.cpp
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "global_defaults.h"
-#include "global_config.h"
+#include "project_settings.h"
void register_iphone_global_defaults() {
/*GLOBAL_DEF("rasterizer.iOS/use_fragment_lighting",false);
GLOBAL_DEF("rasterizer.iOS/fp16_framebuffer",false);
GLOBAL_DEF("display.iOS/driver","GLES2");
- GlobalConfig::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
+ ProjectSettings::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
GLOBAL_DEF("display.iOS/use_cadisplaylink",true);
*/
}
diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm
index e9c164393..6c9590324 100644
--- a/platform/iphone/ios.mm
+++ b/platform/iphone/ios.mm
@@ -36,7 +36,7 @@ void iOS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rate_url", "app_id"), &iOS::get_rate_url);
};
-void iOS::alert(const char* p_alert, const char* p_title) {
+void iOS::alert(const char *p_alert, const char *p_title) {
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:[NSString stringWithUTF8String:p_title] message:[NSString stringWithUTF8String:p_alert] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] autorelease];
[alert show];
}
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index b244edbff..cb5c02276 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -38,10 +38,10 @@
#include "audio_driver_iphone.h"
#include "main/main.h"
-#include "core/global_config.h"
#include "core/io/file_access_pack.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
+#include "core/project_settings.h"
#include "sem_iphone.h"
@@ -109,7 +109,6 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
- RasterizerStorageGLES3::system_fbo = gl_view_base_fb;
visual_server = memnew(VisualServerRaster());
/*
@@ -122,6 +121,9 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_
visual_server->init();
visual_server->cursor_set_visible(false, 0);
+ // reset this to what it should be, it will have been set to 0 after visual_server->init() is called
+ RasterizerStorageGLES3::system_fbo = gl_view_base_fb;
+
audio_driver = memnew(AudioDriverIphone);
audio_driver->set_singleton();
audio_driver->init();
@@ -138,28 +140,28 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_
/*
#ifdef IOS_SCORELOOP_ENABLED
scoreloop = memnew(ScoreloopIOS);
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Scoreloop", scoreloop));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Scoreloop", scoreloop));
scoreloop->connect();
#endif
*/
#ifdef GAME_CENTER_ENABLED
game_center = memnew(GameCenter);
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("GameCenter", game_center));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("GameCenter", game_center));
game_center->connect();
#endif
#ifdef STOREKIT_ENABLED
store_kit = memnew(InAppStore);
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("InAppStore", store_kit));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("InAppStore", store_kit));
#endif
#ifdef ICLOUD_ENABLED
icloud = memnew(ICloud);
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("ICloud", icloud));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ICloud", icloud));
//icloud->connect();
#endif
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("iOS", memnew(iOS)));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("iOS", memnew(iOS)));
};
MainLoop *OSIPhone::get_main_loop() const {
@@ -434,7 +436,8 @@ bool OSIPhone::can_draw() const {
int OSIPhone::set_base_framebuffer(int p_fb) {
- RasterizerStorageGLES3::system_fbo = gl_view_base_fb;
+ // gl_view_base_fb has not been updated yet
+ RasterizerStorageGLES3::system_fbo = p_fb;
return 0;
};
@@ -517,7 +520,7 @@ Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_
print("Unable to play %S using the native player as it resides in a .pck file\n", p_path.c_str());
return ERR_INVALID_PARAMETER;
} else {
- p_path = p_path.replace("res:/", GlobalConfig::get_singleton()->get_resource_path());
+ p_path = p_path.replace("res:/", ProjectSettings::get_singleton()->get_resource_path());
}
} else if (p_path.begins_with("user://"))
p_path = p_path.replace("user:/", get_data_dir());
@@ -552,6 +555,11 @@ void OSIPhone::native_video_stop() {
_stop_video();
}
+bool OSIPhone::_check_internal_feature_support(const String &p_feature) {
+
+ return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2";
+}
+
OSIPhone::OSIPhone(int width, int height) {
main_loop = NULL;
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 4031b7524..b15e9fdff 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -200,6 +200,7 @@ public:
virtual void native_video_focus_out();
virtual void native_video_stop();
+ virtual bool _check_internal_feature_support(const String &p_feature);
OSIPhone(int width, int height);
~OSIPhone();
};
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 02ff2090f..b804863ee 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -19,29 +19,34 @@ javascript_objects = []
for x in javascript_files:
javascript_objects.append(env_javascript.Object(x))
-env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync']\""])
+env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync','_send_notification']\""])
env.Append(LINKFLAGS=["--shell-file", '"platform/javascript/godot_shell.html"'])
-html_file = env.Program('#bin/godot', javascript_objects, PROGSUFFIX=env["PROGSUFFIX"] + ".html")[0]
+# output file name without file extension
+basename = "godot" + env["PROGSUFFIX"]
+target_dir = env.Dir("#bin")
+js_file = target_dir.File(basename + ".js")
+implicit_targets = [js_file]
+
+zip_dir = target_dir.Dir('.javascript_zip')
+zip_files = env.InstallAs([zip_dir.File("godot.js"), zip_dir.File("godotfs.js")], [js_file, "#misc/dist/html_fs/godotfs.js"])
+
+if env['wasm'] == 'yes':
+ wasm_file = target_dir.File(basename+'.wasm')
+ implicit_targets.append(wasm_file)
+ zip_files.append(InstallAs(zip_dir.File('godot.wasm'), wasm_file))
+else:
+ asmjs_files = [target_dir.File(basename+'.asm.js'), target_dir.File(basename+'.html.mem')]
+ zip_files.append(InstallAs([zip_dir.File('godot.asm.js'), zip_dir.File('godot.mem')], asmjs_files))
+ implicit_targets.extend(asmjs_files)
+
+# HTML file must be the first target in the list
+html_file = env.Program(["#bin/godot"] + implicit_targets, javascript_objects, PROGSUFFIX=env["PROGSUFFIX"]+".html")[0]
Depends(html_file, "godot_shell.html")
-basename = "godot" + env["PROGSUFFIX"] # output file name without file extension
# Emscripten hardcodes file names, so replace common base name with
# placeholder while leaving extension; also change `.html.mem` to just `.mem`
fixup_html = env.Substfile(html_file, SUBST_DICT=[(basename, '$$GODOT_BASE'), ('.html.mem', '.mem')], SUBSTFILESUFFIX='.fixup.html')
-zip_dir = env.Dir('#bin/.javascript_zip')
-zip_files = []
-js_file = env.SideEffect(html_file.File(basename+'.js'), html_file)
-zip_files.append(env.InstallAs(
- [zip_dir.File('godot.html'), zip_dir.File('godot.js'), zip_dir.File('godotfs.js')],
- [fixup_html, js_file, '#misc/dist/html_fs/godotfs.js']))
-
-if env['wasm'] == 'yes':
- wasm_file = env.SideEffect(html_file.File(basename+'.wasm'), html_file)
- zip_files.append(env.InstallAs(zip_dir.File('godot.wasm'), wasm_file))
-else:
- asmjs_files = env.SideEffect([html_file.File(basename+'.asm.js'), html_file.File(basename+'.html.mem')], html_file)
- zip_files.append(env.InstallAs([zip_dir.File('godot.asm.js'), zip_dir.File('godot.mem')], asmjs_files))
-
-Zip('#bin/godot', zip_files, ZIPSUFFIX=env['PROGSUFFIX']+env['ZIPSUFFIX'], ZIPROOT=zip_dir)
+zip_files.append(InstallAs(zip_dir.File('godot.html'), fixup_html))
+Zip('#bin/godot', zip_files, ZIPSUFFIX=env['PROGSUFFIX']+env['ZIPSUFFIX'], ZIPROOT=zip_dir, ZIPCOMSTR="Archving $SOURCES as $TARGET")
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 41fe3fb02..68c8d1eea 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -1,6 +1,6 @@
import os
-import sys
import string
+import sys
def is_active():
@@ -12,7 +12,8 @@ def get_name():
def can_build():
- return os.environ.has_key("EMSCRIPTEN_ROOT")
+
+ return (os.environ.has_key("EMSCRIPTEN_ROOT"))
def get_opts():
@@ -27,12 +28,12 @@ def get_flags():
return [
('tools', 'no'),
- ('module_etc1_enabled', 'no'),
('module_theora_enabled', 'no'),
]
def create(env):
+
# remove Windows' .exe suffix
return env.Clone(tools=['textfile', 'zip'], PROGSUFFIX='')
@@ -45,10 +46,26 @@ def escape_target_backslashes(target, source, env, for_signature):
def configure(env):
- env['ENV'] = os.environ
- env.Append(CPPPATH=['#platform/javascript'])
+ ## Build type
+
+ if (env["target"] == "release"):
+ env.Append(CCFLAGS=['-O3'])
+ env.Append(LINKFLAGS=['-O3'])
+ elif (env["target"] == "release_debug"):
+ env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+ env.Append(LINKFLAGS=['-O2', '-s', 'ASSERTIONS=1'])
+ # retain function names at the cost of file size, for backtraces and profiling
+ env.Append(LINKFLAGS=['--profiling-funcs'])
+
+ elif (env["target"] == "debug"):
+ env.Append(CCFLAGS=['-O1', '-D_DEBUG', '-g', '-DDEBUG_ENABLED'])
+ env.Append(LINKFLAGS=['-O1', '-g'])
+
+ ## Compiler configuration
+
+ env['ENV'] = os.environ
env.PrependENVPath('PATH', os.environ['EMSCRIPTEN_ROOT'])
env['CC'] = 'emcc'
env['CXX'] = 'em++'
@@ -57,6 +74,7 @@ def configure(env):
# Emscripten's ar has issues with duplicate file names, so use cc
env['AR'] = 'emcc'
env['ARFLAGS'] = '-o'
+
if (os.name == 'nt'):
# use TempFileMunge on Windows since some commands get too long for
# cmd.exe even with spawn_fix
@@ -68,26 +86,20 @@ def configure(env):
env['OBJSUFFIX'] = '.bc'
env['LIBSUFFIX'] = '.bc'
- if (env["target"] == "release"):
- env.Append(CCFLAGS=['-O3'])
- env.Append(LINKFLAGS=['-O3'])
- elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
- env.Append(LINKFLAGS=['-O2', '-s', 'ASSERTIONS=1'])
- # retain function names at the cost of file size, for backtraces and profiling
- env.Append(LINKFLAGS=['--profiling-funcs'])
- elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-O1', '-D_DEBUG', '-g', '-DDEBUG_ENABLED'])
- env.Append(LINKFLAGS=['-O1', '-g'])
+ ## Compile flags
- # TODO: Move that to opus module's config
- if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"):
- env.opus_fixed_point = "yes"
+ env.Append(CPPPATH=['#platform/javascript'])
+ env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DTYPED_METHOD_BIND', '-DNO_THREADS'])
+ env.Append(CPPFLAGS=['-DGLES3_ENABLED'])
# These flags help keep the file size down
env.Append(CPPFLAGS=["-fno-exceptions", '-DNO_SAFE_CAST', '-fno-rtti'])
- env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DTYPED_METHOD_BIND', '-DNO_THREADS'])
- env.Append(CPPFLAGS=['-DGLES3_ENABLED'])
+
+ if env['javascript_eval'] == 'yes':
+ env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED'])
+
+ ## Link flags
+
env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1'])
if (env['wasm'] == 'yes'):
@@ -101,8 +113,6 @@ def configure(env):
env.Append(LINKFLAGS=['-s', 'ASM_JS=1'])
env.Append(LINKFLAGS=['--separate-asm'])
- if env['javascript_eval'] == 'yes':
- env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED'])
-
-
- import methods
+ # TODO: Move that to opus module's config
+ if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"):
+ env.opus_fixed_point = "yes"
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 4bdfdae39..b436d5236 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -61,6 +61,7 @@ public:
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual String get_name() const;
+ virtual String get_os_name() const;
virtual Ref<Texture> get_logo() const;
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
@@ -74,6 +75,12 @@ public:
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags);
virtual Ref<Texture> get_run_icon() const;
+ virtual void get_platform_features(List<String> *r_features) {
+
+ r_features->push_back("web");
+ r_features->push_back("JavaScript");
+ }
+
EditorExportPlatformJavaScript();
};
@@ -167,6 +174,11 @@ String EditorExportPlatformJavaScript::get_name() const {
return "HTML5";
}
+String EditorExportPlatformJavaScript::get_os_name() const {
+
+ return "JavaScript";
+}
+
Ref<Texture> EditorExportPlatformJavaScript::get_logo() const {
return logo;
diff --git a/platform/javascript/godot_shell.html b/platform/javascript/godot_shell.html
index 6c7069a8f..ee7399a12 100644
--- a/platform/javascript/godot_shell.html
+++ b/platform/javascript/godot_shell.html
@@ -83,6 +83,10 @@
color: white;
}
+ #canvas:focus {
+ outline: none;
+ }
+
/* Status display
* ============== */
@@ -147,7 +151,7 @@ $GODOT_HEAD_INCLUDE
</head>
<body>
<div id="container">
- <canvas id="canvas" width="640" height="480" onclick="canvas.ownerDocument.defaultView.focus();" oncontextmenu="event.preventDefault();">
+ <canvas id="canvas" width="640" height="480" tabindex="0" oncontextmenu="event.preventDefault();">
HTML5 canvas appears to be unsupported in the current browser.<br />
Please try updating or use a different browser.
</canvas>
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 9df26f147..0708d4619 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "os_javascript.h"
-#include "core/global_config.h"
#include "core/io/file_access_buffered_fa.h"
+#include "core/project_settings.h"
#include "dom_keys.h"
#include "drivers/gles3/rasterizer_gles3.h"
#include "drivers/unix/dir_access_unix.h"
@@ -145,6 +145,31 @@ static EM_BOOL _fullscreen_change_callback(int event_type, const EmscriptenFulls
static InputDefault *_input;
+static bool is_canvas_focused() {
+
+ /* clang-format off */
+ return EM_ASM_INT_V(
+ return document.activeElement == Module.canvas;
+ );
+ /* clang-format on */
+}
+
+static void focus_canvas() {
+
+ /* clang-format off */
+ EM_ASM(
+ Module.canvas.focus();
+ );
+ /* clang-format on */
+}
+
+static bool _cursor_inside_canvas = true;
+
+static bool is_cursor_inside_canvas() {
+
+ return _cursor_inside_canvas;
+}
+
static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data) {
ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEDOWN && event_type != EMSCRIPTEN_EVENT_MOUSEUP, false);
@@ -164,26 +189,42 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent
}
int mask = _input->get_mouse_button_mask();
- if (ev->is_pressed())
+ if (ev->is_pressed()) {
+ // since the event is consumed, focus manually
+ if (!is_canvas_focused()) {
+ focus_canvas();
+ }
mask |= 1 << ev->get_button_index();
- else
+ } else if (mask & (1 << ev->get_button_index())) {
mask &= ~(1 << ev->get_button_index());
+ } else {
+ // release event, but press was outside the canvas, so ignore
+ return false;
+ }
ev->set_button_mask(mask >> 1);
_input->parse_input_event(ev);
+ // prevent selection dragging
return true;
}
static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data) {
ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEMOVE, false);
+ OS_JavaScript *os = static_cast<OS_JavaScript *>(user_data);
+ int input_mask = _input->get_mouse_button_mask();
+ Point2 pos = Point2(mouse_event->canvasX, mouse_event->canvasY);
+ // outside the canvas, only read mouse movement if dragging started inside
+ // the canvas; imitating desktop app behaviour
+ if (!is_cursor_inside_canvas() && !input_mask)
+ return false;
Ref<InputEventMouseMotion> ev;
ev.instance();
dom2godot_mod(mouse_event, ev);
- ev->set_button_mask(_input->get_mouse_button_mask() >> 1);
+ ev->set_button_mask(input_mask >> 1);
- ev->set_position(Point2(mouse_event->canvasX, mouse_event->canvasY));
+ ev->set_position(pos);
ev->set_global_position(ev->get_position());
ev->set_relative(_input->get_mouse_position() - ev->get_position());
@@ -191,12 +232,20 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m
ev->set_speed(_input->get_last_mouse_speed());
_input->parse_input_event(ev);
- return true;
+ // don't suppress mouseover/leave events
+ return false;
}
static EM_BOOL _wheel_callback(int event_type, const EmscriptenWheelEvent *wheel_event, void *user_data) {
ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_WHEEL, false);
+ if (!is_canvas_focused()) {
+ if (is_cursor_inside_canvas()) {
+ focus_canvas();
+ } else {
+ return false;
+ }
+ }
Ref<InputEventMouseButton> ev;
ev.instance();
@@ -387,6 +436,15 @@ static EM_BOOL joy_callback_func(int p_type, const EmscriptenGamepadEvent *p_eve
return false;
}
+extern "C" {
+void send_notification(int notif) {
+ if (notif == MainLoop::NOTIFICATION_WM_MOUSE_ENTER || notif == MainLoop::NOTIFICATION_WM_MOUSE_EXIT) {
+ _cursor_inside_canvas = notif == MainLoop::NOTIFICATION_WM_MOUSE_ENTER;
+ }
+ OS_JavaScript::get_singleton()->get_main_loop()->notification(notif);
+}
+}
+
void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
print_line("Init OS");
@@ -465,17 +523,17 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
EM_CHECK(ev)
EMSCRIPTEN_RESULT result;
- SET_EM_CALLBACK("#canvas", mousemove, _mousemove_callback)
+ SET_EM_CALLBACK("#window", mousemove, _mousemove_callback)
SET_EM_CALLBACK("#canvas", mousedown, _mousebutton_callback)
- SET_EM_CALLBACK("#canvas", mouseup, _mousebutton_callback)
- SET_EM_CALLBACK("#canvas", wheel, _wheel_callback)
- SET_EM_CALLBACK("#canvas", touchstart, _touchpress_callback)
- SET_EM_CALLBACK("#canvas", touchmove, _touchmove_callback)
- SET_EM_CALLBACK("#canvas", touchend, _touchpress_callback)
- SET_EM_CALLBACK("#canvas", touchcancel, _touchpress_callback)
- SET_EM_CALLBACK(NULL, keydown, _keydown_callback)
- SET_EM_CALLBACK(NULL, keypress, _keypress_callback)
- SET_EM_CALLBACK(NULL, keyup, _keyup_callback)
+ SET_EM_CALLBACK("#window", mouseup, _mousebutton_callback)
+ SET_EM_CALLBACK("#window", wheel, _wheel_callback)
+ SET_EM_CALLBACK("#window", touchstart, _touchpress_callback)
+ SET_EM_CALLBACK("#window", touchmove, _touchmove_callback)
+ SET_EM_CALLBACK("#window", touchend, _touchpress_callback)
+ SET_EM_CALLBACK("#window", touchcancel, _touchpress_callback)
+ SET_EM_CALLBACK("#canvas", keydown, _keydown_callback)
+ SET_EM_CALLBACK("#canvas", keypress, _keypress_callback)
+ SET_EM_CALLBACK("#canvas", keyup, _keyup_callback)
SET_EM_CALLBACK(NULL, resize, _browser_resize_callback)
SET_EM_CALLBACK(NULL, fullscreenchange, _fullscreen_change_callback)
SET_EM_CALLBACK_NODATA(gamepadconnected, joy_callback_func)
@@ -485,9 +543,24 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
#undef SET_EM_CALLBACK
#undef EM_CHECK
+ /* clang-format off */
+ EM_ASM_ARGS({
+ const send_notification = Module.cwrap('send_notification', null, ['number']);
+ const notifs = arguments;
+ (['mouseover', 'mouseleave', 'focus', 'blur']).forEach(function(event, i) {
+ Module.canvas.addEventListener(event, send_notification.bind(this, notifs[i]));
+ });
+ },
+ MainLoop::NOTIFICATION_WM_MOUSE_ENTER,
+ MainLoop::NOTIFICATION_WM_MOUSE_EXIT,
+ MainLoop::NOTIFICATION_WM_FOCUS_IN,
+ MainLoop::NOTIFICATION_WM_FOCUS_OUT
+ );
+/* clang-format on */
+
#ifdef JAVASCRIPT_EVAL_ENABLED
javascript_eval = memnew(JavaScript);
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("JavaScript", javascript_eval));
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaScript", javascript_eval));
#endif
visual_server->init();
@@ -777,20 +850,6 @@ void OS_JavaScript::main_loop_end() {
main_loop->finish();
}
-void OS_JavaScript::main_loop_focusout() {
-
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
- //audio_driver_javascript.set_pause(true);
-}
-
-void OS_JavaScript::main_loop_focusin() {
-
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
- //audio_driver_javascript.set_pause(false);
-}
-
void OS_JavaScript::process_accelerometer(const Vector3 &p_accelerometer) {
input->set_accelerometer(p_accelerometer);
@@ -828,7 +887,7 @@ String OS_JavaScript::get_data_dir() const {
return get_data_dir_func();
*/
return "/userfs";
- //return GlobalConfig::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
+ //return ProjectSettings::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
};
String OS_JavaScript::get_executable_path() const {
@@ -911,6 +970,11 @@ int OS_JavaScript::get_power_percent_left() {
return power_manager->get_power_percent_left();
}
+bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
+
+ return p_feature == "web" || p_feature == "s3tc"; // TODO check for these features really being available
+}
+
OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func) {
set_cmdline(p_execpath, get_cmdline_args());
main_loop = NULL;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 65269148e..24e96e20d 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -164,6 +164,8 @@ public:
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
+ virtual bool _check_internal_feature_support(const String &p_feature);
+
OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func);
~OS_JavaScript();
};
diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp
index 7469d5297..d7a91b165 100644
--- a/platform/osx/audio_driver_osx.cpp
+++ b/platform/osx/audio_driver_osx.cpp
@@ -31,11 +31,15 @@
#include "audio_driver_osx.h"
-Error AudioDriverOSX::init() {
+static OSStatus outputDeviceAddressCB(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *__nullable inClientData) {
+ AudioDriverOSX *driver = (AudioDriverOSX *)inClientData;
- active = false;
- channels = 2;
+ driver->reopen();
+ return noErr;
+}
+
+Error AudioDriverOSX::initDevice() {
AudioStreamBasicDescription strdesc;
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
@@ -43,12 +47,10 @@ Error AudioDriverOSX::init() {
strdesc.mSampleRate = 44100;
strdesc.mFramesPerPacket = 1;
strdesc.mBitsPerChannel = 16;
- strdesc.mBytesPerFrame =
- strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
- strdesc.mBytesPerPacket =
- strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
+ strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
+ strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
- OSStatus result = noErr;
+ OSStatus result;
AURenderCallbackStruct callback;
AudioComponentDescription desc;
AudioComponent comp = NULL;
@@ -58,83 +60,130 @@ Error AudioDriverOSX::init() {
zeromem(&desc, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
- desc.componentSubType = 0; /* !!! FIXME: ? */
- comp = AudioComponentFindNext(NULL, &desc);
+ desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ comp = AudioComponentFindNext(NULL, &desc);
+ ERR_FAIL_COND_V(comp == NULL, FAILED);
+
result = AudioComponentInstanceNew(comp, &audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
- ERR_FAIL_COND_V(comp == NULL, FAILED);
- result = AudioUnitSetProperty(audio_unit,
- kAudioUnitProperty_StreamFormat,
- scope, bus, &strdesc, sizeof(strdesc));
+ result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, scope, bus, &strdesc, sizeof(strdesc));
ERR_FAIL_COND_V(result != noErr, FAILED);
zeromem(&callback, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverOSX::output_callback;
callback.inputProcRefCon = this;
- result = AudioUnitSetProperty(audio_unit,
- kAudioUnitProperty_SetRenderCallback,
- scope, bus, &callback, sizeof(callback));
+ result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, scope, bus, &callback, sizeof(callback));
ERR_FAIL_COND_V(result != noErr, FAILED);
result = AudioUnitInitialize(audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
- result = AudioOutputUnitStart(audio_unit);
+ return OK;
+}
+
+Error AudioDriverOSX::finishDevice() {
+ OSStatus result;
+
+ if (active) {
+ result = AudioOutputUnitStop(audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ active = false;
+ }
+
+ result = AudioUnitUninitialize(audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ return OK;
+}
+
+Error AudioDriverOSX::init() {
+ OSStatus result;
+
+ mutex = Mutex::create();
+ active = false;
+ channels = 2;
+
+ outputDeviceAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ outputDeviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
+ outputDeviceAddress.mElement = kAudioObjectPropertyElementMaster;
+
+ result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this);
ERR_FAIL_COND_V(result != noErr, FAILED);
const int samples = 1024;
samples_in = memnew_arr(int32_t, samples); // whatever
buffer_frames = samples / channels;
- return OK;
+ return initDevice();
};
+Error AudioDriverOSX::reopen() {
+ Error err;
+ bool restart = false;
+
+ lock();
+
+ if (active) {
+ restart = true;
+ }
+
+ err = finishDevice();
+ if (err != OK) {
+ ERR_PRINT("finishDevice failed");
+ unlock();
+ return err;
+ }
+
+ err = initDevice();
+ if (err != OK) {
+ ERR_PRINT("initDevice failed");
+ unlock();
+ return err;
+ }
+
+ if (restart) {
+ start();
+ }
+
+ unlock();
+
+ return OK;
+}
+
OSStatus AudioDriverOSX::output_callback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData) {
- AudioBuffer *abuf;
AudioDriverOSX *ad = (AudioDriverOSX *)inRefCon;
- bool mix = true;
-
- if (!ad->active)
- mix = false;
- else if (ad->mutex) {
- mix = ad->mutex->try_lock() == OK;
- };
-
- if (!mix) {
+ if (!ad->active || !ad->try_lock()) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
- abuf = &ioData->mBuffers[i];
+ AudioBuffer *abuf = &ioData->mBuffers[i];
zeromem(abuf->mData, abuf->mDataByteSize);
};
return 0;
};
- int frames_left;
-
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
- abuf = &ioData->mBuffers[i];
- frames_left = inNumberFrames;
+ AudioBuffer *abuf = &ioData->mBuffers[i];
+ int frames_left = inNumberFrames;
int16_t *out = (int16_t *)abuf->mData;
while (frames_left) {
int frames = MIN(frames_left, ad->buffer_frames);
- //ad->lock();
ad->audio_server_process(frames, ad->samples_in);
- //ad->unlock();
- for (int i = 0; i < frames * ad->channels; i++) {
+ for (int j = 0; j < frames * ad->channels; j++) {
- out[i] = ad->samples_in[i] >> 16;
+ out[j] = ad->samples_in[j] >> 16;
}
frames_left -= frames;
@@ -142,14 +191,20 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon,
};
};
- if (ad->mutex)
- ad->mutex->unlock();
+ ad->unlock();
return 0;
};
void AudioDriverOSX::start() {
- active = true;
+ if (!active) {
+ OSStatus result = AudioOutputUnitStart(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioOutputUnitStart failed");
+ } else {
+ active = true;
+ }
+ }
};
int AudioDriverOSX::get_mix_rate() const {
@@ -161,29 +216,47 @@ AudioDriver::SpeakerMode AudioDriverOSX::get_speaker_mode() const {
};
void AudioDriverOSX::lock() {
- if (active && mutex)
+ if (mutex)
mutex->lock();
};
+
void AudioDriverOSX::unlock() {
- if (active && mutex)
+ if (mutex)
mutex->unlock();
};
+bool AudioDriverOSX::try_lock() {
+ if (mutex)
+ return mutex->try_lock() == OK;
+ return true;
+}
+
void AudioDriverOSX::finish() {
+ OSStatus result;
- if (active)
- AudioOutputUnitStop(audio_unit);
+ finishDevice();
- memdelete_arr(samples_in);
-};
+ result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this);
+ if (result != noErr) {
+ ERR_PRINT("AudioObjectRemovePropertyListener failed");
+ }
-AudioDriverOSX::AudioDriverOSX() {
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
- mutex = Mutex::create(); //NULL;
+ if (samples_in) {
+ memdelete_arr(samples_in);
+ samples_in = NULL;
+ }
};
-AudioDriverOSX::~AudioDriverOSX(){
-
+AudioDriverOSX::AudioDriverOSX() {
+ mutex = NULL;
+ samples_in = NULL;
};
+AudioDriverOSX::~AudioDriverOSX(){};
+
#endif
diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h
index 9b48dab40..287c9d6cb 100644
--- a/platform/osx/audio_driver_osx.h
+++ b/platform/osx/audio_driver_osx.h
@@ -35,10 +35,12 @@
#include "servers/audio_server.h"
#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/AudioHardware.h>
class AudioDriverOSX : public AudioDriver {
AudioComponentInstance audio_unit;
+ AudioObjectPropertyAddress outputDeviceAddress;
bool active;
Mutex *mutex;
@@ -52,6 +54,9 @@ class AudioDriverOSX : public AudioDriver {
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData);
+ Error initDevice();
+ Error finishDevice();
+
public:
const char *get_name() const {
return "AudioUnit";
@@ -65,6 +70,9 @@ public:
virtual void unlock();
virtual void finish();
+ bool try_lock();
+ Error reopen();
+
AudioDriverOSX();
~AudioDriverOSX();
};
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 39ee33ae8..d9891dda6 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -1,4 +1,3 @@
-
import os
import sys
@@ -22,9 +21,7 @@ def can_build():
def get_opts():
return [
- ('force_64_bits', 'Force 64 bits binary', 'no'),
('osxcross_sdk', 'OSXCross SDK version', 'darwin14'),
-
]
@@ -36,36 +33,37 @@ def get_flags():
def configure(env):
- env.Append(CPPPATH=['#platform/osx'])
-
- if (env["bits"] == "default"):
- env["bits"] = "32"
+ ## Build type
if (env["target"] == "release"):
-
- env.Append(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2'])
+ env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2'])
elif (env["target"] == "release_debug"):
-
- env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
elif (env["target"] == "debug"):
+ env.Prepend(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
- env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ ## Architecture
- if (not os.environ.has_key("OSXCROSS_ROOT")):
- # regular native build
- if (env["bits"] == "64"):
- env.Append(CCFLAGS=['-arch', 'x86_64'])
- env.Append(LINKFLAGS=['-arch', 'x86_64'])
+ is64 = sys.maxsize > 2**32
+ if (env["bits"] == "default"):
+ env["bits"] = "64" if is64 else "32"
+
+ ## Compiler configuration
+
+ if (not os.environ.has_key("OSXCROSS_ROOT")): # regular native build
+ if (env["bits"] == "fat"):
+ env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64'])
+ env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64'])
elif (env["bits"] == "32"):
env.Append(CCFLAGS=['-arch', 'i386'])
env.Append(LINKFLAGS=['-arch', 'i386'])
- else:
- env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64'])
- env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64'])
- else:
- # osxcross build
+ else: # 64-bit, default
+ env.Append(CCFLAGS=['-arch', 'x86_64'])
+ env.Append(LINKFLAGS=['-arch', 'x86_64'])
+
+ else: # osxcross build
root = os.environ.get("OSXCROSS_ROOT", 0)
if env["bits"] == "64":
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
@@ -78,26 +76,22 @@ def configure(env):
env['RANLIB'] = basecmd + "ranlib"
env['AS'] = basecmd + "as"
- env.Append(CPPFLAGS=["-DAPPLE_STYLE_KEYS"])
- env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DOSX_ENABLED'])
- env.Append(CPPFLAGS=["-mmacosx-version-min=10.9"])
- env.Append(LIBS=['pthread'])
- #env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4'])
- #env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk'])
- env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
- env.Append(LINKFLAGS=["-mmacosx-version-min=10.9"])
-
if (env["CXX"] == "clang++"):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env["CC"] = "clang"
env["LD"] = "clang++"
- import methods
+ ## Dependencies
+
+ if (env['builtin_libtheora'] != 'no'):
+ env["x86_libtheora_opt_gcc"] = True
- env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
- #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
+ ## Flags
+
+ env.Append(CPPPATH=['#platform/osx'])
+ env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DAPPLE_STYLE_KEYS'])
+ env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
+ env.Append(LIBS=['pthread'])
- env["x86_libtheora_opt_gcc"] = True
-
+ env.Append(CPPFLAGS=['-mmacosx-version-min=10.9'])
+ env.Append(LINKFLAGS=['-mmacosx-version-min=10.9'])
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 066adde78..03f424de8 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -32,15 +32,16 @@
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
-#include "global_config.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 {
@@ -52,6 +53,10 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
+#ifdef OSX_ENABLED
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
+#endif
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
@@ -59,13 +64,25 @@ protected:
public:
virtual String get_name() const { return "Mac OSX"; }
+ virtual String get_os_name() const { return "OSX"; }
virtual Ref<Texture> get_logo() const { return logo; }
+#ifdef OSX_ENABLED
+ virtual String get_binary_extension() const { return "dmg"; }
+#else
virtual String get_binary_extension() const { return "zip"; }
+#endif
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;
+ virtual void get_platform_features(List<String> *r_features) {
+
+ r_features->push_back("pc");
+ r_features->push_back("s3tc");
+ r_features->push_back("OSX");
+ }
+
EditorExportPlatformOSX();
~EditorExportPlatformOSX();
};
@@ -90,6 +107,11 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
+
+#ifdef OSX_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements"), ""));
+#endif
}
void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
@@ -171,27 +193,68 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
}
CharString cs = strnew.utf8();
- plist.resize(cs.size());
- for (int i = 9; i < cs.size(); i++) {
+ plist.resize(cs.size() - 1);
+ for (int i = 0; i < cs.size() - 1; i++) {
plist[i] = cs[i];
}
}
+#ifdef OSX_ENABLED
+/**
+ 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::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ List<String> args;
+ if (p_preset->get("codesign/entitlements") != "") {
+ /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */
+ args.push_back("-entitlements");
+ args.push_back(p_preset->get("codesign/entitlements"));
+ }
+ args.push_back("-s");
+ args.push_back(p_preset->get("codesign/identity"));
+ args.push_back("-v"); /* provide some more feedback */
+ args.push_back(p_path);
+ Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) {
+ List<String> args;
+ args.push_back("create");
+ args.push_back(p_dmg_path);
+ args.push_back("-volname");
+ args.push_back(p_pkg_name);
+ args.push_back("-fs");
+ args.push_back("HFS+");
+ args.push_back("-srcfolder");
+ args.push_back(p_app_path_name);
+ Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- String src_pkg;
+ String src_pkg_name;
- EditorProgress ep("export", "Exporting for OSX", 104);
+ EditorProgress ep("export", "Exporting for OSX", 3);
if (p_debug)
- src_pkg = p_preset->get("custom_package/debug");
+ src_pkg_name = p_preset->get("custom_package/debug");
else
- src_pkg = p_preset->get("custom_package/release");
+ src_pkg_name = p_preset->get("custom_package/release");
- if (src_pkg == "") {
+ if (src_pkg_name == "") {
String err;
- src_pkg = find_export_template("osx.zip", &err);
- if (src_pkg == "") {
+ src_pkg_name = find_export_template("osx.zip", &err);
+ if (src_pkg_name == "") {
EditorNode::add_io_error(err);
return ERR_FILE_NOT_FOUND;
}
@@ -202,20 +265,15 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ep.step("Creating app", 0);
- unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io);
- if (!pkg) {
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
- EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg);
+ EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
return ERR_FILE_NOT_FOUND;
}
- ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
- int ret = unzGoToFirstFile(pkg);
-
- zlib_filefunc_def io2 = io;
- FileAccess *dst_f = NULL;
- io2.opaque = &dst_f;
- zipFile dpkg = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+ ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(src_pkg_zip);
String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".";
int bits_mode = p_preset->get("application/bits_mode");
@@ -225,19 +283,39 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
String pkg_name;
if (p_preset->get("application/name") != "")
pkg_name = p_preset->get("application/name"); // app_name
- else if (String(GlobalConfig::get_singleton()->get("application/name")) != "")
- pkg_name = String(GlobalConfig::get_singleton()->get("application/name"));
+ else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "")
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
else
pkg_name = "Unnamed";
+ // We're on OSX so we can export to DMG, but first we create our application bundle
+ String tmp_app_path_name = p_path.get_base_dir() + "/" + pkg_name + ".app";
+ print_line("Exporting to " + tmp_app_path_name);
+ DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
+ ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE)
+
+ ///@TODO We should delete the existing application bundle especially if we attempt to code sign it, but what is a safe way to do this? Maybe call system function so it moves to trash?
+ // tmp_app_path->erase_contents_recursive();
+
+ // Create our folder structure or rely on unzip?
+ print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
+ Error dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
+ ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE)
+ print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
+ dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
+ ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE)
+
+ /* Now process our template */
bool found_binary = false;
+ int total_size = 0;
while (ret == UNZ_OK) {
+ bool is_execute = false;
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
String file = fname;
@@ -246,9 +324,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
data.resize(info.uncompressed_size);
//read
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptr(), data.size());
- unzCloseCurrentFile(pkg);
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
//write
@@ -261,10 +339,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (file.begins_with("Contents/MacOS/godot_")) {
if (file != "Contents/MacOS/" + binary_to_use) {
- ret = unzGoToNextFile(pkg);
+ ret = unzGoToNextFile(src_pkg_zip);
continue; //ignore!
}
found_binary = true;
+ is_execute = true;
file = "Contents/MacOS/" + pkg_name;
}
@@ -274,7 +353,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (p_preset->get("application/icon") != "")
iconpath = p_preset->get("application/icon");
else
- iconpath = GlobalConfig::get_singleton()->get("application/icon");
+ iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
print_line("icon? " + iconpath);
if (iconpath != "") {
Ref<Image> icon;
@@ -288,11 +367,206 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
//bleh?
}
- file = pkg_name + ".app/" + file;
+ if (data.size() > 0) {
+ print_line("ADDING: " + file + " size: " + itos(data.size()));
+ total_size += data.size();
+
+ /* write it into our application bundle */
+ file = tmp_app_path_name + "/" + file;
+
+ /* write the file, need to add chmod */
+ FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
+ ERR_FAIL_COND_V(!f, ERR_CANT_CREATE)
+ f->store_buffer(data.ptr(), data.size());
+ f->close();
+ memdelete(f);
+
+ if (is_execute) {
+ // we need execute rights on this file
+ chmod(file.utf8().get_data(), 0755);
+ } else {
+ // seems to already be set correctly
+ // chmod(file.utf8().get_data(), 0644);
+ }
+ }
+
+ ret = unzGoToNextFile(src_pkg_zip);
+ }
+
+ /* we're done with our source zip */
+ unzClose(src_pkg_zip);
+
+ if (!found_binary) {
+ ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
+ unzClose(src_pkg_zip);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ep.step("Making PKG", 1);
+
+ String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
+ Error err = save_pack(p_preset, pack_path);
+ // chmod(pack_path.utf8().get_data(), 0644);
+
+ if (err) {
+ return err;
+ }
+
+ /* see if we can code sign our new package */
+ if (p_preset->get("codesign/identity") != "") {
+ ep.step("Code signing bundle", 2);
+
+ /* the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP */
+
+ // start with our application
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name);
+ ERR_FAIL_COND_V(err, err);
+
+ ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign
+
+ // we should probably loop through all resources and sign them?
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns");
+ ERR_FAIL_COND_V(err, err);
+ err = _code_sign(p_preset, pack_path);
+ ERR_FAIL_COND_V(err, err);
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist");
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ /* and finally create a DMG */
+ ep.step("Making DMG", 3);
+ err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+#else
+
+/**
+ When exporting for OSX from any other platform we don't have access to code signing or creating DMGs so we'll wrap the bundle into a zip file.
+
+ Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very
+ messy with switches inside of it.
+**/
+Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+
+ String src_pkg_name;
+
+ EditorProgress ep("export", "Exporting for OSX", 104);
+
+ if (p_debug)
+ src_pkg_name = p_preset->get("custom_package/debug");
+ else
+ src_pkg_name = p_preset->get("custom_package/release");
+
+ if (src_pkg_name == "") {
+ String err;
+ src_pkg_name = find_export_template("osx.zip", &err);
+ if (src_pkg_name == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ FileAccess *src_f = NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ ep.step("Creating app", 0);
+
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
+
+ EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(src_pkg_zip);
+
+ String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".";
+ int bits_mode = p_preset->get("application/bits_mode");
+ binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32");
+
+ print_line("binary: " + binary_to_use);
+ String pkg_name;
+ if (p_preset->get("application/name") != "")
+ pkg_name = p_preset->get("application/name"); // app_name
+ else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "")
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ else
+ pkg_name = "Unnamed";
+
+ /* Open our destination zip file */
+ zlib_filefunc_def io2 = io;
+ FileAccess *dst_f = NULL;
+ io2.opaque = &dst_f;
+ zipFile dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+
+ bool found_binary = false;
+
+ while (ret == UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
+
+ String file = fname;
+
+ print_line("READ: " + file);
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
+
+ //write
+
+ file = file.replace_first("osx_template.app/", "");
+
+ if (file == "Contents/Info.plist") {
+ print_line("parse plist");
+ _fix_plist(p_preset, data, pkg_name);
+ }
+
+ if (file.begins_with("Contents/MacOS/godot_")) {
+ if (file != "Contents/MacOS/" + binary_to_use) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; //ignore!
+ }
+ found_binary = true;
+ file = "Contents/MacOS/" + pkg_name;
+ }
+
+ if (file == "Contents/Resources/icon.icns") {
+ //see if there is an icon
+ String iconpath;
+ if (p_preset->get("application/icon") != "")
+ iconpath = p_preset->get("application/icon");
+ else
+ iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
+ print_line("icon? " + iconpath);
+ if (iconpath != "") {
+ Ref<Image> icon;
+ icon.instance();
+ icon->load(iconpath);
+ if (!icon->empty()) {
+ print_line("loaded?");
+ _make_icon(icon, data);
+ }
+ }
+ //bleh?
+ }
if (data.size() > 0) {
print_line("ADDING: " + file + " size: " + itos(data.size()));
+ /* add it to our zip file */
+ file = pkg_name + ".app/" + file;
+
zip_fileinfo fi;
fi.tmz_date.tm_hour = info.tmu_date.tm_hour;
fi.tmz_date.tm_min = info.tmu_date.tm_min;
@@ -304,7 +578,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
fi.internal_fa = info.internal_fa;
fi.external_fa = info.external_fa;
- int err = zipOpenNewFileInZip(dpkg,
+ int err = zipOpenNewFileInZip(dst_pkg_zip,
file.utf8().get_data(),
&fi,
NULL,
@@ -316,37 +590,37 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
Z_DEFAULT_COMPRESSION);
print_line("OPEN ERR: " + itos(err));
- err = zipWriteInFileInZip(dpkg, data.ptr(), data.size());
+ err = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size());
print_line("WRITE ERR: " + itos(err));
- zipCloseFileInZip(dpkg);
+ zipCloseFileInZip(dst_pkg_zip);
}
- ret = unzGoToNextFile(pkg);
+ ret = unzGoToNextFile(src_pkg_zip);
}
if (!found_binary) {
ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
- zipClose(dpkg, NULL);
- unzClose(pkg);
+ zipClose(dst_pkg_zip, NULL);
+ unzClose(src_pkg_zip);
return ERR_FILE_NOT_FOUND;
}
ep.step("Making PKG", 1);
- String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/data.pck";
+ String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck";
Error err = save_pack(p_preset, pack_path);
if (err) {
- zipClose(dpkg, NULL);
- unzClose(pkg);
+ zipClose(dst_pkg_zip, NULL);
+ unzClose(src_pkg_zip);
return err;
}
{
//write datapack
- zipOpenNewFileInZip(dpkg,
- (pkg_name + ".app/Contents/Resources/data.pck").utf8().get_data(),
+ zipOpenNewFileInZip(dst_pkg_zip,
+ (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(),
NULL,
NULL,
0,
@@ -366,17 +640,18 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
int r = pf->get_buffer(buf, BSIZE);
if (r <= 0)
break;
- zipWriteInFileInZip(dpkg, buf, r);
+ zipWriteInFileInZip(dst_pkg_zip, buf, r);
}
- zipCloseFileInZip(dpkg);
+ zipCloseFileInZip(dst_pkg_zip);
memdelete(pf);
}
- zipClose(dpkg, NULL);
- unzClose(pkg);
+ zipClose(dst_pkg_zip, NULL);
+ unzClose(src_pkg_zip);
return OK;
}
+#endif
bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index dc3e88df2..cb9dd1dd8 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -101,11 +101,7 @@ public:
bool maximized;
bool zoomed;
- Vector<Rect2> screens;
- Vector<int> screen_dpi;
-
Size2 window_size;
- int current_screen;
Rect2 restore_rect;
power_osx *power_manager;
@@ -117,6 +113,8 @@ public:
return 1.0;
}
+ void _update_window();
+
float display_scale;
protected:
@@ -208,6 +206,8 @@ public:
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
+ virtual bool _check_internal_feature_support(const String &p_feature);
+
void run();
void set_mouse_mode(MouseMode p_mode);
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index ad1e308ae..4a01532d8 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -80,6 +80,7 @@ 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;
@interface GodotApplication : NSApplication
@end
@@ -151,6 +152,46 @@ static int button_mask = 0;
return NO;
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+- (void)windowDidEnterFullScreen:(NSNotification *)notification {
+ OS_OSX::singleton->zoomed = true;
+}
+
+- (void)windowDidExitFullScreen:(NSNotification *)notification {
+ OS_OSX::singleton->zoomed = false;
+}
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED
+
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
+ if (!OS_OSX::singleton)
+ return;
+
+ NSWindow *window = (NSWindow *)[notification object];
+ CGFloat newBackingScaleFactor = [window backingScaleFactor];
+ CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
+
+ if (newBackingScaleFactor != oldBackingScaleFactor) {
+ //Set new display scale and window size
+ OS_OSX::singleton->display_scale = newBackingScaleFactor;
+
+ const NSRect contentRect = [OS_OSX::singleton->window_view frame];
+ const NSRect fbRect = contentRect; //convertRectToBacking(contentRect);
+
+ OS_OSX::singleton->window_size.width = fbRect.size.width * OS_OSX::singleton->display_scale;
+ OS_OSX::singleton->window_size.height = fbRect.size.height * OS_OSX::singleton->display_scale;
+
+ //Update context
+ if (OS_OSX::singleton->main_loop) {
+ [OS_OSX::singleton->context update];
+
+ //Force window resize ???
+ NSRect frame = [OS_OSX::singleton->window_object frame];
+ [OS_OSX::singleton->window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, 1, 1) display:YES];
+ [OS_OSX::singleton->window_object setFrame:frame display:YES];
+ }
+ }
+}
+
- (void)windowDidResize:(NSNotification *)notification {
[OS_OSX::singleton->context update];
@@ -160,6 +201,12 @@ static int button_mask = 0;
OS_OSX::singleton->window_size.width = fbRect.size.width * OS_OSX::singleton->display_scale;
OS_OSX::singleton->window_size.height = fbRect.size.height * OS_OSX::singleton->display_scale;
+ if (OS_OSX::singleton->main_loop) {
+ Main::force_redraw();
+ //Event retrieval blocks until resize is over. Call Main::iteration() directly.
+ Main::iteration();
+ }
+
/*
_GodotInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
_GodotInputWindowSize(window, contentRect.size.width, contentRect.size.height);
@@ -285,41 +332,48 @@ static int button_mask = 0;
//setModeCursor(window, window->cursorMode);
}
-- (void)mouseDown:(NSEvent *)event {
-
- button_mask |= BUTTON_MASK_LEFT;
+static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
+ if (pressed) {
+ button_mask |= mask;
+ } else {
+ button_mask &= ~mask;
+ }
Ref<InputEventMouseButton> mb;
mb.instance();
get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(BUTTON_LEFT);
- mb->set_pressed(true);
+ 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_button_mask(button_mask);
- mb->set_doubleclick([event clickCount] == 2);
+ if (index == BUTTON_LEFT && pressed) {
+ mb->set_doubleclick([event clickCount] == 2);
+ }
OS_OSX::singleton->push_input(mb);
}
+- (void)mouseDown:(NSEvent *)event {
+ if (([event modifierFlags] & NSControlKeyMask)) {
+ mouse_down_control = true;
+ _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+ } else {
+ mouse_down_control = false;
+ _mouseDownEvent(event, BUTTON_LEFT, BUTTON_MASK_LEFT, true);
+ }
+}
+
- (void)mouseDragged:(NSEvent *)event {
[self mouseMoved:event];
}
- (void)mouseUp:(NSEvent *)event {
-
- button_mask &= ~BUTTON_MASK_LEFT;
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(BUTTON_LEFT);
- mb->set_pressed(false);
- mb->set_position(Vector2(mouse_x, mouse_y));
- mb->set_global_position(Vector2(mouse_x, mouse_y));
- mb->set_button_mask(button_mask);
- mb->set_doubleclick([event clickCount] == 2);
- OS_OSX::singleton->push_input(mb);
+ if (mouse_down_control) {
+ _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+ } else {
+ _mouseDownEvent(event, BUTTON_LEFT, BUTTON_MASK_LEFT, false);
+ }
}
- (void)mouseMoved:(NSEvent *)event {
@@ -347,20 +401,7 @@ static int button_mask = 0;
}
- (void)rightMouseDown:(NSEvent *)event {
-
- button_mask |= BUTTON_MASK_RIGHT;
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(BUTTON_RIGHT);
- mb->set_pressed(true);
- mb->set_position(Vector2(mouse_x, mouse_y));
- mb->set_global_position(Vector2(mouse_x, mouse_y));
- mb->set_button_mask(button_mask);
- mb->set_doubleclick([event clickCount] == 2);
- OS_OSX::singleton->push_input(mb);
+ _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
}
- (void)rightMouseDragged:(NSEvent *)event {
@@ -368,20 +409,7 @@ static int button_mask = 0;
}
- (void)rightMouseUp:(NSEvent *)event {
-
- button_mask &= ~BUTTON_MASK_RIGHT;
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(BUTTON_RIGHT);
- mb->set_pressed(false);
- mb->set_position(Vector2(mouse_x, mouse_y));
- mb->set_global_position(Vector2(mouse_x, mouse_y));
- mb->set_button_mask(button_mask);
- mb->set_doubleclick([event clickCount] == 2);
- OS_OSX::singleton->push_input(mb);
+ _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
}
- (void)otherMouseDown:(NSEvent *)event {
@@ -389,19 +417,7 @@ static int button_mask = 0;
if ((int)[event buttonNumber] != 2)
return;
- button_mask |= BUTTON_MASK_MIDDLE;
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(BUTTON_MIDDLE);
- mb->set_pressed(true);
- mb->set_position(Vector2(mouse_x, mouse_y));
- mb->set_global_position(Vector2(mouse_x, mouse_y));
- mb->set_button_mask(button_mask);
- mb->set_doubleclick([event clickCount] == 2);
- OS_OSX::singleton->push_input(mb);
+ _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true);
}
- (void)otherMouseDragged:(NSEvent *)event {
@@ -413,19 +429,7 @@ static int button_mask = 0;
if ((int)[event buttonNumber] != 2)
return;
- button_mask &= ~BUTTON_MASK_MIDDLE;
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(BUTTON_MIDDLE);
- mb->set_pressed(false);
- mb->set_position(Vector2(mouse_x, mouse_y));
- mb->set_global_position(Vector2(mouse_x, mouse_y));
- mb->set_button_mask(button_mask);
- mb->set_doubleclick([event clickCount] == 2);
- OS_OSX::singleton->push_input(mb);
+ _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false);
}
- (void)mouseExited:(NSEvent *)event {
@@ -554,7 +558,7 @@ static int translateKey(unsigned int key) {
/* 49 */ KEY_UNKNOWN, /* VolumeDown */
/* 4a */ KEY_UNKNOWN, /* Mute */
/* 4b */ KEY_KP_DIVIDE,
- /* 4c */ KEY_KP_ENTER,
+ /* 4c */ KEY_ENTER,
/* 4d */ KEY_UNKNOWN,
/* 4e */ KEY_KP_SUBTRACT,
/* 4f */ KEY_UNKNOWN,
@@ -921,6 +925,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
[NSApp activateIgnoringOtherApps:YES];
+ _update_window();
+
[window_object makeKeyAndOrderFront:nil];
if (p_desired.fullscreen)
@@ -970,32 +976,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
_ensure_data_dir();
- NSArray *screenArray = [NSScreen screens];
- printf("nscreen count %i\n", (int)[screenArray count]);
- for (int i = 0; i < [screenArray count]; i++) {
-
- float displayScale = 1.0;
-
- if (display_scale > 1.0 && [[screenArray objectAtIndex:i] respondsToSelector:@selector(backingScaleFactor)]) {
- displayScale = [[screenArray objectAtIndex:i] backingScaleFactor];
- }
-
- NSRect nsrect = [[screenArray objectAtIndex:i] visibleFrame];
- Rect2 rect = Rect2(nsrect.origin.x, nsrect.origin.y, nsrect.size.width, nsrect.size.height);
- rect.position *= displayScale;
- rect.size *= displayScale;
- screens.push_back(rect);
-
- NSDictionary *description = [[screenArray objectAtIndex:i] deviceDescription];
- NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
- CGSize displayPhysicalSize = CGDisplayScreenSize(
- [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
-
- //printf("width: %i pwidth %i rect width %i\n",int(displayPixelSize.width*displayScale),int(displayPhysicalSize.width*displayScale),int(nsrect.size.width));
- int dpi = (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale;
-
- screen_dpi.push_back(dpi);
- };
restore_rect = Rect2(get_window_position(), get_window_size());
}
@@ -1016,8 +996,6 @@ void OS_OSX::finalize() {
physics_2d_server->finish();
memdelete(physics_2d_server);
-
- screens.clear();
}
void OS_OSX::set_main_loop(MainLoop *p_main_loop) {
@@ -1267,37 +1245,105 @@ void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con
}
int OS_OSX::get_screen_count() const {
-
- return screens.size();
+ NSArray *screenArray = [NSScreen screens];
+ return [screenArray count];
};
int OS_OSX::get_current_screen() const {
+ Vector2 wpos = get_window_position();
- return current_screen;
+ int count = get_screen_count();
+ for (int i = 0; i < count; i++) {
+ Point2 pos = get_screen_position(i);
+ Size2 size = get_screen_size(i);
+ if ((wpos.x >= pos.x && wpos.x < pos.x + size.width) && (wpos.y >= pos.y && wpos.y < pos.y + size.height))
+ return i;
+ }
+ return 0;
};
void OS_OSX::set_current_screen(int p_screen) {
-
- current_screen = p_screen;
+ Vector2 wpos = get_window_position() - get_screen_position(get_current_screen());
+ set_window_position(wpos + get_screen_position(p_screen));
};
Point2 OS_OSX::get_screen_position(int p_screen) const {
+ NSArray *screenArray = [NSScreen screens];
+ if (p_screen < [screenArray count]) {
+ float displayScale = 1.0;
- ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2());
- return screens[p_screen].position;
-};
+ if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) {
+ displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor];
+ }
+
+ NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
+ return Point2(nsrect.origin.x, nsrect.origin.y) * displayScale;
+ }
+
+ return Point2();
+}
int OS_OSX::get_screen_dpi(int p_screen) const {
+ NSArray *screenArray = [NSScreen screens];
+ if (p_screen < [screenArray count]) {
+ float displayScale = 1.0;
+
+ if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) {
+ displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor];
+ }
+
+ NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
+ NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
+ CGSize displayPhysicalSize = CGDisplayScreenSize(
+ [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
+
+ return (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale;
+ }
- ERR_FAIL_INDEX_V(p_screen, screens.size(), 72);
- return screen_dpi[p_screen];
+ return 72;
}
Size2 OS_OSX::get_screen_size(int p_screen) const {
+ NSArray *screenArray = [NSScreen screens];
+ if (p_screen < [screenArray count]) {
+ float displayScale = 1.0;
- ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2());
- return screens[p_screen].size;
-};
+ if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) {
+ displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor];
+ }
+
+ // Note: Use frame to get the whole screen size
+ NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
+ return Size2(nsrect.size.width, nsrect.size.height) * displayScale;
+ }
+
+ return Size2();
+}
+
+void OS_OSX::_update_window() {
+ bool borderless_full = false;
+
+ if (get_borderless_window()) {
+ NSRect frameRect = [window_object frame];
+ NSRect screenRect = [[window_object screen] frame];
+
+ // Check if our window covers up the screen
+ if (frameRect.origin.x <= screenRect.origin.x && frameRect.origin.y <= frameRect.origin.y &&
+ frameRect.size.width >= screenRect.size.width && frameRect.size.height >= screenRect.size.height) {
+ borderless_full = true;
+ }
+ }
+
+ if (borderless_full) {
+ // If the window covers up the screen set the level to above the main menu and hide on deactivate
+ [window_object setLevel:NSMainMenuWindowLevel + 1];
+ [window_object setHidesOnDeactivate:YES];
+ } else {
+ // Reset these when our window is not a borderless window that covers up the screen
+ [window_object setLevel:NSNormalWindowLevel];
+ [window_object setHidesOnDeactivate:NO];
+ }
+}
Point2 OS_OSX::get_window_position() const {
@@ -1311,6 +1357,8 @@ void OS_OSX::set_window_position(const Point2 &p_position) {
Point2 size = p_position;
size /= display_scale;
[window_object setFrame:NSMakeRect(size.x, size.y, [window_object frame].size.width, [window_object frame].size.height) display:YES];
+
+ _update_window();
};
Size2 OS_OSX::get_window_size() const {
@@ -1322,17 +1370,22 @@ void OS_OSX::set_window_size(const Size2 p_size) {
Size2 size = p_size;
- // NSRect used by setFrame includes the title bar, so add it to our size.y
- CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
- if (menuBarHeight != 0.f) {
- size.y += menuBarHeight;
+ if (get_borderless_window() == false) {
+ // NSRect used by setFrame includes the title bar, so add it to our size.y
+ CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
+ if (menuBarHeight != 0.f) {
+ size.y += menuBarHeight;
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101104
- } else {
- size.y += [[NSStatusBar systemStatusBar] thickness];
+ } else {
+ size.y += [[NSStatusBar systemStatusBar] thickness];
#endif
+ }
}
+
NSRect frame = [window_object frame];
[window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES];
+
+ _update_window();
};
void OS_OSX::set_window_fullscreen(bool p_enabled) {
@@ -1390,7 +1443,7 @@ void OS_OSX::set_window_maximized(bool p_enabled) {
if (p_enabled) {
restore_rect = Rect2(get_window_position(), get_window_size());
- [window_object setFrame:[[[NSScreen screens] objectAtIndex:current_screen] visibleFrame] display:YES];
+ [window_object setFrame:[[[NSScreen screens] objectAtIndex:get_current_screen()] visibleFrame] display:YES];
} else {
set_window_size(restore_rect.size);
set_window_position(restore_rect.position);
@@ -1416,9 +1469,12 @@ void OS_OSX::request_attention() {
void OS_OSX::set_borderless_window(int p_borderless) {
- if (p_borderless)
+ // OrderOut prevents a lose focus bug with the window
+ [window_object orderOut:nil];
+
+ if (p_borderless) {
[window_object setStyleMask:NSWindowStyleMaskBorderless];
- else {
+ } else {
[window_object setStyleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask];
// Force update of the window styles
@@ -1429,6 +1485,10 @@ void OS_OSX::set_borderless_window(int p_borderless) {
// Restore the window title
[window_object setTitle:[NSString stringWithUTF8String:title.utf8().get_data()]];
}
+
+ _update_window();
+
+ [window_object makeKeyAndOrderFront:nil];
}
bool OS_OSX::get_borderless_window() {
@@ -1661,12 +1721,52 @@ OS_OSX::OS_OSX() {
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
-#if 0
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
// of NSApplicationMain
- createMenuBar();
-#endif
+ NSMenuItem *menu_item;
+ NSString *title;
+
+ NSString *nsappname = [[[NSBundle mainBundle] performSelector:@selector(localizedInfoDictionary)] objectForKey:@"CFBundleName"];
+ if (nsappname == nil)
+ nsappname = [[NSProcessInfo processInfo] processName];
+
+ // Setup Apple menu
+ NSMenu *apple_menu = [[NSMenu alloc] initWithTitle:@""];
+ title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname];
+ [apple_menu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+ [apple_menu addItem:[NSMenuItem separatorItem]];
+
+ NSMenu *services = [[NSMenu alloc] initWithTitle:@""];
+ menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""];
+ [apple_menu setSubmenu:services forItem:menu_item];
+ [NSApp setServicesMenu:services];
+ [services release];
+
+ [apple_menu addItem:[NSMenuItem separatorItem]];
+
+ title = [NSString stringWithFormat:NSLocalizedString(@"Hide %@", nil), nsappname];
+ [apple_menu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+ menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menu_item setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+
+ [apple_menu addItemWithTitle:NSLocalizedString(@"Show all", nil) action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [apple_menu addItem:[NSMenuItem separatorItem]];
+
+ title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
+ [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+ // Setup menu bar
+ NSMenu *main_menu = [[NSMenu alloc] initWithTitle:@""];
+ menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
+ [main_menu setSubmenu:apple_menu forItem:menu_item];
+ [NSApp setMainMenu:main_menu];
+
+ [main_menu release];
+ [apple_menu release];
[NSApp finishLaunching];
@@ -1676,11 +1776,13 @@ OS_OSX::OS_OSX() {
cursor_shape = CURSOR_ARROW;
- current_screen = 0;
-
maximized = false;
minimized = false;
window_size = Vector2(1024, 600);
zoomed = false;
display_scale = 1.0;
}
+
+bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
+ return p_feature == "pc" || p_feature == "s3tc";
+}
diff --git a/platform/server/detect.py b/platform/server/detect.py
index 32f3c5513..2bb4b59e9 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -1,4 +1,3 @@
-
import os
import sys
@@ -13,17 +12,16 @@ def get_name():
def can_build():
- if (os.name != "posix"):
+ if (os.name != "posix" or sys.platform == "darwin"):
return False
- return True # enabled
+ return True
def get_opts():
return [
- ('use_llvm', 'Use llvm compiler', 'no'),
- ('force_32_bits', 'Force 32 bits binary', 'no')
+ ('use_llvm', 'Use the LLVM compiler', 'no'),
]
@@ -35,46 +33,59 @@ def get_flags():
def configure(env):
- env.Append(CPPPATH=['#platform/server'])
- if (env["use_llvm"] == "yes"):
- env["CC"] = "clang"
- env["CXX"] = "clang++"
- env["LD"] = "clang++"
-
- is64 = sys.maxsize > 2**32
-
- if (env["bits"] == "default"):
- if (is64):
- env["bits"] = "64"
- else:
- env["bits"] = "32"
-
- # if (env["tools"]=="no"):
- # #no tools suffix
- # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
- # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+ ## Build type
if (env["target"] == "release"):
-
env.Append(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer'])
elif (env["target"] == "release_debug"):
-
env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
elif (env["target"] == "debug"):
-
env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ ## Architecture
+
+ is64 = sys.maxsize > 2**32
+ if (env["bits"] == "default"):
+ env["bits"] = "64" if is64 else "32"
+
+ ## Compiler configuration
+
+ if (env["use_llvm"] == "yes"):
+ if ('clang++' not in env['CXX']):
+ env["CC"] = "clang"
+ env["CXX"] = "clang++"
+ env["LD"] = "clang++"
+ env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
+ env.extra_suffix = ".llvm" + env.extra_suffix
+
+ ## Dependencies
- # Shared libraries, when requested
+ # FIXME: Check for existence of the libs before parsing their flags with pkg-config
if (env['builtin_openssl'] == 'no'):
+ # Currently not compatible with OpenSSL 1.1.0+
+ # https://github.com/godotengine/godot/issues/8624
+ import subprocess
+ openssl_version = subprocess.check_output(['pkg-config', 'openssl', '--modversion']).strip('\n')
+ if (openssl_version >= "1.1.0"):
+ print("Error: Found system-installed OpenSSL %s, currently only supporting version 1.0.x." % openssl_version)
+ print("Aborting.. You can compile with 'builtin_openssl=yes' to use the bundled version.\n")
+ sys.exit(255)
+
env.ParseConfig('pkg-config openssl --cflags --libs')
if (env['builtin_libwebp'] == 'no'):
env.ParseConfig('pkg-config libwebp --cflags --libs')
+ # freetype depends on libpng and zlib, so bundling one of them while keeping others
+ # as shared libraries leads to weird issues
+ if (env['builtin_freetype'] == 'yes' or env['builtin_libpng'] == 'yes' or env['builtin_zlib'] == 'yes'):
+ env['builtin_freetype'] = 'yes'
+ env['builtin_libpng'] = 'yes'
+ env['builtin_zlib'] = 'yes'
+
if (env['builtin_freetype'] == 'no'):
env.ParseConfig('pkg-config freetype2 --cflags --libs')
@@ -109,11 +120,12 @@ def configure(env):
if (env['builtin_libogg'] == 'no'):
env.ParseConfig('pkg-config ogg --cflags --libs')
+ ## Flags
- env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED'])
- env.Append(LIBS=['pthread', 'z']) # TODO detect linux/BSD!
+ # Linkflags below this line should typically stay the last ones
+ if (env['builtin_zlib'] == 'no'):
+ env.ParseConfig('pkg-config zlib --cflags --libs')
- if (env["CXX"] == "clang++"):
- env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
- env["CC"] = "clang"
- env["LD"] = "clang++"
+ env.Append(CPPPATH=['#platform/server'])
+ env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED'])
+ env.Append(LIBS=['pthread'])
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index baff7f978..64dac93f1 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -1,8 +1,7 @@
+import methods
import os
-
-import sys
import string
-import methods
+import sys
def is_active():
@@ -26,7 +25,9 @@ def can_build():
def get_opts():
- return []
+
+ return [
+ ]
def get_flags():
@@ -39,16 +40,36 @@ def get_flags():
def configure(env):
- if(env["bits"] != "default"):
- print "Error: bits argument is disabled for MSVC"
- print ("Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings)"
- + " that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler"
- + " will be executed and inform you.")
+ if (env["bits"] != "default"):
+ print("Error: bits argument is disabled for MSVC")
+ print("""
+ Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console
+ (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits
+ argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
+ """)
sys.exit()
- arch = ""
- env['ENV'] = os.environ
+ ## Build type
+ if (env["target"] == "release"):
+ env.Append(CPPFLAGS=['/O2', '/GL'])
+ env.Append(CPPFLAGS=['/MD'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG'])
+
+ elif (env["target"] == "release_debug"):
+ env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['/MD'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+
+ elif (env["target"] == "debug"):
+ env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED'])
+ env.Append(CPPFLAGS=['/MDd'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ env.Append(LINKFLAGS=['/DEBUG'])
+
+ ## Compiler configuration
+
+ env['ENV'] = os.environ
vc_base_path = os.environ['VCTOOLSINSTALLDIR'] if "VCTOOLSINSTALLDIR" in os.environ else os.environ['VCINSTALLDIR']
# ANGLE
@@ -60,9 +81,12 @@ def configure(env):
if os.path.isfile(str(os.getenv("ANGLE_SRC_PATH")) + "/winrt/10/src/angle.sln"):
env["build_angle"] = True
+ ## Architecture
+
+ arch = ""
if os.getenv('Platform') == "ARM":
- print "Compiled program architecture will be an ARM executable. (forcing bits=32)."
+ print("Compiled program architecture will be an ARM executable. (forcing bits=32).")
arch = "arm"
env["bits"] = "32"
@@ -74,17 +98,16 @@ def configure(env):
env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_ARM/lib'])
else:
-
compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV'])
if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"):
env["bits"] = "64"
- print "Compiled program architecture will be a x64 executable (forcing bits=64)."
+ print("Compiled program architecture will be a x64 executable (forcing bits=64).")
elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"):
env["bits"] = "32"
- print "Compiled program architecture will be a x86 executable. (forcing bits=32)."
+ print("Compiled program architecture will be a x86 executable. (forcing bits=32).")
else:
- print "Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup."
+ print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.")
env["bits"] = "32"
if (env["bits"] == "32"):
@@ -92,7 +115,6 @@ def configure(env):
angle_build_cmd += "Win32"
- env.Append(CPPFLAGS=['/DPNG_ABORT=abort'])
env.Append(LINKFLAGS=['/MACHINE:X86'])
env.Append(LIBPATH=[vc_base_path + 'lib/store'])
env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_Win32/lib'])
@@ -106,48 +128,30 @@ def configure(env):
env.Append(LIBPATH=[os.environ['VCINSTALLDIR'] + 'lib/store/amd64'])
env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_x64/lib'])
- env.Append(CPPPATH=['#platform/uwp', '#drivers/windows'])
- env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"'])
- env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32'])
-
- env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references'])
- env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references'])
+ env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"]
+ env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"]
+ env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"]
- if (env["target"] == "release"):
+ ## Compile flags
- env.Append(CPPFLAGS=['/O2', '/GL'])
- env.Append(CPPFLAGS=['/MD'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG'])
-
- elif (env["target"] == "release_debug"):
-
- env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED'])
- env.Append(CPPFLAGS=['/MD'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ env.Append(CPPPATH=['#platform/uwp', '#drivers/windows'])
+ env.Append(CCFLAGS=['/DUWP_ENABLED', '/DWINDOWS_ENABLED', '/DTYPED_METHOD_BIND'])
+ env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED'])
+ winver = "0x0602" # Windows 8 is the minimum target for UWP build
+ env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver])
- elif (env["target"] == "debug"):
+ env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32', '/DPNG_ABORT=abort'])
- env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED'])
- env.Append(CPPFLAGS=['/MDd'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG'])
+ env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references'])
+ env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references'])
env.Append(CCFLAGS=string.split('/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo'))
env.Append(CXXFLAGS=string.split('/ZW /FS'))
env.Append(CCFLAGS=['/AI', vc_base_path + '\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR'] + '\\References\\CommonConfiguration\\Neutral'])
- env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"]
- env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"]
- env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"]
-
- env.Append(CCFLAGS=['/DUWP_ENABLED'])
- env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
- env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
-
- env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED'])
+ ## Link flags
- winver = "0x0602" # Windows 8 is the minimum target for UWP build
- env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver])
+ env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"'])
LIBS = [
'WindowsApp',
@@ -164,8 +168,3 @@ def configure(env):
env['BUILDERS']['Program'] = methods.precious_program
env.Append(BUILDERS={'ANGLE': env.Builder(action=angle_build_cmd)})
-
- env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'HLSL9': env.Builder(action=methods.build_hlsl_dx9_headers, suffix='hlsl.h', src_suffix='.hlsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 976e6208e..a1aa58a5e 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -28,55 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-/*************************************************************************
- * The code for signing the package was ported from fb-util-for-appx
- * available at https://github.com/facebook/fb-util-for-appx
- * and distributed also under the following license:
-
-BSD License
-
-For fb-util-for-appx software
-
-Copyright (c) 2016, Facebook, Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- * Neither the name Facebook nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*************************************************************************/
-
-#if 0
#include "export.h"
#include "bind/core_bind.h"
-#include "editor/editor_import_export.h"
+#include "editor/editor_export.h"
#include "editor/editor_node.h"
-#include "global_config.h"
#include "io/marshalls.h"
#include "io/zip_io.h"
#include "object.h"
#include "os/file_access.h"
-#include "platform/uwp/logo.h"
+#include "platform/uwp/logo.gen.h"
+#include "project_settings.h"
#include "version.h"
#include "thirdparty/minizip/unzip.h"
@@ -87,7 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <zlib.h>
// Capabilities
-static const char* uwp_capabilities[] = {
+static const char *uwp_capabilities[] = {
"allJoyn",
"codeGeneration",
"internetClient",
@@ -95,7 +56,7 @@ static const char* uwp_capabilities[] = {
"privateNetworkClientServer",
NULL
};
-static const char* uwp_uap_capabilities[] = {
+static const char *uwp_uap_capabilities[] = {
"appointments",
"blockedChatMessages",
"chat",
@@ -112,7 +73,7 @@ static const char* uwp_uap_capabilities[] = {
"voipCall",
NULL
};
-static const char* uwp_device_capabilites[] = {
+static const char *uwp_device_capabilites[] = {
"bluetooth",
"location",
"microphone",
@@ -121,166 +82,6 @@ static const char* uwp_device_capabilites[] = {
NULL
};
-#ifdef OPENSSL_ENABLED
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/ossl_typ.h>
-#include <openssl/pkcs12.h>
-#include <openssl/pkcs7.h>
-#include <openssl/x509.h>
-
-namespace asn1 {
- // https://msdn.microsoft.com/en-us/gg463180.aspx
-
- struct SPCStatementType {
- ASN1_OBJECT *type;
- };
- DECLARE_ASN1_FUNCTIONS(SPCStatementType)
-
- struct SPCSpOpusInfo {
- ASN1_TYPE *programName;
- ASN1_TYPE *moreInfo;
- };
- DECLARE_ASN1_FUNCTIONS(SPCSpOpusInfo)
-
- struct DigestInfo {
- X509_ALGOR *digestAlgorithm;
- ASN1_OCTET_STRING *digest;
- };
- DECLARE_ASN1_FUNCTIONS(DigestInfo)
-
- struct SPCAttributeTypeAndOptionalValue {
- ASN1_OBJECT *type;
- ASN1_TYPE *value; // SPCInfoValue
- };
- DECLARE_ASN1_FUNCTIONS(SPCAttributeTypeAndOptionalValue)
-
- // Undocumented.
- struct SPCInfoValue {
- ASN1_INTEGER *i1;
- ASN1_OCTET_STRING *s1;
- ASN1_INTEGER *i2;
- ASN1_INTEGER *i3;
- ASN1_INTEGER *i4;
- ASN1_INTEGER *i5;
- ASN1_INTEGER *i6;
- };
- DECLARE_ASN1_FUNCTIONS(SPCInfoValue)
-
- struct SPCIndirectDataContent {
- SPCAttributeTypeAndOptionalValue *data;
- DigestInfo *messageDigest;
- };
- DECLARE_ASN1_FUNCTIONS(SPCIndirectDataContent)
-
- IMPLEMENT_ASN1_FUNCTIONS(SPCIndirectDataContent)
- ASN1_SEQUENCE(SPCIndirectDataContent) = {
- ASN1_SIMPLE(SPCIndirectDataContent, data,
- SPCAttributeTypeAndOptionalValue),
- ASN1_SIMPLE(SPCIndirectDataContent, messageDigest, DigestInfo),
- } ASN1_SEQUENCE_END(SPCIndirectDataContent)
-
- IMPLEMENT_ASN1_FUNCTIONS(SPCAttributeTypeAndOptionalValue)
- ASN1_SEQUENCE(SPCAttributeTypeAndOptionalValue) = {
- ASN1_SIMPLE(SPCAttributeTypeAndOptionalValue, type,
- ASN1_OBJECT),
- ASN1_OPT(SPCAttributeTypeAndOptionalValue, value, ASN1_ANY),
- } ASN1_SEQUENCE_END(SPCAttributeTypeAndOptionalValue)
-
- IMPLEMENT_ASN1_FUNCTIONS(SPCInfoValue)
- ASN1_SEQUENCE(SPCInfoValue) = {
- ASN1_SIMPLE(SPCInfoValue, i1, ASN1_INTEGER),
- ASN1_SIMPLE(SPCInfoValue, s1, ASN1_OCTET_STRING),
- ASN1_SIMPLE(SPCInfoValue, i2, ASN1_INTEGER),
- ASN1_SIMPLE(SPCInfoValue, i3, ASN1_INTEGER),
- ASN1_SIMPLE(SPCInfoValue, i4, ASN1_INTEGER),
- ASN1_SIMPLE(SPCInfoValue, i5, ASN1_INTEGER),
- ASN1_SIMPLE(SPCInfoValue, i6, ASN1_INTEGER),
- } ASN1_SEQUENCE_END(SPCInfoValue)
-
- IMPLEMENT_ASN1_FUNCTIONS(DigestInfo)
- ASN1_SEQUENCE(DigestInfo) = {
- ASN1_SIMPLE(DigestInfo, digestAlgorithm, X509_ALGOR),
- ASN1_SIMPLE(DigestInfo, digest, ASN1_OCTET_STRING),
- } ASN1_SEQUENCE_END(DigestInfo)
-
- ASN1_SEQUENCE(SPCSpOpusInfo) = {
- ASN1_OPT(SPCSpOpusInfo, programName, ASN1_ANY),
- ASN1_OPT(SPCSpOpusInfo, moreInfo, ASN1_ANY),
- } ASN1_SEQUENCE_END(SPCSpOpusInfo)
- IMPLEMENT_ASN1_FUNCTIONS(SPCSpOpusInfo)
-
- ASN1_SEQUENCE(SPCStatementType) = {
- ASN1_SIMPLE(SPCStatementType, type, ASN1_OBJECT),
- } ASN1_SEQUENCE_END(SPCStatementType)
- IMPLEMENT_ASN1_FUNCTIONS(SPCStatementType)
-}
-
-class EncodedASN1 {
-
- uint8_t* i_data;
- size_t i_size;
-
- EncodedASN1(uint8_t** p_data, size_t p_size) {
-
- i_data = *p_data;
- i_size = p_size;
- }
-
-public:
-
- template <typename T, int(*TEncode)(T *, uint8_t **)>
- static EncodedASN1 FromItem(T *item) {
- uint8_t *dataRaw = NULL;
- int size = TEncode(item, &dataRaw);
-
- return EncodedASN1(&dataRaw, size);
- }
-
- const uint8_t *data() const {
- return i_data;
- }
-
- size_t size() const {
- return i_size;
- }
-
- // Assumes the encoded ASN.1 represents a SEQUENCE and puts it into
- // an ASN1_STRING.
- //
- // The returned object holds a copy of this object's data.
- ASN1_STRING* ToSequenceString() {
- ASN1_STRING* string = ASN1_STRING_new();
- if (!string) {
- return NULL;
- }
- if (!ASN1_STRING_set(string, i_data, i_size)) {
- return NULL;
- }
- return string;
- }
-
- // Assumes the encoded ASN.1 represents a SEQUENCE and puts it into
- // an ASN1_TYPE.
- //
- // The returned object holds a copy of this object's data.
- ASN1_TYPE* ToSequenceType() {
- ASN1_STRING* string = ToSequenceString();
- ASN1_TYPE* type = ASN1_TYPE_new();
- if (!type) {
- return NULL;
- }
- type->type = V_ASN1_SEQUENCE;
- type->value.sequence = string;
- return type;
- }
-
-};
-
-#endif // OPENSSL_ENABLED
-
class AppxPackager {
enum {
@@ -336,34 +137,33 @@ class AppxPackager {
ZPOS64_T end_of_central_dir_offset;
Vector<uint8_t> central_dir_data;
- String hash_block(uint8_t* p_block_data, size_t p_block_len);
+ String hash_block(uint8_t *p_block_data, size_t p_block_len);
void make_block_map();
void make_content_types();
-
- _FORCE_INLINE_ unsigned int buf_put_int16(uint16_t p_val, uint8_t * p_buf) {
+ _FORCE_INLINE_ unsigned int buf_put_int16(uint16_t p_val, uint8_t *p_buf) {
for (int i = 0; i < 2; i++) {
*p_buf++ = (p_val >> (i * 8)) & 0xFF;
}
return 2;
}
- _FORCE_INLINE_ unsigned int buf_put_int32(uint32_t p_val, uint8_t * p_buf) {
+ _FORCE_INLINE_ unsigned int buf_put_int32(uint32_t p_val, uint8_t *p_buf) {
for (int i = 0; i < 4; i++) {
*p_buf++ = (p_val >> (i * 8)) & 0xFF;
}
return 4;
}
- _FORCE_INLINE_ unsigned int buf_put_int64(uint64_t p_val, uint8_t * p_buf) {
+ _FORCE_INLINE_ unsigned int buf_put_int64(uint64_t p_val, uint8_t *p_buf) {
for (int i = 0; i < 8; i++) {
*p_buf++ = (p_val >> (i * 8)) & 0xFF;
}
return 8;
}
- _FORCE_INLINE_ unsigned int buf_put_string(String p_val, uint8_t * p_buf) {
+ _FORCE_INLINE_ unsigned int buf_put_string(String p_val, uint8_t *p_buf) {
for (int i = 0; i < p_val.length(); i++) {
*p_buf++ = p_val.utf8().get(i);
}
@@ -376,168 +176,19 @@ class AppxPackager {
String content_type(String p_extension);
-#ifdef OPENSSL_ENABLED
-
- // Signing methods and structs:
-
- String certificate_path;
- String certificate_pass;
- bool sign_package;
-
- struct CertFile {
-
- EVP_PKEY* private_key;
- X509* certificate;
- };
-
- SHA256_CTX axpc_context; // SHA256 context for ZIP file entries
- SHA256_CTX axcd_context; // SHA256 context for ZIP directory entries
-
- struct AppxDigests {
-
- uint8_t axpc[SHA256_DIGEST_LENGTH]; // ZIP file entries
- uint8_t axcd[SHA256_DIGEST_LENGTH]; // ZIP directory entry
- uint8_t axct[SHA256_DIGEST_LENGTH]; // Content types XML
- uint8_t axbm[SHA256_DIGEST_LENGTH]; // Block map XML
- uint8_t axci[SHA256_DIGEST_LENGTH]; // Code Integrity file (optional)
- };
-
- CertFile cert_file;
- AppxDigests digests;
-
- void MakeSPCInfoValue(asn1::SPCInfoValue &info);
- Error MakeIndirectDataContent(asn1::SPCIndirectDataContent &idc);
- Error add_attributes(PKCS7_SIGNER_INFO *signerInfo);
- void make_digests();
- void write_digest(Vector<uint8_t> &p_out_buffer);
-
- Error openssl_error(unsigned long p_err);
- Error read_cert_file(const String &p_path, const String &p_password, CertFile* p_out_cf);
- Error sign(const CertFile &p_cert, const AppxDigests &digests, PKCS7* p_out_signature);
-
-#endif // OPENSSL_ENABLED
-
public:
-
- enum SignOption {
-
- SIGN,
- DONT_SIGN,
- };
-
void set_progress_task(String p_task) { progress_task = p_task; }
- void init(FileAccess* p_fa, SignOption p_sign, String &p_certificate_path, String &p_certificate_password);
- void add_file(String p_file_name, const uint8_t* p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false);
+ void init(FileAccess *p_fa);
+ void add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false);
void finish();
AppxPackager();
~AppxPackager();
};
-class EditorExportPlatformUWP : public EditorExportPlatform {
-
- GDCLASS(EditorExportPlatformUWP, EditorExportPlatform);
-
- Ref<ImageTexture> logo;
-
- enum Platform {
- ARM,
- X86,
- X64
- } arch;
-
- bool is_debug;
-
- String custom_release_package;
- String custom_debug_package;
-
- String cmdline;
-
- String display_name;
- String short_name;
- String unique_name;
- String description;
- String publisher;
- String publisher_display_name;
-
- String product_guid;
- String publisher_guid;
-
- int version_major;
- int version_minor;
- int version_build;
- int version_revision;
-
- bool orientation_landscape;
- bool orientation_portrait;
- bool orientation_landscape_flipped;
- bool orientation_portrait_flipped;
-
- String background_color;
- Ref<ImageTexture> store_logo;
- Ref<ImageTexture> square44;
- Ref<ImageTexture> square71;
- Ref<ImageTexture> square150;
- Ref<ImageTexture> square310;
- Ref<ImageTexture> wide310;
- Ref<ImageTexture> splash;
-
- bool name_on_square150;
- bool name_on_square310;
- bool name_on_wide;
-
- Set<String> capabilities;
- Set<String> uap_capabilities;
- Set<String> device_capabilities;
-
- bool sign_package;
- String certificate_path;
- String certificate_pass;
-
- _FORCE_INLINE_ bool array_has(const char** p_array, const char* p_value) const {
- while (*p_array) {
- if (String(*p_array) == String(p_value)) return true;
- p_array++;
- }
- return false;
- }
-
- bool _valid_resource_name(const String &p_name) const;
- bool _valid_guid(const String &p_guid) const;
- bool _valid_bgcolor(const String &p_color) const;
- bool _valid_image(const Ref<ImageTexture> p_image, int p_width, int p_height) const;
-
- Vector<uint8_t> _fix_manifest(const Vector<uint8_t> &p_template, bool p_give_internet) const;
- Vector<uint8_t> _get_image_data(const String &p_path);
-
- static Error save_appx_file(void *p_userdata, const String& p_path, const Vector<uint8_t>& p_data, int p_file, int p_total);
- static bool _should_compress_asset(const String& p_path, const Vector<uint8_t>& p_data);
-
-protected:
-
- bool _set(const StringName& p_name, const Variant& p_value);
- bool _get(const StringName& p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
-
- virtual String get_name() const { return "Windows Universal"; }
- virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_ETC1; }
- virtual Ref<Texture> get_logo() const { return logo; }
-
- virtual bool can_export(String *r_error = NULL) const;
- virtual String get_binary_extension() const { return "appx"; }
-
- virtual Error export_project(const String& p_path, bool p_debug, int p_flags = 0);
-
- EditorExportPlatformUWP();
- ~EditorExportPlatformUWP();
-};
-
-
///////////////////////////////////////////////////////////////////////////
-String AppxPackager::hash_block(uint8_t * p_block_data, size_t p_block_len) {
+String AppxPackager::hash_block(uint8_t *p_block_data, size_t p_block_len) {
char hash[32];
char base64[45];
@@ -545,7 +196,7 @@ String AppxPackager::hash_block(uint8_t * p_block_data, size_t p_block_len) {
sha256_context ctx;
sha256_init(&ctx);
sha256_hash(&ctx, p_block_data, p_block_len);
- sha256_done(&ctx, (uint8_t*)hash);
+ sha256_done(&ctx, (uint8_t *)hash);
base64_encode(base64, hash, 32);
base64[44] = '\0';
@@ -555,7 +206,7 @@ String AppxPackager::hash_block(uint8_t * p_block_data, size_t p_block_len) {
void AppxPackager::make_block_map() {
- FileAccess* tmp_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::WRITE);
+ FileAccess *tmp_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::WRITE);
tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
tmp_file->store_string("<BlockMap xmlns=\"http://schemas.microsoft.com/appx/2010/blockmap\" HashMethod=\"http://www.w3.org/2001/04/xmlenc#sha256\">");
@@ -565,15 +216,11 @@ void AppxPackager::make_block_map() {
FileMeta file = file_metadata[i];
tmp_file->store_string(
- "<File Name=\"" + file.name.replace("/", "\\")
- + "\" Size=\"" + itos(file.uncompressed_size)
- + "\" LfhSize=\"" + itos(file.lfh_size) + "\">");
-
+ "<File Name=\"" + file.name.replace("/", "\\") + "\" Size=\"" + itos(file.uncompressed_size) + "\" LfhSize=\"" + itos(file.lfh_size) + "\">");
for (int j = 0; j < file.hashes.size(); j++) {
- tmp_file->store_string("<Block Hash=\""
- + file.hashes[j].base64_hash + "\" ");
+ tmp_file->store_string("<Block Hash=\"" + file.hashes[j].base64_hash + "\" ");
if (file.compressed)
tmp_file->store_string("Size=\"" + itos(file.hashes[j].compressed_size) + "\" ");
tmp_file->store_string("/>");
@@ -605,12 +252,12 @@ String AppxPackager::content_type(String p_extension) {
void AppxPackager::make_content_types() {
- FileAccess* tmp_file = FileAccess::open(tmp_content_types_file_path, FileAccess::WRITE);
+ FileAccess *tmp_file = FileAccess::open(tmp_content_types_file_path, FileAccess::WRITE);
tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
tmp_file->store_string("<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
- Map<String, String> types;
+ Map<String, String> types;
for (int i = 0; i < file_metadata.size(); i++) {
@@ -688,7 +335,6 @@ void AppxPackager::store_central_dir_header(const FileMeta p_file, bool p_do_has
int offs = buf.size();
buf.resize(buf.size() + BASE_CENTRAL_DIR_SIZE + p_file.name.length());
-
// Write magic
offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf[offs]);
@@ -732,12 +378,6 @@ void AppxPackager::store_central_dir_header(const FileMeta p_file, bool p_do_has
// File name
offs += buf_put_string(p_file.name, &buf[offs]);
-#ifdef OPENSSL_ENABLED
- // Calculate the hash for signing
- if (p_do_hash)
- SHA256_Update(&axcd_context, buf.ptr(), buf.size());
-#endif // OPENSSL_ENABLED
-
// Done!
}
@@ -811,23 +451,16 @@ Vector<uint8_t> AppxPackager::make_end_of_central_record() {
return buf;
}
-void AppxPackager::init(FileAccess * p_fa, SignOption p_sign, String &p_certificate_path, String &p_certificate_password) {
+void AppxPackager::init(FileAccess *p_fa) {
package = p_fa;
central_dir_offset = 0;
end_of_central_dir_offset = 0;
tmp_blockmap_file_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpblockmap.xml";
tmp_content_types_file_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpcontenttypes.xml";
-#ifdef OPENSSL_ENABLED
- certificate_path = p_certificate_path;
- certificate_pass = p_certificate_password;
- sign_package = p_sign == SIGN;
- SHA256_Init(&axpc_context);
- SHA256_Init(&axcd_context);
-#endif // OPENSSL_ENABLED
}
-void AppxPackager::add_file(String p_file_name, const uint8_t * p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) {
+void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) {
if (p_file_no >= 1 && p_total_files >= 1) {
EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files);
@@ -846,7 +479,7 @@ void AppxPackager::add_file(String p_file_name, const uint8_t * p_buffer, size_t
// Data for compression
z_stream strm;
- FileAccess* strm_f = NULL;
+ FileAccess *strm_f = NULL;
Vector<uint8_t> strm_in;
strm_in.resize(BLOCK_SIZE);
Vector<uint8_t> strm_out;
@@ -892,11 +525,6 @@ void AppxPackager::add_file(String p_file_name, const uint8_t * p_buffer, size_t
file_buffer.resize(file_buffer.size() + bh.compressed_size);
for (int i = 0; i < bh.compressed_size; i++)
file_buffer[start + i] = strm_out[i];
-#ifdef OPENSSL_ENABLED
- if (do_hash)
- SHA256_Update(&axpc_context, strm_out.ptr(), strm.total_out - total_out_before);
-#endif // OPENSSL_ENABLED
-
} else {
bh.compressed_size = block_size;
//package->store_buffer(strm_in.ptr(), block_size);
@@ -904,10 +532,6 @@ void AppxPackager::add_file(String p_file_name, const uint8_t * p_buffer, size_t
file_buffer.resize(file_buffer.size() + block_size);
for (int i = 0; i < bh.compressed_size; i++)
file_buffer[start + i] = strm_in[i];
-#ifdef OPENSSL_ENABLED
- if (do_hash)
- SHA256_Update(&axpc_context, strm_in.ptr(), block_size);
-#endif // OPENSSL_ENABLED
}
meta.hashes.push_back(bh);
@@ -931,10 +555,6 @@ void AppxPackager::add_file(String p_file_name, const uint8_t * p_buffer, size_t
file_buffer.resize(file_buffer.size() + (strm.total_out - total_out_before));
for (int i = 0; i < (strm.total_out - total_out_before); i++)
file_buffer[start + i] = strm_out[i];
-#ifdef OPENSSL_ENABLED
- if (do_hash)
- SHA256_Update(&axpc_context, strm_out.ptr(), strm.total_out - total_out_before);
-#endif // OPENSSL_ENABLED
deflateEnd(&strm);
meta.compressed_size = strm.total_out;
@@ -953,14 +573,6 @@ void AppxPackager::add_file(String p_file_name, const uint8_t * p_buffer, size_t
Vector<uint8_t> file_header = make_file_header(meta);
meta.lfh_size = file_header.size();
-#ifdef OPENSSL_ENABLED
- // Hash the data for signing
- if (do_hash) {
- SHA256_Update(&axpc_context, file_header.ptr(), file_header.size());
- SHA256_Update(&axpc_context, file_buffer.ptr(), file_buffer.size());
- }
-#endif // OPENSSL_ENABLED
-
// Store the header and file;
package->store_buffer(file_header.ptr(), file_header.size());
package->store_buffer(file_buffer.ptr(), file_buffer.size());
@@ -974,22 +586,12 @@ void AppxPackager::finish() {
EditorNode::progress_task_step("export", "Creating block map...", 4);
make_block_map();
- FileAccess* blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
+ FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
Vector<uint8_t> blockmap_buffer;
blockmap_buffer.resize(blockmap_file->get_len());
blockmap_file->get_buffer(blockmap_buffer.ptr(), blockmap_buffer.size());
-#ifdef OPENSSL_ENABLED
- // Hash the file for signing
- if (sign_package) {
- SHA256_CTX axbm_context;
- SHA256_Init(&axbm_context);
- SHA256_Update(&axbm_context, blockmap_buffer.ptr(), blockmap_buffer.size());
- SHA256_Final(digests.axbm, &axbm_context);
- }
-#endif // OPENSSL_ENABLED
-
add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true);
blockmap_file->close();
@@ -1000,22 +602,12 @@ void AppxPackager::finish() {
EditorNode::progress_task_step("export", "Setting content types...", 5);
make_content_types();
- FileAccess* types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
+ FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
Vector<uint8_t> types_buffer;
types_buffer.resize(types_file->get_len());
types_file->get_buffer(types_buffer.ptr(), types_buffer.size());
-#ifdef OPENSSL_ENABLED
- if (sign_package) {
- // Hash the file for signing
- SHA256_CTX axct_context;
- SHA256_Init(&axct_context);
- SHA256_Update(&axct_context, types_buffer.ptr(), types_buffer.size());
- SHA256_Final(digests.axct, &axct_context);
- }
-#endif // OPENSSL_ENABLED
-
add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true);
types_file->close();
@@ -1027,76 +619,6 @@ void AppxPackager::finish() {
store_central_dir_header(file_metadata[i]);
}
-#ifdef OPENSSL_ENABLED
- // Create the signature file
- if (sign_package) {
-
- Error err = read_cert_file(certificate_path, certificate_pass, &cert_file);
-
- if (err != OK) {
- EditorNode::add_io_error(TTR("Couldn't read the certificate file. Are the path and password both correct?"));
- package->close();
- memdelete(package);
- package = NULL;
- return;
- }
-
-
- // Make a temp end of the zip for hashing
- central_dir_offset = package->get_pos();
- end_of_central_dir_offset = central_dir_offset + central_dir_data.size();
- Vector<uint8_t> zip_end_dir = make_end_of_central_record();
-
- // Hash the end directory
- SHA256_Update(&axcd_context, zip_end_dir.ptr(), zip_end_dir.size());
-
- // Finish the hashes
- make_digests();
-
- PKCS7* signature = PKCS7_new();
- if (!signature) {
- EditorNode::add_io_error(TTR("Error creating the signature object."));
- package->close();
- memdelete(package);
- package = NULL;
- return;
- }
-
- err = sign(cert_file, digests, signature);
-
- if (err != OK) {
- EditorNode::add_io_error(TTR("Error creating the package signature."));
- package->close();
- memdelete(package);
- package = NULL;
- return;
- }
-
- // Read the signature as bytes
- BIO* bio_out = BIO_new(BIO_s_mem());
- i2d_PKCS7_bio(bio_out, signature);
-
- BIO_flush(bio_out);
-
- uint8_t* bio_ptr;
- size_t bio_size = BIO_get_mem_data(bio_out, &bio_ptr);
-
- // Create the signature buffer with magic number
- Vector<uint8_t> signature_file;
- signature_file.resize(4 + bio_size);
- buf_put_int32(P7X_SIGNATURE, signature_file.ptr());
- for (int i = 0; i < bio_size; i++)
- signature_file[i + 4] = bio_ptr[i];
-
- // Add the signature to the package
- add_file("AppxSignature.p7x", signature_file.ptr(), signature_file.size(), -1, -1, true);
-
- // Add central directory entry
- store_central_dir_header(file_metadata[file_metadata.size() - 1], false);
- }
-#endif // OPENSSL_ENABLED
-
-
// Write central directory
EditorNode::progress_task_step("export", "Finishing package...", 6);
central_dir_offset = package->get_pos();
@@ -1112,1284 +634,759 @@ void AppxPackager::finish() {
package = NULL;
}
-#ifdef OPENSSL_ENABLED
-// https://support.microsoft.com/en-us/kb/287547
-const char SPC_INDIRECT_DATA_OBJID[] = "1.3.6.1.4.1.311.2.1.4";
-const char SPC_STATEMENT_TYPE_OBJID[] = "1.3.6.1.4.1.311.2.1.11";
-const char SPC_SP_OPUS_INFO_OBJID[] = "1.3.6.1.4.1.311.2.1.12";
-const char SPC_SIPINFO_OBJID[] = "1.3.6.1.4.1.311.2.1.30";
-#endif // OPENSSL_ENABLED
-
AppxPackager::AppxPackager() {}
AppxPackager::~AppxPackager() {}
-
////////////////////////////////////////////////////////////////////
-#ifdef OPENSSL_ENABLED
-Error AppxPackager::openssl_error(unsigned long p_err) {
+class EditorExportUWP : public EditorExportPlatform {
- ERR_load_crypto_strings();
+ GDCLASS(EditorExportUWP, EditorExportPlatform);
- char buffer[256];
- ERR_error_string_n(p_err, buffer, sizeof(buffer));
-
- String err(buffer);
-
- ERR_EXPLAIN(err);
- ERR_FAIL_V(FAILED);
-}
-
-void AppxPackager::MakeSPCInfoValue(asn1::SPCInfoValue &info) {
+ Ref<ImageTexture> logo;
- // I have no idea what these numbers mean.
- static uint8_t s1Magic[] = {
- 0x4B, 0xDF, 0xC5, 0x0A, 0x07, 0xCE, 0xE2, 0x4D,
- 0xB7, 0x6E, 0x23, 0xC8, 0x39, 0xA0, 0x9F, 0xD1,
+ enum Platform {
+ ARM,
+ X86,
+ X64
};
- ASN1_INTEGER_set(info.i1, 0x01010000);
- ASN1_OCTET_STRING_set(info.s1, s1Magic, sizeof(s1Magic));
- ASN1_INTEGER_set(info.i2, 0x00000000);
- ASN1_INTEGER_set(info.i3, 0x00000000);
- ASN1_INTEGER_set(info.i4, 0x00000000);
- ASN1_INTEGER_set(info.i5, 0x00000000);
- ASN1_INTEGER_set(info.i6, 0x00000000);
-}
-
-Error AppxPackager::MakeIndirectDataContent(asn1::SPCIndirectDataContent &idc) {
-
- using namespace asn1;
-
- ASN1_TYPE* algorithmParameter = ASN1_TYPE_new();
- if (!algorithmParameter) {
- return openssl_error(ERR_peek_last_error());
- }
- algorithmParameter->type = V_ASN1_NULL;
- SPCInfoValue* infoValue = SPCInfoValue_new();
- if (!infoValue) {
- return openssl_error(ERR_peek_last_error());
- }
- MakeSPCInfoValue(*infoValue);
+ bool _valid_resource_name(const String &p_name) const {
- ASN1_TYPE* value =
- EncodedASN1::FromItem<asn1::SPCInfoValue,
- asn1::i2d_SPCInfoValue>(infoValue)
- .ToSequenceType();
+ if (p_name.empty()) return false;
+ if (p_name.ends_with(".")) return false;
- {
- Vector<uint8_t> digest;
- write_digest(digest);
- if (!ASN1_OCTET_STRING_set(idc.messageDigest->digest,
- digest.ptr(), digest.size())) {
+ static const char *invalid_names[] = {
+ "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
+ "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
+ NULL
+ };
- return openssl_error(ERR_peek_last_error());
+ const char **t = invalid_names;
+ while (*t) {
+ if (p_name == *t) return false;
+ t++;
}
- }
-
- idc.data->type = OBJ_txt2obj(SPC_SIPINFO_OBJID, 1);
- idc.data->value = value;
- idc.messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(NID_sha256);
- idc.messageDigest->digestAlgorithm->parameter = algorithmParameter;
-
- return OK;
-}
-
-Error AppxPackager::add_attributes(PKCS7_SIGNER_INFO * p_signer_info) {
-
- // Add opus attribute
- asn1::SPCSpOpusInfo* opus = asn1::SPCSpOpusInfo_new();
- if (!opus) return openssl_error(ERR_peek_last_error());
- ASN1_STRING* opus_value =
- EncodedASN1::FromItem<asn1::SPCSpOpusInfo,
- asn1::i2d_SPCSpOpusInfo>(opus)
- .ToSequenceString();
-
- if (!PKCS7_add_signed_attribute(
- p_signer_info,
- OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
- V_ASN1_SEQUENCE,
- opus_value
- )) {
-
- asn1::SPCSpOpusInfo_free(opus);
-
- ASN1_STRING_free(opus_value);
- return openssl_error(ERR_peek_last_error());
- }
-
- // Add content type attribute
- if (!PKCS7_add_signed_attribute(
- p_signer_info,
- NID_pkcs9_contentType,
- V_ASN1_OBJECT,
- OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)
- )) {
-
- asn1::SPCSpOpusInfo_free(opus);
- ASN1_STRING_free(opus_value);
- return openssl_error(ERR_peek_last_error());
- }
-
- // Add statement type attribute
- asn1::SPCStatementType* statement_type = asn1::SPCStatementType_new();
- if (!statement_type) return openssl_error(ERR_peek_last_error());
-
- statement_type->type = OBJ_nid2obj(NID_ms_code_ind);
- ASN1_STRING* statement_type_value =
- EncodedASN1::FromItem<asn1::SPCStatementType,
- asn1::i2d_SPCStatementType>(statement_type)
- .ToSequenceString();
-
- if (!PKCS7_add_signed_attribute(
- p_signer_info,
- OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
- V_ASN1_SEQUENCE,
- statement_type_value
- )) {
-
- ASN1_STRING_free(opus_value);
- asn1::SPCStatementType_free(statement_type);
- ASN1_STRING_free(statement_type_value);
-
- return openssl_error(ERR_peek_last_error());
+ return true;
}
- return OK;
-
-}
-
-void AppxPackager::make_digests() {
-
- // AXPC
- SHA256_Final(digests.axpc, &axpc_context);
-
- // AXCD
- SHA256_Final(digests.axcd, &axcd_context);
-
- // AXCI
- for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
- digests.axci[i] = 0;
-
-}
-
-void AppxPackager::write_digest(Vector<uint8_t>& p_out_buffer) {
+ bool _valid_guid(const String &p_guid) const {
- // Size of digests plus 6 32-bit magic numbers
- p_out_buffer.resize((SHA256_DIGEST_LENGTH * 5) + (6 * 4));
+ Vector<String> parts = p_guid.split("-");
- int offs = 0;
-
- // APPX
- uint32_t sig = 0x58505041;
- offs += buf_put_int32(sig, &p_out_buffer[offs]);
+ if (parts.size() != 5) return false;
+ if (parts[0].length() != 8) return false;
+ for (int i = 1; i < 4; i++)
+ if (parts[i].length() != 4) return false;
+ if (parts[4].length() != 12) return false;
- // AXPC
- uint32_t axpc_sig = 0x43505841;
- offs += buf_put_int32(axpc_sig, &p_out_buffer[offs]);
- for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- p_out_buffer[offs++] = digests.axpc[i];
+ return true;
}
- // AXCD
- uint32_t axcd_sig = 0x44435841;
- offs += buf_put_int32(axcd_sig, &p_out_buffer[offs]);
- for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- p_out_buffer[offs++] = digests.axcd[i];
- }
+ bool _valid_bgcolor(const String &p_color) const {
- // AXCT
- uint32_t axct_sig = 0x54435841;
- offs += buf_put_int32(axct_sig, &p_out_buffer[offs]);
- for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- p_out_buffer[offs++] = digests.axct[i];
- }
+ if (p_color.empty()) return true;
+ if (p_color.begins_with("#") && p_color.is_valid_html_color()) return true;
- // AXBM
- uint32_t axbm_sig = 0x4D425841;
- offs += buf_put_int32(axbm_sig, &p_out_buffer[offs]);
- for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- p_out_buffer[offs++] = digests.axbm[i];
- }
+ // Colors from https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
+ static const char *valid_colors[] = {
+ "aliceBlue", "antiqueWhite", "aqua", "aquamarine", "azure", "beige",
+ "bisque", "black", "blanchedAlmond", "blue", "blueViolet", "brown",
+ "burlyWood", "cadetBlue", "chartreuse", "chocolate", "coral", "cornflowerBlue",
+ "cornsilk", "crimson", "cyan", "darkBlue", "darkCyan", "darkGoldenrod",
+ "darkGray", "darkGreen", "darkKhaki", "darkMagenta", "darkOliveGreen", "darkOrange",
+ "darkOrchid", "darkRed", "darkSalmon", "darkSeaGreen", "darkSlateBlue", "darkSlateGray",
+ "darkTurquoise", "darkViolet", "deepPink", "deepSkyBlue", "dimGray", "dodgerBlue",
+ "firebrick", "floralWhite", "forestGreen", "fuchsia", "gainsboro", "ghostWhite",
+ "gold", "goldenrod", "gray", "green", "greenYellow", "honeydew",
+ "hotPink", "indianRed", "indigo", "ivory", "khaki", "lavender",
+ "lavenderBlush", "lawnGreen", "lemonChiffon", "lightBlue", "lightCoral", "lightCyan",
+ "lightGoldenrodYellow", "lightGreen", "lightGray", "lightPink", "lightSalmon", "lightSeaGreen",
+ "lightSkyBlue", "lightSlateGray", "lightSteelBlue", "lightYellow", "lime", "limeGreen",
+ "linen", "magenta", "maroon", "mediumAquamarine", "mediumBlue", "mediumOrchid",
+ "mediumPurple", "mediumSeaGreen", "mediumSlateBlue", "mediumSpringGreen", "mediumTurquoise", "mediumVioletRed",
+ "midnightBlue", "mintCream", "mistyRose", "moccasin", "navajoWhite", "navy",
+ "oldLace", "olive", "oliveDrab", "orange", "orangeRed", "orchid",
+ "paleGoldenrod", "paleGreen", "paleTurquoise", "paleVioletRed", "papayaWhip", "peachPuff",
+ "peru", "pink", "plum", "powderBlue", "purple", "red",
+ "rosyBrown", "royalBlue", "saddleBrown", "salmon", "sandyBrown", "seaGreen",
+ "seaShell", "sienna", "silver", "skyBlue", "slateBlue", "slateGray",
+ "snow", "springGreen", "steelBlue", "tan", "teal", "thistle",
+ "tomato", "transparent", "turquoise", "violet", "wheat", "white",
+ "whiteSmoke", "yellow", "yellowGreen",
+ NULL
+ };
- // AXCI
- uint32_t axci_sig = 0x49435841;
- offs += buf_put_int32(axci_sig, &p_out_buffer[offs]);
- for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- p_out_buffer[offs++] = digests.axci[i];
- }
+ const char **color = valid_colors;
- // Done!
-}
-
-Error AppxPackager::read_cert_file(const String & p_path, const String &p_password, CertFile* p_out_cf) {
-
- ERR_FAIL_COND_V(!p_out_cf, ERR_INVALID_PARAMETER);
-
- BIO* bio = BIO_new_file(p_path.utf8().get_data(), "rb");
- if (!bio) {
- return openssl_error(ERR_peek_last_error());
- }
-
- PKCS12* data = d2i_PKCS12_bio(bio, NULL);
- if (!data) {
- BIO_free(bio);
- return openssl_error(ERR_peek_last_error());
- }
-
- /* Fails to link with GCC, need to solve when implement signing
- if (!PKCS12_parse(data, p_password.utf8().get_data(), &p_out_cf->private_key, &p_out_cf->certificate, NULL)) {
- PKCS12_free(data);
- BIO_free(bio);
- return openssl_error(ERR_peek_last_error());
- }*/
-
- if (!p_out_cf->private_key) {
- PKCS12_free(data);
- BIO_free(bio);
- return openssl_error(ERR_peek_last_error());
- }
+ while (*color) {
+ if (p_color == *color) return true;
+ color++;
+ }
- if (!p_out_cf->certificate) {
- PKCS12_free(data);
- BIO_free(bio);
- return openssl_error(ERR_peek_last_error());
+ return false;
}
- PKCS12_free(data);
- BIO_free(bio);
+ bool _valid_image(const StreamTexture *p_image, int p_width, int p_height) const {
- return OK;
-}
+ if (!p_image) {
+ return false;
+ }
-Error AppxPackager::sign(const CertFile & p_cert, const AppxDigests & digests, PKCS7 * p_out_signature) {
+ // TODO: Add resource creation or image rescaling to enable other scales:
+ // 1.25, 1.5, 2.0
+ real_t scales[] = { 1.0 };
+ bool valid_w = false;
+ bool valid_h = false;
- OpenSSL_add_all_algorithms();
+ for (int i = 0; i < 1; i++) {
- // Register object IDs
- OBJ_create_and_add_object(SPC_INDIRECT_DATA_OBJID, NULL, NULL);
- OBJ_create_and_add_object(SPC_SIPINFO_OBJID, NULL, NULL);
- OBJ_create_and_add_object(SPC_SP_OPUS_INFO_OBJID, NULL, NULL);
- OBJ_create_and_add_object(SPC_STATEMENT_TYPE_OBJID, NULL, NULL);
+ int w = ceil(p_width * scales[i]);
+ int h = ceil(p_height * scales[i]);
- if (!PKCS7_set_type(p_out_signature, NID_pkcs7_signed)) {
+ if (w == p_image->get_width())
+ valid_w = true;
+ if (h == p_image->get_height())
+ valid_h = true;
+ }
- return openssl_error(ERR_peek_last_error());
+ return valid_w && valid_h;
}
- PKCS7_SIGNER_INFO *signer_info = PKCS7_add_signature(p_out_signature, p_cert.certificate, p_cert.private_key, EVP_sha256());
- if (!signer_info) return openssl_error(ERR_peek_last_error());
+ Vector<uint8_t> _fix_manifest(const Ref<EditorExportPreset> &p_preset, const Vector<uint8_t> &p_template, bool p_give_internet) const {
- add_attributes(signer_info);
+ String result = String::utf8((const char *)p_template.ptr(), p_template.size());
- if (!PKCS7_content_new(p_out_signature, NID_pkcs7_data)) {
+ result = result.replace("$godot_version$", VERSION_FULL_NAME);
- return openssl_error(ERR_peek_last_error());
- }
+ result = result.replace("$identity_name$", p_preset->get("package/unique_name"));
+ result = result.replace("$publisher$", p_preset->get("package/publisher"));
- if (!PKCS7_add_certificate(p_out_signature, p_cert.certificate)) {
+ result = result.replace("$product_guid$", p_preset->get("identity/product_guid"));
+ result = result.replace("$publisher_guid$", p_preset->get("identity/publisher_guid"));
- return openssl_error(ERR_peek_last_error());
- }
+ String version = itos(p_preset->get("version/major")) + "." + itos(p_preset->get("version/minor")) + "." + itos(p_preset->get("version/build")) + "." + itos(p_preset->get("version/revision"));
+ result = result.replace("$version_string$", version);
- asn1::SPCIndirectDataContent* idc = asn1::SPCIndirectDataContent_new();
+ Platform arch = (Platform)(int)p_preset->get("architecture/target");
+ String architecture = arch == ARM ? "ARM" : arch == X86 ? "x86" : "x64";
+ result = result.replace("$architecture$", architecture);
- MakeIndirectDataContent(*idc);
- EncodedASN1 idc_encoded =
- EncodedASN1::FromItem<asn1::SPCIndirectDataContent, asn1::i2d_SPCIndirectDataContent>(idc);
+ result = result.replace("$display_name$", String(p_preset->get("package/display_name")).empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name")));
- BIO* signed_data = PKCS7_dataInit(p_out_signature, NULL);
-
- if (idc_encoded.size() < 2) {
-
- ERR_EXPLAIN("Invalid encoded size");
- ERR_FAIL_V(FAILED);
- }
+ result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name"));
+ result = result.replace("$app_description$", p_preset->get("package/description"));
+ result = result.replace("$bg_color$", p_preset->get("images/background_color"));
+ result = result.replace("$short_name$", p_preset->get("package/short_name"));
- if ((idc_encoded.data()[1] & 0x80) == 0x00) {
-
- ERR_EXPLAIN("Invalid encoded data");
- ERR_FAIL_V(FAILED);
- }
+ String name_on_tiles = "";
+ if ((bool)p_preset->get("tiles/show_name_on_square150x150")) {
+ name_on_tiles += " <uap:ShowOn Tile=\"square150x150Logo\" />\n";
+ }
+ if ((bool)p_preset->get("tiles/show_name_on_wide310x150")) {
+ name_on_tiles += " <uap:ShowOn Tile=\"wide310x150Logo\" />\n";
+ }
+ if ((bool)p_preset->get("tiles/show_name_on_square310x310")) {
+ name_on_tiles += " <uap:ShowOn Tile=\"square310x310Logo\" />\n";
+ }
- size_t skip = 4;
+ String show_name_on_tiles = "";
+ if (!name_on_tiles.empty()) {
+ show_name_on_tiles = "<uap:ShowNameOnTiles>\n" + name_on_tiles + " </uap:ShowNameOnTiles>";
+ }
- if (BIO_write(signed_data, idc_encoded.data() + skip, idc_encoded.size() - skip)
- != idc_encoded.size() - skip) {
+ result = result.replace("$name_on_tiles$", name_on_tiles);
- return openssl_error(ERR_peek_last_error());
- }
- if (BIO_flush(signed_data) != 1) {
+ String rotations = "";
+ if ((bool)p_preset->get("orientation/landscape")) {
+ rotations += " <uap:Rotation Preference=\"landscape\" />\n";
+ }
+ if ((bool)p_preset->get("orientation/portrait")) {
+ rotations += " <uap:Rotation Preference=\"portrait\" />\n";
+ }
+ if ((bool)p_preset->get("orientation/landscape_flipped")) {
+ rotations += " <uap:Rotation Preference=\"landscapeFlipped\" />\n";
+ }
+ if ((bool)p_preset->get("orientation/portrait_flipped")) {
+ rotations += " <uap:Rotation Preference=\"portraitFlipped\" />\n";
+ }
- return openssl_error(ERR_peek_last_error());
- }
+ String rotation_preference = "";
+ if (!rotations.empty()) {
+ rotation_preference = "<uap:InitialRotationPreference>\n" + rotations + " </uap:InitialRotationPreference>";
+ }
- if (!PKCS7_dataFinal(p_out_signature, signed_data)) {
+ result = result.replace("$rotation_preference$", rotation_preference);
- return openssl_error(ERR_peek_last_error());
- }
+ String capabilities_elements = "";
+ const char **basic = uwp_capabilities;
+ while (*basic) {
+ if ((bool)p_preset->get("capabilities/" + String(*basic))) {
+ capabilities_elements += " <Capability Name=\"" + String(*basic) + "\" />\n";
+ }
+ basic++;
+ }
+ const char **uap = uwp_uap_capabilities;
+ while (*uap) {
+ if ((bool)p_preset->get("capabilities/" + String(*uap))) {
+ capabilities_elements += " <uap:Capability Name=\"" + String(*uap) + "\" />\n";
+ }
+ uap++;
+ }
+ const char **device = uwp_device_capabilites;
+ while (*device) {
+ if ((bool)p_preset->get("capabilities/" + String(*device))) {
+ capabilities_elements += " <DeviceCapability Name=\"" + String(*device) + "\" />\n";
+ }
+ device++;
+ }
- PKCS7* content = PKCS7_new();
- if (!content) {
+ if (!((bool)p_preset->get("capabilities/internetClient")) && p_give_internet) {
+ capabilities_elements += " <Capability Name=\"internetClient\" />\n";
+ }
- return openssl_error(ERR_peek_last_error());
- }
+ String capabilities_string = "<Capabilities />";
+ if (!capabilities_elements.empty()) {
+ capabilities_string = "<Capabilities>\n" + capabilities_elements + " </Capabilities>";
+ }
- content->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
+ result = result.replace("$capabilities_place$", capabilities_string);
- ASN1_TYPE* idc_sequence = idc_encoded.ToSequenceType();
- content->d.other = idc_sequence;
+ Vector<uint8_t> r_ret;
+ r_ret.resize(result.length());
- if (!PKCS7_set_content(p_out_signature, content)) {
+ for (int i = 0; i < result.length(); i++)
+ r_ret[i] = result.utf8().get(i);
- return openssl_error(ERR_peek_last_error());
+ return r_ret;
}
- return OK;
-}
+ Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
-#endif // OPENSSL_ENABLED
+ Vector<uint8_t> data;
+ StreamTexture *image;
-////////////////////////////////////////////////////////////////////
+ if (p_path.find("StoreLogo") != -1) {
+ image = p_preset->get("images/store_logo").is_zero() ? NULL : ((Object *)p_preset->get("images/store_logo"))->cast_to<StreamTexture>();
+ } else if (p_path.find("Square44x44Logo") != -1) {
+ image = p_preset->get("images/square44x44_logo").is_zero() ? NULL : ((Object *)p_preset->get("images/square44x44_logo"))->cast_to<StreamTexture>();
+ } else if (p_path.find("Square71x71Logo") != -1) {
+ image = p_preset->get("images/square71x71_logo").is_zero() ? NULL : ((Object *)p_preset->get("images/square71x71_logo"))->cast_to<StreamTexture>();
+ } else if (p_path.find("Square150x150Logo") != -1) {
+ image = p_preset->get("images/square150x150_logo").is_zero() ? NULL : ((Object *)p_preset->get("images/square150x150_logo"))->cast_to<StreamTexture>();
+ } else if (p_path.find("Square310x310Logo") != -1) {
+ image = p_preset->get("images/square310x310_logo").is_zero() ? NULL : ((Object *)p_preset->get("images/square310x310_logo"))->cast_to<StreamTexture>();
+ } else if (p_path.find("Wide310x150Logo") != -1) {
+ image = p_preset->get("images/wide310x150_logo").is_zero() ? NULL : ((Object *)p_preset->get("images/wide310x150_logo"))->cast_to<StreamTexture>();
+ } else if (p_path.find("SplashScreen") != -1) {
+ image = p_preset->get("images/splash_screen").is_zero() ? NULL : ((Object *)p_preset->get("images/splash_screen"))->cast_to<StreamTexture>();
+ }
+ if (!image) return data;
-bool EditorExportPlatformUWP::_valid_resource_name(const String &p_name) const {
+ String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/uwp_tmp_logo.png");
- if (p_name.empty()) return false;
- if (p_name.ends_with(".")) return false;
+ Error err = image->get_data()->save_png(tmp_path);
- static const char* invalid_names[] = {
- "CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7",
- "COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9",
- NULL
- };
+ if (err != OK) {
- const char** t = invalid_names;
- while (*t) {
- if (p_name == *t) return false;
- t++;
- }
+ String err_string = "Couldn't save temp logo file.";
- return true;
-}
+ EditorNode::add_io_error(err_string);
+ ERR_EXPLAIN(err_string);
+ ERR_FAIL_V(data);
+ }
-bool EditorExportPlatformUWP::_valid_guid(const String & p_guid) const {
+ FileAccess *f = FileAccess::open(tmp_path, FileAccess::READ, &err);
- Vector<String> parts = p_guid.split("-");
+ if (err != OK) {
- if (parts.size() != 5) return false;
- if (parts[0].length() != 8) return false;
- for (int i = 1; i < 4; i++)
- if (parts[i].length() != 4) return false;
- if (parts[4].length() != 12) return false;
+ String err_string = "Couldn't open temp logo file.";
- return true;
-}
+ EditorNode::add_io_error(err_string);
+ ERR_EXPLAIN(err_string);
+ ERR_FAIL_V(data);
+ }
-bool EditorExportPlatformUWP::_valid_bgcolor(const String & p_color) const {
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(), data.size());
- if (p_color.empty()) return true;
- if (p_color.begins_with("#") && p_color.is_valid_html_color()) return true;
+ f->close();
+ memdelete(f);
- // Colors from https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
- static const char* valid_colors[] = {
- "aliceBlue","antiqueWhite","aqua","aquamarine","azure","beige",
- "bisque","black","blanchedAlmond","blue","blueViolet","brown",
- "burlyWood","cadetBlue","chartreuse","chocolate","coral","cornflowerBlue",
- "cornsilk","crimson","cyan","darkBlue","darkCyan","darkGoldenrod",
- "darkGray","darkGreen","darkKhaki","darkMagenta","darkOliveGreen","darkOrange",
- "darkOrchid","darkRed","darkSalmon","darkSeaGreen","darkSlateBlue","darkSlateGray",
- "darkTurquoise","darkViolet","deepPink","deepSkyBlue","dimGray","dodgerBlue",
- "firebrick","floralWhite","forestGreen","fuchsia","gainsboro","ghostWhite",
- "gold","goldenrod","gray","green","greenYellow","honeydew",
- "hotPink","indianRed","indigo","ivory","khaki","lavender",
- "lavenderBlush","lawnGreen","lemonChiffon","lightBlue","lightCoral","lightCyan",
- "lightGoldenrodYellow","lightGreen","lightGray","lightPink","lightSalmon","lightSeaGreen",
- "lightSkyBlue","lightSlateGray","lightSteelBlue","lightYellow","lime","limeGreen",
- "linen","magenta","maroon","mediumAquamarine","mediumBlue","mediumOrchid",
- "mediumPurple","mediumSeaGreen","mediumSlateBlue","mediumSpringGreen","mediumTurquoise","mediumVioletRed",
- "midnightBlue","mintCream","mistyRose","moccasin","navajoWhite","navy",
- "oldLace","olive","oliveDrab","orange","orangeRed","orchid",
- "paleGoldenrod","paleGreen","paleTurquoise","paleVioletRed","papayaWhip","peachPuff",
- "peru","pink","plum","powderBlue","purple","red",
- "rosyBrown","royalBlue","saddleBrown","salmon","sandyBrown","seaGreen",
- "seaShell","sienna","silver","skyBlue","slateBlue","slateGray",
- "snow","springGreen","steelBlue","tan","teal","thistle",
- "tomato","transparent","turquoise","violet","wheat","white",
- "whiteSmoke","yellow","yellowGreen",
- NULL
- };
+ // Delete temp file
+ DirAccess *dir = DirAccess::open(tmp_path.get_base_dir(), &err);
- const char** color = valid_colors;
+ if (err != OK) {
- while(*color) {
- if (p_color == *color) return true;
- color++;
- }
+ String err_string = "Couldn't open temp path to remove temp logo file.";
- return false;
-}
+ EditorNode::add_io_error(err_string);
+ ERR_EXPLAIN(err_string);
+ ERR_FAIL_V(data);
+ }
-bool EditorExportPlatformUWP::_valid_image(const Ref<ImageTexture> p_image, int p_width, int p_height) const {
+ err = dir->remove(tmp_path);
- if (!p_image.is_valid()) return false;
+ memdelete(dir);
- // TODO: Add resource creation or image rescaling to enable other scales:
- // 1.25, 1.5, 2.0
- real_t scales[] = { 1.0 };
- bool valid_w = false;
- bool valid_h = false;
+ if (err != OK) {
- for (int i = 0; i < 1; i++) {
+ String err_string = "Couldn't remove temp logo file.";
- int w = ceil(p_width * scales[i]);
- int h = ceil(p_height * scales[i]);
+ EditorNode::add_io_error(err_string);
+ ERR_EXPLAIN(err_string);
+ ERR_FAIL_V(data);
+ }
- if (w == p_image->get_width())
- valid_w = true;
- if (h == p_image->get_height())
- valid_h = true;
+ return data;
}
- return valid_w && valid_h;
-}
-
-Vector<uint8_t> EditorExportPlatformUWP::_fix_manifest(const Vector<uint8_t> &p_template, bool p_give_internet) const {
-
- String result = String::utf8((const char*)p_template.ptr(), p_template.size());
-
- result = result.replace("$godot_version$", VERSION_FULL_NAME);
-
- result = result.replace("$identity_name$", unique_name);
- result = result.replace("$publisher$", publisher);
-
- result = result.replace("$product_guid$", product_guid);
- result = result.replace("$publisher_guid$", publisher_guid);
+ static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
- String version = itos(version_major) + "." + itos(version_minor) + "." + itos(version_build) + "." + itos(version_revision);
- result = result.replace("$version_string$", version);
+ /* TODO: This was copied verbatim from Android export. It should be
+ * refactored to the parent class and also be used for .zip export.
+ */
- String architecture = arch == ARM ? "ARM" : arch == X86 ? "x86" : "x64";
- result = result.replace("$architecture$", architecture);
+ /*
+ * By not compressing files with little or not benefit in doing so,
+ * a performance gain is expected at runtime. Moreover, if the APK is
+ * zip-aligned, assets stored as they are can be efficiently read by
+ * Android by memory-mapping them.
+ */
- result = result.replace("$display_name$", display_name.empty() ? (String)GlobalConfig::get_singleton()->get("application/name") : display_name);
- result = result.replace("$publisher_display_name$", publisher_display_name);
- result = result.replace("$app_description$", description);
- result = result.replace("$bg_color$", background_color);
- result = result.replace("$short_name$", short_name);
+ // -- Unconditional uncompress to mimic AAPT plus some other
- String name_on_tiles = "";
- if (name_on_square150) {
- name_on_tiles += " <uap:ShowOn Tile=\"square150x150Logo\" />\n";
- }
- if (name_on_wide) {
- name_on_tiles += " <uap:ShowOn Tile=\"wide310x150Logo\" />\n";
- }
- if (name_on_square310) {
- name_on_tiles += " <uap:ShowOn Tile=\"square310x310Logo\" />\n";
- }
-
- String show_name_on_tiles = "";
- if (!name_on_tiles.empty()) {
- show_name_on_tiles = "<uap:ShowNameOnTiles>\n" + name_on_tiles + " </uap:ShowNameOnTiles>";
- }
-
- result = result.replace("$name_on_tiles$", name_on_tiles);
-
- String rotations = "";
- if (orientation_landscape) {
- rotations += " <uap:Rotation Preference=\"landscape\" />\n";
- }
- if (orientation_portrait) {
- rotations += " <uap:Rotation Preference=\"portrait\" />\n";
- }
- if (orientation_landscape_flipped) {
- rotations += " <uap:Rotation Preference=\"landscapeFlipped\" />\n";
- }
- if (orientation_portrait_flipped) {
- rotations += " <uap:Rotation Preference=\"portraitFlipped\" />\n";
- }
+ static const char *unconditional_compress_ext[] = {
+ // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
+ // These formats are already compressed, or don't compress well:
+ ".jpg", ".jpeg", ".png", ".gif",
+ ".wav", ".mp2", ".mp3", ".ogg", ".aac",
+ ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
+ ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
+ ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
+ ".amr", ".awb", ".wma", ".wmv",
+ // Godot-specific:
+ ".webp", // Same reasoning as .png
+ ".cfb", // Don't let small config files slow-down startup
+ ".scn", // Binary scenes are usually already compressed
+ ".stex", // Streamable textures are usually already compressed
+ // Trailer for easier processing
+ NULL
+ };
- String rotation_preference = "";
- if (!rotations.empty()) {
- rotation_preference = "<uap:InitialRotationPreference>\n" + rotations + " </uap:InitialRotationPreference>";
- }
+ for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
+ if (p_path.to_lower().ends_with(String(*ext))) {
+ return false;
+ }
+ }
- result = result.replace("$rotation_preference$", rotation_preference);
+ // -- Compressed resource?
- String capabilities_elements = "";
- const char **basic = uwp_capabilities;
- while (*basic) {
- if (capabilities.has(*basic)) {
- capabilities_elements += " <Capability Name=\"" + String(*basic) + "\" />\n";
- }
- basic++;
- }
- const char **uap = uwp_uap_capabilities;
- while (*uap) {
- if (uap_capabilities.has(*uap)) {
- capabilities_elements += " <uap:Capability Name=\"" + String(*uap) + "\" />\n";
- }
- uap++;
- }
- const char **device = uwp_device_capabilites;
- while (*device) {
- if (uap_capabilities.has(*device)) {
- capabilities_elements += " <DeviceCapability Name=\"" + String(*device) + "\" />\n";
+ if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
+ // Already compressed
+ return false;
}
- device++;
- }
- if (!capabilities.has("internetClient") && p_give_internet) {
- capabilities_elements += " <Capability Name=\"internetClient\" />\n";
- }
+ // --- TODO: Decide on texture resources according to their image compression setting
- String capabilities_string = "<Capabilities />";
- if (!capabilities_elements.empty()) {
- capabilities_string = "<Capabilities>\n" + capabilities_elements + " </Capabilities>";
+ return true;
}
- result = result.replace("$capabilities_place$", capabilities_string);
+ static Error save_appx_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
- Vector<uint8_t> r_ret;
- r_ret.resize(result.length());
+ AppxPackager *packager = (AppxPackager *)p_userdata;
+ String dst_path = p_path.replace_first("res://", "game/");
- for (int i = 0; i < result.length(); i++)
- r_ret[i] = result.utf8().get(i);
+ packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data));
- return r_ret;
-}
-
-Vector<uint8_t> EditorExportPlatformUWP::_get_image_data(const String & p_path) {
-
- Vector<uint8_t> data;
- Ref<ImageTexture> ref;
-
- if (p_path.find("StoreLogo") != -1) {
- ref = store_logo;
- } else if (p_path.find("Square44x44Logo") != -1) {
- ref = square44;
- } else if (p_path.find("Square71x71Logo") != -1) {
- ref = square71;
- } else if (p_path.find("Square150x150Logo") != -1) {
- ref = square150;
- } else if (p_path.find("Square310x310Logo") != -1) {
- ref = square310;
- } else if (p_path.find("Wide310x150Logo") != -1) {
- ref = wide310;
- } else if (p_path.find("SplashScreen") != -1) {
- ref = splash;
+ return OK;
}
- if (!ref.is_valid()) return data;
-
-
- String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/uwp_tmp_logo.png");
-
- Error err = ref->get_data().save_png(tmp_path);
-
- if (err != OK) {
-
- String err_string = "Couldn't save temp logo file.";
-
- EditorNode::add_io_error(err_string);
- ERR_EXPLAIN(err_string);
- ERR_FAIL_V(data);
+public:
+ virtual String get_name() const {
+ return "Windows Universal";
}
-
- FileAccess* f = FileAccess::open(tmp_path, FileAccess::READ, &err);
-
- if (err != OK) {
-
- String err_string = "Couldn't open temp logo file.";
-
- EditorNode::add_io_error(err_string);
- ERR_EXPLAIN(err_string);
- ERR_FAIL_V(data);
+ virtual String get_os_name() const {
+ return "UWP";
}
- data.resize(f->get_len());
- f->get_buffer(data.ptr(), data.size());
-
- f->close();
- memdelete(f);
-
- // Delete temp file
- DirAccess* dir = DirAccess::open(tmp_path.get_base_dir(), &err);
-
- if (err != OK) {
-
- String err_string = "Couldn't open temp path to remove temp logo file.";
-
- EditorNode::add_io_error(err_string);
- ERR_EXPLAIN(err_string);
- ERR_FAIL_V(data);
+ virtual String get_binary_extension() const {
+ return "appx";
}
- err = dir->remove(tmp_path);
-
- memdelete(dir);
-
- if (err != OK) {
-
- String err_string = "Couldn't remove temp logo file.";
-
- EditorNode::add_io_error(err_string);
- ERR_EXPLAIN(err_string);
- ERR_FAIL_V(data);
+ virtual Ref<Texture> get_logo() const {
+ return logo;
}
- return data;
-}
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+ r_features->push_back("s3tc");
+ r_features->push_back("etc");
+ }
-Error EditorExportPlatformUWP::save_appx_file(void * p_userdata, const String & p_path, const Vector<uint8_t>& p_data, int p_file, int p_total) {
+ virtual void get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "ARM,x86,x64"), 1));
- AppxPackager *packager = (AppxPackager*)p_userdata;
- String dst_path = p_path.replace_first("res://", "game/");
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
- packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/display_name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/short_name"), "Godot"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name"), "Godot.Engine"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/description"), "Godot Engine"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher"), "CN=GodotEngine"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher_display_name"), "Godot Engine"));
- return OK;
-}
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid"), "00000000-0000-0000-0000-000000000000"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid"), "00000000-0000-0000-0000-000000000000"));
-bool EditorExportPlatformUWP::_should_compress_asset(const String & p_path, const Vector<uint8_t>& p_data) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/minor"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/build"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/revision"), 0));
- /* TODO: This was copied verbatim from Android export. It should be
- * refactored to the parent class and also be used for .zip export.
- */
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_flipped"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_flipped"), true));
- /*
- * By not compressing files with little or not benefit in doing so,
- * a performance gain is expected at runtime. Moreover, if the APK is
- * zip-aligned, assets stored as they are can be efficiently read by
- * Android by memory-mapping them.
- */
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "images/background_color"), "transparent"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/store_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square44x44_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square71x71_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square150x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square310x310_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/wide310x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/splash_screen", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture"), Variant()));
- // -- Unconditional uncompress to mimic AAPT plus some other
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square150x150"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_wide310x150"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square310x310"), false));
- static const char* unconditional_compress_ext[] = {
- // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
- // These formats are already compressed, or don't compress well:
- ".jpg", ".jpeg", ".png", ".gif",
- ".wav", ".mp2", ".mp3", ".ogg", ".aac",
- ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
- ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
- ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
- ".amr", ".awb", ".wma", ".wmv",
- // Godot-specific:
- ".webp", // Same reasoning as .png
- ".cfb", // Don't let small config files slow-down startup
- // Trailer for easier processing
- NULL
- };
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
- for (const char** ext = unconditional_compress_ext; *ext; ++ext) {
- if (p_path.to_lower().ends_with(String(*ext))) {
- return false;
+ // Capabilites
+ const char **basic = uwp_capabilities;
+ while (*basic) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic).camelcase_to_underscore(false)), false));
+ basic++;
}
- }
- // -- Compressed resource?
+ const char **uap = uwp_uap_capabilities;
+ while (*uap) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap).camelcase_to_underscore(false)), false));
+ uap++;
+ }
- if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
- // Already compressed
- return false;
+ const char **device = uwp_device_capabilites;
+ while (*device) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device).camelcase_to_underscore(false)), false));
+ device++;
+ }
}
- // --- TODO: Decide on texture resources according to their image compression setting
-
- return true;
-}
-
-bool EditorExportPlatformUWP::_set(const StringName& p_name, const Variant& p_value) {
-
- String n = p_name;
-
- if (n == "architecture/target")
- arch = (Platform)((int)p_value);
- else if (n == "custom_package/debug")
- custom_debug_package = p_value;
- else if (n == "custom_package/release")
- custom_release_package = p_value;
- else if (n == "command_line/extra_args")
- cmdline = p_value;
- else if (n == "package/display_name")
- display_name = p_value;
- else if (n == "package/short_name")
- short_name = p_value;
- else if (n == "package/unique_name")
- unique_name = p_value;
- else if (n == "package/description")
- description = p_value;
- else if (n == "package/publisher")
- publisher = p_value;
- else if (n == "package/publisher_display_name")
- publisher_display_name = p_value;
- else if (n == "identity/product_guid")
- product_guid = p_value;
- else if (n == "identity/publisher_guid")
- publisher_guid = p_value;
- else if (n == "version/major")
- version_major = p_value;
- else if (n == "version/minor")
- version_minor = p_value;
- else if (n == "version/build")
- version_build = p_value;
- else if (n == "version/revision")
- version_revision = p_value;
- else if (n == "orientation/landscape")
- orientation_landscape = p_value;
- else if (n == "orientation/portrait")
- orientation_portrait = p_value;
- else if (n == "orientation/landscape_flipped")
- orientation_landscape_flipped = p_value;
- else if (n == "orientation/portrait_flipped")
- orientation_portrait_flipped = p_value;
- else if (n == "images/background_color")
- background_color = p_value;
- else if (n == "images/store_logo")
- store_logo = p_value;
- else if (n == "images/square44x44_logo")
- square44 = p_value;
- else if (n == "images/square71x71_logo")
- square71 = p_value;
- else if (n == "images/square150x150_logo")
- square150 = p_value;
- else if (n == "images/square310x310_logo")
- square310 = p_value;
- else if (n == "images/wide310x150_logo")
- wide310 = p_value;
- else if (n == "images/splash_screen")
- splash = p_value;
- else if (n == "tiles/show_name_on_square150x150")
- name_on_square150 = p_value;
- else if (n == "tiles/show_name_on_wide310x150")
- name_on_wide = p_value;
- else if (n == "tiles/show_name_on_square310x310")
- name_on_square310 = p_value;
-
-#if 0 // Signing disabled
- else if (n == "signing/sign")
- sign_package = p_value;
- else if (n == "signing/certificate_file")
- certificate_path = p_value;
- else if (n == "signing/certificate_password")
- certificate_pass = p_value;
-#endif
- else if (n.begins_with("capabilities/")) {
-
- String what = n.get_slice("/", 1).replace("_", "");
- bool enable = p_value;
-
- if (array_has(uwp_capabilities, what.utf8().get_data())) {
-
- if (enable)
- capabilities.insert(what);
- else
- capabilities.erase(what);
-
- } else if (array_has(uwp_uap_capabilities, what.utf8().get_data())) {
+ virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String err;
+ bool valid = true;
+ Platform arch = (Platform)(int)(p_preset->get("architecture/target"));
- if (enable)
- uap_capabilities.insert(what);
- else
- uap_capabilities.erase(what);
+ String custom_debug_binary = p_preset->get("custom_template/debug");
+ String custom_release_binary = p_preset->get("custom_template/release");
- } else if (array_has(uwp_device_capabilites, what.utf8().get_data())) {
+ String platform_infix;
- if (enable)
- device_capabilities.insert(what);
- else
- device_capabilities.erase(what);
+ switch (arch) {
+ case EditorExportUWP::ARM: {
+ platform_infix = "arm";
+ } break;
+ case EditorExportUWP::X86: {
+ platform_infix = "x86";
+ } break;
+ case EditorExportUWP::X64: {
+ platform_infix = "x64";
+ } break;
}
- } else return false;
-
- return true;
-}
-
-bool EditorExportPlatformUWP::_get(const StringName& p_name, Variant &r_ret) const {
-
- String n = p_name;
- if (n == "architecture/target")
- r_ret = (int)arch;
- else if (n == "custom_package/debug")
- r_ret = custom_debug_package;
- else if (n == "custom_package/release")
- r_ret = custom_release_package;
- else if (n == "command_line/extra_args")
- r_ret = cmdline;
- else if (n == "package/display_name")
- r_ret = display_name;
- else if (n == "package/short_name")
- r_ret = short_name;
- else if (n == "package/unique_name")
- r_ret = unique_name;
- else if (n == "package/description")
- r_ret = description;
- else if (n == "package/publisher")
- r_ret = publisher;
- else if (n == "package/publisher_display_name")
- r_ret = publisher_display_name;
- else if (n == "identity/product_guid")
- r_ret = product_guid;
- else if (n == "identity/publisher_guid")
- r_ret = publisher_guid;
- else if (n == "version/major")
- r_ret = version_major;
- else if (n == "version/minor")
- r_ret = version_minor;
- else if (n == "version/build")
- r_ret = version_build;
- else if (n == "version/revision")
- r_ret = version_revision;
- else if (n == "orientation/landscape")
- r_ret = orientation_landscape;
- else if (n == "orientation/portrait")
- r_ret = orientation_portrait;
- else if (n == "orientation/landscape_flipped")
- r_ret = orientation_landscape_flipped;
- else if (n == "orientation/portrait_flipped")
- r_ret = orientation_portrait_flipped;
- else if (n == "images/background_color")
- r_ret = background_color;
- else if (n == "images/store_logo")
- r_ret = store_logo;
- else if (n == "images/square44x44_logo")
- r_ret = square44;
- else if (n == "images/square71x71_logo")
- r_ret = square71;
- else if (n == "images/square150x150_logo")
- r_ret = square150;
- else if (n == "images/square310x310_logo")
- r_ret = square310;
- else if (n == "images/wide310x150_logo")
- r_ret = wide310;
- else if (n == "images/splash_screen")
- r_ret = splash;
- else if (n == "tiles/show_name_on_square150x150")
- r_ret = name_on_square150;
- else if (n == "tiles/show_name_on_wide310x150")
- r_ret = name_on_wide;
- else if (n == "tiles/show_name_on_square310x310")
- r_ret = name_on_square310;
-
-#if 0 // Signing disabled
- else if (n == "signing/sign")
- r_ret = sign_package;
- else if (n == "signing/certificate_file")
- r_ret = certificate_path;
- else if (n == "signing/certificate_password")
- r_ret = certificate_pass;
-#endif
- else if (n.begins_with("capabilities/")) {
-
- String what = n.get_slice("/", 1).replace("_", "");
-
- if (array_has(uwp_capabilities, what.utf8().get_data())) {
-
- r_ret = capabilities.has(what);
-
- } else if (array_has(uwp_uap_capabilities, what.utf8().get_data())) {
-
- r_ret = uap_capabilities.has(what);
-
- } else if (array_has(uwp_device_capabilites, what.utf8().get_data())) {
-
- r_ret = device_capabilities.has(what);
+ if (!exists_export_template("uwp_" + platform_infix + "_debug.zip", &err) || !exists_export_template("uwp_" + platform_infix + "_debug.zip", &err)) {
+ valid = false;
+ r_missing_templates = true;
}
- } else return false;
-
- return true;
-}
-
-void EditorExportPlatformUWP::_get_property_list(List<PropertyInfo>* p_list) const {
-
- p_list->push_back(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "appx"));
- p_list->push_back(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "appx"));
-
- p_list->push_back(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "ARM,x86,x64"));
-
- p_list->push_back(PropertyInfo(Variant::STRING, "command_line/extra_args"));
- p_list->push_back(PropertyInfo(Variant::STRING, "package/display_name"));
- p_list->push_back(PropertyInfo(Variant::STRING, "package/short_name"));
- p_list->push_back(PropertyInfo(Variant::STRING, "package/unique_name"));
- p_list->push_back(PropertyInfo(Variant::STRING, "package/description"));
- p_list->push_back(PropertyInfo(Variant::STRING, "package/publisher"));
- p_list->push_back(PropertyInfo(Variant::STRING, "package/publisher_display_name"));
-
- p_list->push_back(PropertyInfo(Variant::STRING, "identity/product_guid"));
- p_list->push_back(PropertyInfo(Variant::STRING, "identity/publisher_guid"));
-
- p_list->push_back(PropertyInfo(Variant::INT, "version/major"));
- p_list->push_back(PropertyInfo(Variant::INT, "version/minor"));
- p_list->push_back(PropertyInfo(Variant::INT, "version/build"));
- p_list->push_back(PropertyInfo(Variant::INT, "version/revision"));
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "orientation/landscape"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "orientation/portrait"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "orientation/landscape_flipped"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "orientation/portrait_flipped"));
-
- p_list->push_back(PropertyInfo(Variant::STRING, "images/background_color"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/store_logo", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/square44x44_logo", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/square71x71_logo", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/square150x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/square310x310_logo", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/wide310x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "images/splash_screen", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture"));
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square150x150"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "tiles/show_name_on_wide310x150"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square310x310"));
-
-#if 0 // Signing does not work :( disabling for now
- p_list->push_back(PropertyInfo(Variant::BOOL, "signing/sign"));
- p_list->push_back(PropertyInfo(Variant::STRING, "signing/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "pfx"));
- p_list->push_back(PropertyInfo(Variant::STRING, "signing/certificate_password"));
-#endif
-
- // Capabilites
- const char **basic = uwp_capabilities;
- while (*basic) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic).camelcase_to_underscore(false)));
- basic++;
- }
-
- const char **uap = uwp_uap_capabilities;
- while (*uap) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap).camelcase_to_underscore(false)));
- uap++;
- }
+ if (!valid && custom_debug_binary == "" && custom_release_binary == "") {
+ if (!err.empty()) {
+ r_error = err;
+ }
+ return valid;
+ }
- const char **device = uwp_device_capabilites;
- while (*device) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device).camelcase_to_underscore(false)));
- device++;
- }
+ bool dvalid = true;
+ bool rvalid = true;
-}
-
-bool EditorExportPlatformUWP::can_export(String * r_error) const {
+ if (!FileAccess::exists(custom_debug_binary)) {
+ dvalid = false;
+ err = "\nCustom debug binary not found.";
+ }
- String err;
- bool valid = true;
+ if (!FileAccess::exists(custom_release_binary)) {
+ rvalid = false;
+ err += "\nCustom release binary not found.";
+ }
- if (!exists_export_template("uwp_x86_debug.zip") || !exists_export_template("uwp_x86_release.zip")
- || !exists_export_template("uwp_arm_debug.zip") || !exists_export_template("uwp_arm_release.zip")
- || !exists_export_template("uwp_x64_debug.zip") || !exists_export_template("uwp_x64_release.zip")) {
- valid = false;
- err += TTR("No export templates found.\nDownload and install export templates.") + "\n";
- }
+ if (dvalid || rvalid)
+ valid = true;
- if (custom_debug_package != "" && !FileAccess::exists(custom_debug_package)) {
- valid = false;
- err += TTR("Custom debug package not found.") + "\n";
- }
+ if (!valid) {
+ r_error = err;
+ return valid;
+ }
- if (custom_release_package != "" && !FileAccess::exists(custom_release_package)) {
- valid = false;
- err += TTR("Custom release package not found.") + "\n";
- }
+ if (!_valid_resource_name(p_preset->get("package/unique_name"))) {
+ valid = false;
+ err += "\nInvalid unique name.";
+ }
- if (!_valid_resource_name(unique_name)) {
- valid = false;
- err += TTR("Invalid unique name.") + "\n";
- }
+ if (!_valid_guid(p_preset->get("identity/product_guid"))) {
+ valid = false;
+ err += "\nInvalid product GUID.";
+ }
- if (!_valid_guid(product_guid)) {
- valid = false;
- err += TTR("Invalid product GUID.") + "\n";
- }
+ if (!_valid_guid(p_preset->get("identity/publisher_guid"))) {
+ valid = false;
+ err += "\nInvalid publisher GUID.";
+ }
- if (!_valid_guid(publisher_guid)) {
- valid = false;
- err += TTR("Invalid publisher GUID.") + "\n";
- }
+ if (!_valid_bgcolor(p_preset->get("images/background_color"))) {
+ valid = false;
+ err += "\nInvalid background color.";
+ }
- if (!_valid_bgcolor(background_color)) {
- valid = false;
- err += TTR("Invalid background color.") + "\n";
- }
+ if (!p_preset->get("images/store_logo").is_zero() && !_valid_image(((Object *)p_preset->get("images/store_logo"))->cast_to<StreamTexture>(), 50, 50)) {
+ valid = false;
+ err += "\nInvalid Store Logo image dimensions (should be 50x50).";
+ }
- if (store_logo.is_valid() && !_valid_image(store_logo, 50, 50)) {
- valid = false;
- err += TTR("Invalid Store Logo image dimensions (should be 50x50).") + "\n";
- }
+ if (!p_preset->get("images/square44x44_logo").is_zero() && !_valid_image(((Object *)p_preset->get("images/square44x44_logo"))->cast_to<StreamTexture>(), 44, 44)) {
+ valid = false;
+ err += "\nInvalid square 44x44 logo image dimensions (should be 44x44).";
+ }
- if (square44.is_valid() && !_valid_image(square44, 44, 44)) {
- valid = false;
- err += TTR("Invalid square 44x44 logo image dimensions (should be 44x44).") + "\n";
- }
+ if (!p_preset->get("images/square71x71_logo").is_zero() && !_valid_image(((Object *)p_preset->get("images/square71x71_logo"))->cast_to<StreamTexture>(), 71, 71)) {
+ valid = false;
+ err += "\nInvalid square 71x71 logo image dimensions (should be 71x71).";
+ }
- if (square71.is_valid() && !_valid_image(square71, 71, 71)) {
- valid = false;
- err += TTR("Invalid square 71x71 logo image dimensions (should be 71x71).") + "\n";
- }
+ if (!p_preset->get("images/square150x150_logo").is_zero() && !_valid_image(((Object *)p_preset->get("images/square150x150_logo"))->cast_to<StreamTexture>(), 150, 0)) {
+ valid = false;
+ err += "\nInvalid square 150x150 logo image dimensions (should be 150x150).";
+ }
- if (square150.is_valid() && !_valid_image(square150, 150, 150)) {
- valid = false;
- err += TTR("Invalid square 150x150 logo image dimensions (should be 150x150).") + "\n";
- }
+ if (!p_preset->get("images/square310x310_logo").is_zero() && !_valid_image(((Object *)p_preset->get("images/square310x310_logo"))->cast_to<StreamTexture>(), 310, 310)) {
+ valid = false;
+ err += "\nInvalid square 310x310 logo image dimensions (should be 310x310).";
+ }
- if (square310.is_valid() && !_valid_image(square310, 310, 310)) {
- valid = false;
- err += TTR("Invalid square 310x310 logo image dimensions (should be 310x310).") + "\n";
- }
+ if (!p_preset->get("images/wide310x150_logo").is_zero() && !_valid_image(((Object *)p_preset->get("images/wide310x150_logo"))->cast_to<StreamTexture>(), 310, 150)) {
+ valid = false;
+ err += "\nInvalid wide 310x150 logo image dimensions (should be 310x150).";
+ }
- if (wide310.is_valid() && !_valid_image(wide310, 310, 150)) {
- valid = false;
- err += TTR("Invalid wide 310x150 logo image dimensions (should be 310x150).") + "\n";
- }
+ if (!p_preset->get("images/splash_screen").is_zero() && !_valid_image(((Object *)p_preset->get("images/splash_screen"))->cast_to<StreamTexture>(), 620, 300)) {
+ valid = false;
+ err += "\nInvalid splash screen image dimensions (should be 620x300).";
+ }
- if (splash.is_valid() && !_valid_image(splash, 620, 300)) {
- valid = false;
- err += TTR("Invalid splash screen image dimensions (should be 620x300).") + "\n";
+ r_error = err;
+ return valid;
}
- if (r_error)
- *r_error = err;
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
- return valid;
-}
+ String src_appx;
-Error EditorExportPlatformUWP::export_project(const String & p_path, bool p_debug, int p_flags) {
+ EditorProgress ep("export", "Exporting for Windows Universal", 7);
- String src_appx;
+ if (p_debug)
+ src_appx = p_preset->get("custom_template/debug");
+ else
+ src_appx = p_preset->get("custom_template/release");
- EditorProgress ep("export", "Exporting for Windows Universal", 7);
+ src_appx = src_appx.strip_edges();
- if (is_debug)
- src_appx = custom_debug_package;
- else
- src_appx = custom_release_package;
+ Platform arch = (Platform)(int)p_preset->get("architecture/target");
- if (src_appx == "") {
- String err;
- if (p_debug) {
+ if (src_appx == "") {
+ String err, infix;
switch (arch) {
- case X86: {
- src_appx = find_export_template("uwp_x86_debug.zip", &err);
- break;
- }
- case X64: {
- src_appx = find_export_template("uwp_x64_debug.zip", &err);
- break;
- }
case ARM: {
- src_appx = find_export_template("uwp_arm_debug.zip", &err);
- break;
- }
- }
- } else {
- switch (arch) {
+ infix = "_arm_";
+ } break;
case X86: {
- src_appx = find_export_template("uwp_x86_release.zip", &err);
- break;
- }
+ infix = "_x86_";
+ } break;
case X64: {
- src_appx = find_export_template("uwp_x64_release.zip", &err);
- break;
- }
- case ARM: {
- src_appx = find_export_template("uwp_arm_release.zip", &err);
- break;
- }
+ infix = "_x64_";
+ } break;
+ }
+ if (p_debug) {
+ src_appx = find_export_template("uwp" + infix + "debug.zip", &err);
+ } else {
+ src_appx = find_export_template("uwp" + infix + "release.zip", &err);
+ }
+ if (src_appx == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
}
}
- if (src_appx == "") {
- EditorNode::add_io_error(err);
- return ERR_FILE_NOT_FOUND;
- }
- }
-
- Error err = OK;
-
- FileAccess *fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-
- AppxPackager packager;
- packager.init(fa_pack, sign_package ? AppxPackager::SIGN : AppxPackager::DONT_SIGN, certificate_path, certificate_pass);
-
- FileAccess *src_f = NULL;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- ep.step("Creating package...", 0);
+ Error err = OK;
- unzFile pkg = unzOpen2(src_appx.utf8().get_data(), &io);
+ FileAccess *fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
- if (!pkg) {
+ AppxPackager packager;
+ packager.init(fa_pack);
- EditorNode::add_io_error("Could not find template appx to export:\n" + src_appx);
- return ERR_FILE_NOT_FOUND;
- }
-
- int ret = unzGoToFirstFile(pkg);
-
- ep.step("Copying template files...", 1);
-
- EditorNode::progress_add_task("template_files", "Template files", 100);
- packager.set_progress_task("template_files");
+ FileAccess *src_f = NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- int template_files_amount = 9;
- int template_file_no = 1;
+ ep.step("Creating package...", 0);
- while (ret == UNZ_OK) {
+ unzFile pkg = unzOpen2(src_appx.utf8().get_data(), &io);
- // get file name
- unz_file_info info;
- char fname[16834];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, NULL, 0, NULL, 0);
+ if (!pkg) {
- String path = fname;
-
- if (path.ends_with("/")) {
- // Ignore directories
- ret = unzGoToNextFile(pkg);
- continue;
+ EditorNode::add_io_error("Could not find template appx to export:\n" + src_appx);
+ return ERR_FILE_NOT_FOUND;
}
- Vector<uint8_t> data;
- bool do_read = true;
+ int ret = unzGoToFirstFile(pkg);
- if (path.begins_with("Assets/")) {
+ ep.step("Copying template files...", 1);
- path = path.replace(".scale-100", "");
+ EditorNode::progress_add_task("template_files", "Template files", 100);
+ packager.set_progress_task("template_files");
- data = _get_image_data(path);
- if (data.size() > 0) do_read = false;
- }
+ int template_files_amount = 9;
+ int template_file_no = 1;
- //read
- if (do_read) {
- data.resize(info.uncompressed_size);
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptr(), data.size());
- unzCloseCurrentFile(pkg);
- }
+ while (ret == UNZ_OK) {
- if (path == "AppxManifest.xml") {
+ // get file name
+ unz_file_info info;
+ char fname[16834];
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, NULL, 0, NULL, 0);
- data = _fix_manifest(data, p_flags&(EXPORT_DUMB_CLIENT | EXPORT_REMOTE_DEBUG));
- }
+ String path = fname;
- print_line("ADDING: " + path);
-
- packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data));
+ if (path.ends_with("/")) {
+ // Ignore directories
+ ret = unzGoToNextFile(pkg);
+ continue;
+ }
- ret = unzGoToNextFile(pkg);
- }
+ Vector<uint8_t> data;
+ bool do_read = true;
- EditorNode::progress_end_task("template_files");
+ if (path.begins_with("Assets/")) {
- ep.step("Creating command line...", 2);
+ path = path.replace(".scale-100", "");
- Vector<String> cl = cmdline.strip_edges().split(" ");
- for (int i = 0;i<cl.size();i++) {
- if (cl[i].strip_edges().length() == 0) {
- cl.remove(i);
- i--;
- }
- }
+ data = _get_image_data(p_preset, path);
+ if (data.size() > 0) do_read = false;
+ }
- if (!(p_flags & EXPORT_DUMB_CLIENT)) {
- cl.push_back("-path");
- cl.push_back("game");
- }
+ //read
+ if (do_read) {
+ data.resize(info.uncompressed_size);
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg, data.ptr(), data.size());
+ unzCloseCurrentFile(pkg);
+ }
- gen_export_flags(cl, p_flags);
+ if (path == "AppxManifest.xml") {
- // Command line file
- Vector<uint8_t> clf;
+ data = _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG));
+ }
- // Argc
- clf.resize(4);
- encode_uint32(cl.size(), clf.ptr());
+ print_line("ADDING: " + path);
- for (int i = 0; i < cl.size(); i++) {
+ packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data));
- CharString txt = cl[i].utf8();
- int base = clf.size();
- clf.resize(base + 4 + txt.length());
- encode_uint32(txt.length(), &clf[base]);
- copymem(&clf[base + 4], txt.ptr(), txt.length());
- print_line(itos(i) + " param: " + cl[i]);
- }
-
- packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false);
+ ret = unzGoToNextFile(pkg);
+ }
- ep.step("Adding project files...", 3);
+ EditorNode::progress_end_task("template_files");
- EditorNode::progress_add_task("project_files", "Project Files", 100);
- packager.set_progress_task("project_files");
+ ep.step("Creating command line...", 2);
- err = export_project_files(save_appx_file, &packager, false);
+ Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" ");
+ for (int i = 0; i < cl.size(); i++) {
+ if (cl[i].strip_edges().length() == 0) {
+ cl.remove(i);
+ i--;
+ }
+ }
- EditorNode::progress_end_task("project_files");
+ if (!(p_flags & DEBUG_FLAG_DUMB_CLIENT)) {
+ cl.push_back("-path");
+ cl.push_back("game");
+ }
- ep.step("Closing package...", 7);
+ gen_export_flags(cl, p_flags);
- unzClose(pkg);
+ // Command line file
+ Vector<uint8_t> clf;
- packager.finish();
+ // Argc
+ clf.resize(4);
+ encode_uint32(cl.size(), clf.ptr());
- return OK;
-}
+ for (int i = 0; i < cl.size(); i++) {
-EditorExportPlatformUWP::EditorExportPlatformUWP() {
+ CharString txt = cl[i].utf8();
+ int base = clf.size();
+ clf.resize(base + 4 + txt.length());
+ encode_uint32(txt.length(), &clf[base]);
+ copymem(&clf[base + 4], txt.ptr(), txt.length());
+ print_line(itos(i) + " param: " + cl[i]);
+ }
- Image img(_uwp_logo);
- logo = Ref<ImageTexture>(memnew(ImageTexture));
- logo->create_from_image(img);
+ packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false);
- is_debug = true;
+ ep.step("Adding project files...", 3);
- custom_release_package = "";
- custom_debug_package = "";
+ EditorNode::progress_add_task("project_files", "Project Files", 100);
+ packager.set_progress_task("project_files");
- arch = X86;
+ err = export_project_files(p_preset, save_appx_file, &packager);
- display_name = "";
- short_name = "Godot";
- unique_name = "Godot.Engine";
- description = "Godot Engine";
- publisher = "CN=GodotEngine";
- publisher_display_name = "Godot Engine";
+ EditorNode::progress_end_task("project_files");
- product_guid = "00000000-0000-0000-0000-000000000000";
- publisher_guid = "00000000-0000-0000-0000-000000000000";
+ ep.step("Closing package...", 7);
- version_major = 1;
- version_minor = 0;
- version_build = 0;
- version_revision = 0;
+ unzClose(pkg);
- orientation_landscape = true;
- orientation_portrait = true;
- orientation_landscape_flipped = true;
- orientation_portrait_flipped = true;
+ packager.finish();
- background_color = "transparent";
+ return OK;
+ }
- name_on_square150 = false;
- name_on_square310 = false;
- name_on_wide = false;
+ virtual void get_platform_features(List<String> *r_features) {
- sign_package = false;
- certificate_path = "";
- certificate_pass = "";
-}
+ r_features->push_back("pc");
+ r_features->push_back("UWP");
+ }
-EditorExportPlatformUWP::~EditorExportPlatformUWP() {}
+ EditorExportUWP() {
+ Ref<Image> img = memnew(Image(_uwp_logo));
+ logo.instance();
+ logo->create_from_image(img);
+ }
+};
-#endif
void register_uwp_exporter() {
-#if 0
- Ref<EditorExportPlatformUWP> exporter = Ref<EditorExportPlatformUWP>(memnew(EditorExportPlatformUWP));
- EditorImportExport::get_singleton()->add_export_platform(exporter);
-#endif
+ Ref<EditorExportUWP> exporter = Ref<EditorExportUWP>(memnew(EditorExportUWP));
+ EditorExport::get_singleton()->add_export_platform(exporter);
}
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 28aaf9161..fabb227bf 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -35,12 +35,12 @@
#include "drivers/windows/mutex_windows.h"
#include "drivers/windows/rw_lock_windows.h"
#include "drivers/windows/semaphore_windows.h"
-#include "global_config.h"
#include "io/marshalls.h"
#include "main/main.h"
#include "platform/windows/packet_peer_udp_winsock.h"
#include "platform/windows/stream_peer_winsock.h"
#include "platform/windows/tcp_server_winsock.h"
+#include "project_settings.h"
#include "servers/audio_server.h"
#include "servers/visual/visual_server_raster.h"
#include "thread_uwp.h"
@@ -310,7 +310,7 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud
if (is_keep_screen_on())
display_request->RequestActive();
- set_keep_screen_on(GLOBAL_DEF("display/keep_screen_on", true));
+ set_keep_screen_on(GLOBAL_DEF("display/window/keep_screen_on", true));
}
void OSUWP::set_clipboard(const String &p_text) {
@@ -851,9 +851,8 @@ String OSUWP::get_data_dir() const {
return String(data_folder->Path->Data()).replace("\\", "/");
}
-bool OSUWP::check_feature_support(const String &p_feature) {
-
- return VisualServer::get_singleton()->has_os_feature(p_feature);
+bool OSUWP::_check_internal_feature_support(const String &p_feature) {
+ return p_feature == "pc" || p_feature == "s3tc";
}
PowerState OSUWP::get_power_state() {
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 45b8eefde..dfa21a093 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -236,7 +236,7 @@ public:
virtual void move_window_to_foreground();
virtual String get_data_dir() const;
- virtual bool check_feature_support(const String &p_feature);
+ virtual bool _check_internal_feature_support(const String &p_feature);
void set_gl_context(ContextEGL *p_context);
void screen_size_changed();
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 5e56c1db4..4d93b3f24 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,104 +1,7 @@
-#
-# tested on | Windows native | Linux cross-compilation
-# ----------------------------+-------------------+---------------------------
-# Visual C++ Build Tools 2015 | WORKS | n/a
-# MSVS C++ 2010 Express | WORKS | n/a
-# Mingw-w64 | WORKS | WORKS
-# Mingw-w32 | WORKS | WORKS
-# MinGW | WORKS | untested
-#
-#####
-# Note about Visual C++ Build Tools :
-#
-# - Visual C++ Build Tools is the standalone MSVC compiler :
-# http://landinghub.visualstudio.com/visual-cpp-build-tools
-#
-#####
-# Notes about MSVS C++ :
-#
-# - MSVC2010-Express compiles to 32bits only.
-#
-#####
-# Notes about Mingw-w64 and Mingw-w32 under Windows :
-#
-# - both can be installed using the official installer :
-# http://mingw-w64.sourceforge.net/download.php#mingw-builds
-#
-# - if you want to compile both 32bits and 64bits, don't forget to
-# run the installer twice to install them both.
-#
-# - install them into a path that does not contain spaces
-# ( example : "C:/Mingw-w32", "C:/Mingw-w64" )
-#
-# - if you want to compile faster using the "-j" option, don't forget
-# to install the appropriate version of the Pywin32 python extension
-# available from : http://sourceforge.net/projects/pywin32/files/
-#
-# - before running scons, you must add into the environment path
-# the path to the "/bin" directory of the Mingw version you want
-# to use :
-#
-# set PATH=C:/Mingw-w32/bin;%PATH%
-#
-# - then, scons should be able to detect gcc.
-# - Mingw-w32 only compiles 32bits.
-# - Mingw-w64 only compiles 64bits.
-#
-# - it is possible to add them both at the same time into the PATH env,
-# if you also define the MINGW32_PREFIX and MINGW64_PREFIX environment
-# variables.
-# For instance, you could store that set of commands into a .bat script
-# that you would run just before scons :
-#
-# set PATH=C:\mingw-w32\bin;%PATH%
-# set PATH=C:\mingw-w64\bin;%PATH%
-# set MINGW32_PREFIX=C:\mingw-w32\bin\
-# set MINGW64_PREFIX=C:\mingw-w64\bin\
-#
-#####
-# Notes about Mingw, Mingw-w64 and Mingw-w32 under Linux :
-#
-# - default toolchain prefixes are :
-# "i586-mingw32msvc-" for MinGW
-# "i686-w64-mingw32-" for Mingw-w32
-# "x86_64-w64-mingw32-" for Mingw-w64
-#
-# - if both MinGW and Mingw-w32 are installed on your system
-# Mingw-w32 should take the priority over MinGW.
-#
-# - it is possible to manually override prefixes by defining
-# the MINGW32_PREFIX and MINGW64_PREFIX environment variables.
-#
-#####
-# Notes about Mingw under Windows :
-#
-# - this is the MinGW version from http://mingw.org/
-# - install it into a path that does not contain spaces
-# ( example : "C:/MinGW" )
-# - several DirectX headers might be missing. You can copy them into
-# the C:/MinGW/include" directory from this page :
-# https://code.google.com/p/mingw-lib/source/browse/trunk/working/avcodec_to_widget_5/directx_include/
-# - before running scons, add the path to the "/bin" directory :
-# set PATH=C:/MinGW/bin;%PATH%
-# - scons should be able to detect gcc.
-#
-
-#####
-# TODO :
-#
-# - finish to cleanup this script to remove all the remains of previous hacks and workarounds
-# - make it work with the Windows7 SDK that is supposed to enable 64bits compilation for MSVC2010-Express
-# - confirm it works well with other Visual Studio versions.
-# - update the wiki about the pywin32 extension required for the "-j" option under Windows.
-# - update the wiki to document MINGW32_PREFIX and MINGW64_PREFIX
-#
-
+import methods
import os
-
import sys
-import methods
-
def is_active():
return True
@@ -115,7 +18,7 @@ def can_build():
if (os.getenv("VCINSTALLDIR")):
return True
else:
- print("\nMSVC not detected, attempting Mingw.")
+ print("\nMSVC not detected, attempting MinGW.")
mingw32 = ""
mingw64 = ""
if (os.getenv("MINGW32_PREFIX")):
@@ -126,7 +29,7 @@ def can_build():
test = "gcc --version > NUL 2>&1"
if os.system(test) != 0 and os.system(mingw32 + test) != 0 and os.system(mingw64 + test) != 0:
print("- could not detect gcc.")
- print("Please, make sure a path to a Mingw /bin directory is accessible into the environment PATH.\n")
+ print("Please, make sure a path to a MinGW /bin directory is accessible into the environment PATH.\n")
return False
else:
print("- gcc detected.")
@@ -145,7 +48,7 @@ def can_build():
if (os.getenv("MINGW64_PREFIX")):
mingw64 = os.getenv("MINGW64_PREFIX")
- test = "gcc --version &>/dev/null"
+ test = "gcc --version > /dev/null 2>&1"
if (os.system(mingw + test) == 0 or os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0):
return True
@@ -162,7 +65,7 @@ def get_opts():
mingw32 = "i686-w64-mingw32-"
mingw64 = "x86_64-w64-mingw32-"
- if os.system(mingw32 + "gcc --version &>/dev/null") != 0:
+ if os.system(mingw32 + "gcc --version > /dev/null 2>&1") != 0:
mingw32 = mingw
if (os.getenv("MINGW32_PREFIX")):
@@ -172,8 +75,8 @@ def get_opts():
mingw64 = os.getenv("MINGW64_PREFIX")
return [
- ('mingw_prefix', 'Mingw Prefix', mingw32),
- ('mingw_prefix_64', 'Mingw Prefix 64 bits', mingw64),
+ ('mingw_prefix', 'MinGW Prefix', mingw32),
+ ('mingw_prefix_64', 'MinGW Prefix 64 bits', mingw64),
]
@@ -211,55 +114,86 @@ def configure(env):
# Targeted Windows version: Vista (and later)
winver = "0x0600" # Windows Vista is the minimum target for windows builds
- env['is_mingw'] = False
- if (os.name == "nt" and os.getenv("VCINSTALLDIR")):
- # build using visual studio
+ if (os.name == "nt" and os.getenv("VCINSTALLDIR")): # MSVC
+
env['ENV']['TMP'] = os.environ['TMP']
- env.Append(CPPPATH=['#platform/windows/include'])
- env.Append(LIBPATH=['#platform/windows/lib'])
- env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver])
- if (env["target"] == "release"):
+ ## Build type
+ if (env["target"] == "release"):
env.Append(CCFLAGS=['/O2'])
env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
elif (env["target"] == "release_debug"):
-
env.Append(CCFLAGS=['/O2', '/DDEBUG_ENABLED'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- elif (env["target"] == "debug_release"):
+ elif (env["target"] == "debug_release"):
env.Append(CCFLAGS=['/Z7', '/Od'])
env.Append(LINKFLAGS=['/DEBUG'])
env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
elif (env["target"] == "debug"):
-
env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
env.Append(LINKFLAGS=['/DEBUG'])
- env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo'])
+ ## Architecture
+
+ # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows)
+ if (env["bits"] != "default"):
+ print("Error: bits argument is disabled for MSVC")
+ print("""
+ Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console
+ (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits
+ argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
+ """)
+ sys.exit()
+
+ # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt
+ # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with)
+ env["bits"] = "32"
+ env["x86_libtheora_opt_vc"] = True
+
+ ## Compiler configuration
+
+ env['ENV'] = os.environ
+ # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far bellow in the code
+ compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV'])
+
+ print("Detected MSVC compiler: " + compiler_version_str)
+ # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writting)... vc compiler for 64bit can not compile _asm
+ if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"):
+ env["bits"] = "64"
+ env["x86_libtheora_opt_vc"] = False
+ print("Compiled program architecture will be a 64 bit executable (forcing bits=64).")
+ elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"):
+ print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).")
+ else:
+ print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.")
+
+ ## Compile flags
+
+ env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo'])
env.Append(CXXFLAGS=['/TP'])
env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
env.Append(CCFLAGS=['/I' + os.getenv("WindowsSdkDir") + "/Include"])
+
env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
+ env.Append(CCFLAGS=['/DOPENGL_ENABLED'])
env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
- env.Append(CCFLAGS=['/DWIN32'])
env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
+ env.Append(CCFLAGS=['/DWIN32'])
+ env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver])
+ if env["bits"] == "64":
+ env.Append(CCFLAGS=['/D_WIN64'])
- env.Append(CCFLAGS=['/DOPENGL_ENABLED'])
LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid']
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"])
- if (os.getenv("DXSDK_DIR")):
- DIRECTX_PATH = os.getenv("DXSDK_DIR")
- else:
- DIRECTX_PATH = "C:/Program Files/Microsoft DirectX SDK (March 2009)"
if (os.getenv("VCINSTALLDIR")):
VC_PATH = os.getenv("VCINSTALLDIR")
@@ -268,51 +202,37 @@ def configure(env):
env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
- env.Append(CCFLAGS=["/I" + DIRECTX_PATH + "/Include"])
- env.Append(LIBPATH=[DIRECTX_PATH + "/Lib/x86"])
- env['ENV'] = os.environ
-
- # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far bellow in the code
- compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV'])
-
- # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows)
- if(env["bits"] != "default"):
- print "Error: bits argument is disabled for MSVC"
- print ("Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings)"
- + " that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler"
- + " will be executed and inform you.")
- sys.exit()
-
- # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt
- # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with)
- env["bits"] = "32"
- env["x86_libtheora_opt_vc"] = True
-
- print "Detected MSVC compiler: " + compiler_version_str
- # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writting)... vc compiler for 64bit can not compile _asm
- if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"):
- env["bits"] = "64"
- env["x86_libtheora_opt_vc"] = False
- print "Compiled program architecture will be a 64 bit executable (forcing bits=64)."
- elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"):
- print "Compiled program architecture will be a 32 bit executable. (forcing bits=32)."
- else:
- print "Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup."
- if env["bits"] == "64":
- env.Append(CCFLAGS=['/D_WIN64'])
# Incremental linking fix
env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program']
env['BUILDERS']['Program'] = methods.precious_program
- else:
+ else: # MinGW
# Workaround for MinGW. See:
# http://www.scons.org/wiki/LongCmdLinesOnWin32
env.use_windows_spawn_fix()
- # build using mingw
- env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver])
+ ## Build type
+
+ if (env["target"] == "release"):
+ env.Append(CCFLAGS=['-msse2'])
+
+ if (env["bits"] == "64"):
+ env.Append(CCFLAGS=['-O3'])
+ else:
+ env.Append(CCFLAGS=['-O2'])
+
+ env.Append(LINKFLAGS=['-Wl,--subsystem,windows'])
+
+ elif (env["target"] == "release_debug"):
+ env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+
+ elif (env["target"] == "debug"):
+ env.Append(CCFLAGS=['-g', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+
+ ## Compiler configuration
+
if (os.name == "nt"):
env['ENV']['TMP'] = os.environ['TMP'] # way to go scons, you can be so stupid sometimes
else:
@@ -332,37 +252,6 @@ def configure(env):
env.Append(LINKFLAGS=['-static'])
mingw_prefix = env["mingw_prefix_64"]
- nulstr = ""
-
- if (os.name == "posix"):
- nulstr = ">/dev/null"
- else:
- nulstr = ">nul"
-
- # if os.system(mingw_prefix+"gcc --version"+nulstr)!=0:
- # #not really super consistent but..
- # print("Can't find Windows compiler: "+mingw_prefix)
- # sys.exit(255)
-
- if (env["target"] == "release"):
-
- env.Append(CCFLAGS=['-msse2'])
-
- if (env["bits"] == "64"):
- env.Append(CCFLAGS=['-O3'])
- else:
- env.Append(CCFLAGS=['-O2'])
-
- env.Append(LINKFLAGS=['-Wl,--subsystem,windows'])
-
- elif (env["target"] == "release_debug"):
-
- env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
-
- elif (env["target"] == "debug"):
-
- env.Append(CCFLAGS=['-g', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
-
env["CC"] = mingw_prefix + "gcc"
env['AS'] = mingw_prefix + "as"
env['CXX'] = mingw_prefix + "g++"
@@ -371,29 +260,15 @@ def configure(env):
env['LD'] = mingw_prefix + "g++"
env["x86_libtheora_opt_gcc"] = True
- #env['CC'] = "winegcc"
- #env['CXX'] = "wineg++"
+ ## Compile flags
env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows'])
- env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
env.Append(CCFLAGS=['-DOPENGL_ENABLED'])
+ env.Append(CCFLAGS=['-DRTAUDIO_ENABLED'])
+ env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver])
env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid'])
- # if (env["bits"]=="32"):
- # env.Append(LIBS=['gcc_s'])
- # #--with-arch=i686
- # env.Append(CPPFLAGS=['-march=i686'])
- # env.Append(LINKFLAGS=['-march=i686'])
-
- #'d3dx9d'
env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
- # env.Append(LINKFLAGS=['-g'])
# resrc
- env['is_mingw'] = True
env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')})
-
- env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'HLSL9': env.Builder(action=methods.build_hlsl_dx9_headers, suffix='hlsl.h', src_suffix='.hlsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index c9271f626..6cb33e2ff 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -46,6 +46,7 @@ void register_windows_exporter() {
platform->set_debug_32("windows_32_debug.exe");
platform->set_release_64("windows_64_release.exe");
platform->set_debug_64("windows_64_debug.exe");
+ platform->set_os_name("Windows");
EditorExport::get_singleton()->add_export_platform(platform);
}
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index e94529dd9..da14d5c28 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -37,12 +37,12 @@
#include "drivers/windows/rw_lock_windows.h"
#include "drivers/windows/semaphore_windows.h"
#include "drivers/windows/thread_windows.h"
-#include "global_config.h"
#include "io/marshalls.h"
#include "joypad.h"
#include "lang_table.h"
#include "main/main.h"
#include "packet_peer_udp_winsock.h"
+#include "project_settings.h"
#include "servers/audio_server.h"
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
@@ -805,7 +805,12 @@ void OS_Windows::process_key_events() {
k->set_pressed(ke.uMsg == WM_KEYDOWN);
- k->set_scancode(KeyMappingWindows::get_keysym(ke.wParam));
+ if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
+ // Special case for Numpad Enter key
+ k->set_scancode(KEY_ENTER);
+ } else {
+ k->set_scancode(KeyMappingWindows::get_keysym(ke.wParam));
+ }
if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
k->set_unicode(key_event_buffer[i + 1].wParam);
@@ -1410,28 +1415,21 @@ void OS_Windows::set_window_size(const Size2 p_size) {
return;
}
- RECT crect;
- GetClientRect(hWnd, &crect);
+ int w = p_size.width;
+ int h = p_size.height;
RECT rect;
GetWindowRect(hWnd, &rect);
- int dx = (rect.right - rect.left) - (crect.right - crect.left);
- int dy = (rect.bottom - rect.top) - (crect.bottom - crect.top);
-
- rect.right = rect.left + p_size.width + dx;
- rect.bottom = rect.top + p_size.height + dy;
- //print_line("PRE: "+itos(rect.left)+","+itos(rect.top)+","+itos(rect.right-rect.left)+","+itos(rect.bottom-rect.top));
+ if (video_mode.borderless_window == false) {
+ RECT crect;
+ GetClientRect(hWnd, &crect);
- /*if (video_mode.resizable) {
- AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
- } else {
- AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE);
- }*/
-
- //print_line("POST: "+itos(rect.left)+","+itos(rect.top)+","+itos(rect.right-rect.left)+","+itos(rect.bottom-rect.top));
+ w += (rect.right - rect.left) - (crect.right - crect.left);
+ h += (rect.bottom - rect.top) - (crect.bottom - crect.top);
+ }
- MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
+ MoveWindow(hWnd, rect.left, rect.top, w, h, TRUE);
}
void OS_Windows::set_window_fullscreen(bool p_enabled) {
@@ -1451,21 +1449,18 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) {
Point2 pos = get_screen_position(cs);
Size2 size = get_screen_size(cs);
- /* r.left = pos.x;
- r.top = pos.y;
- r.bottom = pos.y+size.y;
- r.right = pos.x+size.x;
-*/
- SetWindowLongPtr(hWnd, GWL_STYLE,
- WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
- MoveWindow(hWnd, pos.x, pos.y, size.width, size.height, TRUE);
-
video_mode.fullscreen = true;
+ _update_window_style(false);
+
+ MoveWindow(hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+
} else {
RECT rect;
+ video_mode.fullscreen = false;
+
if (pre_fs_valid) {
rect = pre_fs_rect;
} else {
@@ -1475,35 +1470,12 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) {
rect.bottom = video_mode.height;
}
- if (video_mode.resizable) {
-
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
- //AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
- MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
- } else {
+ _update_window_style(false);
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE);
- //AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE);
- MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
- }
+ MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
- video_mode.fullscreen = false;
pre_fs_valid = true;
- /*
- DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
- DWORD dwStyle=WS_OVERLAPPEDWINDOW;
- if (!video_mode.resizable) {
- dwStyle &= ~WS_THICKFRAME;
- dwStyle &= ~WS_MAXIMIZEBOX;
- }
- AdjustWindowRectEx(&pre_fs_rect, dwStyle, FALSE, dwExStyle);
- video_mode.fullscreen=false;
- video_mode.width=pre_fs_rect.right-pre_fs_rect.left;
- video_mode.height=pre_fs_rect.bottom-pre_fs_rect.top;
-*/
}
-
- //MoveWindow(hWnd,r.left,r.top,p_size.x,p_size.y,TRUE);
}
bool OS_Windows::is_window_fullscreen() const {
@@ -1513,30 +1485,10 @@ void OS_Windows::set_window_resizable(bool p_enabled) {
if (video_mode.resizable == p_enabled)
return;
- /*
- GetWindowRect(hWnd,&pre_fs_rect);
- DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
- DWORD dwStyle=WS_OVERLAPPEDWINDOW;
- if (!p_enabled) {
- dwStyle &= ~WS_THICKFRAME;
- dwStyle &= ~WS_MAXIMIZEBOX;
- }
- AdjustWindowRectEx(&pre_fs_rect, dwStyle, FALSE, dwExStyle);
- */
-
- if (!video_mode.fullscreen) {
- if (p_enabled) {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
- } else {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE);
- }
-
- RECT rect;
- GetWindowRect(hWnd, &rect);
- MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
- }
video_mode.resizable = p_enabled;
+
+ _update_window_style();
}
bool OS_Windows::is_window_resizable() const {
@@ -1576,13 +1528,36 @@ bool OS_Windows::is_window_maximized() const {
}
void OS_Windows::set_borderless_window(int p_borderless) {
+ if (video_mode.borderless_window == p_borderless)
+ return;
+
video_mode.borderless_window = p_borderless;
+
+ _update_window_style();
}
bool OS_Windows::get_borderless_window() {
return video_mode.borderless_window;
}
+void OS_Windows::_update_window_style(bool repaint) {
+ if (video_mode.fullscreen || video_mode.borderless_window) {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
+ } else {
+ if (video_mode.resizable) {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
+ } else {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE);
+ }
+ }
+
+ if (repaint) {
+ RECT rect;
+ GetWindowRect(hWnd, &rect);
+ MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
+ }
+}
+
Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle) {
p_library_handle = (void *)LoadLibrary(p_path.utf8().get_data());
if (!p_library_handle) {
@@ -1599,12 +1574,16 @@ Error OS_Windows::close_dynamic_library(void *p_library_handle) {
return OK;
}
-Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle) {
+Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) {
char *error;
p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data());
if (!p_symbol_handle) {
- ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + String::num(GetLastError()));
- ERR_FAIL_V(ERR_CANT_RESOLVE);
+ if (!p_optional) {
+ ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + String::num(GetLastError()));
+ ERR_FAIL_V(ERR_CANT_RESOLVE);
+ } else {
+ return ERR_CANT_RESOLVE;
+ }
}
return OK;
}
@@ -2259,7 +2238,7 @@ String OS_Windows::get_data_dir() const {
if (has_environment("APPDATA")) {
- bool use_godot = GlobalConfig::get_singleton()->get("application/use_shared_user_dir");
+ bool use_godot = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir");
if (!use_godot)
return (OS::get_singleton()->get_environment("APPDATA") + "/" + an).replace("\\", "/");
else
@@ -2267,7 +2246,7 @@ String OS_Windows::get_data_dir() const {
}
}
- return GlobalConfig::get_singleton()->get_resource_path();
+ return ProjectSettings::get_singleton()->get_resource_path();
}
bool OS_Windows::is_joy_known(int p_device) {
@@ -2304,9 +2283,9 @@ int OS_Windows::get_power_percent_left() {
return power_manager->get_power_percent_left();
}
-bool OS_Windows::check_feature_support(const String &p_feature) {
+bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
- return VisualServer::get_singleton()->has_os_feature(p_feature);
+ return p_feature == "pc" || p_feature == "s3tc";
}
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 6cbdd5883..6856e7e9b 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -133,6 +133,8 @@ class OS_Windows : public OS {
void _drag_event(int p_x, int p_y, int idx);
void _touch_event(bool p_pressed, int p_x, int p_y, int idx);
+ void _update_window_style(bool repaint = true);
+
// functions used by main to initialize/deintialize the OS
protected:
virtual int get_video_driver_count() const;
@@ -225,7 +227,7 @@ public:
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle);
virtual Error close_dynamic_library(void *p_library_handle);
- virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle);
+ virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
virtual MainLoop *get_main_loop() const;
@@ -286,7 +288,7 @@ public:
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
- virtual bool check_feature_support(const String &p_feature);
+ virtual bool _check_internal_feature_support(const String &p_feature);
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 0ba0f6839..79778136a 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -1,7 +1,6 @@
-
import os
-import sys
import platform
+import sys
def is_active():
@@ -14,15 +13,12 @@ def get_name():
def can_build():
- if (os.name != "posix"):
+ if (os.name != "posix" or sys.platform == "darwin"):
return False
- if sys.platform == "darwin":
- return False # no x11 on mac for now
-
- errorval = os.system("pkg-config --version > /dev/null")
-
- if (errorval):
+ # Check the minimal dependencies
+ x11_error = os.system("pkg-config --version > /dev/null")
+ if (x11_error):
print("pkg-config not found.. x11 disabled.")
return False
@@ -31,11 +27,6 @@ def can_build():
print("X11 not found.. x11 disabled.")
return False
- ssl_error = os.system("pkg-config openssl --modversion > /dev/null ")
- if (ssl_error):
- print("OpenSSL not found.. x11 disabled.")
- return False
-
x11_error = os.system("pkg-config xcursor --modversion > /dev/null ")
if (x11_error):
print("xcursor not found.. x11 disabled.")
@@ -51,18 +42,18 @@ def can_build():
print("xrandr not found.. x11 disabled.")
return False
- return True # X11 enabled
+ return True
def get_opts():
return [
- ('use_llvm', 'Use llvm compiler', 'no'),
- ('use_static_cpp', 'link stdc++ statically', 'no'),
- ('use_sanitizer', 'Use llvm compiler sanitize address', 'no'),
- ('use_leak_sanitizer', 'Use llvm compiler sanitize memory leaks', 'no'),
+ ('use_llvm', 'Use the LLVM compiler', 'no'),
+ ('use_static_cpp', 'Link stdc++ statically', 'no'),
+ ('use_sanitizer', 'Use LLVM compiler address sanitizer', 'no'),
+ ('use_leak_sanitizer', 'Use LLVM compiler memory leaks sanitizer (implies use_sanitizer)', 'no'),
('use_lto', 'Use link time optimization', 'no'),
- ('pulseaudio', 'Detect & Use pulseaudio', 'yes'),
+ ('pulseaudio', 'Detect & use pulseaudio', 'yes'),
('udev', 'Use udev for gamepad connection callbacks', 'no'),
('debug_release', 'Add debug symbols to release version', 'no'),
]
@@ -80,66 +71,62 @@ def get_flags():
def configure(env):
- is64 = sys.maxsize > 2**32
+ ## Build type
+
+ if (env["target"] == "release"):
+ env.Prepend(CCFLAGS=['-Ofast'])
+ if (env["debug_release"] == "yes"):
+ env.Prepend(CCFLAGS=['-g2'])
+ elif (env["target"] == "release_debug"):
+ env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
+ if (env["debug_release"] == "yes"):
+ env.Prepend(CCFLAGS=['-g2'])
+
+ elif (env["target"] == "debug"):
+ env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+
+ ## Architecture
+
+ is64 = sys.maxsize > 2**32
if (env["bits"] == "default"):
- if (is64):
- env["bits"] = "64"
- else:
- env["bits"] = "32"
+ env["bits"] = "64" if is64 else "32"
+
+ ## Compiler configuration
- env.Append(CPPPATH=['#platform/x11'])
if (env["use_llvm"] == "yes"):
- if 'clang++' not in env['CXX']:
+ if ('clang++' not in env['CXX']):
env["CC"] = "clang"
env["CXX"] = "clang++"
env["LD"] = "clang++"
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
- env.extra_suffix = ".llvm"
-
- if (env["use_sanitizer"] == "yes"):
- env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer'])
- env.Append(LINKFLAGS=['-fsanitize=address'])
- env.extra_suffix += "s"
+ env.extra_suffix = ".llvm" + env.extra_suffix
- if (env["use_leak_sanitizer"] == "yes"):
+ # leak sanitizer requires (address) sanitizer
+ if (env["use_sanitizer"] == "yes" or env["use_leak_sanitizer"] == "yes"):
env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer'])
env.Append(LINKFLAGS=['-fsanitize=address'])
env.extra_suffix += "s"
-
- # if (env["tools"]=="no"):
- # #no tools suffix
- # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
- # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+ if (env["use_leak_sanitizer"] == "yes"):
+ env.Append(CCFLAGS=['-fsanitize=leak'])
+ env.Append(LINKFLAGS=['-fsanitize=leak'])
if (env["use_lto"] == "yes"):
env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto'])
-
env.Append(CCFLAGS=['-pipe'])
env.Append(LINKFLAGS=['-pipe'])
- if (env["target"] == "release"):
- env.Prepend(CCFLAGS=['-Ofast'])
- if (env["debug_release"] == "yes"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "release_debug"):
-
- env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
- if (env["debug_release"] == "yes"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "debug"):
-
- env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ ## Dependencies
env.ParseConfig('pkg-config x11 --cflags --libs')
- env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xcursor --cflags --libs')
+ env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xrandr --cflags --libs')
+ # FIXME: Check for existence of the libs before parsing their flags with pkg-config
+
if (env['builtin_openssl'] == 'no'):
# Currently not compatible with OpenSSL 1.1.0+
# https://github.com/godotengine/godot/issues/8624
@@ -196,47 +183,51 @@ def configure(env):
if (env['builtin_libogg'] == 'no'):
env.ParseConfig('pkg-config ogg --cflags --libs')
- env.Append(CPPFLAGS=['-DOPENGL_ENABLED'])
+ if (env['builtin_libtheora'] != 'no'):
+ list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
+ if any(platform.machine() in s for s in list_of_x86):
+ env["x86_libtheora_opt_gcc"] = True
- if os.system("pkg-config --exists alsa") == 0:
+ ## Flags
+
+ if (os.system("pkg-config --exists alsa") == 0): # 0 means found
print("Enabling ALSA")
env.Append(CPPFLAGS=["-DALSA_ENABLED"])
env.ParseConfig('pkg-config alsa --cflags --libs')
else:
print("ALSA libraries not found, disabling driver")
- if (platform.system() == "Linux"):
- env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"])
- if (env["udev"] == "yes"):
- # pkg-config returns 0 when the lib exists...
- found_udev = not os.system("pkg-config --exists libudev")
-
- if (found_udev):
- print("Enabling udev support")
- env.Append(CPPFLAGS=["-DUDEV_ENABLED"])
- env.ParseConfig('pkg-config libudev --cflags --libs')
- else:
- print("libudev development libraries not found, disabling udev support")
-
if (env["pulseaudio"] == "yes"):
- if not os.system("pkg-config --exists libpulse-simple"):
+ if (os.system("pkg-config --exists libpulse-simple") == 0): # 0 means found
print("Enabling PulseAudio")
env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"])
env.ParseConfig('pkg-config --cflags --libs libpulse-simple')
else:
print("PulseAudio development libraries not found, disabling driver")
+ if (platform.system() == "Linux"):
+ env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"])
+
+ if (env["udev"] == "yes"):
+ if (os.system("pkg-config --exists libudev") == 0): # 0 means found
+ print("Enabling udev support")
+ env.Append(CPPFLAGS=["-DUDEV_ENABLED"])
+ env.ParseConfig('pkg-config libudev --cflags --libs')
+ else:
+ print("libudev development libraries not found, disabling udev support")
+
+ # Linkflags below this line should typically stay the last ones
if (env['builtin_zlib'] == 'no'):
env.ParseConfig('pkg-config zlib --cflags --libs')
- env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
+ env.Append(CPPPATH=['#platform/x11'])
+ env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
env.Append(LIBS=['GL', 'pthread'])
if (platform.system() == "Linux"):
env.Append(LIBS=['dl'])
- # env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])
- # host compiler is default..
+ ## Cross-compilation
if (is64 and env["bits"] == "32"):
env.Append(CPPFLAGS=['-m32'])
@@ -245,17 +236,5 @@ def configure(env):
env.Append(CPPFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
- import methods
-
- # FIXME: Commented out when moving to gles3
- #env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- #env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- #env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
- #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
-
if (env["use_static_cpp"] == "yes"):
env.Append(LINKFLAGS=['-static-libstdc++'])
-
- list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
- if any(platform.machine() in s for s in list_of_x86):
- env["x86_libtheora_opt_gcc"] = True
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
index 69784a473..c8d6220ae 100644
--- a/platform/x11/export/export.cpp
+++ b/platform/x11/export/export.cpp
@@ -48,6 +48,7 @@ void register_x11_exporter() {
platform->set_debug_32("linux_x11_32_debug");
platform->set_release_64("linux_x11_64_release");
platform->set_debug_64("linux_x11_64_debug");
+ platform->set_os_name("X11");
EditorExport::get_singleton()->add_export_platform(platform);
diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp
index b293b1beb..6f418b213 100644
--- a/platform/x11/godot_x11.cpp
+++ b/platform/x11/godot_x11.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <limits.h>
+#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
@@ -38,6 +39,8 @@ int main(int argc, char *argv[]) {
OS_X11 os;
+ setlocale(LC_CTYPE, "");
+
char *cwd = (char *)malloc(PATH_MAX);
getcwd(cwd, PATH_MAX);
diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp
index 362fc3618..1d7eb1692 100644
--- a/platform/x11/key_mapping_x11.cpp
+++ b/platform/x11/key_mapping_x11.cpp
@@ -94,7 +94,6 @@ static _XTranslatePair _xkeysym_to_keycode[] = {
//{ XK_KP_Separator, KEY_COMMA },
{ XK_KP_Decimal, KEY_KP_PERIOD },
{ XK_KP_Delete, KEY_KP_PERIOD },
- { XK_KP_Enter, KEY_KP_ENTER },
{ XK_KP_Multiply, KEY_KP_MULTIPLY },
{ XK_KP_Divide, KEY_KP_DIVIDE },
{ XK_KP_Subtract, KEY_KP_SUBTRACT },
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 2eebc96d2..1dde328ed 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -68,6 +68,8 @@
#undef CursorShape
+#include <X11/XKBlib.h>
+
int OS_X11::get_video_driver_count() const {
return 1;
}
@@ -93,6 +95,7 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
+ long im_event_mask = 0;
last_button_state = 0;
xmbstring = NULL;
@@ -113,7 +116,32 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
/** XLIB INITIALIZATION **/
x11_display = XOpenDisplay(NULL);
- char *modifiers = XSetLocaleModifiers("@im=none");
+ Bool xkb_dar = False;
+ if (x11_display) {
+ XAutoRepeatOn(x11_display);
+ xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL);
+ }
+
+ char *modifiers = NULL;
+
+ // Try to support IME if detectable auto-repeat is supported
+
+ if (xkb_dar == True) {
+
+// Xutf8LookupString will be used later instead of XmbLookupString before
+// the multibyte sequences can be converted to unicode string.
+
+#ifdef X_HAVE_UTF8_STRING
+ modifiers = XSetLocaleModifiers("");
+#endif
+ }
+
+ if (modifiers == NULL) {
+ if (is_stdout_verbose()) {
+ WARN_PRINT("IME is disabled");
+ }
+ modifiers = XSetLocaleModifiers("@im=none");
+ }
if (modifiers == NULL) {
WARN_PRINT("Error setting locale modifiers");
}
@@ -153,6 +181,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
WARN_PRINT("XOpenIM failed");
xim_style = 0L;
} else {
+ ::XIMCallback im_destroy_callback;
+ im_destroy_callback.client_data = (::XPointer)(this);
+ im_destroy_callback.callback = (::XIMProc)(xim_destroy_callback);
+ if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback,
+ NULL) != NULL) {
+ WARN_PRINT("Error setting XIM destroy callback");
+ }
+
::XIMStyles *xim_styles = NULL;
xim_style = 0L;
char *imvalret = NULL;
@@ -242,6 +278,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
xev.xclient.data.l[2] = 0;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev);
+ } else if (current_videomode.borderless_window) {
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = 0;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
}
// disable resizable window
@@ -303,7 +346,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
StructureNotifyMask |
SubstructureNotifyMask | SubstructureRedirectMask |
FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask;
+ ColormapChangeMask | OwnerGrabButtonMask |
+ im_event_mask;
XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
@@ -327,6 +371,16 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
if (xim && xim_style) {
xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, x11_window, XNFocusWindow, x11_window, (char *)NULL);
+ if (XGetICValues(xic, XNFilterEvents, &im_event_mask, NULL) != NULL) {
+ WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
+ XDestroyIC(xic);
+ xic = NULL;
+ }
+ if (xic) {
+ XSetICFocus(xic);
+ } else {
+ WARN_PRINT("XCreateIC couldn't create xic");
+ }
} else {
xic = NULL;
@@ -443,6 +497,30 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
joypad = memnew(JoypadLinux(input));
#endif
_ensure_data_dir();
+
+ power_manager = memnew(PowerX11);
+}
+
+void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data) {
+
+ WARN_PRINT("Input method stopped");
+ OS_X11 *os = reinterpret_cast<OS_X11 *>(client_data);
+ os->xim = NULL;
+ os->xic = NULL;
+}
+
+void OS_X11::set_ime_position(const Point2 &p_pos) {
+
+ if (!xic)
+ return;
+
+ ::XPoint spot;
+ spot.x = short(p_pos.x);
+ spot.y = short(p_pos.y);
+ XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+ XSetICValues(xic, XNPreeditAttributes, preedit_attr, NULL);
+ XFree(preedit_attr);
}
void OS_X11::finalize() {
@@ -492,8 +570,12 @@ void OS_X11::finalize() {
XcursorImageDestroy(img[i]);
};
- XDestroyIC(xic);
- XCloseIM(xim);
+ if (xic) {
+ XDestroyIC(xic);
+ }
+ if (xim) {
+ XCloseIM(xim);
+ }
XCloseDisplay(x11_display);
if (xmbstring)
@@ -606,6 +688,16 @@ void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con
}
void OS_X11::set_wm_fullscreen(bool p_enabled) {
+ if (p_enabled && !is_window_resizable()) {
+ // Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
+ XSizeHints *xsh;
+
+ xsh = XAllocSizeHints();
+ xsh->flags = 0L;
+ XSetWMNormalHints(x11_display, x11_window, xsh);
+ XFree(xsh);
+ }
+
// Using EWMH -- Extened Window Manager Hints
XEvent xev;
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
@@ -621,6 +713,23 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) {
xev.xclient.data.l[2] = 0;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ XFlush(x11_display);
+
+ if (!p_enabled && !is_window_resizable()) {
+ // Reset the non-resizable flags if we un-set these before.
+ Size2 size = get_window_size();
+ XSizeHints *xsh;
+
+ xsh = XAllocSizeHints();
+ xsh->flags = PMinSize | PMaxSize;
+ xsh->min_width = size.x;
+ xsh->max_width = size.x;
+ xsh->min_height = size.y;
+ xsh->max_height = size.y;
+
+ XSetWMNormalHints(x11_display, x11_window, xsh);
+ XFree(xsh);
+ }
}
int OS_X11::get_screen_count() const {
@@ -940,6 +1049,25 @@ bool OS_X11::is_window_maximized() const {
return false;
}
+void OS_X11::set_borderless_window(int p_borderless) {
+
+ if (current_videomode.borderless_window == p_borderless)
+ return;
+
+ current_videomode.borderless_window = p_borderless;
+
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = current_videomode.borderless_window ? 0 : 1;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+}
+
+bool OS_X11::get_borderless_window() {
+ return current_videomode.borderless_window;
+}
+
void OS_X11::request_attention() {
// Using EWMH -- Extended Window Manager Hints
//
@@ -1041,9 +1169,61 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
xmblen = 8;
}
+ keysym_unicode = keysym_keycode;
+
if (xkeyevent->type == KeyPress && xic) {
Status status;
+#ifdef X_HAVE_UTF8_STRING
+ int utf8len = 8;
+ char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
+ int utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ if (status == XBufferOverflow) {
+ utf8len = utf8bytes + 1;
+ utf8string = (char *)memrealloc(utf8string, utf8len);
+ utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ }
+ utf8string[utf8bytes] = '\0';
+
+ if (status == XLookupChars) {
+ bool keypress = xkeyevent->type == KeyPress;
+ unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+ if (keycode >= 'a' && keycode <= 'z')
+ keycode -= 'a' - 'A';
+
+ String tmp;
+ tmp.parse_utf8(utf8string, utf8bytes);
+ for (int i = 0; i < tmp.length(); i++) {
+ Ref<InputEventKey> k;
+ k.instance();
+ if (keycode == 0 && tmp[i] == 0) {
+ continue;
+ }
+
+ get_key_modifier_state(xkeyevent->state, k);
+
+ k->set_unicode(tmp[i]);
+
+ k->set_pressed(keypress);
+
+ k->set_scancode(keycode);
+
+ k->set_echo(false);
+
+ if (k->get_scancode() == KEY_BACKTAB) {
+ //make it consistent across platforms.
+ k->set_scancode(KEY_TAB);
+ k->set_shift(true);
+ }
+
+ input->parse_input_event(k);
+ }
+ return;
+ }
+ memfree(utf8string);
+#else
do {
int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
@@ -1054,6 +1234,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
xmbstring = (char *)memrealloc(xmbstring, xmblen);
}
} while (status == XBufferOverflow);
+#endif
}
/* Phase 2, obtain a pigui keycode from the keysym */
@@ -1082,11 +1263,6 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
bool keypress = xkeyevent->type == KeyPress;
- if (xkeyevent->type == KeyPress && xic) {
- if (XFilterEvent((XEvent *)xkeyevent, x11_window))
- return;
- }
-
if (keycode == 0 && unicode == 0)
return;
@@ -1108,17 +1284,19 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
// Echo characters in X11 are a keyrelease and a keypress
// one after the other with the (almot) same timestamp.
// To detect them, i use XPeekEvent and check that their
- // difference in time is below a treshold.
+ // difference in time is below a threshold.
if (xkeyevent->type != KeyPress) {
+ p_echo = false;
+
// make sure there are events pending,
// so this call won't block.
if (XPending(x11_display) > 0) {
XEvent peek_event;
XPeekEvent(x11_display, &peek_event);
- // I'm using a treshold of 5 msecs,
+ // I'm using a threshold of 5 msecs,
// since sometimes there seems to be a little
// jitter. I'm still not convinced that all this approach
// is correct, but the xorg developers are
@@ -1172,6 +1350,18 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
k->set_metakey(false);
}
+ bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_scancode());
+ if (k->is_pressed()) {
+ if (last_is_pressed) {
+ k->set_echo(true);
+ }
+ } else {
+ //ignore
+ if (last_is_pressed == false) {
+ return;
+ }
+ }
+
//printf("key: %x\n",k->get_scancode());
input->parse_input_event(k);
}
@@ -1253,6 +1443,10 @@ void OS_X11::process_xevents() {
XEvent event;
XNextEvent(x11_display, &event);
+ if (XFilterEvent(&event, None)) {
+ continue;
+ }
+
switch (event.type) {
case Expose:
Main::force_redraw();
@@ -1295,6 +1489,9 @@ void OS_X11::process_xevents() {
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
+ if (xic) {
+ XSetICFocus(xic);
+ }
break;
case FocusOut:
@@ -1308,9 +1505,16 @@ void OS_X11::process_xevents() {
}
XUngrabPointer(x11_display, CurrentTime);
}
+ if (xic) {
+ XUnsetICFocus(xic);
+ }
break;
case ConfigureNotify:
+ if (xic) {
+ // Not portable.
+ set_ime_position(Point2(0, 1));
+ }
/* call resizeGLScene only if our window-size changed */
if ((event.xconfigure.width == current_videomode.width) &&
@@ -1656,7 +1860,7 @@ void OS_X11::set_clipboard(const String &p_text) {
XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime);
};
-static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+static String _get_clipboard_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) {
String ret;
@@ -1673,7 +1877,7 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di
};
if (Sown != None) {
- XConvertSelection(x11_display, p_source, XA_STRING, selection,
+ XConvertSelection(x11_display, p_source, target, selection,
x11_window, CurrentTime);
XFlush(x11_display);
while (true) {
@@ -1713,6 +1917,18 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di
return ret;
}
+static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+ String ret;
+ Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
+ if (utf8_atom != None) {
+ ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom);
+ }
+ if (ret == "") {
+ ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING);
+ }
+ return ret;
+}
+
String OS_X11::get_clipboard() const {
String ret;
@@ -1745,6 +1961,11 @@ Error OS_X11::shell_open(String p_uri) {
return ok;
}
+bool OS_X11::_check_internal_feature_support(const String &p_feature) {
+
+ return p_feature == "pc" || p_feature == "s3tc";
+}
+
String OS_X11::get_system_dir(SystemDir p_dir) const {
String xdgparam;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index d62186e5b..db70f8f84 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -113,6 +113,9 @@ class OS_X11 : public OS_Unix {
::XIC xic;
::XIM xim;
::XIMStyle xim_style;
+ static void xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data);
+
Point2i last_mouse_pos;
bool last_mouse_pos_valid;
Point2i last_click_pos;
@@ -247,6 +250,10 @@ public:
virtual bool is_window_maximized() const;
virtual void request_attention();
+ virtual void set_borderless_window(int p_borderless);
+ virtual bool get_borderless_window();
+ virtual void set_ime_position(const Point2 &p_pos);
+
virtual void move_window_to_foreground();
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
@@ -262,6 +269,8 @@ public:
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
+ virtual bool _check_internal_feature_support(const String &p_feature);
+
void run();
OS_X11();
diff --git a/platform/x11/power_x11.cpp b/platform/x11/power_x11.cpp
index 093d24f40..8e69a2223 100644
--- a/platform/x11/power_x11.cpp
+++ b/platform/x11/power_x11.cpp
@@ -171,25 +171,18 @@ void PowerX11::check_proc_acpi_battery(const char *node, bool *have_battery, boo
charge = true;
}
} else if (String(key) == "remaining capacity") {
- char *endptr = NULL;
- //const int cvt = (int) strtol(val, &endptr, 10);
String sval = val;
const int cvt = sval.to_int();
- if (*endptr == ' ') {
- remaining = cvt;
- }
+ remaining = cvt;
}
}
ptr = &info[0];
while (make_proc_acpi_key_val(&ptr, &key, &val)) {
if (String(key) == "design capacity") {
- char *endptr = NULL;
String sval = val;
const int cvt = sval.to_int();
- if (*endptr == ' ') {
- maximum = cvt;
- }
+ maximum = cvt;
}
}