summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml35
-rw-r--r--core/debugger/remote_debugger.cpp2
-rw-r--r--core/engine.cpp2
-rw-r--r--core/engine.h2
-rw-r--r--core/global_constants.cpp3
-rw-r--r--core/object.h1
-rw-r--r--core/undo_redo.cpp3
-rw-r--r--doc/classes/Control.xml2
-rw-r--r--doc/classes/Dictionary.xml2
-rw-r--r--doc/classes/File.xml4
-rw-r--r--doc/classes/OptionButton.xml4
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml2
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--doc/classes/TileMap.xml4
-rw-r--r--doc/classes/UndoRedo.xml2
-rwxr-xr-xdoc/tools/makerst.py2
-rw-r--r--drivers/vulkan/SCsub8
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp35
-rw-r--r--editor/animation_track_editor.cpp2
-rw-r--r--editor/editor_themes.cpp2
-rw-r--r--editor/icons/AcceptDialog.svg2
-rw-r--r--editor/icons/ConfirmationDialog.svg2
-rw-r--r--editor/icons/EditorFileDialog.svg (renamed from editor/icons/PopupDialog.svg)2
-rw-r--r--editor/icons/FileDialog.svg2
-rw-r--r--editor/icons/Popup.svg2
-rw-r--r--editor/icons/PopupMenu.svg2
-rw-r--r--editor/icons/PopupPanel.svg2
-rw-r--r--editor/icons/ScriptCreateDialog.svg2
-rw-r--r--editor/icons/Window.svg (renamed from editor/icons/WindowDialog.svg)2
-rw-r--r--editor/icons/XRAnchor3D.svg (renamed from editor/icons/ARVRAnchor.svg)0
-rw-r--r--editor/icons/XRCamera3D.svg (renamed from editor/icons/ARVRCamera.svg)0
-rw-r--r--editor/icons/XRController3D.svg (renamed from editor/icons/ARVRController.svg)0
-rw-r--r--editor/icons/XROrigin3D.svg (renamed from editor/icons/ARVROrigin.svg)0
-rw-r--r--editor/plugins/material_editor_plugin.cpp12
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp68
-rw-r--r--editor/plugins/node_3d_editor_plugin.h11
-rw-r--r--editor/script_create_dialog.cpp9
-rw-r--r--editor/script_create_dialog.h1
-rw-r--r--main/main.cpp8
-rwxr-xr-xmisc/travis/android-tools-linux.sh4
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h3
-rw-r--r--modules/gdscript/gdscript_parser.cpp9
-rw-r--r--modules/opensimplex/noise_texture.cpp11
-rw-r--r--modules/visual_script/visual_script_editor.cpp16
-rw-r--r--modules/visual_script/visual_script_nodes.cpp3
-rw-r--r--platform/android/api/api.cpp5
-rw-r--r--platform/android/api/jni_singleton.h242
-rw-r--r--platform/android/java/app/build.gradle5
-rw-r--r--platform/android/java/app/settings.gradle2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java85
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java98
-rw-r--r--platform/android/java_godot_lib_jni.cpp2
-rw-r--r--platform/android/jni_utils.h186
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp48
-rw-r--r--platform/android/plugin/godot_plugin_jni.h2
-rw-r--r--platform/android/vulkan/vulkan_context_android.cpp8
-rw-r--r--platform/linuxbsd/display_server_x11.cpp8
-rw-r--r--scene/3d/light_3d.cpp11
-rw-r--r--scene/3d/light_3d.h1
-rw-r--r--scene/gui/option_button.cpp4
-rw-r--r--scene/gui/slider.cpp5
-rw-r--r--scene/gui/tree.cpp7
-rw-r--r--scene/resources/default_theme/default_theme.cpp2
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp44
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp2
-rw-r--r--servers/register_server_types.cpp8
-rw-r--r--servers/rendering/rasterizer.h2
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp73
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h18
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp4
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h15
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp1
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl385
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl20
-rw-r--r--servers/rendering/rendering_server_raster.cpp23
-rw-r--r--servers/rendering/rendering_server_raster.h4
-rw-r--r--servers/rendering/rendering_server_scene.cpp41
-rw-r--r--servers/rendering/rendering_server_viewport.cpp61
-rw-r--r--servers/rendering/rendering_server_viewport.h26
-rw-r--r--servers/rendering/rendering_server_wrap_mt.cpp22
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h8
-rw-r--r--servers/rendering_server.h5
-rw-r--r--thirdparty/vulkan/android/vk_mem_alloc.cpp8
83 files changed, 1386 insertions, 399 deletions
diff --git a/.travis.yml b/.travis.yml
index 14ee95e77e..8cfd7a1a7f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -55,17 +55,15 @@ matrix:
packages:
- *linux_deps
-# TODO: Android support
-
-# - name: Android export template (release_debug, Clang)
-# stage: build
-# env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
-# os: linux
-# compiler: clang
-# addons:
-# apt:
-# packages:
-# - openjdk-8-jdk
+ - name: Android export template (release_debug, Clang)
+ stage: build
+ env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
+ os: linux
+ compiler: clang
+ addons:
+ apt:
+ packages:
+ - openjdk-8-jdk
- name: macOS editor (debug, Clang)
stage: build
@@ -92,21 +90,6 @@ matrix:
# packages:
# - scons
-# TODO: Dummy/Offscreen rasterizer
-
-# - name: Linux headless editor (release_debug, GCC 9, testing project exporting and script running)
-# stage: build
-# env: PLATFORM=server TOOLS=yes TARGET=release_debug CACHE_NAME=${PLATFORM}-tools-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="warnings=extra werror=yes" TEST_PROJECT=yes
-# os: linux
-# compiler: gcc-9
-# addons:
-# apt:
-# sources:
-# - sourceline: "ppa:ubuntu-toolchain-r/test"
-# packages:
-# - *gcc9_deps
-# - *linux_deps
-
- name: Linux export template (release_debug, GCC 7, without 3D support)
stage: build
env: PLATFORM=linuxbsd TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-7 EXTRA_ARGS="disable_3d=yes"
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index c2996e552f..e6bcc5f77e 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -318,7 +318,7 @@ struct RemoteDebugger::ServersProfiler {
void _send_frame_data(bool p_final) {
DebuggerMarshalls::ServersProfilerFrame frame;
- frame.frame_number = Engine::get_singleton()->get_frames_drawn();
+ frame.frame_number = Engine::get_singleton()->get_idle_frames();
frame.frame_time = frame_time;
frame.idle_time = idle_time;
frame.physics_time = physics_time;
diff --git a/core/engine.cpp b/core/engine.cpp
index 36987eab31..5361e09a8a 100644
--- a/core/engine.cpp
+++ b/core/engine.cpp
@@ -60,7 +60,7 @@ void Engine::set_target_fps(int p_fps) {
_target_fps = p_fps > 0 ? p_fps : 0;
}
-float Engine::get_target_fps() const {
+int Engine::get_target_fps() const {
return _target_fps;
}
diff --git a/core/engine.h b/core/engine.h
index 4cfdeffa82..8512779d4c 100644
--- a/core/engine.h
+++ b/core/engine.h
@@ -86,7 +86,7 @@ public:
float get_physics_jitter_fix() const;
virtual void set_target_fps(int p_fps);
- virtual float get_target_fps() const;
+ virtual int get_target_fps() const;
virtual float get_frames_per_second() const { return _fps; }
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 8706a38453..6f6b8c1dd3 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -568,9 +568,6 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
- //deprecated, replaced by ClassDB function to check default value
- //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO);
- //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
diff --git a/core/object.h b/core/object.h
index 06dd610a3b..1eaab5034e 100644
--- a/core/object.h
+++ b/core/object.h
@@ -60,7 +60,6 @@ enum PropertyHint {
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
- PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat.
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index 8bd5a4915d..62ad3e9f98 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -511,8 +511,7 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action);
- // FIXME: Typo in "commiting", fix in 4.0 when breaking compat.
- ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_committing_action);
+ ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
{
MethodInfo mi;
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 85a75fda37..0c8d42021a 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -838,7 +838,7 @@
Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Also controls whether the control can receive the [signal mouse_entered], and [signal mouse_exited] signals. See the constants to learn what each does.
</member>
<member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false">
- Enables whether rendering of children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered.
+ Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered.
</member>
<member name="rect_global_position" type="Vector2" setter="_set_global_position" getter="get_global_position">
The node's global position, relative to the world (usually to the top-left corner of the window).
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 540ebf3931..cf0ed8bf68 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -78,7 +78,7 @@
<argument index="0" name="deep" type="bool" default="false">
</argument>
<description>
- Creates a copy of the dictionary, and returns it.
+ Creates a copy of the dictionary, and returns it. The [code]deep[/code] parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects.
</description>
</method>
<method name="empty">
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index e9477517cf..17c65731ff 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -297,6 +297,7 @@
</argument>
<description>
Stores an integer as 16 bits in the file.
+ [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^16 - 1][/code].
</description>
</method>
<method name="store_32">
@@ -306,6 +307,7 @@
</argument>
<description>
Stores an integer as 32 bits in the file.
+ [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^32 - 1][/code].
</description>
</method>
<method name="store_64">
@@ -315,6 +317,7 @@
</argument>
<description>
Stores an integer as 64 bits in the file.
+ [b]Note:[/b] The [code]value[/code] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value).
</description>
</method>
<method name="store_8">
@@ -324,6 +327,7 @@
</argument>
<description>
Stores an integer as 8 bits in the file.
+ [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 255][/code].
</description>
</method>
<method name="store_buffer">
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 5cb2aaf314..39d974ec47 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -214,14 +214,14 @@
</members>
<signals>
<signal name="item_focused">
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
Emitted the when user navigates to an item using the [code]ui_up[/code] or [code]ui_down[/code] actions. The index of the item selected is passed as argument.
</description>
</signal>
<signal name="item_selected">
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
Emitted when the current item has been changed by the user. The index of the item selected is passed as argument.
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index 09ee93732d..ea094dcd90 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -19,7 +19,7 @@
</argument>
<description>
Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code].
- If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics.
+ If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics3D.
</description>
</method>
<method name="collide_shape">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 3a4e516d86..2b3cb6b56c 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -911,7 +911,7 @@
</member>
<member name="physics/2d/physics_engine" type="String" setter="" getter="" default="&quot;DEFAULT&quot;">
Sets which physics engine to use for 2D physics.
- "DEFAULT" and "GodotPhysics" are the same, as there is currently no alternative 2D physics server implemented.
+ "DEFAULT" and "GodotPhysics2D" are the same, as there is currently no alternative 2D physics server implemented.
</member>
<member name="physics/2d/sleep_threshold_angular" type="float" setter="" getter="" default="0.139626">
Threshold angular velocity under which a 2D physics body will be considered inactive. See [constant PhysicsServer2D.SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD].
@@ -953,7 +953,7 @@
</member>
<member name="physics/3d/physics_engine" type="String" setter="" getter="" default="&quot;DEFAULT&quot;">
Sets which physics engine to use for 3D physics.
- "DEFAULT" is currently the [url=https://bulletphysics.org]Bullet[/url] physics engine. The "GodotPhysics" engine is still supported as an alternative.
+ "DEFAULT" is currently the [url=https://bulletphysics.org]Bullet[/url] physics engine. The "GodotPhysics3D" engine is still supported as an alternative.
</member>
<member name="physics/common/enable_object_picking" type="bool" setter="" getter="" default="true">
Enables [member Viewport.physics_object_picking] on the root viewport.
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 1db1142aa0..5b7694b775 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -43,7 +43,7 @@
<argument index="1" name="y" type="int">
</argument>
<description>
- Returns the coordinate of the autotile variation in the tileset. Returns a zero vector if the cell doesn't have autotiling.
+ Returns the coordinate (subtile column and row) of the autotile variation in the tileset. Returns a zero vector if the cell doesn't have autotiling.
</description>
</method>
<method name="get_cellv" qualifiers="const">
@@ -161,7 +161,7 @@
<description>
Sets the tile index for the cell given by a Vector2.
An index of [code]-1[/code] clears the cell.
- Optionally, the tile can also be flipped, transposed, or given autotile coordinates.
+ Optionally, the tile can also be flipped, transposed, or given autotile coordinates. The autotile coordinate refers to the column and row of the subtile.
[b]Note:[/b] Data such as navigation polygons and collision shapes are not immediately updated for performance reasons.
If you need these to be immediately updated, you can call [method update_dirty_quadrants].
Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed:
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 766ebf7e32..2cc3e974e2 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -155,7 +155,7 @@
Returns [code]true[/code] if an "undo" action is available.
</description>
</method>
- <method name="is_commiting_action" qualifiers="const">
+ <method name="is_committing_action" qualifiers="const">
<return type="bool">
</return>
<description>
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index 9de5eac31d..c6c6cae6c0 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -424,7 +424,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value
if property_def.overridden:
- ml.append((type_rst, property_def.name, "**O:** " + default))
+ ml.append((type_rst, property_def.name, default + " *(parent override)*"))
else:
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
ml.append((type_rst, ref, default))
diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub
index 35c2d61530..91d0e42f80 100644
--- a/drivers/vulkan/SCsub
+++ b/drivers/vulkan/SCsub
@@ -14,6 +14,14 @@ if env["platform"] == "android":
thirdparty_dir + "/layers/generated",
]
env.Prepend(CPPPATH=thirdparty_includes)
+
+ # Build Vulkan memory allocator
+ env_thirdparty = env.Clone()
+ env_thirdparty.disable_warnings()
+
+ thirdparty_dir = "#thirdparty/vulkan"
+ vma_sources = [thirdparty_dir + "/android/vk_mem_alloc.cpp"]
+ env_thirdparty.add_source_files(env.drivers_sources, vma_sources)
elif env["builtin_vulkan"]:
# Use bundled Vulkan headers
thirdparty_dir = "#thirdparty/vulkan"
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 09f10ef8b1..96d6f99f6f 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -6935,9 +6935,42 @@ uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const {
return frames[frame].index;
}
+static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
+ uint64_t u1 = (u & 0xffffffff);
+ uint64_t v1 = (v & 0xffffffff);
+ uint64_t t = (u1 * v1);
+ uint64_t w3 = (t & 0xffffffff);
+ uint64_t k = (t >> 32);
+
+ u >>= 32;
+ t = (u * v1) + k;
+ k = (t & 0xffffffff);
+ uint64_t w1 = (t >> 32);
+
+ v >>= 32;
+ t = (u1 * v) + k;
+ k = (t >> 32);
+
+ h = (u * v) + w1 + k;
+ l = (t << 32) + w3;
+}
+
uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
- return frames[frame].timestamp_result_values[p_index] * limits.timestampPeriod;
+
+ // this sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs.
+ // so, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible
+ // need to do 128 bits fixed point multiplication to get the rigth value
+
+ uint64_t shift_bits = 16;
+
+ uint64_t h, l;
+
+ mult64to128(frames[frame].timestamp_result_values[p_index], uint64_t(double(limits.timestampPeriod) * double(1 << shift_bits)), h, l);
+ l >>= shift_bits;
+ l |= h << (64 - shift_bits);
+
+ return l;
}
uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index b393ff5fd4..f10e439f10 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1402,7 +1402,7 @@ void AnimationTimelineEdit::_zoom_changed(double) {
float AnimationTimelineEdit::get_zoom_scale() const {
- float zv = zoom->get_value();
+ float zv = zoom->get_max() - zoom->get_value();
if (zv < 1) {
zv = 1.0 - zv;
return Math::pow(1.0f + zv, 8.0f) * 100;
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 37bca661dd..576ee436de 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -961,12 +961,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("grabber", "HSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons"));
theme->set_stylebox("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2));
theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
+ theme->set_stylebox("grabber_area_highlight", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
// VSlider
theme->set_icon("grabber", "VSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons"));
theme->set_icon("grabber_highlight", "VSlider", theme->get_icon("GuiSliderGrabberHl", "EditorIcons"));
theme->set_stylebox("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0));
theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
+ theme->set_stylebox("grabber_area_highlight", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
//RichTextLabel
theme->set_color("default_color", "RichTextLabel", font_color);
diff --git a/editor/icons/AcceptDialog.svg b/editor/icons/AcceptDialog.svg
index e0bf7b8336..07e54d722f 100644
--- a/editor/icons/AcceptDialog.svg
+++ b/editor/icons/AcceptDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm9.4746 1.6367 1.4141 1.4141-4.9492 4.9492-2.8281-2.8281 1.4141-1.4141 1.4141 1.4141z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm9.4746 1.6367 1.4141 1.4141-4.9492 4.9492-2.8281-2.8281 1.4141-1.4141 1.4141 1.4141z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/ConfirmationDialog.svg b/editor/icons/ConfirmationDialog.svg
index d1f13fbb3b..2d6e45b51f 100644
--- a/editor/icons/ConfirmationDialog.svg
+++ b/editor/icons/ConfirmationDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6.9863 1.002c.34689-.0022844.6986.055762 1.0391.17969 1.3618.4956 2.1813 1.9126 1.9297 3.3398-.19105 1.0835-.96172 1.9461-1.9551 2.3008v.17773h-1-1v-.8418a1.0001 1.0001 0 0 1 1-1.1582c.49193 0 .89895-.34177.98438-.82617.085424-.4845-.18031-.94508-.64258-1.1133-.46227-.1683-.96106.013453-1.207.43945a1.0002 1.0002 0 0 1 -1.7324-1c.54346-.94148 1.5433-1.4912 2.584-1.498zm-.98633 6.998h2v1h-2z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6.9863 1.002c.34689-.0022844.6986.055762 1.0391.17969 1.3618.4956 2.1813 1.9126 1.9297 3.3398-.19105 1.0835-.96172 1.9461-1.9551 2.3008v.17773h-1-1v-.8418a1.0001 1.0001 0 0 1 1-1.1582c.49193 0 .89895-.34177.98438-.82617.085424-.4845-.18031-.94508-.64258-1.1133-.46227-.1683-.96106.013453-1.207.43945a1.0002 1.0002 0 0 1 -1.7324-1c.54346-.94148 1.5433-1.4912 2.584-1.498zm-.98633 6.998h2v1h-2z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/PopupDialog.svg b/editor/icons/EditorFileDialog.svg
index d871e56a63..95906234ab 100644
--- a/editor/icons/PopupDialog.svg
+++ b/editor/icons/EditorFileDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6 1h2v5h-2zm0 6h2v2h-2z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/FileDialog.svg b/editor/icons/FileDialog.svg
index 7708659c21..95906234ab 100644
--- a/editor/icons/FileDialog.svg
+++ b/editor/icons/FileDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/Popup.svg b/editor/icons/Popup.svg
index 93f7e5000d..a497b7a7fc 100644
--- a/editor/icons/Popup.svg
+++ b/editor/icons/Popup.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/PopupMenu.svg b/editor/icons/PopupMenu.svg
index dd7b2bb0fd..ebf62208e0 100644
--- a/editor/icons/PopupMenu.svg
+++ b/editor/icons/PopupMenu.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7a1 1 0 0 0 -1-1zm1 2h10v2h-10zm0 3h10v2h-10z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7a1 1 0 0 0 -1-1zm1 2h10v2h-10zm0 3h10v2h-10z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/PopupPanel.svg b/editor/icons/PopupPanel.svg
index 47a5448f5b..b45a3c9c3c 100644
--- a/editor/icons/PopupPanel.svg
+++ b/editor/icons/PopupPanel.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4c-.55228 0-1 .44772-1 1v7c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-7c0-.55228-.44772-1-1-1z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4c-.55228 0-1 .44772-1 1v7c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-7c0-.55228-.44772-1-1-1z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/ScriptCreateDialog.svg b/editor/icons/ScriptCreateDialog.svg
index 751b799ba9..78a69c5e59 100644
--- a/editor/icons/ScriptCreateDialog.svg
+++ b/editor/icons/ScriptCreateDialog.svg
@@ -1 +1 @@
-<svg height="17.067" viewBox="0 0 16 16" width="17.067" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m6 1v1c-.55228 0-1 .44772-1 1v10h-1v-2h-2v2c.0002826.35698.19084.68674.5.86523.15194.088045.32439.13452.5.13477v1h6v-5l3-2v-3h3v-2c0-1.1046-.89543-2-2-2z" fill="#a5efac" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-3v3c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v3h5v-1h-4v-2c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#87e29f" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0" r="0"/><g fill="#87e29f"><ellipse cx="12" cy="1048.4" rx=".5" ry="3"/><ellipse cx="913.91" cy="513.79" rx=".5" ry="3" transform="matrix(.5 .8660254 -.8660254 .5 0 0)"/><ellipse cx="901.91" cy="-534.57" rx=".5" ry="3" transform="matrix(-.5 .8660254 -.8660254 -.5 0 0)"/></g></g></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm5.5722656 1h3.9980464a1.1426143 1.1426143 0 0 1 1.142579 1.1425781v1.1425781h-1.712891-2.2851562v-.5703124-.5722657c0-.6310659-.5115295-1.1425781-1.1425782-1.1425781zm0 .5722656c.3155215 0 .5703125.254791.5703125.5703125v.5722657.5703124.5722657h.5722657 2.2851562v3.9980471a1.1426143 1.1426143 0 0 1 -1.1425781 1.142578h-4c.6310487 0 1.1425781-.511529 1.1425781-1.142578v-5.7128909c0-.0785019.01823-.1545692.046875-.2226562v-.0019531c.02868-.0672829.0683226-.1266374.1191406-.1777344.00097-.00096.0029352-.0010048.0039063-.0019532.0513303-.0508898.1121075-.0944618.1796875-.1230468.0683505-.028909.1437752-.0429688.2226562-.0429688zm-2.2851562 5.1406254h1.1425781v1.142578c0 .315522-.2567441.572265-.5722656.572265-.0776611 0-.15125-.016852-.21875-.044922-.00206-.000799-.0038594-.003049-.0058594-.003906-.0656506-.028192-.1236101-.067817-.1738281-.117187a.57130715.57130715 0 0 1 -.0097656-.009766c-.0490902-.050487-.0893425-.107988-.1171876-.173828-.028908-.06835-.0449218-.143776-.0449218-.222656z"/><circle cx="-23.915255" cy="3.118624" r="0"/></g></svg> \ No newline at end of file
diff --git a/editor/icons/WindowDialog.svg b/editor/icons/Window.svg
index 3c7be2a58d..a02a86d56a 100644
--- a/editor/icons/WindowDialog.svg
+++ b/editor/icons/Window.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/ARVRAnchor.svg b/editor/icons/XRAnchor3D.svg
index f1571b3fcc..f1571b3fcc 100644
--- a/editor/icons/ARVRAnchor.svg
+++ b/editor/icons/XRAnchor3D.svg
diff --git a/editor/icons/ARVRCamera.svg b/editor/icons/XRCamera3D.svg
index f59a8c8b4a..f59a8c8b4a 100644
--- a/editor/icons/ARVRCamera.svg
+++ b/editor/icons/XRCamera3D.svg
diff --git a/editor/icons/ARVRController.svg b/editor/icons/XRController3D.svg
index 40e5b8dce1..40e5b8dce1 100644
--- a/editor/icons/ARVRController.svg
+++ b/editor/icons/XRController3D.svg
diff --git a/editor/icons/ARVROrigin.svg b/editor/icons/XROrigin3D.svg
index dbb93ba7a5..dbb93ba7a5 100644
--- a/editor/icons/ARVROrigin.svg
+++ b/editor/icons/XROrigin3D.svg
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 00e8a05e4e..eb14495b9c 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -95,6 +95,7 @@ void MaterialEditor::_button_pressed(Node *p_button) {
sphere_instance->hide();
box_switch->set_pressed(true);
sphere_switch->set_pressed(false);
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false);
}
if (p_button == sphere_switch) {
@@ -102,6 +103,7 @@ void MaterialEditor::_button_pressed(Node *p_button) {
sphere_instance->show();
box_switch->set_pressed(false);
sphere_switch->set_pressed(true);
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true);
}
}
@@ -155,7 +157,6 @@ MaterialEditor::MaterialEditor() {
sphere_instance->set_mesh(sphere_mesh);
box_mesh.instance();
box_instance->set_mesh(box_mesh);
- box_instance->hide();
set_custom_minimum_size(Size2(1, 150) * EDSCALE);
@@ -194,6 +195,15 @@ MaterialEditor::MaterialEditor() {
light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed), varray(light_2_switch));
first_enter = true;
+
+ if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
+ box_instance->hide();
+ } else {
+ box_instance->show();
+ sphere_instance->hide();
+ box_switch->set_pressed(true);
+ sphere_switch->set_pressed(false);
+ }
}
///////////////////////
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 1c16ed6b58..7ba38036ac 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -347,7 +347,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
if (orthogonal) {
float half_fov = Math::deg2rad(get_fov()) / 2.0;
float height = 2.0 * cursor.distance * Math::tan(half_fov);
- camera->set_orthogonal(height, 0.1, 8192);
+ camera->set_orthogonal(height, get_znear(), get_zfar());
} else {
camera->set_perspective(get_fov(), get_znear(), get_zfar());
}
@@ -364,7 +364,7 @@ Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) cons
camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot);
if (orthogonal)
- camera_transform.translate(0, 0, 4096);
+ camera_transform.translate(0, 0, (get_zfar() - get_znear()) / 2.0);
else
camera_transform.translate(0, 0, p_cursor.distance);
@@ -2482,7 +2482,9 @@ void Node3DEditorViewport::_notification(int p_what) {
viewport->set_msaa(Viewport::MSAA(msaa_mode));
bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
- info_label->set_visible(show_info);
+ if (show_info != info_label->is_visible()) {
+ info_label->set_visible(show_info);
+ }
Camera3D *current_camera;
@@ -2509,17 +2511,46 @@ void Node3DEditorViewport::_notification(int p_what) {
text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n";
text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n";
text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME));
+
info_label->set_text(text);
}
// FPS Counter.
- bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
- fps_label->set_visible(show_fps);
-
+ bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
+
+ if (show_fps != fps_label->is_visible()) {
+ fps_label->set_visible(show_fps);
+ RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps);
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ cpu_time_history[i] = 0;
+ gpu_time_history[i] = 0;
+ }
+ cpu_time_history_index = 0;
+ cpu_time_history_index = 0;
+ }
if (show_fps) {
+
+ cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid());
+ cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY;
+ float cpu_time = 0.0;
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ cpu_time += cpu_time_history[i];
+ }
+ cpu_time /= FRAME_TIME_HISTORY;
+
+ gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid());
+ gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY;
+ float gpu_time = 0.0;
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ gpu_time += gpu_time_history[i];
+ }
+ gpu_time /= FRAME_TIME_HISTORY;
+
String text;
- const float temp_fps = Engine::get_singleton()->get_frames_per_second();
- text += TTR(vformat("FPS: %d (%s ms)", temp_fps, String::num(1000.0f / temp_fps, 2)));
+ text += TTR("CPU Time") + ": " + String::num(cpu_time, 1) + " ms\n";
+ text += TTR("GPU Time") + ": " + String::num(gpu_time, 1) + " ms\n";
+ text += TTR("FPS") + ": " + itos(1000.0 / gpu_time);
+
fps_label->set_text(text);
}
@@ -2980,9 +3011,9 @@ void Node3DEditorViewport::_menu_option(int p_option) {
view_menu->get_popup()->set_item_checked(idx, !current);
} break;
- case VIEW_FPS: {
+ case VIEW_FRAME_TIME: {
- int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
+ int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME);
bool current = view_menu->get_popup()->is_item_checked(idx);
view_menu->get_popup()->set_item_checked(idx, !current);
@@ -3338,12 +3369,12 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) {
if (view_menu->get_popup()->is_item_checked(idx) != information)
_menu_option(VIEW_INFORMATION);
}
- if (p_state.has("fps")) {
- bool fps = p_state["fps"];
+ if (p_state.has("frame_time")) {
+ bool fps = p_state["frame_time"];
- int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
+ int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME);
if (view_menu->get_popup()->is_item_checked(idx) != fps)
- _menu_option(VIEW_FPS);
+ _menu_option(VIEW_FRAME_TIME);
}
if (p_state.has("half_res")) {
bool half_res = p_state["half_res"];
@@ -3400,7 +3431,7 @@ Dictionary Node3DEditorViewport::get_state() const {
d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
- d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
+ d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
d["half_res"] = subviewport_container->get_stretch_shrink() > 1;
d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
if (previewing)
@@ -3812,6 +3843,9 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
+ cpu_time_history_index = 0;
+ cpu_time_history_index = 0;
+
_edit.mode = TRANSFORM_NONE;
_edit.plane = TRANSFORM_VIEW;
_edit.edited_gizmo = 0;
@@ -3912,7 +3946,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS);
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View Frame Time")), VIEW_FRAME_TIME);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
@@ -3989,7 +4023,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
- fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance."));
+ fps_label->set_tooltip(TTR("Note: The FPS is estimated on a 60hz refresh rate."));
fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show.
surface->add_child(fps_label);
fps_label->hide();
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index bb83e7f626..5f0ba1921b 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -202,7 +202,7 @@ class Node3DEditorViewport : public Control {
VIEW_AUDIO_DOPPLER,
VIEW_GIZMOS,
VIEW_INFORMATION,
- VIEW_FPS,
+ VIEW_FRAME_TIME,
VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME,
VIEW_DISPLAY_OVERDRAW,
@@ -229,7 +229,9 @@ public:
enum {
GIZMO_BASE_LAYER = 27,
GIZMO_EDIT_LAYER = 26,
- GIZMO_GRID_LAYER = 25
+ GIZMO_GRID_LAYER = 25,
+
+ FRAME_TIME_HISTORY = 20,
};
enum NavigationScheme {
@@ -239,6 +241,11 @@ public:
};
private:
+ float cpu_time_history[FRAME_TIME_HISTORY];
+ int cpu_time_history_index;
+ float gpu_time_history[FRAME_TIME_HISTORY];
+ int gpu_time_history_index;
+
int index;
String name;
void _menu_option(int p_option);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 82199fc1f1..12b21d871b 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -689,6 +689,8 @@ void ScriptCreateDialog::_update_dialog() {
// Is Script created or loaded from existing file?
+ builtin_warning_label->set_visible(is_built_in);
+
if (is_built_in) {
get_ok()->set_text(TTR("Create"));
parent_name->set_editable(true);
@@ -756,6 +758,13 @@ ScriptCreateDialog::ScriptCreateDialog() {
path_error_label = memnew(Label);
vb->add_child(path_error_label);
+ builtin_warning_label = memnew(Label);
+ builtin_warning_label->set_text(
+ TTR("Note: Built-in scripts have some limitations and can't be edited using an external editor."));
+ vb->add_child(builtin_warning_label);
+ builtin_warning_label->set_autowrap(true);
+ builtin_warning_label->hide();
+
status_panel = memnew(PanelContainer);
status_panel->set_h_size_flags(Control::SIZE_FILL);
status_panel->add_child(vb);
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index f164cd2a15..63a30eba88 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -49,6 +49,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
LineEdit *class_name;
Label *error_label;
Label *path_error_label;
+ Label *builtin_warning_label;
PanelContainer *status_panel;
LineEdit *parent_name;
Button *parent_browse_button;
diff --git a/main/main.cpp b/main/main.cpp
index 92f40588f2..fb42f71a75 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -478,6 +478,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
I = args.front();
while (I) {
+#ifdef OSX_ENABLED
+ // Ignore the process serial number argument passed by macOS Gatekeeper.
+ // Otherwise, Godot would try to open a non-existent project on the first start and abort.
+ if (I->get().begins_with("-psn_")) {
+ I = I->next();
+ continue;
+ }
+#endif
List<String>::Element *N = I->next();
diff --git a/misc/travis/android-tools-linux.sh b/misc/travis/android-tools-linux.sh
index d0c123ee6c..4eeb54412c 100755
--- a/misc/travis/android-tools-linux.sh
+++ b/misc/travis/android-tools-linux.sh
@@ -24,12 +24,12 @@ ANDROID_SDK_URL=$ANDROID_BASE_URL/$ANDROID_SDK_FILENAME
ANDROID_SDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_SDK_DIR
ANDROID_SDK_SHA256=92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9
-ANDROID_NDK_RELEASE=r20
+ANDROID_NDK_RELEASE=r21
ANDROID_NDK_DIR=android-ndk
ANDROID_NDK_FILENAME=android-ndk-$ANDROID_NDK_RELEASE-linux-x86_64.zip
ANDROID_NDK_URL=$ANDROID_BASE_URL/$ANDROID_NDK_FILENAME
ANDROID_NDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_NDK_DIR
-ANDROID_NDK_SHA1=8665fc84a1b1f0d6ab3b5fdd1e30200cc7b9adff
+ANDROID_NDK_SHA1=afc9c0b9faad222898ac8168c78ad4ccac8a1b5c
echo
echo "Download and install Android development tools ..."
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index 1b131c8cf0..dcf2ddb9ca 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -54,7 +54,6 @@ typedef enum {
GODOT_PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
GODOT_PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease)
GODOT_PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
- GODOT_PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat
GODOT_PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
GODOT_PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
GODOT_PROPERTY_HINT_LAYERS_2D_RENDER,
@@ -96,8 +95,6 @@ typedef enum {
GODOT_PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings
GODOT_PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor
GODOT_PROPERTY_USAGE_CATEGORY = 256,
- GODOT_PROPERTY_USAGE_STORE_IF_NONZERO = 512, // FIXME: Obsolete: drop whenever we can break compat
- GODOT_PROPERTY_USAGE_STORE_IF_NONONE = 1024, // FIXME: Obsolete: drop whenever we can break compat
GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE = 2048,
GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED = 4096,
GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE = 8192,
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a99d4b96f7..8d34ce5c70 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -7364,6 +7364,8 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
}
}
+#define IS_USAGE_MEMBER(m_usage) (!(m_usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)))
+
// Check other script types
while (scr.is_valid()) {
Map<StringName, Variant> constants;
@@ -7376,7 +7378,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
List<PropertyInfo> properties;
scr->get_script_property_list(&properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().name == p_member) {
+ if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) {
r_member_type = _type_from_property(E->get());
return true;
}
@@ -7418,7 +7420,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
List<PropertyInfo> properties;
ClassDB::get_property_list(native, &properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().name == p_member) {
+ if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) {
// Check if a getter exists
StringName getter_name = ClassDB::get_property_getter(native, p_member);
if (getter_name != StringName()) {
@@ -7458,7 +7460,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
List<PropertyInfo> properties;
ClassDB::get_property_list(native, &properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().name == p_member) {
+ if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) {
// Check if a getter exists
StringName getter_name = ClassDB::get_property_getter(native, p_member);
if (getter_name != StringName()) {
@@ -7480,6 +7482,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
}
}
}
+#undef IS_USAGE_MEMBER
return false;
}
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp
index ec67030a65..2018f90e9f 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -137,14 +137,19 @@ void NoiseTexture::_queue_update() {
Ref<Image> NoiseTexture::_generate_texture() {
- if (noise.is_null()) return Ref<Image>();
+ // Prevent memdelete due to unref() on other thread.
+ Ref<OpenSimplexNoise> ref_noise = noise;
+
+ if (ref_noise.is_null()) {
+ return Ref<Image>();
+ }
Ref<Image> image;
if (seamless) {
- image = noise->get_seamless_image(size.x);
+ image = ref_noise->get_seamless_image(size.x);
} else {
- image = noise->get_image(size.x, size.y);
+ image = ref_noise->get_image(size.x, size.y);
}
if (as_normalmap) {
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index ab528fac30..ea60b6222e 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -350,8 +350,11 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::STRING: color = Color(0.42, 0.65, 0.93); break;
case Variant::VECTOR2: color = Color(0.74, 0.57, 0.95); break;
+ case Variant::VECTOR2I: color = Color(0.74, 0.57, 0.95); break;
case Variant::RECT2: color = Color(0.95, 0.57, 0.65); break;
+ case Variant::RECT2I: color = Color(0.95, 0.57, 0.65); break;
case Variant::VECTOR3: color = Color(0.84, 0.49, 0.93); break;
+ case Variant::VECTOR3I: color = Color(0.84, 0.49, 0.93); break;
case Variant::TRANSFORM2D: color = Color(0.77, 0.93, 0.41); break;
case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break;
case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break;
@@ -389,8 +392,11 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::STRING: color = Color(0.27, 0.56, 0.91); break;
case Variant::VECTOR2: color = Color(0.68, 0.46, 0.93); break;
+ case Variant::VECTOR2I: color = Color(0.68, 0.46, 0.93); break;
case Variant::RECT2: color = Color(0.93, 0.46, 0.56); break;
+ case Variant::RECT2I: color = Color(0.93, 0.46, 0.56); break;
case Variant::VECTOR3: color = Color(0.86, 0.42, 0.93); break;
+ case Variant::VECTOR3I: color = Color(0.86, 0.42, 0.93); break;
case Variant::TRANSFORM2D: color = Color(0.59, 0.81, 0.1); break;
case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break;
case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break;
@@ -510,8 +516,11 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
Control::get_theme_icon("float", "EditorIcons"),
Control::get_theme_icon("String", "EditorIcons"),
Control::get_theme_icon("Vector2", "EditorIcons"),
+ Control::get_theme_icon("Vector2i", "EditorIcons"),
Control::get_theme_icon("Rect2", "EditorIcons"),
+ Control::get_theme_icon("Rect2i", "EditorIcons"),
Control::get_theme_icon("Vector3", "EditorIcons"),
+ Control::get_theme_icon("Vector3i", "EditorIcons"),
Control::get_theme_icon("Transform2D", "EditorIcons"),
Control::get_theme_icon("Plane", "EditorIcons"),
Control::get_theme_icon("Quat", "EditorIcons"),
@@ -522,6 +531,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
Control::get_theme_icon("NodePath", "EditorIcons"),
Control::get_theme_icon("RID", "EditorIcons"),
Control::get_theme_icon("MiniObject", "EditorIcons"),
+ Control::get_theme_icon("Callable", "EditorIcons"),
+ Control::get_theme_icon("Signal", "EditorIcons"),
Control::get_theme_icon("Dictionary", "EditorIcons"),
Control::get_theme_icon("Array", "EditorIcons"),
Control::get_theme_icon("PackedByteArray", "EditorIcons"),
@@ -974,8 +985,11 @@ void VisualScriptEditor::_update_members() {
Control::get_theme_icon("float", "EditorIcons"),
Control::get_theme_icon("String", "EditorIcons"),
Control::get_theme_icon("Vector2", "EditorIcons"),
+ Control::get_theme_icon("Vector2i", "EditorIcons"),
Control::get_theme_icon("Rect2", "EditorIcons"),
+ Control::get_theme_icon("Rect2i", "EditorIcons"),
Control::get_theme_icon("Vector3", "EditorIcons"),
+ Control::get_theme_icon("Vector3i", "EditorIcons"),
Control::get_theme_icon("Transform2D", "EditorIcons"),
Control::get_theme_icon("Plane", "EditorIcons"),
Control::get_theme_icon("Quat", "EditorIcons"),
@@ -986,6 +1000,8 @@ void VisualScriptEditor::_update_members() {
Control::get_theme_icon("NodePath", "EditorIcons"),
Control::get_theme_icon("RID", "EditorIcons"),
Control::get_theme_icon("MiniObject", "EditorIcons"),
+ Control::get_theme_icon("Callable", "EditorIcons"),
+ Control::get_theme_icon("Signal", "EditorIcons"),
Control::get_theme_icon("Dictionary", "EditorIcons"),
Control::get_theme_icon("Array", "EditorIcons"),
Control::get_theme_icon("PackedByteArray", "EditorIcons"),
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 97c2686cd5..c860e08943 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -4184,9 +4184,12 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2), create_node_deconst_typed<Variant::Type::VECTOR2>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2I), create_node_deconst_typed<Variant::Type::VECTOR2I>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3), create_node_deconst_typed<Variant::Type::VECTOR3>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3I), create_node_deconst_typed<Variant::Type::VECTOR3I>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::COLOR), create_node_deconst_typed<Variant::Type::COLOR>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2), create_node_deconst_typed<Variant::Type::RECT2>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUAT), create_node_deconst_typed<Variant::Type::QUAT>);
diff --git a/platform/android/api/api.cpp b/platform/android/api/api.cpp
index ef11b12971..4fe868d4f0 100644
--- a/platform/android/api/api.cpp
+++ b/platform/android/api/api.cpp
@@ -32,6 +32,7 @@
#include "core/engine.h"
#include "java_class_wrapper.h"
+#include "jni_singleton.h"
#if !defined(ANDROID_ENABLED)
static JavaClassWrapper *java_class_wrapper = nullptr;
@@ -40,7 +41,11 @@ static JavaClassWrapper *java_class_wrapper = nullptr;
void register_android_api() {
#if !defined(ANDROID_ENABLED)
+ // On Android platforms, the `java_class_wrapper` instantiation and the
+ // `JNISingleton` registration occurs in
+ // `platform/android/java_godot_lib_jni.cpp#Java_org_godotengine_godot_GodotLib_setup`
java_class_wrapper = memnew(JavaClassWrapper); // Dummy
+ ClassDB::register_class<JNISingleton>();
#endif
ClassDB::register_class<JavaClass>();
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
new file mode 100644
index 0000000000..917c3f5029
--- /dev/null
+++ b/platform/android/api/jni_singleton.h
@@ -0,0 +1,242 @@
+/*************************************************************************/
+/* jni_singleton.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef JNI_SINGLETON_H
+#define JNI_SINGLETON_H
+
+#include <core/engine.h>
+#include <core/variant.h>
+#ifdef ANDROID_ENABLED
+#include <platform/android/jni_utils.h>
+#endif
+
+class JNISingleton : public Object {
+
+ GDCLASS(JNISingleton, Object);
+
+#ifdef ANDROID_ENABLED
+ struct MethodData {
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName, MethodData> method_map;
+#endif
+
+public:
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+#ifdef ANDROID_ENABLED
+ Map<StringName, MethodData>::Element *E = method_map.find(p_method);
+
+ // Check the method we're looking for is in the JNISingleton map and that
+ // the arguments match.
+ bool call_error = !E || E->get().argtypes.size() != p_argcount;
+ if (!call_error) {
+ for (int i = 0; i < p_argcount; i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
+ call_error = true;
+ break;
+ }
+ }
+ }
+
+ if (call_error) {
+ // The method is not in this map, defaulting to the regular instance calls.
+ return Object::call(p_method, p_args, p_argcount, r_error);
+ }
+
+ ERR_FAIL_COND_V(!instance, Variant());
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ jvalue *v = nullptr;
+
+ if (p_argcount) {
+
+ v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
+ }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ int res = env->PushLocalFrame(16);
+
+ ERR_FAIL_COND_V(res != 0, Variant());
+
+ List<jobject> to_erase;
+ for (int i = 0; i < p_argcount; i++) {
+
+ jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ v[i] = vr.val;
+ if (vr.obj)
+ to_erase.push_back(vr.obj);
+ }
+
+ Variant ret;
+
+ switch (E->get().ret_type) {
+
+ case Variant::NIL: {
+
+ env->CallVoidMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::FLOAT: {
+
+ ret = env->CallFloatMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = jstring_to_string((jstring)o, env);
+ env->DeleteLocalRef(o);
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ ret = _jobject_to_variant(env, arr);
+
+ env->DeleteLocalRef(arr);
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<int> sarr;
+ sarr.resize(fCount);
+
+ int *w = sarr.ptrw();
+ env->GetIntArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<float> sarr;
+ sarr.resize(fCount);
+
+ float *w = sarr.ptrw();
+ env->GetFloatArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
+
+#ifndef _MSC_VER
+#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
+#endif
+ case Variant::DICTIONARY: {
+
+ jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = _jobject_to_variant(env, obj);
+ env->DeleteLocalRef(obj);
+
+ } break;
+ default: {
+
+ env->PopLocalFrame(nullptr);
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ while (to_erase.size()) {
+ env->DeleteLocalRef(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ env->PopLocalFrame(nullptr);
+
+ return ret;
+#else // ANDROID_ENABLED
+
+ // Defaulting to the regular instance calls.
+ return Object::call(p_method, p_args, p_argcount, r_error);
+#endif
+ }
+
+#ifdef ANDROID_ENABLED
+ jobject get_instance() const {
+
+ return instance;
+ }
+
+ void set_instance(jobject p_instance) {
+
+ instance = p_instance;
+ }
+
+ void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method = p_method;
+ md.argtypes = p_args;
+ md.ret_type = p_ret_type;
+ method_map[p_name] = md;
+ }
+
+ void add_signal(const StringName &p_name, const Vector<Variant::Type> &p_args) {
+ if (p_args.size() == 0)
+ ADD_SIGNAL(MethodInfo(p_name));
+ else if (p_args.size() == 1)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1")));
+ else if (p_args.size() == 2)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2")));
+ else if (p_args.size() == 3)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3")));
+ else if (p_args.size() == 4)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4")));
+ else if (p_args.size() == 5)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4"), PropertyInfo(p_args[4], "arg5")));
+ }
+
+#endif
+
+ JNISingleton() {
+#ifdef ANDROID_ENABLED
+ instance = nullptr;
+#endif
+ }
+};
+
+#endif // JNI_SINGLETON_H
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 1a3bb77670..99080eeb3c 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -56,6 +56,11 @@ android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+
defaultConfig {
// Feel free to modify the application id to your own.
applicationId getExportPackageName()
diff --git a/platform/android/java/app/settings.gradle b/platform/android/java/app/settings.gradle
new file mode 100644
index 0000000000..33b863c7bf
--- /dev/null
+++ b/platform/android/java/app/settings.gradle
@@ -0,0 +1,2 @@
+// Empty settings.gradle file to denote this directory as being the root project
+// of the Godot custom build.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index e3683704e1..a051164d15 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -34,6 +34,8 @@ import android.app.Activity;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
import android.view.Surface;
import android.view.View;
import java.lang.reflect.Method;
@@ -41,8 +43,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import org.godotengine.godot.BuildConfig;
import org.godotengine.godot.Godot;
/**
@@ -70,7 +74,10 @@ import org.godotengine.godot.Godot;
*/
public abstract class GodotPlugin {
+ private static final String TAG = GodotPlugin.class.getSimpleName();
+
private final Godot godot;
+ private final ConcurrentHashMap<String, SignalInfo> registeredSignals = new ConcurrentHashMap<>();
public GodotPlugin(Godot godot) {
this.godot = godot;
@@ -118,6 +125,13 @@ public abstract class GodotPlugin {
nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt);
}
+ // Register the signals for this plugin.
+ for (SignalInfo signalInfo : getPluginSignals()) {
+ String signalName = signalInfo.getName();
+ nativeRegisterSignal(getPluginName(), signalName, signalInfo.getParamTypesNames());
+ registeredSignals.put(signalName, signalInfo);
+ }
+
// Get the list of gdnative libraries to register.
Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths();
if (!gdnativeLibrariesPaths.isEmpty()) {
@@ -220,7 +234,17 @@ public abstract class GodotPlugin {
* Returns the list of methods to be exposed to Godot.
*/
@NonNull
- public abstract List<String> getPluginMethods();
+ public List<String> getPluginMethods() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns the list of signals to be exposed to Godot.
+ */
+ @NonNull
+ public Set<SignalInfo> getPluginSignals() {
+ return Collections.emptySet();
+ }
/**
* Returns the paths for the plugin's gdnative libraries.
@@ -253,6 +277,49 @@ public abstract class GodotPlugin {
}
/**
+ * Emit a registered Godot signal.
+ * @param signalName
+ * @param signalArgs
+ */
+ protected void emitSignal(final String signalName, final Object... signalArgs) {
+ try {
+ // Check that the given signal is among the registered set.
+ SignalInfo signalInfo = registeredSignals.get(signalName);
+ if (signalInfo == null) {
+ throw new IllegalArgumentException(
+ "Signal " + signalName + " is not registered for this plugin.");
+ }
+
+ // Validate the arguments count.
+ Class<?>[] signalParamTypes = signalInfo.getParamTypes();
+ if (signalArgs.length != signalParamTypes.length) {
+ throw new IllegalArgumentException(
+ "Invalid arguments count. Should be " + signalParamTypes.length + " but is " + signalArgs.length);
+ }
+
+ // Validate the argument's types.
+ for (int i = 0; i < signalParamTypes.length; i++) {
+ if (!signalParamTypes[i].isInstance(signalArgs[i])) {
+ throw new IllegalArgumentException(
+ "Invalid type for argument #" + i + ". Should be of type " + signalParamTypes[i].getName());
+ }
+ }
+
+ runOnRenderThread(new Runnable() {
+ @Override
+ public void run() {
+ nativeEmitSignal(getPluginName(), signalName, signalArgs);
+ }
+ });
+ } catch (IllegalArgumentException exception) {
+ Log.w(TAG, exception.getMessage());
+ if (BuildConfig.DEBUG) {
+ throw exception;
+ }
+ }
+ }
+
+ /**
* Used to setup a {@link GodotPlugin} instance.
* @param p_name Name of the instance.
*/
@@ -272,4 +339,20 @@ public abstract class GodotPlugin {
* @param gdnlibPaths Paths to the libraries relative to the 'assets' directory.
*/
private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
+
+ /**
+ * Used to complete registration of the {@link GodotPlugin} instance's methods.
+ * @param pluginName Name of the plugin
+ * @param signalName Name of the signal to register
+ * @param signalParamTypes Signal parameters types
+ */
+ private native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes);
+
+ /**
+ * Used to emit signal by {@link GodotPlugin} instance.
+ * @param pluginName Name of the plugin
+ * @param signalName Name of the signal to emit
+ * @param signalParams Signal parameters
+ */
+ private native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java
new file mode 100644
index 0000000000..f907706889
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java
@@ -0,0 +1,98 @@
+/*************************************************************************/
+/* SignalInfo.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.plugin;
+
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import java.util.Arrays;
+
+/**
+ * Store information about a {@link GodotPlugin}'s signal.
+ */
+public final class SignalInfo {
+
+ private final String name;
+ private final Class<?>[] paramTypes;
+ private final String[] paramTypesNames;
+
+ public SignalInfo(@NonNull String signalName, Class<?>... paramTypes) {
+ if (TextUtils.isEmpty(signalName)) {
+ throw new IllegalArgumentException("Invalid signal name: " + signalName);
+ }
+
+ this.name = signalName;
+ this.paramTypes = paramTypes == null ? new Class<?>[ 0 ] : paramTypes;
+ this.paramTypesNames = new String[this.paramTypes.length];
+ for (int i = 0; i < this.paramTypes.length; i++) {
+ this.paramTypesNames[i] = this.paramTypes[i].getName();
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ Class<?>[] getParamTypes() {
+ return paramTypes;
+ }
+
+ String[] getParamTypesNames() {
+ return paramTypesNames;
+ }
+
+ @Override
+ public String toString() {
+ return "SignalInfo{"
+ +
+ "name='" + name + '\'' +
+ ", paramsTypes=" + Arrays.toString(paramTypes) +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SignalInfo)) {
+ return false;
+ }
+
+ SignalInfo that = (SignalInfo)o;
+
+ return name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index c103e74222..8b38113e09 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -35,6 +35,7 @@
#include "android/asset_manager_jni.h"
#include "api/java_class_wrapper.h"
+#include "api/jni_singleton.h"
#include "audio_driver_jandroid.h"
#include "core/engine.h"
#include "core/input/input_filter.h"
@@ -162,6 +163,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
}
java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
+ ClassDB::register_class<JNISingleton>();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height) {
diff --git a/platform/android/jni_utils.h b/platform/android/jni_utils.h
index b9ee243308..c2baa51b4a 100644
--- a/platform/android/jni_utils.h
+++ b/platform/android/jni_utils.h
@@ -53,190 +53,4 @@ Variant::Type get_jni_type(const String &p_type);
const char *get_jni_sig(const String &p_type);
-class JNISingleton : public Object {
-
- GDCLASS(JNISingleton, Object);
-
- struct MethodData {
-
- jmethodID method;
- Variant::Type ret_type;
- Vector<Variant::Type> argtypes;
- };
-
- jobject instance;
- Map<StringName, MethodData> method_map;
-
-public:
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-
- ERR_FAIL_COND_V(!instance, Variant());
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Map<StringName, MethodData>::Element *E = method_map.find(p_method);
- if (!E) {
-
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
- int ac = E->get().argtypes.size();
- if (ac < p_argcount) {
-
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- if (ac > p_argcount) {
-
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- for (int i = 0; i < p_argcount; i++) {
-
- if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
-
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = i;
- r_error.expected = E->get().argtypes[i];
- }
- }
-
- jvalue *v = nullptr;
-
- if (p_argcount) {
-
- v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
- }
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- int res = env->PushLocalFrame(16);
-
- ERR_FAIL_COND_V(res != 0, Variant());
-
- List<jobject> to_erase;
- for (int i = 0; i < p_argcount; i++) {
-
- jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
- v[i] = vr.val;
- if (vr.obj)
- to_erase.push_back(vr.obj);
- }
-
- Variant ret;
-
- switch (E->get().ret_type) {
-
- case Variant::NIL: {
-
- env->CallVoidMethodA(instance, E->get().method, v);
- } break;
- case Variant::BOOL: {
-
- ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
- } break;
- case Variant::INT: {
-
- ret = env->CallIntMethodA(instance, E->get().method, v);
- } break;
- case Variant::FLOAT: {
-
- ret = env->CallFloatMethodA(instance, E->get().method, v);
- } break;
- case Variant::STRING: {
-
- jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- ret = jstring_to_string((jstring)o, env);
- env->DeleteLocalRef(o);
- } break;
- case Variant::PACKED_STRING_ARRAY: {
-
- jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- ret = _jobject_to_variant(env, arr);
-
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_INT32_ARRAY: {
-
- jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<int> sarr;
- sarr.resize(fCount);
-
- int *w = sarr.ptrw();
- env->GetIntArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
-
- jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<float> sarr;
- sarr.resize(fCount);
-
- float *w = sarr.ptrw();
- env->GetFloatArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
-
-#ifndef _MSC_VER
-#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
-#endif
- case Variant::DICTIONARY: {
-
- jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
- ret = _jobject_to_variant(env, obj);
- env->DeleteLocalRef(obj);
-
- } break;
- default: {
-
- env->PopLocalFrame(nullptr);
- ERR_FAIL_V(Variant());
- } break;
- }
-
- while (to_erase.size()) {
- env->DeleteLocalRef(to_erase.front()->get());
- to_erase.pop_front();
- }
-
- env->PopLocalFrame(nullptr);
-
- return ret;
- }
-
- jobject get_instance() const {
-
- return instance;
- }
- void set_instance(jobject p_instance) {
-
- instance = p_instance;
- }
-
- void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
-
- MethodData md;
- md.method = p_method;
- md.argtypes = p_args;
- md.ret_type = p_ret_type;
- method_map[p_name] = md;
- }
-
- JNISingleton() {
- instance = nullptr;
- }
-};
-
#endif // JNI_UTILS_H
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 7413236e5d..c3bfb2f2ed 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -33,6 +33,7 @@
#include <core/engine.h>
#include <core/error_macros.h>
#include <core/project_settings.h>
+#include <platform/android/api/jni_singleton.h>
#include <platform/android/jni_utils.h>
#include <platform/android/string_android.h>
@@ -43,7 +44,7 @@ extern "C" {
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name) {
String singname = jstring_to_string(name, env);
- JNISingleton *s = memnew(JNISingleton);
+ JNISingleton *s = (JNISingleton *)ClassDB::instance("JNISingleton");
s->set_instance(env->NewGlobalRef(obj));
jni_singletons[singname] = s;
@@ -86,6 +87,51 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
s->add_method(mname, mid, types, get_jni_type(retval));
}
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) {
+ String singleton_name = jstring_to_string(j_plugin_name, env);
+
+ ERR_FAIL_COND(!jni_singletons.has(singleton_name));
+
+ JNISingleton *singleton = jni_singletons.get(singleton_name);
+
+ String signal_name = jstring_to_string(j_signal_name, env);
+ Vector<Variant::Type> types;
+
+ int stringCount = env->GetArrayLength(j_signal_param_types);
+
+ for (int i = 0; i < stringCount; i++) {
+
+ jstring j_signal_param_type = (jstring)env->GetObjectArrayElement(j_signal_param_types, i);
+ const String signal_param_type = jstring_to_string(j_signal_param_type, env);
+ types.push_back(get_jni_type(signal_param_type));
+ }
+
+ singleton->add_signal(signal_name, types);
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params) {
+ String singleton_name = jstring_to_string(j_plugin_name, env);
+
+ ERR_FAIL_COND(!jni_singletons.has(singleton_name));
+
+ JNISingleton *singleton = jni_singletons.get(singleton_name);
+
+ String signal_name = jstring_to_string(j_signal_name, env);
+
+ int count = env->GetArrayLength(j_signal_params);
+ const Variant *args[count];
+
+ for (int i = 0; i < count; i++) {
+
+ jobject j_param = env->GetObjectArrayElement(j_signal_params, i);
+ Variant variant = _jobject_to_variant(env, j_param);
+ args[i] = &variant;
+ env->DeleteLocalRef(j_param);
+ };
+
+ singleton->emit_signal(signal_name, args, count);
+}
+
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths) {
int gdnlib_count = env->GetArrayLength(gdnlib_paths);
if (gdnlib_count == 0) {
diff --git a/platform/android/plugin/godot_plugin_jni.h b/platform/android/plugin/godot_plugin_jni.h
index 0d613d3bfe..80ce332e7c 100644
--- a/platform/android/plugin/godot_plugin_jni.h
+++ b/platform/android/plugin/godot_plugin_jni.h
@@ -37,6 +37,8 @@
extern "C" {
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name);
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params);
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths);
}
diff --git a/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp
index b238f849fc..5fb7a83da4 100644
--- a/platform/android/vulkan/vulkan_context_android.cpp
+++ b/platform/android/vulkan/vulkan_context_android.cpp
@@ -31,14 +31,6 @@
#include "vulkan_context_android.h"
#include <vulkan/vulkan_android.h>
-#define VMA_IMPLEMENTATION
-#ifdef DEBUG_ENABLED
-#ifndef _DEBUG
-#define _DEBUG
-#endif
-#endif
-#include <vk_mem_alloc.h>
-
const char *VulkanContextAndroid::_get_platform_surface_extension() const {
return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
}
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 47497eb95f..6049dbf4d6 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -254,10 +254,10 @@ bool DisplayServerX11::_refresh_device_info() {
bool absolute_mode = false;
int resolution_x = 0;
int resolution_y = 0;
- int range_min_x = 0;
- int range_min_y = 0;
- int range_max_x = 0;
- int range_max_y = 0;
+ double range_min_x = 0;
+ double range_min_y = 0;
+ double range_max_x = 0;
+ double range_max_y = 0;
int pressure_resolution = 0;
int tilt_resolution_x = 0;
int tilt_resolution_y = 0;
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index c822b70a4b..2455d46e43 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -216,6 +216,14 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &property) const {
+
+ if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") {
+ property.usage = 0;
+ }
+
+ if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
+ property.usage = 0;
+ }
}
void Light3D::_bind_methods() {
@@ -251,6 +259,8 @@ void Light3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,64,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode");
@@ -315,6 +325,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_INDIRECT_ENERGY, 1);
set_param(PARAM_SPECULAR, 0.5);
set_param(PARAM_RANGE, 5);
+ set_param(PARAM_SIZE, 0);
set_param(PARAM_ATTENUATION, 1);
set_param(PARAM_SPOT_ANGLE, 45);
set_param(PARAM_SPOT_ATTENUATION, 1);
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index ad2a1d5a84..21810e03dd 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -46,6 +46,7 @@ public:
PARAM_INDIRECT_ENERGY = RS::LIGHT_PARAM_INDIRECT_ENERGY,
PARAM_SPECULAR = RS::LIGHT_PARAM_SPECULAR,
PARAM_RANGE = RS::LIGHT_PARAM_RANGE,
+ PARAM_SIZE = RS::LIGHT_PARAM_SIZE,
PARAM_ATTENUATION = RS::LIGHT_PARAM_ATTENUATION,
PARAM_SPOT_ANGLE = RS::LIGHT_PARAM_SPOT_ANGLE,
PARAM_SPOT_ATTENUATION = RS::LIGHT_PARAM_SPOT_ATTENUATION,
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 30ecd651b1..a03d6d0cdc 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -340,8 +340,8 @@ void OptionButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
// "selected" property must come after "items", otherwise GH-10213 occurs.
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
- ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "id")));
- ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index")));
}
OptionButton::OptionButton() {
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index e47e2b869d..1f135163d4 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -166,8 +166,9 @@ void Slider::_notification(int p_what) {
RID ci = get_canvas_item();
Size2i size = get_size();
Ref<StyleBox> style = get_theme_stylebox("slider");
- Ref<StyleBox> grabber_area = get_theme_stylebox("grabber_area");
- Ref<Texture2D> grabber = get_theme_icon(editable ? ((mouse_inside || has_focus()) ? "grabber_highlight" : "grabber") : "grabber_disabled");
+ bool highlighted = mouse_inside || has_focus();
+ Ref<StyleBox> grabber_area = get_theme_stylebox(highlighted ? "grabber_area_highlight" : "grabber_area");
+ Ref<Texture2D> grabber = get_theme_icon(editable ? (highlighted ? "grabber_highlight" : "grabber") : "grabber_disabled");
Ref<Texture2D> tick = get_theme_icon("tick");
double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index a7acaae8df..509a52d36a 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -3045,13 +3045,6 @@ void Tree::_notification(int p_what) {
draw_item(Point2(), draw_ofs, draw_size, root);
}
- int ofs = 0;
-
- for (int i = 0; i < (columns.size() - 1 - 1); i++) {
-
- ofs += get_column_width(i);
- }
-
if (show_column_titles) {
//title buttons
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index e6f09eb034..a1e8bf51bd 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -497,6 +497,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("slider", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4));
theme->set_stylebox("grabber_area", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4));
+ theme->set_stylebox("grabber_area_highlight", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4));
theme->set_icon("grabber", "HSlider", make_icon(hslider_grabber_png));
theme->set_icon("grabber_highlight", "HSlider", make_icon(hslider_grabber_hl_png));
@@ -507,6 +508,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("slider", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4));
theme->set_stylebox("grabber_area", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4));
+ theme->set_stylebox("grabber_area_highlight", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4));
theme->set_icon("grabber", "VSlider", make_icon(vslider_grabber_png));
theme->set_icon("grabber_highlight", "VSlider", make_icon(vslider_grabber_hl_png));
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
index 1f433ec6a5..e15aeca842 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -497,28 +497,28 @@ void Generic6DOFJoint3DSW::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DO
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning
}
@@ -597,28 +597,28 @@ real_t Generic6DOFJoint3DSW::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning
}
@@ -643,13 +643,13 @@ void Generic6DOFJoint3DSW::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOF
m_angularLimits[p_axis].m_enableMotor = p_value;
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
}
@@ -671,13 +671,13 @@ bool Generic6DOFJoint3DSW::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOF
return m_angularLimits[p_axis].m_enableMotor;
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
- // Not implemented in GodotPhysics backend
+ // Not implemented in GodotPhysics3D backend
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
}
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index bc42c2fd9e..d8da6e715b 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -70,7 +70,7 @@ RID PhysicsServer3DSW::shape_create(ShapeType p_shape) {
} break;
case SHAPE_CYLINDER: {
- ERR_FAIL_V_MSG(RID(), "CylinderShape3D is not supported in GodotPhysics. Please switch to Bullet in the Project Settings.");
+ ERR_FAIL_V_MSG(RID(), "CylinderShape3D is not supported in GodotPhysics3D. Please switch to Bullet in the Project Settings.");
} break;
case SHAPE_CONVEX_POLYGON: {
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index dadd26dade..556f9cd8e3 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -178,15 +178,15 @@ void register_server_types() {
GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT");
ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
- PhysicsServer2DManager::register_server("GodotPhysics", &_createGodotPhysics2DCallback);
- PhysicsServer2DManager::set_default_server("GodotPhysics");
+ PhysicsServer2DManager::register_server("GodotPhysics2D", &_createGodotPhysics2DCallback);
+ PhysicsServer2DManager::set_default_server("GodotPhysics2D");
// Physics 3D
GLOBAL_DEF(PhysicsServer3DManager::setting_property_name, "DEFAULT");
ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer3DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
- PhysicsServer3DManager::register_server("GodotPhysics", &_createGodotPhysics3DCallback);
- PhysicsServer3DManager::set_default_server("GodotPhysics");
+ PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback);
+ PhysicsServer3DManager::set_default_server("GodotPhysics3D");
}
void unregister_server_types() {
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index 5013b38f3f..cf0afe6097 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -231,7 +231,7 @@ public:
virtual RID light_instance_create(RID p_light) = 0;
virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0;
- virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0) = 0;
+ virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0;
virtual void light_instance_mark_visible(RID p_light_instance) = 0;
virtual bool light_instances_can_render_shadow_cube() const {
return true;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index 8d9b352a85..ec05c9e964 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -965,6 +965,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer
scene_state.ubo.shadow_filter_mode = shadow_filter_get();
scene_state.ubo.pancake_shadows = p_pancake_shadows;
+ scene_state.ubo.shadow_blocker_count = 16;
scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y;
@@ -1484,6 +1485,10 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.specular = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
light_data.mask = storage->light_get_cull_mask(base);
+ float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+
Color shadow_col = storage->light_get_shadow_color(base).to_linear();
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
@@ -1551,12 +1556,44 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j);
light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
light_data.shadow_transmittance_z_scale[j] = light_instance_get_shadow_range(li, j);
+ light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j);
store_camera(shadow_mtx, light_data.shadow_matrices[j]);
+
+ Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j);
+ uv_scale *= atlas_rect.size; //adapt to atlas size
+ switch (j) {
+ case 0: {
+ light_data.uv_scale1[0] = uv_scale.x;
+ light_data.uv_scale1[1] = uv_scale.y;
+ } break;
+ case 1: {
+ light_data.uv_scale2[0] = uv_scale.x;
+ light_data.uv_scale2[1] = uv_scale.y;
+ } break;
+ case 2: {
+ light_data.uv_scale3[0] = uv_scale.x;
+ light_data.uv_scale3[1] = uv_scale.y;
+ } break;
+ case 3: {
+ light_data.uv_scale4[0] = uv_scale.x;
+ light_data.uv_scale4[1] = uv_scale.y;
+ } break;
+ }
}
float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
light_data.fade_to = -light_data.shadow_split_offsets[3];
+
+ float softshadow_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (softshadow_angle > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // technically this will keep expanding until reaching the sun, but all we care
+ // is expand until we reach the radius of the near plane (there can't be more occluders than that)
+ light_data.softshadow_angle = Math::tan(Math::deg2rad(softshadow_angle));
+ } else {
+ light_data.softshadow_angle = 0;
+ }
}
// Copy to SkyDirectionalLightData
@@ -1619,6 +1656,10 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.direction[1] = direction.y;
light_data.direction[2] = direction.z;
+ float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = size;
+
light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION));
float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle)));
@@ -1646,6 +1687,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas);
light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size;
+
} else { //omni
light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0;
float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas);
@@ -1656,18 +1698,31 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas);
- if (type == RS::LIGHT_OMNI) {
+ light_data.atlas_rect[0] = rect.position.x;
+ light_data.atlas_rect[1] = rect.position.y;
+ light_data.atlas_rect[2] = rect.size.width;
+ light_data.atlas_rect[3] = rect.size.height;
- light_data.atlas_rect[0] = rect.position.x;
- light_data.atlas_rect[1] = rect.position.y;
- light_data.atlas_rect[2] = rect.size.width;
- light_data.atlas_rect[3] = rect.size.height * 0.5;
+ if (type == RS::LIGHT_OMNI) {
+ light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
Transform proj = (p_camera_inverse_transform * light_transform).inverse();
store_transform(proj, light_data.shadow_matrix);
+
+ if (size > 0.0) {
+
+ light_data.soft_shadow_size = size;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ }
+
} else if (type == RS::LIGHT_SPOT) {
+ //used for clamping in this light type
+ light_data.atlas_rect[2] += light_data.atlas_rect[0];
+ light_data.atlas_rect[3] += light_data.atlas_rect[1];
+
Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
CameraMatrix bias;
bias.set_light_bias();
@@ -1676,6 +1731,14 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview;
store_camera(shadow_mtx, light_data.shadow_matrix);
+
+ if (size > 0.0) {
+ CameraMatrix cm = light_instance_get_shadow_camera(li, 0);
+ float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle));
+ light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ }
}
} else {
light_data.shadow_color_enabled[3] = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
index b89de11bb4..b4f5d25afd 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
@@ -254,17 +254,19 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float position[3];
float inv_radius;
float direction[3];
+ float size;
uint16_t attenuation_energy[2]; //16 bits attenuation, then energy
uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm)
uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float)
- uint32_t mask;
uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm)
float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
float shadow_matrix[16];
float shadow_bias;
float shadow_normal_bias;
float transmittance_bias;
- uint32_t pad;
+ float soft_shadow_size;
+ uint32_t mask;
+ uint32_t pad[3];
};
struct DirectionalLightData {
@@ -272,9 +274,11 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float direction[3];
float energy;
float color[3];
+ float size;
float specular;
uint32_t mask;
- uint32_t pad[3];
+ float softshadow_angle;
+ uint32_t pad[1];
uint32_t blend_splits;
uint32_t shadow_enabled;
float fade_from;
@@ -283,12 +287,17 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float shadow_normal_bias[4];
float shadow_transmittance_bias[4];
float shadow_transmittance_z_scale[4];
+ float shadow_range_begin[4];
float shadow_split_offsets[4];
float shadow_matrices[4][16];
float shadow_color1[4];
float shadow_color2[4];
float shadow_color3[4];
float shadow_color4[4];
+ float uv_scale1[2];
+ float uv_scale2[2];
+ float uv_scale3[2];
+ float uv_scale4[2];
};
struct GIProbeData {
@@ -343,6 +352,9 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
uint32_t pancake_shadows;
uint32_t shadow_filter_mode;
+ uint32_t shadow_blocker_count;
+ uint32_t shadow_pad[3];
+
float ambient_light_color_energy[4];
float ambient_color_sky_mix;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index deef34d71f..a0bbf8bd43 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -2032,7 +2032,7 @@ void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const
light_instance->transform = p_transform;
}
-void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale) {
+void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
ERR_FAIL_COND(!light_instance);
@@ -2048,7 +2048,9 @@ void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance
light_instance->shadow_transform[p_pass].farplane = p_far;
light_instance->shadow_transform[p_pass].split = p_split;
light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
+ light_instance->shadow_transform[p_pass].range_begin = p_range_begin;
light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size;
+ light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale;
}
void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) {
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index 94c7971ec3..3478c05fb1 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -573,7 +573,9 @@ private:
float split;
float bias_scale;
float shadow_texel_size;
+ float range_begin;
Rect2 atlas_rect;
+ Vector2 uv_scale;
};
RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
@@ -883,7 +885,7 @@ public:
RID light_instance_create(RID p_light);
void light_instance_set_transform(RID p_light_instance, const Transform &p_transform);
- void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0);
+ void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2());
void light_instance_mark_visible(RID p_light_instance);
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
@@ -967,6 +969,17 @@ public:
LightInstance *li = light_instance_owner.getornull(p_light_instance);
return li->shadow_transform[p_index].farplane;
}
+ _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].range_begin;
+ }
+
+ _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].uv_scale;
+ }
_FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index 8c73cecec3..0b26ec1be6 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -3104,6 +3104,7 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5;
light.param[RS::LIGHT_PARAM_RANGE] = 1.0;
+ light.param[RS::LIGHT_PARAM_SIZE] = 0.0;
light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45;
light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index 62ab188ddc..70ce8d61e4 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -441,7 +441,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
-void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -481,7 +481,7 @@ LIGHT_SHADER_CODE
/* clang-format on */
#else
- float NdotL = dot(N, L);
+ float NdotL = min(A + dot(N, L), 1.0);
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
float cNdotV = max(NdotV, 0.0);
@@ -491,11 +491,11 @@ LIGHT_SHADER_CODE
#endif
#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
- float cNdotH = max(dot(N, H), 0.0);
+ float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
#endif
#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
- float cLdotH = max(dot(L, H), 0.0);
+ float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
#endif
if (metallic < 1.0) {
@@ -613,7 +613,7 @@ LIGHT_SHADER_CODE
#elif defined(SPECULAR_PHONG)
vec3 R = normalize(-reflect(L, N));
- float cRdotV = max(0.0, dot(R, V));
+ float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float phong = pow(cRdotV, shininess);
phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
@@ -686,6 +686,24 @@ LIGHT_SHADER_CODE
#ifndef USE_NO_SHADOWS
+const vec2 shadow_poisson_disk[16] = vec2[](
+ vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
vec2 pos = coord.xy;
@@ -725,6 +743,51 @@ float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
return 0;
}
+float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
+
+ //find blocker
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 poisson_rotate;
+
+ {
+ float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123));
+ float sr = sin(r);
+ float cr = cos(r);
+ poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ for (uint i = 0; i < scene_data.shadow_blocker_count; i++) {
+ vec2 suv = pssm_coord.xy + (poisson_rotate * shadow_poisson_disk[i]) * tex_scale;
+ float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ if (d < pssm_coord.z) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (pssm_coord.z - blocker_average) / blocker_average;
+ tex_scale *= penumbra;
+
+ float s = 0.0;
+ for (uint i = 0; i < scene_data.shadow_blocker_count; i++) {
+ vec2 suv = pssm_coord.xy + (poisson_rotate * shadow_poisson_disk[i]) * tex_scale;
+ s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
+ }
+
+ return s / float(scene_data.shadow_blocker_count);
+
+ } else {
+ //no blockers found, so no shadow
+ return 1.0;
+ }
+}
+
#endif //USE_NO_SHADOWS
void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
@@ -760,6 +823,13 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
vec3 shadow_attenuation = vec3(1.0);
vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
color_specular.rgb *= attenuation_energy.y;
+ float size_A = 0.0;
+
+ if (lights.data[idx].size > 0.0) {
+
+ float t = lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth; //no transmittance by default
@@ -773,7 +843,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
vec4 v = vec4(vertex, 1.0);
vec4 splane = (lights.data[idx].shadow_matrix * v);
- float shadow_len = length(splane.xyz);
+ float shadow_len = length(splane.xyz); //need to remember shadow len from here
{
vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius;
@@ -782,26 +852,126 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
splane = (lights.data[idx].shadow_matrix * v);
}
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = lights.data[idx].atlas_rect;
+ float shadow;
+
+ if (lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 poisson_rotate;
+
+ {
+ float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123));
+ float sr = sin(r);
+ float cr = cos(r);
+ poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ vec3 normal = normalize(splane.xyz);
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, normal));
+ vec3 bitangent = normalize(cross(tangent, normal));
+ float z_norm = shadow_len * lights.data[idx].inv_radius;
+
+ tangent *= lights.data[idx].soft_shadow_size;
+ bitangent *= lights.data[idx].soft_shadow_size;
- if (splane.z >= 0.0) {
+ for (uint i = 0; i < scene_data.shadow_blocker_count; i++) {
+ vec2 poisson = (poisson_rotate * shadow_poisson_disk[i]);
+ vec3 pos = splane.xyz + tangent * poisson.x + bitangent * poisson.y;
- splane.z += 1.0;
+ pos = normalize(pos);
+ vec4 uv_rect = lights.data[idx].atlas_rect;
- clamp_rect.y += clamp_rect.w;
+ if (pos.z >= 0.0) {
+ pos.z += 1.0;
+ uv_rect.y += uv_rect.w;
+ } else {
+
+ pos.z = 1.0 - pos.z;
+ }
+
+ pos.xy /= pos.z;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+
+ float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r;
+ if (d < z_norm) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (z_norm - blocker_average) / blocker_average;
+ tangent *= penumbra;
+ bitangent *= penumbra;
+
+ z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias;
+
+ shadow = 0.0;
+ for (uint i = 0; i < scene_data.shadow_blocker_count; i++) {
+
+ vec2 poisson = (poisson_rotate * shadow_poisson_disk[i]);
+ vec3 pos = splane.xyz + tangent * poisson.x + bitangent * poisson.y;
+
+ pos = normalize(pos);
+ vec4 uv_rect = lights.data[idx].atlas_rect;
+
+ if (pos.z >= 0.0) {
+
+ pos.z += 1.0;
+ uv_rect.y += uv_rect.w;
+ } else {
+
+ pos.z = 1.0 - pos.z;
+ }
+
+ pos.xy /= pos.z;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
+ }
+
+ shadow /= float(scene_data.shadow_blocker_count);
+
+ } else {
+ //no blockers found, so no shadow
+ shadow = 1.0;
+ }
} else {
- splane.z = 1.0 - splane.z;
- }
- splane.xy /= splane.z;
+ splane.xyz = normalize(splane.xyz);
+ vec4 clamp_rect = lights.data[idx].atlas_rect;
+
+ if (splane.z >= 0.0) {
+
+ splane.z += 1.0;
+
+ clamp_rect.y += clamp_rect.w;
+
+ } else {
+ splane.z = 1.0 - splane.z;
+ }
+
+ splane.xy /= splane.z;
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = (shadow_len - lights.data[idx].shadow_bias) * lights.data[idx].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
- float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = (shadow_len - lights.data[idx].shadow_bias) * lights.data[idx].inv_radius;
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ splane.w = 1.0; //needed? i think it should be 1 already
+ shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
+ }
#ifdef LIGHT_TRANSMITTANCE_USED
{
@@ -836,7 +1006,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
}
#endif //USE_NO_SHADOWS
- light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -903,6 +1073,13 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
color_specular.rgb *= attenuation_energy.y;
+ float size_A = 0.0;
+
+ if (lights.data[idx].size > 0.0) {
+
+ float t = lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
/*
if (lights.data[idx].atlas_rect!=vec4(0.0)) {
//use projector texture
@@ -920,22 +1097,82 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
v.xyz -= spot_dir * lights.data[idx].shadow_bias;
- float depth_bias_scale = 1.0 / (max(0.0001, dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius)); //the closer to the light origin, the more you have to offset to reach 1px in the map
+ float z_norm = dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius;
+
+ float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * lights.data[idx].shadow_normal_bias * depth_bias_scale;
normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
v.xyz += normal_bias;
+ //adjust with bias
+ z_norm = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius;
+
+ float shadow;
+
vec4 splane = (lights.data[idx].shadow_matrix * v);
splane /= splane.w;
- splane.z = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius;
- float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
+
+ if (lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 poisson_rotate;
+
+ {
+ float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123));
+ float sr = sin(r);
+ float cr = cos(r);
+ poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float uv_size = lights.data[idx].soft_shadow_size * z_norm;
+ for (uint i = 0; i < scene_data.shadow_blocker_count; i++) {
+ vec2 suv = splane.xy + (poisson_rotate * shadow_poisson_disk[i]) * uv_size;
+ suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw);
+ float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ if (d < z_norm) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (z_norm - blocker_average) / blocker_average;
+ uv_size *= penumbra;
+
+ shadow = 0.0;
+ for (uint i = 0; i < scene_data.shadow_blocker_count; i++) {
+ vec2 suv = splane.xy + (poisson_rotate * shadow_poisson_disk[i]) * uv_size;
+ suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw);
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
+ }
+
+ shadow /= float(scene_data.shadow_blocker_count);
+
+ } else {
+ //no blockers found, so no shadow
+ shadow = 1.0;
+ }
+
+ } else {
+ //hard shadow
+ splane.z = z_norm;
+ shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
+ }
shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
#ifdef LIGHT_TRANSMITTANCE_USED
{
- splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
+ vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
splane /= splane.w;
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
@@ -950,7 +1187,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
#endif //USE_NO_SHADOWS
- light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1636,13 +1873,28 @@ FRAGMENT_SHADER_CODE
normal_bias -= light_dir * dot(light_dir, normal_bias); \
m_var.xyz += normal_bias;
+ float shadow = 0.0;
+
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 0)
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.x;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
shadow_color = directional_lights.data[i].shadow_color1.rgb;
+
#ifdef LIGHT_TRANSMITTANCE_USED
{
vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0);
@@ -1663,6 +1915,18 @@ FRAGMENT_SHADER_CODE
BIAS_FUNC(v, 1)
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.y;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
shadow_color = directional_lights.data[i].shadow_color2.rgb;
#ifdef LIGHT_TRANSMITTANCE_USED
{
@@ -1684,6 +1948,18 @@ FRAGMENT_SHADER_CODE
BIAS_FUNC(v, 2)
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.z;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
shadow_color = directional_lights.data[i].shadow_color3.rgb;
#ifdef LIGHT_TRANSMITTANCE_USED
{
@@ -1706,7 +1982,20 @@ FRAGMENT_SHADER_CODE
BIAS_FUNC(v, 3)
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
shadow_color = directional_lights.data[i].shadow_color4.rgb;
+
#ifdef LIGHT_TRANSMITTANCE_USED
{
vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0);
@@ -1722,40 +2011,72 @@ FRAGMENT_SHADER_CODE
#endif
}
- pssm_coord /= pssm_coord.w;
-
- float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
-
if (directional_lights.data[i].blend_splits) {
vec3 shadow_color_blend = vec3(0.0);
float pssm_blend;
+ float shadow2;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 1)
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.y;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
shadow_color_blend = directional_lights.data[i].shadow_color2.rgb;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 2)
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.z;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+
shadow_color_blend = directional_lights.data[i].shadow_color3.rgb;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 3)
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale);
+ } else {
+ shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ }
+
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
shadow_color_blend = directional_lights.data[i].shadow_color4.rgb;
} else {
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
}
- pssm_coord /= pssm_coord.w;
+ pssm_blend = sqrt(pssm_blend);
- float shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
shadow = mix(shadow, shadow2, pssm_blend);
shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend);
}
@@ -1767,7 +2088,7 @@ FRAGMENT_SHADER_CODE
#undef BIAS_FUNC
}
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity,
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
index e3f1e650ed..59f326bc9b 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
@@ -47,6 +47,11 @@ layout(set = 0, binding = 3, std140) uniform SceneData {
bool pancake_shadows;
uint shadow_filter_mode;
+ uint shadow_blocker_count;
+ uint shadow_pad0;
+ uint shadow_pad1;
+ uint shadow_pad2;
+
vec4 ambient_light_color_energy;
float ambient_color_sky_mix;
@@ -141,17 +146,19 @@ struct LightData { //this structure needs to be as packed as possible
vec3 position;
float inv_radius;
vec3 direction;
+ float size;
uint attenuation_energy; //attenuation
uint color_specular; //rgb color, a specular (8 bit unorm)
uint cone_attenuation_angle; // attenuation and angle, (16bit float)
- uint mask;
uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
vec4 atlas_rect; // used for spot
mat4 shadow_matrix;
float shadow_bias;
float shadow_normal_bias;
float transmittance_bias;
- uint pad;
+ float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ uint mask;
+ uint pad[3];
};
layout(set = 0, binding = 5, std430) buffer Lights {
@@ -180,11 +187,11 @@ struct DirectionalLightData {
vec3 direction;
float energy;
vec3 color;
+ float size;
float specular;
uint mask;
- uint pad0;
+ float softshadow_angle;
uint pad1;
- uint pad2;
bool blend_splits;
bool shadow_enabled;
float fade_from;
@@ -193,6 +200,7 @@ struct DirectionalLightData {
vec4 shadow_normal_bias;
vec4 shadow_transmittance_bias;
vec4 shadow_transmittance_z_scale;
+ vec4 shadow_range_begin;
vec4 shadow_split_offsets;
mat4 shadow_matrix1;
mat4 shadow_matrix2;
@@ -202,6 +210,10 @@ struct DirectionalLightData {
vec4 shadow_color2;
vec4 shadow_color3;
vec4 shadow_color4;
+ vec2 uv_scale1;
+ vec2 uv_scale2;
+ vec2 uv_scale3;
+ vec2 uv_scale4;
};
layout(set = 0, binding = 7, std140) uniform DirectionalLights {
diff --git a/servers/rendering/rendering_server_raster.cpp b/servers/rendering/rendering_server_raster.cpp
index 7cc06527e4..c6f3273339 100644
--- a/servers/rendering/rendering_server_raster.cpp
+++ b/servers/rendering/rendering_server_raster.cpp
@@ -135,16 +135,27 @@ void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) {
if (RSG::storage->get_captured_timestamps_count()) {
Vector<FrameProfileArea> new_profile;
- new_profile.resize(RSG::storage->get_captured_timestamps_count());
+ if (RSG::storage->capturing_timestamps) {
+ new_profile.resize(RSG::storage->get_captured_timestamps_count());
+ }
uint64_t base_cpu = RSG::storage->get_captured_timestamp_cpu_time(0);
uint64_t base_gpu = RSG::storage->get_captured_timestamp_gpu_time(0);
for (uint32_t i = 0; i < RSG::storage->get_captured_timestamps_count(); i++) {
- uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i) - base_cpu;
- uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i) - base_gpu;
- new_profile.write[i].gpu_msec = float(time_gpu / 1000) / 1000.0;
- new_profile.write[i].cpu_msec = float(time_cpu) / 1000.0;
- new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i);
+ uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i);
+ uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i);
+
+ String name = RSG::storage->get_captured_timestamp_name(i);
+
+ if (name.begins_with("vp_")) {
+ RSG::viewport->handle_timestamp(name, time_cpu, time_gpu);
+ }
+
+ if (RSG::storage->capturing_timestamps) {
+ new_profile.write[i].gpu_msec = float((time_gpu - base_gpu) / 1000) / 1000.0;
+ new_profile.write[i].cpu_msec = float(time_cpu - base_cpu) / 1000.0;
+ new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i);
+ }
}
frame_profile = new_profile;
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index 1b9755397a..7ea7d0a4dc 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -493,6 +493,10 @@ public:
BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw)
+ BIND2(viewport_set_measure_render_time, RID, bool)
+ BIND1RC(float, viewport_get_measured_render_time_cpu, RID)
+ BIND1RC(float, viewport_get_measured_render_time_gpu, RID)
+
/* ENVIRONMENT API */
#undef BINDBASE
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp
index 4f40012c98..d66708587a 100644
--- a/servers/rendering/rendering_server_scene.cpp
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -1499,7 +1499,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c
if (j == 0 || d_z > z_max)
z_max = d_z;
}
+
real_t radius = 0;
+ real_t soft_shadow_expand = 0;
Vector3 center;
{
@@ -1528,12 +1530,30 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c
bias_scale = radius / first_radius;
}
- x_max_cam = x_vec.dot(center) + radius;
- x_min_cam = x_vec.dot(center) - radius;
- y_max_cam = y_vec.dot(center) + radius;
- y_min_cam = y_vec.dot(center) - radius;
z_min_cam = z_vec.dot(center) - radius;
+ {
+
+ float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE);
+
+ if (soft_shadow_angle > 0.0 && pancake_size > 0.0) {
+
+ float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam;
+ soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range;
+
+ x_max += soft_shadow_expand;
+ y_max += soft_shadow_expand;
+
+ x_min -= soft_shadow_expand;
+ y_min -= soft_shadow_expand;
+ }
+ }
+
+ x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand;
+ x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand;
+ y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand;
+ y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand;
+
if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) {
//this trick here is what stabilizes the shadow (make potential jaggies to not move)
//at the cost of some wasted resolution. Still the quality increase is very well worth it
@@ -1588,8 +1608,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c
}
}
- if (cull_max > z_max)
+ if (cull_max > z_max) {
z_max = cull_max;
+ }
if (pancake_size > 0) {
z_max = z_vec.dot(center) + radius + pancake_size;
@@ -1677,11 +1698,19 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c
ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam));
+ Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam));
+
Transform ortho_transform;
ortho_transform.basis = transform.basis;
ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max;
- RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale);
+ {
+ Vector3 max_in_view = p_cam_transform.affine_inverse().xform(z_vec * cull_max);
+ Vector3 dir_in_view = p_cam_transform.xform_inv(z_vec).normalized();
+ cull_max = dir_in_view.dot(max_in_view);
+ }
+
+ RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale);
}
RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/rendering_server_viewport.cpp
index 87dcb772bc..152e79f3e0 100644
--- a/servers/rendering/rendering_server_viewport.cpp
+++ b/servers/rendering/rendering_server_viewport.cpp
@@ -81,6 +81,12 @@ void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p
void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+ if (p_viewport->measure_render_time) {
+ String rt_id = "vp_begin_" + itos(p_viewport->self.get_id());
+ RSG::storage->capture_timestamp(rt_id);
+ timestamp_vp_map[rt_id] = p_viewport->self;
+ }
+
/* Camera should always be BEFORE any other 3D */
bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
@@ -289,10 +295,18 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
//was never cleared in the end, force clear it
RSG::storage->render_target_do_clear_request(p_viewport->render_target);
}
+
+ if (p_viewport->measure_render_time) {
+ String rt_id = "vp_end_" + itos(p_viewport->self.get_id());
+ RSG::storage->capture_timestamp(rt_id);
+ timestamp_vp_map[rt_id] = p_viewport->self;
+ }
}
void RenderingServerViewport::draw_viewports() {
+ timestamp_vp_map.clear();
+
// get our xr interface in case we need it
Ref<XRInterface> xr_interface;
@@ -745,6 +759,30 @@ void RenderingServerViewport::viewport_set_debug_draw(RID p_viewport, RS::Viewpo
viewport->debug_draw = p_draw;
}
+void RenderingServerViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->measure_render_time = p_enable;
+}
+
+float RenderingServerViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, 0);
+
+ return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0;
+}
+
+float RenderingServerViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, 0);
+
+ return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0;
+}
+
bool RenderingServerViewport::free(RID p_rid) {
if (viewport_owner.owns(p_rid)) {
@@ -773,6 +811,29 @@ bool RenderingServerViewport::free(RID p_rid) {
return false;
}
+void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) {
+
+ RID *vp = timestamp_vp_map.getptr(p_timestamp);
+ if (!vp) {
+ return;
+ }
+
+ Viewport *viewport = viewport_owner.getornull(*vp);
+ if (!viewport) {
+ return;
+ }
+
+ if (p_timestamp.begins_with("vp_begin")) {
+ viewport->time_cpu_begin = p_cpu_time;
+ viewport->time_gpu_begin = p_gpu_time;
+ }
+
+ if (p_timestamp.begins_with("vp_end")) {
+ viewport->time_cpu_end = p_cpu_time;
+ viewport->time_gpu_end = p_gpu_time;
+ }
+}
+
void RenderingServerViewport::set_default_clear_color(const Color &p_color) {
RSG::storage->set_default_clear_color(p_color);
}
diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/rendering_server_viewport.h
index 71d8408ed1..910d1ef5e9 100644
--- a/servers/rendering/rendering_server_viewport.h
+++ b/servers/rendering/rendering_server_viewport.h
@@ -67,8 +67,13 @@ public:
bool hide_scenario;
bool hide_canvas;
bool disable_environment;
- bool disable_3d_by_usage;
- bool keep_3d_linear;
+ bool measure_render_time;
+
+ uint64_t time_cpu_begin;
+ uint64_t time_cpu_end;
+
+ uint64_t time_gpu_begin;
+ uint64_t time_gpu_end;
RID shadow_atlas;
int shadow_atlas_size;
@@ -121,16 +126,25 @@ public:
disable_environment = false;
viewport_to_screen = DisplayServer::INVALID_WINDOW_ID;
shadow_atlas_size = 0;
- keep_3d_linear = false;
+ measure_render_time = false;
+
debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
msaa = RS::VIEWPORT_MSAA_DISABLED;
for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) {
render_info[i] = 0;
}
use_xr = false;
+
+ time_cpu_begin = 0;
+ time_cpu_end = 0;
+
+ time_gpu_begin = 0;
+ time_gpu_end = 0;
}
};
+ HashMap<String, RID> timestamp_vp_map;
+
uint64_t draw_viewports_pass = 0;
mutable RID_PtrOwner<Viewport> viewport_owner;
@@ -196,6 +210,12 @@ public:
virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw);
+ void viewport_set_measure_render_time(RID p_viewport, bool p_enable);
+ float viewport_get_measured_render_time_cpu(RID p_viewport) const;
+ float viewport_get_measured_render_time_gpu(RID p_viewport) const;
+
+ void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time);
+
void set_default_clear_color(const Color &p_color);
void draw_viewports();
diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp
index aa3bf583c7..4ca13dbef9 100644
--- a/servers/rendering/rendering_server_wrap_mt.cpp
+++ b/servers/rendering/rendering_server_wrap_mt.cpp
@@ -126,17 +126,6 @@ void RenderingServerWrapMT::init() {
void RenderingServerWrapMT::finish() {
- if (thread) {
-
- command_queue.push(this, &RenderingServerWrapMT::thread_exit);
- Thread::wait_to_finish(thread);
- memdelete(thread);
-
- thread = nullptr;
- } else {
- rendering_server->finish();
- }
-
sky_free_cached_ids();
shader_free_cached_ids();
material_free_cached_ids();
@@ -161,6 +150,17 @@ void RenderingServerWrapMT::finish() {
canvas_item_free_cached_ids();
canvas_light_occluder_free_cached_ids();
canvas_occluder_polygon_free_cached_ids();
+
+ if (thread) {
+
+ command_queue.push(this, &RenderingServerWrapMT::thread_exit);
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+
+ thread = nullptr;
+ } else {
+ rendering_server->finish();
+ }
}
void RenderingServerWrapMT::set_use_vsync_callback(bool p_enable) {
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index 9a98841b2c..834cf82d79 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -411,6 +411,14 @@ public:
FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw)
+ FUNC2(viewport_set_measure_render_time, RID, bool)
+ virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const {
+ return rendering_server->viewport_get_measured_render_time_cpu(p_viewport);
+ }
+ virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const {
+ return rendering_server->viewport_get_measured_render_time_gpu(p_viewport);
+ }
+
FUNC1(directional_shadow_atlas_set_size, int)
/* SKY API */
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index cb7c2cecf6..df91fc59bc 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -382,6 +382,7 @@ public:
LIGHT_PARAM_INDIRECT_ENERGY,
LIGHT_PARAM_SPECULAR,
LIGHT_PARAM_RANGE,
+ LIGHT_PARAM_SIZE,
LIGHT_PARAM_ATTENUATION,
LIGHT_PARAM_SPOT_ANGLE,
LIGHT_PARAM_SPOT_ATTENUATION,
@@ -672,6 +673,10 @@ public:
virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0;
+ virtual void viewport_set_measure_render_time(RID p_viewport, bool p_enable) = 0;
+ virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0;
+ virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0;
+
virtual void directional_shadow_atlas_set_size(int p_size) = 0;
/* SKY API */
diff --git a/thirdparty/vulkan/android/vk_mem_alloc.cpp b/thirdparty/vulkan/android/vk_mem_alloc.cpp
new file mode 100644
index 0000000000..a28454cf6e
--- /dev/null
+++ b/thirdparty/vulkan/android/vk_mem_alloc.cpp
@@ -0,0 +1,8 @@
+#define VMA_IMPLEMENTATION
+#ifdef DEBUG_ENABLED
+#ifndef _DEBUG
+#define _DEBUG
+#endif
+#endif
+// Include memory allocator from Android NDK
+#include <vk_mem_alloc.h>