diff options
Diffstat (limited to 'platform')
30 files changed, 256 insertions, 113 deletions
diff --git a/platform/android/detect.py b/platform/android/detect.py index 6eb8ba34ed..ec36a40941 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -24,7 +24,11 @@ def can_build(): def get_opts(): return [ ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()), - ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), + ( + "ndk_platform", + 'Target platform (android-<api>, e.g. "android-' + str(get_min_target_api()) + '")', + "android-" + str(get_min_target_api()), + ), ] @@ -46,6 +50,11 @@ def get_ndk_version(): return "23.2.8568313" +# This is kept in sync with the value in 'platform/android/java/app/config.gradle'. +def get_min_target_api(): + return 21 + + def get_flags(): return [ ("arch", "arm64"), # Default for convenience. @@ -87,30 +96,26 @@ def configure(env: "Environment"): ) sys.exit() + if get_min_sdk_version(env["ndk_platform"]) < get_min_target_api(): + print( + "WARNING: minimum supported Android target api is %d. Forcing target api %d." + % (get_min_target_api(), get_min_target_api()) + ) + env["ndk_platform"] = "android-" + str(get_min_target_api()) + install_ndk_if_needed(env) ndk_root = env["ANDROID_NDK_ROOT"] # Architecture - if get_min_sdk_version(env["ndk_platform"]) < 21 and env["arch"] in ["x86_64", "arm64"]: - print( - 'WARNING: arch="%s" is not supported with "ndk_platform" lower than "android-21". Forcing platform 21.' - % env["arch"] - ) - env["ndk_platform"] = "android-21" - if env["arch"] == "arm32": target_triple = "armv7a-linux-androideabi" - env.extra_suffix = ".armv7" + env.extra_suffix elif env["arch"] == "arm64": target_triple = "aarch64-linux-android" - env.extra_suffix = ".armv8" + env.extra_suffix elif env["arch"] == "x86_32": target_triple = "i686-linux-android" - env.extra_suffix = ".x86" + env.extra_suffix elif env["arch"] == "x86_64": target_triple = "x86_64-linux-android" - env.extra_suffix = ".x86_64" + env.extra_suffix target_option = ["-target", target_triple + str(get_min_sdk_version(env["ndk_platform"]))] env.Append(ASFLAGS=[target_option, "-c"]) @@ -165,7 +170,6 @@ def configure(env: "Environment"): "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split() ) ) - env.Append(CPPDEFINES=["GLES_ENABLED"]) if get_min_sdk_version(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) @@ -188,9 +192,13 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/android"]) env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"]) - env.Append(LIBS=["OpenSLES", "EGL", "GLESv2", "android", "log", "z", "dl"]) + env.Append(LIBS=["OpenSLES", "EGL", "android", "log", "z", "dl"]) if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) + + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.Append(LIBS=["GLESv3"]) diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 967f5c7dae..f76f3844e9 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -41,6 +41,10 @@ #include "platform/android/vulkan/vulkan_context_android.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif +#ifdef GLES3_ENABLED +#include "drivers/gles3/rasterizer_gles3.h" +#include <EGL/egl.h> +#endif DisplayServerAndroid *DisplayServerAndroid::get_singleton() { return static_cast<DisplayServerAndroid *>(DisplayServer::get_singleton()); @@ -323,7 +327,7 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type, } #ifdef GLES3_ENABLED case OPENGL_CONTEXT: { - return eglGetCurrentContext(); + return reinterpret_cast<int64_t>(eglGetCurrentContext()); } #endif default: { @@ -449,6 +453,14 @@ DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_drive DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); if (r_error != OK) { OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver"); + if (p_rendering_driver == "vulkan") { + OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" + "Please try exporting your game using the gl_compatibility renderer.", + "Unable to initialize Video driver"); + } else { + OS::get_singleton()->alert("Your video card driver does not support OpenGL ES 3.0.", + "Unable to initialize Video driver"); + } } return ds; } @@ -493,28 +505,11 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) { DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; - // TODO: rendering_driver is broken, change when different drivers are supported again - rendering_driver = "vulkan"; - keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on"); #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { - bool gl_initialization_error = false; - - if (RasterizerGLES3::is_viable() == OK) { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - } else { - gl_initialization_error = true; - } - - if (gl_initialization_error) { - OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n" - "Please try updating your Android version.", - "Unable to initialize video driver"); - return; - } + RasterizerGLES3::make_current(); } #endif @@ -619,11 +614,11 @@ MouseButton DisplayServerAndroid::mouse_get_button_state() const { return (MouseButton)Input::get_singleton()->get_mouse_button_mask(); } -void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) { +void DisplayServerAndroid::_cursor_set_shape_helper(CursorShape p_shape, bool force) { if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon()) { return; } - if (cursor_shape == p_shape) { + if (cursor_shape == p_shape && !force) { return; } @@ -634,10 +629,23 @@ void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) } } +void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) { + _cursor_set_shape_helper(p_shape); +} + DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const { return cursor_shape; } +void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { + String cursor_path = p_cursor.is_valid() ? p_cursor->get_path() : ""; + if (!cursor_path.is_empty()) { + cursor_path = ProjectSettings::get_singleton()->globalize_path(cursor_path); + } + OS_Android::get_singleton()->get_godot_java()->get_godot_view()->configure_pointer_icon(android_cursors[cursor_shape], cursor_path, p_hotspot); + _cursor_set_shape_helper(p_shape, true); +} + void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { #if defined(VULKAN_ENABLED) context_vulkan->set_vsync_mode(p_window, p_vsync_mode); @@ -651,3 +659,23 @@ DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_ return DisplayServer::VSYNC_ENABLED; #endif } + +void DisplayServerAndroid::reset_swap_buffers_flag() { + swap_buffers_flag = false; +} + +bool DisplayServerAndroid::should_swap_buffers() const { + return swap_buffers_flag; +} + +void DisplayServerAndroid::swap_buffers() { + swap_buffers_flag = true; +} + +void DisplayServerAndroid::set_native_icon(const String &p_filename) { + // NOT SUPPORTED +} + +void DisplayServerAndroid::set_icon(const Ref<Image> &p_icon) { + // NOT SUPPORTED +} diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index a6bc88e048..c7f4d8046f 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -66,6 +66,7 @@ class DisplayServerAndroid : public DisplayServer { MouseMode mouse_mode = MouseMode::MOUSE_MODE_VISIBLE; bool keep_screen_on; + bool swap_buffers_flag; CursorShape cursor_shape = CursorShape::CURSOR_ARROW; @@ -188,8 +189,10 @@ public: void process_magnetometer(const Vector3 &p_magnetometer); void process_gyroscope(const Vector3 &p_gyroscope); + void _cursor_set_shape_helper(CursorShape p_shape, bool force = false); virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; + virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; virtual void mouse_set_mode(MouseMode p_mode) override; virtual MouseMode mouse_get_mode() const override; @@ -204,6 +207,13 @@ public: virtual Point2i mouse_get_position() const override; virtual MouseButton mouse_get_button_state() const override; + void reset_swap_buffers_flag(); + bool should_swap_buffers() const; + virtual void swap_buffers() override; + + virtual void set_native_icon(const String &p_filename) override; + virtual void set_icon(const Ref<Image> &p_icon) override; + DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); ~DisplayServerAndroid(); }; diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index c3fba625c6..737e25b270 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -245,7 +245,7 @@ static const int EXPORT_FORMAT_AAB = 1; static const char *APK_ASSETS_DIRECTORY = "res://android/build/assets"; static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/installTime/src/main/assets"; -static const int DEFAULT_MIN_SDK_VERSION = 19; // Should match the value in 'platform/android/java/app/config.gradle#minSdk' +static const int DEFAULT_MIN_SDK_VERSION = 21; // Should match the value in 'platform/android/java/app/config.gradle#minSdk' static const int DEFAULT_TARGET_SDK_VERSION = 32; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk' #ifndef ANDROID_ENABLED diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 2d4c4763a2..1db135826a 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -13,7 +13,7 @@ android:xlargeScreens="true" /> <uses-feature - android:glEsVersion="0x00020000" + android:glEsVersion="0x00030000" android:required="true" /> <application diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index e1d9dc4cde..f1b4bfd534 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -1,14 +1,17 @@ ext.versions = [ androidGradlePlugin: '7.2.1', compileSdk : 32, - minSdk : 19, // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION' - targetSdk : 32, // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION' + // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION' + minSdk : 21, + // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION' + targetSdk : 32, buildTools : '32.0.0', kotlinVersion : '1.7.0', fragmentVersion : '1.3.6', nexusPublishVersion: '1.1.0', javaVersion : 11, - ndkVersion : '23.2.8568313' // Also update 'platform/android/detect.py#get_ndk_version()' when this is updated. + // Also update 'platform/android/detect.py#get_ndk_version()' when this is updated. + ndkVersion : '23.2.8568313' ] diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml index 6aa5f06f31..f3ddaafd0e 100644 --- a/platform/android/java/editor/src/main/AndroidManifest.xml +++ b/platform/android/java/editor/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:xlargeScreens="true" /> <uses-feature - android:glEsVersion="0x00020000" + android:glEsVersion="0x00030000" android:required="true" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index a002a37ab9..3487e5019c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -175,6 +175,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public GodotIO io; public GodotNetUtils netUtils; public GodotTTS tts; + DirectoryAccessHandler directoryAccessHandler; public interface ResultCallback { void callback(int requestCode, int resultCode, Intent data); @@ -488,7 +489,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC netUtils = new GodotNetUtils(activity); tts = new GodotTTS(activity); Context context = getContext(); - DirectoryAccessHandler directoryAccessHandler = new DirectoryAccessHandler(context); + directoryAccessHandler = new DirectoryAccessHandler(context); FileAccessHandler fileAccessHandler = new FileAccessHandler(context); mSensorManager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index 3dfc37f6b0..f8d937521b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -43,8 +43,13 @@ import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.PixelFormat; import android.os.Build; +import android.text.TextUtils; +import android.util.SparseArray; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -52,6 +57,8 @@ import android.view.SurfaceView; import androidx.annotation.Keep; +import java.io.InputStream; + /** * A simple GLSurfaceView sub-class that demonstrate how to perform * OpenGL ES 2.0 rendering into a GL Surface. Note the following important @@ -61,7 +68,7 @@ import androidx.annotation.Keep; * See ContextFactory class definition below. * * - The class must use a custom EGLConfigChooser to be able to select - * an EGLConfig that supports 2.0. This is done by providing a config + * an EGLConfig that supports 3.0. This is done by providing a config * specification to eglChooseConfig() that has the attribute * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag * set. See ConfigChooser class definition below. @@ -74,6 +81,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView private final Godot godot; private final GodotInputHandler inputHandler; private final GodotRenderer godotRenderer; + private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>(); public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_debug_opengl) { super(context); @@ -169,12 +177,49 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView } /** + * Used to configure the PointerIcon for the given type. + * + * Called from JNI + */ + @Keep + @Override + public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + try { + Bitmap bitmap = null; + if (!TextUtils.isEmpty(imagePath)) { + if (godot.directoryAccessHandler.filesystemFileExists(imagePath)) { + // Try to load the bitmap from the file system + bitmap = BitmapFactory.decodeFile(imagePath); + } else if (godot.directoryAccessHandler.assetsFileExists(imagePath)) { + // Try to load the bitmap from the assets directory + AssetManager am = getContext().getAssets(); + InputStream imageInputStream = am.open(imagePath); + bitmap = BitmapFactory.decodeStream(imageInputStream); + } + } + + PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY); + customPointerIcons.put(pointerType, customPointerIcon); + } catch (Exception e) { + // Reset the custom pointer icon + customPointerIcons.delete(pointerType); + } + } + } + + /** * called from JNI to change pointer icon */ @Keep + @Override public void setPointerIcon(int pointerType) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType)); + PointerIcon pointerIcon = customPointerIcons.get(pointerType); + if (pointerIcon == null) { + pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType); + } + setPointerIcon(pointerIcon); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java index cb63fd885f..ab74ba037d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java @@ -48,5 +48,7 @@ public interface GodotRenderView { GodotInputHandler getInputHandler(); + void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY); + void setPointerIcon(int pointerType); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java index 0becf00d93..56bc7f9e76 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -36,7 +36,12 @@ import org.godotengine.godot.vulkan.VkSurfaceView; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Build; +import android.text.TextUtils; +import android.util.SparseArray; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -44,10 +49,13 @@ import android.view.SurfaceView; import androidx.annotation.Keep; +import java.io.InputStream; + public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { private final Godot godot; private final GodotInputHandler mInputHandler; private final VkRenderer mRenderer; + private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>(); public GodotVulkanRenderView(Context context, Godot godot) { super(context); @@ -143,12 +151,49 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV } /** + * Used to configure the PointerIcon for the given type. + * + * Called from JNI + */ + @Keep + @Override + public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + try { + Bitmap bitmap = null; + if (!TextUtils.isEmpty(imagePath)) { + if (godot.directoryAccessHandler.filesystemFileExists(imagePath)) { + // Try to load the bitmap from the file system + bitmap = BitmapFactory.decodeFile(imagePath); + } else if (godot.directoryAccessHandler.assetsFileExists(imagePath)) { + // Try to load the bitmap from the assets directory + AssetManager am = getContext().getAssets(); + InputStream imageInputStream = am.open(imagePath); + bitmap = BitmapFactory.decodeStream(imageInputStream); + } + } + + PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY); + customPointerIcons.put(pointerType, customPointerIcon); + } catch (Exception e) { + // Reset the custom pointer icon + customPointerIcons.delete(pointerType); + } + } + } + + /** * called from JNI to change pointer icon */ @Keep + @Override public void setPointerIcon(int pointerType) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType)); + PointerIcon pointerIcon = customPointerIcons.get(pointerType); + if (pointerIcon == null) { + pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType); + } + setPointerIcon(pointerIcon); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt index fedcf4843f..6bc317415f 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt @@ -79,6 +79,9 @@ class DirectoryAccessHandler(context: Context) { private val assetsDirAccess = AssetsDirectoryAccess(context) private val fileSystemDirAccess = FilesystemDirectoryAccess(context) + fun assetsFileExists(assetsPath: String) = assetsDirAccess.fileExists(assetsPath) + fun filesystemFileExists(path: String) = fileSystemDirAccess.fileExists(path) + private fun hasDirId(accessType: AccessType, dirId: Int): Boolean { return when (accessType) { ACCESS_RESOURCES -> assetsDirAccess.hasDirId(dirId) diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java index 445238b1c2..9834fdfb88 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java @@ -45,20 +45,18 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { private int[] mValue = new int[1]; - // FIXME: Add support for Vulkan. - - /* This EGL config specification is used to specify 2.0 rendering. + /* This EGL config specification is used to specify 3.0 rendering. * We use a minimum size of 4 bits for red/green/blue, but will * perform actual matching in chooseConfig() below. */ private static int EGL_OPENGL_ES2_BIT = 4; - private static int[] s_configAttribs2 = { + private static int[] s_configAttribs = { EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, - // EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_DEPTH_SIZE, 16, // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT EGL10.EGL_NONE }; @@ -75,7 +73,7 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { /* Get the number of minimally matching EGL configurations */ int[] num_config = new int[1]; - egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); + egl.eglChooseConfig(display, s_configAttribs, null, 0, num_config); int numConfigs = num_config[0]; @@ -86,7 +84,7 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { /* Allocate then read the array of minimally matching EGL configs */ EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); + egl.eglChooseConfig(display, s_configAttribs, configs, numConfigs, num_config); if (GLUtils.DEBUG) { GLUtils.printConfigs(egl, display, configs); diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index 5d62723170..8fb86bf6d0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -52,17 +52,16 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - // FIXME: Add support for Vulkan. - Log.w(TAG, "creating OpenGL ES 2.0 context :"); + Log.w(TAG, "creating OpenGL ES 3.0 context :"); GLUtils.checkEglError(TAG, "Before eglCreateContext", egl); EGLContext context; if (GLUtils.use_debug_opengl) { - int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; - context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list2); + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); } else { - int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; - context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list2); + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); } GLUtils.checkEglError(TAG, "After eglCreateContext", egl); return context; diff --git a/platform/android/java/nativeSrcsConfigs/CMakeLists.txt b/platform/android/java/nativeSrcsConfigs/CMakeLists.txt index 711f7cd502..e1534c7685 100644 --- a/platform/android/java/nativeSrcsConfigs/CMakeLists.txt +++ b/platform/android/java/nativeSrcsConfigs/CMakeLists.txt @@ -17,4 +17,4 @@ target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${GODOT_ROOT_DIR}) -add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED) +add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED -DGLES3_ENABLED -DTOOLS_ENABLED) diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp index 378a467772..23cfc5f2e6 100644 --- a/platform/android/java_godot_view_wrapper.cpp +++ b/platform/android/java_godot_view_wrapper.cpp @@ -42,6 +42,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { int android_device_api_level = android_get_device_api_level(); if (android_device_api_level >= __ANDROID_API_N__) { + _configure_pointer_icon = env->GetMethodID(_cls, "configurePointerIcon", "(ILjava/lang/String;FF)V"); _set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V"); } if (android_device_api_level >= __ANDROID_API_O__) { @@ -51,7 +52,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { } bool GodotJavaViewWrapper::can_update_pointer_icon() const { - return _set_pointer_icon != nullptr; + return _configure_pointer_icon != nullptr && _set_pointer_icon != nullptr; } bool GodotJavaViewWrapper::can_capture_pointer() const { @@ -76,6 +77,16 @@ void GodotJavaViewWrapper::release_pointer_capture() { } } +void GodotJavaViewWrapper::configure_pointer_icon(int pointer_type, const String &image_path, const Vector2 &p_hotspot) { + if (_configure_pointer_icon != nullptr) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL(env); + + jstring jImagePath = env->NewStringUTF(image_path.utf8().get_data()); + env->CallVoidMethod(_godot_view, _configure_pointer_icon, pointer_type, jImagePath, p_hotspot.x, p_hotspot.y); + } +} + void GodotJavaViewWrapper::set_pointer_icon(int pointer_type) { if (_set_pointer_icon != nullptr) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h index b398c73cac..b58a6607ce 100644 --- a/platform/android/java_godot_view_wrapper.h +++ b/platform/android/java_godot_view_wrapper.h @@ -31,6 +31,7 @@ #ifndef JAVA_GODOT_VIEW_WRAPPER_H #define JAVA_GODOT_VIEW_WRAPPER_H +#include "core/math/vector2.h" #include <android/log.h> #include <jni.h> @@ -45,6 +46,8 @@ private: jmethodID _request_pointer_capture = 0; jmethodID _release_pointer_capture = 0; + + jmethodID _configure_pointer_icon = 0; jmethodID _set_pointer_icon = 0; public: @@ -55,6 +58,8 @@ public: void request_pointer_capture(); void release_pointer_capture(); + + void configure_pointer_icon(int pointer_type, const String &image_path, const Vector2 &p_hotspot); void set_pointer_icon(int pointer_type); ~GodotJavaViewWrapper(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 97fa90b1d2..4f81e4bccd 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -268,12 +268,16 @@ bool OS_Android::main_loop_iterate(bool *r_should_swap_buffers) { if (!main_loop) { return false; } + DisplayServerAndroid::get_singleton()->reset_swap_buffers_flag(); DisplayServerAndroid::get_singleton()->process_events(); uint64_t current_frames_drawn = Engine::get_singleton()->get_frames_drawn(); bool exit = Main::iteration(); if (r_should_swap_buffers) { - *r_should_swap_buffers = !is_in_low_processor_usage_mode() || RenderingServer::get_singleton()->has_changed() || current_frames_drawn != Engine::get_singleton()->get_frames_drawn(); + *r_should_swap_buffers = !is_in_low_processor_usage_mode() || + DisplayServerAndroid::get_singleton()->should_swap_buffers() || + RenderingServer::get_singleton()->has_changed() || + current_frames_drawn != Engine::get_singleton()->get_frames_drawn(); } return exit; @@ -474,7 +478,6 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god #if defined(GLES3_ENABLED) gl_extensions = nullptr; - use_gl2 = false; #endif #if defined(VULKAN_ENABLED) diff --git a/platform/ios/app_delegate.mm b/platform/ios/app_delegate.mm index fb183d52d4..3ebd530585 100644 --- a/platform/ios/app_delegate.mm +++ b/platform/ios/app_delegate.mm @@ -45,7 +45,7 @@ extern int gargc; extern char **gargv; -extern int ios_main(int, char **, String, String); +extern int ios_main(int, char **); extern void ios_finish(); @implementation AppDelegate @@ -66,12 +66,7 @@ static ViewController *mainViewController = nil; // Create a full-screen window self.window = [[UIWindow alloc] initWithFrame:windowBounds]; - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString *cacheDirectory = [paths objectAtIndex:0]; - - int err = ios_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String])); + int err = ios_main(gargc, gargv); if (err != 0) { // bail, things did not go very well for us, should probably output a message on screen with our error code... diff --git a/platform/ios/godot_ios.mm b/platform/ios/godot_ios.mm index 5f3e786b8a..abe7c59ce2 100644 --- a/platform/ios/godot_ios.mm +++ b/platform/ios/godot_ios.mm @@ -38,10 +38,6 @@ static OS_IOS *os = nullptr; -int add_path(int, char **); -int add_cmdline(int, char **); -int ios_main(int, char **, String); - int add_path(int p_argc, char **p_args) { NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"]; if (!str) { @@ -74,7 +70,7 @@ int add_cmdline(int p_argc, char **p_args) { return p_argc; } -int ios_main(int argc, char **argv, String data_dir, String cache_dir) { +int ios_main(int argc, char **argv) { size_t len = strlen(argv[0]); while (len--) { @@ -95,7 +91,7 @@ int ios_main(int argc, char **argv, String data_dir, String cache_dir) { char cwd[512]; getcwd(cwd, sizeof(cwd)); printf("cwd %s\n", cwd); - os = new OS_IOS(data_dir, cache_dir); + os = new OS_IOS(); // We must override main when testing is enabled TEST_MAIN_OVERRIDE diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index 400040875f..3560de7486 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -71,9 +71,6 @@ private: virtual void finalize() override; - String user_data_dir; - String cache_dir; - bool is_focused = false; void deinitialize_modules(); @@ -81,7 +78,7 @@ private: public: static OS_IOS *get_singleton(); - OS_IOS(String p_data_dir, String p_cache_dir); + OS_IOS(); ~OS_IOS(); void initialize_modules(); @@ -106,7 +103,6 @@ public: virtual Error shell_open(String p_uri) override; - void set_user_data_dir(String p_dir); virtual String get_user_data_dir() const override; virtual String get_cache_path() const override; diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index b6b94d2f5e..9a8cfc2593 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -90,7 +90,7 @@ OS_IOS *OS_IOS::get_singleton() { return (OS_IOS *)OS::get_singleton(); } -OS_IOS::OS_IOS(String p_data_dir, String p_cache_dir) { +OS_IOS::OS_IOS() { for (int i = 0; i < ios_init_callbacks_count; ++i) { ios_init_callbacks[i](); } @@ -101,11 +101,6 @@ OS_IOS::OS_IOS(String p_data_dir, String p_cache_dir) { main_loop = nullptr; - // can't call set_data_dir from here, since it requires DirAccess - // which is initialized in initialize_core - user_data_dir = p_data_dir; - cache_dir = p_cache_dir; - Vector<Logger *> loggers; loggers.push_back(memnew(SyslogLogger)); #ifdef DEBUG_ENABLED @@ -130,8 +125,6 @@ void OS_IOS::alert(const String &p_alert, const String &p_title) { void OS_IOS::initialize_core() { OS_Unix::initialize_core(); - - set_user_data_dir(user_data_dir); } void OS_IOS::initialize() { @@ -273,18 +266,26 @@ Error OS_IOS::shell_open(String p_uri) { return OK; } -void OS_IOS::set_user_data_dir(String p_dir) { - Ref<DirAccess> da = DirAccess::open(p_dir); - user_data_dir = da->get_current_dir(); - printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data()); -} - String OS_IOS::get_user_data_dir() const { - return user_data_dir; + static String ret; + if (ret.is_empty()) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + if (paths && [paths count] >= 1) { + ret.parse_utf8([[paths firstObject] UTF8String]); + } + } + return ret; } String OS_IOS::get_cache_path() const { - return cache_dir; + static String ret; + if (ret.is_empty()) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + if (paths && [paths count] >= 1) { + ret.parse_utf8([[paths firstObject] UTF8String]); + } + } + return ret; } String OS_IOS::get_locale() const { diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 3aff5b8b7e..a3bee13f69 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -2348,9 +2348,6 @@ void DisplayServerMacOS::reparent_check(WindowID p_window) { if (parent_screen == screen) { if (![[wd_parent.window_object childWindows] containsObject:wd.window_object]) { - if (wd.exclusive) { - ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); - } [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; [wd_parent.window_object addChildWindow:wd.window_object ordered:NSWindowAbove]; } @@ -2369,9 +2366,6 @@ void DisplayServerMacOS::reparent_check(WindowID p_window) { if (child_screen == screen) { if (![[wd.window_object childWindows] containsObject:wd_child.window_object]) { - if (wd_child.exclusive) { - ERR_FAIL_COND_MSG([[wd.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); - } if (wd_child.fullscreen) { [wd_child.window_object toggleFullScreen:nil]; } diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 5860a4f0ae..5e71d10a3f 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -1834,8 +1834,8 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor if (p_preset->get("notarization/apple_id_name") != "") { if (p_preset->get("notarization/apple_id_password") == "") { err += TTR("Notarization: Apple ID password not specified.") + "\n"; + valid = false; } - valid = false; } if (p_preset->get("notarization/api_uuid") != "") { if (p_preset->get("notarization/api_key") == "") { diff --git a/platform/web/js/engine/features.js b/platform/web/js/engine/features.js index f91a4eff81..b7c6c9d445 100644 --- a/platform/web/js/engine/features.js +++ b/platform/web/js/engine/features.js @@ -76,19 +76,19 @@ const Features = { // eslint-disable-line no-unused-vars getMissingFeatures: function () { const missing = []; if (!Features.isWebGLAvailable(2)) { - missing.push('WebGL2'); + missing.push('WebGL2 - Check web browser configuration and hardware support'); } if (!Features.isFetchAvailable()) { - missing.push('Fetch'); + missing.push('Fetch - Check web browser version'); } if (!Features.isSecureContext()) { - missing.push('Secure Context'); + missing.push('Secure Context - Check web server configuration (use HTTPS)'); } if (!Features.isCrossOriginIsolated()) { - missing.push('Cross Origin Isolation'); + missing.push('Cross Origin Isolation - Check web server configuration (send correct headers)'); } if (!Features.isSharedArrayBufferAvailable()) { - missing.push('SharedArrayBuffer'); + missing.push('SharedArrayBuffer - Check web server configuration (send correct headers)'); } // Audio is normally optional since we have a dummy fallback. return missing; diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index b501ee78db..7ba66750cf 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -157,7 +157,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { return EXCEPTION_CONTINUE_SEARCH; } - SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_EXACT_SYMBOLS); EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); module_handles.resize(cbNeeded / sizeof(HMODULE)); EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 0b878feb7f..29482213d8 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3919,6 +3919,8 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution)); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); + joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); + for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, main_window); @@ -3958,8 +3960,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win _update_real_mouse_position(MAIN_WINDOW_ID); - joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); - r_error = OK; static_cast<OS_Windows *>(OS::get_singleton())->set_main_window(windows[MAIN_WINDOW_ID].hWnd); diff --git a/platform/windows/godot.ico b/platform/windows/godot.ico Binary files differindex 25830ffdc6..f0bb68225d 100644 --- a/platform/windows/godot.ico +++ b/platform/windows/godot.ico diff --git a/platform/windows/godot_console.ico b/platform/windows/godot_console.ico Binary files differnew file mode 100644 index 0000000000..1d27e3d6ae --- /dev/null +++ b/platform/windows/godot_console.ico diff --git a/platform/windows/godot_res_wrap.rc b/platform/windows/godot_res_wrap.rc index 9877ff6075..9dd29afe51 100644 --- a/platform/windows/godot_res_wrap.rc +++ b/platform/windows/godot_res_wrap.rc @@ -4,7 +4,7 @@ #define _MKSTR(m_x) _STR(m_x) #endif -GODOT_ICON ICON platform/windows/godot.ico +GODOT_ICON ICON platform/windows/godot_console.ico 1 VERSIONINFO FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0 |