summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/SCsub113
-rw-r--r--platform/android/audio_driver_jandroid.h2
-rw-r--r--platform/android/audio_driver_opensl.cpp119
-rw-r--r--platform/android/audio_driver_opensl.h17
-rw-r--r--platform/android/detect.py55
-rw-r--r--platform/android/dir_access_jandroid.cpp3
-rw-r--r--platform/android/dir_access_jandroid.h2
-rw-r--r--platform/android/export/export.cpp433
-rw-r--r--platform/android/file_access_android.h2
-rw-r--r--platform/android/file_access_jandroid.h4
-rw-r--r--platform/android/java/AndroidManifest.xml (renamed from platform/android/AndroidManifest.xml.template)22
-rw-r--r--platform/android/java/build.gradle (renamed from platform/android/build.gradle.template)59
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java72
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java3
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java1
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotIO.java46
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotInstrumentation.java50
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotLib.java6
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java8
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotView.java18
-rw-r--r--platform/android/java/src/org/godotengine/godot/input/GodotEditText.java11
-rw-r--r--platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java1
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java4
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java12
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java7
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java12
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java7
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java21
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java2
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java8
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/RequestParams.java1
-rw-r--r--platform/android/java_class_wrapper.cpp11
-rw-r--r--platform/android/java_godot_io_wrapper.cpp207
-rw-r--r--platform/android/java_godot_io_wrapper.h88
-rw-r--r--platform/android/java_godot_lib_jni.cpp (renamed from platform/android/java_glue.cpp)346
-rw-r--r--platform/android/java_godot_lib_jni.h (renamed from platform/android/java_glue.h)16
-rw-r--r--platform/android/java_godot_wrapper.cpp185
-rw-r--r--platform/android/java_godot_wrapper.h81
-rw-r--r--platform/android/os_android.cpp170
-rw-r--r--platform/android/os_android.h66
-rw-r--r--platform/android/string_android.h58
-rw-r--r--platform/haiku/audio_driver_media_kit.cpp4
-rw-r--r--platform/haiku/context_gl_haiku.h22
-rw-r--r--platform/haiku/detect.py2
-rw-r--r--platform/haiku/os_haiku.cpp6
-rw-r--r--platform/haiku/os_haiku.h1
-rw-r--r--platform/iphone/SCsub2
-rw-r--r--platform/iphone/app_delegate.mm24
-rw-r--r--platform/iphone/detect.py24
-rw-r--r--platform/iphone/export/export.cpp31
-rw-r--r--platform/iphone/gl_view.mm32
-rw-r--r--platform/iphone/os_iphone.cpp10
-rw-r--r--platform/iphone/os_iphone.h3
-rw-r--r--platform/javascript/SCsub7
-rw-r--r--platform/javascript/detect.py5
-rw-r--r--platform/javascript/export/export.cpp40
-rw-r--r--platform/javascript/id_handler.js62
-rw-r--r--platform/javascript/os_javascript.cpp12
-rw-r--r--platform/osx/SCsub1
-rw-r--r--platform/osx/detect.py16
-rw-r--r--platform/osx/export/export.cpp6
-rw-r--r--platform/osx/os_osx.h1
-rw-r--r--platform/osx/os_osx.mm123
-rw-r--r--platform/server/SCsub2
-rw-r--r--platform/server/detect.py77
-rw-r--r--platform/server/os_server.cpp6
-rw-r--r--platform/server/os_server.h3
-rw-r--r--platform/uwp/context_egl_uwp.h21
-rw-r--r--platform/uwp/detect.py30
-rw-r--r--platform/uwp/export/export.cpp6
-rw-r--r--platform/uwp/os_uwp.cpp11
-rw-r--r--platform/uwp/os_uwp.h1
-rw-r--r--platform/windows/context_gl_windows.h21
-rw-r--r--platform/windows/detect.py22
-rw-r--r--platform/windows/godot.natvis147
-rw-r--r--platform/windows/os_windows.cpp110
-rw-r--r--platform/windows/os_windows.h6
-rw-r--r--platform/x11/SCsub1
-rw-r--r--platform/x11/context_gl_x11.h21
-rw-r--r--platform/x11/detect.py51
-rw-r--r--platform/x11/detect_prime.cpp4
-rw-r--r--platform/x11/joypad_linux.cpp8
-rw-r--r--platform/x11/os_x11.cpp105
-rw-r--r--platform/x11/os_x11.h1
84 files changed, 2300 insertions, 1137 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 47d5035224..22ed476c6f 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -2,7 +2,6 @@
Import('env')
-import shutil
from compat import open_utf8
from distutils.version import LooseVersion
from detect import get_ndk_version
@@ -16,8 +15,10 @@ android_files = [
'dir_access_jandroid.cpp',
'thread_jandroid.cpp',
'audio_driver_jandroid.cpp',
- 'java_glue.cpp',
+ 'java_godot_lib_jni.cpp',
'java_class_wrapper.cpp',
+ 'java_godot_wrapper.cpp',
+ 'java_godot_io_wrapper.cpp',
# 'power_android.cpp'
]
@@ -33,114 +34,6 @@ env_thirdparty = env_android.Clone()
env_thirdparty.disable_warnings()
android_objects.append(env_thirdparty.SharedObject('#thirdparty/misc/ifaddrs-android.cc'))
-abspath = env.Dir(".").abspath
-
-with open_utf8(abspath + "/build.gradle.template", "r") as gradle_basein:
- gradle_text = gradle_basein.read()
-
-gradle_maven_flat_text = ""
-if len(env.android_flat_dirs) > 0:
- gradle_maven_flat_text += "flatDir {\n"
- gradle_maven_flat_text += "\tdirs "
- for x in env.android_flat_dirs:
- gradle_maven_flat_text += "'" + x + "',"
-
- gradle_maven_flat_text = gradle_maven_flat_text[:-1]
- gradle_maven_flat_text += "\n\t}\n"
-
-gradle_maven_repos_text = ""
-gradle_maven_repos_text += gradle_maven_flat_text
-
-if len(env.android_maven_repos) > 0:
- gradle_maven_repos_text += ""
- for x in env.android_maven_repos:
- gradle_maven_repos_text += "\tmaven {\n"
- gradle_maven_repos_text += "\t" + x + "\n"
- gradle_maven_repos_text += "\t}\n"
-
-gradle_maven_dependencies_text = ""
-
-for x in env.android_dependencies:
- gradle_maven_dependencies_text += x + "\n\t"
-
-gradle_java_dirs_text = ""
-
-for x in env.android_java_dirs:
- gradle_java_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_plugins = ""
-for x in env.android_gradle_plugins:
- gradle_plugins += "apply plugin: \"" + x + "\"\n"
-
-gradle_classpath = ""
-for x in env.android_gradle_classpath:
- gradle_classpath += "\t\tclasspath \"" + x + "\"\n"
-
-gradle_res_dirs_text = ""
-
-for x in env.android_res_dirs:
- gradle_res_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_aidl_dirs_text = ""
-
-for x in env.android_aidl_dirs:
- gradle_aidl_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_jni_dirs_text = ""
-
-for x in env.android_jni_dirs:
- gradle_jni_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_asset_dirs_text = ""
-
-for x in env.android_asset_dirs:
- gradle_asset_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_default_config_text = ""
-
-minSdk = 18
-targetSdk = 28
-
-for x in env.android_default_config:
- if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk:
- x = "minSdkVersion " + str(minSdk)
- if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk:
- x = "targetSdkVersion " + str(targetSdk)
-
- gradle_default_config_text += x + "\n\t\t"
-
-if "minSdkVersion" not in gradle_default_config_text:
- gradle_default_config_text += ("minSdkVersion " + str(minSdk) + "\n\t\t")
-
-if "targetSdkVersion" not in gradle_default_config_text:
- gradle_default_config_text += ("targetSdkVersion " + str(targetSdk) + "\n\t\t")
-
-gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$", gradle_maven_repos_text)
-gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$", gradle_maven_dependencies_text)
-gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$", gradle_java_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$", gradle_res_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$", gradle_asset_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$", gradle_aidl_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$", gradle_jni_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$", gradle_default_config_text)
-gradle_text = gradle_text.replace("$$GRADLE_PLUGINS$$", gradle_plugins)
-gradle_text = gradle_text.replace("$$GRADLE_CLASSPATH$$", gradle_classpath)
-
-with open_utf8(abspath + "/java/build.gradle", "w") as gradle_baseout:
- gradle_baseout.write(gradle_text)
-
-
-with open_utf8(abspath + "/AndroidManifest.xml.template", "r") as pp_basein:
- manifest = pp_basein.read()
-
-manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$", env.android_manifest_chunk)
-manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$", env.android_permission_chunk)
-manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$", env.android_appattributes_chunk)
-
-with open_utf8(abspath + "/java/AndroidManifest.xml", "w") as pp_baseout:
- pp_baseout.write(manifest)
-
-
lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
lib_arch_dir = ''
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
index a5b49e9077..f92ef06052 100644
--- a/platform/android/audio_driver_jandroid.h
+++ b/platform/android/audio_driver_jandroid.h
@@ -33,7 +33,7 @@
#include "servers/audio_server.h"
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
class AudioDriverAndroid : public AudioDriver {
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index e259380a63..1232fc7453 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -53,7 +53,7 @@ void AudioDriverOpenSL::_buffer_callback(
} else {
int32_t *src_buff = mixdown_buffer;
- for (int i = 0; i < buffer_size * 2; i++) {
+ for (unsigned int i = 0; i < buffer_size * 2; i++) {
src_buff[i] = 0;
}
}
@@ -66,7 +66,7 @@ void AudioDriverOpenSL::_buffer_callback(
int16_t *ptr = (int16_t *)buffers[last_free];
last_free = (last_free + 1) % BUFFER_COUNT;
- for (int i = 0; i < buffer_size * 2; i++) {
+ for (unsigned int i = 0; i < buffer_size * 2; i++) {
ptr[i] = src_buff[i] >> 16;
}
@@ -211,9 +211,122 @@ void AudioDriverOpenSL::start() {
active = true;
}
+void AudioDriverOpenSL::_record_buffer_callback(SLAndroidSimpleBufferQueueItf queueItf) {
+
+ for (int i = 0; i < rec_buffer.size(); i++) {
+ int32_t sample = rec_buffer[i] << 16;
+ input_buffer_write(sample);
+ input_buffer_write(sample); // call twice to convert to Stereo
+ }
+
+ SLresult res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t));
+ ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
+}
+
+void AudioDriverOpenSL::_record_buffer_callbacks(SLAndroidSimpleBufferQueueItf queueItf, void *pContext) {
+
+ AudioDriverOpenSL *ad = (AudioDriverOpenSL *)pContext;
+
+ ad->_record_buffer_callback(queueItf);
+}
+
+Error AudioDriverOpenSL::capture_init_device() {
+
+ SLDataLocator_IODevice loc_dev = {
+ SL_DATALOCATOR_IODEVICE,
+ SL_IODEVICE_AUDIOINPUT,
+ SL_DEFAULTDEVICEID_AUDIOINPUT,
+ NULL
+ };
+ SLDataSource recSource = { &loc_dev, NULL };
+
+ SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+ 2
+ };
+ SLDataFormat_PCM format_pcm = {
+ SL_DATAFORMAT_PCM,
+ 1,
+ SL_SAMPLINGRATE_44_1,
+ SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_SPEAKER_FRONT_CENTER,
+ SL_BYTEORDER_LITTLEENDIAN
+ };
+ SLDataSink recSnk = { &loc_bq, &format_pcm };
+
+ const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
+ const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
+
+ SLresult res = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recSnk, 2, ids, req);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void *)&recordItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void *)&recordBufferQueueItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordBufferQueueItf)->RegisterCallback(recordBufferQueueItf, _record_buffer_callbacks, this);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ SLuint32 state;
+ res = (*recordItf)->GetRecordState(recordItf, &state);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ if (state != SL_RECORDSTATE_STOPPED) {
+ res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+ }
+
+ const int rec_buffer_frames = 2048;
+ rec_buffer.resize(rec_buffer_frames);
+ input_buffer_init(rec_buffer_frames);
+
+ res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t));
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ return OK;
+}
+
+Error AudioDriverOpenSL::capture_start() {
+
+ if (OS::get_singleton()->request_permission("RECORD_AUDIO")) {
+ return capture_init_device();
+ }
+
+ return OK;
+}
+
+Error AudioDriverOpenSL::capture_stop() {
+
+ SLuint32 state;
+ SLresult res = (*recordItf)->GetRecordState(recordItf, &state);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ if (state != SL_RECORDSTATE_STOPPED) {
+ res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+ }
+
+ return OK;
+}
+
int AudioDriverOpenSL::get_mix_rate() const {
- return 44100;
+ return 44100; // hardcoded for Android, as selected by SL_SAMPLINGRATE_44_1
}
AudioDriver::SpeakerMode AudioDriverOpenSL::get_speaker_mode() const {
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index 77e16e507a..2981073cec 100644
--- a/platform/android/audio_driver_opensl.h
+++ b/platform/android/audio_driver_opensl.h
@@ -54,13 +54,18 @@ class AudioDriverOpenSL : public AudioDriver {
int32_t *mixdown_buffer;
int last_free;
+ Vector<int16_t> rec_buffer;
+
SLPlayItf playItf;
+ SLRecordItf recordItf;
SLObjectItf sl;
SLEngineItf EngineItf;
SLObjectItf OutputMix;
SLVolumeItf volumeItf;
SLObjectItf player;
+ SLObjectItf recorder;
SLAndroidSimpleBufferQueueItf bufferQueueItf;
+ SLAndroidSimpleBufferQueueItf recordBufferQueueItf;
SLDataSource audioSource;
SLDataFormat_PCM pcm;
SLDataSink audioSink;
@@ -76,6 +81,15 @@ class AudioDriverOpenSL : public AudioDriver {
SLAndroidSimpleBufferQueueItf queueItf,
void *pContext);
+ void _record_buffer_callback(
+ SLAndroidSimpleBufferQueueItf queueItf);
+
+ static void _record_buffer_callbacks(
+ SLAndroidSimpleBufferQueueItf queueItf,
+ void *pContext);
+
+ virtual Error capture_init_device();
+
public:
void set_singleton();
@@ -91,6 +105,9 @@ public:
virtual void set_pause(bool p_pause);
+ virtual Error capture_start();
+ virtual Error capture_stop();
+
AudioDriverOpenSL();
};
diff --git a/platform/android/detect.py b/platform/android/detect.py
index aa48252435..6c67067db7 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -1,6 +1,5 @@
import os
import sys
-import string
import platform
from distutils.version import LooseVersion
@@ -151,19 +150,21 @@ def configure(env):
if (env["target"].startswith("release")):
if (env["optimize"] == "speed"): #optimize for speed (default)
env.Append(LINKFLAGS=['-O2'])
- env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-fomit-frame-pointer'])
+ env.Append(CCFLAGS=['-O2', '-fomit-frame-pointer'])
+ env.Append(CPPFLAGS=['-DNDEBUG'])
else: #optimize for size
- env.Append(CPPFLAGS=['-Os', '-DNDEBUG'])
+ env.Append(CCFLAGS=['-Os'])
+ env.Append(CPPFLAGS=['-DNDEBUG'])
env.Append(LINKFLAGS=['-Os'])
if (can_vectorize):
- env.Append(CPPFLAGS=['-ftree-vectorize'])
+ env.Append(CCFLAGS=['-ftree-vectorize'])
if (env["target"] == "release_debug"):
env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
elif (env["target"] == "debug"):
env.Append(LINKFLAGS=['-O0'])
- env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED',
- '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info'])
+ env.Append(CCFLAGS=['-O0', '-g', '-fno-limit-debug-info'])
+ env.Append(CPPFLAGS=['-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
## Compiler configuration
@@ -217,15 +218,16 @@ def configure(env):
if env['android_stl']:
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/include"])
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
- env.Append(CXXFLAGS=['-frtti',"-std=gnu++14"])
+ env.Append(CXXFLAGS=['-frtti', "-std=gnu++14"])
else:
- env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST'])
+ env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions'])
+ env.Append(CPPFLAGS=['-DNO_SAFE_CAST'])
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=["--sysroot="+sysroot])
+ env.Append(CPPFLAGS=["--sysroot=" + sysroot])
env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath])
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/android/support/include"])
# For unified headers this define has to be set manually
@@ -234,48 +236,51 @@ def configure(env):
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(CCFLAGS='-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'.split())
env.Append(CPPFLAGS='-DNO_STATVFS -DGLES_ENABLED'.split())
env['neon_enabled'] = False
if env['android_arch'] == 'x86':
target_opts = ['-target', 'i686-none-linux-android']
# The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least
- env.Append(CPPFLAGS=['-mstackrealign'])
+ env.Append(CCFLAGS=['-mstackrealign'])
elif env['android_arch'] == 'x86_64':
target_opts = ['-target', 'x86_64-none-linux-android']
elif env["android_arch"] == "armv6":
target_opts = ['-target', 'armv6-none-linux-androideabi']
- env.Append(CPPFLAGS='-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp'.split())
+ env.Append(CCFLAGS='-march=armv6 -mfpu=vfp -mfloat-abi=softfp'.split())
+ env.Append(CPPFLAGS=['-D__ARM_ARCH_6__'])
elif env["android_arch"] == "armv7":
target_opts = ['-target', 'armv7-none-linux-androideabi']
- env.Append(CPPFLAGS='-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp'.split())
+ env.Append(CCFLAGS='-march=armv7-a -mfloat-abi=softfp'.split())
+ env.Append(CPPFLAGS='-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__'.split())
if env['android_neon']:
env['neon_enabled'] = True
- env.Append(CPPFLAGS=['-mfpu=neon', '-D__ARM_NEON__'])
+ env.Append(CCFLAGS=['-mfpu=neon'])
+ env.Append(CPPFLAGS=['-D__ARM_NEON__'])
else:
- env.Append(CPPFLAGS=['-mfpu=vfpv3-d16'])
+ env.Append(CCFLAGS=['-mfpu=vfpv3-d16'])
elif env["android_arch"] == "arm64v8":
target_opts = ['-target', 'aarch64-none-linux-android']
+ env.Append(CCFLAGS=['-mfix-cortex-a53-835769'])
env.Append(CPPFLAGS=['-D__ARM_ARCH_8A__'])
- env.Append(CPPFLAGS=['-mfix-cortex-a53-835769'])
- env.Append(CPPFLAGS=target_opts)
- env.Append(CPPFLAGS=common_opts)
+ env.Append(CCFLAGS=target_opts)
+ env.Append(CCFLAGS=common_opts)
## Link flags
if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("15.0.4075724"):
if LooseVersion(ndk_version) >= LooseVersion("17.1.4828580"):
- env.Append(LINKFLAGS=['-Wl,--exclude-libs,libgcc.a','-Wl,--exclude-libs,libatomic.a','-nostdlib++'])
+ env.Append(LINKFLAGS=['-Wl,--exclude-libs,libgcc.a', '-Wl,--exclude-libs,libatomic.a', '-nostdlib++'])
else:
- env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"] +"/sources/cxx-stl/llvm-libc++/libs/"+arch_subpath+"/libandroid_support.a"])
+ env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libandroid_support.a"])
env.Append(LINKFLAGS=['-shared', '--sysroot=' + lib_sysroot, '-Wl,--warn-shared-textrel'])
- env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/"+arch_subpath+"/"])
- env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"] +"/sources/cxx-stl/llvm-libc++/libs/"+arch_subpath+"/libc++_shared.so"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/"])
+ env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"] +"/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libc++_shared.so"])
else:
env.Append(LINKFLAGS=['-shared', '--sysroot=' + lib_sysroot, '-Wl,--warn-shared-textrel'])
if mt_link:
@@ -298,12 +303,6 @@ def configure(env):
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL'])
env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z', 'dl'])
- # TODO: Move that to opus module's config
- if 'module_opus_enabled' in env and env['module_opus_enabled']:
- 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 is None:
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 4b3d93aaa7..8c464465ca 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -31,6 +31,7 @@
#include "dir_access_jandroid.h"
#include "core/print_string.h"
#include "file_access_jandroid.h"
+#include "string_android.h"
#include "thread_jandroid.h"
jobject DirAccessJAndroid::io = NULL;
@@ -69,7 +70,7 @@ String DirAccessJAndroid::get_next() {
if (!str)
return "";
- String ret = String::utf8(env->GetStringUTFChars((jstring)str, NULL));
+ String ret = jstring_to_string((jstring)str, env);
env->DeleteLocalRef((jobject)str);
return ret;
}
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index e7a2d5ada1..cdea93ff4c 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -32,7 +32,7 @@
#define DIR_ACCESS_JANDROID_H
#include "core/os/dir_access.h"
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
#include <stdio.h>
class DirAccessJAndroid : public DirAccess {
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 9d9270bdac..2a3d0843a8 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -417,6 +417,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
name = "noname";
pname = pname.replace("$genname", name);
+
return pname;
}
@@ -658,6 +659,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int orientation = p_preset->get("screen/orientation");
+ bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES3" &&
+ !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2");
bool screen_support_small = p_preset->get("screen/support_small");
bool screen_support_normal = p_preset->get("screen/support_normal");
bool screen_support_large = p_preset->get("screen/support_large");
@@ -815,6 +818,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
+ if (tname == "uses-feature" && attrname == "glEsVersion") {
+
+ encode_uint32(min_gles3 ? 0x00030000 : 0x00020000, &p_manifest.write[iofs + 16]);
+ }
+
iofs += 20;
}
@@ -1114,17 +1122,14 @@ public:
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- // Re-enable when a GLES 2.0 backend is read
- /*int api = p_preset->get("graphics/api");
- if (api == 0)
- r_features->push_back("etc");
- else*/
String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
- if (driver == "GLES2" || driver == "GLES3") {
+ if (driver == "GLES2") {
r_features->push_back("etc");
- }
- if (driver == "GLES3") {
+ } else if (driver == "GLES3") {
r_features->push_back("etc2");
+ if (ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2")) {
+ r_features->push_back("etc");
+ }
}
Vector<String> abis = get_enabled_abis(p_preset);
@@ -1139,11 +1144,12 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_package/use_custom_build"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.$genname"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0));
@@ -1384,21 +1390,25 @@ public:
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
- r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String();
- if (p_preset->get("custom_package/debug") != "") {
- if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
- r_missing_templates = false;
- } else {
- err += TTR("Custom debug template not found.") + "\n";
+ if (!bool(p_preset->get("custom_package/use_custom_build"))) {
+
+ r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String();
+
+ if (p_preset->get("custom_package/debug") != "") {
+ if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
+ r_missing_templates = false;
+ } else {
+ err += TTR("Custom debug template not found.") + "\n";
+ }
}
- }
- if (p_preset->get("custom_package/release") != "") {
- if (FileAccess::exists(p_preset->get("custom_package/release"))) {
- r_missing_templates = false;
- } else {
- err += TTR("Custom release template not found.") + "\n";
+ if (p_preset->get("custom_package/release") != "") {
+ if (FileAccess::exists(p_preset->get("custom_package/release"))) {
+ r_missing_templates = false;
+ } else {
+ err += TTR("Custom release template not found.") + "\n";
+ }
}
}
@@ -1431,6 +1441,30 @@ public:
}
}
+ if (bool(p_preset->get("custom_package/use_custom_build"))) {
+ String sdk_path = EditorSettings::get_singleton()->get("export/android/custom_build_sdk_path");
+ if (sdk_path == "") {
+ err += TTR("Custom build requires a valid Android SDK path in Editor Settings.") + "\n";
+ valid = false;
+ } else {
+ Error errn;
+ DirAccess *da = DirAccess::open(sdk_path.plus_file("tools"), &errn);
+ if (errn != OK) {
+ err += TTR("Invalid Android SDK path for custom build in Editor Settings.") + "\n";
+ valid = false;
+ }
+ if (da) {
+ memdelete(da);
+ }
+ }
+
+ if (!FileAccess::exists("res://android/build/build.gradle")) {
+
+ err += TTR("Android project is not installed for compiling. Install from Editor menu.") + "\n";
+ valid = false;
+ }
+ }
+
bool apk_expansion = p_preset->get("apk_expansion/enable");
if (apk_expansion) {
@@ -1453,6 +1487,12 @@ public:
err += TTR("Invalid package name:") + " " + pn_err + "\n";
}
+ String etc_error = test_etc2();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+
r_error = err;
return valid;
}
@@ -1463,6 +1503,260 @@ public:
return list;
}
+ void _update_custom_build_project() {
+
+ DirAccessRef da = DirAccess::open("res://android");
+
+ ERR_FAIL_COND(!da);
+ Map<String, List<String> > directory_paths;
+ Map<String, List<String> > manifest_sections;
+ Map<String, List<String> > gradle_sections;
+ da->list_dir_begin();
+ String d = da->get_next();
+ while (d != String()) {
+
+ if (!d.begins_with(".") && d != "build" && da->current_is_dir()) { //a dir and not the build dir
+ //add directories found
+ DirAccessRef ds = DirAccess::open(String("res://android").plus_file(d));
+ if (ds) {
+ ds->list_dir_begin();
+ String sd = ds->get_next();
+ while (sd != String()) {
+
+ if (!sd.begins_with(".") && ds->current_is_dir()) {
+ String key = sd.to_upper();
+ if (!directory_paths.has(key)) {
+ directory_paths[key] = List<String>();
+ }
+ String path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android").plus_file(d).plus_file(sd);
+ directory_paths[key].push_back(path);
+ print_line("Add: " + sd + ":" + path);
+ }
+
+ sd = ds->get_next();
+ }
+ ds->list_dir_end();
+ }
+ //parse manifest
+ {
+ FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("AndroidManifest.conf"), FileAccess::READ);
+ if (f) {
+
+ String section;
+ while (!f->eof_reached()) {
+ String l = f->get_line();
+ String k = l.strip_edges();
+ if (k.begins_with("[")) {
+ section = k.substr(1, k.length() - 2).strip_edges().to_upper();
+ print_line("Section: " + section);
+ } else if (k != String()) {
+ if (!manifest_sections.has(section)) {
+ manifest_sections[section] = List<String>();
+ }
+ manifest_sections[section].push_back(l);
+ }
+ }
+
+ f->close();
+ }
+ }
+ //parse gradle
+ {
+ FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("gradle.conf"), FileAccess::READ);
+ if (f) {
+
+ String section;
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+ String k = l.strip_edges();
+ if (k.begins_with("[")) {
+ section = k.substr(1, k.length() - 2).strip_edges().to_upper();
+ print_line("Section: " + section);
+ } else if (k != String()) {
+ if (!gradle_sections.has(section)) {
+ gradle_sections[section] = List<String>();
+ }
+ gradle_sections[section].push_back(l);
+ }
+ }
+ }
+ }
+ }
+ d = da->get_next();
+ }
+ da->list_dir_end();
+
+ { //fix gradle build
+
+ String new_file;
+ {
+ FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::READ);
+ if (f) {
+
+ while (!f->eof_reached()) {
+ String l = f->get_line();
+
+ if (l.begins_with("//CHUNK_")) {
+ String text = l.replace_first("//CHUNK_", "");
+ int begin_pos = text.find("_BEGIN");
+ if (begin_pos != -1) {
+ text = text.substr(0, begin_pos);
+ text = text.to_upper(); //just in case
+
+ String end_marker = "//CHUNK_" + text + "_END";
+ size_t pos = f->get_position();
+ bool found = false;
+ while (!f->eof_reached()) {
+ l = f->get_line();
+ if (l.begins_with(end_marker)) {
+ found = true;
+ break;
+ }
+ }
+
+ new_file += "//CHUNK_" + text + "_BEGIN\n";
+
+ if (!found) {
+ ERR_PRINTS("No end marker found in build.gradle for chunk: " + text);
+ f->seek(pos);
+ } else {
+
+ //add chunk lines
+ if (gradle_sections.has(text)) {
+ for (List<String>::Element *E = gradle_sections[text].front(); E; E = E->next()) {
+ new_file += E->get() + "\n";
+ }
+ }
+ new_file += end_marker + "\n";
+ }
+ } else {
+ new_file += l + "\n"; //pass line by
+ }
+ } else if (l.begins_with("//DIR_")) {
+ String text = l.replace_first("//DIR_", "");
+ int begin_pos = text.find("_BEGIN");
+ if (begin_pos != -1) {
+ text = text.substr(0, begin_pos);
+ text = text.to_upper(); //just in case
+
+ String end_marker = "//DIR_" + text + "_END";
+ size_t pos = f->get_position();
+ bool found = false;
+ while (!f->eof_reached()) {
+ l = f->get_line();
+ if (l.begins_with(end_marker)) {
+ found = true;
+ break;
+ }
+ }
+
+ new_file += "//DIR_" + text + "_BEGIN\n";
+
+ if (!found) {
+ ERR_PRINTS("No end marker found in build.gradle for dir: " + text);
+ f->seek(pos);
+ } else {
+ //add chunk lines
+ if (directory_paths.has(text)) {
+ for (List<String>::Element *E = directory_paths[text].front(); E; E = E->next()) {
+ new_file += ",'" + E->get().replace("'", "\'") + "'";
+ new_file += "\n";
+ }
+ }
+ new_file += end_marker + "\n";
+ }
+ } else {
+ new_file += l + "\n"; //pass line by
+ }
+
+ } else {
+ new_file += l + "\n";
+ }
+ }
+ }
+ }
+
+ FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::WRITE);
+ f->store_string(new_file);
+ f->close();
+ }
+
+ { //fix manifest
+
+ String new_file;
+ {
+ FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::READ);
+ if (f) {
+
+ while (!f->eof_reached()) {
+ String l = f->get_line();
+
+ if (l.begins_with("<!--CHUNK_")) {
+ String text = l.replace_first("<!--CHUNK_", "");
+ int begin_pos = text.find("_BEGIN-->");
+ if (begin_pos != -1) {
+ text = text.substr(0, begin_pos);
+ text = text.to_upper(); //just in case
+
+ String end_marker = "<!--CHUNK_" + text + "_END-->";
+ size_t pos = f->get_position();
+ bool found = false;
+ while (!f->eof_reached()) {
+ l = f->get_line();
+ if (l.begins_with(end_marker)) {
+ found = true;
+ break;
+ }
+ }
+
+ new_file += "<!--CHUNK_" + text + "_BEGIN-->\n";
+
+ if (!found) {
+ ERR_PRINTS("No end marker found in AndroidManifest.conf for chunk: " + text);
+ f->seek(pos);
+ } else {
+ //add chunk lines
+ if (manifest_sections.has(text)) {
+ for (List<String>::Element *E = manifest_sections[text].front(); E; E = E->next()) {
+ new_file += E->get() + "\n";
+ }
+ }
+ new_file += end_marker + "\n";
+ }
+ } else {
+ new_file += l + "\n"; //pass line by
+ }
+
+ } else if (l.strip_edges().begins_with("<application")) {
+ String last_tag = "android:icon=\"@drawable/icon\"";
+ int last_tag_pos = l.find(last_tag);
+ if (last_tag_pos == -1) {
+ WARN_PRINTS("No adding of application tags because could not find last tag for <application: " + last_tag);
+ new_file += l + "\n";
+ } else {
+ String base = l.substr(0, last_tag_pos + last_tag.length());
+ if (manifest_sections.has("application_attribs")) {
+ for (List<String>::Element *E = manifest_sections["application_attribs"].front(); E; E = E->next()) {
+ String to_add = E->get().strip_edges();
+ base += " " + to_add + " ";
+ }
+ }
+ base += ">\n";
+ new_file += base;
+ }
+ } else {
+ new_file += l + "\n";
+ }
+ }
+ }
+ }
+
+ FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::WRITE);
+ f->store_string(new_file);
+ f->close();
+ }
+ }
+
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -1471,24 +1765,93 @@ public:
EditorProgress ep("export", "Exporting for Android", 105);
- if (p_debug)
- src_apk = p_preset->get("custom_package/debug");
- else
- src_apk = p_preset->get("custom_package/release");
+ if (bool(p_preset->get("custom_package/use_custom_build"))) { //custom build
+ //re-generate build.gradle and AndroidManifest.xml
+
+ { //test that installed build version is alright
+ FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
+ return ERR_UNCONFIGURED;
+ }
+ String version = f->get_line().strip_edges();
+ if (version != VERSION_FULL_CONFIG) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
+ return ERR_UNCONFIGURED;
+ }
+ }
+ //build project if custom build is enabled
+ String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path");
+
+ ERR_FAIL_COND_V(sdk_path == "", ERR_UNCONFIGURED);
+
+ _update_custom_build_project();
+
+ OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
+
+ String build_command;
+#ifdef WINDOWS_ENABLED
+ build_command = "gradlew.bat";
+#else
+ build_command = "gradlew";
+#endif
+
+ String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
- src_apk = src_apk.strip_edges();
- if (src_apk == "") {
+ build_command = build_path.plus_file(build_command);
+
+ List<String> cmdline;
+ cmdline.push_back("build");
+ cmdline.push_back("-p");
+ cmdline.push_back(build_path);
+ /*{ used for debug
+ int ec;
+ String pipe;
+ OS::get_singleton()->execute(build_command, cmdline, true, NULL, NULL, &ec);
+ print_line("exit code: " + itos(ec));
+ }
+ */
+ int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
+ if (result != 0) {
+ EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation."));
+ return ERR_CANT_CREATE;
+ }
if (p_debug) {
- src_apk = find_export_template("android_debug.apk");
+ src_apk = build_path.plus_file("build/outputs/apk/debug/build-debug-unsigned.apk");
} else {
- src_apk = find_export_template("android_release.apk");
+ src_apk = build_path.plus_file("build/outputs/apk/release/build-release-unsigned.apk");
+ }
+
+ if (!FileAccess::exists(src_apk)) {
+ EditorNode::get_singleton()->show_warning(TTR("No build apk generated at: ") + "\n" + src_apk);
+ return ERR_CANT_CREATE;
}
+
+ } else {
+
+ if (p_debug)
+ src_apk = p_preset->get("custom_package/debug");
+ else
+ src_apk = p_preset->get("custom_package/release");
+
+ src_apk = src_apk.strip_edges();
if (src_apk == "") {
- EditorNode::add_io_error("Package not found: " + src_apk);
- return ERR_FILE_NOT_FOUND;
+ if (p_debug) {
+ src_apk = find_export_template("android_debug.apk");
+ } else {
+ src_apk = find_export_template("android_release.apk");
+ }
+ if (src_apk == "") {
+ EditorNode::add_io_error("Package not found: " + src_apk);
+ return ERR_FILE_NOT_FOUND;
+ }
}
}
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
FileAccess *src_f = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -1909,10 +2272,6 @@ public:
zipClose(final_apk, NULL);
unzClose(tmp_unaligned);
- if (err) {
- return err;
- }
-
return OK;
}
@@ -1965,6 +2324,8 @@ void register_android_exporter() {
EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey");
EDITOR_DEF("export/android/debug_keystore_pass", "android");
EDITOR_DEF("export/android/force_system_user", false);
+ EDITOR_DEF("export/android/custom_build_sdk_path", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR, "*.keystore"));
EDITOR_DEF("export/android/timestamping_authority_url", "");
EDITOR_DEF("export/android/shutdown_adb_on_exit", true);
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index f8d46ea5d2..b8e78627ec 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -70,6 +70,8 @@ public:
virtual bool file_exists(const String &p_path); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
//static void make_default();
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
index 304c33ecac..9429100d65 100644
--- a/platform/android/file_access_jandroid.h
+++ b/platform/android/file_access_jandroid.h
@@ -32,7 +32,7 @@
#define FILE_ACCESS_JANDROID_H
#include "core/os/file_access.h"
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
class FileAccessJAndroid : public FileAccess {
static jobject io;
@@ -74,6 +74,8 @@ public:
static void setup(jobject p_io);
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
FileAccessJAndroid();
~FileAccessJAndroid();
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/java/AndroidManifest.xml
index d8fb9326ea..613d24fbd2 100644
--- a/platform/android/AndroidManifest.xml.template
+++ b/platform/android/java/AndroidManifest.xml
@@ -11,11 +11,20 @@
android:largeScreens="true"
android:xlargeScreens="true"/>
+<!--glEsVersion is modified by the exporter, changing this value here has no effect-->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
+<!--Adding custom text to manifest is fine, but do it outside the custom user and application BEGIN/ENDregions, as that gets rewritten-->
-$$ADD_PERMISSION_CHUNKS$$
+<!--Custom permissions XML added by add-ons. It's recommended to add them from the export preset, though-->
+<!--CHUNK_USER_PERMISSIONS_BEGIN-->
+<!--CHUNK_USER_PERMISSIONS_END-->
+
+<!--Anything in this line after the icon will be erased when doing custom build. If you want to add tags manually, do before it.-->
+ <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:icon="@drawable/icon">
+
+<!--The following values are replaced when Godot exports, modifying them here has no effect. Do theses changes in the-->
+<!--export preset. Adding new ones is fine.-->
- <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" $$ADD_APPATTRIBUTE_CHUNKS$$ >
<activity android:name="org.godotengine.godot.Godot"
android:label="@string/godot_project_name_string"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -32,8 +41,15 @@ $$ADD_PERMISSION_CHUNKS$$
</activity>
<service android:name="org.godotengine.godot.GodotDownloaderService" />
-$$ADD_APPLICATION_CHUNKS$$
+<!--Custom application XML added by add-ons-->
+<!--CHUNK_APPLICATION_BEGIN-->
+<!--CHUNK_APPLICATION_END-->
</application>
+ <instrumentation android:icon="@drawable/icon"
+ android:label="@string/godot_project_name_string"
+ android:name="org.godotengine.godot.GodotInstrumentation"
+ android:targetPackage="org.godotengine.game" />
+
</manifest>
diff --git a/platform/android/build.gradle.template b/platform/android/java/build.gradle
index 2fea250061..c468277daa 100644
--- a/platform/android/build.gradle.template
+++ b/platform/android/java/build.gradle
@@ -1,12 +1,17 @@
+//Gradle project for Godot Engine Android port.
+//Do not modify code between the BEGIN/END sections, as it's autogenerated by add-ons
+
buildscript {
repositories {
google()
jcenter()
- $$GRADLE_REPOSITORY_URLS$$
+//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN
+//CHUNK_BUILDSCRIPT_REPOSITORIES_END
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
- $$GRADLE_CLASSPATH$$
+//CHUNK_BUILDSCRIPT_DEPENDENCIES_BEGIN
+//CHUNK_BUILDSCRIPT_DEPENDENCIES_END
}
}
@@ -17,13 +22,16 @@ allprojects {
mavenCentral()
google()
jcenter()
- $$GRADLE_REPOSITORY_URLS$$
+//CHUNK_ALLPROJECTS_REPOSITORIES_BEGIN
+//CHUNK_ALLPROJECTS_REPOSITORIES_END
+
}
}
dependencies {
implementation "com.android.support:support-core-utils:28.0.0"
- $$GRADLE_DEPENDENCIES$$
+//CHUNK_DEPENDENCIES_BEGIN
+//CHUNK_DEPENDENCIES_END
}
android {
@@ -42,7 +50,10 @@ android {
exclude 'META-INF/NOTICE'
}
defaultConfig {
- $$GRADLE_DEFAULT_CONFIG$$
+ minSdkVersion 18
+ targetSdkVersion 28
+//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN
+//CHUNK_ANDROID_DEFAULTCONFIG_END
}
// Both signing and zip-aligning will be done at export time
buildTypes.all { buildType ->
@@ -53,36 +64,50 @@ android {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src'
- $$GRADLE_JAVA_DIRS$$
+//DIR_SRC_BEGIN
+//DIR_SRC_END
]
res.srcDirs = [
'res'
- $$GRADLE_RES_DIRS$$
+//DIR_RES_BEGIN
+//DIR_RES_END
]
aidl.srcDirs = [
'aidl'
- $$GRADLE_AIDL_DIRS$$
+//DIR_AIDL_BEGIN
+//DIR_AIDL_END
]
assets.srcDirs = [
'assets'
- $$GRADLE_ASSET_DIRS$$
+//DIR_ASSETS_BEGIN
+//DIR_ASSETS_END
+
]
}
debug.jniLibs.srcDirs = [
'libs/debug'
- $$GRADLE_JNI_DIRS$$
+//DIR_JNI_DEBUG_BEGIN
+//DIR_JNI_DEBUG_END
]
release.jniLibs.srcDirs = [
'libs/release'
- $$GRADLE_JNI_DIRS$$
+//DIR_JNI_RELEASE_BEGIN
+//DIR_JNI_RELEASE_END
]
}
+// No longer used, as it's not useful for build source template
+// applicationVariants.all { variant ->
+// variant.outputs.all { output ->
+// output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk"
+// }
+// }
- applicationVariants.all { variant ->
- variant.outputs.all { output ->
- output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk"
- }
- }
}
-$$GRADLE_PLUGINS$$
+//CHUNK_GLOBAL_BEGIN
+//CHUNK_GLOBAL_END
+
+
+
+
+
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index a10d7876f4..374d40463a 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -32,18 +32,21 @@ package org.godotengine.godot;
//import android.R;
+import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ConfigurationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Point;
import android.graphics.Rect;
@@ -56,6 +59,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Messenger;
import android.provider.Settings.Secure;
+import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
@@ -71,7 +75,6 @@ import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
-
import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller;
@@ -79,10 +82,6 @@ import com.google.android.vending.expansion.downloader.Helpers;
import com.google.android.vending.expansion.downloader.IDownloaderClient;
import com.google.android.vending.expansion.downloader.IDownloaderService;
import com.google.android.vending.expansion.downloader.IStub;
-
-import org.godotengine.godot.input.GodotEditText;
-import org.godotengine.godot.payments.PaymentsManager;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@@ -92,12 +91,15 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
-
import javax.microedition.khronos.opengles.GL10;
+import org.godotengine.godot.input.GodotEditText;
+import org.godotengine.godot.payments.PaymentsManager;
public class Godot extends Activity implements SensorEventListener, IDownloaderClient {
static final int MAX_SINGLETONS = 64;
+ static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
+ static final int REQUEST_CAMERA_PERMISSION = 2;
private IStub mDownloaderClientStub;
private IDownloaderService mRemoteService;
private TextView mStatusText;
@@ -258,6 +260,10 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
for (int i = 0; i < singleton_count; i++) {
singletons[i].onMainRequestPermissionsResult(requestCode, permissions, grantResults);
}
+
+ for (int i = 0; i < permissions.length; i++) {
+ GodotLib.requestPermissionResult(permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED);
+ }
};
public void onVideoInit() {
@@ -318,6 +324,23 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
});
}
+ public void restart() {
+ // HACK:
+ //
+ // Currently it's very hard to properly deinitialize Godot on Android to restart the game
+ // from scratch. Therefore, we need to kill the whole app process and relaunch it.
+ //
+ // Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
+ // releasing and reloading native libs or resetting their state somehow and clearing statics).
+ //
+ // Using instrumentation is a way of making the whole app process restart, because Android
+ // will kill any process of the same package which was already running.
+ //
+ Bundle args = new Bundle();
+ args.putParcelable("intent", mCurrentIntent);
+ startInstrumentation(new ComponentName(Godot.this, GodotInstrumentation.class), null, args);
+ }
+
public void alert(final String message, final String title) {
final Activity activity = this;
runOnUiThread(new Runnable() {
@@ -403,7 +426,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
io = new GodotIO(this);
- io.unique_id = Secure.ANDROID_ID;
+ io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
GodotLib.io = io;
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
@@ -415,7 +438,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
- GodotLib.initialize(this, io.needsReloadHooks(), getAssets(), use_apk_expansion);
+ GodotLib.initialize(this, getAssets(), use_apk_expansion);
result_callback = null;
@@ -580,6 +603,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
for (int i = 0; i < singleton_count; i++) {
singletons[i].onMainDestroy();
}
+
+ GodotLib.ondestroy(this);
+
super.onDestroy();
}
@@ -918,13 +944,33 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
*/
- // Audio
+ public boolean requestPermission(String p_name) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ // Not necessary, asked on install already
+ return true;
+ }
+
+ if (p_name.equals("RECORD_AUDIO")) {
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);
+ return false;
+ }
+ }
+
+ if (p_name.equals("CAMERA")) {
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
+ return false;
+ }
+ }
+ return true;
+ }
/**
- * The download state should trigger changes in the UI --- it may be useful
- * to show the state as being indeterminate at times. This sample can be
- * considered a guideline.
- */
+ * The download state should trigger changes in the UI --- it may be useful
+ * to show the state as being indeterminate at times. This sample can be
+ * considered a guideline.
+ */
@Override
public void onDownloadStateChanged(int newState) {
setState(newState);
diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java
index fb7477c09c..e7e2a3f808 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java
@@ -30,13 +30,12 @@
package org.godotengine.godot;
-import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
+import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
/**
* You should start your derived downloader class when this receiver gets the message
diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java
index 91a7b99c36..8e10710c9f 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java
@@ -33,7 +33,6 @@ package org.godotengine.godot;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
-
import com.google.android.vending.expansion.downloader.impl.DownloaderService;
/**
diff --git a/platform/android/java/src/org/godotengine/godot/GodotIO.java b/platform/android/java/src/org/godotengine/godot/GodotIO.java
index 8cee20e435..98174157ec 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotIO.java
@@ -29,28 +29,27 @@
/*************************************************************************/
package org.godotengine.godot;
-import java.util.HashMap;
-import java.util.Locale;
-import android.net.Uri;
-import android.content.Intent;
-import android.content.res.AssetManager;
-import java.io.InputStream;
-import java.io.IOException;
import android.app.*;
import android.content.*;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.AssetManager;
+import android.graphics.*;
+import android.hardware.*;
+import android.media.*;
+import android.net.Uri;
+import android.os.*;
+import android.text.*;
+import android.text.method.*;
+import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.SparseArray;
import android.view.*;
import android.view.inputmethod.InputMethodManager;
-import android.os.*;
-import android.util.Log;
-import android.util.DisplayMetrics;
-import android.graphics.*;
-import android.text.method.*;
-import android.text.*;
-import android.media.*;
-import android.hardware.*;
-import android.content.*;
-import android.content.pm.ActivityInfo;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Locale;
import org.godotengine.godot.input.*;
//android.os.Build
@@ -500,11 +499,6 @@ public class GodotIO {
return (int)(metrics.density * 160f);
}
- public boolean needsReloadHooks() {
-
- return false;
- }
-
public void showKeyboard(String p_existing_text) {
if (edit != null)
edit.showKeyboard(p_existing_text);
@@ -516,14 +510,6 @@ public class GodotIO {
public void hideKeyboard() {
if (edit != null)
edit.hideKeyboard();
-
- InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
- View v = activity.getCurrentFocus();
- if (v != null) {
- inputMgr.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- } else {
- inputMgr.hideSoftInputFromWindow(new View(activity).getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- }
};
public void setScreenOrientation(int p_orientation) {
diff --git a/platform/android/java/src/org/godotengine/godot/GodotInstrumentation.java b/platform/android/java/src/org/godotengine/godot/GodotInstrumentation.java
new file mode 100644
index 0000000000..0466f380e8
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotInstrumentation.java
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* GodotInstrumentation.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "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. */
+/*************************************************************************/
+
+package org.godotengine.godot;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class GodotInstrumentation extends Instrumentation {
+ private Intent intent;
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ intent = arguments.getParcelable("intent");
+ start();
+ }
+
+ @Override
+ public void onStart() {
+ startActivitySync(intent);
+ }
+}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java
index 29e7918645..31ca9a8500 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java
@@ -45,9 +45,10 @@ public class GodotLib {
* @param height the current view height
*/
- public static native void initialize(Godot p_instance, boolean need_reload_hook, Object p_asset_manager, boolean use_apk_expansion);
+ public static native void initialize(Godot p_instance, Object p_asset_manager, boolean use_apk_expansion);
+ public static native void ondestroy(Godot p_instance);
public static native void setup(String[] p_cmdline);
- public static native void resize(int width, int height, boolean reload);
+ public static native void resize(int width, int height);
public static native void newcontext(boolean p_32_bits);
public static native void back();
public static native void step();
@@ -69,6 +70,7 @@ public class GodotLib {
public static native String getGlobal(String p_key);
public static native void callobject(int p_ID, String p_method, Object[] p_params);
public static native void calldeferred(int p_ID, String p_method, Object[] p_params);
+ public static native void requestPermissionResult(String p_permission, boolean p_result);
public static native void setVirtualKeyboardHeight(int p_height);
}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
index c3d81c5c1d..1432cd3a67 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
@@ -32,14 +32,12 @@ package org.godotengine.godot;
import android.app.Activity;
import android.util.Log;
-
-import org.godotengine.godot.payments.PaymentsManager;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import org.godotengine.godot.payments.PaymentsManager;
+import org.json.JSONException;
+import org.json.JSONObject;
public class GodotPaymentV3 extends Godot.SingletonBase {
diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java
index ba8e8bd07b..d7cd5b4360 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotView.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotView.java
@@ -31,16 +31,15 @@
package org.godotengine.godot;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.content.ContextWrapper;
import android.graphics.PixelFormat;
+import android.hardware.input.InputManager;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.content.ContextWrapper;
-import android.view.InputDevice;
-import android.hardware.input.InputManager;
-
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
@@ -51,7 +50,6 @@ import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;
-
import org.godotengine.godot.input.InputManagerCompat;
import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
/**
@@ -79,7 +77,6 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
private Context ctx;
private GodotIO io;
- private static boolean firsttime = true;
private static boolean use_gl3 = false;
private static boolean use_32 = false;
private static boolean use_debug_opengl = false;
@@ -97,10 +94,8 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
activity = p_activity;
- if (!p_io.needsReloadHooks()) {
- //will only work on SDK 11+!!
- setPreserveEGLContextOnPause(true);
- }
+ setPreserveEGLContextOnPause(true);
+
mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext());
mInputManager.registerInputDeviceListener(this, null);
init(false, 16, 0);
@@ -718,8 +713,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
public void onSurfaceChanged(GL10 gl, int width, int height) {
- GodotLib.resize(width, height, !firsttime);
- firsttime = false;
+ GodotLib.resize(width, height);
for (int i = 0; i < Godot.singleton_count; i++) {
Godot.singletons[i].onGLSurfaceChanged(gl, width, height);
}
diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java
index 44bd462ed0..45b739baa0 100644
--- a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java
@@ -30,16 +30,15 @@
package org.godotengine.godot.input;
import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.EditText;
-import org.godotengine.godot.*;
import android.os.Handler;
import android.os.Message;
-import android.view.inputmethod.InputMethodManager;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
-
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
import java.lang.ref.WeakReference;
+import org.godotengine.godot.*;
public class GodotEditText extends EditText {
// ===========================================================
diff --git a/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java b/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java
index 3b88609cc9..e4bafa7ff9 100644
--- a/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java
+++ b/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java
@@ -23,7 +23,6 @@ import android.os.Build;
import android.os.Handler;
import android.view.InputDevice;
import android.view.MotionEvent;
-
import java.util.HashMap;
import java.util.Map;
diff --git a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java
index 1d42aa4464..f872e7af56 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java
@@ -30,13 +30,11 @@
package org.godotengine.godot.payments;
-import com.android.vending.billing.IInAppBillingService;
-
import android.content.Context;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.util.Log;
-
+import com.android.vending.billing.IInAppBillingService;
import java.lang.ref.WeakReference;
abstract public class ConsumeTask {
diff --git a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java
index 835779ba00..5424ebb49d 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java
@@ -30,13 +30,6 @@
package org.godotengine.godot.payments;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.utils.Crypt;
-import com.android.vending.billing.IInAppBillingService;
-
import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
@@ -47,6 +40,11 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
+import com.android.vending.billing.IInAppBillingService;
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.utils.Crypt;
+import org.json.JSONException;
+import org.json.JSONObject;
abstract public class HandlePurchaseTask {
diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
index 747a4ffd45..a0dbc432c1 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
@@ -40,17 +40,14 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
-
import com.android.vending.billing.IInAppBillingService;
-
+import java.util.ArrayList;
+import java.util.Arrays;
import org.godotengine.godot.Godot;
import org.godotengine.godot.GodotPaymentV3;
import org.json.JSONException;
import org.json.JSONObject;
-import java.util.ArrayList;
-import java.util.Arrays;
-
public class PaymentsManager {
public static final int BILLING_RESPONSE_RESULT_OK = 0;
diff --git a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java
index 000aaa9456..650c5178f0 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java
@@ -30,13 +30,6 @@
package org.godotengine.godot.payments;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.utils.Crypt;
-import com.android.vending.billing.IInAppBillingService;
-
import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
@@ -47,6 +40,11 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
+import com.android.vending.billing.IInAppBillingService;
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.utils.Crypt;
+import org.json.JSONException;
+import org.json.JSONObject;
abstract public class PurchaseTask {
diff --git a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
index cf750872d5..daca6ef5ae 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
@@ -34,14 +34,11 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
-
import com.android.vending.billing.IInAppBillingService;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import org.json.JSONException;
+import org.json.JSONObject;
abstract public class ReleaseAllConsumablesTask {
diff --git a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java
index 6701f9396a..d32c80e8e0 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java
@@ -30,17 +30,6 @@
package org.godotengine.godot.payments;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.godotengine.godot.Godot;
-import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.GodotPaymentV3;
-import org.godotengine.godot.utils.Crypt;
-import org.godotengine.godot.utils.HttpRequester;
-import org.godotengine.godot.utils.RequestParams;
-import com.android.vending.billing.IInAppBillingService;
-
import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
@@ -51,8 +40,16 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
-
+import com.android.vending.billing.IInAppBillingService;
import java.lang.ref.WeakReference;
+import org.godotengine.godot.Godot;
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.GodotPaymentV3;
+import org.godotengine.godot.utils.Crypt;
+import org.godotengine.godot.utils.HttpRequester;
+import org.godotengine.godot.utils.RequestParams;
+import org.json.JSONException;
+import org.json.JSONObject;
abstract public class ValidateTask {
diff --git a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
index 3806d4bcad..b61007faa3 100644
--- a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
+++ b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
@@ -37,10 +37,8 @@ import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
-
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
-
import org.apache.http.conn.ssl.SSLSocketFactory;
/**
diff --git a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java
index e9c81eb2e5..e98f533c23 100644
--- a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java
+++ b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java
@@ -30,6 +30,9 @@
package org.godotengine.godot.utils;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -39,7 +42,6 @@ import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
@@ -64,10 +66,6 @@ import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
/**
*
* @author Luis Linietsky <luis.linietsky@gmail.com>
diff --git a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java
index c5778102f6..b9fe0dd0c9 100644
--- a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java
+++ b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java
@@ -34,7 +34,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
-
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index 4be1106967..2bed1f0892 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "java_class_wrapper.h"
+#include "string_android.h"
#include "thread_jandroid.h"
bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error, Variant &ret) {
@@ -553,7 +554,7 @@ void JavaClassWrapper::_bind_methods() {
bool JavaClassWrapper::_get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig) {
jstring name2 = (jstring)env->CallObjectMethod(obj, Class_getName);
- String str_type = env->GetStringUTFChars(name2, NULL);
+ String str_type = jstring_to_string(name2, env);
env->DeleteLocalRef(name2);
uint32_t t = 0;
@@ -697,7 +698,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
} break;
case ARG_TYPE_STRING: {
- var = String::utf8(env->GetStringUTFChars((jstring)obj, NULL));
+ var = jstring_to_string((jstring)obj, env);
return true;
} break;
case ARG_TYPE_CLASS: {
@@ -1030,7 +1031,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
if (!o)
ret.push_back(Variant());
else {
- String val = String::utf8(env->GetStringUTFChars((jstring)o, NULL));
+ String val = jstring_to_string((jstring)o, env);
ret.push_back(val);
}
env->DeleteLocalRef(o);
@@ -1075,7 +1076,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
ERR_CONTINUE(!obj);
jstring name = (jstring)env->CallObjectMethod(obj, getName);
- String str_method = env->GetStringUTFChars(name, NULL);
+ String str_method = jstring_to_string(name, env);
env->DeleteLocalRef(name);
Vector<String> params;
@@ -1204,7 +1205,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
ERR_CONTINUE(!obj);
jstring name = (jstring)env->CallObjectMethod(obj, Field_getName);
- String str_field = env->GetStringUTFChars(name, NULL);
+ String str_field = jstring_to_string(name, env);
env->DeleteLocalRef(name);
int mods = env->CallIntMethod(obj, Field_getModifiers);
if ((mods & 0x8) && (mods & 0x10) && (mods & 0x1)) { //static final public!
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
new file mode 100644
index 0000000000..0c41b85939
--- /dev/null
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -0,0 +1,207 @@
+/*************************************************************************/
+/* java_godot_io_wrapper.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "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 "java_godot_io_wrapper.h"
+#include "core/error_list.h"
+
+// JNIEnv is only valid within the thread it belongs to, in a multi threading environment
+// we can't cache it.
+// For GodotIO we call all access methods from our thread and we thus get a valid JNIEnv
+// from ThreadAndroid.
+
+GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instance) {
+ godot_io_instance = p_env->NewGlobalRef(p_godot_io_instance);
+ if (godot_io_instance) {
+ cls = p_env->GetObjectClass(godot_io_instance);
+ if (cls) {
+ cls = (jclass)p_env->NewGlobalRef(cls);
+ } else {
+ // this is a pretty serious fail.. bail... pointers will stay 0
+ return;
+ }
+
+ _open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
+ _get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;");
+ _get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
+ _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
+ _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
+ _get_unique_ID = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
+ _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;)V");
+ _hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
+ _set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
+ _get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(I)Ljava/lang/String;");
+ _play_video = p_env->GetMethodID(cls, "playVideo", "(Ljava/lang/String;)V");
+ _is_video_playing = p_env->GetMethodID(cls, "isVideoPlaying", "()Z");
+ _pause_video = p_env->GetMethodID(cls, "pauseVideo", "()V");
+ _stop_video = p_env->GetMethodID(cls, "stopVideo", "()V");
+ }
+}
+
+GodotIOJavaWrapper::~GodotIOJavaWrapper() {
+ // nothing to do here for now
+}
+
+jobject GodotIOJavaWrapper::get_instance() {
+ return godot_io_instance;
+}
+
+Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
+ if (_open_URI) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
+ return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
+ } else {
+ return ERR_UNAVAILABLE;
+ }
+}
+
+String GodotIOJavaWrapper::get_user_data_dir() {
+ if (_get_data_dir) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
+String GodotIOJavaWrapper::get_locale() {
+ if (_get_locale) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_locale);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
+String GodotIOJavaWrapper::get_model() {
+ if (_get_model) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_model);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
+int GodotIOJavaWrapper::get_screen_dpi() {
+ if (_get_screen_DPI) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ return env->CallIntMethod(godot_io_instance, _get_screen_DPI);
+ } else {
+ return 160;
+ }
+}
+
+String GodotIOJavaWrapper::get_unique_id() {
+ if (_get_unique_ID) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_unique_ID);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
+bool GodotIOJavaWrapper::has_vk() {
+ return (_show_keyboard != 0) && (_hide_keyboard != 0);
+}
+
+void GodotIOJavaWrapper::show_vk(const String &p_existing) {
+ if (_show_keyboard) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
+ env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr);
+ }
+}
+
+void GodotIOJavaWrapper::hide_vk() {
+ if (_hide_keyboard) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io_instance, _hide_keyboard);
+ }
+}
+
+void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
+ if (_set_screen_orientation) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient);
+ }
+}
+
+String GodotIOJavaWrapper::get_system_dir(int p_dir) {
+ if (_get_system_dir) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
+ return jstring_to_string(s, env);
+ } else {
+ return String(".");
+ }
+}
+
+void GodotIOJavaWrapper::play_video(const String &p_path) {
+ // Why is this not here?!?!
+}
+
+bool GodotIOJavaWrapper::is_video_playing() {
+ if (_is_video_playing) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ return env->CallBooleanMethod(godot_io_instance, _is_video_playing);
+ } else {
+ return false;
+ }
+}
+
+void GodotIOJavaWrapper::pause_video() {
+ if (_pause_video) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io_instance, _pause_video);
+ }
+}
+
+void GodotIOJavaWrapper::stop_video() {
+ if (_stop_video) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io_instance, _stop_video);
+ }
+}
+
+// volatile because it can be changed from non-main thread and we need to
+// ensure the change is immediately visible to other threads.
+static volatile int virtual_keyboard_height;
+
+int GodotIOJavaWrapper::get_vk_height() {
+ return virtual_keyboard_height;
+}
+
+void GodotIOJavaWrapper::set_vk_height(int p_height) {
+ virtual_keyboard_height = p_height;
+}
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
new file mode 100644
index 0000000000..920c433b08
--- /dev/null
+++ b/platform/android/java_godot_io_wrapper.h
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* java_godot_io_wrapper.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "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. */
+/*************************************************************************/
+
+// note, swapped java and godot around in the file name so all the java
+// wrappers are together
+
+#ifndef JAVA_GODOT_IO_WRAPPER_H
+#define JAVA_GODOT_IO_WRAPPER_H
+
+#include <android/log.h>
+#include <jni.h>
+
+#include "string_android.h"
+
+// Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++
+class GodotIOJavaWrapper {
+private:
+ jobject godot_io_instance;
+ jclass cls;
+
+ jmethodID _open_URI = 0;
+ jmethodID _get_data_dir = 0;
+ jmethodID _get_locale = 0;
+ jmethodID _get_model = 0;
+ jmethodID _get_screen_DPI = 0;
+ jmethodID _get_unique_ID = 0;
+ jmethodID _show_keyboard = 0;
+ jmethodID _hide_keyboard = 0;
+ jmethodID _set_screen_orientation = 0;
+ jmethodID _get_system_dir = 0;
+ jmethodID _play_video = 0;
+ jmethodID _is_video_playing = 0;
+ jmethodID _pause_video = 0;
+ jmethodID _stop_video = 0;
+
+public:
+ GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instance);
+ ~GodotIOJavaWrapper();
+
+ jobject get_instance();
+
+ Error open_uri(const String &p_uri);
+ String get_user_data_dir();
+ String get_locale();
+ String get_model();
+ int get_screen_dpi();
+ String get_unique_id();
+ bool has_vk();
+ void show_vk(const String &p_existing);
+ void hide_vk();
+ int get_vk_height();
+ void set_vk_height(int p_height);
+ void set_screen_orientation(int p_orient);
+ String get_system_dir(int p_dir);
+ void play_video(const String &p_path);
+ bool is_video_playing();
+ void pause_video();
+ void stop_video();
+};
+
+#endif /* !JAVA_GODOT_IO_WRAPPER_H */
diff --git a/platform/android/java_glue.cpp b/platform/android/java_godot_lib_jni.cpp
index 885fb185a7..466f79c215 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* java_glue.cpp */
+/* java_godot_lib_jni.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
+#include "java_godot_io_wrapper.h"
+#include "java_godot_wrapper.h"
+
#include "android/asset_manager_jni.h"
#include "audio_driver_jandroid.h"
#include "core/engine.h"
@@ -41,11 +44,14 @@
#include "main/input_default.h"
#include "main/main.h"
#include "os_android.h"
+#include "string_android.h"
#include "thread_jandroid.h"
#include <unistd.h>
static JavaClassWrapper *java_class_wrapper = NULL;
static OS_Android *os_android = NULL;
+static GodotJavaWrapper *godot_java = NULL;
+static GodotIOJavaWrapper *godot_io_java = NULL;
struct jvalret {
@@ -223,7 +229,7 @@ String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
jboolean isarr = env->CallBooleanMethod(cls, isArray);
(*array) = isarr ? true : false;
}
- String name = env->GetStringUTFChars(clsName, NULL);
+ String name = jstring_to_string(clsName, env);
env->DeleteLocalRef(clsName);
return name;
@@ -241,7 +247,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
if (name == "java.lang.String") {
- return String::utf8(env->GetStringUTFChars((jstring)obj, NULL));
+ return jstring_to_string((jstring)obj, env);
};
if (name == "[Ljava.lang.String;") {
@@ -252,7 +258,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
for (int i = 0; i < stringCount; i++) {
jstring string = (jstring)env->GetObjectArrayElement(arr, i);
- sarr.push_back(String::utf8(env->GetStringUTFChars(string, NULL)));
+ sarr.push_back(jstring_to_string(string, env));
env->DeleteLocalRef(string);
}
@@ -487,7 +493,7 @@ public:
case Variant::STRING: {
jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- ret = String::utf8(env->GetStringUTFChars((jstring)o, NULL));
+ ret = jstring_to_string((jstring)o, env);
env->DeleteLocalRef(o);
} break;
case Variant::POOL_STRING_ARRAY: {
@@ -587,251 +593,73 @@ TST tst;
static bool initialized = false;
static int step = 0;
+
static Size2 new_size;
static Vector3 accelerometer;
static Vector3 gravity;
static Vector3 magnetometer;
static Vector3 gyroscope;
static HashMap<String, JNISingleton *> jni_singletons;
-static jobject godot_io;
-
-typedef void (*GFXInitFunc)(void *ud, bool gl2);
-
-static jmethodID _on_video_init = 0;
-static jobject _godot_instance;
-
-static jmethodID _openURI = 0;
-static jmethodID _getDataDir = 0;
-static jmethodID _getLocale = 0;
-static jmethodID _getClipboard = 0;
-static jmethodID _setClipboard = 0;
-static jmethodID _getModel = 0;
-static jmethodID _getScreenDPI = 0;
-static jmethodID _showKeyboard = 0;
-static jmethodID _hideKeyboard = 0;
-static jmethodID _setScreenOrientation = 0;
-static jmethodID _getUniqueID = 0;
-static jmethodID _getSystemDir = 0;
-static jmethodID _getGLESVersionCode = 0;
-static jmethodID _playVideo = 0;
-static jmethodID _isVideoPlaying = 0;
-static jmethodID _pauseVideo = 0;
-static jmethodID _stopVideo = 0;
-static jmethodID _setKeepScreenOn = 0;
-static jmethodID _alertDialog = 0;
-
-static void _gfx_init_func(void *ud, bool gl2) {
-}
-
-static int _open_uri(const String &p_uri) {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
- return env->CallIntMethod(godot_io, _openURI, jStr);
-}
-
-static String _get_user_data_dir() {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(godot_io, _getDataDir);
- return String(env->GetStringUTFChars(s, NULL));
-}
-
-static String _get_locale() {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(godot_io, _getLocale);
- return String(env->GetStringUTFChars(s, NULL));
-}
-
-static String _get_clipboard() {
- JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(_godot_instance, _getClipboard);
- return String(env->GetStringUTFChars(s, NULL));
-}
-
-static void _set_clipboard(const String &p_text) {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
- env->CallVoidMethod(_godot_instance, _setClipboard, jStr);
-}
-
-static String _get_model() {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(godot_io, _getModel);
- return String(env->GetStringUTFChars(s, NULL));
-}
-
-static int _get_screen_dpi() {
-
- JNIEnv *env = ThreadAndroid::get_env();
- return env->CallIntMethod(godot_io, _getScreenDPI);
-}
-
-static String _get_unique_id() {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(godot_io, _getUniqueID);
- return String(env->GetStringUTFChars(s, NULL));
-}
-
-static void _show_vk(const String &p_existing) {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
- env->CallVoidMethod(godot_io, _showKeyboard, jStr);
-}
-
-static void _set_screen_orient(int p_orient) {
-
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(godot_io, _setScreenOrientation, p_orient);
-}
-
-static String _get_system_dir(int p_dir) {
-
- JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(godot_io, _getSystemDir, p_dir);
- return String(env->GetStringUTFChars(s, NULL));
-}
-
-static int _get_gles_version_code() {
- JNIEnv *env = ThreadAndroid::get_env();
- return env->CallIntMethod(_godot_instance, _getGLESVersionCode);
-}
-
-static void _hide_vk() {
-
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(godot_io, _hideKeyboard);
-}
// virtual Error native_video_play(String p_path);
// virtual bool native_video_is_playing();
// virtual void native_video_pause();
// virtual void native_video_stop();
-static void _play_video(const String &p_path) {
-}
-
-static bool _is_video_playing() {
- JNIEnv *env = ThreadAndroid::get_env();
- return env->CallBooleanMethod(godot_io, _isVideoPlaying);
- //return false;
-}
-
-static void _pause_video() {
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(godot_io, _pauseVideo);
-}
-
-static void _stop_video() {
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(godot_io, _stopVideo);
-}
-
-static void _set_keep_screen_on(bool p_enabled) {
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(_godot_instance, _setKeepScreenOn, p_enabled);
-}
-
-static void _alert(const String &p_message, const String &p_title) {
- JNIEnv *env = ThreadAndroid::get_env();
- jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
- jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
- env->CallVoidMethod(_godot_instance, _alertDialog, jStrMessage, jStrTitle);
-}
-
-// volatile because it can be changed from non-main thread and we need to
-// ensure the change is immediately visible to other threads.
-static volatile int virtual_keyboard_height;
-
-static int _get_vk_height() {
- return virtual_keyboard_height;
-}
-
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height) {
- virtual_keyboard_height = p_height;
+ if (godot_io_java) {
+ godot_io_java->set_vk_height(p_height);
+ }
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion) {
initialized = true;
JavaVM *jvm;
env->GetJavaVM(&jvm);
- _godot_instance = env->NewGlobalRef(activity);
- //_godot_instance=activity;
-
- {
- //setup IO Object
+ // create our wrapper classes
+ godot_java = new GodotJavaWrapper(env, activity); // our activity is our godot instance is our activity..
+ godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env));
- jclass cls = env->FindClass("org/godotengine/godot/Godot");
- if (cls) {
-
- cls = (jclass)env->NewGlobalRef(cls);
- }
-
- jfieldID fid = env->GetStaticFieldID(cls, "io", "Lorg/godotengine/godot/GodotIO;");
- jobject ob = env->GetStaticObjectField(cls, fid);
- jobject gob = env->NewGlobalRef(ob);
-
- godot_io = gob;
-
- _on_video_init = env->GetMethodID(cls, "onVideoInit", "()V");
- _setKeepScreenOn = env->GetMethodID(cls, "setKeepScreenOn", "(Z)V");
- _alertDialog = env->GetMethodID(cls, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
- _getGLESVersionCode = env->GetMethodID(cls, "getGLESVersionCode", "()I");
- _getClipboard = env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
- _setClipboard = env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
-
- if (cls) {
- jclass c = env->GetObjectClass(gob);
- _openURI = env->GetMethodID(c, "openURI", "(Ljava/lang/String;)I");
- _getDataDir = env->GetMethodID(c, "getDataDir", "()Ljava/lang/String;");
- _getLocale = env->GetMethodID(c, "getLocale", "()Ljava/lang/String;");
- _getModel = env->GetMethodID(c, "getModel", "()Ljava/lang/String;");
- _getScreenDPI = env->GetMethodID(c, "getScreenDPI", "()I");
- _getUniqueID = env->GetMethodID(c, "getUniqueID", "()Ljava/lang/String;");
- _showKeyboard = env->GetMethodID(c, "showKeyboard", "(Ljava/lang/String;)V");
- _hideKeyboard = env->GetMethodID(c, "hideKeyboard", "()V");
- _setScreenOrientation = env->GetMethodID(c, "setScreenOrientation", "(I)V");
- _getSystemDir = env->GetMethodID(c, "getSystemDir", "(I)Ljava/lang/String;");
- _playVideo = env->GetMethodID(c, "playVideo", "(Ljava/lang/String;)V");
- _isVideoPlaying = env->GetMethodID(c, "isVideoPlaying", "()Z");
- _pauseVideo = env->GetMethodID(c, "pauseVideo", "()V");
- _stopVideo = env->GetMethodID(c, "stopVideo", "()V");
- }
-
- ThreadAndroid::make_default(jvm);
+ ThreadAndroid::make_default(jvm);
#ifdef USE_JAVA_FILE_ACCESS
- FileAccessJAndroid::setup(gob);
+ FileAccessJAndroid::setup(godot_io_java->get_instance());
#else
- jobject amgr = env->NewGlobalRef(p_asset_manager);
+ jobject amgr = env->NewGlobalRef(p_asset_manager);
- FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
+ FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
#endif
- DirAccessJAndroid::setup(gob);
- AudioDriverAndroid::setup(gob);
- }
- 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, _get_gles_version_code, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, _set_clipboard, _get_clipboard, p_use_apk_expansion);
- os_android->set_need_reload_hooks(p_need_reload_hook);
+ DirAccessJAndroid::setup(godot_io_java->get_instance());
+ AudioDriverAndroid::setup(godot_io_java->get_instance());
+
+ os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion);
char wd[500];
getcwd(wd, 500);
- env->CallVoidMethod(_godot_instance, _on_video_init);
+ godot_java->on_video_init(env);
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env) {
+ // lets cleanup
+ if (godot_io_java) {
+ delete godot_io_java;
+ }
+ if (godot_java) {
+ delete godot_java;
+ }
+ if (os_android) {
+ delete os_android;
+ }
}
static void _initialize_java_modules() {
if (!ProjectSettings::get_singleton()->has_setting("android/modules")) {
- print_line("Android modules: Nothing to load, aborting");
return;
}
@@ -843,27 +671,19 @@ static void _initialize_java_modules() {
Vector<String> mods = modules.split(",", false);
if (mods.size()) {
+ jobject cls = godot_java->get_class_loader();
- JNIEnv *env = ThreadAndroid::get_env();
-
- jclass activityClass = env->FindClass("org/godotengine/godot/Godot");
-
- jmethodID getClassLoader = env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
-
- jobject cls = env->CallObjectMethod(_godot_instance, getClassLoader);
- //cls=env->NewGlobalRef(cls);
+ // TODO create wrapper for class loader
+ JNIEnv *env = ThreadAndroid::get_env();
jclass classLoader = env->FindClass("java/lang/ClassLoader");
- //classLoader=(jclass)env->NewGlobalRef(classLoader);
-
jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
for (int i = 0; i < mods.size(); i++) {
String m = mods[i];
- //jclass singletonClass = env->FindClass(m.utf8().get_data());
- print_line("Loading module: " + m);
+ print_line("Loading Android module: " + m);
jstring strClassName = env->NewStringUTF(m.utf8().get_data());
jclass singletonClass = (jclass)env->CallObjectMethod(cls, findClass, strClassName);
@@ -872,7 +692,6 @@ static void _initialize_java_modules() {
ERR_EXPLAIN("Couldn't find singleton for class: " + m);
ERR_CONTINUE(!singletonClass);
}
- //singletonClass=(jclass)env->NewGlobalRef(singletonClass);
jmethodID initialize = env->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
@@ -881,7 +700,7 @@ static void _initialize_java_modules() {
ERR_EXPLAIN("Couldn't find proper initialize function 'public static Godot.SingletonBase Class::initialize(Activity p_activity)' initializer for singleton class: " + m);
ERR_CONTINUE(!initialize);
}
- jobject obj = env->CallStaticObjectMethod(singletonClass, initialize, _godot_instance);
+ jobject obj = env->CallStaticObjectMethod(singletonClass, initialize, godot_java->get_activity());
env->NewGlobalRef(obj);
}
}
@@ -891,12 +710,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
ThreadAndroid::setup_thread();
const char **cmdline = NULL;
+ jstring *j_cmdline = NULL;
int cmdlen = 0;
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
- cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *));
+ cmdline = (const char **)malloc((cmdlen + 1) * sizeof(const char *));
cmdline[cmdlen] = NULL;
+ j_cmdline = (jstring *)malloc(cmdlen * sizeof(jstring));
for (int i = 0; i < cmdlen; i++) {
@@ -904,12 +725,19 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
const char *rawString = env->GetStringUTFChars(string, 0);
cmdline[i] = rawString;
+ j_cmdline[i] = string;
}
}
}
Error err = Main::setup("apk", cmdlen, (char **)cmdline, false);
if (cmdline) {
+ if (j_cmdline) {
+ for (int i = 0; i < cmdlen; ++i) {
+ env->ReleaseStringUTFChars(j_cmdline[i], cmdline[i]);
+ }
+ free(j_cmdline);
+ }
free(cmdline);
}
@@ -917,12 +745,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
return; //should exit instead and print the error
}
- java_class_wrapper = memnew(JavaClassWrapper(_godot_instance));
+ java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
Engine::get_singleton()->add_singleton(Engine::Singleton("JavaClassWrapper", java_class_wrapper));
_initialize_java_modules();
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height) {
if (os_android)
os_android->set_display_size(Size2(width, height));
@@ -931,12 +759,15 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) {
if (os_android) {
- os_android->set_context_is_16_bits(!p_32_bits);
- }
-
- if (os_android && step > 0) {
-
- os_android->reload_gfx();
+ if (step == 0) {
+ // During startup
+ os_android->set_context_is_16_bits(!p_32_bits);
+ } else {
+ // GL context recreated because it was lost; restart app to let it reload everything
+ os_android->main_loop_end();
+ godot_java->restart(env);
+ step = -1; // Ensure no further steps are attempted
+ }
}
}
@@ -948,6 +779,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, job
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) {
+ if (step == -1)
+ return;
+
if (step == 0) {
// Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id,
@@ -967,18 +801,13 @@ 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);
if (os_android->main_loop_iterate()) {
- jclass cls = env->FindClass("org/godotengine/godot/Godot");
- jmethodID _finish = env->GetMethodID(cls, "forceQuit", "()V");
- env->CallVoidMethod(_godot_instance, _finish);
+ godot_java->force_quit(env);
}
}
@@ -1313,7 +1142,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) {
if (os_android) {
- String name = env->GetStringUTFChars(p_name, NULL);
+ String name = jstring_to_string(p_name, env);
os_android->joy_connection_changed(p_device, p_connected, name);
}
}
@@ -1386,7 +1215,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jo
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env, jobject obj, jstring name, jobject p_object) {
- String singname = env->GetStringUTFChars(name, NULL);
+ String singname = jstring_to_string(name, env);
JNISingleton *s = memnew(JNISingleton);
s->set_instance(env->NewGlobalRef(p_object));
jni_singletons[singname] = s;
@@ -1463,21 +1292,21 @@ static const char *get_jni_sig(const String &p_type) {
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path) {
- String js = env->GetStringUTFChars(path, NULL);
+ String js = jstring_to_string(path, env);
return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
- String singname = env->GetStringUTFChars(sname, NULL);
+ String singname = jstring_to_string(sname, env);
ERR_FAIL_COND(!jni_singletons.has(singname));
JNISingleton *s = jni_singletons.get(singname);
- String mname = env->GetStringUTFChars(name, NULL);
- String retval = env->GetStringUTFChars(ret, NULL);
+ String mname = jstring_to_string(name, env);
+ String retval = jstring_to_string(ret, env);
Vector<Variant::Type> types;
String cs = "(";
@@ -1486,9 +1315,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j
for (int i = 0; i < stringCount; i++) {
jstring string = (jstring)env->GetObjectArrayElement(args, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
- types.push_back(get_jni_type(String(rawString)));
- cs += get_jni_sig(String(rawString));
+ const String rawString = jstring_to_string(string, env);
+ types.push_back(get_jni_type(rawString));
+ cs += get_jni_sig(rawString);
}
cs += ")";
@@ -1511,7 +1340,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
int res = env->PushLocalFrame(16);
ERR_FAIL_COND(res != 0);
- String str_method = env->GetStringUTFChars(method, NULL);
+ String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
Variant *vlist = (Variant *)alloca(sizeof(Variant) * count);
@@ -1543,7 +1372,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
int res = env->PushLocalFrame(16);
ERR_FAIL_COND(res != 0);
- String str_method = env->GetStringUTFChars(method, NULL);
+ String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
Variant args[VARIANT_ARG_MAX];
@@ -1561,6 +1390,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
env->PopLocalFrame(NULL);
}
-//Main::cleanup();
-
-//return os.get_exit_code();
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jobject p_obj, jstring p_permission, jboolean p_result) {
+ String permission = jstring_to_string(p_permission, env);
+ if (permission == "android.permission.RECORD_AUDIO" && p_result) {
+ AudioDriver::get_singleton()->capture_start();
+ }
+}
diff --git a/platform/android/java_glue.h b/platform/android/java_godot_lib_jni.h
index e8d0d55bb3..3a03294b08 100644
--- a/platform/android/java_glue.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* java_glue.h */
+/* java_godot_lib_jni.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVA_GLUE_H
-#define JAVA_GLUE_H
+#ifndef JAVA_GODOT_LIB_JNI_H
+#define JAVA_GODOT_LIB_JNI_H
#include <android/log.h>
#include <jni.h>
+// These functions can be called from within JAVA and are the means by which our JAVA implementation calls back into our C++ code.
+// See java/src/org/godotengine/godot/GodotLib.java for the JAVA side of this (yes thats why we have the long names)
extern "C" {
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj);
@@ -60,6 +63,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jobject p_obj, jstring p_permission, jboolean p_result);
}
-#endif // JAVA_GLUE_H
+#endif /* !JAVA_GODOT_LIB_JNI_H */
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
new file mode 100644
index 0000000000..101a1d76c6
--- /dev/null
+++ b/platform/android/java_godot_wrapper.cpp
@@ -0,0 +1,185 @@
+/*************************************************************************/
+/* java_godot_wrapper.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "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 "java_godot_wrapper.h"
+
+// JNIEnv is only valid within the thread it belongs to, in a multi threading environment
+// we can't cache it.
+// For Godot we call most access methods from our thread and we thus get a valid JNIEnv
+// from ThreadAndroid. For one or two we expect to pass the environment
+
+// TODO we could probably create a base class for this...
+
+GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
+ godot_instance = p_env->NewGlobalRef(p_godot_instance);
+
+ // get info about our Godot class so we can get pointers and stuff...
+ cls = p_env->FindClass("org/godotengine/godot/Godot");
+ if (cls) {
+ cls = (jclass)p_env->NewGlobalRef(cls);
+ } else {
+ // this is a pretty serious fail.. bail... pointers will stay 0
+ return;
+ }
+
+ // get some method pointers...
+ _on_video_init = p_env->GetMethodID(cls, "onVideoInit", "()V");
+ _restart = p_env->GetMethodID(cls, "restart", "()V");
+ _finish = p_env->GetMethodID(cls, "forceQuit", "()V");
+ _set_keep_screen_on = p_env->GetMethodID(cls, "setKeepScreenOn", "(Z)V");
+ _alert = p_env->GetMethodID(cls, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
+ _get_GLES_version_code = p_env->GetMethodID(cls, "getGLESVersionCode", "()I");
+ _get_clipboard = p_env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
+ _set_clipboard = p_env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
+ _request_permission = p_env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z");
+}
+
+GodotJavaWrapper::~GodotJavaWrapper() {
+ // nothing to do here for now
+}
+
+jobject GodotJavaWrapper::get_activity() {
+ // our godot instance is our activity
+ return godot_instance;
+}
+
+jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env) {
+ if (cls) {
+ if (p_env == NULL)
+ p_env = ThreadAndroid::get_env();
+
+ jfieldID fid = p_env->GetStaticFieldID(cls, p_name, p_class);
+ return p_env->GetStaticObjectField(cls, fid);
+ } else {
+ return NULL;
+ }
+}
+
+jobject GodotJavaWrapper::get_class_loader() {
+ if (cls) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jmethodID getClassLoader = env->GetMethodID(cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
+ return env->CallObjectMethod(godot_instance, getClassLoader);
+ } else {
+ return NULL;
+ }
+}
+
+void GodotJavaWrapper::gfx_init(bool gl2) {
+ // beats me what this once did, there was no code,
+ // but we're getting false if our GLES3 driver is initialised
+ // and true for our GLES2 driver
+ // Maybe we're supposed to communicate this back or store it?
+}
+
+void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
+ if (_on_video_init)
+ if (p_env == NULL)
+ p_env = ThreadAndroid::get_env();
+
+ p_env->CallVoidMethod(godot_instance, _on_video_init);
+}
+
+void GodotJavaWrapper::restart(JNIEnv *p_env) {
+ if (_restart)
+ if (p_env == NULL)
+ p_env = ThreadAndroid::get_env();
+
+ p_env->CallVoidMethod(godot_instance, _restart);
+}
+
+void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
+ if (_finish)
+ if (p_env == NULL)
+ p_env = ThreadAndroid::get_env();
+
+ p_env->CallVoidMethod(godot_instance, _finish);
+}
+
+void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
+ if (_set_keep_screen_on) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_instance, _set_keep_screen_on, p_enabled);
+ }
+}
+
+void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
+ if (_alert) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
+ jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
+ env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle);
+ }
+}
+
+int GodotJavaWrapper::get_gles_version_code() {
+ JNIEnv *env = ThreadAndroid::get_env();
+ if (_get_GLES_version_code) {
+ return env->CallIntMethod(godot_instance, _get_GLES_version_code);
+ }
+
+ return 0;
+}
+
+bool GodotJavaWrapper::has_get_clipboard() {
+ return _get_clipboard != 0;
+}
+
+String GodotJavaWrapper::get_clipboard() {
+ if (_get_clipboard) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_clipboard);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
+bool GodotJavaWrapper::has_set_clipboard() {
+ return _set_clipboard != 0;
+}
+
+void GodotJavaWrapper::set_clipboard(const String &p_text) {
+ if (_set_clipboard) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
+ env->CallVoidMethod(godot_instance, _set_clipboard, jStr);
+ }
+}
+
+bool GodotJavaWrapper::request_permission(const String &p_name) {
+ if (_request_permission) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
+ return env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
+ } else {
+ return false;
+ }
+}
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
new file mode 100644
index 0000000000..438aee019b
--- /dev/null
+++ b/platform/android/java_godot_wrapper.h
@@ -0,0 +1,81 @@
+/*************************************************************************/
+/* java_godot_wrapper.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "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. */
+/*************************************************************************/
+
+// note, swapped java and godot around in the file name so all the java
+// wrappers are together
+
+#ifndef JAVA_GODOT_WRAPPER_H
+#define JAVA_GODOT_WRAPPER_H
+
+#include <android/log.h>
+#include <jni.h>
+
+#include "string_android.h"
+
+// Class that makes functions in java/src/org/godotengine/godot/Godot.java callable from C++
+class GodotJavaWrapper {
+private:
+ jobject godot_instance;
+ jclass cls;
+
+ jmethodID _on_video_init = 0;
+ jmethodID _restart = 0;
+ jmethodID _finish = 0;
+ jmethodID _set_keep_screen_on = 0;
+ jmethodID _alert = 0;
+ jmethodID _get_GLES_version_code = 0;
+ jmethodID _get_clipboard = 0;
+ jmethodID _set_clipboard = 0;
+ jmethodID _request_permission = 0;
+
+public:
+ GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
+ ~GodotJavaWrapper();
+
+ jobject get_activity();
+ jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = NULL);
+
+ jobject get_class_loader();
+
+ void gfx_init(bool gl2);
+ void on_video_init(JNIEnv *p_env = NULL);
+ void restart(JNIEnv *p_env = NULL);
+ void force_quit(JNIEnv *p_env = NULL);
+ void set_keep_screen_on(bool p_enabled);
+ void alert(const String &p_message, const String &p_title);
+ int get_gles_version_code();
+ bool has_get_clipboard();
+ String get_clipboard();
+ bool has_set_clipboard();
+ void set_clipboard(const String &p_text);
+ bool request_permission(const String &p_name);
+};
+
+#endif /* !JAVA_GODOT_WRAPPER_H */
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 3ba8468e0b..93d39859f2 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -46,6 +46,9 @@
#include <dlfcn.h>
+#include "java_godot_io_wrapper.h"
+#include "java_godot_wrapper.h"
+
class AndroidLogger : public Logger {
public:
virtual void logv(const char *p_format, va_list p_list, bool p_err) {
@@ -118,20 +121,19 @@ int OS_Android::get_current_video_driver() const {
Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
- bool use_gl3 = get_gl_version_code_func() >= 0x00030000;
+ bool use_gl3 = godot_java->get_gles_version_code() >= 0x00030000;
use_gl3 = use_gl3 && (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES3");
bool gl_initialization_error = false;
while (true) {
if (use_gl3) {
if (RasterizerGLES3::is_viable() == OK) {
- if (gfx_init_func)
- gfx_init_func(gfx_init_ud, false);
+ godot_java->gfx_init(false);
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
p_video_driver = VIDEO_DRIVER_GLES2;
use_gl3 = false;
continue;
@@ -142,8 +144,7 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
}
} else {
if (RasterizerGLES2::is_viable() == OK) {
- if (gfx_init_func)
- gfx_init_func(gfx_init_ud, true);
+ godot_java->gfx_init(true);
RasterizerGLES2::register_config();
RasterizerGLES2::make_current();
break;
@@ -195,11 +196,23 @@ void OS_Android::finalize() {
memdelete(input);
}
+GodotJavaWrapper *OS_Android::get_godot_java() {
+ return godot_java;
+}
+
+GodotIOJavaWrapper *OS_Android::get_godot_io_java() {
+ return godot_io_java;
+}
+
void OS_Android::alert(const String &p_alert, const String &p_title) {
//print("ALERT: %s\n", p_alert.utf8().get_data());
- if (alert_func)
- alert_func(p_alert, p_title);
+ godot_java->alert(p_alert, p_title);
+}
+
+bool OS_Android::request_permission(const String &p_name) {
+
+ return godot_java->request_permission(p_name);
}
Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
@@ -256,9 +269,7 @@ void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen)
void OS_Android::set_keep_screen_on(bool p_enabled) {
OS::set_keep_screen_on(p_enabled);
- if (set_keep_screen_on_func) {
- set_keep_screen_on_func(p_enabled);
- }
+ godot_java->set_keep_screen_on(p_enabled);
}
Size2 OS_Android::get_window_size() const {
@@ -281,14 +292,6 @@ bool OS_Android::can_draw() const {
return true; //always?
}
-void OS_Android::set_cursor_shape(CursorShape p_shape) {
-
- //android really really really has no mouse.. how amazing..
-}
-
-void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-}
-
void OS_Android::main_loop_begin() {
if (main_loop)
@@ -499,18 +502,16 @@ bool OS_Android::has_virtual_keyboard() const {
}
int OS_Android::get_virtual_keyboard_height() const {
- if (get_virtual_keyboard_height_func) {
- return get_virtual_keyboard_height_func();
- }
+ return godot_io_java->get_vk_height();
- ERR_PRINT("Cannot obtain virtual keyboard height.");
- return 0;
+ // ERR_PRINT("Cannot obtain virtual keyboard height.");
+ // return 0;
}
void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) {
- if (show_virtual_keyboard_func) {
- show_virtual_keyboard_func(p_existing_text);
+ if (godot_io_java->has_vk()) {
+ godot_io_java->show_vk(p_existing_text);
} else {
ERR_PRINT("Virtual keyboard not available");
@@ -519,9 +520,9 @@ void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect
void OS_Android::hide_virtual_keyboard() {
- if (hide_virtual_keyboard_func) {
+ if (godot_io_java->has_vk()) {
- hide_virtual_keyboard_func();
+ godot_io_java->hide_vk();
} else {
ERR_PRINT("Virtual keyboard not available");
@@ -548,19 +549,9 @@ void OS_Android::set_display_size(Size2 p_size) {
default_videomode.height = p_size.y;
}
-void OS_Android::reload_gfx() {
-
- if (gfx_init_func)
- gfx_init_func(gfx_init_ud, use_gl2);
- //if (rasterizer)
- // rasterizer->reload_vram();
-}
-
Error OS_Android::shell_open(String p_uri) {
- if (open_uri_func)
- return open_uri_func(p_uri) ? ERR_CANT_OPEN : OK;
- return ERR_UNAVAILABLE;
+ return godot_io_java->open_uri(p_uri);
}
String OS_Android::get_resource_dir() const {
@@ -570,23 +561,29 @@ String OS_Android::get_resource_dir() const {
String OS_Android::get_locale() const {
- if (get_locale_func)
- return get_locale_func();
+ String locale = godot_io_java->get_locale();
+ if (locale != "") {
+ return locale;
+ }
+
return OS_Unix::get_locale();
}
void OS_Android::set_clipboard(const String &p_text) {
- if (set_clipboard_func) {
- set_clipboard_func(p_text);
+ // DO we really need the fallback to OS_Unix here?!
+ if (godot_java->has_set_clipboard()) {
+ godot_java->set_clipboard(p_text);
} else {
OS_Unix::set_clipboard(p_text);
}
}
String OS_Android::get_clipboard() const {
- if (get_clipboard_func) {
- return get_clipboard_func();
+
+ // DO we really need the fallback to OS_Unix here?!
+ if (godot_java->has_get_clipboard()) {
+ return godot_java->get_clipboard();
}
return OS_Unix::get_clipboard();
@@ -594,22 +591,16 @@ String OS_Android::get_clipboard() const {
String OS_Android::get_model_name() const {
- if (get_model_func)
- return get_model_func();
+ String model = godot_io_java->get_model();
+ if (model != "")
+ return model;
+
return OS_Unix::get_model_name();
}
int OS_Android::get_screen_dpi(int p_screen) const {
- if (get_screen_dpi_func) {
- return get_screen_dpi_func();
- }
- return 160;
-}
-
-void OS_Android::set_need_reload_hooks(bool p_needs_them) {
-
- use_reload_hooks = p_needs_them;
+ return godot_io_java->get_screen_dpi();
}
String OS_Android::get_user_data_dir() const {
@@ -617,8 +608,8 @@ String OS_Android::get_user_data_dir() const {
if (data_dir_cache != String())
return data_dir_cache;
- if (get_user_data_dir_func) {
- String data_dir = get_user_data_dir_func();
+ String data_dir = godot_io_java->get_user_data_dir();
+ if (data_dir != "") {
//store current dir
char real_current_dir_name[2048];
@@ -645,45 +636,43 @@ String OS_Android::get_user_data_dir() const {
void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
- if (set_screen_orientation_func)
- set_screen_orientation_func(p_orientation);
+ godot_io_java->set_screen_orientation(p_orientation);
}
String OS_Android::get_unique_id() const {
- if (get_unique_id_func)
- return get_unique_id_func();
+ String unique_id = godot_io_java->get_unique_id();
+ if (unique_id != "")
+ return unique_id;
+
return OS::get_unique_id();
}
Error OS_Android::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
// FIXME: Add support for volume, audio and subtitle tracks
- if (video_play_func)
- video_play_func(p_path);
+
+ godot_io_java->play_video(p_path);
return OK;
}
bool OS_Android::native_video_is_playing() const {
- if (video_is_playing_func)
- return video_is_playing_func();
- return false;
+
+ return godot_io_java->is_video_playing();
}
void OS_Android::native_video_pause() {
- if (video_pause_func)
- video_pause_func();
+
+ godot_io_java->pause_video();
}
String OS_Android::get_system_dir(SystemDir p_dir) const {
- if (get_system_dir_func)
- return get_system_dir_func(p_dir);
- return String(".");
+ return godot_io_java->get_system_dir(p_dir);
}
void OS_Android::native_video_stop() {
- if (video_stop_func)
- video_stop_func();
+
+ godot_io_java->stop_video();
}
void OS_Android::set_context_is_16_bits(bool p_is_16) {
@@ -706,7 +695,7 @@ String OS_Android::get_joy_guid(int p_device) const {
}
bool OS_Android::_check_internal_feature_support(const String &p_feature) {
- if (p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2") {
+ if (p_feature == "mobile") {
//TODO support etc2 only if GLES3 driver is selected
return true;
}
@@ -726,7 +715,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) {
return false;
}
-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, GetGLVersionCodeFunc p_get_gl_version_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, SetClipboardFunc p_set_clipboard_func, GetClipboardFunc p_get_clipboard_func, bool p_use_apk_expansion) {
+OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion) {
use_apk_expansion = p_use_apk_expansion;
default_videomode.width = 800;
@@ -734,38 +723,13 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI
default_videomode.fullscreen = true;
default_videomode.resizable = false;
- gfx_init_func = p_gfx_init_func;
- gfx_init_ud = p_gfx_init_ud;
main_loop = NULL;
gl_extensions = NULL;
//rasterizer = NULL;
use_gl2 = false;
- open_uri_func = p_open_uri_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;
- get_unique_id_func = p_get_unique_id;
- get_system_dir_func = p_get_sdir_func;
- get_gl_version_code_func = p_get_gl_version_func;
-
- video_play_func = p_video_play_func;
- video_is_playing_func = p_video_is_playing_func;
- video_pause_func = p_video_pause_func;
- video_stop_func = p_video_stop_func;
-
- show_virtual_keyboard_func = p_show_vk;
- hide_virtual_keyboard_func = p_hide_vk;
- get_virtual_keyboard_height_func = p_vk_height_func;
-
- set_clipboard_func = p_set_clipboard_func;
- get_clipboard_func = p_get_clipboard_func;
-
- set_screen_orientation_func = p_screen_orient;
- set_keep_screen_on_func = p_set_keep_screen_on_func;
- alert_func = p_alert_func;
- use_reload_hooks = false;
+ godot_java = p_godot_java;
+ godot_io_java = p_godot_io_java;
Vector<Logger *> loggers;
loggers.push_back(memnew(AndroidLogger));
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 1e5b89e24d..d2198b0579 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -41,28 +41,8 @@
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
-typedef void (*GFXInitFunc)(void *ud, bool gl2);
-typedef int (*OpenURIFunc)(const String &);
-typedef String (*GetUserDataDirFunc)();
-typedef String (*GetLocaleFunc)();
-typedef void (*SetClipboardFunc)(const String &);
-typedef String (*GetClipboardFunc)();
-typedef String (*GetModelFunc)();
-typedef int (*GetScreenDPIFunc)();
-typedef String (*GetUniqueIDFunc)();
-typedef void (*ShowVirtualKeyboardFunc)(const String &);
-typedef void (*HideVirtualKeyboardFunc)();
-typedef void (*SetScreenOrientationFunc)(int);
-typedef String (*GetSystemDirFunc)(int);
-typedef int (*GetGLVersionCodeFunc)();
-
-typedef void (*VideoPlayFunc)(const String &);
-typedef bool (*VideoIsPlayingFunc)();
-typedef void (*VideoPauseFunc)();
-typedef void (*VideoStopFunc)();
-typedef void (*SetKeepScreenOnFunc)(bool p_enabled);
-typedef void (*AlertFunc)(const String &, const String &);
-typedef int (*VirtualKeyboardHeightFunc)();
+class GodotJavaWrapper;
+class GodotIOJavaWrapper;
class OS_Android : public OS_Unix {
public:
@@ -90,11 +70,7 @@ public:
private:
Vector<TouchPos> touch;
- GFXInitFunc gfx_init_func;
- void *gfx_init_ud;
-
bool use_gl2;
- bool use_reload_hooks;
bool use_apk_expansion;
bool use_16bits_fbo;
@@ -112,29 +88,11 @@ private:
VideoMode default_videomode;
MainLoop *main_loop;
- OpenURIFunc open_uri_func;
- GetUserDataDirFunc get_user_data_dir_func;
- GetLocaleFunc get_locale_func;
- SetClipboardFunc set_clipboard_func;
- GetClipboardFunc get_clipboard_func;
- GetModelFunc get_model_func;
- GetScreenDPIFunc get_screen_dpi_func;
- ShowVirtualKeyboardFunc show_virtual_keyboard_func;
- HideVirtualKeyboardFunc hide_virtual_keyboard_func;
- VirtualKeyboardHeightFunc get_virtual_keyboard_height_func;
- SetScreenOrientationFunc set_screen_orientation_func;
- GetUniqueIDFunc get_unique_id_func;
- GetSystemDirFunc get_system_dir_func;
- GetGLVersionCodeFunc get_gl_version_code_func;
-
- VideoPlayFunc video_play_func;
- VideoIsPlayingFunc video_is_playing_func;
- VideoPauseFunc video_pause_func;
- VideoStopFunc video_stop_func;
- SetKeepScreenOnFunc set_keep_screen_on_func;
- AlertFunc alert_func;
-
- //PowerAndroid *power_manager;
+ GodotJavaWrapper *godot_java;
+ GodotIOJavaWrapper *godot_io_java;
+
+ //PowerAndroid *power_manager_func;
+
int video_driver_index;
public:
@@ -158,8 +116,11 @@ public:
typedef int64_t ProcessID;
static OS *get_singleton();
+ GodotJavaWrapper *get_godot_java();
+ GodotIOJavaWrapper *get_godot_io_java();
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+ virtual bool request_permission(const String &p_name);
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
@@ -183,9 +144,6 @@ public:
virtual bool can_draw() const;
- virtual void set_cursor_shape(CursorShape p_shape);
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
-
void main_loop_begin();
bool main_loop_iterate();
void main_loop_request_go_back();
@@ -203,10 +161,8 @@ public:
void set_opengl_extensions(const char *p_gl_extensions);
void set_display_size(Size2 p_size);
- void reload_gfx();
void set_context_is_16_bits(bool p_is_16);
- void set_need_reload_hooks(bool p_needs_them);
virtual void set_screen_orientation(ScreenOrientation p_orientation);
virtual Error shell_open(String p_uri);
@@ -241,7 +197,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, 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, GetGLVersionCodeFunc p_get_gl_version_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, SetClipboardFunc p_set_clipboard, GetClipboardFunc p_get_clipboard, bool p_use_apk_expansion);
+ OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion);
~OS_Android();
};
diff --git a/platform/android/string_android.h b/platform/android/string_android.h
new file mode 100644
index 0000000000..fe627a3e0c
--- /dev/null
+++ b/platform/android/string_android.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* string_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "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 STRING_ANDROID_H
+#define STRING_ANDROID_H
+#include "core/ustring.h"
+#include "thread_jandroid.h"
+#include <jni.h>
+
+/**
+ * Converts JNI jstring to Godot String.
+ * @param source Source JNI string. If null an empty string is returned.
+ * @param env JNI environment instance. If null obtained by ThreadAndroid::get_env().
+ * @return Godot string instance.
+ */
+static inline String jstring_to_string(jstring source, JNIEnv *env = NULL) {
+ String result;
+ if (source) {
+ if (!env) {
+ env = ThreadAndroid::get_env();
+ }
+ const char *const source_utf8 = env->GetStringUTFChars(source, NULL);
+ if (source_utf8) {
+ result.parse_utf8(source_utf8);
+ env->ReleaseStringUTFChars(source, source_utf8);
+ }
+ }
+ return result;
+}
+
+#endif // STRING_ANDROID_H
diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp
index 8b7dd08bb7..3c4e31da36 100644
--- a/platform/haiku/audio_driver_media_kit.cpp
+++ b/platform/haiku/audio_driver_media_kit.cpp
@@ -39,11 +39,11 @@ int32_t *AudioDriverMediaKit::samples_in = NULL;
Error AudioDriverMediaKit::init() {
active = false;
- mix_rate = 44100;
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
- int latency = GLOBAL_DEF_RST("audio/output_latency", 25);
+ int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
buffer_size = next_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels);
diff --git a/platform/haiku/context_gl_haiku.h b/platform/haiku/context_gl_haiku.h
index 6eb67fea70..8452f5fbfb 100644
--- a/platform/haiku/context_gl_haiku.h
+++ b/platform/haiku/context_gl_haiku.h
@@ -33,12 +33,10 @@
#if defined(OPENGL_ENABLED)
-#include "drivers/gl_context/context_gl.h"
-
#include "haiku_direct_window.h"
#include "haiku_gl_view.h"
-class ContextGL_Haiku : public ContextGL {
+class ContextGL_Haiku {
private:
HaikuGLView *view;
HaikuDirectWindow *window;
@@ -46,18 +44,18 @@ private:
bool use_vsync;
public:
- virtual Error initialize();
- virtual void release_current();
- virtual void make_current();
- virtual void swap_buffers();
- virtual int get_window_width();
- virtual int get_window_height();
+ Error initialize();
+ void release_current();
+ void make_current();
+ void swap_buffers();
+ int get_window_width();
+ int get_window_height();
- virtual void set_use_vsync(bool p_use);
- virtual bool is_using_vsync() const;
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
ContextGL_Haiku(HaikuDirectWindow *p_window);
- virtual ~ContextGL_Haiku();
+ ~ContextGL_Haiku();
};
#endif
diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py
index ae8cc58a4a..874b1ab1fb 100644
--- a/platform/haiku/detect.py
+++ b/platform/haiku/detect.py
@@ -150,6 +150,6 @@ def configure(env):
env.Append(CPPPATH=['#platform/haiku'])
env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES_ENABLED'])
env.Append(CPPFLAGS=['-DMEDIA_KIT_ENABLED'])
- # env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+ # env.Append(CPPFLAGS=['-DFREETYPE_ENABLED'])
env.Append(CPPFLAGS=['-DPTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np
env.Append(LIBS=['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL'])
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index a5b2e66a22..f3fed6669b 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -203,6 +203,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
}
+OS::CursorShape OS_Haiku::get_cursor_shape() const {
+ // TODO: implement get_cursor_shape
+}
+
void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// TODO
}
@@ -322,7 +326,7 @@ String OS_Haiku::get_executable_path() const {
bool OS_Haiku::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc" || p_feature == "s3tc";
+ return p_feature == "pc";
}
String OS_Haiku::get_config_path() const {
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index d7eac10635..6ab006843a 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -86,6 +86,7 @@ public:
virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const;
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual int get_screen_count() const;
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index 41991bce86..fa1b124561 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -2,8 +2,6 @@
Import('env')
-import os
-
iphone_lib = [
'godot_iphone.cpp',
'os_iphone.cpp',
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index bb0c11c767..64405bfa5b 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -598,8 +598,10 @@ static int frame_count = 0;
};
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
- OS::get_singleton()->get_main_loop()->notification(
- MainLoop::NOTIFICATION_OS_MEMORY_WARNING);
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(
+ MainLoop::NOTIFICATION_OS_MEMORY_WARNING);
+ }
};
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
@@ -613,18 +615,6 @@ static int frame_count = 0;
// Create a full-screen window
window = [[UIWindow alloc] initWithFrame:rect];
- // window.autoresizesSubviews = YES;
- //[window setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
- // UIViewAutoresizingFlexibleWidth];
-
- // Create the OpenGL ES view and add it to the window
- GLView *glView = [[GLView alloc] initWithFrame:rect];
- printf("glview is %p\n", glView);
- //[window addSubview:glView];
- glView.delegate = self;
- // glView.autoresizesSubviews = YES;
- //[glView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
- // UIViewAutoresizingFlexibleWidth];
OS::VideoMode vm = _get_video_mode();
@@ -639,6 +629,12 @@ static int frame_count = 0;
return FALSE;
};
+ // WARNING: We must *always* create the GLView after we have constructed the
+ // OS with iphone_main. This allows the GLView to access project settings so
+ // it can properly initialize the OpenGL context
+ GLView *glView = [[GLView alloc] initWithFrame:rect];
+ glView.delegate = self;
+
view_controller = [[ViewController alloc] init];
view_controller.view = glView;
window.rootViewController = view_controller;
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index d0e6a4cefe..d56e28a4af 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -1,5 +1,4 @@
import os
-import string
import sys
from methods import detect_darwin_sdk_path
@@ -46,20 +45,21 @@ def configure(env):
if (env["target"].startswith("release")):
env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1'])
if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Append(CPPFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer'])
+ env.Append(CCFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer'])
env.Append(LINKFLAGS=['-O2'])
else: #optimize for size
- env.Append(CPPFLAGS=['-Os', '-ftree-vectorize'])
+ env.Append(CCFLAGS=['-Os', '-ftree-vectorize'])
env.Append(LINKFLAGS=['-Os'])
if env["target"] == "release_debug":
env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
elif (env["target"] == "debug"):
- env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Append(CCFLAGS=['-gdwarf-2', '-O0'])
+ env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
if (env["use_lto"]):
- env.Append(CPPFLAGS=['-flto'])
+ env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto'])
## Architecture
@@ -105,7 +105,7 @@ def configure(env):
detect_darwin_sdk_path('iphonesimulator', env)
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=10.0 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"').split())
+ 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=10.0').split())
elif (env["arch"] == "arm"):
detect_darwin_sdk_path('iphone', env)
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=10.0 -MMD -MT dependencies'.split())
@@ -116,9 +116,9 @@ def configure(env):
env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON'])
if env['ios_exceptions']:
- env.Append(CPPFLAGS=['-fexceptions'])
+ env.Append(CCFLAGS=['-fexceptions'])
else:
- env.Append(CPPFLAGS=['-fno-exceptions'])
+ env.Append(CCFLAGS=['-fno-exceptions'])
## Link flags
@@ -174,11 +174,3 @@ def configure(env):
env.Append(CPPPATH=['#platform/iphone'])
env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DCOREAUDIO_ENABLED'])
-
- # TODO: Move that to opus module's config
- if 'module_opus_enabled' in env and env['module_opus_enabled']:
- env.opus_fixed_point = "yes"
- if (env["arch"] == "arm"):
- env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
- elif (env["arch"] == "arm64"):
- env.Append(CFLAGS=["-DOPUS_ARM64_OPT"])
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index d234ddac27..85d4b9e847 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -196,15 +196,16 @@ public:
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- if (p_preset->get("texture_format/s3tc")) {
- r_features->push_back("s3tc");
- }
- if (p_preset->get("texture_format/etc")) {
+ String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
+ if (driver == "GLES2") {
r_features->push_back("etc");
- }
- if (p_preset->get("texture_format/etc2")) {
+ } else if (driver == "GLES3") {
r_features->push_back("etc2");
+ if (ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2")) {
+ r_features->push_back("etc");
+ }
}
+
Vector<String> architectures = _get_preset_architectures(p_preset);
for (int i = 0; i < architectures.size(); ++i) {
r_features->push_back(architectures[i]);
@@ -268,7 +269,6 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description"), "Godot would like to use your camera"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description"), "Godot would like to use your microphone"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description"), "Godot would like to use your photos"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true));
@@ -290,10 +290,6 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), ""));
}
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true));
-
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));
@@ -402,9 +398,6 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
} else if (lines[i].find("$camera_usage_description") != -1) {
String description = p_preset->get("privacy/camera_usage_description");
strnew += lines[i].replace("$camera_usage_description", description) + "\n";
- } else if (lines[i].find("$microphone_usage_description") != -1) {
- String description = p_preset->get("privacy/microphone_usage_description");
- strnew += lines[i].replace("$microphone_usage_description", description) + "\n";
} else if (lines[i].find("$photolibrary_usage_description") != -1) {
String description = p_preset->get("privacy/photolibrary_usage_description");
strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
@@ -846,6 +839,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
}
+ if (!DirAccess::exists(dest_dir)) {
+ return ERR_FILE_BAD_PATH;
+ }
+
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da) {
String current_dir = da->get_current_dir();
@@ -1150,6 +1147,12 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
}
}
+ String etc_error = test_etc2();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+
if (!err.empty())
r_error = err;
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
index 6f4d0ddb57..1cb8d0e44e 100644
--- a/platform/iphone/gl_view.mm
+++ b/platform/iphone/gl_view.mm
@@ -284,19 +284,37 @@ static void clear_touches() {
kEAGLColorFormatRGBA8,
kEAGLDrawablePropertyColorFormat,
nil];
+ bool fallback_gl2 = false;
+ // Create a GL ES 3 context based on the gl driver from project settings
+ if (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES3") {
+ context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
+ NSLog(@"Setting up an OpenGL ES 3.0 context. Based on Project Settings \"rendering/quality/driver/driver_name\"");
+ if (!context && GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
+ gles3_available = false;
+ fallback_gl2 = true;
+ NSLog(@"Failed to create OpenGL ES 3.0 context. Falling back to OpenGL ES 2.0");
+ }
+ }
- // Create our EAGLContext, and if successful make it current and create our framebuffer.
- context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
-
- if (!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer]) {
+ // Create GL ES 2 context
+ if (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES2" || fallback_gl2) {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
- gles3_available = false;
- if (!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer]) {
- [self release];
+ NSLog(@"Setting up an OpenGL ES 2.0 context.");
+ if (!context) {
+ NSLog(@"Failed to create OpenGL ES 2.0 context!");
return nil;
}
}
+ if (![EAGLContext setCurrentContext:context]) {
+ NSLog(@"Failed to set EAGLContext!");
+ return nil;
+ }
+ if (![self createFramebuffer]) {
+ NSLog(@"Failed to create frame buffer!");
+ return nil;
+ }
+
// Default the animation interval to 1/60th of a second.
animationInterval = 1.0 / 60.0;
return self;
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index c939e234b9..e25efc813b 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -120,7 +120,7 @@ Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
p_video_driver = VIDEO_DRIVER_GLES2;
use_gl3 = false;
continue;
@@ -490,17 +490,11 @@ void OSIPhone::set_keep_screen_on(bool p_enabled) {
_set_keep_screen_on(p_enabled);
};
-void OSIPhone::set_cursor_shape(CursorShape p_shape){
-
-};
-
String OSIPhone::get_user_data_dir() const {
return data_dir;
};
-void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){};
-
String OSIPhone::get_name() {
return "iOS";
@@ -587,7 +581,7 @@ void OSIPhone::native_video_stop() {
bool OSIPhone::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2";
+ return p_feature == "mobile";
}
// Initialization order between compilation units is not guaranteed,
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 30d7a1ba41..49c6475cf9 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -167,9 +167,6 @@ public:
virtual void hide_virtual_keyboard();
virtual int get_virtual_keyboard_height() const;
- virtual void set_cursor_shape(CursorShape p_shape);
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
-
virtual Size2 get_window_size() const;
virtual Rect2 get_window_safe_area() const;
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index a93c98a89f..85a633442e 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -20,6 +20,13 @@ for lib in js_libraries:
env.Append(LINKFLAGS=['--js-library', env.File(lib).path])
env.Depends(build, js_libraries)
+js_modules = [
+ 'id_handler.js',
+]
+for module in js_modules:
+ env.Append(LINKFLAGS=['--pre-js', env.File(module).path])
+env.Depends(build, js_modules)
+
wrapper_start = env.File('pre.js')
wrapper_end = env.File('engine.js')
js_wrapped = env.Textfile('#bin/godot', [wrapper_start, js, wrapper_end], TEXTFILESUFFIX='${PROGSUFFIX}.wrapped.js')
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 3cc79097f8..c7acbde3f7 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -1,5 +1,4 @@
import os
-import sys
def is_active():
@@ -136,7 +135,3 @@ def configure(env):
# TODO: Reevaluate usage of this setting now that engine.js manages engine runtime.
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']:
- env.opus_fixed_point = 'yes'
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 123c6ae645..487da77b10 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -104,22 +104,27 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- if (p_preset->get("texture_format/s3tc")) {
+ if (p_preset->get("vram_texture_compression/for_desktop")) {
r_features->push_back("s3tc");
}
- if (p_preset->get("texture_format/etc")) {
- r_features->push_back("etc");
- }
- if (p_preset->get("texture_format/etc2")) {
- r_features->push_back("etc2");
+
+ if (p_preset->get("vram_texture_compression/for_mobile")) {
+ String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
+ if (driver == "GLES2") {
+ r_features->push_back("etc");
+ } else if (driver == "GLES3") {
+ r_features->push_back("etc2");
+ if (ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2")) {
+ r_features->push_back("etc");
+ }
+ }
}
}
void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_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"), ""));
@@ -167,10 +172,19 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p
}
}
+ r_missing_templates = !valid;
+
+ if (p_preset->get("vram_texture_compression/for_mobile")) {
+ String etc_error = test_etc2();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+ }
+
if (!err.empty())
r_error = err;
- r_missing_templates = !valid;
return valid;
}
@@ -200,6 +214,10 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE);
}
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
if (template_path != String() && !FileAccess::exists(template_path)) {
EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path);
return ERR_FILE_NOT_FOUND;
@@ -349,7 +367,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
if (err) {
return err;
}
- OS::get_singleton()->shell_open(path);
+ OS::get_singleton()->shell_open(String("file://") + path);
return OK;
}
diff --git a/platform/javascript/id_handler.js b/platform/javascript/id_handler.js
new file mode 100644
index 0000000000..36ef5aa8ef
--- /dev/null
+++ b/platform/javascript/id_handler.js
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* id_handler.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 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 IDHandler = function() {
+
+ var ids = {};
+ var size = 0;
+
+ this.has = function(id) {
+ return ids.hasOwnProperty(id);
+ }
+
+ this.add = function(obj) {
+ size += 1;
+ var id = crypto.getRandomValues(new Int32Array(32))[0];
+ ids[id] = obj;
+ return id;
+ }
+
+ this.get = function(id) {
+ return ids[id];
+ }
+
+ this.remove = function(id) {
+ size -= 1;
+ delete ids[id];
+ }
+
+ this.size = function() {
+ return size;
+ }
+
+ this.ids = ids;
+};
+
+Module.IDHandler = new IDHandler;
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 594c0a46cc..34781ce365 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -829,7 +829,7 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
p_video_driver = VIDEO_DRIVER_GLES2;
gles3 = false;
continue;
@@ -1071,16 +1071,6 @@ bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
return true;
#endif
- EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context();
- // All extensions are already automatically enabled, this function allows
- // checking WebGL extension support without inline JavaScript
- if (p_feature == "s3tc")
- return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc_srgb");
- if (p_feature == "etc")
- return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc1");
- if (p_feature == "etc2")
- return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc");
-
return false;
}
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index d2952ebdc0..e15b4339a7 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -2,7 +2,6 @@
Import('env')
-import os
from platform_methods import run_in_subprocess
import platform_osx_builders
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 36a753e683..8024897195 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -53,16 +53,18 @@ def configure(env):
elif (env["target"] == "release_debug"):
if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-O2'])
else: #optimize for size
- env.Prepend(CCFLAGS=['-Os', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-Os'])
+ env.Prepend(CPPFLAGS=['-DDEBUG_ENABLED'])
if (env["debug_symbols"] == "yes"):
env.Prepend(CCFLAGS=['-g1'])
if (env["debug_symbols"] == "full"):
env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "debug"):
- env.Prepend(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Prepend(CCFLAGS=['-g3'])
+ env.Prepend(CPPFLAGS=['-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
## Architecture
@@ -88,10 +90,10 @@ def configure(env):
env['AR'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar"
env['RANLIB'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib"
env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as"
- env.Append(CCFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
+ env.Append(CPPFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
detect_darwin_sdk_path('osx', env)
- env.Append(CPPFLAGS=['-isysroot', '$MACOS_SDK_PATH'])
+ env.Append(CCFLAGS=['-isysroot', '$MACOS_SDK_PATH'])
env.Append(LINKFLAGS=['-isysroot', '$MACOS_SDK_PATH'])
else: # osxcross build
@@ -110,7 +112,7 @@ def configure(env):
env['AR'] = basecmd + "ar"
env['RANLIB'] = basecmd + "ranlib"
env['AS'] = basecmd + "as"
- env.Append(CCFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
+ env.Append(CPPFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
if (env["CXX"] == "clang++"):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
@@ -129,5 +131,5 @@ def configure(env):
env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo'])
env.Append(LIBS=['pthread'])
- env.Append(CPPFLAGS=['-mmacosx-version-min=10.9'])
+ env.Append(CCFLAGS=['-mmacosx-version-min=10.9'])
env.Append(LINKFLAGS=['-mmacosx-version-min=10.9'])
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index b8f6977b39..1a63d6ff75 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -425,6 +425,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
}
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
FileAccess *src_f = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -564,7 +568,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
f->close();
if (is_execute) {
// Chmod with 0755 if the file is executable
- f->_chmod(file, 0755);
+ FileAccess::set_unix_permissions(file, 0755);
}
memdelete(f);
} else {
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index dfe7b27bd0..125a88ab6d 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -172,6 +172,7 @@ public:
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_mouse_show(bool p_show);
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 4e4d9c9eea..fec524c04b 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -102,8 +102,6 @@ static void push_to_key_event_buffer(const OS_OSX::KeyEvent &p_event) {
static int mouse_x = 0;
static int mouse_y = 0;
-static int prev_mouse_x = 0;
-static int prev_mouse_y = 0;
static int button_mask = 0;
static bool mouse_down_control = false;
@@ -273,6 +271,8 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
- (void)windowDidExitFullScreen:(NSNotification *)notification {
OS_OSX::singleton->zoomed = false;
+ if (!OS_OSX::singleton->resizable)
+ [OS_OSX::singleton->window_object setStyleMask:[OS_OSX::singleton->window_object styleMask] & ~NSWindowStyleMaskResizable];
}
- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
@@ -337,6 +337,11 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
}
- (void)windowDidMove:(NSNotification *)notification {
+
+ if (OS_OSX::singleton->get_main_loop()) {
+ OS_OSX::singleton->input->release_pressed_events();
+ }
+
/*
[window->nsgl.context update];
@@ -601,12 +606,13 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
Ref<InputEventMouseButton> mb;
mb.instance();
-
+ const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
+ const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
get_key_modifier_state([event modifierFlags], mb);
mb->set_button_index(index);
mb->set_pressed(pressed);
- mb->set_position(Vector2(mouse_x, mouse_y));
- mb->set_global_position(Vector2(mouse_x, mouse_y));
+ mb->set_position(pos);
+ mb->set_global_position(pos);
mb->set_button_mask(button_mask);
if (index == BUTTON_LEFT && pressed) {
mb->set_doubleclick([event clickCount] == 2);
@@ -642,8 +648,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
mm.instance();
mm->set_button_mask(button_mask);
- prev_mouse_x = mouse_x;
- prev_mouse_y = mouse_y;
const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
mm->set_position(pos);
@@ -713,8 +717,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
- if (OS_OSX::singleton->input)
- OS_OSX::singleton->input->set_mouse_in_window(false);
}
- (void)mouseEntered:(NSEvent *)event {
@@ -722,8 +724,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
return;
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
- if (OS_OSX::singleton->input)
- OS_OSX::singleton->input->set_mouse_in_window(true);
OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape;
OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
@@ -765,9 +765,41 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
[super updateTrackingAreas];
}
+static bool isNumpadKey(unsigned int key) {
+
+ static const unsigned int table[] = {
+ 0x41, /* kVK_ANSI_KeypadDecimal */
+ 0x43, /* kVK_ANSI_KeypadMultiply */
+ 0x45, /* kVK_ANSI_KeypadPlus */
+ 0x47, /* kVK_ANSI_KeypadClear */
+ 0x4b, /* kVK_ANSI_KeypadDivide */
+ 0x4c, /* kVK_ANSI_KeypadEnter */
+ 0x4e, /* kVK_ANSI_KeypadMinus */
+ 0x51, /* kVK_ANSI_KeypadEquals */
+ 0x52, /* kVK_ANSI_Keypad0 */
+ 0x53, /* kVK_ANSI_Keypad1 */
+ 0x54, /* kVK_ANSI_Keypad2 */
+ 0x55, /* kVK_ANSI_Keypad3 */
+ 0x56, /* kVK_ANSI_Keypad4 */
+ 0x57, /* kVK_ANSI_Keypad5 */
+ 0x58, /* kVK_ANSI_Keypad6 */
+ 0x59, /* kVK_ANSI_Keypad7 */
+ 0x5b, /* kVK_ANSI_Keypad8 */
+ 0x5c, /* kVK_ANSI_Keypad9 */
+ 0x5f, /* kVK_JIS_KeypadComma */
+ 0x00
+ };
+ for (int i = 0; table[i] != 0; i++) {
+ if (key == table[i])
+ return true;
+ }
+ return false;
+}
+
// Translates a OS X keycode to a Godot keycode
//
static int translateKey(unsigned int key) {
+
// Keyboard symbol translation table
static const unsigned int table[128] = {
/* 00 */ KEY_A,
@@ -780,7 +812,7 @@ static int translateKey(unsigned int key) {
/* 07 */ KEY_X,
/* 08 */ KEY_C,
/* 09 */ KEY_V,
- /* 0a */ KEY_UNKNOWN,
+ /* 0a */ KEY_SECTION, /* ISO Section */
/* 0b */ KEY_B,
/* 0c */ KEY_Q,
/* 0d */ KEY_W,
@@ -834,7 +866,7 @@ static int translateKey(unsigned int key) {
/* 3d */ KEY_ALT,
/* 3e */ KEY_CONTROL,
/* 3f */ KEY_UNKNOWN, /* Function */
- /* 40 */ KEY_UNKNOWN,
+ /* 40 */ KEY_UNKNOWN, /* F17 */
/* 41 */ KEY_KP_PERIOD,
/* 42 */ KEY_UNKNOWN,
/* 43 */ KEY_KP_MULTIPLY,
@@ -842,16 +874,16 @@ static int translateKey(unsigned int key) {
/* 45 */ KEY_KP_ADD,
/* 46 */ KEY_UNKNOWN,
/* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
- /* 48 */ KEY_UNKNOWN, /* VolumeUp */
- /* 49 */ KEY_UNKNOWN, /* VolumeDown */
- /* 4a */ KEY_UNKNOWN, /* Mute */
+ /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
+ /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
+ /* 4a */ KEY_VOLUMEMUTE, /* Mute */
/* 4b */ KEY_KP_DIVIDE,
/* 4c */ KEY_KP_ENTER,
/* 4d */ KEY_UNKNOWN,
/* 4e */ KEY_KP_SUBTRACT,
- /* 4f */ KEY_UNKNOWN,
- /* 50 */ KEY_UNKNOWN,
- /* 51 */ KEY_EQUAL, //wtf equal?
+ /* 4f */ KEY_UNKNOWN, /* F18 */
+ /* 50 */ KEY_UNKNOWN, /* F19 */
+ /* 51 */ KEY_EQUAL, /* KeypadEqual */
/* 52 */ KEY_KP_0,
/* 53 */ KEY_KP_1,
/* 54 */ KEY_KP_2,
@@ -860,27 +892,27 @@ static int translateKey(unsigned int key) {
/* 57 */ KEY_KP_5,
/* 58 */ KEY_KP_6,
/* 59 */ KEY_KP_7,
- /* 5a */ KEY_UNKNOWN,
+ /* 5a */ KEY_UNKNOWN, /* F20 */
/* 5b */ KEY_KP_8,
/* 5c */ KEY_KP_9,
- /* 5d */ KEY_UNKNOWN,
- /* 5e */ KEY_UNKNOWN,
- /* 5f */ KEY_UNKNOWN,
+ /* 5d */ KEY_YEN, /* JIS Yen */
+ /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
+ /* 5f */ KEY_COMMA, /* JIS KeypadComma */
/* 60 */ KEY_F5,
/* 61 */ KEY_F6,
/* 62 */ KEY_F7,
/* 63 */ KEY_F3,
/* 64 */ KEY_F8,
/* 65 */ KEY_F9,
- /* 66 */ KEY_UNKNOWN,
+ /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
/* 67 */ KEY_F11,
- /* 68 */ KEY_UNKNOWN,
+ /* 68 */ KEY_UNKNOWN, /* JIS Kana */
/* 69 */ KEY_F13,
/* 6a */ KEY_F16,
/* 6b */ KEY_F14,
/* 6c */ KEY_UNKNOWN,
/* 6d */ KEY_F10,
- /* 6e */ KEY_UNKNOWN,
+ /* 6e */ KEY_MENU,
/* 6f */ KEY_F12,
/* 70 */ KEY_UNKNOWN,
/* 71 */ KEY_F15,
@@ -938,10 +970,10 @@ static const _KeyCodeMap _keycodes[55] = {
{ 'i', KEY_I },
{ 'o', KEY_O },
{ 'p', KEY_P },
- { '[', KEY_BRACERIGHT },
- { ']', KEY_BRACELEFT },
- { '{', KEY_BRACERIGHT },
- { '}', KEY_BRACELEFT },
+ { '[', KEY_BRACELEFT },
+ { ']', KEY_BRACERIGHT },
+ { '{', KEY_BRACELEFT },
+ { '}', KEY_BRACERIGHT },
{ 'a', KEY_A },
{ 's', KEY_S },
{ 'd', KEY_D },
@@ -971,6 +1003,9 @@ static const _KeyCodeMap _keycodes[55] = {
static int remapKey(unsigned int key) {
+ if (isNumpadKey(key))
+ return translateKey(key);
+
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (!currentKeyboard)
return translateKey(key);
@@ -1096,6 +1131,7 @@ static int remapKey(unsigned int key) {
inline void sendScrollEvent(int button, double factor, int modifierFlags) {
unsigned int mask = 1 << (button - 1);
+ Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
Ref<InputEventMouseButton> sc;
sc.instance();
@@ -1104,14 +1140,18 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
sc->set_button_index(button);
sc->set_factor(factor);
sc->set_pressed(true);
- Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
sc->set_position(mouse_pos);
sc->set_global_position(mouse_pos);
button_mask |= mask;
sc->set_button_mask(button_mask);
OS_OSX::singleton->push_input(sc);
+ sc.instance();
+ sc->set_button_index(button);
+ sc->set_factor(factor);
sc->set_pressed(false);
+ sc->set_position(mouse_pos);
+ sc->set_global_position(mouse_pos);
button_mask &= ~mask;
sc->set_button_mask(button_mask);
OS_OSX::singleton->push_input(sc);
@@ -1420,7 +1460,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) {
p_video_driver = VIDEO_DRIVER_GLES2;
gles3 = false;
continue;
@@ -1657,6 +1697,11 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape;
}
+OS::CursorShape OS_OSX::get_cursor_shape() const {
+
+ return cursor_shape;
+}
+
void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor;
@@ -2233,12 +2278,12 @@ Size2 OS_OSX::get_window_size() const {
Size2 OS_OSX::get_real_window_size() const {
NSRect frame = [window_object frame];
- return Size2(frame.size.width, frame.size.height);
+ return Size2(frame.size.width, frame.size.height) * _display_scale();
}
void OS_OSX::set_window_size(const Size2 p_size) {
- Size2 size = p_size;
+ Size2 size = p_size / _display_scale();
if (get_borderless_window() == false) {
// NSRect used by setFrame includes the title bar, so add it to our size.y
@@ -2263,6 +2308,8 @@ void OS_OSX::set_window_fullscreen(bool p_enabled) {
if (zoomed != p_enabled) {
if (layered_window)
set_window_per_pixel_transparency_enabled(false);
+ if (!resizable)
+ [window_object setStyleMask:[window_object styleMask] | NSWindowStyleMaskResizable];
[window_object toggleFullScreen:nil];
}
zoomed = p_enabled;
@@ -2277,7 +2324,7 @@ void OS_OSX::set_window_resizable(bool p_enabled) {
if (p_enabled)
[window_object setStyleMask:[window_object styleMask] | NSWindowStyleMaskResizable];
- else
+ else if (!zoomed)
[window_object setStyleMask:[window_object styleMask] & ~NSWindowStyleMaskResizable];
resizable = p_enabled;
@@ -2529,6 +2576,8 @@ void OS_OSX::process_events() {
[autoreleasePool drain];
autoreleasePool = [[NSAutoreleasePool alloc] init];
+
+ input->flush_accumulated_events();
}
void OS_OSX::process_key_events() {
@@ -2571,7 +2620,7 @@ void OS_OSX::process_key_events() {
void OS_OSX::push_input(const Ref<InputEvent> &p_event) {
Ref<InputEvent> ev = p_event;
- input->parse_input_event(ev);
+ input->accumulate_input_event(ev);
}
void OS_OSX::force_process_input() {
@@ -2812,7 +2861,7 @@ OS_OSX::OS_OSX() {
}
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc" || p_feature == "s3tc";
+ return p_feature == "pc";
}
void OS_OSX::disable_crash_handler() {
diff --git a/platform/server/SCsub b/platform/server/SCsub
index 62d45efbc0..f977275595 100644
--- a/platform/server/SCsub
+++ b/platform/server/SCsub
@@ -1,7 +1,5 @@
#!/usr/bin/env python
-import os
-import platform
import sys
Import('env')
diff --git a/platform/server/detect.py b/platform/server/detect.py
index 392a987ee9..5306a2bf69 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -2,6 +2,8 @@ import os
import platform
import sys
+# This file is mostly based on platform/x11/detect.py.
+# If editing this file, make sure to apply relevant changes here too.
def is_active():
return True
@@ -26,10 +28,16 @@ def can_build():
def get_opts():
- from SCons.Variables import BoolVariable
+ from SCons.Variables import BoolVariable, EnumVariable
return [
BoolVariable('use_llvm', 'Use the LLVM compiler', False),
BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
+ BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False),
+ BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False),
+ BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False),
+ EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
+ BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
+ BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False),
]
@@ -43,13 +51,32 @@ def configure(env):
## Build type
if (env["target"] == "release"):
- env.Append(CCFLAGS=['-O2', '-fomit-frame-pointer'])
+ if (env["optimize"] == "speed"): #optimize for speed (default)
+ env.Prepend(CCFLAGS=['-O3'])
+ else: #optimize for size
+ env.Prepend(CCFLAGS=['-Os'])
+
+ if (env["debug_symbols"] == "yes"):
+ env.Prepend(CCFLAGS=['-g1'])
+ if (env["debug_symbols"] == "full"):
+ env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+ if (env["optimize"] == "speed"): #optimize for speed (default)
+ env.Prepend(CCFLAGS=['-O2'])
+ else: #optimize for size
+ env.Prepend(CCFLAGS=['-Os'])
+ env.Prepend(CPPFLAGS=['-DDEBUG_ENABLED'])
+
+ if (env["debug_symbols"] == "yes"):
+ env.Prepend(CCFLAGS=['-g1'])
+ if (env["debug_symbols"] == "full"):
+ env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Prepend(CCFLAGS=['-g3'])
+ env.Prepend(CPPFLAGS=['-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Append(LINKFLAGS=['-rdynamic'])
## Architecture
@@ -59,6 +86,10 @@ def configure(env):
## Compiler configuration
+ if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
+ # Convenience check to enforce the use_llvm overrides when CXX is clang(++)
+ env['use_llvm'] = True
+
if env['use_llvm']:
if ('clang++' not in os.path.basename(env['CXX'])):
env["CC"] = "clang"
@@ -67,6 +98,35 @@ def configure(env):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env.extra_suffix = ".llvm" + env.extra_suffix
+
+ if env['use_ubsan'] or env['use_asan'] or env['use_lsan']:
+ env.extra_suffix += "s"
+
+ if env['use_ubsan']:
+ env.Append(CCFLAGS=['-fsanitize=undefined'])
+ env.Append(LINKFLAGS=['-fsanitize=undefined'])
+
+ if env['use_asan']:
+ env.Append(CCFLAGS=['-fsanitize=address'])
+ env.Append(LINKFLAGS=['-fsanitize=address'])
+
+ if env['use_lsan']:
+ env.Append(CCFLAGS=['-fsanitize=leak'])
+ env.Append(LINKFLAGS=['-fsanitize=leak'])
+
+ if env['use_lto']:
+ env.Append(CCFLAGS=['-flto'])
+ if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
+ env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
+ else:
+ env.Append(LINKFLAGS=['-flto'])
+ if not env['use_llvm']:
+ env['RANLIB'] = 'gcc-ranlib'
+ env['AR'] = 'gcc-ar'
+
+ env.Append(CCFLAGS=['-pipe'])
+ env.Append(LINKFLAGS=['-pipe'])
+
## Dependencies
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
@@ -88,7 +148,7 @@ def configure(env):
# We need at least version 2.88
import subprocess
bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
- if bullet_version < "2.88":
+ if str(bullet_version) < "2.88":
# Abort as system bullet was requested but too old
print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88"))
sys.exit(255)
@@ -110,6 +170,10 @@ def configure(env):
env['builtin_libogg'] = False # Needed to link against system libtheora
env['builtin_libvorbis'] = False # Needed to link against system libtheora
env.ParseConfig('pkg-config theora theoradec --cflags --libs')
+ else:
+ list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
+ if any(platform.machine() in s for s in list_of_x86):
+ env["x86_libtheora_opt_gcc"] = True
if not env['builtin_libvpx']:
env.ParseConfig('pkg-config vpx --cflags --libs')
@@ -163,6 +227,9 @@ def configure(env):
env.Append(LIBS=['dl'])
if (platform.system().find("BSD") >= 0):
+ env["execinfo"] = True
+
+ if env["execinfo"]:
env.Append(LIBS=['execinfo'])
# Link those statically for portability
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index e643d3e8bb..53f2a65c8e 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -198,12 +198,6 @@ String OS_Server::get_name() {
void OS_Server::move_window_to_foreground() {
}
-void OS_Server::set_cursor_shape(CursorShape p_shape) {
-}
-
-void OS_Server::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-}
-
OS::PowerState OS_Server::get_power_state() {
return power_manager->get_power_state();
}
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index eebe8ae777..7441064790 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -95,9 +95,6 @@ protected:
public:
virtual String get_name();
- virtual void set_cursor_shape(CursorShape p_shape);
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
-
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);
virtual bool is_mouse_grab_enabled() const;
diff --git a/platform/uwp/context_egl_uwp.h b/platform/uwp/context_egl_uwp.h
index 812bdfb688..0c62fe7456 100644
--- a/platform/uwp/context_egl_uwp.h
+++ b/platform/uwp/context_egl_uwp.h
@@ -37,11 +37,10 @@
#include "core/error_list.h"
#include "core/os/os.h"
-#include "drivers/gl_context/context_gl.h"
using namespace Windows::UI::Core;
-class ContextEGL_UWP : public ContextGL {
+class ContextEGL_UWP {
public:
enum Driver {
@@ -64,24 +63,24 @@ private:
Driver driver;
public:
- virtual void release_current();
+ void release_current();
- virtual void make_current();
+ void make_current();
- virtual int get_window_width();
- virtual int get_window_height();
- virtual void swap_buffers();
+ int get_window_width();
+ int get_window_height();
+ void swap_buffers();
- virtual void set_use_vsync(bool use) { vsync = use; }
- virtual bool is_using_vsync() const { return vsync; }
+ void set_use_vsync(bool use) { vsync = use; }
+ bool is_using_vsync() const { return vsync; }
- virtual Error initialize();
+ Error initialize();
void reset();
void cleanup();
ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver);
- virtual ~ContextEGL_UWP();
+ ~ContextEGL_UWP();
};
#endif // CONTEXT_EGL_UWP_H
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index c32a11b396..17f8242466 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -1,6 +1,5 @@
import methods
import os
-import string
import sys
@@ -25,8 +24,6 @@ def can_build():
def get_opts():
- from SCons.Variables import BoolVariable
-
return [
('msvc_version', 'MSVC version to use (ignored if the VCINSTALLDIR environment variable is set)', None),
]
@@ -56,18 +53,20 @@ def configure(env):
## Build type
if (env["target"] == "release"):
- env.Append(CPPFLAGS=['/O2', '/GL'])
- env.Append(CPPFLAGS=['/MD'])
+ env.Append(CCFLAGS=['/O2', '/GL'])
+ env.Append(CCFLAGS=['/MD'])
env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG'])
elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED'])
- env.Append(CPPFLAGS=['/MD'])
+ env.Append(CCFLAGS=['/O2', '/Zi'])
+ env.Append(CCFLAGS=['/MD'])
+ env.Append(CPPFLAGS=['/DDEBUG_ENABLED'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED'])
- env.Append(CPPFLAGS=['/MDd'])
+ env.Append(CCFLAGS=['/Zi'])
+ env.Append(CCFLAGS=['/MDd'])
+ env.Append(CPPFLAGS=['/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
env.Append(LINKFLAGS=['/DEBUG'])
@@ -139,18 +138,19 @@ def configure(env):
## Compile flags
env.Append(CPPPATH=['#platform/uwp', '#drivers/windows'])
- env.Append(CCFLAGS=['/DUWP_ENABLED', '/DWINDOWS_ENABLED', '/DTYPED_METHOD_BIND'])
- env.Append(CCFLAGS=['/DGLES_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED'])
+ env.Append(CPPFLAGS=['/DUWP_ENABLED', '/DWINDOWS_ENABLED', '/DTYPED_METHOD_BIND'])
+ env.Append(CPPFLAGS=['/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])
+ env.Append(CPPFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver])
- env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32', '/DPNG_ABORT=abort'])
+ env.Append(CPPFLAGS=['/D__WRL_NO_DEFAULT_LIB__', '/DWIN32', '/DPNG_ABORT=abort'])
env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references'])
env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references'])
- env.Append(CCFLAGS='/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo'.split())
- env.Append(CXXFLAGS='/ZW /FS'.split())
+ env.Append(CCFLAGS='/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo'.split())
+ env.Append(CPPFLAGS=['/D_UNICODE', '/DUNICODE', '/D "WINAPI_FAMILY=WINAPI_FAMILY_APP"'])
+ env.Append(CXXFLAGS=['/ZW'])
env.Append(CCFLAGS=['/AI', vc_base_path + '\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR'] + '\\References\\CommonConfiguration\\Neutral'])
## Link flags
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index a4655117a7..a0ab398f89 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -505,7 +505,7 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t
while (p_len - step > 0) {
- size_t block_size = (p_len - step) > BLOCK_SIZE ? BLOCK_SIZE : (p_len - step);
+ size_t block_size = (p_len - step) > BLOCK_SIZE ? (size_t)BLOCK_SIZE : (p_len - step);
for (uint32_t i = 0; i < block_size; i++) {
strm_in.write[i] = p_buffer[step + i];
@@ -1265,6 +1265,10 @@ public:
}
}
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
Error err = OK;
FileAccess *fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err);
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 520e179611..82f09032f5 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -202,7 +202,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
memdelete(gl_context);
gl_context = NULL;
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
if (p_video_driver == VIDEO_DRIVER_GLES2) {
gl_initialization_error = true;
break;
@@ -224,7 +224,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
p_video_driver = VIDEO_DRIVER_GLES2;
opengl_api_type = ContextEGL_UWP::GLES_2_0;
continue;
@@ -704,6 +704,11 @@ void OS_UWP::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape;
}
+OS::CursorShape OS_UWP::get_cursor_shape() const {
+
+ return cursor_shape;
+}
+
void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// TODO
}
@@ -889,7 +894,7 @@ String OS_UWP::get_user_data_dir() const {
}
bool OS_UWP::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc" || p_feature == "s3tc";
+ return p_feature == "pc";
}
OS::PowerState OS_UWP::get_power_state() {
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index fd78b3cdf7..00f79efb04 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -219,6 +219,7 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
+ CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_icon(const Ref<Image> &p_icon);
diff --git a/platform/windows/context_gl_windows.h b/platform/windows/context_gl_windows.h
index 09801b9146..d23fba50e1 100644
--- a/platform/windows/context_gl_windows.h
+++ b/platform/windows/context_gl_windows.h
@@ -37,13 +37,12 @@
#include "core/error_list.h"
#include "core/os/os.h"
-#include "drivers/gl_context/context_gl.h"
#include <windows.h>
typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval);
-class ContextGL_Windows : public ContextGL {
+class ContextGL_Windows {
HDC hDC;
HGLRC hRC;
@@ -55,21 +54,21 @@ class ContextGL_Windows : public ContextGL {
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
public:
- virtual void release_current();
+ void release_current();
- virtual void make_current();
+ void make_current();
- virtual int get_window_width();
- virtual int get_window_height();
- virtual void swap_buffers();
+ int get_window_width();
+ int get_window_height();
+ void swap_buffers();
- virtual Error initialize();
+ Error initialize();
- virtual void set_use_vsync(bool p_use);
- virtual bool is_using_vsync() const;
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
ContextGL_Windows(HWND hwnd, bool p_opengl_3_context);
- virtual ~ContextGL_Windows();
+ ~ContextGL_Windows();
};
#endif
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 426a5e9e61..5c38eebf04 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,6 +1,5 @@
import methods
import os
-import sys
def is_active():
@@ -197,6 +196,8 @@ def configure_msvc(env, manual_msvc_config):
## Compile/link flags
env.AppendUnique(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo'])
+ if int(env['MSVC_VERSION'].split('.')[0]) >= 14: #vs2015 and later
+ env.AppendUnique(CCFLAGS=['/utf-8'])
env.AppendUnique(CXXFLAGS=['/TP']) # assume all sources are C++
if manual_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
@@ -272,7 +273,8 @@ def configure_mingw(env):
env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+ env.Append(CCFLAGS=['-O2'])
+ env.Append(CPPFLAGS=['-DDEBUG_ENABLED'])
if (env["debug_symbols"] == "yes"):
env.Prepend(CCFLAGS=['-g1'])
if (env["debug_symbols"] == "full"):
@@ -283,7 +285,8 @@ def configure_mingw(env):
env.Prepend(CCFLAGS=['-Os'])
elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Append(CCFLAGS=['-g3'])
+ env.Append(CPPFLAGS=['-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
## Compiler configuration
@@ -324,12 +327,13 @@ def configure_mingw(env):
## Compile flags
- env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows'])
- env.Append(CCFLAGS=['-DOPENGL_ENABLED'])
- env.Append(CCFLAGS=['-DWASAPI_ENABLED'])
- env.Append(CCFLAGS=['-DWINMIDI_ENABLED'])
- env.Append(CCFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']])
- env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt','avrt'])
+ env.Append(CCFLAGS=['-mwindows'])
+ env.Append(CPPFLAGS=['-DWINDOWS_ENABLED'])
+ env.Append(CPPFLAGS=['-DOPENGL_ENABLED'])
+ env.Append(CPPFLAGS=['-DWASAPI_ENABLED'])
+ env.Append(CPPFLAGS=['-DWINMIDI_ENABLED'])
+ env.Append(CPPFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']])
+ env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt', 'avrt', 'uuid'])
env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index 01963035a1..55c83c3f3c 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -2,92 +2,109 @@
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Vector&lt;*&gt;">
<Expand>
- <Item Name="size">(_cowdata &amp;&amp; _cowdata-&gt;_ptr) ? (((const unsigned int *)(_cowdata-&gt;_ptr))[-1]) : 0</Item>
+ <Item Name="[size]">_cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0</Item>
<ArrayItems>
- <Size>(_cowdata &amp;&amp; _cowdata-&gt;_ptr) ? (((const unsigned int *)(_cowdata-&gt;_ptr))[-1]) : 0</Size>
- <ValuePointer>(_cowdata) ? (_cowdata-&gt;_ptr) : 0</ValuePointer>
+ <Size>_cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0</Size>
+ <ValuePointer>_cowdata._ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="PoolVector&lt;*&gt;">
<Expand>
- <Item Name="size">alloc ? (alloc-&gt;size / sizeof($T1)) : 0</Item>
+ <Item Name="[size]">alloc ? (alloc-&gt;size / sizeof($T1)) : 0</Item>
<ArrayItems>
<Size>alloc ? (alloc-&gt;size / sizeof($T1)) : 0</Size>
<ValuePointer>alloc ? (($T1 *)alloc-&gt;mem) : 0</ValuePointer>
</ArrayItems>
</Expand>
</Type>
+
+ <Type Name="List&lt;*&gt;">
+ <Expand>
+ <Item Name="[size]">_data ? (_data->size_cache) : 0</Item>
+ <LinkedListItems>
+ <Size>_data ? (_data->size_cache) : 0</Size>
+ <HeadPointer>_data->first</HeadPointer>
+ <NextPointer>next_ptr</NextPointer>
+ <ValueNode>value</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
<Type Name="Variant">
- <DisplayString Condition="this-&gt;type == Variant::NIL">nil</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::BOOL">{_data._bool}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::INT">{_data._int}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::REAL">{_data._real}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::AABB">{_data._aabb}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::BASIS">{_data._basis}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::TRANSFORM">{_data._transform}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::STRING &amp;&amp; ((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr == 0">""</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::STRING &amp;&amp; ((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr != 0">{((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr,su}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::_RID">{*(RID *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_BYTE_ARRAY">{*(PoolByteArray *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_INT_ARRAY">{*(PoolIntArray *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_REAL_ARRAY">{*(PoolRealArray *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_STRING_ARRAY">{*(PoolStringArray *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_VECTOR2_ARRAY">{*(PoolVector2Array *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_VECTOR3_ARRAY">{*(PoolVector3Array *)_data._mem}</DisplayString>
- <DisplayString Condition="this-&gt;type == Variant::POOL_COLOR_ARRAY">{*(PoolColorArray *)_data._mem}</DisplayString>
-
- <StringView Condition="this-&gt;type == Variant::STRING &amp;&amp; ((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr != 0">((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr,su</StringView>
+ <DisplayString Condition="type == Variant::NIL">nil</DisplayString>
+ <DisplayString Condition="type == Variant::BOOL">{_data._bool}</DisplayString>
+ <DisplayString Condition="type == Variant::INT">{_data._int}</DisplayString>
+ <DisplayString Condition="type == Variant::REAL">{_data._real}</DisplayString>
+ <DisplayString Condition="type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString>
+ <DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString>
+ <DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString>
+ <DisplayString Condition="type == Variant::TRANSFORM">{_data._transform}</DisplayString>
+ <DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::_RID">{*(RID *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_BYTE_ARRAY">{*(PoolByteArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_INT_ARRAY">{*(PoolIntArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_REAL_ARRAY">{*(PoolRealArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_STRING_ARRAY">{*(PoolStringArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_VECTOR2_ARRAY">{*(PoolVector2Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_VECTOR3_ARRAY">{*(PoolVector3Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::POOL_COLOR_ARRAY">{*(PoolColorArray *)_data._mem}</DisplayString>
+ <StringView Condition="type == Variant::STRING &amp;&amp; ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,su</StringView>
+
<Expand>
- <Item Name="value" Condition="this-&gt;type == Variant::BOOL">_data._bool</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::INT">_data._int</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::REAL">_data._real</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::TRANSFORM2D">_data._transform2d</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::AABB">_data._aabb</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::BASIS">_data._basis</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::TRANSFORM">_data._transform</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::ARRAY">*(Array *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::STRING">*(String *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::RECT2">*(Rect2 *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::PLANE">*(Plane *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::QUAT">*(Quat *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::COLOR">*(Color *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::_RID">*(RID *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::OBJECT">*(Object *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::ARRAY">*(Array *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_BYTE_ARRAY">*(PoolByteArray *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_INT_ARRAY">*(PoolIntArray *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_REAL_ARRAY">*(PoolRealArray *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_STRING_ARRAY">*(PoolStringArray *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_VECTOR2_ARRAY">*(PoolVector2Array *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_VECTOR3_ARRAY">*(PoolVector3Array *)_data._mem</Item>
- <Item Name="value" Condition="this-&gt;type == Variant::POOL_COLOR_ARRAY">*(PoolColorArray *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::BOOL">_data._bool</Item>
+ <Item Name="[value]" Condition="type == Variant::INT">_data._int</Item>
+ <Item Name="[value]" Condition="type == Variant::REAL">_data._real</Item>
+ <Item Name="[value]" Condition="type == Variant::TRANSFORM2D">_data._transform2d</Item>
+ <Item Name="[value]" Condition="type == Variant::AABB">_data._aabb</Item>
+ <Item Name="[value]" Condition="type == Variant::BASIS">_data._basis</Item>
+ <Item Name="[value]" Condition="type == Variant::TRANSFORM">_data._transform</Item>
+ <Item Name="[value]" Condition="type == Variant::STRING">*(String *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::RECT2">*(Rect2 *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::PLANE">*(Plane *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::QUAT">*(Quat *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::COLOR">*(Color *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::_RID">*(RID *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::OBJECT">*(Object *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::ARRAY">*(Array *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_BYTE_ARRAY">*(PoolByteArray *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_INT_ARRAY">*(PoolIntArray *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_REAL_ARRAY">*(PoolRealArray *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_STRING_ARRAY">*(PoolStringArray *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_VECTOR2_ARRAY">*(PoolVector2Array *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_VECTOR3_ARRAY">*(PoolVector3Array *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::POOL_COLOR_ARRAY">*(PoolColorArray *)_data._mem</Item>
</Expand>
</Type>
<Type Name="String">
- <DisplayString Condition="this-&gt;_cowdata._ptr == 0">empty</DisplayString>
- <DisplayString Condition="this-&gt;_cowdata._ptr != 0">{this->_cowdata._ptr,su}</DisplayString>
- <StringView Condition="this-&gt;_cowdata._ptr != 0">this->_cowdata._ptr,su</StringView>
+ <DisplayString Condition="_cowdata._ptr == 0">[empty]</DisplayString>
+ <DisplayString Condition="_cowdata._ptr != 0">{_cowdata._ptr,su}</DisplayString>
+ <StringView Condition="_cowdata._ptr != 0">_cowdata._ptr,su</StringView>
+ </Type>
+
+ <Type Name="StringName">
+ <DisplayString Condition="_data &amp;&amp; _data->cname">{_data->cname}</DisplayString>
+ <DisplayString Condition="_data &amp;&amp; !_data->cname">{_data->name,su}</DisplayString>
+ <DisplayString Condition="!_data">[empty]</DisplayString>
+ <StringView Condition="_data &amp;&amp; _data->cname">_data->cname</StringView>
+ <StringView Condition="_data &amp;&amp; !_data->cname">_data->name,su</StringView>
</Type>
<Type Name="Vector2">
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 6e31f5b21d..0b61770d87 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -53,6 +53,7 @@
#include <avrt.h>
#include <direct.h>
+#include <knownfolders.h>
#include <process.h>
#include <regstr.h>
#include <shlobj.h>
@@ -271,7 +272,7 @@ void OS_Windows::_touch_event(bool p_pressed, float p_x, float p_y, int idx) {
event->set_position(Vector2(p_x, p_y));
if (main_loop) {
- input->parse_input_event(event);
+ input->accumulate_input_event(event);
}
};
@@ -293,11 +294,21 @@ void OS_Windows::_drag_event(float p_x, float p_y, int idx) {
event->set_position(Vector2(p_x, p_y));
if (main_loop)
- input->parse_input_event(event);
+ input->accumulate_input_event(event);
};
LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ if (drop_events) {
+
+ if (user_proc) {
+
+ return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
+ } else {
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }
+ };
+
switch (uMsg) // Check For Windows Messages
{
case WM_SETFOCUS: {
@@ -335,6 +346,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
control_mem = false;
shift_mem = false;
} else { // WM_INACTIVE
+ input->release_pressed_events();
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
alt_mem = false;
};
@@ -374,8 +386,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
outside = true;
if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
- if (input)
- input->set_mouse_in_window(false);
} break;
case WM_INPUT: {
@@ -448,7 +458,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
if (window_has_focus && main_loop && mm->get_relative() != Vector2())
- input->parse_input_event(mm);
+ input->accumulate_input_event(mm);
}
delete[] lpb;
} break;
@@ -470,8 +480,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
- if (input)
- input->set_mouse_in_window(true);
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
@@ -535,7 +543,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
old_x = mm->get_position().x;
old_y = mm->get_position().y;
if (window_has_focus && main_loop)
- input->parse_input_event(mm);
+ input->accumulate_input_event(mm);
} break;
case WM_LBUTTONDOWN:
@@ -660,7 +668,9 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mb->set_button_index(BUTTON_XBUTTON2);
mb->set_doubleclick(true);
} break;
- default: { return 0; }
+ default: {
+ return 0;
+ }
}
mb->set_control((wParam & MK_CONTROL) != 0);
@@ -708,14 +718,14 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mb->set_global_position(mb->get_position());
if (main_loop) {
- input->parse_input_event(mb);
+ input->accumulate_input_event(mb);
if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
//send release for mouse wheel
Ref<InputEventMouseButton> mbd = mb->duplicate();
last_button_state &= ~(1 << (mbd->get_button_index() - 1));
mbd->set_button_mask(last_button_state);
mbd->set_pressed(false);
- input->parse_input_event(mbd);
+ input->accumulate_input_event(mbd);
}
}
} break;
@@ -777,6 +787,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} break;
case WM_ENTERSIZEMOVE: {
+ input->release_pressed_events();
move_timer_id = SetTimer(hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC)NULL);
} break;
case WM_EXITSIZEMOVE: {
@@ -978,7 +989,7 @@ void OS_Windows::process_key_events() {
if (k->get_unicode() < 32)
k->set_unicode(0);
- input->parse_input_event(k);
+ input->accumulate_input_event(k);
}
//do nothing
@@ -1016,7 +1027,7 @@ void OS_Windows::process_key_events() {
k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30))));
- input->parse_input_event(k);
+ input->accumulate_input_event(k);
} break;
}
@@ -1280,7 +1291,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
memdelete(gl_context);
gl_context = NULL;
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) {
if (p_video_driver == VIDEO_DRIVER_GLES2) {
gl_initialization_error = true;
break;
@@ -1302,7 +1313,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) {
p_video_driver = VIDEO_DRIVER_GLES2;
gles3_context = false;
continue;
@@ -1402,26 +1413,29 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
void OS_Windows::set_clipboard(const String &p_text) {
+ // Convert LF line endings to CRLF in clipboard content
+ // Otherwise, line endings won't be visible when pasted in other software
+ String text = p_text.replace("\n", "\r\n");
+
if (!OpenClipboard(hWnd)) {
ERR_EXPLAIN("Unable to open clipboard.");
ERR_FAIL();
};
EmptyClipboard();
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (p_text.length() + 1) * sizeof(CharType));
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType));
if (mem == NULL) {
ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
ERR_FAIL();
};
LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
- memcpy(lptstrCopy, p_text.c_str(), (p_text.length() + 1) * sizeof(CharType));
- //memset((lptstrCopy + p_text.length()), 0, sizeof(CharType));
+ memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType));
GlobalUnlock(mem);
SetClipboardData(CF_UNICODETEXT, mem);
// set the CF_TEXT version (not needed?)
- CharString utf8 = p_text.utf8();
+ CharString utf8 = text.utf8();
mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
if (mem == NULL) {
ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
@@ -2230,7 +2244,9 @@ void OS_Windows::process_events() {
MSG msg;
- joypad->process_joypads();
+ if (!drop_events) {
+ joypad->process_joypads();
+ }
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
@@ -2238,7 +2254,10 @@ void OS_Windows::process_events() {
DispatchMessageW(&msg);
}
- process_key_events();
+ if (!drop_events) {
+ process_key_events();
+ input->flush_accumulated_events();
+ }
}
void OS_Windows::set_cursor_shape(CursorShape p_shape) {
@@ -2282,6 +2301,11 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape;
}
+OS::CursorShape OS_Windows::get_cursor_shape() const {
+
+ return cursor_shape;
+}
+
void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor;
@@ -2442,7 +2466,7 @@ void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent,
DeleteDC(hMainDC);
}
-Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
+Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
if (p_blocking && r_pipe) {
@@ -2461,7 +2485,13 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
char buf[65535];
while (fgets(buf, 65535, f)) {
+ if (p_pipe_mutex) {
+ p_pipe_mutex->lock();
+ }
(*r_pipe) += buf;
+ if (p_pipe_mutex) {
+ p_pipe_mutex->unlock();
+ }
}
int rv = _pclose(f);
@@ -2852,39 +2882,41 @@ String OS_Windows::get_godot_dir_name() const {
String OS_Windows::get_system_dir(SystemDir p_dir) const {
- int id;
+ KNOWNFOLDERID id;
switch (p_dir) {
case SYSTEM_DIR_DESKTOP: {
- id = CSIDL_DESKTOPDIRECTORY;
+ id = FOLDERID_Desktop;
} break;
case SYSTEM_DIR_DCIM: {
- id = CSIDL_MYPICTURES;
+ id = FOLDERID_Pictures;
} break;
case SYSTEM_DIR_DOCUMENTS: {
- id = CSIDL_PERSONAL;
+ id = FOLDERID_Documents;
} break;
case SYSTEM_DIR_DOWNLOADS: {
- id = 0x000C;
+ id = FOLDERID_Downloads;
} break;
case SYSTEM_DIR_MOVIES: {
- id = CSIDL_MYVIDEO;
+ id = FOLDERID_Videos;
} break;
case SYSTEM_DIR_MUSIC: {
- id = CSIDL_MYMUSIC;
+ id = FOLDERID_Music;
} break;
case SYSTEM_DIR_PICTURES: {
- id = CSIDL_MYPICTURES;
+ id = FOLDERID_Pictures;
} break;
case SYSTEM_DIR_RINGTONES: {
- id = CSIDL_MYMUSIC;
+ id = FOLDERID_Music;
} break;
}
- WCHAR szPath[MAX_PATH];
- HRESULT res = SHGetFolderPathW(NULL, id, NULL, 0, szPath);
+ PWSTR szPath;
+ HRESULT res = SHGetKnownFolderPath(id, 0, NULL, &szPath);
ERR_FAIL_COND_V(res != S_OK, String());
- return String(szPath);
+ String path = String(szPath);
+ CoTaskMemFree(szPath);
+ return path;
}
String OS_Windows::get_user_data_dir() const {
@@ -2976,7 +3008,7 @@ int OS_Windows::get_power_percent_left() {
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc" || p_feature == "s3tc" || p_feature == "bptc";
+ return p_feature == "pc";
}
void OS_Windows::disable_crash_handler() {
@@ -2987,6 +3019,13 @@ bool OS_Windows::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}
+void OS_Windows::process_and_drop_events() {
+
+ drop_events = true;
+ process_events();
+ drop_events = false;
+}
+
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
WCHAR *from = new WCHAR[p_path.length() + 2];
@@ -3015,6 +3054,7 @@ Error OS_Windows::move_to_trash(const String &p_path) {
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
+ drop_events = false;
key_event_pos = 0;
layered_window = false;
hBitmap = NULL;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 6c257016ec..0e0b9bf3f6 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -127,6 +127,7 @@ class OS_Windows : public OS {
bool window_has_focus;
uint32_t last_button_state;
bool use_raw_input;
+ bool drop_events;
HCURSOR cursors[CURSOR_MAX] = { NULL };
CursorShape cursor_shape;
@@ -260,7 +261,7 @@ public:
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;
@@ -272,6 +273,7 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
+ CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
void set_icon(const Ref<Image> &p_icon);
@@ -330,6 +332,8 @@ public:
virtual Error move_to_trash(const String &p_path);
+ virtual void process_and_drop_events();
+
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
};
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index e302f09c88..3d5aa15208 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -2,7 +2,6 @@
Import('env')
-import os
from platform_methods import run_in_subprocess
import platform_x11_builders
diff --git a/platform/x11/context_gl_x11.h b/platform/x11/context_gl_x11.h
index 02455ce005..46420df48b 100644
--- a/platform/x11/context_gl_x11.h
+++ b/platform/x11/context_gl_x11.h
@@ -39,13 +39,12 @@
#if defined(OPENGL_ENABLED)
#include "core/os/os.h"
-#include "drivers/gl_context/context_gl.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
struct ContextGL_X11_Private;
-class ContextGL_X11 : public ContextGL {
+class ContextGL_X11 {
public:
enum ContextType {
@@ -67,19 +66,19 @@ private:
ContextType context_type;
public:
- virtual void release_current();
- virtual void make_current();
- virtual void swap_buffers();
- virtual int get_window_width();
- virtual int get_window_height();
+ void release_current();
+ void make_current();
+ void swap_buffers();
+ int get_window_width();
+ int get_window_height();
- virtual Error initialize();
+ Error initialize();
- virtual void set_use_vsync(bool p_use);
- virtual bool is_using_vsync() const;
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type);
- virtual ~ContextGL_X11();
+ ~ContextGL_X11();
};
#endif
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 1355ae542d..f8ae5e9acb 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -1,8 +1,8 @@
import os
import platform
import sys
-from compat import decode_utf8
-from methods import get_compiler_version, use_gcc
+from methods import get_compiler_version, using_gcc, using_clang
+
def is_active():
return True
@@ -20,12 +20,10 @@ def can_build():
# Check the minimal dependencies
x11_error = os.system("pkg-config --version > /dev/null")
if (x11_error):
- print("pkg-config not found.. x11 disabled.")
return False
x11_error = os.system("pkg-config x11 --modversion > /dev/null ")
if (x11_error):
- print("X11 not found.. x11 disabled.")
return False
x11_error = os.system("pkg-config xcursor --modversion > /dev/null ")
@@ -60,11 +58,13 @@ def get_opts():
return [
BoolVariable('use_llvm', 'Use the LLVM compiler', False),
+ BoolVariable('use_lld', 'Use the LLD linker', False),
+ BoolVariable('use_thinlto', 'Use ThinLTO', False),
BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False),
BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False),
BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False),
- BoolVariable('pulseaudio', 'Detect & use pulseaudio', True),
+ BoolVariable('pulseaudio', 'Detect and use PulseAudio', True),
BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
@@ -99,9 +99,10 @@ def configure(env):
elif (env["target"] == "release_debug"):
if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-O2'])
else: #optimize for size
- env.Prepend(CCFLAGS=['-Os', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-Os'])
+ env.Prepend(CPPFLAGS=['-DDEBUG_ENABLED'])
if (env["debug_symbols"] == "yes"):
env.Prepend(CCFLAGS=['-g1'])
@@ -109,7 +110,8 @@ def configure(env):
env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "debug"):
- env.Prepend(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Prepend(CCFLAGS=['-g3'])
+ env.Prepend(CPPFLAGS=['-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
env.Append(LINKFLAGS=['-rdynamic'])
## Architecture
@@ -132,6 +134,15 @@ def configure(env):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env.extra_suffix = ".llvm" + env.extra_suffix
+ if env['use_lld']:
+ if env['use_llvm']:
+ env.Append(LINKFLAGS=['-fuse-ld=lld'])
+ if env['use_thinlto']:
+ # A convenience so you don't need to write use_lto too when using SCons
+ env['use_lto'] = True
+ else:
+ print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
+ sys.exit(255)
if env['use_ubsan'] or env['use_asan'] or env['use_lsan']:
env.extra_suffix += "s"
@@ -149,11 +160,17 @@ def configure(env):
env.Append(LINKFLAGS=['-fsanitize=leak'])
if env['use_lto']:
- env.Append(CCFLAGS=['-flto'])
if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
+ env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
else:
- env.Append(LINKFLAGS=['-flto'])
+ if env['use_lld'] and env['use_thinlto']:
+ env.Append(CCFLAGS=['-flto=thin'])
+ env.Append(LINKFLAGS=['-flto=thin'])
+ else:
+ env.Append(CCFLAGS=['-flto'])
+ env.Append(LINKFLAGS=['-flto'])
+
if not env['use_llvm']:
env['RANLIB'] = 'gcc-ranlib'
env['AR'] = 'gcc-ar'
@@ -162,11 +179,17 @@ def configure(env):
env.Append(LINKFLAGS=['-pipe'])
# Check for gcc version >= 6 before adding -no-pie
- if use_gcc(env):
+ if using_gcc(env):
version = get_compiler_version(env)
if version != None and version[0] >= '6':
env.Append(CCFLAGS=['-fpie'])
env.Append(LINKFLAGS=['-no-pie'])
+ # Do the same for clang should be fine with Clang 4 and higher
+ if using_clang(env):
+ version = get_compiler_version(env)
+ if version != None and version[0] >= '4':
+ env.Append(CCFLAGS=['-fpie'])
+ env.Append(LINKFLAGS=['-no-pie'])
## Dependencies
@@ -199,7 +222,7 @@ def configure(env):
# We need at least version 2.88
import subprocess
bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
- if bullet_version < "2.88":
+ if str(bullet_version) < "2.88":
# Abort as system bullet was requested but too old
print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88"))
sys.exit(255)
@@ -309,10 +332,10 @@ def configure(env):
## Cross-compilation
if (is64 and env["bits"] == "32"):
- env.Append(CPPFLAGS=['-m32'])
+ env.Append(CCFLAGS=['-m32'])
env.Append(LINKFLAGS=['-m32', '-L/usr/lib/i386-linux-gnu'])
elif (not is64 and env["bits"] == "64"):
- env.Append(CPPFLAGS=['-m64'])
+ env.Append(CCFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
# Link those statically for portability
diff --git a/platform/x11/detect_prime.cpp b/platform/x11/detect_prime.cpp
index 04a825fac9..0fde2a0c04 100644
--- a/platform/x11/detect_prime.cpp
+++ b/platform/x11/detect_prime.cpp
@@ -180,8 +180,8 @@ int detect_prime() {
const char *vendor = (const char *)glGetString(GL_VENDOR);
const char *renderer = (const char *)glGetString(GL_RENDERER);
- int vendor_len = strlen(vendor) + 1;
- int renderer_len = strlen(renderer) + 1;
+ unsigned int vendor_len = strlen(vendor) + 1;
+ unsigned int renderer_len = strlen(renderer) + 1;
if (vendor_len + renderer_len >= sizeof(string)) {
renderer_len = 200 - vendor_len;
diff --git a/platform/x11/joypad_linux.cpp b/platform/x11/joypad_linux.cpp
index 7cf0a1ef1e..c4dd8fe0e0 100644
--- a/platform/x11/joypad_linux.cpp
+++ b/platform/x11/joypad_linux.cpp
@@ -367,12 +367,12 @@ void JoypadLinux::open_joypad(const char *p_path) {
joy.fd = fd;
joy.devpath = String(p_path);
setup_joypad_properties(joy_num);
- sprintf(uid, "%04x%04x", __bswap_16(inpid.bustype), 0);
+ sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0);
if (inpid.vendor && inpid.product && inpid.version) {
- uint16_t vendor = __bswap_16(inpid.vendor);
- uint16_t product = __bswap_16(inpid.product);
- uint16_t version = __bswap_16(inpid.version);
+ uint16_t vendor = BSWAP16(inpid.vendor);
+ uint16_t product = BSWAP16(inpid.product);
+ uint16_t version = BSWAP16(inpid.version);
sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0);
input->joy_connection_changed(joy_num, true, name, uid);
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 879642d8f9..267ac08a72 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -299,7 +299,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
memdelete(context_gl);
context_gl = NULL;
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) {
if (p_video_driver == VIDEO_DRIVER_GLES2) {
gl_initialization_error = true;
break;
@@ -321,7 +321,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
RasterizerGLES3::make_current();
break;
} else {
- if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) {
+ if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) {
p_video_driver = VIDEO_DRIVER_GLES2;
opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
continue;
@@ -1165,7 +1165,7 @@ int OS_X11::get_screen_dpi(int p_screen) const {
int height_mm = DisplayHeightMM(x11_display, p_screen);
double xdpi = (width_mm ? sc.width / (double)width_mm * 25.4 : 0);
double ydpi = (height_mm ? sc.height / (double)height_mm * 25.4 : 0);
- if (xdpi || xdpi)
+ if (xdpi || ydpi)
return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1);
//could not get dpi
@@ -1176,15 +1176,28 @@ Point2 OS_X11::get_window_position() const {
int x, y;
Window child;
XTranslateCoordinates(x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
-
- int screen = get_current_screen();
- Point2i screen_position = get_screen_position(screen);
-
- return Point2i(x - screen_position.x, y - screen_position.y);
+ return Point2i(x, y);
}
void OS_X11::set_window_position(const Point2 &p_position) {
- XMoveWindow(x11_display, x11_window, p_position.x, p_position.y);
+ int x = 0;
+ int y = 0;
+ if (get_borderless_window() == false) {
+ //exclude window decorations
+ XSync(x11_display, False);
+ Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+ if (XGetWindowProperty(x11_display, x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ long *extents = (long *)data;
+ x = extents[0];
+ y = extents[2];
+ }
+ }
+ XMoveWindow(x11_display, x11_window, p_position.x - x, p_position.y - y);
update_real_mouse_position();
}
@@ -1660,7 +1673,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
k->set_shift(true);
}
- input->parse_input_event(k);
+ input->accumulate_input_event(k);
}
return;
}
@@ -1804,7 +1817,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
}
//printf("key: %x\n",k->get_scancode());
- input->parse_input_event(k);
+ input->accumulate_input_event(k);
}
struct Property {
@@ -1991,12 +2004,12 @@ void OS_X11::process_xevents() {
// in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
xi.mouse_pos_to_filter = pos;
}
- input->parse_input_event(st);
+ input->accumulate_input_event(st);
} else {
if (!xi.state.has(index)) // Defensive
break;
xi.state.erase(index);
- input->parse_input_event(st);
+ input->accumulate_input_event(st);
}
} break;
@@ -2014,7 +2027,7 @@ void OS_X11::process_xevents() {
sd->set_index(index);
sd->set_position(pos);
sd->set_relative(pos - curr_pos_elem->value());
- input->parse_input_event(sd);
+ input->accumulate_input_event(sd);
curr_pos_elem->value() = pos;
}
@@ -2041,15 +2054,11 @@ void OS_X11::process_xevents() {
case LeaveNotify: {
if (main_loop && !mouse_mode_grab)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
- if (input)
- input->set_mouse_in_window(false);
} break;
case EnterNotify: {
if (main_loop && !mouse_mode_grab)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
- if (input)
- input->set_mouse_in_window(true);
} break;
case FocusIn:
minimized = false;
@@ -2080,7 +2089,9 @@ void OS_X11::process_xevents() {
case FocusOut:
window_has_focus = false;
+ input->release_pressed_events();
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+
if (mouse_mode_grab) {
//dear X11, I try, I really try, but you never work, you do whathever you want.
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -2102,7 +2113,7 @@ void OS_X11::process_xevents() {
st.instance();
st->set_index(E->key());
st->set_position(E->get());
- input->parse_input_event(st);
+ input->accumulate_input_event(st);
}
xi.state.clear();
#endif
@@ -2163,7 +2174,7 @@ void OS_X11::process_xevents() {
}
}
- input->parse_input_event(mb);
+ input->accumulate_input_event(mb);
} break;
case MotionNotify: {
@@ -2273,7 +2284,7 @@ void OS_X11::process_xevents() {
// this is so that the relative motion doesn't get messed up
// after we regain focus.
if (window_has_focus || !mouse_mode_grab)
- input->parse_input_event(mm);
+ input->accumulate_input_event(mm);
} break;
case KeyPress:
@@ -2355,7 +2366,7 @@ void OS_X11::process_xevents() {
Vector<String> files = String((char *)p.data).split("\n", false);
for (int i = 0; i < files.size(); i++) {
- files.write[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes();
+ files.write[i] = files[i].replace("file://", "").http_unescape().strip_escapes();
}
main_loop->drop_files(files);
@@ -2457,6 +2468,8 @@ void OS_X11::process_xevents() {
printf("Win: %d,%d\n", win_x, win_y);
*/
}
+
+ input->flush_accumulated_events();
}
MainLoop *OS_X11::get_main_loop() const {
@@ -2593,7 +2606,7 @@ Error OS_X11::shell_open(String p_uri) {
bool OS_X11::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc" || p_feature == "s3tc" || p_feature == "bptc";
+ return p_feature == "pc";
}
String OS_X11::get_config_path() const {
@@ -2720,6 +2733,11 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
current_cursor = p_shape;
}
+OS::CursorShape OS_X11::get_cursor_shape() const {
+
+ return current_cursor;
+}
+
void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor;
@@ -3033,33 +3051,40 @@ bool OS_X11::is_vsync_enabled() const {
*/
void OS_X11::set_context(int p_context) {
- char *config_name = NULL;
XClassHint *classHint = XAllocClassHint();
if (classHint) {
- char *wm_class = (char *)"Godot";
- if (p_context == CONTEXT_EDITOR)
- classHint->res_name = (char *)"Godot_Editor";
- if (p_context == CONTEXT_PROJECTMAN)
- classHint->res_name = (char *)"Godot_ProjectList";
+ CharString name_str;
+ switch (p_context) {
+ case CONTEXT_EDITOR:
+ name_str = "Godot_Editor";
+ break;
+ case CONTEXT_PROJECTMAN:
+ name_str = "Godot_ProjectList";
+ break;
+ case CONTEXT_ENGINE:
+ name_str = "Godot_Engine";
+ break;
+ }
+ CharString class_str;
if (p_context == CONTEXT_ENGINE) {
- classHint->res_name = (char *)"Godot_Engine";
- char *config_name_tmp = (char *)((String)GLOBAL_GET("application/config/name")).utf8().ptrw();
- if (config_name_tmp)
- config_name = strdup(config_name_tmp);
- else
- config_name = strdup("Godot Engine");
-
- wm_class = config_name;
+ String config_name = GLOBAL_GET("application/config/name");
+ if (config_name.length() == 0) {
+ class_str = "Godot_Engine";
+ } else {
+ class_str = config_name.utf8();
+ }
+ } else {
+ class_str = "Godot";
}
- classHint->res_class = wm_class;
+ classHint->res_class = class_str.ptrw();
+ classHint->res_name = name_str.ptrw();
XSetClassHint(x11_display, x11_window, classHint);
XFree(classHint);
- free(config_name);
}
}
@@ -3235,6 +3260,8 @@ OS_X11::OS_X11() {
AudioDriverManager::add_driver(&driver_alsa);
#endif
+ xi.opcode = 0;
+ xi.last_relative_time = 0;
layered_window = false;
minimized = false;
xim_style = 0L;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 6d1a66af84..a54851d4e7 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -219,6 +219,7 @@ public:
virtual String get_name();
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_mouse_mode(MouseMode p_mode);