diff options
Diffstat (limited to 'platform')
51 files changed, 1212 insertions, 640 deletions
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template index d8fb9326ea..daaf847f11 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/AndroidManifest.xml.template @@ -36,4 +36,9 @@ $$ADD_APPLICATION_CHUNKS$$ </application> + <instrumentation android:icon="@drawable/icon" + android:label="@string/godot_project_name_string" + android:name="org.godotengine.godot.GodotInstrumentation" + android:targetPackage="com.godot.game" /> + </manifest> diff --git a/platform/android/SCsub b/platform/android/SCsub index 47d5035224..d494372bcd 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' ] 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 0d62b242a8..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; } @@ -230,7 +230,7 @@ void AudioDriverOpenSL::_record_buffer_callbacks(SLAndroidSimpleBufferQueueItf q ad->_record_buffer_callback(queueItf); } -Error AudioDriverOpenSL::capture_start() { +Error AudioDriverOpenSL::capture_init_device() { SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, @@ -298,6 +298,15 @@ Error AudioDriverOpenSL::capture_start() { 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; @@ -317,7 +326,7 @@ Error AudioDriverOpenSL::capture_stop() { 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 9bd0d5e999..2981073cec 100644 --- a/platform/android/audio_driver_opensl.h +++ b/platform/android/audio_driver_opensl.h @@ -88,6 +88,8 @@ class AudioDriverOpenSL : public AudioDriver { SLAndroidSimpleBufferQueueItf queueItf, void *pContext); + virtual Error capture_init_device(); + public: void set_singleton(); diff --git a/platform/android/detect.py b/platform/android/detect.py index 80cda68a9e..5623274050 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 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 8ffd355219..e489bce3f8 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -658,6 +658,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 +817,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } } + if (tname == "uses-feature" && attrname == "glEsVersion") { + + encode_uint32(min_gles3 ? 0x00030000 : 0x00020000, &p_manifest.write[iofs + 16]); + } + iofs += 20; } @@ -1119,6 +1126,9 @@ public: 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"); + } } Vector<String> abis = get_enabled_abis(p_preset); @@ -1489,6 +1499,10 @@ public: } } + 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); diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index 304c33ecac..4f02fea81d 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; diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index a10d7876f4..48fd076d31 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -38,12 +38,14 @@ 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; @@ -51,11 +53,13 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.Manifest; import android.os.Build; 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; @@ -98,6 +102,7 @@ import javax.microedition.khronos.opengles.GL10; public class Godot extends Activity implements SensorEventListener, IDownloaderClient { static final int MAX_SINGLETONS = 64; + static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; private IStub mDownloaderClientStub; private IDownloaderService mRemoteService; private TextView mStatusText; @@ -258,6 +263,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 +327,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() { @@ -415,7 +441,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 +606,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 +947,27 @@ 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; + } + } + + 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/GodotIO.java b/platform/android/java/src/org/godotengine/godot/GodotIO.java index 85bba8bb4c..1b2ff61314 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/src/org/godotengine/godot/GodotIO.java @@ -500,11 +500,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); 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/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index ba8e8bd07b..ccf78f26f3 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -79,7 +79,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 +96,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 +715,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_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 53c909da88..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" @@ -47,6 +50,8 @@ 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 { @@ -588,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 jstring_to_string(s, env); -} - -static String _get_locale() { - - JNIEnv *env = ThreadAndroid::get_env(); - jstring s = (jstring)env->CallObjectMethod(godot_io, _getLocale); - return jstring_to_string(s, env); -} - -static String _get_clipboard() { - JNIEnv *env = ThreadAndroid::get_env(); - jstring s = (jstring)env->CallObjectMethod(_godot_instance, _getClipboard); - return jstring_to_string(s, env); -} - -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 jstring_to_string(s, env); -} - -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 jstring_to_string(s, env); -} - -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 jstring_to_string(s, env); -} - -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 - - jclass cls = env->FindClass("org/godotengine/godot/Godot"); - if (cls) { + // 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)); - 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; } @@ -844,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); @@ -873,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;"); @@ -882,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); } } @@ -927,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)); @@ -941,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 + } } } @@ -958,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, @@ -977,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); } } @@ -1571,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 b86976843c..d65cf2f31e 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 { @@ -499,18 +510,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 +528,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 +557,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 +569,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 +599,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 +616,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 +644,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) { @@ -726,7 +723,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 +731,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..3a5404124a 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); @@ -203,10 +164,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 +200,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/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/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 d160553050..64405bfa5b 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -615,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(); @@ -641,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 172572bcb4..853f24379e 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 diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index c45931fdfd..85d4b9e847 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -201,6 +201,9 @@ void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> 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"); + } } Vector<String> architectures = _get_preset_architectures(p_preset); @@ -266,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)); @@ -396,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"; @@ -840,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(); 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 b44b3127c7..7d0fdd2078 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; diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 47da8de5df..c7acbde3f7 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -1,5 +1,4 @@ import os -import sys def is_active(): diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 5704433650..487da77b10 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -114,6 +114,9 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP 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"); + } } } } @@ -211,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; @@ -360,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/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 57ae1b6e26..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; 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/export/export.cpp b/platform/osx/export/export.cpp index b8f6977b39..5e94bc457b 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); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 5206dc13b6..7d2116ba7e 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; @@ -601,12 +599,13 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { Ref<InputEventMouseButton> mb; mb.instance(); - + const CGFloat backingScaleFactor = [[event window] backingScaleFactor]; + const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor); get_key_modifier_state([event modifierFlags], mb); mb->set_button_index(index); mb->set_pressed(pressed); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); + mb->set_position(pos); + mb->set_global_position(pos); mb->set_button_mask(button_mask); if (index == BUTTON_LEFT && pressed) { mb->set_doubleclick([event clickCount] == 2); @@ -642,8 +641,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); @@ -765,9 +762,41 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { [super updateTrackingAreas]; } +static bool isNumpadKey(unsigned int key) { + + static const unsigned int table[] = { + 0x41, /* kVK_ANSI_KeypadDecimal */ + 0x43, /* kVK_ANSI_KeypadMultiply */ + 0x45, /* kVK_ANSI_KeypadPlus */ + 0x47, /* kVK_ANSI_KeypadClear */ + 0x4b, /* kVK_ANSI_KeypadDivide */ + 0x4c, /* kVK_ANSI_KeypadEnter */ + 0x4e, /* kVK_ANSI_KeypadMinus */ + 0x51, /* kVK_ANSI_KeypadEquals */ + 0x52, /* kVK_ANSI_Keypad0 */ + 0x53, /* kVK_ANSI_Keypad1 */ + 0x54, /* kVK_ANSI_Keypad2 */ + 0x55, /* kVK_ANSI_Keypad3 */ + 0x56, /* kVK_ANSI_Keypad4 */ + 0x57, /* kVK_ANSI_Keypad5 */ + 0x58, /* kVK_ANSI_Keypad6 */ + 0x59, /* kVK_ANSI_Keypad7 */ + 0x5b, /* kVK_ANSI_Keypad8 */ + 0x5c, /* kVK_ANSI_Keypad9 */ + 0x5f, /* kVK_JIS_KeypadComma */ + 0x00 + }; + for (int i = 0; table[i] != 0; i++) { + if (key == table[i]) + return true; + } + return false; +} + // Translates a OS X keycode to a Godot keycode // static int translateKey(unsigned int key) { + // Keyboard symbol translation table static const unsigned int table[128] = { /* 00 */ KEY_A, @@ -780,7 +809,7 @@ static int translateKey(unsigned int key) { /* 07 */ KEY_X, /* 08 */ KEY_C, /* 09 */ KEY_V, - /* 0a */ KEY_UNKNOWN, + /* 0a */ KEY_SECTION, /* ISO Section */ /* 0b */ KEY_B, /* 0c */ KEY_Q, /* 0d */ KEY_W, @@ -834,7 +863,7 @@ static int translateKey(unsigned int key) { /* 3d */ KEY_ALT, /* 3e */ KEY_CONTROL, /* 3f */ KEY_UNKNOWN, /* Function */ - /* 40 */ KEY_UNKNOWN, + /* 40 */ KEY_UNKNOWN, /* F17 */ /* 41 */ KEY_KP_PERIOD, /* 42 */ KEY_UNKNOWN, /* 43 */ KEY_KP_MULTIPLY, @@ -842,16 +871,16 @@ static int translateKey(unsigned int key) { /* 45 */ KEY_KP_ADD, /* 46 */ KEY_UNKNOWN, /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */ - /* 48 */ KEY_UNKNOWN, /* VolumeUp */ - /* 49 */ KEY_UNKNOWN, /* VolumeDown */ - /* 4a */ KEY_UNKNOWN, /* Mute */ + /* 48 */ KEY_VOLUMEUP, /* VolumeUp */ + /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */ + /* 4a */ KEY_VOLUMEMUTE, /* Mute */ /* 4b */ KEY_KP_DIVIDE, /* 4c */ KEY_KP_ENTER, /* 4d */ KEY_UNKNOWN, /* 4e */ KEY_KP_SUBTRACT, - /* 4f */ KEY_UNKNOWN, - /* 50 */ KEY_UNKNOWN, - /* 51 */ KEY_EQUAL, //wtf equal? + /* 4f */ KEY_UNKNOWN, /* F18 */ + /* 50 */ KEY_UNKNOWN, /* F19 */ + /* 51 */ KEY_EQUAL, /* KeypadEqual */ /* 52 */ KEY_KP_0, /* 53 */ KEY_KP_1, /* 54 */ KEY_KP_2, @@ -860,27 +889,27 @@ static int translateKey(unsigned int key) { /* 57 */ KEY_KP_5, /* 58 */ KEY_KP_6, /* 59 */ KEY_KP_7, - /* 5a */ KEY_UNKNOWN, + /* 5a */ KEY_UNKNOWN, /* F20 */ /* 5b */ KEY_KP_8, /* 5c */ KEY_KP_9, - /* 5d */ KEY_UNKNOWN, - /* 5e */ KEY_UNKNOWN, - /* 5f */ KEY_UNKNOWN, + /* 5d */ KEY_YEN, /* JIS Yen */ + /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */ + /* 5f */ KEY_COMMA, /* JIS KeypadComma */ /* 60 */ KEY_F5, /* 61 */ KEY_F6, /* 62 */ KEY_F7, /* 63 */ KEY_F3, /* 64 */ KEY_F8, /* 65 */ KEY_F9, - /* 66 */ KEY_UNKNOWN, + /* 66 */ KEY_UNKNOWN, /* JIS Eisu */ /* 67 */ KEY_F11, - /* 68 */ KEY_UNKNOWN, + /* 68 */ KEY_UNKNOWN, /* JIS Kana */ /* 69 */ KEY_F13, /* 6a */ KEY_F16, /* 6b */ KEY_F14, /* 6c */ KEY_UNKNOWN, /* 6d */ KEY_F10, - /* 6e */ KEY_UNKNOWN, + /* 6e */ KEY_MENU, /* 6f */ KEY_F12, /* 70 */ KEY_UNKNOWN, /* 71 */ KEY_F15, @@ -971,6 +1000,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 +1128,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 +1137,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 +1457,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a RasterizerGLES3::make_current(); break; } else { - if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) { p_video_driver = VIDEO_DRIVER_GLES2; gles3 = false; continue; @@ -2233,12 +2270,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 @@ -2529,6 +2566,8 @@ void OS_OSX::process_events() { [autoreleasePool drain]; autoreleasePool = [[NSAutoreleasePool alloc] init]; + + input->flush_accumulated_events(); } void OS_OSX::process_key_events() { @@ -2571,7 +2610,7 @@ void OS_OSX::process_key_events() { void OS_OSX::push_input(const Ref<InputEvent> &p_event) { Ref<InputEvent> ev = p_event; - input->parse_input_event(ev); + input->accumulate_input_event(ev); } void OS_OSX::force_process_input() { 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..f13ee72fd2 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,30 @@ 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', '-DDEBUG_ENABLED']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os', '-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', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + env.Append(LINKFLAGS=['-rdynamic']) ## Architecture @@ -59,6 +84,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 +96,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 +146,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 +168,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 +225,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/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..f8f1b066f6 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), ] 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 637ef5aaef..bc74da8a1b 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; 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..0118b5bae2 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -1,6 +1,5 @@ import methods import os -import sys def is_active(): 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<*>"> <Expand> - <Item Name="size">(_cowdata && _cowdata->_ptr) ? (((const unsigned int *)(_cowdata->_ptr))[-1]) : 0</Item> + <Item Name="[size]">_cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0</Item> <ArrayItems> - <Size>(_cowdata && _cowdata->_ptr) ? (((const unsigned int *)(_cowdata->_ptr))[-1]) : 0</Size> - <ValuePointer>(_cowdata) ? (_cowdata->_ptr) : 0</ValuePointer> + <Size>_cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0</Size> + <ValuePointer>_cowdata._ptr</ValuePointer> </ArrayItems> </Expand> </Type> <Type Name="PoolVector<*>"> <Expand> - <Item Name="size">alloc ? (alloc->size / sizeof($T1)) : 0</Item> + <Item Name="[size]">alloc ? (alloc->size / sizeof($T1)) : 0</Item> <ArrayItems> <Size>alloc ? (alloc->size / sizeof($T1)) : 0</Size> <ValuePointer>alloc ? (($T1 *)alloc->mem) : 0</ValuePointer> </ArrayItems> </Expand> </Type> + + <Type Name="List<*>"> + <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->type == Variant::NIL">nil</DisplayString> - <DisplayString Condition="this->type == Variant::BOOL">{_data._bool}</DisplayString> - <DisplayString Condition="this->type == Variant::INT">{_data._int}</DisplayString> - <DisplayString Condition="this->type == Variant::REAL">{_data._real}</DisplayString> - <DisplayString Condition="this->type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString> - <DisplayString Condition="this->type == Variant::AABB">{_data._aabb}</DisplayString> - <DisplayString Condition="this->type == Variant::BASIS">{_data._basis}</DisplayString> - <DisplayString Condition="this->type == Variant::TRANSFORM">{_data._transform}</DisplayString> - <DisplayString Condition="this->type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::STRING && ((String *)(&_data._mem[0]))->_cowdata._ptr == 0">""</DisplayString> - <DisplayString Condition="this->type == Variant::STRING && ((String *)(&_data._mem[0]))->_cowdata._ptr != 0">{((String *)(&_data._mem[0]))->_cowdata._ptr,su}</DisplayString> - <DisplayString Condition="this->type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::_RID">{*(RID *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_BYTE_ARRAY">{*(PoolByteArray *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_INT_ARRAY">{*(PoolIntArray *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_REAL_ARRAY">{*(PoolRealArray *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_STRING_ARRAY">{*(PoolStringArray *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_VECTOR2_ARRAY">{*(PoolVector2Array *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_VECTOR3_ARRAY">{*(PoolVector3Array *)_data._mem}</DisplayString> - <DisplayString Condition="this->type == Variant::POOL_COLOR_ARRAY">{*(PoolColorArray *)_data._mem}</DisplayString> - - <StringView Condition="this->type == Variant::STRING && ((String *)(&_data._mem[0]))->_cowdata._ptr != 0">((String *)(&_data._mem[0]))->_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 && ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,su</StringView> + <Expand> - <Item Name="value" Condition="this->type == Variant::BOOL">_data._bool</Item> - <Item Name="value" Condition="this->type == Variant::INT">_data._int</Item> - <Item Name="value" Condition="this->type == Variant::REAL">_data._real</Item> - <Item Name="value" Condition="this->type == Variant::TRANSFORM2D">_data._transform2d</Item> - <Item Name="value" Condition="this->type == Variant::AABB">_data._aabb</Item> - <Item Name="value" Condition="this->type == Variant::BASIS">_data._basis</Item> - <Item Name="value" Condition="this->type == Variant::TRANSFORM">_data._transform</Item> - <Item Name="value" Condition="this->type == Variant::ARRAY">*(Array *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::STRING">*(String *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::RECT2">*(Rect2 *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::PLANE">*(Plane *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::QUAT">*(Quat *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::COLOR">*(Color *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::_RID">*(RID *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::OBJECT">*(Object *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::ARRAY">*(Array *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::POOL_BYTE_ARRAY">*(PoolByteArray *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::POOL_INT_ARRAY">*(PoolIntArray *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::POOL_REAL_ARRAY">*(PoolRealArray *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::POOL_STRING_ARRAY">*(PoolStringArray *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::POOL_VECTOR2_ARRAY">*(PoolVector2Array *)_data._mem</Item> - <Item Name="value" Condition="this->type == Variant::POOL_VECTOR3_ARRAY">*(PoolVector3Array *)_data._mem</Item> - <Item Name="value" Condition="this->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->_cowdata._ptr == 0">empty</DisplayString> - <DisplayString Condition="this->_cowdata._ptr != 0">{this->_cowdata._ptr,su}</DisplayString> - <StringView Condition="this->_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 && _data->cname">{_data->cname}</DisplayString> + <DisplayString Condition="_data && !_data->cname">{_data->name,su}</DisplayString> + <DisplayString Condition="!_data">[empty]</DisplayString> + <StringView Condition="_data && _data->cname">_data->cname</StringView> + <StringView Condition="_data && !_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 bace65e772..6125455e74 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -271,7 +271,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,7 +293,7 @@ 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) { @@ -458,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; @@ -545,7 +545,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: @@ -718,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; @@ -988,7 +988,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 @@ -1026,7 +1026,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; } @@ -1290,7 +1290,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; @@ -1312,7 +1312,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; @@ -2252,6 +2252,7 @@ void OS_Windows::process_events() { if (!drop_events) { process_key_events(); + input->flush_accumulated_events(); } } 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 b5ad59e60a..5f7b825f5e 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 + def is_active(): return True @@ -160,7 +160,7 @@ 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']) @@ -197,7 +197,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) 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 b7fbb89edf..0fe91f3d00 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; @@ -1660,7 +1660,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 +1804,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 +1991,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 +2014,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; } @@ -2102,7 +2102,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 +2163,7 @@ void OS_X11::process_xevents() { } } - input->parse_input_event(mb); + input->accumulate_input_event(mb); } break; case MotionNotify: { @@ -2273,7 +2273,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: @@ -2457,6 +2457,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 { @@ -3046,11 +3048,12 @@ void OS_X11::set_context(int p_context) { 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 + String config_name_tmp = GLOBAL_GET("application/config/name"); + if (config_name_tmp.length() > 0) { + config_name = strdup(config_name_tmp.utf8().get_data()); + } else { config_name = strdup("Godot Engine"); + } wm_class = config_name; } |