summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/SCsub31
-rw-r--r--platform/android/SCsub3
-rw-r--r--platform/android/build.gradle.template2
-rw-r--r--platform/android/detect.py49
-rw-r--r--platform/android/export/export.cpp218
-rw-r--r--platform/android/globals/global_defaults.cpp8
-rw-r--r--platform/android/godot_android.cpp28
-rw-r--r--platform/android/java/gradlew.bat180
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java31
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotLib.java1
-rw-r--r--platform/android/java_class_wrapper.cpp2
-rw-r--r--platform/android/java_glue.cpp16
-rw-r--r--platform/android/java_glue.h1
-rw-r--r--platform/android/os_android.cpp59
-rw-r--r--platform/android/os_android.h17
-rw-r--r--platform/android/platform_config.h1
-rw-r--r--platform/haiku/SCsub2
-rw-r--r--platform/haiku/detect.py2
-rw-r--r--platform/haiku/os_haiku.cpp56
-rw-r--r--platform/haiku/os_haiku.h9
-rw-r--r--platform/iphone/SCsub12
-rw-r--r--platform/iphone/app_delegate.mm3
-rw-r--r--platform/iphone/detect.py42
-rw-r--r--platform/iphone/export/export.cpp459
-rw-r--r--platform/iphone/game_center.mm14
-rw-r--r--platform/iphone/globals/global_defaults.cpp7
-rw-r--r--platform/iphone/in_app_store.mm3
-rw-r--r--platform/iphone/os_iphone.cpp114
-rw-r--r--platform/iphone/os_iphone.h17
-rw-r--r--platform/iphone/platform_config.h2
-rw-r--r--platform/javascript/SCsub34
-rw-r--r--platform/javascript/api/api.cpp73
-rw-r--r--platform/javascript/api/api.h31
-rw-r--r--platform/javascript/api/javascript_eval.h (renamed from platform/javascript/javascript_eval.h)3
-rw-r--r--platform/javascript/audio_driver_javascript.cpp44
-rw-r--r--platform/javascript/audio_driver_javascript.h5
-rw-r--r--platform/javascript/audio_server_javascript.cpp853
-rw-r--r--platform/javascript/audio_server_javascript.h229
-rw-r--r--platform/javascript/detect.py18
-rw-r--r--platform/javascript/engine.js219
-rw-r--r--platform/javascript/export/export.cpp136
-rw-r--r--platform/javascript/http_client.h.inc48
-rw-r--r--platform/javascript/http_client_javascript.cpp282
-rw-r--r--platform/javascript/http_request.h74
-rw-r--r--platform/javascript/http_request.js145
-rw-r--r--platform/javascript/javascript_eval.cpp71
-rw-r--r--platform/javascript/javascript_main.cpp1
-rw-r--r--platform/javascript/os_javascript.cpp73
-rw-r--r--platform/javascript/os_javascript.h21
-rw-r--r--platform/javascript/pre.js (renamed from platform/javascript/pre_wasm.js)1
-rw-r--r--platform/javascript/pre_asmjs.js3
-rw-r--r--platform/osx/SCsub5
-rw-r--r--platform/osx/crash_handler_osx.mm1
-rw-r--r--platform/osx/detect.py13
-rw-r--r--platform/osx/export/export.cpp9
-rw-r--r--platform/osx/os_osx.h20
-rw-r--r--platform/osx/os_osx.mm233
-rw-r--r--platform/register_platform_apis.h36
-rw-r--r--platform/server/SCsub2
-rw-r--r--platform/server/os_server.cpp18
-rw-r--r--platform/server/os_server.h7
-rw-r--r--platform/uwp/SCsub2
-rw-r--r--platform/uwp/app.h1
-rw-r--r--platform/uwp/detect.py4
-rw-r--r--platform/uwp/export/export.cpp30
-rw-r--r--platform/uwp/gl_context_egl.cpp39
-rw-r--r--platform/uwp/logo.pngbin1882 -> 1519 bytes
-rw-r--r--platform/uwp/os_uwp.cpp38
-rw-r--r--platform/uwp/os_uwp.h9
-rw-r--r--platform/windows/SCsub4
-rw-r--r--platform/windows/context_gl_win.cpp19
-rw-r--r--platform/windows/context_gl_win.h13
-rw-r--r--platform/windows/crash_handler_win.cpp1
-rw-r--r--platform/windows/godot_res.rc8
-rw-r--r--platform/windows/os_windows.cpp148
-rw-r--r--platform/windows/os_windows.h20
-rw-r--r--platform/windows/stream_peer_winsock.cpp4
-rw-r--r--platform/x11/SCsub5
-rw-r--r--platform/x11/crash_handler_x11.cpp1
-rw-r--r--platform/x11/detect.py2
-rw-r--r--platform/x11/os_x11.cpp136
-rw-r--r--platform/x11/os_x11.h13
82 files changed, 2345 insertions, 2249 deletions
diff --git a/platform/SCsub b/platform/SCsub
new file mode 100644
index 0000000000..e624f8e90f
--- /dev/null
+++ b/platform/SCsub
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+from compat import open_utf8
+
+Import('env')
+platform_sources = []
+
+# Register platform-exclusive APIs
+reg_apis_inc = '#include "register_platform_apis.h"\n'
+reg_apis = 'void register_platform_apis() {\n'
+unreg_apis = 'void unregister_platform_apis() {\n'
+for platform in env.platform_apis:
+ platform_dir = env.Dir(platform)
+ platform_sources.append(platform_dir.File('api/api.cpp'))
+ reg_apis += '\tregister_' + platform + '_api();\n'
+ unreg_apis += '\tunregister_' + platform + '_api();\n'
+ reg_apis_inc += '#include "' + platform + '/api/api.h"\n'
+reg_apis_inc += '\n'
+reg_apis += '}\n\n'
+unreg_apis += '}\n'
+f = open_utf8('register_platform_apis.gen.cpp', 'w')
+f.write(reg_apis_inc)
+f.write(reg_apis)
+f.write(unreg_apis)
+f.close()
+platform_sources.append('register_platform_apis.gen.cpp')
+
+lib = env.add_library('platform', platform_sources)
+env.Prepend(LIBS=lib)
+
+Export('env')
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 7fa0262359..0cd91276ef 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -144,8 +144,7 @@ manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$", env.android_appattrib
pp_baseout.write(manifest)
-env_android.SharedLibrary("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
-
+lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
lib_arch_dir = ''
if env['android_arch'] == 'armv6':
diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template
index 7cb6cf860a..4a44d1c5f9 100644
--- a/platform/android/build.gradle.template
+++ b/platform/android/build.gradle.template
@@ -31,7 +31,7 @@ android {
disable 'MissingTranslation'
}
- compileSdkVersion 23
+ compileSdkVersion 26
buildToolsVersion "26.0.1"
useLibrary 'org.apache.http.legacy'
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 13fc4ee810..bc67f6e6dc 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -2,6 +2,7 @@ import os
import sys
import string
import platform
+from distutils.version import LooseVersion
def is_active():
@@ -25,7 +26,7 @@ def get_opts():
('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"),
EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'armv6', 'arm64v8', 'x86')),
BoolVariable('android_neon', 'Enable NEON support (armv7 only)', True),
- BoolVariable('android_stl', 'Enable Android STL support (for modules)', False),
+ BoolVariable('android_stl', 'Enable Android STL support (for modules)', True)
]
@@ -172,20 +173,39 @@ def configure(env):
# For Clang to find NDK tools in preference of those system-wide
env.PrependENVPath('PATH', tools_path)
- env['CC'] = compiler_path + '/clang'
- env['CXX'] = compiler_path + '/clang++'
+ ccache_path = os.environ.get("CCACHE")
+ if ccache_path == None:
+ env['CC'] = compiler_path + '/clang'
+ env['CXX'] = compiler_path + '/clang++'
+ else:
+ # there aren't any ccache wrappers available for Android,
+ # to enable caching we need to prepend the path to the ccache binary
+ env['CC'] = ccache_path + ' ' + compiler_path + '/clang'
+ env['CXX'] = ccache_path + ' ' + compiler_path + '/clang++'
env['AR'] = tools_path + "/ar"
env['RANLIB'] = tools_path + "/ranlib"
env['AS'] = tools_path + "/as"
- sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path]
+ lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
+
## Compile flags
- env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
+ ndk_version = get_ndk_version(env["ANDROID_NDK_ROOT"])
+ if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("15.0.4075724"):
+ print("Using NDK unified headers")
+ sysroot = env["ANDROID_NDK_ROOT"] + "/sysroot"
+ env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
+ env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath])
+ # For unified headers this define has to be set manually
+ env.Append(CPPFLAGS=["-D__ANDROID_API__=" + str(int(env['ndk_platform'].split("-")[1]))])
+ else:
+ print("Using NDK deprecated headers")
+ env.Append(CPPFLAGS=["-isystem", lib_sysroot + "/usr/include"])
+
env.Append(CPPFLAGS='-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'.split())
- env.Append(CPPFLAGS='-DNO_STATVFS -DGLES2_ENABLED'.split())
+ env.Append(CPPFLAGS='-DNO_STATVFS -DGLES_ENABLED'.split())
env['neon_enabled'] = False
if env['android_arch'] == 'x86':
@@ -224,7 +244,7 @@ def configure(env):
## Link flags
- env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel']
+ env['LINKFLAGS'] = ['-shared', '--sysroot=' + lib_sysroot, '-Wl,--warn-shared-textrel']
if env["android_arch"] == "armv7":
env.Append(LINKFLAGS='-Wl,--fix-cortex-a8'.split())
env.Append(LINKFLAGS='-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'.split())
@@ -248,3 +268,18 @@ def configure(env):
if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"):
env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
env.opus_fixed_point = "yes"
+
+# Return NDK version string in source.properties (adapted from the Chromium project).
+def get_ndk_version(path):
+ if path == None:
+ return None
+ prop_file_path = os.path.join(path, "source.properties")
+ try:
+ with open(prop_file_path) as prop_file:
+ for line in prop_file:
+ key_value = map(lambda x: string.strip(x), line.split("="))
+ if key_value[0] == "Pkg.Revision":
+ return key_value[1]
+ except:
+ print("Could not read source prop file '%s'" % prop_file_path)
+ return None
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 79be1501a7..67e00f4952 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -192,6 +192,19 @@ static const char *android_perms[] = {
NULL
};
+struct LauncherIcon {
+ char *option_id;
+ char *export_path;
+};
+
+static const LauncherIcon launcher_icons[] = {
+ { "launcher_icons/xxxhdpi_192x192", "res/drawable-xxxhdpi-v4/icon.png" },
+ { "launcher_icons/xxhdpi_144x144", "res/drawable-xxhdpi-v4/icon.png" },
+ { "launcher_icons/xhdpi_96x96", "res/drawable-xhdpi-v4/icon.png" },
+ { "launcher_icons/hdpi_72x72", "res/drawable-hdpi-v4/icon.png" },
+ { "launcher_icons/mdpi_48x48", "res/drawable-mdpi-v4/icon.png" }
+};
+
class EditorExportAndroid : public EditorExportPlatform {
GDCLASS(EditorExportAndroid, EditorExportPlatform)
@@ -370,7 +383,7 @@ class EditorExportAndroid : public EditorExportPlatform {
}
if (aname == "") {
- aname = _MKSTR(VERSION_NAME);
+ aname = VERSION_NAME;
}
return aname;
@@ -467,52 +480,72 @@ class EditorExportAndroid : public EditorExportPlatform {
return zipfi;
}
- static Set<String> get_abis() {
- Set<String> abis;
- abis.insert("armeabi");
- abis.insert("armeabi-v7a");
- abis.insert("arm64-v8a");
- abis.insert("x86");
- abis.insert("x86_64");
- abis.insert("mips");
- abis.insert("mips64");
+ static Vector<String> get_abis() {
+ // mips and armv6 are dead (especially for games), so not including them
+ Vector<String> abis;
+ abis.push_back("armeabi-v7a");
+ abis.push_back("arm64-v8a");
+ abis.push_back("x86");
+ abis.push_back("x86_64");
return abis;
}
- static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
- APKExportData *ed = (APKExportData *)p_userdata;
- String dst_path = p_path;
- static Set<String> android_abis = get_abis();
-
- if (dst_path.ends_with(".so")) {
- String abi = dst_path.get_base_dir().get_file().strip_edges(); // parent dir name
- if (android_abis.has(abi)) {
- dst_path = "lib/" + abi + "/" + dst_path.get_file();
- } else {
- String err = "Dynamic libraries must be located in the folder named after Android ABI they were compiled for. " +
- p_path + " does not follow this convention.";
- ERR_PRINT(err.utf8().get_data());
- return ERR_FILE_BAD_PATH;
- }
- } else {
- dst_path = dst_path.replace_first("res://", "assets/");
- }
-
+ static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED) {
zip_fileinfo zipfi = get_zip_fileinfo();
-
zipOpenNewFileInZip(ed->apk,
- dst_path.utf8().get_data(),
+ p_path.utf8().get_data(),
&zipfi,
NULL,
0,
NULL,
0,
NULL,
- _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0,
+ compression_method,
Z_DEFAULT_COMPRESSION);
zipWriteInFileInZip(ed->apk, p_data.ptr(), p_data.size());
zipCloseFileInZip(ed->apk);
+
+ return OK;
+ }
+
+ static Error save_apk_so(void *p_userdata, const SharedObject &p_so) {
+ if (!p_so.path.get_file().begins_with("lib")) {
+ String err = "Android .so file names must start with \"lib\", but got: " + p_so.path;
+ ERR_PRINT(err.utf8().get_data());
+ return FAILED;
+ }
+ APKExportData *ed = (APKExportData *)p_userdata;
+ Vector<String> abis = get_abis();
+ bool exported = false;
+ for (int i = 0; i < p_so.tags.size(); ++i) {
+ // shared objects can be fat (compatible with multiple ABIs)
+ int start_pos = 0;
+ int abi_index = abis.find(p_so.tags[i]);
+ if (abi_index != -1) {
+ exported = true;
+ start_pos = abi_index + 1;
+ String abi = abis[abi_index];
+ String dst_path = "lib/" + abi + "/" + p_so.path.get_file();
+ Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
+ Error store_err = store_in_apk(ed, dst_path, array);
+ ERR_FAIL_COND_V(store_err, store_err);
+ }
+ }
+ if (!exported) {
+ String abis_string = String(" ").join(abis);
+ String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string;
+ ERR_PRINT(err.utf8().get_data());
+ return FAILED;
+ }
+ return OK;
+ }
+
+ static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
+ APKExportData *ed = (APKExportData *)p_userdata;
+ String dst_path = p_path.replace_first("res://", "assets/");
+
+ store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0);
ed->ep->step("File: " + p_path, 3 + p_file * 100 / p_total);
return OK;
}
@@ -935,6 +968,18 @@ class EditorExportAndroid : public EditorExportPlatform {
//printf("end\n");
}
+ static Vector<String> get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
+ Vector<String> abis = get_abis();
+ Vector<String> enabled_abis;
+ for (int i = 0; i < abis.size(); ++i) {
+ bool is_enabled = p_preset->get("architectures/" + abis[i]);
+ if (is_enabled) {
+ enabled_abis.push_back(abis[i]);
+ }
+ }
+ return enabled_abis;
+ }
+
public:
enum {
MAX_USER_PERMISSIONS = 20
@@ -945,16 +990,22 @@ public:
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- int api = p_preset->get("graphics/api");
+ // Reenable when a GLES 2.0 backend is readded
+ /*int api = p_preset->get("graphics/api");
if (api == 0)
r_features->push_back("etc");
- else
- r_features->push_back("etc2");
+ else*/
+ r_features->push_back("etc2");
+
+ Vector<String> abis = get_enabled_abis(p_preset);
+ for (int i = 0; i < abis.size(); ++i) {
+ r_features->push_back(abis[i]);
+ }
}
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::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"), ""));
@@ -964,16 +1015,18 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name"), "org.godotengine.$genname"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/icon", PROPERTY_HINT_FILE, "png"), ""));
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/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));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true));
+
+ for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icons[i].option_id, PROPERTY_HINT_FILE, "png"), ""));
+ }
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "keystore"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), ""));
@@ -981,6 +1034,13 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ Vector<String> abis = get_abis();
+ for (int i = 0; i < abis.size(); ++i) {
+ String abi = abis[i];
+ bool is_default = (abi == "armeabi-v7a");
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
+ }
+
const char **perms = android_perms;
while (*perms) {
@@ -1066,7 +1126,7 @@ public:
if (use_reverse)
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
- String export_to = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpexport.apk";
+ String export_to = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.apk");
Error err = export_project(p_preset, true, export_to, p_debug_flags);
if (err) {
device_lock->unlock();
@@ -1291,13 +1351,9 @@ public:
zlib_filefunc_def io2 = io;
FileAccess *dst_f = NULL;
io2.opaque = &dst_f;
- String unaligned_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpexport-unaligned.apk";
+ String unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk");
zipFile unaligned_apk = zipOpen2(unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
- bool export_x86 = p_preset->get("architecture/x86");
- bool export_arm = p_preset->get("architecture/arm");
- bool export_arm64 = p_preset->get("architecture/arm64");
-
bool use_32_fb = p_preset->get("graphics/32_bits_framebuffer");
bool immersive = p_preset->get("screen/immersive_mode");
@@ -1317,6 +1373,8 @@ public:
String release_username = p_preset->get("keystore/release_user");
String release_password = p_preset->get("keystore/release_password");
+ Vector<String> enabled_abis = get_enabled_abis(p_preset);
+
while (ret == UNZ_OK) {
//get filename
@@ -1333,7 +1391,7 @@ public:
//read
unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptr(), data.size());
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
//write
@@ -1349,23 +1407,20 @@ public:
}
if (file == "res/drawable/icon.png") {
-
- String icon = p_preset->get("package/icon");
- icon = icon.strip_edges();
bool found = false;
-
- if (icon != "" && icon.ends_with(".png")) {
-
- FileAccess *f = FileAccess::open(icon, FileAccess::READ);
- if (f) {
-
- data.resize(f->get_len());
- f->get_buffer(data.ptr(), data.size());
- memdelete(f);
- found = true;
+ for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) {
+ String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges();
+ if (icon_path != "" && icon_path.ends_with(".png")) {
+ FileAccess *f = FileAccess::open(icon_path, FileAccess::READ);
+ if (f) {
+ data.resize(f->get_len());
+ f->get_buffer(data.ptrw(), data.size());
+ memdelete(f);
+ found = true;
+ break;
+ }
}
}
-
if (!found) {
String appicon = ProjectSettings::get_singleton()->get("application/config/icon");
@@ -1373,32 +1428,32 @@ public:
FileAccess *f = FileAccess::open(appicon, FileAccess::READ);
if (f) {
data.resize(f->get_len());
- f->get_buffer(data.ptr(), data.size());
+ f->get_buffer(data.ptrw(), data.size());
memdelete(f);
}
}
}
}
- if (file == "lib/x86/*.so" && !export_x86) {
- skip = true;
- }
-
- if (file.match("lib/armeabi*/*.so") && !export_arm) {
- skip = true;
- }
-
- if (file.match("lib/arm64*/*.so") && !export_arm64) {
- skip = true;
+ if (file.ends_with(".so")) {
+ bool enabled = false;
+ for (int i = 0; i < enabled_abis.size(); ++i) {
+ if (file.begins_with("lib/" + enabled_abis[i] + "/")) {
+ enabled = true;
+ break;
+ }
+ }
+ if (!enabled) {
+ skip = true;
+ }
}
if (file.begins_with("META-INF") && _signed) {
skip = true;
}
- print_line("ADDING: " + file);
-
if (!skip) {
+ print_line("ADDING: " + file);
// Respect decision on compression made by AAPT for the export template
const bool uncompressed = info.compression_method == 0;
@@ -1472,7 +1527,20 @@ public:
ed.ep = &ep;
ed.apk = unaligned_apk;
- err = export_project_files(p_preset, save_apk_file, &ed);
+ err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
+ }
+
+ if (!err) {
+ APKExportData ed;
+ ed.ep = &ep;
+ ed.apk = unaligned_apk;
+ for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) {
+ String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges();
+ if (icon_path != "" && icon_path.ends_with(".png") && FileAccess::exists(icon_path)) {
+ Vector<uint8_t> data = FileAccess::get_file_as_array(icon_path);
+ store_in_apk(&ed, launcher_icons[i].export_path, data);
+ }
+ }
}
}
@@ -1635,7 +1703,7 @@ public:
int method, level;
unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read
long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned);
- unzReadCurrentFile(tmp_unaligned, data.ptr(), data.size());
+ unzReadCurrentFile(tmp_unaligned, data.ptrw(), data.size());
unzCloseCurrentFile(tmp_unaligned);
// align
diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp
index c73b578154..0e1c17e9c8 100644
--- a/platform/android/globals/global_defaults.cpp
+++ b/platform/android/globals/global_defaults.cpp
@@ -31,12 +31,4 @@
#include "project_settings.h"
void register_android_global_defaults() {
-
- /* GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false);
- GLOBAL_DEF("rasterizer.Android/fp16_framebuffer",false);
- GLOBAL_DEF("display.Android/driver","GLES2");
- //GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false);
-
- 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 8235683496..f9bcbadc24 100644
--- a/platform/android/godot_android.cpp
+++ b/platform/android/godot_android.cpp
@@ -29,23 +29,23 @@
/*************************************************************************/
#ifdef ANDROID_NATIVE_ACTIVITY
-#include <errno.h>
-#include <jni.h>
-
-#include <EGL/egl.h>
-#include <GLES2/gl2.h>
-
+#include "engine.h"
#include "file_access_android.h"
#include "main/main.h"
#include "os_android.h"
#include "project_settings.h"
+
+#include <EGL/egl.h>
#include <android/log.h>
#include <android/sensor.h>
#include <android/window.h>
#include <android_native_app_glue.h>
+#include <errno.h>
+#include <jni.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__))
@@ -669,6 +669,14 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
ASensorEventQueue_setEventRate(engine->sensorEventQueue,
engine->accelerometerSensor, (1000L / 60) * 1000);
}
+ // start monitoring gravity
+ if (engine->gravitySensor != NULL) {
+ ASensorEventQueue_enableSensor(engine->sensorEventQueue,
+ engine->gravitySensor);
+ // We'd like to get 60 events per second (in us).
+ ASensorEventQueue_setEventRate(engine->sensorEventQueue,
+ engine->gravitySensor, (1000L / 60) * 1000);
+ }
// Also start monitoring the magnetometer.
if (engine->magnetometerSensor != NULL) {
ASensorEventQueue_enableSensor(engine->sensorEventQueue,
@@ -694,6 +702,10 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
ASensorEventQueue_disableSensor(engine->sensorEventQueue,
engine->accelerometerSensor);
}
+ if (engine->gravitySensor != NULL) {
+ ASensorEventQueue_disableSensor(engine->sensorEventQueue,
+ engine->gravitySensor);
+ }
if (engine->magnetometerSensor != NULL) {
ASensorEventQueue_disableSensor(engine->sensorEventQueue,
engine->magnetometerSensor);
@@ -729,6 +741,8 @@ void android_main(struct android_app *app) {
engine.sensorManager = ASensorManager_getInstance();
engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
ASENSOR_TYPE_ACCELEROMETER);
+ engine.gravitySensor = ASensorManager_getDefaultSensor(engine.sensorManager,
+ ASENSOR_TYPE_GRAVITY);
engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
ASENSOR_TYPE_MAGNETIC_FIELD);
engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
@@ -828,7 +842,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv
s->set_instance(env->NewGlobalRef(p_object));
jni_singletons[singname] = s;
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton(singname, s));
+ Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
}
static Variant::Type get_jni_type(const String &p_type) {
diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat
index aec99730b4..8a0b282aa6 100644
--- a/platform/android/java/gradlew.bat
+++ b/platform/android/java/gradlew.bat
@@ -1,90 +1,90 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index 59fefc498f..4daf06142d 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -219,6 +219,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
private SensorManager mSensorManager;
private Sensor mAccelerometer;
+ private Sensor mGravity;
private Sensor mMagnetometer;
private Sensor mGyroscope;
@@ -435,6 +436,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+ mGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
+ mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
@@ -667,6 +670,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
});
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+ mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
@@ -734,13 +738,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
@Override
public void run() {
if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) {
- GodotLib.accelerometer(x,y,z);
+ GodotLib.accelerometer(-x,y,-z);
+ }
+ if (typeOfSensor == Sensor.TYPE_GRAVITY) {
+ GodotLib.gravity(-x,y,-z);
}
if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) {
- GodotLib.magnetometer(x,y,z);
+ GodotLib.magnetometer(-x,y,-z);
}
if (typeOfSensor == Sensor.TYPE_GYROSCOPE) {
- GodotLib.gyroscope(x,y,z);
+ GodotLib.gyroscope(x,-y,z);
}
}
});
@@ -963,7 +970,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
boolean indeterminate;
switch (newState) {
case IDownloaderClient.STATE_IDLE:
- Log.d("GODOT", "STATE IDLE");
+ Log.d("GODOT", "DOWNLOAD STATE IDLE");
// STATE_IDLE means the service is listening, so it's
// safe to start making calls via mRemoteService.
paused = false;
@@ -971,13 +978,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
break;
case IDownloaderClient.STATE_CONNECTING:
case IDownloaderClient.STATE_FETCHING_URL:
- Log.d("GODOT", "STATE CONNECTION / FETCHING URL");
+ Log.d("GODOT", "DOWNLOAD STATE CONNECTION / FETCHING URL");
showDashboard = true;
paused = false;
indeterminate = true;
break;
case IDownloaderClient.STATE_DOWNLOADING:
- Log.d("GODOT", "STATE DOWNLOADING");
+ Log.d("GODOT", "DOWNLOAD STATE DOWNLOADING");
paused = false;
showDashboard = true;
indeterminate = false;
@@ -987,14 +994,14 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
case IDownloaderClient.STATE_FAILED:
case IDownloaderClient.STATE_FAILED_FETCHING_URL:
case IDownloaderClient.STATE_FAILED_UNLICENSED:
- Log.d("GODOT", "MANY TYPES OF FAILING");
+ Log.d("GODOT", "DOWNLOAD STATE: FAILED, CANCELLED, UNLICENSED OR FAILED TO FETCH URL");
paused = true;
showDashboard = false;
indeterminate = false;
break;
case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
- Log.d("GODOT", "PAUSED FOR SOME STUPID REASON");
+ Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY MISSING CELLULAR PERMISSION");
showDashboard = false;
paused = true;
indeterminate = false;
@@ -1002,18 +1009,18 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
break;
case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- Log.d("GODOT", "PAUSED BY STUPID USER");
+ Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY USER");
paused = true;
indeterminate = false;
break;
case IDownloaderClient.STATE_PAUSED_ROAMING:
case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
- Log.d("GODOT", "PAUSED BY ROAMING WTF!?");
+ Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY ROAMING OR SDCARD UNAVAILABLE");
paused = true;
indeterminate = false;
break;
case IDownloaderClient.STATE_COMPLETED:
- Log.d("GODOT", "COMPLETED");
+ Log.d("GODOT", "DOWNLOAD STATE: COMPLETED");
showDashboard = false;
paused = false;
indeterminate = false;
@@ -1021,7 +1028,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
initializeGodot();
return;
default:
- Log.d("GODOT", "DEFAULT ????");
+ Log.d("GODOT", "DOWNLOAD STATE: DEFAULT");
paused = true;
indeterminate = true;
showDashboard = true;
diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java
index e0ed4cd38c..6b84ad6555 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java
@@ -53,6 +53,7 @@ public class GodotLib {
public static native void step();
public static native void touch(int what,int pointer,int howmany, int[] arr);
public static native void accelerometer(float x, float y, float z);
+ public static native void gravity(float x, float y, float z);
public static native void magnetometer(float x, float y, float z);
public static native void gyroscope(float x, float y, float z);
public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed);
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index 8606ea41a0..892e64cdfc 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -59,7 +59,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
r_error.argument = pc;
continue;
}
- uint32_t *ptypes = E->get().param_types.ptr();
+ uint32_t *ptypes = E->get().param_types.ptrw();
bool valid = true;
for (int i = 0; i < pc; i++) {
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 0b193f5882..40dfe6d909 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -34,6 +34,7 @@
#include "audio_driver_jandroid.h"
#include "core/os/keyboard.h"
#include "dir_access_jandroid.h"
+#include "engine.h"
#include "file_access_android.h"
#include "file_access_jandroid.h"
#include "java_class_wrapper.h"
@@ -608,6 +609,7 @@ static bool resized = false;
static bool resized_reload = false;
static Size2 new_size;
static Vector3 accelerometer;
+static Vector3 gravity;
static Vector3 magnetometer;
static Vector3 gyroscope;
static HashMap<String, JNISingleton *> jni_singletons;
@@ -645,7 +647,7 @@ static int _open_uri(const String &p_uri) {
return env->CallIntMethod(godot_io, _openURI, jStr);
}
-static String _get_data_dir() {
+static String _get_user_data_dir() {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(godot_io, _getDataDir);
@@ -823,7 +825,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
AudioDriverAndroid::setup(gob);
}
- os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion);
+ os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_user_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion);
os_android->set_need_reload_hooks(p_need_reload_hook);
char wd[500];
@@ -952,7 +954,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
__android_log_print(ANDROID_LOG_INFO, "godot", "*****SETUP OK");
java_class_wrapper = memnew(JavaClassWrapper(_godot_instance));
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("JavaClassWrapper", java_class_wrapper));
_initialize_java_modules();
}
@@ -1012,6 +1014,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
os_android->process_accelerometer(accelerometer);
+ os_android->process_gravity(gravity);
+
os_android->process_magnetometer(magnetometer);
os_android->process_gyroscope(gyroscope);
@@ -1386,6 +1390,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv
accelerometer = Vector3(x, y, z);
}
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
+ gravity = Vector3(x, y, z);
+}
+
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
magnetometer = Vector3(x, y, z);
}
@@ -1419,7 +1427,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env
s->set_instance(env->NewGlobalRef(p_object));
jni_singletons[singname] = s;
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton(singname, s));
+ Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
ProjectSettings::get_singleton()->set(singname, s);
}
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
index 0aa2489813..4790c65617 100644
--- a/platform/android/java_glue.h
+++ b/platform/android/java_glue.h
@@ -50,6 +50,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jobject obj);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 45df312cae..b575f15559 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -65,12 +65,6 @@ const char *OS_Android::get_video_driver_name(int p_driver) const {
return "GLES2";
}
-
-OS::VideoMode OS_Android::get_default_video_mode() const {
-
- return OS::VideoMode();
-}
-
int OS_Android::get_audio_driver_count() const {
return 1;
@@ -120,15 +114,6 @@ void OS_Android::initialize_core() {
#endif
}
-void OS_Android::initialize_logger() {
- Vector<Logger *> loggers;
- loggers.push_back(memnew(AndroidLogger));
- // FIXME: Reenable once we figure out how to get this properly in user://
- // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277)
- //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt")));
- _set_logger(memnew(CompositeLogger(loggers)));
-}
-
void OS_Android::set_opengl_extensions(const char *p_gl_extensions) {
ERR_FAIL_COND(!p_gl_extensions);
@@ -157,11 +142,6 @@ void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
AudioDriverManager::initialize(p_audio_driver);
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
- physics_2d_server->init();
-
input = memnew(InputDefault);
input->set_fallback_mapping("Default Android Gamepad");
@@ -501,6 +481,11 @@ void OS_Android::process_accelerometer(const Vector3 &p_accelerometer) {
input->set_accelerometer(p_accelerometer);
}
+void OS_Android::process_gravity(const Vector3 &p_gravity) {
+
+ input->set_gravity(p_gravity);
+}
+
void OS_Android::process_magnetometer(const Vector3 &p_magnetometer) {
input->set_magnetometer(p_magnetometer);
@@ -618,13 +603,13 @@ void OS_Android::set_need_reload_hooks(bool p_needs_them) {
use_reload_hooks = p_needs_them;
}
-String OS_Android::get_data_dir() const {
+String OS_Android::get_user_data_dir() const {
if (data_dir_cache != String())
return data_dir_cache;
- if (get_data_dir_func) {
- String data_dir = get_data_dir_func();
+ if (get_user_data_dir_func) {
+ String data_dir = get_user_data_dir_func();
//store current dir
char real_current_dir_name[2048];
@@ -647,7 +632,6 @@ String OS_Android::get_data_dir() const {
}
return ".";
- //return ProjectSettings::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
}
void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
@@ -712,10 +696,27 @@ String OS_Android::get_joy_guid(int p_device) const {
}
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
+ if (p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2") {
+ //TODO support etc2 only if GLES3 driver is selected
+ return true;
+ }
+#if defined(__aarch64__)
+ if (p_feature == "arm64-v8a") {
+ return true;
+ }
+#elif defined(__ARM_ARCH_7A__)
+ if (p_feature == "armeabi-v7a" || p_feature == "armeabi") {
+ return true;
+ }
+#elif defined(__arm__)
+ if (p_feature == "armeabi") {
+ return true;
+ }
+#endif
+ return false;
}
-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, VirtualKeyboardHeightFunc p_vk_height_func, 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::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_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, VirtualKeyboardHeightFunc p_vk_height_func, 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;
default_videomode.width = 800;
@@ -731,7 +732,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI
use_gl2 = false;
open_uri_func = p_open_uri_func;
- get_data_dir_func = p_get_data_dir_func;
+ get_user_data_dir_func = p_get_user_data_dir_func;
get_locale_func = p_get_locale_func;
get_model_func = p_get_model_func;
get_screen_dpi_func = p_get_screen_dpi_func;
@@ -752,7 +753,9 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI
alert_func = p_alert_func;
use_reload_hooks = false;
- _set_logger(memnew(AndroidLogger));
+ Vector<Logger *> loggers;
+ loggers.push_back(memnew(AndroidLogger));
+ _set_logger(memnew(CompositeLogger(loggers)));
}
OS_Android::~OS_Android() {
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 0c78c198a8..3b7f55096e 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -38,9 +38,6 @@
#include "os/main_loop.h"
//#include "power_android.h"
#include "servers/audio_server.h"
-#include "servers/physics/physics_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "servers/visual/rasterizer.h"
#ifdef ANDROID_NATIVE_ACTIVITY
@@ -51,7 +48,7 @@
typedef void (*GFXInitFunc)(void *ud, bool gl2);
typedef int (*OpenURIFunc)(const String &);
-typedef String (*GetDataDirFunc)();
+typedef String (*GetUserDataDirFunc)();
typedef String (*GetLocaleFunc)();
typedef String (*GetModelFunc)();
typedef int (*GetScreenDPIFunc)();
@@ -106,8 +103,6 @@ private:
bool use_16bits_fbo;
VisualServer *visual_server;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
mutable String data_dir_cache;
@@ -121,7 +116,7 @@ private:
MainLoop *main_loop;
OpenURIFunc open_uri_func;
- GetDataDirFunc get_data_dir_func;
+ GetUserDataDirFunc get_user_data_dir_func;
GetLocaleFunc get_locale_func;
GetModelFunc get_model_func;
GetScreenDPIFunc get_screen_dpi_func;
@@ -146,12 +141,9 @@ public:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
- virtual void initialize_logger();
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
@@ -215,7 +207,7 @@ public:
virtual void set_screen_orientation(ScreenOrientation p_orientation);
virtual Error shell_open(String p_uri);
- virtual String get_data_dir() const;
+ virtual String get_user_data_dir() const;
virtual String get_resource_dir() const;
virtual String get_locale() const;
virtual String get_model_name() const;
@@ -226,6 +218,7 @@ public:
virtual String get_system_dir(SystemDir p_dir) const;
void process_accelerometer(const Vector3 &p_accelerometer);
+ void process_gravity(const Vector3 &p_gravity);
void process_magnetometer(const Vector3 &p_magnetometer);
void process_gyroscope(const Vector3 &p_gyroscope);
void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points);
@@ -243,7 +236,7 @@ public:
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, VirtualKeyboardHeightFunc p_vk_height_func, 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(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_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, VirtualKeyboardHeightFunc p_vk_height_func, 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/android/platform_config.h b/platform/android/platform_config.h
index b1c3f027f3..b1f51c9256 100644
--- a/platform/android/platform_config.h
+++ b/platform/android/platform_config.h
@@ -28,3 +28,4 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <alloca.h>
+#include <malloc.h>
diff --git a/platform/haiku/SCsub b/platform/haiku/SCsub
index d0c244a194..592f56bbbf 100644
--- a/platform/haiku/SCsub
+++ b/platform/haiku/SCsub
@@ -12,7 +12,7 @@ common_haiku = [
'audio_driver_media_kit.cpp'
]
-target = env.Program(
+target = env.add_program(
'#bin/godot',
['godot_haiku.cpp'] + common_haiku
)
diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py
index 50f9783dd2..7c62654ef6 100644
--- a/platform/haiku/detect.py
+++ b/platform/haiku/detect.py
@@ -67,7 +67,7 @@ def configure(env):
## Flags
env.Append(CPPPATH=['#platform/haiku'])
- env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
+ env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES_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
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index 1d52752f21..ef5a065107 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -76,11 +76,7 @@ int OS_Haiku::get_video_driver_count() const {
}
const char *OS_Haiku::get_video_driver_name(int p_driver) const {
- return "GLES2";
-}
-
-OS::VideoMode OS_Haiku::get_default_video_mode() const {
- return OS::VideoMode(800, 600, false);
+ return "GLES3";
}
void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
@@ -110,7 +106,9 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_
context_gl->initialize();
context_gl->make_current();
- rasterizer = memnew(RasterizerGLES2);
+ /* Port to GLES 3 rasterizer */
+ //rasterizer = memnew(RasterizerGLES2);
+
#endif
visual_server = memnew(VisualServerRaster(rasterizer));
@@ -130,13 +128,6 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_
window->Show();
visual_server->init();
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- physics_2d_server = memnew(Physics2DServerSW);
- // TODO: enable multithreaded PS
- //physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
- physics_2d_server->init();
-
AudioDriverManager::initialize(p_audio_driver);
power_manager = memnew(PowerHaiku);
@@ -153,12 +144,6 @@ void OS_Haiku::finalize() {
memdelete(visual_server);
memdelete(rasterizer);
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
-
memdelete(input);
#if defined(OPENGL_ENABLED)
@@ -331,3 +316,36 @@ bool OS_Haiku::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
+
+String OS_Haiku::get_config_path() const {
+
+ if (has_environment("XDG_CONFIG_HOME")) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".config");
+ } else {
+ return ".";
+ }
+}
+
+String OS_Haiku::get_data_path() const {
+
+ if (has_environment("XDG_DATA_HOME")) {
+ return get_environment("XDG_DATA_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".local/share");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_Haiku::get_cache_path() const {
+
+ if (has_environment("XDG_CACHE_HOME")) {
+ return get_environment("XDG_CACHE_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".cache");
+ } else {
+ return get_config_path();
+ }
+}
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index d929f7e43b..4ee54fb48d 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -38,8 +38,6 @@
#include "main/input_default.h"
#include "power_haiku.h"
#include "servers/audio_server.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_server.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
@@ -52,8 +50,6 @@ private:
Rasterizer *rasterizer;
VisualServer *visual_server;
VideoMode current_video_mode;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
PowerHaiku *power_manager;
#ifdef MEDIA_KIT_ENABLED
@@ -69,7 +65,6 @@ private:
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
@@ -122,6 +117,10 @@ public:
virtual int get_power_percent_left();
virtual bool _check_internal_feature_support(const String &p_feature);
+
+ virtual String get_config_path() const;
+ virtual String get_data_path() const;
+ virtual String get_cache_path() const;
};
#endif
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index 61798c5f87..6b5f30dc41 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -3,7 +3,7 @@
Import('env')
iphone_lib = [
-
+ 'godot_iphone.cpp',
'os_iphone.cpp',
'sem_iphone.cpp',
'gl_view.mm',
@@ -17,10 +17,10 @@ iphone_lib = [
]
env_ios = env.Clone()
+ios_lib = env_ios.add_library('iphone', iphone_lib)
-obj = env_ios.Object('godot_iphone.cpp')
+def combine_libs(target=None, source=None, env=None):
+ lib_path = target[0].srcnode().abspath
+ env.Execute('$IPHONEPATH/usr/bin/libtool -static -o "' + lib_path + '" ' + ' '.join([('"' + lib.srcnode().abspath + '"') for lib in source]))
-prog = None
-prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
-action = "$IPHONEPATH/usr/bin/dsymutil " + File(prog)[0].path + " -o " + File(prog)[0].path + ".dSYM"
-env.AddPostAction(prog, action)
+combine_command = env_ios.Command('#bin/libgodot' + env_ios['LIBSUFFIX'], [ios_lib] + env_ios['LIBS'], combine_libs)
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index 65cafbd6d4..8f2893e69e 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -638,6 +638,9 @@ static int frame_count = 0;
mainViewController = view_controller;
+ // prevent to stop music in another background app
+ [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
+
#ifdef MODULE_GAME_ANALYTICS_ENABLED
printf("********************* didFinishLaunchingWithOptions\n");
if (!ProjectSettings::get_singleton()->has("mobileapptracker/advertiser_id")) {
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 993a93ff89..25674c2b47 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -61,10 +61,13 @@ def configure(env):
env.Append(LINKFLAGS=['-flto'])
## Architecture
+ if env["ios_sim"] and not ("arch" in env):
+ env["arch"] = "x86"
- if env["ios_sim"] or env["arch"] == "x86": # i386, simulator
- env["arch"] = "x86"
+ if env["arch"] == "x86": # i386, simulator
env["bits"] = "32"
+ elif env["arch"] == "x86_64":
+ env["bits"] = "64"
elif (env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32"): # arm
env["arch"] = "arm"
env["bits"] = "32"
@@ -76,18 +79,30 @@ def configure(env):
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'
+ compiler_path = '$IPHONEPATH/usr/bin/${ios_triple}'
+ s_compiler_path = '$IPHONEPATH/Developer/usr/bin/'
+
+ ccache_path = os.environ.get("CCACHE")
+ if ccache_path == None:
+ env['CC'] = compiler_path + 'clang'
+ env['CXX'] = compiler_path + 'clang++'
+ env['S_compiler'] = s_compiler_path + 'gcc'
+ else:
+ # there aren't any ccache wrappers available for iOS,
+ # to enable caching we need to prepend the path to the ccache binary
+ env['CC'] = ccache_path + ' ' + compiler_path + 'clang'
+ env['CXX'] = ccache_path + ' ' + compiler_path + 'clang++'
+ env['S_compiler'] = ccache_path + ' ' + s_compiler_path + 'gcc'
+ env['AR'] = compiler_path + 'ar'
+ env['RANLIB'] = compiler_path + 'ranlib'
## Compile flags
- if (env["arch"] == "x86"):
+ if (env["arch"] == "x86" or env["arch"] == "x86_64"):
env['IPHONEPLATFORM'] = 'iPhoneSimulator'
- env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
- env.Append(CCFLAGS='-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\\\"'.split())
+ env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.9'
+ arch_flag = "i386" if env["arch"] == "x86" else env["arch"]
+ env.Append(CCFLAGS=('-arch ' + arch_flag + ' -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=9.0 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"').split())
elif (env["arch"] == "arm"):
env.Append(CCFLAGS='-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'.split())
elif (env["arch"] == "arm64"):
@@ -102,8 +117,9 @@ def configure(env):
## Link flags
- if (env["arch"] == "x86"):
- env.Append(LINKFLAGS=['-arch', 'i386', '-mios-simulator-version-min=4.3',
+ if (env["arch"] == "x86" or env["arch"] == "x86_64"):
+ arch_flag = "i386" if env["arch"] == "x86" else env["arch"]
+ env.Append(LINKFLAGS=['-arch', arch_flag, '-mios-simulator-version-min=9.0',
'-isysroot', '$IPHONESDK',
'-Xlinker',
'-objc_abi_version',
@@ -152,7 +168,7 @@ def configure(env):
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', '-DCOREAUDIO_ENABLED'])
+ env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DMPC_FIXED_POINT', '-DCOREAUDIO_ENABLED'])
# TODO: Move that to opus module's config
if 'module_opus_enabled' in env and env['module_opus_enabled']:
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 0507ef19d6..b05bb9ab09 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -37,7 +37,7 @@
#include "io/zip_io.h"
#include "os/file_access.h"
#include "os/os.h"
-#include "platform/osx/logo.gen.h"
+#include "platform/iphone/logo.gen.h"
#include "project_settings.h"
#include "string.h"
#include "version.h"
@@ -56,11 +56,48 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata);
static Error _codesign(String p_file, void *p_userdata);
- void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary, bool p_debug);
- static Error _export_dylibs(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total);
+ struct IOSConfigData {
+ String pkg_name;
+ String binary_name;
+ String plist_content;
+ String architectures;
+ String linker_flags;
+ String cpp_code;
+ };
+
+ struct ExportArchitecture {
+ String name;
+ bool is_default;
+
+ ExportArchitecture()
+ : name(""), is_default(false) {
+ }
+
+ ExportArchitecture(String p_name, bool p_is_default) {
+ name = p_name;
+ is_default = p_is_default;
+ }
+ };
+
+ struct IOSExportAsset {
+ String exported_path;
+ bool is_framework; // framework is anything linked to the binary, otherwise it's a resource
+ };
+
+ String _get_additional_plist_content();
+ String _get_linker_flags();
+ String _get_cpp_code();
+ void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
Error _export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
+ Vector<ExportArchitecture> _get_supported_architectures();
+ Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset);
+
+ void _add_assets_to_project(Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
+ Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets);
+ Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
+
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
virtual void get_export_options(List<ExportOption> *r_options);
@@ -96,6 +133,17 @@ void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset>
if (p_preset->get("texture_format/etc2")) {
r_features->push_back("etc2");
}
+ Vector<String> architectures = _get_preset_architectures(p_preset);
+ for (int i = 0; i < architectures.size(); ++i) {
+ r_features->push_back(architectures[i]);
+ }
+}
+
+Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() {
+ Vector<ExportArchitecture> archs;
+ archs.push_back(ExportArchitecture("armv7", true));
+ archs.push_back(ExportArchitecture("arm64", true));
+ return archs;
}
void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) {
@@ -120,7 +168,6 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
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::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "png"), "")); // Home screen on iPhone/iPod Touch with retina display
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/ipad_76x76", PROPERTY_HINT_FILE, "png"), "")); // Home screen on iPad
@@ -145,10 +192,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
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 */
+ Vector<ExportArchitecture> architectures = _get_supported_architectures();
+ for (int i = 0; i < architectures.size(); ++i) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + architectures[i].name), architectures[i].is_default));
+ }
}
-void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary, bool p_debug) {
+void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) {
static const String export_method_string[] = {
"app-store",
"development",
@@ -158,13 +208,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
String str;
String strnew;
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
- print_line(str);
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";
+ strnew += lines[i].replace("$binary", p_config.binary_name) + "\n";
} else if (lines[i].find("$name") != -1) {
- strnew += lines[i].replace("$name", p_name) + "\n";
+ strnew += lines[i].replace("$name", p_config.pkg_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) {
@@ -186,10 +235,21 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n";
} else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) {
strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n";
+ } else if (lines[i].find("$provisioning_profile_uuid") != -1) {
+ String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release");
+ strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n";
} else if (lines[i].find("$code_sign_identity_debug") != -1) {
strnew += lines[i].replace("$code_sign_identity_debug", p_preset->get("application/code_sign_identity_debug")) + "\n";
} else if (lines[i].find("$code_sign_identity_release") != -1) {
strnew += lines[i].replace("$code_sign_identity_release", p_preset->get("application/code_sign_identity_release")) + "\n";
+ } else if (lines[i].find("$additional_plist_content") != -1) {
+ strnew += lines[i].replace("$additional_plist_content", p_config.plist_content) + "\n";
+ } else if (lines[i].find("$godot_archs") != -1) {
+ strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n";
+ } else if (lines[i].find("$linker_flags") != -1) {
+ strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n";
+ } else if (lines[i].find("$cpp_code") != -1) {
+ strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n";
} else {
strnew += lines[i] + "\n";
}
@@ -204,27 +264,37 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
}
-Error EditorExportPlatformIOS::_export_dylibs(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
- if (!p_path.ends_with(".dylib")) return OK;
- const String &dest_dir = *(String *)p_userdata;
- String rel_path = p_path.replace_first("res://", "dylibs/");
- DirAccess *dest_dir_access = DirAccess::open(dest_dir);
- ERR_FAIL_COND_V(!dest_dir_access, ERR_CANT_OPEN);
-
- String base_dir = rel_path.get_base_dir();
- Error make_dir_err = OK;
- if (!dest_dir_access->dir_exists(base_dir)) {
- make_dir_err = dest_dir_access->make_dir_recursive(base_dir);
- }
- if (make_dir_err != OK) {
- memdelete(dest_dir_access);
- return make_dir_err;
+String EditorExportPlatformIOS::_get_additional_plist_content() {
+ Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ String result;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ result += export_plugins[i]->get_ios_plist_content();
}
+ return result;
+}
- Error copy_err = dest_dir_access->copy(p_path, dest_dir + rel_path);
- memdelete(dest_dir_access);
+String EditorExportPlatformIOS::_get_linker_flags() {
+ Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ String result;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ String flags = export_plugins[i]->get_ios_linker_flags();
+ if (flags.length() == 0) continue;
+ if (result.length() > 0) {
+ result += ' ';
+ }
+ result += flags;
+ }
+ // the flags will be enclosed in quotes, so need to escape them
+ return result.replace("\"", "\\\"");
+}
- return copy_err;
+String EditorExportPlatformIOS::_get_cpp_code() {
+ Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ String result;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ result += export_plugins[i]->get_ios_cpp_code();
+ }
+ return result;
}
struct IconInfo {
@@ -402,7 +472,207 @@ Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) {
return OK;
}
+struct PbxId {
+private:
+ static char _hex_char(uint8_t four_bits) {
+ if (four_bits < 10) {
+ return ('0' + four_bits);
+ }
+ return 'A' + (four_bits - 10);
+ }
+
+ static String _hex_pad(uint32_t num) {
+ Vector<char> ret;
+ ret.resize(sizeof(num) * 2);
+ for (int i = 0; i < sizeof(num) * 2; ++i) {
+ uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF;
+ ret[i] = _hex_char(four_bits);
+ }
+ return String::utf8(ret.ptr(), ret.size());
+ }
+
+public:
+ uint32_t high_bits;
+ uint32_t mid_bits;
+ uint32_t low_bits;
+
+ String str() const {
+ return _hex_pad(high_bits) + _hex_pad(mid_bits) + _hex_pad(low_bits);
+ }
+
+ PbxId &operator++() {
+ low_bits++;
+ if (!low_bits) {
+ mid_bits++;
+ if (!mid_bits) {
+ high_bits++;
+ }
+ }
+
+ return *this;
+ }
+};
+
+struct ExportLibsData {
+ Vector<String> lib_paths;
+ String dest_dir;
+};
+
+void EditorExportPlatformIOS::_add_assets_to_project(Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
+ Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<String> frameworks;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ Vector<String> plugin_frameworks = export_plugins[i]->get_ios_frameworks();
+ for (int j = 0; j < plugin_frameworks.size(); ++j) {
+ frameworks.push_back(plugin_frameworks[j]);
+ }
+ }
+
+ // that is just a random number, we just need Godot IDs not to clash with
+ // existing IDs in the project.
+ PbxId current_id = { 0x58938401, 0, 0 };
+ String pbx_files;
+ String pbx_frameworks_build;
+ String pbx_frameworks_refs;
+ String pbx_resources_build;
+ String pbx_resources_refs;
+
+ const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
+ "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = $name; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
+ for (int i = 0; i < p_additional_assets.size(); ++i) {
+ String build_id = (++current_id).str();
+ String ref_id = (++current_id).str();
+ const IOSExportAsset &asset = p_additional_assets[i];
+
+ String type;
+ if (asset.exported_path.ends_with(".framework")) {
+ type = "wrapper.framework";
+ } else if (asset.exported_path.ends_with(".dylib")) {
+ type = "compiled.mach-o.dylib";
+ } else if (asset.exported_path.ends_with(".a")) {
+ type = "archive.ar";
+ } else {
+ type = "file";
+ }
+
+ String &pbx_build = asset.is_framework ? pbx_frameworks_build : pbx_resources_build;
+ String &pbx_refs = asset.is_framework ? pbx_frameworks_refs : pbx_resources_refs;
+
+ if (pbx_build.length() > 0) {
+ pbx_build += ",\n";
+ pbx_refs += ",\n";
+ }
+ pbx_build += build_id;
+ pbx_refs += ref_id;
+
+ Dictionary format_dict;
+ format_dict["build_id"] = build_id;
+ format_dict["ref_id"] = ref_id;
+ format_dict["name"] = asset.exported_path.get_file();
+ format_dict["file_path"] = asset.exported_path;
+ format_dict["file_type"] = type;
+ pbx_files += file_info_format.format(format_dict, "$_");
+ }
+
+ String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size());
+ str = str.replace("$additional_pbx_files", pbx_files);
+ str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build);
+ str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs);
+ str = str.replace("$additional_pbx_resources_build", pbx_resources_build);
+ str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs);
+
+ CharString cs = str.utf8();
+ p_project_data.resize(cs.size() - 1);
+ for (int i = 0; i < cs.size() - 1; i++) {
+ p_project_data[i] = cs[i];
+ }
+}
+
+Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets) {
+ DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!filesystem_da, ERR_CANT_CREATE);
+ for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) {
+ String asset = p_assets[f_idx];
+ if (!asset.begins_with("res://")) {
+ // either SDK-builtin or already a part of the export template
+ IOSExportAsset exported_asset = { asset, p_is_framework };
+ r_exported_assets.push_back(exported_asset);
+ } else {
+ DirAccess *da = DirAccess::create_for_path(asset);
+ if (!da) {
+ memdelete(filesystem_da);
+ ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ }
+ bool file_exists = da->file_exists(asset);
+ bool dir_exists = da->dir_exists(asset);
+ if (!file_exists && !dir_exists) {
+ memdelete(da);
+ memdelete(filesystem_da);
+ return ERR_FILE_NOT_FOUND;
+ }
+ String additional_dir = p_is_framework && asset.ends_with(".dylib") ? "/dylibs/" : "/";
+ String destination_dir = p_out_dir + additional_dir + asset.get_base_dir().replace("res://", "");
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ memdelete(da);
+ memdelete(filesystem_da);
+ return make_dir_err;
+ }
+ }
+
+ String destination = destination_dir + "/" + asset.get_file();
+ Error err = dir_exists ? da->copy_dir(asset, destination) : da->copy(asset, destination);
+ memdelete(da);
+ if (err) {
+ memdelete(filesystem_da);
+ return err;
+ }
+ IOSExportAsset exported_asset = { destination, p_is_framework };
+ r_exported_assets.push_back(exported_asset);
+ }
+ }
+ memdelete(filesystem_da);
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
+ Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ Vector<String> frameworks = export_plugins[i]->get_ios_frameworks();
+ Error err = _export_additional_assets(p_out_dir, frameworks, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+ Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
+ err = _export_additional_assets(p_out_dir, ios_bundle_files, false, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ Vector<String> library_paths;
+ for (int i = 0; i < p_libraries.size(); ++i) {
+ library_paths.push_back(p_libraries[i].path);
+ }
+ Error err = _export_additional_assets(p_out_dir, library_paths, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) {
+ Vector<ExportArchitecture> all_archs = _get_supported_architectures();
+ Vector<String> enabled_archs;
+ for (int i = 0; i < all_archs.size(); ++i) {
+ bool is_enabled = p_preset->get("architectures/" + all_archs[i].name);
+ if (is_enabled) {
+ enabled_archs.push_back(all_archs[i].name);
+ }
+ }
+ return enabled_archs;
+}
+
Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
String src_pkg_name;
String dest_dir = p_path.get_base_dir() + "/";
String binary_name = p_path.get_file().get_basename();
@@ -427,26 +697,43 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
}
- FileAccess *src_f = NULL;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (da) {
+ String current_dir = da->get_current_dir();
- ep.step("Creating app", 0);
+ // remove leftovers from last export so they don't interfere
+ // in case some files are no longer needed
+ if (da->change_dir(dest_dir + binary_name + ".xcodeproj") == OK) {
+ da->erase_contents_recursive();
+ }
+ if (da->change_dir(dest_dir + binary_name) == OK) {
+ da->erase_contents_recursive();
+ }
- unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
- if (!src_pkg_zip) {
+ da->change_dir(current_dir);
- EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
- return ERR_FILE_NOT_FOUND;
+ if (!da->dir_exists(dest_dir + binary_name)) {
+ Error err = da->make_dir(dest_dir + binary_name);
+ if (err) {
+ memdelete(da);
+ return err;
+ }
+ }
+ memdelete(da);
}
- ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
- int ret = unzGoToFirstFile(src_pkg_zip);
+ ep.step("Making .pck", 0);
+ String pack_path = dest_dir + binary_name + ".pck";
+ Vector<SharedObject> libraries;
+ Error err = save_pack(p_preset, pack_path, &libraries);
+ if (err)
+ return err;
+
+ ep.step("Extracting and configuring Xcode project", 1);
- 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");
+ String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".fat.a";
- print_line("binary: " + binary_to_use);
+ print_line("static library: " + library_to_use);
String pkg_name;
if (p_preset->get("application/name") != "")
pkg_name = p_preset->get("application/name"); // app_name
@@ -455,22 +742,41 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
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;
+ bool found_library = false;
int total_size = 0;
+ const String project_file = "godot_ios.xcodeproj/project.pbxproj";
Set<String> files_to_parse;
files_to_parse.insert("godot_ios/godot_ios-Info.plist");
- files_to_parse.insert("godot_ios.xcodeproj/project.pbxproj");
- files_to_parse.insert("export_options.plist");
+ files_to_parse.insert(project_file);
+ files_to_parse.insert("godot_ios/export_options.plist");
+ files_to_parse.insert("godot_ios/dummy.cpp");
files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata");
files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
- print_line("Unzipping...");
+ IOSConfigData config_data = {
+ pkg_name,
+ binary_name,
+ _get_additional_plist_content(),
+ String(" ").join(_get_preset_architectures(p_preset)),
+ _get_linker_flags(),
+ _get_cpp_code()
+ };
+
+ DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir);
+ ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE)
+ print_line("Unzipping...");
+ FileAccess *src_f = NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
+ EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name);
+ return ERR_CANT_OPEN;
+ }
+ ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(src_pkg_zip);
+ Vector<uint8_t> project_file_data;
while (ret == UNZ_OK) {
bool is_execute = false;
@@ -487,7 +793,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
//read
unzOpenCurrentFile(src_pkg_zip);
- unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
unzCloseCurrentFile(src_pkg_zip);
//write
@@ -496,15 +802,18 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
if (files_to_parse.has(file)) {
print_line(String("parse ") + file);
- _fix_config_file(p_preset, data, pkg_name, binary_name, p_debug);
- } else if (file.begins_with("godot.iphone")) {
- if (file != binary_to_use) {
+ _fix_config_file(p_preset, data, config_data, p_debug);
+ } else if (file.begins_with("libgodot.iphone")) {
+ if (file != library_to_use) {
ret = unzGoToNextFile(src_pkg_zip);
continue; //ignore!
}
- found_binary = true;
+ found_library = true;
is_execute = true;
- file = "godot_ios.iphone";
+ file = "godot_ios.a";
+ }
+ if (file == project_file) {
+ project_file_data = data;
}
///@TODO need to parse logo files
@@ -557,16 +866,16 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
/* 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.");
+ if (!found_library) {
+ ERR_PRINTS("Requested template library '" + library_to_use + "' not found. It might be missing from your template archive.");
memdelete(tmp_app_path);
return ERR_FILE_NOT_FOUND;
}
String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/";
- Error err = OK;
+ err = OK;
if (!tmp_app_path->dir_exists(iconset_dir)) {
- Error err = tmp_app_path->make_dir_recursive(iconset_dir);
+ err = tmp_app_path->make_dir_recursive(iconset_dir);
}
memdelete(tmp_app_path);
if (err)
@@ -580,20 +889,23 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
if (err)
return err;
- ep.step("Making .pck", 1);
-
- String pack_path = dest_dir + binary_name + ".pck";
- err = save_pack(p_preset, pack_path);
- if (err)
- return err;
-
- err = export_project_files(p_preset, _export_dylibs, &dest_dir);
- if (err)
- return err;
+ print_line("Exporting additional assets");
+ Vector<IOSExportAsset> assets;
+ _export_additional_assets(dest_dir + binary_name, libraries, assets);
+ _add_assets_to_project(project_file_data, assets);
+ String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj";
+ FileAccess *f = FileAccess::open(project_file_name, FileAccess::WRITE);
+ if (!f) {
+ ERR_PRINTS("Can't write '" + project_file_name + "'.");
+ return ERR_CANT_CREATE;
+ };
+ f->store_buffer(project_file_data.ptr(), project_file_data.size());
+ f->close();
+ memdelete(f);
#ifdef OSX_ENABLED
ep.step("Code-signing dylibs", 2);
- DirAccess *dylibs_dir = DirAccess::open(dest_dir + "dylibs");
+ DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs");
ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN);
CodesignData codesign_data(p_preset, p_debug);
err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data);
@@ -625,13 +937,14 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
export_args.push_back("-archivePath");
export_args.push_back(archive_path);
export_args.push_back("-exportOptionsPlist");
- export_args.push_back(dest_dir + "export_options.plist");
+ export_args.push_back(dest_dir + binary_name + "/export_options.plist");
+ export_args.push_back("-allowProvisioningUpdates");
export_args.push_back("-exportPath");
export_args.push_back(dest_dir);
err = OS::get_singleton()->execute("xcodebuild", export_args, true);
ERR_FAIL_COND_V(err, err);
#else
- print_line(".ipa can only be built on macOS. Leaving XCode project without building the package.");
+ print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package.");
#endif
return OK;
@@ -664,9 +977,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
EditorExportPlatformIOS::EditorExportPlatformIOS() {
- ///@TODO need to create the correct logo
- // Ref<Image> img = memnew(Image(_iphone_logo));
- Ref<Image> img = memnew(Image(_osx_logo));
+ Ref<Image> img = memnew(Image(_iphone_logo));
logo.instance();
logo->create_from_image(img);
}
diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm
index 531b80eee3..d2104ae765 100644
--- a/platform/iphone/game_center.mm
+++ b/platform/iphone/game_center.mm
@@ -109,7 +109,7 @@ void GameCenter::connect() {
GameCenter::get_singleton()->authenticated = true;
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
ret["error_description"] = [error.localizedDescription UTF8String];
GameCenter::get_singleton()->authenticated = false;
};
@@ -145,7 +145,7 @@ Error GameCenter::post_score(Variant p_score) {
ret["result"] = "ok";
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
ret["error_description"] = [error.localizedDescription UTF8String];
};
@@ -183,7 +183,7 @@ Error GameCenter::award_achievement(Variant p_params) {
ret["result"] = "ok";
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
};
pending_events.push_back(ret);
@@ -241,7 +241,7 @@ void GameCenter::request_achievement_descriptions() {
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
};
pending_events.push_back(ret);
@@ -273,7 +273,7 @@ void GameCenter::request_achievements() {
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
};
pending_events.push_back(ret);
@@ -289,7 +289,7 @@ void GameCenter::reset_achievements() {
ret["result"] = "ok";
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
};
pending_events.push_back(ret);
@@ -358,7 +358,7 @@ Error GameCenter::request_identity_verification_signature() {
ret["player_id"] = [player.playerID UTF8String];
} else {
ret["result"] = "error";
- ret["error_code"] = error.code;
+ ret["error_code"] = (int64_t)error.code;
ret["error_description"] = [error.localizedDescription UTF8String];
};
diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp
index 4bdc716d6e..b81e6def3b 100644
--- a/platform/iphone/globals/global_defaults.cpp
+++ b/platform/iphone/globals/global_defaults.cpp
@@ -31,11 +31,4 @@
#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");
- 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/in_app_store.mm b/platform/iphone/in_app_store.mm
index 9efd4b9891..25f4e1e166 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -92,6 +92,7 @@ void InAppStore::_bind_methods() {
PoolRealArray prices;
PoolStringArray ids;
PoolStringArray localized_prices;
+ PoolStringArray currency_codes;
for (int i = 0; i < [products count]; i++) {
@@ -105,12 +106,14 @@ void InAppStore::_bind_methods() {
prices.push_back([product.price doubleValue]);
ids.push_back(String::utf8([product.productIdentifier UTF8String]));
localized_prices.push_back(String::utf8([product.localizedPrice UTF8String]));
+ currency_codes.push_back(String::utf8([[[product priceLocale] objectForKey:NSLocaleCurrencyCode] UTF8String]));
};
ret["titles"] = titles;
ret["descriptions"] = descriptions;
ret["prices"] = prices;
ret["ids"] = ids;
ret["localized_prices"] = localized_prices;
+ ret["currency_codes"] = currency_codes;
PoolStringArray invalid_ids;
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index 0efe22c1af..f06657cd7b 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -46,6 +46,7 @@
#include "sem_iphone.h"
#include "ios.h"
+#include <dlfcn.h>
int OSIPhone::get_video_driver_count() const {
@@ -54,7 +55,7 @@ int OSIPhone::get_video_driver_count() const {
const char *OSIPhone::get_video_driver_name(int p_driver) const {
- return "GLES2";
+ return "GLES3";
};
OSIPhone *OSIPhone::get_singleton() {
@@ -62,11 +63,6 @@ OSIPhone *OSIPhone::get_singleton() {
return (OSIPhone *)OS::get_singleton();
};
-OS::VideoMode OSIPhone::get_default_video_mode() const {
-
- return video_mode;
-};
-
uint8_t OSIPhone::get_orientations() const {
return supported_orientations;
@@ -101,15 +97,6 @@ void OSIPhone::initialize_core() {
set_data_dir(data_dir);
};
-void OSIPhone::initialize_logger() {
- Vector<Logger *> loggers;
- loggers.push_back(memnew(SyslogLogger));
- // FIXME: Reenable once we figure out how to get this properly in user://
- // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277)
- //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt")));
- _set_logger(memnew(CompositeLogger(loggers)));
-}
-
void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
supported_orientations = 0;
@@ -138,40 +125,33 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_
AudioDriverManager::add_driver(&audio_driver);
AudioDriverManager::initialize(p_audio_driver);
- // init physics servers
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- //physics_2d_server = memnew( Physics2DServerSW );
- physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
- physics_2d_server->init();
-
input = memnew(InputDefault);
/*
#ifdef IOS_SCORELOOP_ENABLED
scoreloop = memnew(ScoreloopIOS);
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Scoreloop", scoreloop));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("Scoreloop", scoreloop));
scoreloop->connect();
#endif
*/
#ifdef GAME_CENTER_ENABLED
game_center = memnew(GameCenter);
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("GameCenter", game_center));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("GameCenter", game_center));
game_center->connect();
#endif
#ifdef STOREKIT_ENABLED
store_kit = memnew(InAppStore);
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("InAppStore", store_kit));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("InAppStore", store_kit));
#endif
#ifdef ICLOUD_ENABLED
icloud = memnew(ICloud);
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ICloud", icloud));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("ICloud", icloud));
//icloud->connect();
#endif
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("iOS", memnew(iOS)));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", memnew(iOS)));
};
MainLoop *OSIPhone::get_main_loop() const {
@@ -384,12 +364,6 @@ void OSIPhone::finalize() {
memdelete(visual_server);
// memdelete(rasterizer);
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
-
memdelete(input);
};
@@ -420,6 +394,37 @@ void OSIPhone::alert(const String &p_alert, const String &p_title) {
iOS::alert(utf8_alert.get_data(), utf8_title.get_data());
}
+Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+ if (p_path.length() == 0) {
+ p_library_handle = RTLD_SELF;
+ return OK;
+ }
+ return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path);
+}
+
+Error OSIPhone::close_dynamic_library(void *p_library_handle) {
+ if (p_library_handle == RTLD_SELF) {
+ return OK;
+ }
+ return OS_Unix::close_dynamic_library(p_library_handle);
+}
+
+HashMap<String, void *> OSIPhone::dynamic_symbol_lookup_table;
+void register_dynamic_symbol(char *name, void *address) {
+ OSIPhone::dynamic_symbol_lookup_table[String(name)] = address;
+}
+
+Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) {
+ if (p_library_handle == RTLD_SELF) {
+ void **ptr = OSIPhone::dynamic_symbol_lookup_table.getptr(p_name);
+ if (ptr) {
+ p_symbol_handle = *ptr;
+ return OK;
+ }
+ }
+ return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional);
+}
+
void OSIPhone::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
video_mode = p_video_mode;
@@ -488,7 +493,7 @@ void OSIPhone::set_cursor_shape(CursorShape p_shape){
};
-String OSIPhone::get_data_dir() const {
+String OSIPhone::get_user_data_dir() const {
return data_dir;
};
@@ -527,7 +532,7 @@ Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
bool exists = f && f->is_open();
- String tempFile = get_data_dir();
+ String tempFile = get_user_data_dir();
if (!exists)
return FAILED;
@@ -539,7 +544,7 @@ Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_
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());
+ p_path = p_path.replace("user:/", get_user_data_dir());
memdelete(f);
@@ -576,7 +581,36 @@ bool OSIPhone::_check_internal_feature_support(const String &p_feature) {
return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2";
}
+// Initialization order between compilation units is not guaranteed,
+// so we use this as a hack to ensure certain code is called before
+// everything else, but after all units are initialized.
+typedef void (*init_callback)();
+static init_callback *ios_init_callbacks = NULL;
+static int ios_init_callbacks_count = 0;
+static int ios_init_callbacks_capacity = 0;
+
+void add_ios_init_callback(init_callback cb) {
+ if (ios_init_callbacks_count == ios_init_callbacks_capacity) {
+ void *new_ptr = realloc(ios_init_callbacks, sizeof(cb) * 32);
+ if (new_ptr) {
+ ios_init_callbacks = (init_callback *)(new_ptr);
+ ios_init_callbacks_capacity += 32;
+ }
+ }
+ if (ios_init_callbacks_capacity > ios_init_callbacks_count) {
+ ios_init_callbacks[ios_init_callbacks_count] = cb;
+ ++ios_init_callbacks_count;
+ }
+}
+
OSIPhone::OSIPhone(int width, int height, String p_data_dir) {
+ for (int i = 0; i < ios_init_callbacks_count; ++i) {
+ ios_init_callbacks[i]();
+ }
+ free(ios_init_callbacks);
+ ios_init_callbacks = NULL;
+ ios_init_callbacks_count = 0;
+ ios_init_callbacks_capacity = 0;
main_loop = NULL;
visual_server = NULL;
@@ -594,7 +628,13 @@ OSIPhone::OSIPhone(int width, int height, String p_data_dir) {
// which is initialized in initialize_core
data_dir = p_data_dir;
- _set_logger(memnew(SyslogLogger));
+ Vector<Logger *> loggers;
+ loggers.push_back(memnew(SyslogLogger));
+#ifdef DEBUG_ENABLED
+ // it seems iOS app's stdout/stderr is only obtainable if you launch it from Xcode
+ loggers.push_back(memnew(StdLogger));
+#endif
+ _set_logger(memnew(CompositeLogger(loggers)));
};
OSIPhone::~OSIPhone() {
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index e70ac9ba98..3f989b49be 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -41,9 +41,6 @@
#include "in_app_store.h"
#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/physics/physics_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
@@ -63,11 +60,12 @@ private:
MAX_EVENTS = 64,
};
+ static HashMap<String, void *> dynamic_symbol_lookup_table;
+ friend void register_dynamic_symbol(char *name, void *address);
+
uint8_t supported_orientations;
VisualServer *visual_server;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
AudioDriverCoreAudio audio_driver;
@@ -88,9 +86,6 @@ private:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
- virtual void initialize_logger();
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
@@ -160,6 +155,10 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
+ 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, bool p_optional = false);
+
virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
virtual VideoMode get_video_mode(int p_screen = 0) const;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
@@ -185,7 +184,7 @@ public:
Error shell_open(String p_uri);
- String get_data_dir() const;
+ String get_user_data_dir() const;
void set_locale(String p_locale);
String get_locale() const;
diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h
index 54de66082e..7ff6e7a9a9 100644
--- a/platform/iphone/platform_config.h
+++ b/platform/iphone/platform_config.h
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <alloca.h>
-// #define GLES2_INCLUDE_H <ES2/gl.h>
+
#define GLES3_INCLUDE_H <ES3/gl.h>
#define PLATFORM_REFCOUNT
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index f01d9367d2..05992ebac8 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -6,8 +6,8 @@ javascript_files = [
"os_javascript.cpp",
"audio_driver_javascript.cpp",
"javascript_main.cpp",
- "audio_server_javascript.cpp",
"power_javascript.cpp",
+ "http_client_javascript.cpp",
"javascript_eval.cpp",
]
@@ -19,33 +19,23 @@ 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','_send_notification']\""])
+env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_main_after_fs_sync','_send_notification']\""])
-# output file name without file extension
-basename = "godot" + env["PROGSUFFIX"]
target_dir = env.Dir("#bin")
+build = env.add_program(['#bin/godot', target_dir.File('godot' + env['PROGSUFFIX'] + '.wasm')], javascript_objects, PROGSUFFIX=env['PROGSUFFIX'] + '.js');
-zip_dir = target_dir.Dir('.javascript_zip')
-zip_files = env.InstallAs(zip_dir.File('godot.html'), '#misc/dist/html/default.html')
-
-implicit_targets = []
-if env['wasm']:
- wasm = target_dir.File(basename + '.wasm')
- implicit_targets.append(wasm)
- zip_files.append(InstallAs(zip_dir.File('godot.wasm'), wasm))
- prejs = env.File('pre_wasm.js')
-else:
- asmjs_files = [target_dir.File(basename + '.asm.js'), target_dir.File(basename + '.js.mem')]
- implicit_targets.extend(asmjs_files)
- zip_files.append(InstallAs([zip_dir.File('godot.asm.js'), zip_dir.File('godot.mem')], asmjs_files))
- prejs = env.File('pre_asmjs.js')
-
-js = env.Program(['#bin/godot'] + implicit_targets, javascript_objects, PROGSUFFIX=env['PROGSUFFIX'] + '.js')[0];
-zip_files.append(InstallAs(zip_dir.File('godot.js'), js))
+js_libraries = []
+js_libraries.append(env.File('http_request.js'))
+for lib in js_libraries:
+ env.Append(LINKFLAGS=['--js-library', lib.path])
+env.Depends(build, js_libraries)
+prejs = env.File('pre.js')
postjs = env.File('engine.js')
-env.Depends(js, [prejs, postjs])
env.Append(LINKFLAGS=['--pre-js', prejs.path])
env.Append(LINKFLAGS=['--post-js', postjs.path])
+env.Depends(build, [prejs, postjs])
+zip_dir = target_dir.Dir('.javascript_zip')
+zip_files = env.InstallAs([zip_dir.File('godot.js'), zip_dir.File('godot.wasm'), zip_dir.File('godot.html')], build + ['#misc/dist/html/default.html'])
Zip('#bin/godot', zip_files, ZIPSUFFIX=env['PROGSUFFIX'] + env['ZIPSUFFIX'], ZIPROOT=zip_dir, ZIPCOMSTR="Archving $SOURCES as $TARGET")
diff --git a/platform/javascript/api/api.cpp b/platform/javascript/api/api.cpp
new file mode 100644
index 0000000000..f2b2ca40bf
--- /dev/null
+++ b/platform/javascript/api/api.cpp
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* api.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://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 "api.h"
+#include "engine.h"
+#include "javascript_eval.h"
+
+static JavaScript *javascript_eval;
+
+void register_javascript_api() {
+
+ ClassDB::register_virtual_class<JavaScript>();
+ javascript_eval = memnew(JavaScript);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScript", javascript_eval));
+}
+
+void unregister_javascript_api() {
+
+ memdelete(javascript_eval);
+}
+
+JavaScript *JavaScript::singleton = NULL;
+
+JavaScript *JavaScript::get_singleton() {
+
+ return singleton;
+}
+
+JavaScript::JavaScript() {
+
+ ERR_FAIL_COND(singleton != NULL);
+ singleton = this;
+}
+
+JavaScript::~JavaScript() {}
+
+void JavaScript::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScript::eval, DEFVAL(false));
+}
+
+#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
+Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
+
+ return Variant();
+}
+#endif
diff --git a/platform/javascript/api/api.h b/platform/javascript/api/api.h
new file mode 100644
index 0000000000..53cd9239fc
--- /dev/null
+++ b/platform/javascript/api/api.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* api.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://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_javascript_api();
+void unregister_javascript_api();
diff --git a/platform/javascript/javascript_eval.h b/platform/javascript/api/javascript_eval.h
index ed7cf383da..4d0b0b21ff 100644
--- a/platform/javascript/javascript_eval.h
+++ b/platform/javascript/api/javascript_eval.h
@@ -27,8 +27,6 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_EVAL_ENABLED
-
#ifndef JAVASCRIPT_EVAL_H
#define JAVASCRIPT_EVAL_H
@@ -52,4 +50,3 @@ public:
};
#endif // JAVASCRIPT_EVAL_H
-#endif // JAVASCRIPT_EVAL_ENABLED
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index cd3974669f..9633472cd2 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -30,29 +30,19 @@
#include "audio_driver_javascript.h"
#include <emscripten.h>
-#include <string.h>
-
-#define MAX_NUMBER_INTERFACES 3
-#define MAX_NUMBER_OUTPUT_DEVICES 6
-
-/* Structure for passing information to callback function */
-
-//AudioDriverJavaScript* AudioDriverJavaScript::s_ad=NULL;
AudioDriverJavaScript *AudioDriverJavaScript::singleton_js = NULL;
+
const char *AudioDriverJavaScript::get_name() const {
return "JavaScript";
}
-extern "C" {
-
-void js_audio_driver_mix_function(int p_frames) {
+extern "C" EMSCRIPTEN_KEEPALIVE void js_audio_driver_mix_function(int p_frames) {
//print_line("MIXI! "+itos(p_frames));
AudioDriverJavaScript::singleton_js->mix_to_js(p_frames);
}
-}
void AudioDriverJavaScript::mix_to_js(int p_frames) {
@@ -65,11 +55,11 @@ void AudioDriverJavaScript::mix_to_js(int p_frames) {
audio_server_process(p_frames, stream_buffer);
for (int i = 0; i < tomix * internal_buffer_channels; i++) {
- internal_buffer[i] = float(stream_buffer[i] >> 16) * 32768.0;
+ internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.0;
}
/* clang-format off */
- EM_ASM_({
+ EM_ASM_ARGS({
var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2);
for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) {
@@ -95,29 +85,24 @@ Error AudioDriverJavaScript::init() {
void AudioDriverJavaScript::start() {
- internal_buffer_channels = 2;
internal_buffer = memnew_arr(float, INTERNAL_BUFFER_SIZE *internal_buffer_channels);
stream_buffer = memnew_arr(int32_t, INTERNAL_BUFFER_SIZE * 4); //max 4 channels
/* clang-format off */
- EM_ASM(
- _as_audioctx = new (window.AudioContext || window.webkitAudioContext)();
-
- audio_server_mix_function = Module.cwrap('js_audio_driver_mix_function', 'void', ['number']);
- );
-
- int buffer_latency = 16384;
- EM_ASM_( {
- _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2);
+ mix_rate = EM_ASM_INT({
+ _as_audioctx = new (window.AudioContext || window.webkitAudioContext);
+ _as_script_node = _as_audioctx.createScriptProcessor($0, 0, $1);
_as_script_node.connect(_as_audioctx.destination);
console.log(_as_script_node.bufferSize);
+ var jsAudioDriverMixFunction = cwrap('js_audio_driver_mix_function', null, ['number']);
_as_script_node.onaudioprocess = function(audioProcessingEvent) {
- // The output buffer contains the samples that will be modified and played
+ // The output buffer contains the samples that will be modified and played
_as_output_buffer = audioProcessingEvent.outputBuffer;
- audio_server_mix_function(_as_output_buffer.getChannelData(0).length);
- }
- }, buffer_latency);
+ jsAudioDriverMixFunction([_as_output_buffer.getChannelData(0).length]);
+ };
+ return _as_audioctx.sampleRate;
+ }, INTERNAL_BUFFER_SIZE, internal_buffer_channels);
/* clang-format on */
}
@@ -152,6 +137,7 @@ void AudioDriverJavaScript::finish() {
AudioDriverJavaScript::AudioDriverJavaScript() {
- mix_rate = 44100;
+ internal_buffer_channels = 2;
+ mix_rate = DEFAULT_MIX_RATE;
singleton_js = this;
}
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index c3adeca07b..b265c4e030 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -32,20 +32,15 @@
#include "servers/audio_server.h"
-#include "os/mutex.h"
-
class AudioDriverJavaScript : public AudioDriver {
enum {
INTERNAL_BUFFER_SIZE = 4096,
- STREAM_SCALE_BITS = 12
-
};
int mix_rate;
float *internal_buffer;
int internal_buffer_channels;
- int internal_buffer_size;
int32_t *stream_buffer;
public:
diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp
deleted file mode 100644
index ab9f66ce5b..0000000000
--- a/platform/javascript/audio_server_javascript.cpp
+++ /dev/null
@@ -1,853 +0,0 @@
-/*************************************************************************/
-/* audio_server_javascript.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://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 "audio_server_javascript.h"
-
-// FIXME: Needs to be ported to the new AudioServer API in 3.0
-#if 0
-#include "emscripten.h"
-
-AudioMixer *AudioServerJavascript::get_mixer() {
-
- return NULL;
-}
-
-void AudioServerJavascript::audio_mixer_chunk_callback(int p_frames){
-
-
-}
-
-
-RID AudioServerJavascript::sample_create(SampleFormat p_format, bool p_stereo, int p_length) {
-
- Sample *sample = memnew( Sample );
- sample->format=p_format;
- sample->stereo=p_stereo;
- sample->length=p_length;
- sample->loop_begin=0;
- sample->loop_end=p_length;
- sample->loop_format=SAMPLE_LOOP_NONE;
- sample->mix_rate=44100;
- sample->index=-1;
-
- return sample_owner.make_rid(sample);
-
-}
-
-void AudioServerJavascript::sample_set_description(RID p_sample, const String& p_description){
-
-
-}
-String AudioServerJavascript::sample_get_description(RID p_sample) const{
-
- return String();
-}
-
-AudioServerJavascript::SampleFormat AudioServerJavascript::sample_get_format(RID p_sample) const{
-
- return SAMPLE_FORMAT_PCM8;
-}
-bool AudioServerJavascript::sample_is_stereo(RID p_sample) const{
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,false);
- return sample->stereo;
-
-}
-int AudioServerJavascript::sample_get_length(RID p_sample) const{
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->length;
-}
-const void* AudioServerJavascript::sample_get_data_ptr(RID p_sample) const{
-
- return NULL;
-}
-
-void AudioServerJavascript::sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- int chans = sample->stereo?2:1;
-
- Vector<float> buffer;
- buffer.resize(sample->length*chans);
- PoolVector<uint8_t>::Read r=p_buffer.read();
- if (sample->format==SAMPLE_FORMAT_PCM8) {
- const int8_t*ptr = (const int8_t*)r.ptr();
- for(int i=0;i<sample->length*chans;i++) {
- buffer[i]=ptr[i]/128.0;
- }
- } else if (sample->format==SAMPLE_FORMAT_PCM16){
- const int16_t*ptr = (const int16_t*)r.ptr();
- for(int i=0;i<sample->length*chans;i++) {
- buffer[i]=ptr[i]/32768.0;
- }
- } else {
- ERR_EXPLAIN("Unsupported for now");
- ERR_FAIL();
- }
-
- sample->tmp_data=buffer;
-
-
-
-}
-PoolVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{
-
-
- return PoolVector<uint8_t>();
-}
-
-void AudioServerJavascript::sample_set_mix_rate(RID p_sample,int p_rate){
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->mix_rate=p_rate;
-
-}
-
-int AudioServerJavascript::sample_get_mix_rate(RID p_sample) const{
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->mix_rate;
-}
-
-
-void AudioServerJavascript::sample_set_loop_format(RID p_sample,SampleLoopFormat p_format){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->loop_format=p_format;
-
-}
-
-AudioServerJavascript::SampleLoopFormat AudioServerJavascript::sample_get_loop_format(RID p_sample) const {
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,SAMPLE_LOOP_NONE);
- return sample->loop_format;
-}
-
-void AudioServerJavascript::sample_set_loop_begin(RID p_sample,int p_pos){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->loop_begin=p_pos;
-
-}
-int AudioServerJavascript::sample_get_loop_begin(RID p_sample) const{
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->loop_begin;
-}
-
-void AudioServerJavascript::sample_set_loop_end(RID p_sample,int p_pos){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->loop_end=p_pos;
-
-}
-int AudioServerJavascript::sample_get_loop_end(RID p_sample) const{
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->loop_end;
-}
-
-
-/* VOICE API */
-
-RID AudioServerJavascript::voice_create(){
-
- Voice *voice = memnew( Voice );
-
- voice->index=voice_base;
- voice->volume=1.0;
- voice->pan=0.0;
- voice->pan_depth=.0;
- voice->pan_height=0.0;
- voice->chorus=0;
- voice->reverb_type=REVERB_SMALL;
- voice->reverb=0;
- voice->mix_rate=-1;
- voice->positional=false;
- voice->active=false;
-
- /* clang-format off */
- EM_ASM_( {
- _as_voices[$0] = null;
- _as_voice_gain[$0] = _as_audioctx.createGain();
- _as_voice_pan[$0] = _as_audioctx.createStereoPanner();
- _as_voice_gain[$0].connect(_as_voice_pan[$0]);
- _as_voice_pan[$0].connect(_as_audioctx.destination);
- }, voice_base);
- /* clang-format on */
-
- voice_base++;
-
- return voice_owner.make_rid( voice );
-}
-
-void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
- Sample *sample=sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
-
- // due to how webaudio works, sample cration is deferred until used
- // sorry! WebAudio absolutely sucks
-
-
- if (sample->index==-1) {
- //create sample if not created
- ERR_FAIL_COND(sample->tmp_data.size()==0);
- sample->index=sample_base;
- /* clang-format off */
- EM_ASM_({
- _as_samples[$0] = _as_audioctx.createBuffer($1, $2, $3);
- }, sample_base, sample->stereo ? 2 : 1, sample->length, sample->mix_rate);
- /* clang-format on */
-
- sample_base++;
- int chans = sample->stereo?2:1;
-
-
- for(int i=0;i<chans;i++) {
- /* clang-format off */
- EM_ASM_({
- _as_edited_buffer = _as_samples[$0].getChannelData($1);
- }, sample->index, i);
- /* clang-format on */
-
- for(int j=0;j<sample->length;j++) {
- /* clang-format off */
- EM_ASM_({
- _as_edited_buffer[$0] = $1;
- }, j, sample->tmp_data[j * chans + i]);
- /* clang-format on */
- }
- }
-
- sample->tmp_data.clear();
- }
-
-
- voice->sample_mix_rate=sample->mix_rate;
- if (voice->mix_rate==-1) {
- voice->mix_rate=voice->sample_mix_rate;
- }
-
- float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0);
- int detune = int(freq_diff*1200.0);
-
- /* clang-format off */
- EM_ASM_({
- if (_as_voices[$0] !== null) {
- _as_voices[$0].stop(); //stop and byebye
- }
- _as_voices[$0] = _as_audioctx.createBufferSource();
- _as_voices[$0].connect(_as_voice_gain[$0]);
- _as_voices[$0].buffer = _as_samples[$1];
- _as_voices[$0].loopStart.value = $1;
- _as_voices[$0].loopEnd.value = $2;
- _as_voices[$0].loop.value = $3;
- _as_voices[$0].detune.value = $6;
- _as_voice_pan[$0].pan.value = $4;
- _as_voice_gain[$0].gain.value = $5;
- _as_voices[$0].start();
- _as_voices[$0].onended = function() {
- _as_voices[$0].disconnect(_as_voice_gain[$0]);
- _as_voices[$0] = null;
- }
- }, voice->index, sample->index, sample->mix_rate * sample->loop_begin, sample->mix_rate * sample->loop_end, sample->loop_format != SAMPLE_LOOP_NONE, voice->pan, voice->volume * fx_volume_scale, detune);
- /* clang-format on */
-
- voice->active=true;
-}
-
-void AudioServerJavascript::voice_set_volume(RID p_voice, float p_volume){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- voice->volume=p_volume;
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- _as_voice_gain[$0].gain.value = $1;
- }, voice->index, voice->volume * fx_volume_scale);
- /* clang-format on */
- }
-
-}
-void AudioServerJavascript::voice_set_pan(RID p_voice, float p_pan, float p_depth,float height){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- voice->pan=p_pan;
- voice->pan_depth=p_depth;
- voice->pan_height=height;
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- _as_voice_pan[$0].pan.value = $1;
- }, voice->index, voice->pan);
- /* clang-format on */
- }
-}
-void AudioServerJavascript::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain){
-
-}
-void AudioServerJavascript::voice_set_chorus(RID p_voice, float p_chorus ){
-
-}
-void AudioServerJavascript::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb){
-
-}
-void AudioServerJavascript::voice_set_mix_rate(RID p_voice, int p_mix_rate){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- voice->mix_rate=p_mix_rate;
-
- if (voice->active) {
-
- float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0);
- int detune = int(freq_diff*1200.0);
- /* clang-format off */
- EM_ASM_({
- _as_voices[$0].detune.value = $1;
- }, voice->index, detune);
- /* clang-format on */
- }
-}
-void AudioServerJavascript::voice_set_positional(RID p_voice, bool p_positional){
-
-}
-
-float AudioServerJavascript::voice_get_volume(RID p_voice) const{
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->volume;
-}
-float AudioServerJavascript::voice_get_pan(RID p_voice) const{
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->pan;
-}
-float AudioServerJavascript::voice_get_pan_depth(RID p_voice) const{
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->pan_depth;
-}
-float AudioServerJavascript::voice_get_pan_height(RID p_voice) const{
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->pan_height;
-}
-AudioServerJavascript::FilterType AudioServerJavascript::voice_get_filter_type(RID p_voice) const{
-
- return FILTER_NONE;
-}
-float AudioServerJavascript::voice_get_filter_cutoff(RID p_voice) const{
-
- return 0;
-}
-float AudioServerJavascript::voice_get_filter_resonance(RID p_voice) const{
-
- return 0;
-}
-float AudioServerJavascript::voice_get_chorus(RID p_voice) const{
-
- return 0;
-}
-AudioServerJavascript::ReverbRoomType AudioServerJavascript::voice_get_reverb_type(RID p_voice) const{
-
- return REVERB_SMALL;
-}
-float AudioServerJavascript::voice_get_reverb(RID p_voice) const{
-
- return 0;
-}
-
-int AudioServerJavascript::voice_get_mix_rate(RID p_voice) const{
-
- return 44100;
-}
-
-bool AudioServerJavascript::voice_is_positional(RID p_voice) const{
-
- return false;
-}
-
-void AudioServerJavascript::voice_stop(RID p_voice){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- if (_as_voices[$0] !== null) {
- _as_voices[$0].stop();
- _as_voices[$0].disconnect(_as_voice_gain[$0]);
- _as_voices[$0] = null;
- }
- }, voice->index);
- /* clang-format on */
-
- voice->active=false;
- }
-
-
-}
-bool AudioServerJavascript::voice_is_active(RID p_voice) const{
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,false);
-
- return voice->active;
-}
-
-/* STREAM API */
-
-RID AudioServerJavascript::audio_stream_create(AudioStream *p_stream) {
-
-
- Stream *s = memnew(Stream);
- s->audio_stream=p_stream;
- s->event_stream=NULL;
- s->active=false;
- s->E=NULL;
- s->volume_scale=1.0;
- p_stream->set_mix_rate(webaudio_mix_rate);
-
- return stream_owner.make_rid(s);
-}
-
-RID AudioServerJavascript::event_stream_create(EventStream *p_stream) {
-
-
- Stream *s = memnew(Stream);
- s->audio_stream=NULL;
- s->event_stream=p_stream;
- s->active=false;
- s->E=NULL;
- s->volume_scale=1.0;
- //p_stream->set_mix_rate(AudioDriverJavascript::get_singleton()->get_mix_rate());
-
- return stream_owner.make_rid(s);
-
-
-}
-
-
-void AudioServerJavascript::stream_set_active(RID p_stream, bool p_active) {
-
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND(!s);
-
- if (s->active==p_active)
- return;
-
- s->active=p_active;
- if (p_active)
- s->E=active_audio_streams.push_back(s);
- else {
- active_audio_streams.erase(s->E);
- s->E=NULL;
- }
-}
-
-bool AudioServerJavascript::stream_is_active(RID p_stream) const {
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND_V(!s,false);
- return s->active;
-}
-
-void AudioServerJavascript::stream_set_volume_scale(RID p_stream, float p_scale) {
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND(!s);
- s->volume_scale=p_scale;
-
-}
-
-float AudioServerJavascript::stream_set_volume_scale(RID p_stream) const {
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND_V(!s,0);
- return s->volume_scale;
-
-}
-
-
-/* Audio Physics API */
-
-void AudioServerJavascript::free(RID p_id){
-
- if (voice_owner.owns(p_id)) {
- Voice* voice=voice_owner.get(p_id);
- ERR_FAIL_COND(!voice);
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- if (_as_voices[$0] !== null) {
- _as_voices[$0].stop();
- _as_voices[$0].disconnect(_as_voice_gain[$0]);
- }
- }, voice->index);
- /* clang-format on */
- }
-
- /* clang-format off */
- EM_ASM_({
- delete _as_voices[$0];
- _as_voice_gain[$0].disconnect(_as_voice_pan[$0]);
- delete _as_voice_gain[$0];
- _as_voice_pan[$0].disconnect(_as_audioctx.destination);
- delete _as_voice_pan[$0];
- }, voice->index);
- /* clang-format on */
-
- voice_owner.free(p_id);
- memdelete(voice);
-
- } else if (sample_owner.owns(p_id)) {
-
- Sample *sample = sample_owner.get(p_id);
- ERR_FAIL_COND(!sample);
-
- /* clang-format off */
- EM_ASM_({
- delete _as_samples[$0];
- }, sample->index);
- /* clang-format on */
-
- sample_owner.free(p_id);
- memdelete(sample);
-
- } else if (stream_owner.owns(p_id)) {
-
-
- Stream *s=stream_owner.get(p_id);
-
- if (s->active) {
- stream_set_active(p_id,false);
- }
-
- memdelete(s);
- stream_owner.free(p_id);
- }
-}
-
-extern "C" {
-
-
-void audio_server_mix_function(int p_frames) {
-
- //print_line("MIXI! "+itos(p_frames));
- static_cast<AudioServerJavascript*>(AudioServerJavascript::get_singleton())->mix_to_js(p_frames);
-}
-
-}
-
-void AudioServerJavascript::mix_to_js(int p_frames) {
-
-
- //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
- int todo=p_frames;
- int offset=0;
-
- while(todo) {
-
- int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
- driver_process_chunk(tomix);
-
- /* clang-format off */
- EM_ASM_({
- var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2);
-
- for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) {
- var outputData = _as_output_buffer.getChannelData(channel);
- // Loop through samples
- for (var sample = 0; sample < $2; sample++) {
- // make output equal to the same as the input
- outputData[sample + $1] = data[sample * 2 + channel];
- }
- }
- }, internal_buffer, offset, tomix);
- /* clang-format on */
-
- todo-=tomix;
- offset+=tomix;
- }
-}
-
-void AudioServerJavascript::init(){
-
- /*
- // clang-format off
- EM_ASM(
- console.log('server is ' + audio_server);
- );
- // clang-format on
- */
-
-
- //int latency = GLOBAL_DEF("javascript/audio_latency",16384);
-
- internal_buffer_channels=2;
- internal_buffer = memnew_arr(float,INTERNAL_BUFFER_SIZE*internal_buffer_channels);
- stream_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*4); //max 4 channels
-
- stream_volume=0.3;
-
- int buffer_latency=16384;
-
- /* clang-format off */
- EM_ASM_( {
- _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2);
- _as_script_node.connect(_as_audioctx.destination);
- console.log(_as_script_node.bufferSize);
-
- _as_script_node.onaudioprocess = function(audioProcessingEvent) {
- // The output buffer contains the samples that will be modified and played
- _as_output_buffer = audioProcessingEvent.outputBuffer;
- audio_server_mix_function(_as_output_buffer.getChannelData(0).length);
- }
- }, buffer_latency);
- /* clang-format on */
-
-
-}
-
-void AudioServerJavascript::finish(){
-
-}
-void AudioServerJavascript::update(){
-
- for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback
-
- List<Stream*>::Element *N=E->next();
-
- if (E->get()->audio_stream)
- E->get()->audio_stream->update();
-
- E=N;
- }
-}
-
-/* MISC config */
-
-void AudioServerJavascript::lock(){
-
-}
-void AudioServerJavascript::unlock(){
-
-}
-int AudioServerJavascript::get_default_channel_count() const{
-
- return 1;
-}
-int AudioServerJavascript::get_default_mix_rate() const{
-
- return 44100;
-}
-
-void AudioServerJavascript::set_stream_global_volume_scale(float p_volume){
-
- stream_volume_scale=p_volume;
-}
-void AudioServerJavascript::set_fx_global_volume_scale(float p_volume){
-
- fx_volume_scale=p_volume;
-}
-void AudioServerJavascript::set_event_voice_global_volume_scale(float p_volume){
-
-}
-
-float AudioServerJavascript::get_stream_global_volume_scale() const{
- return 1;
-}
-float AudioServerJavascript::get_fx_global_volume_scale() const{
-
- return 1;
-}
-float AudioServerJavascript::get_event_voice_global_volume_scale() const{
-
- return 1;
-}
-
-uint32_t AudioServerJavascript::read_output_peak() const{
-
- return 0;
-}
-
-AudioServerJavascript *AudioServerJavascript::singleton=NULL;
-
-AudioServer *AudioServerJavascript::get_singleton() {
- return singleton;
-}
-
-double AudioServerJavascript::get_mix_time() const{
-
- return 0;
-}
-double AudioServerJavascript::get_output_delay() const {
-
- return 0;
-}
-
-
-void AudioServerJavascript::driver_process_chunk(int p_frames) {
-
-
-
- int samples=p_frames*internal_buffer_channels;
-
- for(int i=0;i<samples;i++) {
- internal_buffer[i]=0;
- }
-
-
- for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) {
-
- ERR_CONTINUE(!E->get()->active); // bug?
-
-
- AudioStream *as=E->get()->audio_stream;
- if (!as)
- continue;
-
- int channels=as->get_channel_count();
- if (channels==0)
- continue; // does not want mix
- if (!as->mix(stream_buffer,p_frames))
- continue; //nothing was mixed!!
-
- int32_t stream_vol_scale=(stream_volume*stream_volume_scale*E->get()->volume_scale)*(1<<STREAM_SCALE_BITS);
-
-#define STRSCALE(m_val) ((((m_val >> STREAM_SCALE_BITS) * stream_vol_scale) >> 8) / 8388608.0)
- switch(channels) {
- case 1: {
-
- for(int i=0;i<p_frames;i++) {
-
- internal_buffer[(i<<1)+0]+=STRSCALE(stream_buffer[i]);
- internal_buffer[(i<<1)+1]+=STRSCALE(stream_buffer[i]);
- }
- } break;
- case 2: {
-
- for(int i=0;i<p_frames*2;i++) {
-
- internal_buffer[i]+=STRSCALE(stream_buffer[i]);
- }
- } break;
- case 4: {
-
- for(int i=0;i<p_frames;i++) {
-
- internal_buffer[(i<<2)+0]+=STRSCALE((stream_buffer[(i<<2)+0]+stream_buffer[(i<<2)+2])>>1);
- internal_buffer[(i<<2)+1]+=STRSCALE((stream_buffer[(i<<2)+1]+stream_buffer[(i<<2)+3])>>1);
- }
- } break;
-
-
- }
-
-#undef STRSCALE
- }
-}
-
-
-/*void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) {
-
-
- _output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate());
- //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
- int todo=p_frames;
- while(todo) {
-
- int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
- driver_process_chunk(tomix,p_buffer);
- p_buffer+=tomix;
- todo-=tomix;
- }
-
-
-}*/
-
-AudioServerJavascript::AudioServerJavascript() {
-
- singleton=this;
- sample_base=1;
- voice_base=1;
- /* clang-format off */
- EM_ASM(
- _as_samples = {};
- _as_voices = {};
- _as_voice_pan = {};
- _as_voice_gain = {};
-
- _as_audioctx = new (window.AudioContext || window.webkitAudioContext)();
-
- audio_server_mix_function = Module.cwrap('audio_server_mix_function', 'void', ['number']);
- );
- /* clang-format on */
-
- /* clang-format off */
- webaudio_mix_rate = EM_ASM_INT_V(
- return _as_audioctx.sampleRate;
- );
- /* clang-format on */
- print_line("WEBAUDIO MIX RATE: "+itos(webaudio_mix_rate));
- event_voice_scale=1.0;
- fx_volume_scale=1.0;
- stream_volume_scale=1.0;
-
-}
-#endif
diff --git a/platform/javascript/audio_server_javascript.h b/platform/javascript/audio_server_javascript.h
deleted file mode 100644
index 0773459f56..0000000000
--- a/platform/javascript/audio_server_javascript.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*************************************************************************/
-/* audio_server_javascript.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://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. */
-/*************************************************************************/
-#ifndef AUDIO_SERVER_JAVASCRIPT_H
-#define AUDIO_SERVER_JAVASCRIPT_H
-
-// FIXME: Needs to be ported to the new AudioServer API in 3.0
-#if 0
-#include "servers/audio_server.h"
-
-class AudioServerJavascript : public AudioServer {
-
- GDCLASS(AudioServerJavascript,AudioServer);
-
- enum {
- INTERNAL_BUFFER_SIZE=4096,
- STREAM_SCALE_BITS=12
-
- };
-
- AudioMixer *get_mixer();
- void audio_mixer_chunk_callback(int p_frames);
-
- struct Sample {
- SampleFormat format;
- SampleLoopFormat loop_format;
- int loop_begin;
- int loop_end;
- int length;
- int index;
- int mix_rate;
- bool stereo;
-
- Vector<float> tmp_data;
- };
-
- mutable RID_Owner<Sample> sample_owner;
- int sample_base;
-
- struct Voice {
- int index;
- float volume;
- float pan;
- float pan_depth;
- float pan_height;
-
- float chorus;
- ReverbRoomType reverb_type;
- float reverb;
-
- int mix_rate;
- int sample_mix_rate;
- bool positional;
-
- bool active;
-
- };
-
- mutable RID_Owner<Voice> voice_owner;
-
- int voice_base;
-
- struct Stream {
- bool active;
- List<Stream*>::Element *E;
- AudioStream *audio_stream;
- EventStream *event_stream;
- float volume_scale;
- };
-
- List<Stream*> active_audio_streams;
-
- //List<Stream*> event_streams;
-
- float * internal_buffer;
- int internal_buffer_channels;
- int32_t * stream_buffer;
-
- mutable RID_Owner<Stream> stream_owner;
-
- float stream_volume;
- float stream_volume_scale;
-
- float event_voice_scale;
- float fx_volume_scale;
-
-
- void driver_process_chunk(int p_frames);
-
- int webaudio_mix_rate;
-
-
- static AudioServerJavascript *singleton;
-public:
-
- void mix_to_js(int p_frames);
- /* SAMPLE API */
-
- virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length);
-
- virtual void sample_set_description(RID p_sample, const String& p_description);
- virtual String sample_get_description(RID p_sample) const;
-
- virtual SampleFormat sample_get_format(RID p_sample) const;
- virtual bool sample_is_stereo(RID p_sample) const;
- virtual int sample_get_length(RID p_sample) const;
- virtual const void* sample_get_data_ptr(RID p_sample) const;
-
-
- virtual void sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer);
- virtual PoolVector<uint8_t> sample_get_data(RID p_sample) const;
-
- virtual void sample_set_mix_rate(RID p_sample,int p_rate);
- virtual int sample_get_mix_rate(RID p_sample) const;
-
- virtual void sample_set_loop_format(RID p_sample,SampleLoopFormat p_format);
- virtual SampleLoopFormat sample_get_loop_format(RID p_sample) const;
-
- virtual void sample_set_loop_begin(RID p_sample,int p_pos);
- virtual int sample_get_loop_begin(RID p_sample) const;
-
- virtual void sample_set_loop_end(RID p_sample,int p_pos);
- virtual int sample_get_loop_end(RID p_sample) const;
-
-
- /* VOICE API */
-
- virtual RID voice_create();
-
- virtual void voice_play(RID p_voice, RID p_sample);
-
- virtual void voice_set_volume(RID p_voice, float p_volume);
- virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0); //pan and depth go from -1 to 1
- virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain=0);
- virtual void voice_set_chorus(RID p_voice, float p_chorus );
- virtual void voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb);
- virtual void voice_set_mix_rate(RID p_voice, int p_mix_rate);
- virtual void voice_set_positional(RID p_voice, bool p_positional);
-
- virtual float voice_get_volume(RID p_voice) const;
- virtual float voice_get_pan(RID p_voice) const; //pan and depth go from -1 to 1
- virtual float voice_get_pan_depth(RID p_voice) const; //pan and depth go from -1 to 1
- virtual float voice_get_pan_height(RID p_voice) const; //pan and depth go from -1 to 1
- virtual FilterType voice_get_filter_type(RID p_voice) const;
- virtual float voice_get_filter_cutoff(RID p_voice) const;
- virtual float voice_get_filter_resonance(RID p_voice) const;
- virtual float voice_get_chorus(RID p_voice) const;
- virtual ReverbRoomType voice_get_reverb_type(RID p_voice) const;
- virtual float voice_get_reverb(RID p_voice) const;
-
- virtual int voice_get_mix_rate(RID p_voice) const;
- virtual bool voice_is_positional(RID p_voice) const;
-
- virtual void voice_stop(RID p_voice);
- virtual bool voice_is_active(RID p_voice) const;
-
- /* STREAM API */
-
- virtual RID audio_stream_create(AudioStream *p_stream);
- virtual RID event_stream_create(EventStream *p_stream);
-
- virtual void stream_set_active(RID p_stream, bool p_active);
- virtual bool stream_is_active(RID p_stream) const;
-
- virtual void stream_set_volume_scale(RID p_stream, float p_scale);
- virtual float stream_set_volume_scale(RID p_stream) const;
-
- /* Audio Physics API */
-
- virtual void free(RID p_id);
-
- virtual void init();
- virtual void finish();
- virtual void update();
-
- /* MISC config */
-
- virtual void lock();
- virtual void unlock();
- virtual int get_default_channel_count() const;
- virtual int get_default_mix_rate() const;
-
- virtual void set_stream_global_volume_scale(float p_volume);
- virtual void set_fx_global_volume_scale(float p_volume);
- virtual void set_event_voice_global_volume_scale(float p_volume);
-
- virtual float get_stream_global_volume_scale() const;
- virtual float get_fx_global_volume_scale() const;
- virtual float get_event_voice_global_volume_scale() const;
-
- virtual uint32_t read_output_peak() const;
-
- static AudioServer *get_singleton();
-
- virtual double get_mix_time() const; //useful for video -> audio sync
- virtual double get_output_delay() const;
-
-
- AudioServerJavascript();
-};
-
-#endif // AUDIO_SERVER_JAVASCRIPT_H
-#endif
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index a2988d9c60..8472c3ccab 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -19,7 +19,6 @@ def can_build():
def get_opts():
from SCons.Variables import BoolVariable
return [
- BoolVariable('wasm', 'Compile to WebAssembly', False),
BoolVariable('javascript_eval', 'Enable JavaScript eval interface', True),
]
@@ -103,20 +102,13 @@ def configure(env):
## Link flags
- env.Append(LINKFLAGS=['-s', 'EXTRA_EXPORTED_RUNTIME_METHODS="[\'FS\']"'])
+ env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
+ env.Append(LINKFLAGS=['-s', 'ALLOW_MEMORY_GROWTH=1'])
env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1'])
+ env.Append(LINKFLAGS=['-s', 'EXTRA_EXPORTED_RUNTIME_METHODS="[\'FS\']"'])
- if env['wasm']:
- env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
- # In contrast to asm.js, enabling memory growth on WebAssembly has no
- # major performance impact, and causes only a negligible increase in
- # memory size.
- env.Append(LINKFLAGS=['-s', 'ALLOW_MEMORY_GROWTH=1'])
- env.extra_suffix = '.webassembly' + env.extra_suffix
- else:
- env.Append(LINKFLAGS=['-s', 'ASM_JS=1'])
- env.Append(LINKFLAGS=['--separate-asm'])
- env.Append(LINKFLAGS=['--memory-init-file', '1'])
+ env.Append(LINKFLAGS=['-s', 'INVOKE_RUN=0'])
+ env.Append(LINKFLAGS=['-s', 'NO_EXIT_RUNTIME=1'])
# TODO: Move that to opus module's config
if 'module_opus_enabled' in env and env['module_opus_enabled']:
diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js
index 99d1c20bbd..dc4bdc7efb 100644
--- a/platform/javascript/engine.js
+++ b/platform/javascript/engine.js
@@ -5,7 +5,6 @@
(function() {
var engine = Engine;
- var USING_WASM = engine.USING_WASM;
var DOWNLOAD_ATTEMPTS_MAX = 4;
var basePath = null;
@@ -32,87 +31,101 @@
this.rtenv = null;
- var gameInitPromise = null;
+ var initPromise = null;
var unloadAfterInit = true;
- var memorySize = 268435456;
+ var preloadedFiles = [];
+
+ var resizeCanvasOnStart = true;
var progressFunc = null;
- var pckProgressTracker = {};
+ var preloadProgressTracker = {};
var lastProgress = { loaded: 0, total: 0 };
var canvas = null;
+ var executableName = null;
+ var locale = null;
var stdout = null;
var stderr = null;
- this.initGame = function(mainPack) {
-
- if (!gameInitPromise) {
+ this.init = function(newBasePath) {
- if (mainPack === undefined) {
- if (basePath !== null) {
- mainPack = basePath + '.pck';
- } else {
- return Promise.reject(new Error("No main pack to load specified"));
- }
- }
- if (basePath === null)
- basePath = getBasePath(mainPack);
-
- gameInitPromise = Engine.initEngine().then(
+ if (!initPromise) {
+ initPromise = Engine.load(newBasePath).then(
instantiate.bind(this)
);
- var gameLoadPromise = loadPromise(mainPack, pckProgressTracker).then(function(xhr) { return xhr.response; });
- gameInitPromise = Promise.all([gameLoadPromise, gameInitPromise]).then(function(values) {
- // resolve with pck
- return new Uint8Array(values[0]);
- });
- if (unloadAfterInit)
- gameInitPromise.then(Engine.unloadEngine);
requestAnimationFrame(animateProgress);
+ if (unloadAfterInit)
+ initPromise.then(Engine.unloadEngine);
}
- return gameInitPromise;
+ return initPromise;
};
- function instantiate(initializer) {
+ function instantiate(wasmBuf) {
- var rtenvOpts = {
- noInitialRun: true,
- thisProgram: getBaseName(basePath),
+ var rtenvProps = {
engine: this,
+ ENV: {},
};
if (typeof stdout === 'function')
- rtenvOpts.print = stdout;
+ rtenvProps.print = stdout;
if (typeof stderr === 'function')
- rtenvOpts.printErr = stderr;
- if (typeof WebAssembly === 'object' && initializer instanceof ArrayBuffer) {
- rtenvOpts.instantiateWasm = function(imports, onSuccess) {
- WebAssembly.instantiate(initializer, imports).then(function(result) {
- onSuccess(result.instance);
- });
- return {};
- };
- } else if (initializer.asm && initializer.mem) {
- rtenvOpts.asm = initializer.asm;
- rtenvOpts.memoryInitializerRequest = initializer.mem;
- rtenvOpts.TOTAL_MEMORY = memorySize;
- } else {
- throw new Error("Invalid initializer");
- }
+ rtenvProps.printErr = stderr;
+ rtenvProps.instantiateWasm = function(imports, onSuccess) {
+ WebAssembly.instantiate(wasmBuf, imports).then(function(result) {
+ onSuccess(result.instance);
+ });
+ return {};
+ };
return new Promise(function(resolve, reject) {
- rtenvOpts.onRuntimeInitialized = resolve;
- rtenvOpts.onAbort = reject;
- rtenvOpts.engine.rtenv = Engine.RuntimeEnvironment(rtenvOpts);
+ rtenvProps.onRuntimeInitialized = resolve;
+ rtenvProps.onAbort = reject;
+ rtenvProps.engine.rtenv = Engine.RuntimeEnvironment(rtenvProps);
});
}
- this.start = function(mainPack) {
+ this.preloadFile = function(pathOrBuffer, bufferFilename) {
+
+ if (pathOrBuffer instanceof ArrayBuffer) {
+ pathOrBuffer = new Uint8Array(pathOrBuffer);
+ } else if (ArrayBuffer.isView(pathOrBuffer)) {
+ pathOrBuffer = new Uint8Array(pathOrBuffer.buffer);
+ }
+ if (pathOrBuffer instanceof Uint8Array) {
+ preloadedFiles.push({
+ name: bufferFilename,
+ buffer: pathOrBuffer
+ });
+ return Promise.resolve();
+ } else if (typeof pathOrBuffer === 'string') {
+ return loadPromise(pathOrBuffer, preloadProgressTracker).then(function(xhr) {
+ preloadedFiles.push({
+ name: pathOrBuffer,
+ buffer: xhr.response
+ });
+ });
+ } else {
+ throw Promise.reject("Invalid object for preloading");
+ }
+ };
+
+ this.start = function() {
+
+ return this.init().then(
+ Function.prototype.apply.bind(synchronousStart, this, arguments)
+ );
+ };
+
+ this.startGame = function(mainPack) {
- return this.initGame(mainPack).then(synchronousStart.bind(this));
+ executableName = getBaseName(mainPack);
+ return Promise.all([this.init(getBasePath(mainPack)), this.preloadFile(mainPack)]).then(
+ Function.prototype.apply.bind(synchronousStart, this, [])
+ );
};
- function synchronousStart(pckView) {
- // TODO don't expect canvas when runninng as cli tool
+ function synchronousStart() {
+
if (canvas instanceof HTMLCanvasElement) {
this.rtenv.canvas = canvas;
} else {
@@ -147,15 +160,33 @@
ev.preventDefault();
}, false);
- this.rtenv.FS.createDataFile('/', this.rtenv.thisProgram + '.pck', pckView, true, true, true);
- gameInitPromise = null;
- this.rtenv.callMain();
+ if (locale) {
+ this.rtenv.locale = locale;
+ } else {
+ this.rtenv.locale = navigator.languages ? navigator.languages[0] : navigator.language;
+ }
+ this.rtenv.locale = this.rtenv.locale.split('.')[0];
+ this.rtenv.resizeCanvasOnStart = resizeCanvasOnStart;
+
+ this.rtenv.thisProgram = executableName || getBaseName(basePath);
+
+ preloadedFiles.forEach(function(file) {
+ this.rtenv.FS.createDataFile('/', file.name, new Uint8Array(file.buffer), true, true, true);
+ }, this);
+
+ preloadedFiles = null;
+ initPromise = null;
+ this.rtenv.callMain(arguments);
}
this.setProgressFunc = function(func) {
progressFunc = func;
};
+ this.setResizeCanvasOnStart = function(enabled) {
+ resizeCanvasOnStart = enabled;
+ };
+
function animateProgress() {
var loaded = 0;
@@ -163,7 +194,7 @@
var totalIsValid = true;
var progressIsFinal = true;
- [loadingFiles, pckProgressTracker].forEach(function(tracker) {
+ [loadingFiles, preloadProgressTracker].forEach(function(tracker) {
Object.keys(tracker).forEach(function(file) {
if (!tracker[file].final)
progressIsFinal = false;
@@ -190,14 +221,20 @@
canvas = elem;
};
- this.setAsmjsMemorySize = function(size) {
- memorySize = size;
+ this.setExecutableName = function(newName) {
+
+ executableName = newName;
+ };
+
+ this.setLocale = function(newLocale) {
+
+ locale = newLocale;
};
this.setUnloadAfterInit = function(enabled) {
- if (enabled && !unloadAfterInit && gameInitPromise) {
- gameInitPromise.then(Engine.unloadEngine);
+ if (enabled && !unloadAfterInit && initPromise) {
+ initPromise.then(Engine.unloadEngine);
}
unloadAfterInit = enabled;
};
@@ -232,26 +269,16 @@
Engine.RuntimeEnvironment = engine.RuntimeEnvironment;
- Engine.initEngine = function(newBasePath) {
+ Engine.load = function(newBasePath) {
if (newBasePath !== undefined) basePath = getBasePath(newBasePath);
if (engineLoadPromise === null) {
- if (USING_WASM) {
- if (typeof WebAssembly !== 'object')
- return Promise.reject(new Error("Browser doesn't support WebAssembly"));
- // TODO cache/retrieve module to/from idb
- engineLoadPromise = loadPromise(basePath + '.wasm').then(function(xhr) {
- return xhr.response;
- });
- } else {
- var asmjsPromise = loadPromise(basePath + '.asm.js').then(function(xhr) {
- return asmjsModulePromise(xhr.response);
- });
- var memPromise = loadPromise(basePath + '.mem');
- engineLoadPromise = Promise.all([asmjsPromise, memPromise]).then(function(values) {
- return { asm: values[0], mem: values[1] };
- });
- }
+ if (typeof WebAssembly !== 'object')
+ return Promise.reject(new Error("Browser doesn't support WebAssembly"));
+ // TODO cache/retrieve module to/from idb
+ engineLoadPromise = loadPromise(basePath + '.wasm').then(function(xhr) {
+ return xhr.response;
+ });
engineLoadPromise = engineLoadPromise.catch(function(err) {
engineLoadPromise = null;
throw err;
@@ -260,34 +287,7 @@
return engineLoadPromise;
};
- function asmjsModulePromise(module) {
- var elem = document.createElement('script');
- var script = new Blob([
- 'Engine.asm = (function() { var Module = {};',
- module,
- 'return Module.asm; })();'
- ]);
- var url = URL.createObjectURL(script);
- elem.src = url;
- return new Promise(function(resolve, reject) {
- elem.addEventListener('load', function() {
- URL.revokeObjectURL(url);
- var asm = Engine.asm;
- Engine.asm = undefined;
- setTimeout(function() {
- // delay to reclaim compilation memory
- resolve(asm);
- }, 1);
- });
- elem.addEventListener('error', function() {
- URL.revokeObjectURL(url);
- reject("asm.js faiilure");
- });
- document.body.appendChild(elem);
- });
- }
-
- Engine.unloadEngine = function() {
+ Engine.unload = function() {
engineLoadPromise = null;
};
@@ -306,7 +306,7 @@
if (!file.endsWith('.js')) {
xhr.responseType = 'arraybuffer';
}
- ['loadstart', 'progress', 'load', 'error', 'timeout', 'abort'].forEach(function(ev) {
+ ['loadstart', 'progress', 'load', 'error', 'abort'].forEach(function(ev) {
xhr.addEventListener(ev, onXHREvent.bind(xhr, resolve, reject, file, tracker));
});
xhr.send();
@@ -321,7 +321,7 @@
this.abort();
return;
} else {
- loadXHR(resolve, reject, file);
+ setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
}
}
@@ -348,12 +348,11 @@
break;
case 'error':
- case 'timeout':
if (++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
tracker[file].final = true;
reject(new Error("Failed loading file '" + file + "'"));
} else {
- loadXHR(resolve, reject, file);
+ setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
}
break;
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 4a97bf4c32..775e9c7ee0 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -30,13 +30,12 @@
#include "editor/editor_node.h"
#include "editor_export.h"
#include "io/zip_io.h"
+#include "main/splash.gen.h"
#include "platform/javascript/logo.gen.h"
#include "platform/javascript/run_icon.gen.h"
#define EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE "webassembly_release.zip"
#define EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG "webassembly_debug.zip"
-#define EXPORT_TEMPLATE_ASMJS_RELEASE "javascript_release.zip"
-#define EXPORT_TEMPLATE_ASMJS_DEBUG "javascript_debug.zip"
class EditorExportPlatformJavaScript : public EditorExportPlatform {
@@ -47,18 +46,11 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
bool runnable_when_last_polled;
void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug);
- void _fix_fsloader_js(Vector<uint8_t> &p_js, const String &p_pack_name, uint64_t p_pack_size);
public:
- enum Target {
- TARGET_WEBASSEMBLY,
- TARGET_ASMJS
- };
-
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
virtual void get_export_options(List<ExportOption> *r_options);
- 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;
@@ -90,17 +82,9 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
String str_export;
Vector<String> lines = str_template.split("\n");
- int memory_mb;
- if (p_preset->get("options/target").operator int() != TARGET_ASMJS)
- // WebAssembly allows memory growth, so start with a reasonable default
- memory_mb = 1 << 4;
- else
- memory_mb = 1 << (p_preset->get("options/memory_size").operator int() + 5);
-
for (int i = 0; i < lines.size(); i++) {
String current_line = lines[i];
- current_line = current_line.replace("$GODOT_TOTAL_MEMORY", itos(memory_mb * 1024 * 1024));
current_line = current_line.replace("$GODOT_BASENAME", p_name);
current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include"));
current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false");
@@ -129,24 +113,15 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "options/target", PROPERTY_HINT_ENUM, "WebAssembly,asm.js"), TARGET_WEBASSEMBLY));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "options/memory_size", PROPERTY_HINT_ENUM, "32 MB,64 MB,128 MB,256 MB,512 MB,1 GB"), 3));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_GLOBAL_FILE, "html"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
}
-bool EditorExportPlatformJavaScript::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
- if (p_option == "options/memory_size") {
- return p_options["options/target"].operator int() == TARGET_ASMJS;
- }
- return true;
-}
-
String EditorExportPlatformJavaScript::get_name() const {
return "HTML5";
@@ -166,17 +141,10 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p
r_missing_templates = false;
- if (p_preset->get("options/target").operator int() == TARGET_WEBASSEMBLY) {
- if (find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE) == String())
- r_missing_templates = true;
- else if (find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG) == String())
- r_missing_templates = true;
- } else {
- if (find_export_template(EXPORT_TEMPLATE_ASMJS_RELEASE) == String())
- r_missing_templates = true;
- else if (find_export_template(EXPORT_TEMPLATE_ASMJS_DEBUG) == String())
- r_missing_templates = true;
- }
+ if (find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE) == String())
+ r_missing_templates = true;
+ else if (find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG) == String())
+ r_missing_templates = true;
return !r_missing_templates;
}
@@ -187,9 +155,11 @@ String EditorExportPlatformJavaScript::get_binary_extension() const {
}
Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String custom_debug = p_preset->get("custom_template/debug");
String custom_release = p_preset->get("custom_template/release");
+ String custom_html = p_preset->get("html/custom_html_shell");
String template_path = p_debug ? custom_debug : custom_release;
@@ -197,17 +167,10 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
if (template_path == String()) {
- if (p_preset->get("options/target").operator int() == TARGET_WEBASSEMBLY) {
- if (p_debug)
- template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG);
- else
- template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE);
- } else {
- if (p_debug)
- template_path = find_export_template(EXPORT_TEMPLATE_ASMJS_DEBUG);
- else
- template_path = find_export_template(EXPORT_TEMPLATE_ASMJS_RELEASE);
- }
+ if (p_debug)
+ template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG);
+ else
+ template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE);
}
if (template_path != String() && !FileAccess::exists(template_path)) {
@@ -222,14 +185,6 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return error;
}
- FileAccess *f = FileAccess::open(pck_path, FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:\n") + pck_path);
- return ERR_FILE_CANT_READ;
- }
- size_t pack_size = f->get_len();
- memdelete(f);
-
FileAccess *src_f = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(template_path.utf8().get_data(), &io);
@@ -240,13 +195,17 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return ERR_FILE_NOT_FOUND;
}
- int ret = unzGoToFirstFile(pkg);
- while (ret == UNZ_OK) {
+ if (unzGoToFirstFile(pkg) != UNZ_OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid export template:\n") + template_path);
+ unzClose(pkg);
+ return ERR_FILE_CORRUPT;
+ }
+ do {
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
String file = fname;
@@ -255,27 +214,25 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
//read
unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptr(), data.size());
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
//write
if (file == "godot.html") {
+ if (!custom_html.empty()) {
+ continue;
+ }
_fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug);
file = p_path.get_file();
+
} else if (file == "godot.js") {
file = p_path.get_file().get_basename() + ".js";
} else if (file == "godot.wasm") {
file = p_path.get_file().get_basename() + ".wasm";
- } else if (file == "godot.asm.js") {
-
- file = p_path.get_file().get_basename() + ".asm.js";
- } else if (file == "godot.mem") {
-
- file = p_path.get_file().get_basename() + ".mem";
}
String dst = p_path.get_base_dir().plus_file(file);
@@ -288,9 +245,50 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
f->store_buffer(data.ptr(), data.size());
memdelete(f);
- ret = unzGoToNextFile(pkg);
+ } while (unzGoToNextFile(pkg) == UNZ_OK);
+ unzClose(pkg);
+
+ if (!custom_html.empty()) {
+
+ FileAccess *f = FileAccess::open(custom_html, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:\n") + custom_html);
+ return ERR_FILE_CANT_READ;
+ }
+ Vector<uint8_t> buf;
+ buf.resize(f->get_len());
+ f->get_buffer(buf.ptrw(), buf.size());
+ memdelete(f);
+ _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug);
+
+ f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:\n") + p_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(buf.ptr(), buf.size());
+ memdelete(f);
}
+ Ref<Image> splash;
+ String splash_path = GLOBAL_GET("application/boot_splash/image");
+ splash_path = splash_path.strip_edges();
+ if (!splash_path.empty()) {
+ splash.instance();
+ Error err = splash->load(splash_path);
+ if (err) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:\n") + splash_path + "\nUsing default boot splash image");
+ splash.unref();
+ }
+ }
+ if (splash.is_null()) {
+ splash = Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+ String png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png");
+ if (splash->save_png(png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:\n") + png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
return OK;
}
@@ -319,7 +317,7 @@ int EditorExportPlatformJavaScript::get_device_count() const {
Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
- String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmp_export.html";
+ String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_export.html");
Error err = export_project(p_preset, true, path, p_debug_flags);
if (err) {
return err;
diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc
new file mode 100644
index 0000000000..9e4edf7848
--- /dev/null
+++ b/platform/javascript/http_client.h.inc
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* http_client.h.inc */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+
+// HTTPClient's additional private members in the javascript platform
+
+Error prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers);
+
+int xhr_id;
+int read_limit;
+int response_read_offset;
+Status status;
+
+String host;
+int port;
+bool use_tls;
+String username;
+String password;
+
+int polled_response_code;
+String polled_response_header;
+PoolByteArray polled_response;
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
new file mode 100644
index 0000000000..0b105dcb40
--- /dev/null
+++ b/platform/javascript/http_client_javascript.cpp
@@ -0,0 +1,282 @@
+/*************************************************************************/
+/* http_client_javascript.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 "http_request.h"
+#include "io/http_client.h"
+
+Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
+
+ close();
+ if (p_ssl && !p_verify_host) {
+ WARN_PRINT("Disabling HTTPClient's host verification is not supported for the HTML5 platform, host will be verified");
+ }
+
+ host = p_host;
+ if (host.begins_with("http://")) {
+ host.replace_first("http://", "");
+ } else if (host.begins_with("https://")) {
+ host.replace_first("https://", "");
+ }
+
+ status = host.is_valid_ip_address() ? STATUS_CONNECTING : STATUS_RESOLVING;
+ port = p_port;
+ use_tls = p_ssl;
+ return OK;
+}
+
+void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) {
+
+ ERR_EXPLAIN("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform");
+ ERR_FAIL();
+}
+
+Ref<StreamPeer> HTTPClient::get_connection() const {
+
+ ERR_EXPLAIN("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform");
+ ERR_FAIL_V(REF());
+}
+
+Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers) {
+
+ ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(host.empty(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED);
+
+ static const char *_methods[HTTPClient::METHOD_MAX] = {
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "OPTIONS",
+ "TRACE",
+ "CONNECT"
+ };
+
+ String url = (use_tls ? "https://" : "http://") + host + ":" + itos(port) + "/" + p_url;
+ godot_xhr_reset(xhr_id);
+ godot_xhr_open(xhr_id, _methods[p_method], url.utf8().get_data(),
+ username.empty() ? NULL : username.utf8().get_data(),
+ password.empty() ? NULL : password.utf8().get_data());
+
+ for (int i = 0; i < p_headers.size(); i++) {
+ int header_separator = p_headers[i].find(": ");
+ ERR_FAIL_COND_V(header_separator < 0, ERR_INVALID_PARAMETER);
+ godot_xhr_set_request_header(xhr_id,
+ p_headers[i].left(header_separator).utf8().get_data(),
+ p_headers[i].right(header_separator + 2).utf8().get_data());
+ }
+ response_read_offset = 0;
+ status = STATUS_REQUESTING;
+ return OK;
+}
+
+Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) {
+
+ Error err = prepare_request(p_method, p_url, p_headers);
+ if (err != OK)
+ return err;
+ PoolByteArray::Read read = p_body.read();
+ godot_xhr_send_data(xhr_id, read.ptr(), p_body.size());
+ return OK;
+}
+
+Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) {
+
+ Error err = prepare_request(p_method, p_url, p_headers);
+ if (err != OK)
+ return err;
+ godot_xhr_send_string(xhr_id, p_body.utf8().get_data());
+ return OK;
+}
+
+void HTTPClient::close() {
+
+ host = "";
+ port = -1;
+ use_tls = false;
+ status = STATUS_DISCONNECTED;
+ polled_response.resize(0);
+ polled_response_code = 0;
+ polled_response_header = String();
+ godot_xhr_reset(xhr_id);
+}
+
+HTTPClient::Status HTTPClient::get_status() const {
+
+ return status;
+}
+
+bool HTTPClient::has_response() const {
+
+ return !polled_response_header.empty();
+}
+
+bool HTTPClient::is_response_chunked() const {
+
+ // TODO evaluate using moz-chunked-arraybuffer, fetch & ReadableStream
+ return false;
+}
+
+int HTTPClient::get_response_code() const {
+
+ return polled_response_code;
+}
+
+Error HTTPClient::get_response_headers(List<String> *r_response) {
+
+ if (!polled_response_header.size())
+ return ERR_INVALID_PARAMETER;
+
+ Vector<String> header_lines = polled_response_header.split("\r\n", false);
+ for (int i = 0; i < header_lines.size(); ++i) {
+ r_response->push_back(header_lines[i]);
+ }
+ polled_response_header = String();
+ return OK;
+}
+
+int HTTPClient::get_response_body_length() const {
+
+ return polled_response.size();
+}
+
+PoolByteArray HTTPClient::read_response_body_chunk() {
+
+ ERR_FAIL_COND_V(status != STATUS_BODY, PoolByteArray());
+
+ int to_read = MIN(read_limit, polled_response.size() - response_read_offset);
+ PoolByteArray chunk;
+ chunk.resize(to_read);
+ PoolByteArray::Write write = chunk.write();
+ PoolByteArray::Read read = polled_response.read();
+ memcpy(write.ptr(), read.ptr() + response_read_offset, to_read);
+ write = PoolByteArray::Write();
+ read = PoolByteArray::Read();
+ response_read_offset += to_read;
+
+ if (response_read_offset == polled_response.size()) {
+ status = STATUS_CONNECTED;
+ polled_response.resize(0);
+ polled_response_code = 0;
+ polled_response_header = String();
+ godot_xhr_reset(xhr_id);
+ }
+
+ return chunk;
+}
+
+void HTTPClient::set_blocking_mode(bool p_enable) {
+
+ ERR_EXPLAIN("HTTPClient blocking mode is not supported for the HTML5 platform");
+ ERR_FAIL_COND(p_enable);
+}
+
+bool HTTPClient::is_blocking_mode_enabled() const {
+
+ return false;
+}
+
+void HTTPClient::set_read_chunk_size(int p_size) {
+
+ read_limit = p_size;
+}
+
+Error HTTPClient::poll() {
+
+ switch (status) {
+
+ case STATUS_DISCONNECTED:
+ return ERR_UNCONFIGURED;
+
+ case STATUS_RESOLVING:
+ status = STATUS_CONNECTING;
+ return OK;
+
+ case STATUS_CONNECTING:
+ status = STATUS_CONNECTED;
+ return OK;
+
+ case STATUS_CONNECTED:
+ case STATUS_BODY:
+ return OK;
+
+ case STATUS_CONNECTION_ERROR:
+ return ERR_CONNECTION_ERROR;
+
+ case STATUS_REQUESTING:
+ polled_response_code = godot_xhr_get_status(xhr_id);
+ int response_length = godot_xhr_get_response_length(xhr_id);
+ if (response_length == 0) {
+ godot_xhr_ready_state_t ready_state = godot_xhr_get_ready_state(xhr_id);
+ if (ready_state == XHR_READY_STATE_HEADERS_RECEIVED || ready_state == XHR_READY_STATE_LOADING) {
+ return OK;
+ } else {
+ status = STATUS_CONNECTION_ERROR;
+ return ERR_CONNECTION_ERROR;
+ }
+ }
+
+ status = STATUS_BODY;
+
+ PoolByteArray bytes;
+ int len = godot_xhr_get_response_headers_length(xhr_id);
+ bytes.resize(len);
+ PoolByteArray::Write write = bytes.write();
+ godot_xhr_get_response_headers(xhr_id, reinterpret_cast<char *>(write.ptr()), len);
+ write = PoolByteArray::Write();
+
+ PoolByteArray::Read read = bytes.read();
+ polled_response_header = String::utf8(reinterpret_cast<const char *>(read.ptr()));
+ read = PoolByteArray::Read();
+
+ polled_response.resize(response_length);
+ write = polled_response.write();
+ godot_xhr_get_response(xhr_id, write.ptr(), response_length);
+ write = PoolByteArray::Write();
+ break;
+ }
+ return OK;
+}
+
+HTTPClient::HTTPClient() {
+
+ xhr_id = godot_xhr_new();
+ read_limit = 4096;
+ status = STATUS_DISCONNECTED;
+ port = -1;
+ use_tls = false;
+ polled_response_code = 0;
+}
+
+HTTPClient::~HTTPClient() {
+
+ godot_xhr_free(xhr_id);
+}
diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h
new file mode 100644
index 0000000000..06d9239004
--- /dev/null
+++ b/platform/javascript/http_request.h
@@ -0,0 +1,74 @@
+/*************************************************************************/
+/* http_request.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. */
+/*************************************************************************/
+#ifndef HTTP_REQUEST_H
+#define HTTP_REQUEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stddef.h"
+
+typedef enum {
+ XHR_READY_STATE_UNSENT = 0,
+ XHR_READY_STATE_OPENED = 1,
+ XHR_READY_STATE_HEADERS_RECEIVED = 2,
+ XHR_READY_STATE_LOADING = 3,
+ XHR_READY_STATE_DONE = 4,
+} godot_xhr_ready_state_t;
+
+extern int godot_xhr_new();
+extern void godot_xhr_reset(int p_xhr_id);
+extern bool godot_xhr_free(int p_xhr_id);
+
+extern int godot_xhr_open(int p_xhr_id, const char *p_method, const char *p_url, const char *p_user = NULL, const char *p_password = NULL);
+
+extern void godot_xhr_set_request_header(int p_xhr_id, const char *p_header, const char *p_value);
+
+extern void godot_xhr_send_null(int p_xhr_id);
+extern void godot_xhr_send_string(int p_xhr_id, const char *p_data);
+extern void godot_xhr_send_data(int p_xhr_id, const void *p_data, int p_len);
+extern void godot_xhr_abort(int p_xhr_id);
+
+/* this is an HTTPClient::ResponseCode, not ::Status */
+extern int godot_xhr_get_status(int p_xhr_id);
+extern godot_xhr_ready_state_t godot_xhr_get_ready_state(int p_xhr_id);
+
+extern int godot_xhr_get_response_headers_length(int p_xhr_id);
+extern void godot_xhr_get_response_headers(int p_xhr_id, char *r_dst, int p_len);
+
+extern int godot_xhr_get_response_length(int p_xhr_id);
+extern void godot_xhr_get_response(int p_xhr_id, void *r_dst, int p_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HTTP_REQUEST_H */
diff --git a/platform/javascript/http_request.js b/platform/javascript/http_request.js
new file mode 100644
index 0000000000..f30240b41b
--- /dev/null
+++ b/platform/javascript/http_request.js
@@ -0,0 +1,145 @@
+/*************************************************************************/
+/* http_request.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+var GodotHTTPRequest = {
+
+ $GodotHTTPRequest: {
+
+ requests: [],
+
+ getUnusedRequestId: function() {
+ var idMax = GodotHTTPRequest.requests.length;
+ for (var potentialId = 0; potentialId < idMax; ++potentialId) {
+ if (GodotHTTPRequest.requests[potentialId] instanceof XMLHttpRequest) {
+ continue;
+ }
+ return potentialId;
+ }
+ GodotHTTPRequest.requests.push(null)
+ return idMax;
+ },
+
+ setupRequest: function(xhr) {
+ xhr.responseType = 'arraybuffer';
+ },
+ },
+
+ godot_xhr_new: function() {
+ var newId = GodotHTTPRequest.getUnusedRequestId();
+ GodotHTTPRequest.requests[newId] = new XMLHttpRequest;
+ GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[newId]);
+ return newId;
+ },
+
+ godot_xhr_reset: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest;
+ GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]);
+ },
+
+ godot_xhr_free: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId].abort();
+ GodotHTTPRequest.requests[xhrId] = null;
+ },
+
+ godot_xhr_open: function(xhrId, method, url, user, password) {
+ user = user > 0 ? UTF8ToString(user) : null;
+ password = password > 0 ? UTF8ToString(password) : null;
+ GodotHTTPRequest.requests[xhrId].open(UTF8ToString(method), UTF8ToString(url), true, user, password);
+ },
+
+ godot_xhr_set_request_header: function(xhrId, header, value) {
+ GodotHTTPRequest.requests[xhrId].setRequestHeader(UTF8ToString(header), UTF8ToString(value));
+ },
+
+ godot_xhr_send_null: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId].send();
+ },
+
+ godot_xhr_send_string: function(xhrId, strPtr) {
+ if (!strPtr) {
+ Module.printErr("Failed to send string per XHR: null pointer");
+ return;
+ }
+ GodotHTTPRequest.requests[xhrId].send(UTF8ToString(strPtr));
+ },
+
+ godot_xhr_send_data: function(xhrId, ptr, len) {
+ if (!ptr) {
+ Module.printErr("Failed to send data per XHR: null pointer");
+ return;
+ }
+ if (len < 0) {
+ Module.printErr("Failed to send data per XHR: buffer length less than 0");
+ return;
+ }
+ GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len));
+ },
+
+ godot_xhr_abort: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId].abort();
+ },
+
+ godot_xhr_get_status: function(xhrId) {
+ return GodotHTTPRequest.requests[xhrId].status;
+ },
+
+ godot_xhr_get_ready_state: function(xhrId) {
+ return GodotHTTPRequest.requests[xhrId].readyState;
+ },
+
+ godot_xhr_get_response_headers_length: function(xhrId) {
+ var headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
+ return headers === null ? 0 : lengthBytesUTF8(headers);
+ },
+
+ godot_xhr_get_response_headers: function(xhrId, dst, len) {
+ var str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
+ if (str === null)
+ return;
+ var buf = new Uint8Array(len + 1);
+ stringToUTF8Array(str, buf, 0, buf.length);
+ buf = buf.subarray(0, -1);
+ HEAPU8.set(buf, dst);
+ },
+
+ godot_xhr_get_response_length: function(xhrId) {
+ var body = GodotHTTPRequest.requests[xhrId].response;
+ return body === null ? 0 : body.byteLength;
+ },
+
+ godot_xhr_get_response: function(xhrId, dst, len) {
+ var buf = GodotHTTPRequest.requests[xhrId].response;
+ if (buf === null)
+ return;
+ buf = new Uint8Array(buf).subarray(0, len);
+ HEAPU8.set(buf, dst);
+ },
+};
+
+autoAddDeps(GodotHTTPRequest, "$GodotHTTPRequest");
+mergeInto(LibraryManager.library, GodotHTTPRequest);
diff --git a/platform/javascript/javascript_eval.cpp b/platform/javascript/javascript_eval.cpp
index 1d737879f6..9fc23a6747 100644
--- a/platform/javascript/javascript_eval.cpp
+++ b/platform/javascript/javascript_eval.cpp
@@ -29,16 +29,9 @@
/*************************************************************************/
#ifdef JAVASCRIPT_EVAL_ENABLED
-#include "javascript_eval.h"
+#include "api/javascript_eval.h"
#include "emscripten.h"
-JavaScript *JavaScript::singleton = NULL;
-
-JavaScript *JavaScript::get_singleton() {
-
- return singleton;
-}
-
extern "C" EMSCRIPTEN_KEEPALIVE uint8_t *resize_poolbytearray_and_open_write(PoolByteArray *p_arr, PoolByteArray::Write *r_write, int p_len) {
p_arr->resize(p_len);
@@ -52,7 +45,7 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
bool b;
double d;
char *s;
- } js_data[4];
+ } js_data;
PoolByteArray arr;
PoolByteArray::Write arr_write;
@@ -63,9 +56,8 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
const CODE = $0;
const USE_GLOBAL_EXEC_CONTEXT = $1;
const PTR = $2;
- const ELEM_LEN = $3;
- const BYTEARRAY_PTR = $4;
- const BYTEARRAY_WRITE_PTR = $5;
+ const BYTEARRAY_PTR = $3;
+ const BYTEARRAY_WRITE_PTR = $4;
var eval_ret;
try {
if (USE_GLOBAL_EXEC_CONTEXT) {
@@ -125,56 +117,25 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
HEAPU8.set(eval_ret, bytes_ptr);
return 20; // POOL_BYTE_ARRAY
}
-
- if (typeof eval_ret.x==='number' && typeof eval_ret.y==='number') {
- setValue(PTR, eval_ret.x, 'double');
- setValue(PTR + ELEM_LEN, eval_ret.y, 'double');
- if (typeof eval_ret.z==='number') {
- setValue(PTR + ELEM_LEN*2, eval_ret.z, 'double');
- return 7; // VECTOR3
- }
- else if (typeof eval_ret.width==='number' && typeof eval_ret.height==='number') {
- setValue(PTR + ELEM_LEN*2, eval_ret.width, 'double');
- setValue(PTR + ELEM_LEN*3, eval_ret.height, 'double');
- return 6; // RECT2
- }
- return 5; // VECTOR2
- }
-
- if (typeof eval_ret.r === 'number' && typeof eval_ret.g === 'number' && typeof eval_ret.b === 'number') {
- setValue(PTR, eval_ret.r, 'double');
- setValue(PTR + ELEM_LEN, eval_ret.g, 'double');
- setValue(PTR + ELEM_LEN*2, eval_ret.b, 'double');
- setValue(PTR + ELEM_LEN*3, typeof eval_ret.a === 'number' ? eval_ret.a : 1, 'double');
- return 14; // COLOR
- }
break;
}
return 0; // NIL
- }, p_code.utf8().get_data(), p_use_global_exec_context, js_data, sizeof *js_data, &arr, &arr_write));
+ }, p_code.utf8().get_data(), p_use_global_exec_context, &js_data, &arr, &arr_write));
/* clang-format on */
switch (return_type) {
case Variant::BOOL:
- return js_data->b;
+ return js_data.b;
case Variant::REAL:
- return js_data->d;
+ return js_data.d;
case Variant::STRING: {
- String str = String::utf8(js_data->s);
+ String str = String::utf8(js_data.s);
/* clang-format off */
- EM_ASM_({ _free($0); }, js_data->s);
+ EM_ASM_({ _free($0); }, js_data.s);
/* clang-format on */
return str;
}
- case Variant::VECTOR2:
- return Vector2(js_data[0].d, js_data[1].d);
- case Variant::VECTOR3:
- return Vector3(js_data[0].d, js_data[1].d, js_data[2].d);
- case Variant::RECT2:
- return Rect2(js_data[0].d, js_data[1].d, js_data[2].d, js_data[3].d);
- case Variant::COLOR:
- return Color(js_data[0].d, js_data[1].d, js_data[2].d, js_data[3].d);
case Variant::POOL_BYTE_ARRAY:
arr_write = PoolByteArray::Write();
return arr;
@@ -182,18 +143,4 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
return Variant();
}
-void JavaScript::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScript::eval, false);
-}
-
-JavaScript::JavaScript() {
-
- ERR_FAIL_COND(singleton != NULL);
- singleton = this;
-}
-
-JavaScript::~JavaScript() {
-}
-
#endif // JAVASCRIPT_EVAL_ENABLED
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index ed4f416cfd..5c5d608524 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -61,7 +61,6 @@ int main(int argc, char *argv[]) {
// run the 'main_after_fs_sync' function
/* clang-format off */
EM_ASM(
- Module.noExitRuntime = true;
FS.mkdir('/userfs');
FS.mount(IDBFS, {}, '/userfs');
FS.syncfs(true, function(err) {
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index f6446e77da..3b02bfd862 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "os_javascript.h"
+#include "core/engine.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"
@@ -64,11 +64,6 @@ const char *OS_JavaScript::get_video_driver_name(int p_driver) const {
return "GLES3";
}
-OS::VideoMode OS_JavaScript::get_default_video_mode() const {
-
- return OS::VideoMode();
-}
-
int OS_JavaScript::get_audio_driver_count() const {
return 1;
@@ -85,10 +80,6 @@ void OS_JavaScript::initialize_core() {
FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES);
}
-void OS_JavaScript::initialize_logger() {
- _set_logger(memnew(StdLogger));
-}
-
void OS_JavaScript::set_opengl_extensions(const char *p_gl_extensions) {
ERR_FAIL_COND(!p_gl_extensions);
@@ -171,14 +162,15 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent
}
int mask = _input->get_mouse_button_mask();
+ int button_flag = 1 << (ev->get_button_index() - 1);
if (ev->is_pressed()) {
// since the event is consumed, focus manually
if (!is_canvas_focused()) {
focus_canvas();
}
- mask |= ev->get_button_index();
- } else if (mask & ev->get_button_index()) {
- mask &= ~ev->get_button_index();
+ mask |= button_flag;
+ } else if (mask & button_flag) {
+ mask &= ~button_flag;
} else {
// release event, but press was outside the canvas, so ignore
return false;
@@ -209,7 +201,7 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m
ev->set_position(pos);
ev->set_global_position(ev->get_position());
- ev->set_relative(_input->get_mouse_position() - ev->get_position());
+ ev->set_relative(ev->get_position() - _input->get_mouse_position());
_input->set_mouse_position(ev->get_position());
ev->set_speed(_input->get_last_mouse_speed());
@@ -344,7 +336,7 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t
ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
ev_mouse->set_global_position(ev_mouse->get_position());
- ev_mouse->set_relative(_input->get_mouse_position() - ev_mouse->get_position());
+ ev_mouse->set_relative(ev_mouse->get_position() - _input->get_mouse_position());
_input->set_mouse_position(ev_mouse->get_position());
ev_mouse->set_speed(_input->get_last_mouse_speed());
@@ -442,25 +434,23 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
video_mode = p_desired;
// can't fulfil fullscreen request due to browser security
video_mode.fullscreen = false;
- set_window_size(Size2(p_desired.width, p_desired.height));
+ /* clang-format off */
+ bool resize_canvas_on_start = EM_ASM_INT_V(
+ return Module.resizeCanvasOnStart;
+ );
+ /* clang-format on */
+ if (resize_canvas_on_start) {
+ set_window_size(Size2(video_mode.width, video_mode.height));
+ } else {
+ Size2 canvas_size = get_window_size();
+ video_mode.width = canvas_size.width;
+ video_mode.height = canvas_size.height;
+ }
- // find locale, emscripten only sets "C"
char locale_ptr[16];
/* clang-format off */
- EM_ASM_({
- var locale = "";
- if (Module.locale) {
- // best case: server-side script reads Accept-Language early and
- // defines the locale to be read here
- locale = Module.locale;
- } else {
- // no luck, use what the JS engine can tell us
- // if this turns out not compatible enough, add tests for
- // browserLanguage, systemLanguage and userLanguage
- locale = navigator.languages ? navigator.languages[0] : navigator.language;
- }
- locale = locale.split('.')[0];
- stringToUTF8(locale, $0, 16);
+ EM_ASM_ARGS({
+ stringToUTF8(Module.locale, $0, 16);
}, locale_ptr);
/* clang-format on */
setenv("LANG", locale_ptr, true);
@@ -480,11 +470,6 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
print_line("Init Physicsserver");
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- physics_2d_server = memnew(Physics2DServerSW);
- physics_2d_server->init();
-
input = memnew(InputDefault);
_input = input;
@@ -521,11 +506,6 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
#undef SET_EM_CALLBACK
#undef EM_CHECK
-#ifdef JAVASCRIPT_EVAL_ENABLED
- javascript_eval = memnew(JavaScript);
- ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaScript", javascript_eval));
-#endif
-
visual_server->init();
}
@@ -898,14 +878,13 @@ String OS_JavaScript::get_resource_dir() const {
return "/"; //javascript has it's own filesystem for resources inside the APK
}
-String OS_JavaScript::get_data_dir() const {
+String OS_JavaScript::get_user_data_dir() const {
/*
- if (get_data_dir_func)
- return get_data_dir_func();
+ if (get_user_data_dir_func)
+ return get_user_data_dir_func();
*/
return "/userfs";
- //return ProjectSettings::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
};
String OS_JavaScript::get_executable_path() const {
@@ -1003,7 +982,7 @@ bool OS_JavaScript::is_userfs_persistent() const {
return idbfs_available;
}
-OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func) {
+OS_JavaScript::OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_user_data_dir_func) {
set_cmdline(p_execpath, get_cmdline_args());
main_loop = NULL;
gl_extensions = NULL;
@@ -1011,7 +990,7 @@ OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_d
soft_fs_enabled = false;
canvas_size_adjustment_requested = false;
- get_data_dir_func = p_get_data_dir_func;
+ get_user_data_dir_func = p_get_user_data_dir_func;
FileAccessUnix::close_notification_func = _close_notification_funcs;
idbfs_available = false;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 1c939d3fd5..a95b069d03 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -31,21 +31,17 @@
#define OS_JAVASCRIPT_H
#include "audio_driver_javascript.h"
-#include "audio_server_javascript.h"
#include "drivers/unix/os_unix.h"
-#include "javascript_eval.h"
#include "main/input_default.h"
#include "os/input.h"
#include "os/main_loop.h"
#include "power_javascript.h"
#include "servers/audio_server.h"
-#include "servers/physics/physics_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/visual/rasterizer.h"
#include <emscripten/html5.h>
-typedef String (*GetDataDirFunc)();
+typedef String (*GetUserDataDirFunc)();
class OS_JavaScript : public OS_Unix {
@@ -54,8 +50,6 @@ class OS_JavaScript : public OS_Unix {
int64_t last_sync_time;
VisualServer *visual_server;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
AudioDriverJavaScript audio_driver_javascript;
const char *gl_extensions;
@@ -68,14 +62,10 @@ class OS_JavaScript : public OS_Unix {
CursorShape cursor_shape;
MainLoop *main_loop;
- GetDataDirFunc get_data_dir_func;
+ GetUserDataDirFunc get_user_data_dir_func;
PowerJavascript *power_manager;
-#ifdef JAVASCRIPT_EVAL_ENABLED
- JavaScript *javascript_eval;
-#endif
-
static void _close_notification_funcs(const String &p_file, int p_flags);
void process_joypads();
@@ -88,12 +78,9 @@ public:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
- virtual void initialize_logger();
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
@@ -153,7 +140,7 @@ public:
void set_opengl_extensions(const char *p_gl_extensions);
virtual Error shell_open(String p_uri);
- virtual String get_data_dir() const;
+ virtual String get_user_data_dir() const;
String get_executable_path() const;
virtual String get_resource_dir() const;
@@ -172,7 +159,7 @@ public:
void set_idbfs_available(bool p_idbfs_available);
- OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func);
+ OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_user_data_dir_func);
~OS_JavaScript();
};
diff --git a/platform/javascript/pre_wasm.js b/platform/javascript/pre.js
index be4383c8c9..311aa44fda 100644
--- a/platform/javascript/pre_wasm.js
+++ b/platform/javascript/pre.js
@@ -1,3 +1,2 @@
var Engine = {
- USING_WASM: true,
RuntimeEnvironment: function(Module) {
diff --git a/platform/javascript/pre_asmjs.js b/platform/javascript/pre_asmjs.js
deleted file mode 100644
index 3c497721b6..0000000000
--- a/platform/javascript/pre_asmjs.js
+++ /dev/null
@@ -1,3 +0,0 @@
-var Engine = {
- USING_WASM: false,
- RuntimeEnvironment: function(Module) {
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index be3950bc6d..cb88bc470a 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -16,7 +16,8 @@ files = [
'power_osx.cpp',
]
-binary = env.Program('#bin/godot', files)
+prog = env.add_program('#bin/godot', files)
+
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
- env.AddPostAction(binary, make_debug)
+ env.AddPostAction(prog, make_debug)
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 2ed88db309..5635fe0187 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "main/main.h"
#include "os_osx.h"
+#include "project_settings.h"
#include <string.h>
#include <unistd.h>
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 31032659b6..ff7cf2ad2f 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -84,8 +84,15 @@ def configure(env):
else: # 64-bit, default
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
- env['CC'] = basecmd + "cc"
- env['CXX'] = basecmd + "c++"
+ ccache_path = os.environ.get("CCACHE")
+ if ccache_path == None:
+ env['CC'] = basecmd + "cc"
+ env['CXX'] = basecmd + "c++"
+ else:
+ # there aren't any ccache wrappers available for OS X cross-compile,
+ # to enable caching we need to prepend the path to the ccache binary
+ env['CC'] = ccache_path + ' ' + basecmd + "cc"
+ env['CXX'] = ccache_path + ' ' + basecmd + "c++"
env['AR'] = basecmd + "ar"
env['RANLIB'] = basecmd + "ranlib"
env['AS'] = basecmd + "as"
@@ -103,7 +110,7 @@ def configure(env):
## Flags
env.Append(CPPPATH=['#platform/osx'])
- env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED'])
+ env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED'])
env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
env.Append(LIBS=['pthread'])
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 8a6f1dc04c..8091a38adb 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -160,7 +160,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
copy->convert(Image::FORMAT_RGBA8);
copy->resize(size, size);
it->create_from_image(copy);
- String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/icon.png";
+ String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png");
ResourceSaver::save(path, it);
FileAccess *f = FileAccess::open(path, FileAccess::READ);
@@ -288,6 +288,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
}
Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String src_pkg_name;
@@ -344,7 +345,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (use_dmg()) {
// We're on OSX so we can export to DMG, but first we create our application bundle
- tmp_app_path_name = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".app";
+ tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app");
print_line("Exporting to " + tmp_app_path_name);
DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
if (!tmp_app_path) {
@@ -389,7 +390,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
//read
unzOpenCurrentFile(src_pkg_zip);
- unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
unzCloseCurrentFile(src_pkg_zip);
//write
@@ -539,7 +540,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
OS::get_singleton()->move_to_trash(tmp_app_path_name);
} else {
- String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck";
+ String pack_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".pck");
Error err = save_pack(p_preset, pack_path);
if (err == OK) {
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 420bb50af9..6543ca7dd2 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -38,15 +38,11 @@
#include "os/input.h"
#include "power_osx.h"
#include "servers/audio_server.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
-#include "servers/physics_server.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual/visual_server_wrap_mt.h"
#include "servers/visual_server.h"
#include <ApplicationServices/ApplicationServices.h>
-//bitch
#undef CursorShape
/**
@author Juan Linietsky <reduzio@gmail.com>
@@ -62,9 +58,6 @@ public:
List<String> args;
MainLoop *main_loop;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
-
IP_Unix *ip_unix;
AudioDriverCoreAudio audio_driver;
@@ -126,9 +119,7 @@ public:
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
- virtual void initialize_logger();
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
@@ -161,6 +152,11 @@ public:
virtual MainLoop *get_main_loop() const;
+ virtual String get_config_path() const;
+ virtual String get_data_path() const;
+ virtual String get_cache_path() const;
+ virtual String get_godot_dir_name() const;
+
virtual String get_system_dir(SystemDir p_dir) const;
virtual bool can_draw() const;
@@ -233,6 +229,12 @@ public:
virtual Error move_to_trash(const String &p_path);
OS_OSX();
+
+private:
+ Point2 get_native_screen_position(int p_screen) const;
+ Point2 get_native_window_position() const;
+ void set_native_window_position(const Point2 &p_position);
+ Point2 get_screens_origin() const;
};
#endif
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 33586086dc..732ec910c0 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -35,8 +35,8 @@
#include "os/keyboard.h"
#include "print_string.h"
#include "sem_osx.h"
-#include "servers/physics/physics_server_sw.h"
#include "servers/visual/visual_server_raster.h"
+#include "version_generated.gen.h"
#include <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
@@ -85,6 +85,15 @@ static int prev_mouse_y = 0;
static int button_mask = 0;
static bool mouse_down_control = false;
+static Vector2 get_mouse_pos(NSEvent *event) {
+
+ const NSRect contentRect = [OS_OSX::singleton->window_view frame];
+ const NSPoint p = [event locationInWindow];
+ mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
+ mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
+ return Vector2(mouse_x, mouse_y);
+}
+
@interface GodotApplication : NSApplication
@end
@@ -508,12 +517,9 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
mm->set_button_mask(button_mask);
prev_mouse_x = mouse_x;
prev_mouse_y = mouse_y;
- const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- const NSPoint p = [event locationInWindow];
- mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
- mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
- mm->set_position(Vector2(mouse_x, mouse_y));
- mm->set_global_position(Vector2(mouse_x, mouse_y));
+ const Vector2 pos = get_mouse_pos(event);
+ mm->set_position(pos);
+ mm->set_global_position(pos);
Vector2 relativeMotion = Vector2();
relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
relativeMotion.y = [event deltaY] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
@@ -575,6 +581,15 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
OS_OSX::singleton->input->set_mouse_in_window(true);
}
+- (void)magnifyWithEvent:(NSEvent *)event {
+ Ref<InputEventMagnifyGesture> ev;
+ ev.instance();
+ get_key_modifier_state([event modifierFlags], ev);
+ ev->set_position(get_mouse_pos(event));
+ ev->set_factor([event magnification] + 1.0);
+ OS_OSX::singleton->push_input(ev);
+}
+
- (void)viewDidChangeBackingProperties {
// nothing left to do here
}
@@ -838,6 +853,18 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
OS_OSX::singleton->push_input(sc);
}
+inline void sendPanEvent(double dx, double dy, int modifierFlags) {
+
+ Ref<InputEventPanGesture> pg;
+ pg.instance();
+
+ get_key_modifier_state(modifierFlags, pg);
+ Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
+ pg->set_position(mouse_pos);
+ pg->set_delta(Vector2(-dx, -dy));
+ OS_OSX::singleton->push_input(pg);
+}
+
- (void)scrollWheel:(NSEvent *)event {
double deltaX, deltaY;
@@ -856,11 +883,16 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
deltaX = [event deltaX];
deltaY = [event deltaY];
}
- if (fabs(deltaX)) {
- sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
- }
- if (fabs(deltaY)) {
- sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
+
+ if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
+ sendPanEvent(deltaX, deltaY, [event modifierFlags]);
+ } else {
+ if (fabs(deltaX)) {
+ sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
+ }
+ if (fabs(deltaY)) {
+ sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
+ }
}
}
@@ -897,17 +929,7 @@ int OS_OSX::get_video_driver_count() const {
const char *OS_OSX::get_video_driver_name(int p_driver) const {
- return "GLES2";
-}
-
-OS::VideoMode OS_OSX::get_default_video_mode() const {
-
- VideoMode vm;
- vm.width = 1024;
- vm.height = 600;
- vm.fullscreen = false;
- vm.resizable = true;
- return vm;
+ return "GLES3";
}
void OS_OSX::initialize_core() {
@@ -924,10 +946,15 @@ void OS_OSX::initialize_core() {
}
static bool keyboard_layout_dirty = true;
-static void keyboardLayoutChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
+static void keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) {
keyboard_layout_dirty = true;
}
+static bool displays_arrangement_dirty = true;
+static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
+ displays_arrangement_dirty = true;
+}
+
void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
/*** OSX INITIALIZATION ***/
@@ -935,13 +962,17 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
/*** OSX INITIALIZATION ***/
keyboard_layout_dirty = true;
+ displays_arrangement_dirty = true;
// Register to be notified on keyboard layout changes
CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
- NULL, keyboardLayoutChanged,
+ NULL, keyboard_layout_changed,
kTISNotifySelectedKeyboardInputSourceChanged, NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
+ // Register to be notified on displays arrangement changes
+ CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
+
window_delegate = [[GodotWindowDelegate alloc] init];
// Don't use accumulation buffer support; it's not accelerated
@@ -1068,8 +1099,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
zoomed = true;
/*** END OSX INITIALIZATION ***/
- /*** END OSX INITIALIZATION ***/
- /*** END OSX INITIALIZATION ***/
bool use_gl2 = p_video_driver != 1;
@@ -1079,32 +1108,21 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
- //rasterizer = instance_RasterizerGLES2();
- //visual_server = memnew( VisualServerRaster(rasterizer) );
-
visual_server = memnew(VisualServerRaster);
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
visual_server->init();
- // visual_server->cursor_set_visible(false, 0);
AudioDriverManager::initialize(p_audio_driver);
- //
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- //physics_2d_server = memnew( Physics2DServerSW );
- physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
- physics_2d_server->init();
-
input = memnew(InputDefault);
joypad_osx = memnew(JoypadOSX);
power_manager = memnew(power_osx);
- _ensure_data_dir();
+ _ensure_user_data_dir();
restore_rect = Rect2(get_window_position(), get_window_size());
}
@@ -1112,6 +1130,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
void OS_OSX::finalize() {
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
+ CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
+
delete_main_loop();
memdelete(joypad_osx);
@@ -1120,12 +1140,6 @@ void OS_OSX::finalize() {
visual_server->finish();
memdelete(visual_server);
//memdelete(rasterizer);
-
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
}
void OS_OSX::set_main_loop(MainLoop *p_main_loop) {
@@ -1203,15 +1217,6 @@ public:
typedef UnixTerminalLogger OSXTerminalLogger;
#endif
-void OS_OSX::initialize_logger() {
- Vector<Logger *> loggers;
- loggers.push_back(memnew(OSXTerminalLogger));
- // FIXME: Reenable once we figure out how to get this properly in user://
- // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277)
- //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt")));
- _set_logger(memnew(CompositeLogger(loggers)));
-}
-
void OS_OSX::alert(const String &p_alert, const String &p_title) {
// Set OS X-compliant variables
NSAlert *window = [[NSAlert alloc] init];
@@ -1353,6 +1358,43 @@ MainLoop *OS_OSX::get_main_loop() const {
return main_loop;
}
+String OS_OSX::get_config_path() const {
+
+ if (has_environment("XDG_CONFIG_HOME")) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file("Library/Application Support");
+ } else {
+ return ".";
+ }
+}
+
+String OS_OSX::get_data_path() const {
+
+ if (has_environment("XDG_DATA_HOME")) {
+ return get_environment("XDG_DATA_HOME");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_OSX::get_cache_path() const {
+
+ if (has_environment("XDG_CACHE_HOME")) {
+ return get_environment("XDG_CACHE_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file("Library/Caches");
+ } else {
+ return get_config_path();
+ }
+}
+
+// Get properly capitalized engine name for system paths
+String OS_OSX::get_godot_dir_name() const {
+
+ return String(VERSION_SHORT_NAME).capitalize();
+}
+
String OS_OSX::get_system_dir(SystemDir p_dir) const {
NSSearchPathDirectory id = 0;
@@ -1441,7 +1483,7 @@ void OS_OSX::make_rendering_thread() {
Error OS_OSX::shell_open(String p_uri) {
- [[NSWorkspace sharedWorkspace] openURL:[[NSURL alloc] initWithString:[NSString stringWithUTF8String:p_uri.utf8().get_data()]]];
+ [[NSWorkspace sharedWorkspace] openURL:[[NSURL alloc] initWithString:[[NSString stringWithUTF8String:p_uri.utf8().get_data()] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]];
return OK;
}
@@ -1480,6 +1522,32 @@ int OS_OSX::get_screen_count() const {
return [screenArray count];
};
+// Returns the native top-left screen coordinate of the smallest rectangle
+// that encompasses all screens. Needed in get_screen_position(),
+// get_window_position, and set_window_position()
+// to convert between OS X native screen coordinates and the ones expected by Godot
+Point2 OS_OSX::get_screens_origin() const {
+ static Point2 origin;
+
+ if (displays_arrangement_dirty) {
+ origin = Point2();
+
+ for (int i = 0; i < get_screen_count(); i++) {
+ Point2 position = get_native_screen_position(i);
+ if (position.x < origin.x) {
+ origin.x = position.x;
+ }
+ if (position.y > origin.y) {
+ origin.y = position.y;
+ }
+ }
+
+ displays_arrangement_dirty = false;
+ }
+
+ return origin;
+}
+
static int get_screen_index(NSScreen *screen) {
const NSUInteger index = [[NSScreen screens] indexOfObject:screen];
return index == NSNotFound ? 0 : index;
@@ -1498,21 +1566,30 @@ void OS_OSX::set_current_screen(int p_screen) {
set_window_position(wpos + get_screen_position(p_screen));
};
-Point2 OS_OSX::get_screen_position(int p_screen) const {
+Point2 OS_OSX::get_native_screen_position(int p_screen) const {
if (p_screen == -1) {
p_screen = get_current_screen();
}
NSArray *screenArray = [NSScreen screens];
if (p_screen < [screenArray count]) {
- float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
+ float display_scale = _display_scale([screenArray objectAtIndex:p_screen]);
NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
- return Point2(nsrect.origin.x, nsrect.origin.y) * displayScale;
+ // Return the top-left corner of the screen, for OS X the y starts at the bottom
+ return Point2(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * display_scale;
}
return Point2();
}
+Point2 OS_OSX::get_screen_position(int p_screen) const {
+ Point2 position = get_native_screen_position(p_screen) - get_screens_origin();
+ // OS X native y-coordinate relative to get_screens_origin() is negative,
+ // Godot expects a positive value
+ position.y *= -1;
+ return position;
+}
+
int OS_OSX::get_screen_dpi(int p_screen) const {
if (p_screen == -1) {
p_screen = get_current_screen();
@@ -1591,28 +1668,48 @@ float OS_OSX::_display_scale(id screen) const {
}
}
-Point2 OS_OSX::get_window_position() const {
+Point2 OS_OSX::get_native_window_position() const {
+
+ NSRect nsrect = [window_object frame];
+ Point2 pos;
+ float display_scale = _display_scale();
+
+ // Return the position of the top-left corner, for OS X the y starts at the bottom
+ pos.x = nsrect.origin.x * display_scale;
+ pos.y = (nsrect.origin.y + nsrect.size.height) * display_scale;
- Size2 wp([window_object frame].origin.x, [window_object frame].origin.y);
- wp *= _display_scale();
- return wp;
+ return pos;
};
-void OS_OSX::set_window_position(const Point2 &p_position) {
+Point2 OS_OSX::get_window_position() const {
+ Point2 position = get_native_window_position() - get_screens_origin();
+ // OS X native y-coordinate relative to get_screens_origin() is negative,
+ // Godot expects a positive value
+ position.y *= -1;
+ return position;
+}
+
+void OS_OSX::set_native_window_position(const Point2 &p_position) {
- Size2 scr = get_screen_size();
NSPoint pos;
float displayScale = _display_scale();
pos.x = p_position.x / displayScale;
- // For OS X the y starts at the bottom
- pos.y = (scr.height - p_position.y) / displayScale;
+ pos.y = p_position.y / displayScale;
[window_object setFrameTopLeftPoint:pos];
_update_window();
};
+void OS_OSX::set_window_position(const Point2 &p_position) {
+ Point2 position = p_position;
+ // OS X native y-coordinate relative to get_screens_origin() is negative,
+ // Godot passes a positive value
+ position.y *= -1;
+ set_native_window_position(get_screens_origin() + position);
+};
+
Size2 OS_OSX::get_window_size() const {
return window_size;
@@ -2068,7 +2165,9 @@ OS_OSX::OS_OSX() {
window_size = Vector2(1024, 600);
zoomed = false;
- _set_logger(memnew(OSXTerminalLogger));
+ Vector<Logger *> loggers;
+ loggers.push_back(memnew(OSXTerminalLogger));
+ _set_logger(memnew(CompositeLogger(loggers)));
}
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
diff --git a/platform/register_platform_apis.h b/platform/register_platform_apis.h
new file mode 100644
index 0000000000..37f98f6cd3
--- /dev/null
+++ b/platform/register_platform_apis.h
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* register_platform_apis.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://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. */
+/*************************************************************************/
+#ifndef REGISTER_APIS_H
+#define REGISTER_APIS_H
+
+void register_platform_apis();
+void unregister_platform_apis();
+
+#endif
diff --git a/platform/server/SCsub b/platform/server/SCsub
index 30195bb908..30d8cc8064 100644
--- a/platform/server/SCsub
+++ b/platform/server/SCsub
@@ -7,4 +7,4 @@ common_server = [\
"os_server.cpp",\
]
-env.Program('#bin/godot_server', ['godot_server.cpp'] + common_server)
+prog = env.add_program('#bin/godot_server', ['godot_server.cpp'] + common_server)
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 300c5cffcc..5b852af738 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -31,7 +31,6 @@
//#include "servers/visual/rasterizer_dummy.h"
#include "os_server.h"
#include "print_string.h"
-#include "servers/physics/physics_server_sw.h"
#include <stdio.h>
#include <stdlib.h>
@@ -47,10 +46,6 @@ const char *OS_Server::get_video_driver_name(int p_driver) const {
return "Dummy";
}
-OS::VideoMode OS_Server::get_default_video_mode() const {
-
- return OS::VideoMode(800, 600, false);
-}
void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
@@ -75,15 +70,10 @@ void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p
ERR_FAIL_COND(!visual_server);
visual_server->init();
- //
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- physics_2d_server = memnew(Physics2DServerSW);
- physics_2d_server->init();
input = memnew(InputDefault);
- _ensure_data_dir();
+ _ensure_user_data_dir();
}
void OS_Server::finalize() {
@@ -111,12 +101,6 @@ void OS_Server::finalize() {
memdelete(visual_server);
//memdelete(rasterizer);
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
-
memdelete(input);
args.clear();
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index ba12f649be..40b10c019f 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -35,12 +35,9 @@
#include "drivers/unix/os_unix.h"
#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_server.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
-//bitch
#undef CursorShape
/**
@author Juan Linietsky <reduzio@gmail.com>
@@ -56,9 +53,6 @@ class OS_Server : public OS_Unix {
bool grab;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
-
virtual void delete_main_loop();
IP_Unix *ip_unix;
@@ -71,7 +65,6 @@ class OS_Server : public OS_Unix {
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub
index bbd329a7e5..f0d69fef33 100644
--- a/platform/uwp/SCsub
+++ b/platform/uwp/SCsub
@@ -19,7 +19,7 @@ files = [
if "build_angle" in env and env["build_angle"]:
cmd = env.AlwaysBuild(env.ANGLE('libANGLE.lib', None))
-prog = env.Program('#bin/godot', files)
+prog = env.add_program('#bin/godot', files)
if "build_angle" in env and env["build_angle"]:
env.Depends(prog, [cmd])
diff --git a/platform/uwp/app.h b/platform/uwp/app.h
index e079fa9c9d..b812512a98 100644
--- a/platform/uwp/app.h
+++ b/platform/uwp/app.h
@@ -33,6 +33,7 @@
#include <wrl.h>
+// ANGLE doesn't provide a specific lib for GLES3, so we keep using GLES2
#include "GLES2/gl2.h"
#include "os_uwp.h"
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index af53f97446..7cc8afff06 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -84,7 +84,7 @@ def configure(env):
## Architecture
arch = ""
- if os.getenv('Platform') == "ARM":
+ if str(os.getenv('Platform')).lower() == "arm":
print("Compiled program architecture will be an ARM executable. (forcing bits=32).")
@@ -136,7 +136,7 @@ def configure(env):
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'])
+ env.Append(CCFLAGS=['/DGLES_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])
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index d66bcaa91c..7f86b4ae53 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -137,7 +137,7 @@ 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(const uint8_t *p_block_data, size_t p_block_len);
void make_block_map();
void make_content_types();
@@ -188,14 +188,14 @@ public:
///////////////////////////////////////////////////////////////////////////
-String AppxPackager::hash_block(uint8_t *p_block_data, size_t p_block_len) {
+String AppxPackager::hash_block(const uint8_t *p_block_data, size_t p_block_len) {
char hash[32];
char base64[45];
sha256_context ctx;
sha256_init(&ctx);
- sha256_hash(&ctx, p_block_data, p_block_len);
+ sha256_hash(&ctx, (uint8_t *)p_block_data, p_block_len);
sha256_done(&ctx, (uint8_t *)hash);
base64_encode(base64, hash, 32);
@@ -456,8 +456,8 @@ 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";
+ tmp_blockmap_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
+ tmp_content_types_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
}
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) {
@@ -510,8 +510,8 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t
strm.avail_in = block_size;
strm.avail_out = strm_out.size();
- strm.next_in = strm_in.ptr();
- strm.next_out = strm_out.ptr();
+ strm.next_in = (uint8_t *)strm_in.ptr();
+ strm.next_out = strm_out.ptrw();
int total_out_before = strm.total_out;
@@ -541,8 +541,8 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t
strm.avail_in = 0;
strm.avail_out = strm_out.size();
- strm.next_in = strm_in.ptr();
- strm.next_out = strm_out.ptr();
+ strm.next_in = (uint8_t *)strm_in.ptr();
+ strm.next_out = strm_out.ptrw();
int total_out_before = strm.total_out;
@@ -588,7 +588,7 @@ void AppxPackager::finish() {
Vector<uint8_t> blockmap_buffer;
blockmap_buffer.resize(blockmap_file->get_len());
- blockmap_file->get_buffer(blockmap_buffer.ptr(), blockmap_buffer.size());
+ blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size());
add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true);
@@ -604,7 +604,7 @@ void AppxPackager::finish() {
Vector<uint8_t> types_buffer;
types_buffer.resize(types_file->get_len());
- types_file->get_buffer(types_buffer.ptr(), types_buffer.size());
+ types_file->get_buffer(types_buffer.ptrw(), types_buffer.size());
add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true);
@@ -886,7 +886,7 @@ class EditorExportUWP : public EditorExportPlatform {
if (!image) return data;
- String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/uwp_tmp_logo.png");
+ String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
Error err = image->get_data()->save_png(tmp_path);
@@ -911,7 +911,7 @@ class EditorExportUWP : public EditorExportPlatform {
}
data.resize(f->get_len());
- f->get_buffer(data.ptr(), data.size());
+ f->get_buffer(data.ptrw(), data.size());
f->close();
memdelete(f);
@@ -1301,7 +1301,7 @@ public:
if (do_read) {
data.resize(info.uncompressed_size);
unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptr(), data.size());
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
}
@@ -1341,7 +1341,7 @@ public:
// Argc
clf.resize(4);
- encode_uint32(cl.size(), clf.ptr());
+ encode_uint32(cl.size(), clf.ptrw());
for (int i = 0; i < cl.size(); i++) {
diff --git a/platform/uwp/gl_context_egl.cpp b/platform/uwp/gl_context_egl.cpp
index ed3db65cdf..dafe5d5e25 100644
--- a/platform/uwp/gl_context_egl.cpp
+++ b/platform/uwp/gl_context_egl.cpp
@@ -101,26 +101,25 @@ Error ContextEGL::initialize() {
try {
- const EGLint displayAttributes[] =
- {
- /*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
- EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
- EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
- EGL_NONE,*/
- // These are the default display attributes, used to request ANGLE's D3D11 renderer.
- // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
- EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
-
- // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
- // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
- //EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
-
- // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
- // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
- // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
- EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
- EGL_NONE,
- };
+ const EGLint displayAttributes[] = {
+ /*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
+ EGL_NONE,*/
+ // These are the default display attributes, used to request ANGLE's D3D11 renderer.
+ // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+
+ // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
+ // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
+ //EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+
+ // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
+ // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
+ // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+ EGL_NONE,
+ };
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
diff --git a/platform/uwp/logo.png b/platform/uwp/logo.png
index 4376abd563..9017a30636 100644
--- a/platform/uwp/logo.png
+++ b/platform/uwp/logo.png
Binary files differ
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index c67e5bae05..1655caf04b 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "os_uwp.h"
+
#include "drivers/gles3/rasterizer_gles3.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/windows/dir_access_windows.h"
@@ -69,12 +70,7 @@ int OSUWP::get_video_driver_count() const {
}
const char *OSUWP::get_video_driver_name(int p_driver) const {
- return "GLES2";
-}
-
-OS::VideoMode OSUWP::get_default_video_mode() const {
-
- return video_mode;
+ return "GLES3";
}
Size2 OSUWP::get_window_size() const {
@@ -183,15 +179,6 @@ void OSUWP::initialize_core() {
cursor_shape = CURSOR_ARROW;
}
-void OSUWP::initialize_logger() {
- Vector<Logger *> loggers;
- loggers.push_back(memnew(WindowsTerminalLogger));
- // FIXME: Reenable once we figure out how to get this properly in user://
- // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277)
- //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt")));
- _set_logger(memnew(CompositeLogger(loggers)));
-}
-
bool OSUWP::can_draw() const {
return !minimized;
@@ -264,13 +251,6 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud
}
*/
- //
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
-
- physics_2d_server = memnew(Physics2DServerSW);
- physics_2d_server->init();
-
visual_server->init();
input = memnew(InputDefault);
@@ -310,7 +290,7 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud
ref new TypedEventHandler<Gyrometer ^, GyrometerReadingChangedEventArgs ^>(managed_object, &ManagedType::on_gyroscope_reading_changed);
}
- _ensure_data_dir();
+ _ensure_user_data_dir();
if (is_keep_screen_on())
display_request->RequestActive();
@@ -369,12 +349,6 @@ void OSUWP::finalize() {
memdelete(input);
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
-
joypad = nullptr;
}
@@ -799,7 +773,7 @@ MainLoop *OSUWP::get_main_loop() const {
return main_loop;
}
-String OSUWP::get_data_dir() const {
+String OSUWP::get_user_data_dir() const {
Windows::Storage::StorageFolder ^ data_folder = Windows::Storage::ApplicationData::Current->LocalFolder;
@@ -851,7 +825,9 @@ OSUWP::OSUWP() {
AudioDriverManager::add_driver(&audio_driver);
- _set_logger(memnew(WindowsTerminalLogger));
+ Vector<Logger *> loggers;
+ loggers.push_back(memnew(WindowsTerminalLogger));
+ _set_logger(memnew(CompositeLogger(loggers)));
}
OSUWP::~OSUWP() {
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 22f8938049..8d69cd53fd 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -40,8 +40,6 @@
#include "os/os.h"
#include "power_uwp.h"
#include "servers/audio_server.h"
-#include "servers/physics/physics_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
@@ -94,8 +92,6 @@ private:
int old_x, old_y;
Point2i center;
VisualServer *visual_server;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
int pressrc;
ContextEGL *gl_context;
@@ -158,12 +154,9 @@ protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
- virtual void initialize_logger();
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
@@ -232,7 +225,7 @@ public:
virtual String get_locale() const;
virtual void move_window_to_foreground();
- virtual String get_data_dir() const;
+ virtual String get_user_data_dir() const;
virtual bool _check_internal_feature_support(const String &p_feature);
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index aa9eb3e69b..5a253d5db5 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -28,7 +28,7 @@ obj = env.RES(restarget, 'godot_res.rc')
common_win.append(obj)
-binary = env.Program('#bin/godot', ['godot_win.cpp'] + common_win, PROGSUFFIX=env["PROGSUFFIX"])
+prog = env.add_program('#bin/godot', ['godot_win.cpp'] + common_win, PROGSUFFIX=env["PROGSUFFIX"])
# Microsoft Visual Studio Project Generation
if env['vsproj']:
@@ -38,4 +38,4 @@ if env['vsproj']:
if not os.getenv("VCINSTALLDIR"):
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
- env.AddPostAction(binary, make_debug_mingw)
+ env.AddPostAction(prog, make_debug_mingw)
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index 64b6d202a1..81aa18dd23 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -27,25 +27,12 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED)
-
-//
-// C++ Implementation: context_gl_x11
-//
-// Description:
-//
-//
+#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
+
// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008
-//
-// Copyright: See COPYING file that comes with this distribution
-//
-//
#include "context_gl_win.h"
-//#include "drivers/opengl/glwrapper.h"
-//#include "ctxgl_procaddr.h"
-
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_FLAGS_ARB 0x2094
@@ -165,7 +152,7 @@ Error ContextGL_Win::initialize() {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
//and it shall be forward compatible so that we can only use up to date functionality
- WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | _WGL_CONTEXT_DEBUG_BIT_ARB,
+ WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/,
0
}; //zero indicates the end of the array
diff --git a/platform/windows/context_gl_win.h b/platform/windows/context_gl_win.h
index 0059cbc311..5a280b0d08 100644
--- a/platform/windows/context_gl_win.h
+++ b/platform/windows/context_gl_win.h
@@ -27,18 +27,9 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED)
-//
-// C++ Interface: context_gl_x11
-//
-// Description:
-//
-//
+#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
+
// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008
-//
-// Copyright: See COPYING file that comes with this distribution
-//
-//
#ifndef CONTEXT_GL_WIN_H
#define CONTEXT_GL_WIN_H
diff --git a/platform/windows/crash_handler_win.cpp b/platform/windows/crash_handler_win.cpp
index 2f5ee7956e..feea3911b2 100644
--- a/platform/windows/crash_handler_win.cpp
+++ b/platform/windows/crash_handler_win.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "main/main.h"
#include "os_windows.h"
+#include "project_settings.h"
#ifdef CRASH_HANDLER_EXCEPTION
diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc
index b86869d316..c535a749c0 100644
--- a/platform/windows/godot_res.rc
+++ b/platform/windows/godot_res.rc
@@ -23,13 +23,13 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Godot Engine"
- VALUE "FileDescription", _MKSTR(VERSION_NAME) " Editor"
+ VALUE "FileDescription", VERSION_NAME " Editor"
VALUE "FileVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH)
- VALUE "ProductName", _MKSTR(VERSION_NAME)
+ VALUE "ProductName", VERSION_NAME
VALUE "Licence", "MIT"
VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur"
- VALUE "Info", "http://www.godotengine.org"
- VALUE "ProductVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) PATCH_STRING "." _MKSTR(VERSION_REVISION)
+ VALUE "Info", "https://godotengine.org"
+ VALUE "ProductVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) PATCH_STRING "." VERSION_BUILD
END
END
BLOCK "VarFileInfo"
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index ac78dddf0c..9bcbb6ddb6 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -42,12 +42,12 @@
#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"
#include "stream_peer_winsock.h"
#include "tcp_server_winsock.h"
+#include "version_generated.gen.h"
#include "windows_terminal_logger.h"
#include <process.h>
@@ -69,8 +69,26 @@ __attribute__((visibility("default"))) DWORD NvOptimusEnablement = 0x00000001;
#define WM_TOUCH 576
#endif
+static String format_error_message(DWORD id) {
+
+ LPWSTR messageBuffer = NULL;
+ size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
+
+ String msg = "Error "+itos(id)+": "+String(messageBuffer,size);
+
+ LocalFree(messageBuffer);
+
+ return msg;
+
+}
+
+
+
extern HINSTANCE godot_hinstance;
+
+
void RedirectIOToConsole() {
int hConHandle;
@@ -144,12 +162,7 @@ int OS_Windows::get_video_driver_count() const {
}
const char *OS_Windows::get_video_driver_name(int p_driver) const {
- return "GLES2";
-}
-
-OS::VideoMode OS_Windows::get_default_video_mode() const {
-
- return VideoMode(1024, 600, false);
+ return "GLES3";
}
int OS_Windows::get_audio_driver_count() const {
@@ -206,15 +219,6 @@ void OS_Windows::initialize_core() {
cursor_shape = CURSOR_ARROW;
}
-void OS_Windows::initialize_logger() {
- Vector<Logger *> loggers;
- loggers.push_back(memnew(WindowsTerminalLogger));
- // FIXME: Reenable once we figure out how to get this properly in user://
- // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277)
- //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt")));
- _set_logger(memnew(CompositeLogger(loggers)));
-}
-
bool OS_Windows::can_draw() const {
return !minimized;
@@ -1058,18 +1062,6 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
-
- physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
- physics_2d_server->init();
-
- if (!is_no_window_mode_enabled()) {
- ShowWindow(hWnd, SW_SHOW); // Show The Window
- SetForegroundWindow(hWnd); // Slightly Higher Priority
- SetFocus(hWnd); // Sets Keyboard Focus To
- }
-
/*
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
@@ -1102,11 +1094,17 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
//RegisterTouchWindow(hWnd, 0); // Windows 7
- _ensure_data_dir();
+ _ensure_user_data_dir();
DragAcceptFiles(hWnd, true);
move_timer_id = 1;
+
+ if (!is_no_window_mode_enabled()) {
+ ShowWindow(hWnd, SW_SHOW); // Show The Window
+ SetForegroundWindow(hWnd); // Slightly Higher Priority
+ SetFocus(hWnd); // Sets Keyboard Focus To
+ }
}
void OS_Windows::set_clipboard(const String &p_text) {
@@ -1225,12 +1223,6 @@ void OS_Windows::finalize() {
memdelete(debugger_connection_console);
}
*/
-
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
}
void OS_Windows::finalize_core() {
@@ -1614,10 +1606,23 @@ void OS_Windows::_update_window_style(bool repaint) {
}
}
-Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle) {
- p_library_handle = (void *)LoadLibrary(p_path.utf8().get_data());
+Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+
+
+ DLL_DIRECTORY_COOKIE cookie;
+
+ if (p_also_set_library_path) {
+ cookie = AddDllDirectory(p_path.get_base_dir().c_str());
+ }
+
+ p_library_handle = (void *)LoadLibraryExW(p_path.c_str(), NULL, p_also_set_library_path ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
+
+ if (p_also_set_library_path) {
+ RemoveDllDirectory(cookie);
+ }
+
if (!p_library_handle) {
- ERR_EXPLAIN("Can't open dynamic library: " + p_path + ". Error: " + String::num(GetLastError()));
+ ERR_EXPLAIN("Can't open dynamic library: " + p_path + ". Error: " + format_error_message(GetLastError()));
ERR_FAIL_V(ERR_CANT_OPEN);
}
return OK;
@@ -1869,7 +1874,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
modstr.resize(cmdline.size());
for (int i = 0; i < cmdline.size(); i++)
modstr[i] = cmdline[i];
- int ret = CreateProcessW(NULL, modstr.ptr(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, si_w, &pi.pi);
+ int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, si_w, &pi.pi);
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
if (p_blocking) {
@@ -1980,7 +1985,7 @@ void OS_Windows::set_icon(const Ref<Image> &p_icon) {
bool OS_Windows::has_environment(const String &p_var) const {
- return getenv(p_var.utf8().get_data()) != NULL;
+ return _wgetenv(p_var.c_str()) != NULL;
};
String OS_Windows::get_environment(const String &p_var) const {
@@ -2149,6 +2154,43 @@ MainLoop *OS_Windows::get_main_loop() const {
return main_loop;
}
+String OS_Windows::get_config_path() const {
+
+ if (has_environment("XDG_CONFIG_HOME")) { // unlikely, but after all why not?
+ return get_environment("XDG_CONFIG_HOME");
+ } else if (has_environment("APPDATA")) {
+ return get_environment("APPDATA");
+ } else {
+ return ".";
+ }
+}
+
+String OS_Windows::get_data_path() const {
+
+ if (has_environment("XDG_DATA_HOME")) {
+ return get_environment("XDG_DATA_HOME");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_Windows::get_cache_path() const {
+
+ if (has_environment("XDG_CACHE_HOME")) {
+ return get_environment("XDG_CACHE_HOME");
+ } else if (has_environment("TEMP")) {
+ return get_environment("TEMP");
+ } else {
+ return get_config_path();
+ }
+}
+
+// Get properly capitalized engine name for system paths
+String OS_Windows::get_godot_dir_name() const {
+
+ return String(VERSION_SHORT_NAME).capitalize();
+}
+
String OS_Windows::get_system_dir(SystemDir p_dir) const {
int id;
@@ -2185,18 +2227,20 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const {
ERR_FAIL_COND_V(res != S_OK, String());
return String(szPath);
}
-String OS_Windows::get_data_dir() const {
- String an = get_safe_application_name();
- if (an != "") {
+String OS_Windows::get_user_data_dir() const {
- if (has_environment("APPDATA")) {
-
- 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
- return (OS::get_singleton()->get_environment("APPDATA") + "/Godot/app_userdata/" + an).replace("\\", "/");
+ String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (appname != "") {
+ bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir");
+ if (use_custom_dir) {
+ String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true);
+ if (custom_dir == "") {
+ custom_dir = appname;
+ }
+ return get_data_path().plus_file(custom_dir).replace("\\", "/");
+ } else {
+ return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname).replace("\\", "/");
}
}
@@ -2307,7 +2351,9 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
AudioDriverManager::add_driver(&driver_xaudio2);
#endif
- _set_logger(memnew(WindowsTerminalLogger));
+ Vector<Logger *> loggers;
+ loggers.push_back(memnew(WindowsTerminalLogger));
+ _set_logger(memnew(CompositeLogger(loggers)));
}
OS_Windows::~OS_Windows() {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c0b8dfc691..e98f8277df 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -29,8 +29,8 @@
/*************************************************************************/
#ifndef OS_WINDOWS_H
#define OS_WINDOWS_H
-
#include "context_gl_win.h"
+#include "core/project_settings.h"
#include "crash_handler_win.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
@@ -38,7 +38,6 @@
#include "os/os.h"
#include "power_windows.h"
#include "servers/audio_server.h"
-#include "servers/physics/physics_server_sw.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
#ifdef XAUDIO2_ENABLED
@@ -47,8 +46,6 @@
#include "drivers/unix/ip_unix.h"
#include "key_mapping_win.h"
#include "main/input_default.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include <fcntl.h>
#include <io.h>
@@ -90,8 +87,6 @@ class OS_Windows : public OS {
ContextGL_Win *gl_context;
#endif
VisualServer *visual_server;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
int pressrc;
HDC hDC; // Private GDI Device Context
HINSTANCE hInstance; // Holds The Instance Of The Application
@@ -147,12 +142,9 @@ protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
- virtual void initialize_logger();
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
@@ -220,7 +212,7 @@ public:
virtual void set_borderless_window(int p_borderless);
virtual bool get_borderless_window();
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle);
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle,bool p_also_set_library_path=false);
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, bool p_optional = false);
@@ -260,8 +252,14 @@ public:
virtual void enable_for_stealing_focus(ProcessID pid);
virtual void move_window_to_foreground();
- virtual String get_data_dir() const;
+
+ virtual String get_config_path() const;
+ virtual String get_data_path() const;
+ virtual String get_cache_path() const;
+ virtual String get_godot_dir_name() const;
+
virtual String get_system_dir(SystemDir p_dir) const;
+ virtual String get_user_data_dir() const;
virtual void release_rendering_thread();
virtual void make_rendering_thread();
diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp
index a9d9cb9373..8b83215325 100644
--- a/platform/windows/stream_peer_winsock.cpp
+++ b/platform/windows/stream_peer_winsock.cpp
@@ -141,7 +141,7 @@ Error StreamPeerWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent,
if (WSAGetLastError() != WSAEWOULDBLOCK) {
- perror("shit?");
+ perror("Nothing sent");
disconnect_from_host();
ERR_PRINT("Server disconnected!\n");
return FAILED;
@@ -197,7 +197,7 @@ Error StreamPeerWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, b
if (WSAGetLastError() != WSAEWOULDBLOCK) {
- perror("shit?");
+ perror("Nothing read");
disconnect_from_host();
ERR_PRINT("Server disconnected!\n");
return FAILED;
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index aabc49149f..6378553638 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -17,6 +17,7 @@ common_x11 = [
"power_x11.cpp",
]
-binary = env.Program('#bin/godot', ['godot_x11.cpp'] + common_x11)
+prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11)
+
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
- env.AddPostAction(binary, make_debug)
+ env.AddPostAction(prog, make_debug)
diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp
index 3c54d5cbc2..005a7459f9 100644
--- a/platform/x11/crash_handler_x11.cpp
+++ b/platform/x11/crash_handler_x11.cpp
@@ -33,6 +33,7 @@
#include "main/main.h"
#include "os_x11.h"
+#include "project_settings.h"
#ifdef CRASH_HANDLER_ENABLED
#include <cxxabi.h>
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 6bd0ac8317..3d07851c4f 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -236,7 +236,7 @@ def configure(env):
env.ParseConfig('pkg-config zlib --cflags --libs')
env.Append(CPPPATH=['#platform/x11'])
- env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
+ env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES_ENABLED', '-DGLES_OVER_GL'])
env.Append(LIBS=['GL', 'pthread'])
if (platform.system() == "Linux"):
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 09193e0a2b..d1aa129e77 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -32,7 +32,6 @@
#include "errno.h"
#include "key_mapping_x11.h"
#include "print_string.h"
-#include "servers/physics/physics_server_sw.h"
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
@@ -83,10 +82,6 @@ const char *OS_X11::get_video_driver_name(int p_driver) const {
return "GLES3";
}
-OS::VideoMode OS_X11::get_default_video_mode() const {
- return OS::VideoMode(1024, 600, false);
-}
-
int OS_X11::get_audio_driver_count() const {
return AudioDriverManager::get_driver_count();
}
@@ -255,41 +250,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
-
- // borderless fullscreen window mode
- if (current_videomode.fullscreen) {
- // set bypass compositor hint
- Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
- unsigned long compositing_disable_on = 1;
- XChangeProperty(x11_display, x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
-
- // needed for lxde/openbox, possibly others
- 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);
- XMapRaised(x11_display, x11_window);
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, DefaultRootWindow(x11_display), &xwa);
- XMoveResizeWindow(x11_display, x11_window, 0, 0, xwa.width, xwa.height);
-
- // code for netwm-compliants
- XEvent xev;
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = 1;
- xev.xclient.data.l[1] = fullscreen;
- xev.xclient.data.l[2] = 0;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev);
+ if (current_videomode.maximized) {
+ current_videomode.maximized = false;
+ set_window_maximized(true);
+ // borderless fullscreen window mode
+ } else if (current_videomode.fullscreen) {
+ current_videomode.fullscreen = false;
+ set_window_fullscreen(true);
} else if (current_videomode.borderless_window) {
Hints hints;
Atom property;
@@ -462,12 +429,6 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
requested = None;
visual_server->init();
- //
- physics_server = memnew(PhysicsServerSW);
- physics_server->init();
- //physics_2d_server = memnew( Physics2DServerSW );
- physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
- physics_2d_server->init();
input = memnew(InputDefault);
@@ -475,11 +436,20 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
#ifdef JOYDEV_ENABLED
joypad = memnew(JoypadLinux(input));
#endif
- _ensure_data_dir();
+ _ensure_user_data_dir();
power_manager = memnew(PowerX11);
+
+ XEvent xevent;
+ while (XCheckIfEvent(x11_display, &xevent, _check_window_events, NULL)) {
+ _window_changed(&xevent);
+ }
}
+int OS_X11::_check_window_events(Display *display, XEvent *event, char *arg) {
+ if (event->type == ConfigureNotify) return 1;
+ return 0;
+}
void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
::XPointer call_data) {
@@ -523,12 +493,6 @@ void OS_X11::finalize() {
memdelete(visual_server);
//memdelete(rasterizer);
- physics_server->finish();
- memdelete(physics_server);
-
- physics_2d_server->finish();
- memdelete(physics_2d_server);
-
memdelete(power_manager);
if (xrandr_handle)
@@ -665,6 +629,9 @@ 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 (current_videomode.fullscreen == p_enabled)
+ return;
+
if (p_enabled && !is_window_resizable()) {
// Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
XSizeHints *xsh;
@@ -988,6 +955,9 @@ bool OS_X11::is_window_minimized() const {
}
void OS_X11::set_window_maximized(bool p_enabled) {
+ if (is_window_maximized() == p_enabled)
+ return;
+
// Using EWMH -- Extended Window Manager Hints
XEvent xev;
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
@@ -1434,6 +1404,20 @@ static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p
return None;
}
+void OS_X11::_window_changed(XEvent *event) {
+
+ if (xic) {
+ // Not portable.
+ set_ime_position(Point2(0, 1));
+ }
+ if ((event->xconfigure.width == current_videomode.width) &&
+ (event->xconfigure.height == current_videomode.height))
+ return;
+
+ current_videomode.width = event->xconfigure.width;
+ current_videomode.height = event->xconfigure.height;
+}
+
void OS_X11::process_xevents() {
//printf("checking events %i\n", XPending(x11_display));
@@ -1515,18 +1499,7 @@ void OS_X11::process_xevents() {
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) &&
- (event.xconfigure.height == current_videomode.height))
- break;
-
- current_videomode.width = event.xconfigure.width;
- current_videomode.height = event.xconfigure.height;
+ _window_changed(&event);
break;
case ButtonPress:
case ButtonRelease: {
@@ -1958,6 +1931,39 @@ bool OS_X11::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
+String OS_X11::get_config_path() const {
+
+ if (has_environment("XDG_CONFIG_HOME")) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".config");
+ } else {
+ return ".";
+ }
+}
+
+String OS_X11::get_data_path() const {
+
+ if (has_environment("XDG_DATA_HOME")) {
+ return get_environment("XDG_DATA_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".local/share");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_X11::get_cache_path() const {
+
+ if (has_environment("XDG_CACHE_HOME")) {
+ return get_environment("XDG_CACHE_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".cache");
+ } else {
+ return get_config_path();
+ }
+}
+
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 b71b456d49..a74e6ee5f3 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -42,9 +42,6 @@
#include "main/input_default.h"
#include "power_x11.h"
#include "servers/audio_server.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
-#include "servers/physics_server.h"
#include "servers/visual/rasterizer.h"
#include <X11/Xcursor/Xcursor.h>
@@ -121,10 +118,8 @@ class OS_X11 : public OS_Unix {
uint64_t last_click_ms;
uint32_t last_button_state;
- PhysicsServer *physics_server;
unsigned int get_mouse_button_state(unsigned int p_x11_state);
void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
- Physics2DServer *physics_2d_server;
MouseMode mouse_mode;
Point2i center;
@@ -182,7 +177,6 @@ class OS_X11 : public OS_Unix {
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
@@ -193,6 +187,9 @@ protected:
virtual void set_main_loop(MainLoop *p_main_loop);
+ void _window_changed(XEvent *xevent);
+ static int _check_window_events(Display *display, XEvent *xevent, char *arg);
+
public:
virtual String get_name();
@@ -219,6 +216,10 @@ public:
virtual void make_rendering_thread();
virtual void swap_buffers();
+ virtual String get_config_path() const;
+ virtual String get_data_path() const;
+ virtual String get_cache_path() const;
+
virtual String get_system_dir(SystemDir p_dir) const;
virtual Error shell_open(String p_uri);