summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/multiplayer_api.cpp6
-rw-r--r--core/io/multiplayer_api.h1
-rw-r--r--core/io/packet_peer_udp.cpp1
-rw-r--r--core/object/class_db.cpp1
-rw-r--r--core/typedefs.h2
-rw-r--r--doc/classes/Input.xml14
-rw-r--r--doc/classes/MultiplayerAPI.xml14
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp2
-rw-r--r--editor/editor_node.cpp5
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp9
-rw-r--r--modules/gdscript/config.py1
-rw-r--r--modules/gdscript/doc_classes/GDScriptFunctionState.xml45
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp109
-rw-r--r--modules/gdscript/gdscript_analyzer.h3
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp23
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h3
-rw-r--r--modules/gdscript/gdscript_codegen.h3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp26
-rw-r--r--modules/gdscript/gdscript_parser.cpp10
-rw-r--r--modules/gdscript/register_types.cpp1
-rw-r--r--platform/linuxbsd/display_server_x11.cpp129
-rw-r--r--platform/linuxbsd/display_server_x11.h1
-rw-r--r--scene/2d/light_occluder_2d.cpp14
-rw-r--r--scene/2d/light_occluder_2d.h5
-rw-r--r--scene/main/scene_tree.cpp8
-rw-r--r--scene/main/viewport.cpp42
-rw-r--r--scene/main/viewport.h26
-rw-r--r--scene/resources/resource_format_text.cpp5
-rw-r--r--scene/resources/visual_shader_nodes.cpp15
-rw-r--r--scene/resources/visual_shader_nodes.h1
-rw-r--r--servers/rendering/rasterizer.h11
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp240
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h46
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp289
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h45
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.cpp5
-rw-r--r--servers/rendering/rasterizer_rd/shaders/SCsub1
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas.glsl31
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl18
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl135
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl26
-rw-r--r--servers/rendering/rendering_server_canvas.cpp67
-rw-r--r--servers/rendering/rendering_server_canvas.h5
-rw-r--r--servers/rendering/rendering_server_raster.h3
-rw-r--r--servers/rendering/rendering_server_viewport.cpp45
-rw-r--r--servers/rendering/rendering_server_viewport.h5
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h4
-rw-r--r--servers/rendering/shader_types.cpp21
-rw-r--r--servers/rendering_server.cpp1
-rw-r--r--servers/rendering_server.h19
50 files changed, 1264 insertions, 278 deletions
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 2f17d9e746..afab00ebd6 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -142,6 +142,10 @@ void MultiplayerAPI::set_root_node(Node *p_node) {
root_node = p_node;
}
+Node *MultiplayerAPI::get_root_node() {
+ return root_node;
+}
+
void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) {
if (p_peer == network_peer) {
return; // Nothing to do
@@ -1202,6 +1206,7 @@ bool MultiplayerAPI::is_object_decoding_allowed() const {
void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
+ ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node);
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer);
ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer);
@@ -1221,6 +1226,7 @@ void MultiplayerAPI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_root_node", "get_root_node");
ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false);
ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index 5b30c2e680..ca52a1c689 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -114,6 +114,7 @@ public:
void poll();
void clear();
void set_root_node(Node *p_node);
+ Node *get_root_node();
void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer);
Ref<NetworkedMultiplayerPeer> get_network_peer() const;
Error send_bytes(Vector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index e633a56d54..488cfbeaa8 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -178,7 +178,6 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_
}
_sock->set_blocking_enabled(false);
- _sock->set_reuse_address_enabled(true);
_sock->set_broadcasting_enabled(broadcast);
err = _sock->bind(p_bind_address, p_port);
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 64ebeb427e..dc28fa10de 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -978,6 +978,7 @@ void ClassDB::add_property_subgroup(StringName p_class, const String &p_name, co
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP));
}
+// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end.
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
lock->read_lock();
ClassInfo *type = classes.getptr(p_class);
diff --git a/core/typedefs.h b/core/typedefs.h
index d7ee5ee40e..7c98bc37f7 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -92,7 +92,7 @@
#endif
#ifndef SGN
-#define SGN(m_v) (((m_v) < 0) ? (-1.0) : (+1.0))
+#define SGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0)))
#endif
#ifndef MIN
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 5d1d763ae3..cfb3e8d981 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -49,7 +49,7 @@
<return type="Vector3">
</return>
<description>
- Returns the acceleration of the device's accelerometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the acceleration of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
@@ -102,7 +102,7 @@
<return type="Vector3">
</return>
<description>
- Returns the gravity of the device's accelerometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the gravity of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
@@ -110,8 +110,8 @@
<return type="Vector3">
</return>
<description>
- Returns the rotation rate in rad/s around a device's X, Y, and Z axes of the gyroscope, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
- [b]Note:[/b] This method only works on Android. On other platforms, it always returns [constant Vector3.ZERO].
+ Returns the rotation rate in rad/s around a device's X, Y, and Z axes of the gyroscope sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ [b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
<method name="get_joy_axis" qualifiers="const">
@@ -172,8 +172,8 @@
<return type="Vector3">
</return>
<description>
- Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
- [b]Note:[/b] This method only works on Android and UWP. On other platforms, it always returns [constant Vector3.ZERO].
+ Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ [b]Note:[/b] This method only works on Android, iOS and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
<method name="get_mouse_button_mask" qualifiers="const">
@@ -403,7 +403,7 @@
</argument>
<description>
Vibrate Android and iOS devices.
- [b]Note:[/b] It needs VIBRATE permission for Android at export settings. iOS does not support duration.
+ [b]Note:[/b] It needs [code]VIBRATE[/code] permission for Android at export settings. iOS does not support duration.
</description>
</method>
<method name="warp_mouse_position">
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index 9c753818d9..fcc259fb44 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -75,16 +75,6 @@
Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers.
</description>
</method>
- <method name="set_root_node">
- <return type="void">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- Sets the base root node to use for RPCs. Instead of an absolute path, a relative path will be used to find the node upon which the RPC should be executed.
- This effectively allows to have different branches of the scene tree to be managed by different MultiplayerAPI, allowing for example to run both client and server in the same scene.
- </description>
- </method>
</methods>
<members>
<member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed" default="false">
@@ -97,6 +87,10 @@
<member name="refuse_new_network_connections" type="bool" setter="set_refuse_new_network_connections" getter="is_refusing_new_network_connections" default="false">
If [code]true[/code], the MultiplayerAPI's [member network_peer] refuses new incoming connections.
</member>
+ <member name="root_node" type="Node" setter="set_root_node" getter="get_root_node">
+ The root node to use for RPCs. Instead of an absolute path, a relative path will be used to find the node upon which the RPC should be executed.
+ This effectively allows to have different branches of the scene tree to be managed by different MultiplayerAPI, allowing for example to run both client and server in the same scene.
+ </member>
</members>
<signals>
<signal name="connected_to_server">
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 488fd4b468..7aa3787ced 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -183,7 +183,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {
int total = 0;
while (todo && !ad->exit_thread) {
- uint8_t *src = (uint8_t *)ad->samples_out.ptr();
+ int16_t *src = (int16_t *)ad->samples_out.ptr();
int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo);
if (wrote > 0) {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index ff8f089c26..27be3bcc14 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -521,6 +521,11 @@ void EditorNode::_notification(int p_what) {
scene_root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
bool snap_2d_vertices = GLOBAL_GET("rendering/quality/2d/snap_2d_vertices_to_pixel");
scene_root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
+
+ Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_GET("rendering/quality/2d_sdf/oversize")));
+ scene_root->set_sdf_oversize(sdf_oversize);
+ Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/quality/2d_sdf/scale")));
+ scene_root->set_sdf_scale(sdf_scale);
}
ResourceImporterTexture::get_singleton()->update_imports();
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 3116885065..00406dff32 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -102,7 +102,6 @@ void VisualShaderGraphPlugin::_bind_methods() {
ClassDB::bind_method("disconnect_nodes", &VisualShaderGraphPlugin::disconnect_nodes);
ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position);
ClassDB::bind_method("set_node_size", &VisualShaderGraphPlugin::set_node_size);
- ClassDB::bind_method("show_port_preview", &VisualShaderGraphPlugin::show_port_preview);
ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);
ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);
ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
@@ -1559,8 +1558,8 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview"));
undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port);
undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "show_port_preview", (int)type, p_node, p_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "show_port_preview", (int)type, p_node, prev_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, p_node);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, p_node);
undo_redo->commit_action();
}
@@ -1960,6 +1959,8 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->commit_action();
}
@@ -1976,6 +1977,8 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->commit_action();
}
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py
index 6fc227e7f5..61ce6185a5 100644
--- a/modules/gdscript/config.py
+++ b/modules/gdscript/config.py
@@ -10,7 +10,6 @@ def get_doc_classes():
return [
"@GDScript",
"GDScript",
- "GDScriptFunctionState",
]
diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
deleted file mode 100644
index 5e369b32d9..0000000000
--- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScriptFunctionState" inherits="Reference" version="4.0">
- <brief_description>
- State of a function call after yielding.
- </brief_description>
- <description>
- FIXME: Outdated docs as of GDScript rewrite in 4.0.
- Calling [code]yield[/code] within a function will cause that function to yield and return its current state as an object of this type. The yielded function call can then be resumed later by calling [method resume] on this state object.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="is_valid" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="extended_check" type="bool" default="false">
- </argument>
- <description>
- Check whether the function call may be resumed. This is not the case if the function state was already resumed.
- If [code]extended_check[/code] is enabled, it also checks if the associated script and object still exist. The extended check is done in debug mode as part of [method GDScriptFunctionState.resume], but you can use this if you know you may be trying to resume without knowing for sure the object and/or script have survived up to that point.
- </description>
- </method>
- <method name="resume">
- <return type="Variant">
- </return>
- <argument index="0" name="arg" type="Variant" default="null">
- </argument>
- <description>
- Resume execution of the yielded function call.
- If handed an argument, return the argument from the [code]yield[/code] call in the yielded function call. You can pass e.g. an [Array] to hand multiple arguments.
- This function returns what the resumed function call returns, possibly another function state if yielded again.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="completed">
- <argument index="0" name="result" type="Variant">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 851994eff3..3f2fdc04a5 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -983,12 +983,14 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
}
GDScriptParser::DataType arg_type = call->arguments[i]->get_datatype();
- if (arg_type.kind != GDScriptParser::DataType::BUILTIN) {
- all_is_constant = false;
- push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
- } else if (arg_type.builtin_type != Variant::INT && arg_type.builtin_type != Variant::FLOAT) {
- all_is_constant = false;
- push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
+ if (!arg_type.is_variant()) {
+ if (arg_type.kind != GDScriptParser::DataType::BUILTIN) {
+ all_is_constant = false;
+ push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
+ } else if (arg_type.builtin_type != Variant::INT && arg_type.builtin_type != Variant::FLOAT) {
+ all_is_constant = false;
+ push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
+ }
}
}
@@ -2029,9 +2031,17 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
p_get_node->set_datatype(result);
}
-GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name) {
+GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) {
Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(p_class_name));
- ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+
+ if (err) {
+ push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source);
+ GDScriptParser::DataType type;
+ type.type_source = GDScriptParser::DataType::UNDETECTED;
+ type.kind = GDScriptParser::DataType::VARIANT;
+ return type;
+ }
GDScriptParser::DataType type;
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -2303,7 +2313,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
if (ScriptServer::is_global_class(name)) {
- p_identifier->set_datatype(make_global_class_meta_type(name));
+ p_identifier->set_datatype(make_global_class_meta_type(name, p_identifier));
return;
}
@@ -2720,7 +2730,7 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
mark_node_unsafe(p_unary_op);
} else {
bool valid = false;
- result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), p_unary_op->operand->get_datatype(), valid, p_unary_op);
+ result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), valid, p_unary_op);
if (!valid) {
push_error(vformat(R"(Invalid operand of type "%s" for unary operator "%s".)", p_unary_op->operand->get_datatype().to_string(), Variant::get_operator_name(p_unary_op->variant_op)), p_unary_op->operand);
@@ -3086,81 +3096,31 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
}
#endif
-GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
- // This function creates dummy variant values and apply the operation to those. Less error-prone than keeping a table of valid operations.
+GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source) {
+ // Unary version.
+ GDScriptParser::DataType nil_type;
+ nil_type.builtin_type = Variant::NIL;
+ return get_operation_type(p_operation, p_a, nil_type, r_valid, p_source);
+}
+GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.kind = GDScriptParser::DataType::VARIANT;
Variant::Type a_type = p_a.builtin_type;
Variant::Type b_type = p_b.builtin_type;
- Variant a;
- REF a_ref;
- if (a_type == Variant::OBJECT) {
- a_ref.instance();
- a = a_ref;
- } else {
- Callable::CallError err;
- Variant::construct(a_type, a, nullptr, 0, err);
- if (err.error != Callable::CallError::CALL_OK) {
- r_valid = false;
- ERR_FAIL_V_MSG(result, vformat("Could not construct value of type %s", Variant::get_type_name(a_type)));
- }
- }
- Variant b;
- REF b_ref;
- if (b_type == Variant::OBJECT) {
- b_ref.instance();
- b = b_ref;
- } else {
- Callable::CallError err;
- Variant::construct(b_type, b, nullptr, 0, err);
- if (err.error != Callable::CallError::CALL_OK) {
- r_valid = false;
- ERR_FAIL_V_MSG(result, vformat("Could not construct value of type %s", Variant::get_type_name(b_type)));
- }
- }
-
- // Avoid division by zero.
- switch (b_type) {
- case Variant::INT:
- b = 1;
- break;
- case Variant::FLOAT:
- b = 1.0;
- break;
- case Variant::VECTOR2:
- b = Vector2(1.0, 1.0);
- break;
- case Variant::VECTOR2I:
- b = Vector2i(1, 1);
- break;
- case Variant::VECTOR3:
- b = Vector3(1.0, 1.0, 1.0);
- break;
- case Variant::VECTOR3I:
- b = Vector3i(1, 1, 1);
- break;
- case Variant::COLOR:
- b = Color(1.0, 1.0, 1.0, 1.0);
- break;
- default:
- // No change needed.
- break;
- }
+ Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type);
- // Avoid error in formatting operator (%) where it doesn't find a placeholder.
- if (a_type == Variant::STRING && b_type != Variant::ARRAY) {
- a = String("%s");
+ if (op_eval == nullptr) {
+ r_valid = false;
+ return result;
}
- Variant ret;
- Variant::evaluate(p_operation, a, b, ret, r_valid);
+ r_valid = true;
- if (r_valid) {
- return type_from_variant(ret, p_source);
- }
+ result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type);
return result;
}
@@ -3362,7 +3322,6 @@ Error GDScriptAnalyzer::resolve_program() {
}
depended_parsers[E->get()]->raise_status(GDScriptParserRef::FULLY_SOLVED);
}
- depended_parsers.clear();
return parser->errors.empty() ? OK : ERR_PARSE_ERROR;
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 0a952cc621..9925167856 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -96,12 +96,13 @@ class GDScriptAnalyzer {
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
- GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name);
+ GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
bool get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source);
+ GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false) const;
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index a81b3298ef..7c20cda39c 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -321,7 +321,28 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) {
#define IS_BUILTIN_TYPE(m_var, m_type) \
(m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type)
-void GDScriptByteCodeGenerator::write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
+void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) {
+ if (HAS_BUILTIN_TYPE(p_left_operand)) {
+ // Gather specific operator.
+ Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, Variant::NIL);
+
+ append(GDScriptFunction::OPCODE_OPERATOR_VALIDATED, 3);
+ append(p_left_operand);
+ append(Address());
+ append(p_target);
+ append(op_func);
+ return;
+ }
+
+ // No specific types, perform variant evaluation.
+ append(GDScriptFunction::OPCODE_OPERATOR, 3);
+ append(p_left_operand);
+ append(Address());
+ append(p_target);
+ append(p_operator);
+}
+
+void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) {
// Gather specific operator.
Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 0173b7f820..34d2bb6098 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -377,7 +377,8 @@ public:
#endif
virtual void set_initial_line(int p_line) override;
- virtual void write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
+ virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) override;
+ virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) override;
virtual void write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) override;
virtual void write_and_left_operand(const Address &p_left_operand) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index decab3df0b..35e326c61f 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -98,7 +98,8 @@ public:
// virtual void alloc_stack(int p_level) = 0; // Is this needed?
// virtual void alloc_call(int p_arg_count) = 0; // This might be automatic from other functions.
- virtual void write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
+ virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) = 0;
+ virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) = 0;
virtual void write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) = 0;
virtual void write_and_left_operand(const Address &p_left_operand) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 3d327cebeb..b41dc15324 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -677,7 +677,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
return GDScriptCodeGenerator::Address();
}
- gen->write_operator(result, unary->variant_op, operand, GDScriptCodeGenerator::Address());
+ gen->write_unary_operator(result, unary->variant_op, operand);
if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
@@ -745,7 +745,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
- gen->write_operator(result, binary->variant_op, left_operand, right_operand);
+ gen->write_binary_operator(result, binary->variant_op, left_operand, right_operand);
if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
@@ -908,7 +908,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else {
gen->write_get(value, key, prev_base);
}
- gen->write_operator(value, assignment->variant_op, value, assigned);
+ gen->write_binary_operator(value, assignment->variant_op, value, assigned);
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
}
@@ -966,7 +966,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
GDScriptCodeGenerator::Address member = codegen.add_temporary();
gen->write_get_member(member, name);
- gen->write_operator(assigned, assignment->variant_op, member, assigned);
+ gen->write_binary_operator(assigned, assignment->variant_op, member, assigned);
gen->pop_temporary();
}
@@ -1016,7 +1016,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
// Perform operation.
op_result = codegen.add_temporary();
- gen->write_operator(op_result, assignment->variant_op, target, assigned);
+ gen->write_binary_operator(op_result, assignment->variant_op, target, assigned);
} else {
op_result = assigned;
assigned = GDScriptCodeGenerator::Address();
@@ -1072,7 +1072,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check type equality.
GDScriptCodeGenerator::Address type_equality_addr = codegen.add_temporary(equality_type);
- codegen.generator->write_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
+ codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
codegen.generator->write_and_left_operand(type_equality_addr);
// Get literal.
@@ -1083,7 +1083,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check value equality.
GDScriptCodeGenerator::Address equality_addr = codegen.add_temporary(equality_type);
- codegen.generator->write_operator(equality_addr, Variant::OP_EQUAL, p_value_addr, literal_addr);
+ codegen.generator->write_binary_operator(equality_addr, Variant::OP_EQUAL, p_value_addr, literal_addr);
codegen.generator->write_and_right_operand(equality_addr);
// AND both together (reuse temporary location).
@@ -1135,11 +1135,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
codegen.generator->write_call_builtin(result_addr, GDScriptFunctions::TYPE_OF, typeof_args);
// Check type equality.
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
codegen.generator->write_and_left_operand(result_addr);
// Check value equality.
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
codegen.generator->write_and_right_operand(equality_test_addr);
// AND both type and value equality.
@@ -1185,7 +1185,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check type equality.
GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, array_type_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, array_type_addr);
codegen.generator->write_and_left_operand(result_addr);
// Store pattern length in constant map.
@@ -1201,7 +1201,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, array_length_addr);
+ codegen.generator->write_binary_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, array_length_addr);
codegen.generator->write_and_right_operand(length_compat_addr);
// AND type and length check.
@@ -1284,7 +1284,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check type equality.
GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, dict_type_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, dict_type_addr);
codegen.generator->write_and_left_operand(result_addr);
// Store pattern length in constant map.
@@ -1300,7 +1300,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, dict_length_addr);
+ codegen.generator->write_binary_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, dict_length_addr);
codegen.generator->write_and_right_operand(length_compat_addr);
// AND type and length check.
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index fde3662d66..372af204f5 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -184,6 +184,7 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) {
#ifdef DEBUG_ENABLED
void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) {
+ ERR_FAIL_COND(p_source == nullptr);
Vector<String> symbols;
if (!p_symbol1.empty()) {
symbols.push_back(p_symbol1);
@@ -201,6 +202,7 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
}
void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols) {
+ ERR_FAIL_COND(p_source == nullptr);
if (is_ignoring_warnings) {
return;
}
@@ -1419,9 +1421,13 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
}
#ifdef DEBUG_ENABLED
- if (unreachable) {
+ if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
- push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name);
+ if (current_function) {
+ push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name);
+ } else {
+ // TODO: Properties setters and getters with unreachable code are not being warned
+ }
}
#endif
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 065f01e654..6c2af66c65 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -112,7 +112,6 @@ static void _editor_init() {
void register_gdscript_types() {
ClassDB::register_class<GDScript>();
- ClassDB::register_virtual_class<GDScriptFunctionState>();
script_language_gd = memnew(GDScriptLanguage);
ScriptServer::register_language(script_language_gd);
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 74c69c0823..356668a375 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -465,59 +465,138 @@ Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *
}
}
+Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) {
+ if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const {
String ret;
- Atom type;
- Atom selection = XA_PRIMARY;
- int format, result;
- unsigned long len, bytes_left, dummy;
- unsigned char *data;
Window selection_owner = XGetSelectionOwner(x11_display, p_source);
-
if (selection_owner == x11_window) {
return internal_clipboard;
}
if (selection_owner != None) {
- {
- // Block events polling while processing selection events.
- MutexLock mutex_lock(events_mutex);
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
- XConvertSelection(x11_display, p_source, target, selection,
- x11_window, CurrentTime);
+ Atom selection = XA_PRIMARY;
+ XConvertSelection(x11_display, p_source, target, selection,
+ x11_window, CurrentTime);
- XFlush(x11_display);
+ XFlush(x11_display);
- // Blocking wait for predicate to be True
- // and remove the event from the queue.
- XEvent event;
- XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
- }
+ // Blocking wait for predicate to be True and remove the event from the queue.
+ XEvent event;
+ XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
- //
- // Do not get any data, see how much data is there
- //
+ // Do not get any data, see how much data is there.
+ Atom type;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ unsigned char *data;
XGetWindowProperty(x11_display, x11_window,
selection, // Tricky..
0, 0, // offset - len
0, // Delete 0==FALSE
- AnyPropertyType, //flag
+ AnyPropertyType, // flag
&type, // return type
&format, // return format
- &len, &bytes_left, //that
+ &len, &bytes_left, // data length
&data);
- // DATA is There
- if (bytes_left > 0) {
+
+ if (data) {
+ XFree(data);
+ }
+
+ if (type == XInternAtom(x11_display, "INCR", 0)) {
+ // Data is going to be received incrementally.
+ DEBUG_LOG_X11("INCR selection started.\n");
+
+ LocalVector<uint8_t> incr_data;
+ uint32_t data_size = 0;
+ bool success = false;
+
+ // Delete INCR property to notify the owner.
+ XDeleteProperty(x11_display, x11_window, type);
+
+ // Process events from the queue.
+ bool done = false;
+ while (!done) {
+ if (!_wait_for_events()) {
+ // Error or timeout, abort.
+ break;
+ }
+
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) {
+ result = XGetWindowProperty(x11_display, x11_window,
+ selection, // selection type
+ 0, LONG_MAX, // offset - len
+ True, // delete property to notify the owner
+ AnyPropertyType, // flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, // data length
+ &data);
+
+ DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format);
+
+ if (result == Success) {
+ if (data && (len > 0)) {
+ uint32_t prev_size = incr_data.size();
+ if (prev_size == 0) {
+ // First property contains initial data size.
+ unsigned long initial_size = *(unsigned long *)data;
+ incr_data.resize(initial_size);
+ } else {
+ // New chunk, resize to be safe and append data.
+ incr_data.resize(MAX(data_size + len, prev_size));
+ memcpy(incr_data.ptr() + data_size, data, len);
+ data_size += len;
+ }
+ } else {
+ // Last chunk, process finished.
+ done = true;
+ success = true;
+ }
+ } else {
+ printf("Failed to get selection data chunk.\n");
+ done = true;
+ }
+
+ if (data) {
+ XFree(data);
+ }
+
+ if (done) {
+ break;
+ }
+ }
+ }
+
+ if (success && (data_size > 0)) {
+ ret.parse_utf8((const char *)incr_data.ptr(), data_size);
+ }
+ } else if (bytes_left > 0) {
+ // Data is ready and can be processed all at once.
result = XGetWindowProperty(x11_display, x11_window,
selection, 0, bytes_left, 0,
AnyPropertyType, &type, &format,
&len, &dummy, &data);
+
if (result == Success) {
ret.parse_utf8((const char *)data);
} else {
- printf("FAIL\n");
+ printf("Failed to get selection data.\n");
}
+
if (data) {
XFree(data);
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 682f1c8ef3..61fb04cbf3 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -270,6 +270,7 @@ class DisplayServerX11 : public DisplayServer {
static Bool _predicate_all_events(Display *display, XEvent *event, XPointer arg);
static Bool _predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg);
+ static Bool _predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg);
static Bool _predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg);
protected:
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 0531762ed8..6908fbeada 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -265,6 +265,14 @@ String LightOccluder2D::get_configuration_warning() const {
return warning;
}
+void LightOccluder2D::set_as_sdf_collision(bool p_enable) {
+ sdf_collision = p_enable;
+ RS::get_singleton()->canvas_light_occluder_set_as_sdf_collision(occluder, sdf_collision);
+}
+bool LightOccluder2D::is_set_as_sdf_collision() const {
+ return sdf_collision;
+}
+
void LightOccluder2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_occluder_polygon", "polygon"), &LightOccluder2D::set_occluder_polygon);
ClassDB::bind_method(D_METHOD("get_occluder_polygon"), &LightOccluder2D::get_occluder_polygon);
@@ -272,14 +280,20 @@ void LightOccluder2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &LightOccluder2D::set_occluder_light_mask);
ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &LightOccluder2D::get_occluder_light_mask);
+ ClassDB::bind_method(D_METHOD("set_as_sdf_collision", "enable"), &LightOccluder2D::set_as_sdf_collision);
+ ClassDB::bind_method(D_METHOD("is_set_as_sdf_collision"), &LightOccluder2D::is_set_as_sdf_collision);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"), "set_occluder_polygon", "get_occluder_polygon");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdf_collision"), "set_as_sdf_collision", "is_set_as_sdf_collision");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask");
}
LightOccluder2D::LightOccluder2D() {
occluder = RS::get_singleton()->canvas_light_occluder_create();
mask = 1;
+
set_notify_transform(true);
+ set_as_sdf_collision(true);
}
LightOccluder2D::~LightOccluder2D() {
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index 694097f985..97574af542 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -84,7 +84,7 @@ class LightOccluder2D : public Node2D {
bool enabled;
int mask;
Ref<OccluderPolygon2D> occluder_polygon;
-
+ bool sdf_collision;
void _poly_changed();
protected:
@@ -103,6 +103,9 @@ public:
void set_occluder_light_mask(int p_mask);
int get_occluder_light_mask() const;
+ void set_as_sdf_collision(bool p_enable);
+ bool is_set_as_sdf_collision() const;
+
String get_configuration_warning() const override;
LightOccluder2D();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index cea6c6f0ae..9e396d4030 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1397,6 +1397,14 @@ SceneTree::SceneTree() {
bool snap_2d_vertices = GLOBAL_DEF("rendering/quality/2d/snap_2d_vertices_to_pixel", false);
root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
+ Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF("rendering/quality/2d_sdf/oversize", 1)));
+ root->set_sdf_oversize(sdf_oversize);
+ Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF("rendering/quality/2d_sdf/scale", 1)));
+ root->set_sdf_scale(sdf_scale);
+
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d_sdf/oversize", PropertyInfo(Variant::INT, "rendering/quality/2d_sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d_sdf/scale", PropertyInfo(Variant::INT, "rendering/quality/2d_sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%"));
+
{ //load default fallback environment
//get possible extensions
List<String> exts;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index c6d1bb6f9d..8049d4c817 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3388,6 +3388,24 @@ void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
}
}
+void Viewport::set_sdf_oversize(SDFOversize p_sdf_oversize) {
+ ERR_FAIL_INDEX(p_sdf_oversize, SDF_OVERSIZE_MAX);
+ sdf_oversize = p_sdf_oversize;
+ RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
+}
+Viewport::SDFOversize Viewport::get_sdf_oversize() const {
+ return sdf_oversize;
+}
+
+void Viewport::set_sdf_scale(SDFScale p_sdf_scale) {
+ ERR_FAIL_INDEX(p_sdf_scale, SDF_SCALE_MAX);
+ sdf_scale = p_sdf_scale;
+ RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
+}
+Viewport::SDFScale Viewport::get_sdf_scale() const {
+ return sdf_scale;
+}
+
void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d);
ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d);
@@ -3487,6 +3505,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_repeat", "mode"), &Viewport::set_default_canvas_item_texture_repeat);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_repeat"), &Viewport::get_default_canvas_item_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_sdf_oversize", "oversize"), &Viewport::set_sdf_oversize);
+ ClassDB::bind_method(D_METHOD("get_sdf_oversize"), &Viewport::get_sdf_oversize);
+
+ ClassDB::bind_method(D_METHOD("set_sdf_scale", "scale"), &Viewport::set_sdf_scale);
+ ClassDB::bind_method(D_METHOD("get_sdf_scale"), &Viewport::get_sdf_scale);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
@@ -3511,6 +3535,9 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_embed_subwindows"), "set_embed_subwindows_hint", "get_embed_subwindows_hint");
+ ADD_GROUP("SDF", "sdf_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"), "set_sdf_oversize", "get_sdf_oversize");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), "set_sdf_scale", "get_sdf_scale");
ADD_GROUP("Shadow Atlas", "shadow_atlas_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 0);
@@ -3580,6 +3607,17 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_100_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_120_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_150_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_200_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_MAX);
+
+ BIND_ENUM_CONSTANT(SDF_SCALE_100_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_SCALE_50_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_SCALE_25_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_SCALE_MAX);
}
Viewport::Viewport() {
@@ -3666,6 +3704,10 @@ Viewport::Viewport() {
default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+
+ sdf_oversize = SDF_OVERSIZE_120_PERCENT;
+ sdf_scale = SDF_SCALE_50_PERCENT;
+ set_sdf_oversize(SDF_OVERSIZE_120_PERCENT); //set to server
}
Viewport::~Viewport() {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 4be66ae79f..7ce202d27c 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -159,6 +159,21 @@ public:
DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX,
};
+ enum SDFOversize {
+ SDF_OVERSIZE_100_PERCENT,
+ SDF_OVERSIZE_120_PERCENT,
+ SDF_OVERSIZE_150_PERCENT,
+ SDF_OVERSIZE_200_PERCENT,
+ SDF_OVERSIZE_MAX
+ };
+
+ enum SDFScale {
+ SDF_SCALE_100_PERCENT,
+ SDF_SCALE_50_PERCENT,
+ SDF_SCALE_25_PERCENT,
+ SDF_SCALE_MAX
+ };
+
enum {
SUBWINDOW_CANVAS_LAYER = 1024
};
@@ -285,6 +300,9 @@ private:
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
+ SDFOversize sdf_oversize;
+ SDFScale sdf_scale;
+
enum SubWindowDrag {
SUB_WINDOW_DRAG_DISABLED,
SUB_WINDOW_DRAG_MOVE,
@@ -572,6 +590,12 @@ public:
bool gui_is_dragging() const;
+ void set_sdf_oversize(SDFOversize p_sdf_oversize);
+ SDFOversize get_sdf_oversize() const;
+
+ void set_sdf_scale(SDFScale p_sdf_scale);
+ SDFScale get_sdf_scale() const;
+
void set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter);
DefaultCanvasItemTextureFilter get_default_canvas_item_texture_filter() const;
@@ -650,6 +674,8 @@ VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
VARIANT_ENUM_CAST(Viewport::MSAA);
VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA);
VARIANT_ENUM_CAST(Viewport::DebugDraw);
+VARIANT_ENUM_CAST(Viewport::SDFScale);
+VARIANT_ENUM_CAST(Viewport::SDFOversize);
VARIANT_ENUM_CAST(SubViewport::ClearMode);
VARIANT_ENUM_CAST(Viewport::RenderInfo);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter);
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 1d5f29ab14..cf8be8fe15 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -838,6 +838,11 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p
f->seek(tag_end);
uint8_t c = f->get_8();
+ if (c == '\n' && !f->eof_reached()) {
+ // Skip first newline character since we added one
+ c = f->get_8();
+ }
+
while (!f->eof_reached()) {
fw->store_8(c);
c = f->get_8();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 704d1b2ea8..a3358ea8c7 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -724,6 +724,10 @@ Vector<StringName> VisualShaderNodeTexture::get_editable_properties() const {
}
String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+ if (is_input_port_connected(2) && source != SOURCE_PORT) {
+ return TTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'.");
+ }
+
if (source == SOURCE_TEXTURE) {
return String(); // all good
}
@@ -980,6 +984,10 @@ void VisualShaderNodeSample3D::_bind_methods() {
}
String VisualShaderNodeSample3D::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+ if (is_input_port_connected(2) && source != SOURCE_PORT) {
+ return TTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'.");
+ }
+
if (source == SOURCE_TEXTURE) {
return String(); // all good
}
@@ -1276,6 +1284,13 @@ Vector<StringName> VisualShaderNodeCubemap::get_editable_properties() const {
return props;
}
+String VisualShaderNodeCubemap::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+ if (is_input_port_connected(2) && source != SOURCE_PORT) {
+ return TTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'.");
+ }
+ return String();
+}
+
void VisualShaderNodeCubemap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_source", "value"), &VisualShaderNodeCubemap::set_source);
ClassDB::bind_method(D_METHOD("get_source"), &VisualShaderNodeCubemap::get_source);
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index d4d6540baf..4b39c76388 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -448,6 +448,7 @@ public:
TextureType get_texture_type() const;
virtual Vector<StringName> get_editable_properties() const override;
+ virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
VisualShaderNodeCubemap();
};
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index 01c957e242..4df140f8c3 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -752,6 +752,9 @@ public:
virtual void render_target_disable_clear_request(RID p_render_target) = 0;
virtual void render_target_do_clear_request(RID p_render_target) = 0;
+ virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0;
+ virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0;
+
virtual RS::InstanceType get_base_type(RID p_rid) const = 0;
virtual bool free(RID p_rid) = 0;
@@ -1324,7 +1327,7 @@ public:
}
};
- virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) = 0;
+ virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) = 0;
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
struct LightOccluderInstance {
@@ -1336,12 +1339,14 @@ public:
Transform2D xform;
Transform2D xform_cache;
int light_mask;
+ bool sdf_collision;
RS::CanvasOccluderPolygonCullMode cull_cache;
LightOccluderInstance *next;
LightOccluderInstance() {
enabled = true;
+ sdf_collision = false;
next = nullptr;
light_mask = 1;
cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
@@ -1354,8 +1359,10 @@ public:
virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0;
virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0;
+ virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0;
+
virtual RID occluder_polygon_create() = 0;
- virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) = 0;
+ virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0;
virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0;
virtual void set_shadow_texture_size(int p_size) = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
index 174f2d0e58..921a7b966e 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
@@ -30,6 +30,7 @@
#include "rasterizer_canvas_rd.h"
#include "core/config/project_settings.h"
+#include "core/math/geometry_2d.h"
#include "core/math/math_funcs.h"
#include "rasterizer_rd.h"
@@ -1051,10 +1052,19 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_
}
{
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 7;
+ RID sdf = storage->render_target_get_sdf_texture(p_to_render_target);
+ u.ids.push_back(sdf);
+ uniforms.push_back(u);
+ }
+
+ {
//needs samplers for the material (uses custom textures) create them
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 7;
+ u.binding = 8;
u.ids.resize(12);
RID *ids_ptr = u.ids.ptrw();
ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
@@ -1075,7 +1085,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 8;
+ u.binding = 9;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
@@ -1182,7 +1192,8 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
RD::get_singleton()->draw_list_end();
}
-void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {
+void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) {
+ r_sdf_used = false;
int item_count = 0;
//setup canvas state uniforms if needed
@@ -1365,6 +1376,25 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
state_buffer.directional_light_count = directional_light_count;
+ Vector2 canvas_scale = p_canvas_transform.get_scale();
+
+ state_buffer.sdf_to_screen[0] = render_target_size.width / canvas_scale.x;
+ state_buffer.sdf_to_screen[1] = render_target_size.height / canvas_scale.y;
+
+ state_buffer.screen_to_sdf[0] = 1.0 / state_buffer.sdf_to_screen[0];
+ state_buffer.screen_to_sdf[1] = 1.0 / state_buffer.sdf_to_screen[1];
+
+ Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_to_render_target);
+ Rect2 sdf_tex_rect(sdf_rect.position / canvas_scale, sdf_rect.size / canvas_scale);
+
+ state_buffer.sdf_to_tex[0] = 1.0 / sdf_tex_rect.size.width;
+ state_buffer.sdf_to_tex[1] = 1.0 / sdf_tex_rect.size.height;
+ state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width;
+ state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height;
+
+ //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
+ state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
+
RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
}
@@ -1402,6 +1432,9 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
}
}
+ if (md->shader_data->uses_sdf) {
+ r_sdf_used = true;
+ }
if (md->last_frame != RasterizerRD::singleton->get_frame_number()) {
md->last_frame = RasterizerRD::singleton->get_frame_number();
if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
@@ -1687,18 +1720,102 @@ void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow
cl->shadow.directional_xform = to_shadow * to_light_xform;
}
+void RasterizerCanvasRD::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) {
+ RID fb = storage->render_target_get_sdf_framebuffer(p_render_target);
+ Rect2i rect = storage->render_target_get_sdf_rect(p_render_target);
+
+ Transform2D to_sdf;
+ to_sdf.elements[0] *= rect.size.width;
+ to_sdf.elements[1] *= rect.size.height;
+ to_sdf.elements[2] = rect.position;
+
+ Transform2D to_clip;
+ to_clip.elements[0] *= 2.0;
+ to_clip.elements[1] *= 2.0;
+ to_clip.elements[2] = -Vector2(1.0, 1.0);
+
+ to_clip = to_clip * to_sdf.affine_inverse();
+
+ Vector<Color> cc;
+ cc.push_back(Color(0, 0, 0, 0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc);
+
+ CameraMatrix projection;
+
+ ShadowRenderPushConstant push_constant;
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ push_constant.projection[y * 4 + x] = projection.matrix[y][x];
+ }
+ }
+
+ push_constant.direction[0] = 0.0;
+ push_constant.direction[1] = 0.0;
+ push_constant.z_far = 0;
+ push_constant.pad = 0;
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
+
+ if (!co || co->sdf_index_array.is_null()) {
+ instance = instance->next;
+ continue;
+ }
+
+ _update_transform_2d_to_mat2x4(to_clip * instance->xform_cache, push_constant.modelview);
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.sdf_render_pipelines[co->sdf_is_lines ? SHADOW_RENDER_SDF_LINES : SHADOW_RENDER_SDF_TRIANGLES]);
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->sdf_vertex_array);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, co->sdf_index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ instance = instance->next;
+ }
+
+ RD::get_singleton()->draw_list_end();
+
+ storage->render_target_sdf_process(p_render_target); //done rendering, process it
+}
+
RID RasterizerCanvasRD::occluder_polygon_create() {
OccluderPolygon occluder;
- occluder.point_count = 0;
+ occluder.line_point_count = 0;
+ occluder.sdf_point_count = 0;
+ occluder.sdf_index_count = 0;
occluder.cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
return occluder_polygon_owner.make_rid(occluder);
}
-void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) {
+void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
ERR_FAIL_COND(!oc);
- if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) {
+ Vector<Vector2> lines;
+ int lc = p_points.size() * 2;
+
+ lines.resize(lc - (p_closed ? 0 : 2));
+ {
+ Vector2 *w = lines.ptrw();
+ const Vector2 *r = p_points.ptr();
+
+ int max = lc / 2;
+ if (!p_closed) {
+ max--;
+ }
+ for (int i = 0; i < max; i++) {
+ Vector2 a = r[i];
+ Vector2 b = r[(i + 1) % (lc / 2)];
+ w[i * 2 + 0] = a;
+ w[i * 2 + 1] = b;
+ }
+ }
+
+ if (oc->line_point_count != lines.size() && oc->vertex_array.is_valid()) {
RD::get_singleton()->free(oc->vertex_array);
RD::get_singleton()->free(oc->vertex_buffer);
RD::get_singleton()->free(oc->index_array);
@@ -1708,12 +1825,14 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con
oc->vertex_buffer = RID();
oc->index_array = RID();
oc->index_buffer = RID();
+
+ oc->line_point_count = lines.size();
}
- if (p_lines.size()) {
+ if (lines.size()) {
Vector<uint8_t> geometry;
Vector<uint8_t> indices;
- int lc = p_lines.size();
+ lc = lines.size();
geometry.resize(lc * 6 * sizeof(float));
indices.resize(lc * 3 * sizeof(uint16_t));
@@ -1724,7 +1843,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con
uint8_t *iw = indices.ptrw();
uint16_t *iwptr = (uint16_t *)iw;
- const Vector2 *lr = p_lines.ptr();
+ const Vector2 *lr = lines.ptr();
const int POLY_HEIGHT = 16384;
@@ -1778,6 +1897,62 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con
RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir);
}
}
+
+ // sdf
+
+ Vector<int> sdf_indices;
+
+ if (p_closed) {
+ sdf_indices = Geometry2D::triangulate_polygon(p_points);
+ oc->sdf_is_lines = false;
+ } else {
+ int max = p_points.size();
+ sdf_indices.resize(max * 2);
+
+ int *iw = sdf_indices.ptrw();
+ for (int i = 0; i < max; i++) {
+ iw[i * 2 + 0] = i;
+ iw[i * 2 + 1] = (i + 1) % max;
+ }
+ oc->sdf_is_lines = true;
+ }
+
+ if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) {
+ RD::get_singleton()->free(oc->sdf_vertex_array);
+ RD::get_singleton()->free(oc->sdf_vertex_buffer);
+ RD::get_singleton()->free(oc->sdf_index_array);
+ RD::get_singleton()->free(oc->sdf_index_buffer);
+
+ oc->sdf_vertex_array = RID();
+ oc->sdf_vertex_buffer = RID();
+ oc->sdf_index_array = RID();
+ oc->sdf_index_buffer = RID();
+
+ oc->sdf_index_count = sdf_indices.size();
+ oc->sdf_point_count = p_points.size();
+
+ oc->sdf_is_lines = false;
+ }
+
+ if (sdf_indices.size()) {
+ if (oc->sdf_vertex_array.is_null()) {
+ //create from scratch
+ //vertices
+ oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(real_t), p_points.to_byte_array());
+ oc->sdf_index_buffer = RD::get_singleton()->index_buffer_create(sdf_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, sdf_indices.to_byte_array());
+ oc->sdf_index_array = RD::get_singleton()->index_array_create(oc->sdf_index_buffer, 0, sdf_indices.size());
+
+ Vector<RID> buffer;
+ buffer.push_back(oc->sdf_vertex_buffer);
+ oc->sdf_vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), shadow_render.sdf_vertex_format, buffer);
+ //indices
+
+ } else {
+ //update existing
+ RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr());
+ RD::get_singleton()->buffer_update(oc->index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr());
+ }
+ }
}
void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
@@ -1794,6 +1969,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
ubo_size = 0;
uniforms.clear();
uses_screen_texture = false;
+ uses_sdf = false;
if (code == String()) {
return; //just invalid, but no error
@@ -1801,7 +1977,6 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
ShaderCompilerRD::GeneratedCode gen_code;
- int light_mode = LIGHT_MODE_NORMAL;
int blend_mode = BLEND_MODE_MIX;
uses_screen_texture = false;
@@ -1814,10 +1989,8 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
- actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED);
- actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY);
-
actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
actions.uniforms = &uniforms;
@@ -2038,6 +2211,7 @@ Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName &
RasterizerCanvasRD::ShaderData::ShaderData() {
valid = false;
uses_screen_texture = false;
+ uses_sdf = false;
}
RasterizerCanvasRD::ShaderData::~ShaderData() {
@@ -2302,6 +2476,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
actions.renames["LIGHT"] = "light";
actions.renames["SHADOW_MODULATE"] = "shadow_modulate";
+ actions.renames["texture_sdf"] = "texture_sdf";
+ actions.renames["texture_sdf_normal"] = "texture_sdf_normal";
+ actions.renames["sdf_to_screen_uv"] = "sdf_to_screen_uv";
+ actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf";
+
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
@@ -2311,6 +2490,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+ actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
actions.custom_samplers["TEXTURE"] = "texture_sampler";
actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
@@ -2331,7 +2512,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
{ //shadow rendering
Vector<String> versions;
- versions.push_back(String()); //no versions
+ versions.push_back("\n#define MODE_SHADOW\n"); //shadow
+ versions.push_back("\n#define MODE_SDF\n"); //sdf
shadow_render.shader.initialize(versions);
{
@@ -2352,16 +2534,34 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments);
}
+ {
+ Vector<RD::AttachmentFormat> attachments;
+
+ RD::AttachmentFormat af_color;
+ af_color.format = RD::DATA_FORMAT_R8_UNORM;
+ af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ attachments.push_back(af_color);
+
+ shadow_render.sdf_framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments);
+ }
+
//pipelines
Vector<RD::VertexAttribute> vf;
RD::VertexAttribute vd;
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32B32_SFLOAT : RD::DATA_FORMAT_R64G64B64_SFLOAT;
vd.location = 0;
vd.offset = 0;
- vd.stride = sizeof(float) * 3;
+ vd.stride = sizeof(real_t) * 3;
vf.push_back(vd);
shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf);
+ vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32_SFLOAT : RD::DATA_FORMAT_R64G64_SFLOAT;
+ vd.stride = sizeof(real_t) * 2;
+
+ vf.write[0] = vd;
+ shadow_render.sdf_vertex_format = RD::get_singleton()->vertex_format_create(vf);
+
shadow_render.shader_version = shadow_render.shader.version_create();
for (int i = 0; i < 3; i++) {
@@ -2371,7 +2571,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
ds.enable_depth_write = true;
ds.enable_depth_test = true;
ds.depth_compare_operator = RD::COMPARE_OP_LESS;
- shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SHADOW), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ shadow_render.sdf_render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SDF), shadow_render.sdf_framebuffer_format, shadow_render.sdf_vertex_format, i == 0 ? RD::RENDER_PRIMITIVE_TRIANGLES : RD::RENDER_PRIMITIVE_LINES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
}
}
@@ -2482,7 +2686,7 @@ bool RasterizerCanvasRD::free(RID p_rid) {
light_set_use_shadow(p_rid, false);
canvas_light_owner.free(p_rid);
} else if (occluder_polygon_owner.owns(p_rid)) {
- occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>());
+ occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false);
occluder_polygon_owner.free(p_rid);
} else {
return false;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
index b516f63cbf..b09d6578f3 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
@@ -161,12 +161,6 @@ class RasterizerCanvasRD : public RasterizerCanvas {
BLEND_MODE_DISABLED,
};
- enum LightMode {
- LIGHT_MODE_NORMAL,
- LIGHT_MODE_UNSHADED,
- LIGHT_MODE_LIGHT_ONLY
- };
-
bool valid;
RID version;
PipelineVariants pipeline_variants;
@@ -181,7 +175,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
String code;
Map<StringName, RID> default_texture_params;
- bool uses_screen_texture;
+ bool uses_screen_texture = false;
+ bool uses_sdf = false;
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
@@ -284,11 +279,19 @@ class RasterizerCanvasRD : public RasterizerCanvas {
struct OccluderPolygon {
RS::CanvasOccluderPolygonCullMode cull_mode;
- int point_count;
+ int line_point_count;
RID vertex_buffer;
RID vertex_array;
RID index_buffer;
RID index_array;
+
+ int sdf_point_count;
+ int sdf_index_count;
+ RID sdf_vertex_buffer;
+ RID sdf_vertex_array;
+ RID sdf_index_buffer;
+ RID sdf_index_array;
+ bool sdf_is_lines;
};
struct LightUniform {
@@ -310,12 +313,25 @@ class RasterizerCanvasRD : public RasterizerCanvas {
RID_Owner<OccluderPolygon> occluder_polygon_owner;
+ enum ShadowRenderMode {
+ SHADOW_RENDER_MODE_SHADOW,
+ SHADOW_RENDER_MODE_SDF,
+ };
+
+ enum {
+ SHADOW_RENDER_SDF_TRIANGLES,
+ SHADOW_RENDER_SDF_LINES,
+ };
+
struct {
CanvasOcclusionShaderRD shader;
RID shader_version;
RID render_pipelines[3];
+ RID sdf_render_pipelines[2];
RD::VertexFormatID vertex_format;
+ RD::VertexFormatID sdf_vertex_format;
RD::FramebufferFormatID framebuffer_format;
+ RD::FramebufferFormatID sdf_framebuffer_format;
} shadow_render;
/***************/
@@ -336,8 +352,14 @@ class RasterizerCanvasRD : public RasterizerCanvas {
float time;
uint32_t use_pixel_snap;
+ float sdf_to_tex[4];
+ float sdf_to_screen[2];
+ float screen_to_sdf[2];
+
uint32_t directional_light_count;
- uint32_t pad[3];
+ float tex_to_sdf;
+ uint32_t pad1;
+ uint32_t pad2;
};
LightUniform *light_uniforms;
@@ -423,11 +445,13 @@ public:
void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders);
void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders);
+ virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders);
+
RID occluder_polygon_create();
- void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines);
+ void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed);
void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode);
- void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
+ void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used);
void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index 5fd8003f8f..444ef9c49a 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -6029,6 +6029,8 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
rt->backbuffer_uniform_set = RID(); //chain deleted
}
+ _render_target_clear_sdf(rt);
+
rt->framebuffer = RID();
rt->color = RID();
}
@@ -6299,6 +6301,275 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
rt->clear_requested = false;
}
+void RasterizerStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) {
+ return;
+ }
+
+ rt->sdf_oversize = p_size;
+ rt->sdf_scale = p_scale;
+
+ _render_target_clear_sdf(rt);
+}
+
+Rect2i RasterizerStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) const {
+ Size2i margin;
+ int scale;
+ switch (rt->sdf_oversize) {
+ case RS::VIEWPORT_SDF_OVERSIZE_100_PERCENT: {
+ scale = 100;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT: {
+ scale = 120;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_150_PERCENT: {
+ scale = 150;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_200_PERCENT: {
+ scale = 200;
+ } break;
+ default: {
+ }
+ }
+
+ margin = (rt->size * scale / 100) - rt->size;
+
+ Rect2i r(Vector2i(), rt->size);
+ r.position -= margin;
+ r.size += margin * 2;
+
+ return r;
+}
+
+Rect2i RasterizerStorageRD::render_target_get_sdf_rect(RID p_render_target) const {
+ const RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, Rect2i());
+
+ return _render_target_get_sdf_rect(rt);
+}
+
+RID RasterizerStorageRD::render_target_get_sdf_texture(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+ if (rt->sdf_buffer_read.is_null()) {
+ // no texture, create a dummy one for the 2D uniform set
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+ tformat.type = RD::TEXTURE_TYPE_2D;
+
+ Vector<uint8_t> pv;
+ pv.resize(16 * 4);
+ zeromem(pv.ptrw(), 16 * 4);
+ Vector<Vector<uint8_t>> vpv;
+
+ rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ return rt->sdf_buffer_read;
+}
+
+void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
+ ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_valid());
+ if (rt->sdf_buffer_read.is_valid()) {
+ RD::get_singleton()->free(rt->sdf_buffer_read);
+ rt->sdf_buffer_read = RID();
+ }
+
+ Size2i size = _render_target_get_sdf_rect(rt).size;
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8_UNORM;
+ tformat.width = size.width;
+ tformat.height = size.height;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tformat.type = RD::TEXTURE_TYPE_2D;
+
+ rt->sdf_buffer_write = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+
+ {
+ Vector<RID> write_fb;
+ write_fb.push_back(rt->sdf_buffer_write);
+ rt->sdf_buffer_write_fb = RD::get_singleton()->framebuffer_create(write_fb);
+ }
+
+ int scale;
+ switch (rt->sdf_scale) {
+ case RS::VIEWPORT_SDF_SCALE_100_PERCENT: {
+ scale = 100;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
+ scale = 50;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
+ scale = 25;
+ } break;
+ default: {
+ scale = 100;
+ } break;
+ }
+
+ rt->process_size = size * scale / 100;
+ rt->process_size.x = MAX(rt->process_size.x, 1);
+ rt->process_size.y = MAX(rt->process_size.y, 1);
+
+ tformat.format = RD::DATA_FORMAT_R16G16_UINT;
+ tformat.width = rt->process_size.width;
+ tformat.height = rt->process_size.height;
+ tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+ rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+
+ tformat.format = RD::DATA_FORMAT_R16_UNORM;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(rt->sdf_buffer_write);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(rt->sdf_buffer_read);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(rt->sdf_buffer_process[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 4;
+ u.ids.push_back(rt->sdf_buffer_process[1]);
+ uniforms.push_back(u);
+ }
+
+ rt->sdf_buffer_process_uniform_sets[0] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0);
+ SWAP(uniforms.write[2].ids.write[0], uniforms.write[3].ids.write[0]);
+ rt->sdf_buffer_process_uniform_sets[1] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0);
+ }
+}
+
+void RasterizerStorageRD::_render_target_clear_sdf(RenderTarget *rt) {
+ if (rt->sdf_buffer_read.is_valid()) {
+ RD::get_singleton()->free(rt->sdf_buffer_read);
+ rt->sdf_buffer_read = RID();
+ }
+ if (rt->sdf_buffer_write_fb.is_valid()) {
+ RD::get_singleton()->free(rt->sdf_buffer_write);
+ RD::get_singleton()->free(rt->sdf_buffer_process[0]);
+ RD::get_singleton()->free(rt->sdf_buffer_process[1]);
+ rt->sdf_buffer_write = RID();
+ rt->sdf_buffer_write_fb = RID();
+ rt->sdf_buffer_process[0] = RID();
+ rt->sdf_buffer_process[1] = RID();
+ rt->sdf_buffer_process_uniform_sets[0] = RID();
+ rt->sdf_buffer_process_uniform_sets[1] = RID();
+ }
+}
+
+RID RasterizerStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ if (rt->sdf_buffer_write_fb.is_null()) {
+ _render_target_allocate_sdf(rt);
+ }
+
+ return rt->sdf_buffer_write_fb;
+}
+void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null());
+
+ RenderTargetSDF::PushConstant push_constant;
+
+ Rect2i r = _render_target_get_sdf_rect(rt);
+
+ push_constant.size[0] = r.size.width;
+ push_constant.size[1] = r.size.height;
+ push_constant.stride = 0;
+ push_constant.shift = 0;
+ push_constant.base_size[0] = r.size.width;
+ push_constant.base_size[1] = r.size.height;
+
+ bool shrink = false;
+
+ switch (rt->sdf_scale) {
+ case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
+ push_constant.size[0] >>= 1;
+ push_constant.size[1] >>= 1;
+ push_constant.shift = 1;
+ shrink = true;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
+ push_constant.size[0] >>= 2;
+ push_constant.size[1] >>= 2;
+ push_constant.shift = 2;
+ shrink = true;
+ } break;
+ default: {
+ };
+ }
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ /* Load */
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_LOAD_SHRINK : RenderTargetSDF::SHADER_LOAD]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[1], 0); //fill [0]
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1);
+
+ /* Process */
+
+ int stride = nearest_power_of_2_templated(MAX(push_constant.size[0], push_constant.size[1]) / 2);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[RenderTargetSDF::SHADER_PROCESS]);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ bool swap = false;
+
+ //jumpflood
+ while (stride > 0) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0);
+ push_constant.stride = stride;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1);
+ stride /= 2;
+ swap = !swap;
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ /* Store */
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_STORE_SHRINK : RenderTargetSDF::SHADER_STORE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
@@ -8155,6 +8426,24 @@ RasterizerStorageRD::RasterizerStorageRD() {
particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i));
}
}
+
+ {
+ Vector<String> sdf_modes;
+ sdf_modes.push_back("\n#define MODE_LOAD\n");
+ sdf_modes.push_back("\n#define MODE_LOAD_SHRINK\n");
+ sdf_modes.push_back("\n#define MODE_PROCESS\n");
+ sdf_modes.push_back("\n#define MODE_PROCESS_OPTIMIZED\n");
+ sdf_modes.push_back("\n#define MODE_STORE\n");
+ sdf_modes.push_back("\n#define MODE_STORE_SHRINK\n");
+
+ rt_sdf.shader.initialize(sdf_modes);
+
+ rt_sdf.shader_version = rt_sdf.shader.version_create();
+
+ for (int i = 0; i < RenderTargetSDF::SHADER_MAX; i++) {
+ rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i));
+ }
+ }
}
RasterizerStorageRD::~RasterizerStorageRD() {
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index b7ad931149..4a708fc94f 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -35,6 +35,7 @@
#include "servers/rendering/rasterizer.h"
#include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h"
#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h"
+#include "servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h"
@@ -1003,6 +1004,15 @@ private:
RID framebuffer_uniform_set;
RID backbuffer_uniform_set;
+ RID sdf_buffer_write;
+ RID sdf_buffer_write_fb;
+ RID sdf_buffer_process[2];
+ RID sdf_buffer_read;
+ RID sdf_buffer_process_uniform_sets[2];
+ RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
+ RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
+ Size2i process_size;
+
//texture generated for this owner (nor RD).
RID texture;
bool was_used;
@@ -1012,11 +1022,38 @@ private:
Color clear_color;
};
- RID_Owner<RenderTarget> render_target_owner;
+ mutable RID_Owner<RenderTarget> render_target_owner;
void _clear_render_target(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
+ void _render_target_allocate_sdf(RenderTarget *rt);
+ void _render_target_clear_sdf(RenderTarget *rt);
+ Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const;
+
+ struct RenderTargetSDF {
+ enum {
+ SHADER_LOAD,
+ SHADER_LOAD_SHRINK,
+ SHADER_PROCESS,
+ SHADER_PROCESS_OPTIMIZED,
+ SHADER_STORE,
+ SHADER_STORE_SHRINK,
+ SHADER_MAX
+ };
+
+ struct PushConstant {
+ int32_t size[2];
+ int32_t stride;
+ int32_t shift;
+ int32_t base_size[2];
+ int32_t pad[2];
+ };
+
+ CanvasSdfShaderRD shader;
+ RID shader_version;
+ RID pipelines[SHADER_MAX];
+ } rt_sdf;
/* GLOBAL SHADER VARIABLES */
@@ -1930,6 +1967,12 @@ public:
virtual void render_target_disable_clear_request(RID p_render_target);
virtual void render_target_do_clear_request(RID p_render_target);
+ virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale);
+ RID render_target_get_sdf_texture(RID p_render_target);
+ RID render_target_get_sdf_framebuffer(RID p_render_target);
+ void render_target_sdf_process(RID p_render_target);
+ virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const;
+
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
RID render_target_get_rd_texture(RID p_render_target);
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
index 08f4eb6aa0..df5513435a 100644
--- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
@@ -1072,6 +1072,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
} else if (onode->op == SL::OP_CONSTRUCT) {
code += String(vnode->name);
} else {
+ if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) {
+ *p_actions.usage_flag_pointers[vnode->name] = true;
+ used_flag_pointers.insert(vnode->name);
+ }
+
if (internal_functions.has(vnode->name)) {
code += vnode->name;
is_texture_func = texture_functions.has(vnode->name);
diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub
index 9d531d63ad..4cddf0f685 100644
--- a/servers/rendering/rasterizer_rd/shaders/SCsub
+++ b/servers/rendering/rasterizer_rd/shaders/SCsub
@@ -5,6 +5,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
env.RD_GLSL("canvas.glsl")
env.RD_GLSL("canvas_occlusion.glsl")
+ env.RD_GLSL("canvas_sdf.glsl")
env.RD_GLSL("copy.glsl")
env.RD_GLSL("copy_to_fb.glsl")
env.RD_GLSL("cubemap_roughness.glsl")
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
index 2a0f94e733..51d7193a03 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
@@ -233,6 +233,30 @@ MATERIAL_UNIFORMS
} material;
#endif
+vec2 screen_uv_to_sdf(vec2 p_uv) {
+ return canvas_data.screen_to_sdf * p_uv;
+}
+
+float texture_sdf(vec2 p_sdf) {
+ vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
+ float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
+ d = d * SDF_MAX_LENGTH - 1.0;
+ return d * canvas_data.tex_to_sdf;
+}
+
+vec2 texture_sdf_normal(vec2 p_sdf) {
+ vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
+
+ const float EPSILON = 0.001;
+ return normalize(vec2(
+ texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r));
+}
+
+vec2 sdf_to_screen_uv(vec2 p_sdf) {
+ return p_sdf * canvas_data.sdf_to_screen;
+}
+
/* clang-format off */
FRAGMENT_SHADER_GLOBALS
/* clang-format on */
@@ -500,8 +524,13 @@ FRAGMENT_SHADER_CODE
color = vec4(0.0); //invisible by default due to using light mask
}
+#ifdef MODE_LIGHT_ONLY
+ color = vec4(0.0);
+#else
color *= canvas_data.canvas_modulation;
-#ifdef USE_LIGHTING
+#endif
+
+#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED)
// Directional Lights
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
index 421282cd4d..5c25235c58 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
@@ -2,6 +2,8 @@
#version 450
+VERSION_DEFINES
+
layout(location = 0) in highp vec3 vertex;
layout(push_constant, binding = 0, std430) uniform Constants {
@@ -13,12 +15,16 @@ layout(push_constant, binding = 0, std430) uniform Constants {
}
constants;
+#ifdef MODE_SHADOW
layout(location = 0) out highp float depth;
+#endif
void main() {
highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
- depth = dot(constants.direction, vtx.xy);
+#ifdef MODE_SHADOW
+ depth = dot(constants.direction, vtx.xy);
+#endif
gl_Position = constants.projection * vtx;
}
@@ -26,6 +32,8 @@ void main() {
#version 450
+VERSION_DEFINES
+
layout(push_constant, binding = 0, std430) uniform Constants {
mat4 projection;
mat2x4 modelview;
@@ -35,9 +43,17 @@ layout(push_constant, binding = 0, std430) uniform Constants {
}
constants;
+#ifdef MODE_SHADOW
layout(location = 0) in highp float depth;
layout(location = 0) out highp float distance_buf;
+#else
+layout(location = 0) out highp float sdf_buf;
+#endif
void main() {
+#ifdef MODE_SHADOW
distance_buf = depth / constants.z_far;
+#else
+ sdf_buf = 1.0;
+#endif
}
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl
new file mode 100644
index 0000000000..302ad03b41
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl
@@ -0,0 +1,135 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels;
+layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
+
+layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process;
+layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process;
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ ivec2 size;
+ int stride;
+ int shift;
+ ivec2 base_size;
+ uvec2 pad;
+}
+params;
+
+#define SDF_MAX_LENGTH 16384.0
+
+void main() {
+ ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThanEqual(pos, params.size))) { //too large, do nothing
+ return;
+ }
+
+#ifdef MODE_LOAD
+
+ bool solid = imageLoad(src_pixels, pos).r > 0.5;
+ imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0));
+#endif
+
+#ifdef MODE_LOAD_SHRINK
+
+ int s = 1 << params.shift;
+ ivec2 base = pos << params.shift;
+ ivec2 center = base + ivec2(params.shift);
+
+ ivec2 rel = ivec2(32767);
+ float d = 1e20;
+ for (int i = 0; i < s; i++) {
+ for (int j = 0; j < s; j++) {
+ ivec2 src_pos = base + ivec2(i, j);
+ if (any(greaterThanEqual(src_pos, params.base_size))) {
+ continue;
+ }
+ bool solid = imageLoad(src_pixels, src_pos).r > 0.5;
+ if (solid) {
+ float dist = length(vec2(src_pos - center));
+ if (dist < d) {
+ d = dist;
+ rel = src_pos;
+ }
+ }
+ }
+ }
+
+ imageStore(dst_process, pos, ivec4(rel, 0, 0));
+#endif
+
+#ifdef MODE_PROCESS
+
+ ivec2 base = pos << params.shift;
+ ivec2 center = base + ivec2(params.shift);
+
+ ivec2 rel = imageLoad(src_process, pos).xy;
+
+ if (center != rel) {
+ //only process if it does not point to itself
+ const int ofs_table_size = 8;
+ const ivec2 ofs_table[ofs_table_size] = ivec2[](
+ ivec2(-1, -1),
+ ivec2(0, -1),
+ ivec2(+1, -1),
+
+ ivec2(-1, 0),
+ ivec2(+1, 0),
+
+ ivec2(-1, +1),
+ ivec2(0, +1),
+ ivec2(+1, +1));
+
+ float dist = length(vec2(rel - center));
+ for (int i = 0; i < ofs_table_size; i++) {
+ ivec2 src_pos = pos + ofs_table[i] * params.stride;
+ if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, params.size))) {
+ continue;
+ }
+ ivec2 src_rel = imageLoad(src_process, src_pos).xy;
+ float src_dist = length(vec2(src_rel - center));
+ if (src_dist < dist) {
+ dist = src_dist;
+ rel = src_rel;
+ }
+ }
+ }
+
+ imageStore(dst_process, pos, ivec4(rel, 0, 0));
+#endif
+
+#ifdef MODE_STORE
+
+ ivec2 rel = imageLoad(src_process, pos).xy;
+ float d = length(vec2(rel - pos));
+ if (d > 0.01) {
+ d += 1.0; //make it signed
+ }
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, 0.0, 1.0);
+ imageStore(dst_sdf, pos, vec4(d));
+
+#endif
+
+#ifdef MODE_STORE_SHRINK
+
+ ivec2 base = pos << params.shift;
+ ivec2 center = base + ivec2(params.shift);
+
+ ivec2 rel = imageLoad(src_process, pos).xy;
+ float d = length(vec2(rel - center));
+
+ if (d > 0.01) {
+ d += 1.0; //make it signed
+ }
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, 0.0, 1.0);
+ imageStore(dst_sdf, pos, vec4(d));
+
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
index bb39584cbb..cf7678ea31 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
@@ -3,6 +3,8 @@
#define M_PI 3.14159265359
+#define SDF_MAX_LENGTH 16384.0
+
#define FLAGS_INSTANCING_STRIDE_MASK 0xF
#define FLAGS_INSTANCING_ENABLED (1 << 4)
#define FLAGS_INSTANCING_HAS_COLORS (1 << 5)
@@ -24,6 +26,19 @@
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
// Push Constant
layout(push_constant, binding = 0, std430) uniform DrawData {
@@ -68,8 +83,12 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
float time;
bool use_pixel_snap;
+ vec4 sdf_to_tex;
+ vec2 screen_to_sdf;
+ vec2 sdf_to_screen;
+
uint directional_light_count;
- uint pad0;
+ float tex_to_sdf;
uint pad1;
uint pad2;
}
@@ -115,10 +134,11 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture;
layout(set = 0, binding = 5) uniform sampler shadow_sampler;
layout(set = 0, binding = 6) uniform texture2D screen_texture;
+layout(set = 0, binding = 7) uniform texture2D sdf_texture;
-layout(set = 0, binding = 7) uniform sampler material_samplers[12];
+layout(set = 0, binding = 8) uniform sampler material_samplers[12];
-layout(set = 0, binding = 8, std430) restrict readonly buffer GlobalVariableData {
+layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp
index 364839c5d7..ffc1ec391d 100644
--- a/servers/rendering/rendering_server_canvas.cpp
+++ b/servers/rendering/rendering_server_canvas.cpp
@@ -68,7 +68,11 @@ void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Can
RENDER_TIMESTAMP("Render Canvas Items");
- RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
+ bool sdf_flag;
+ RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, sdf_flag);
+ if (sdf_flag) {
+ sdf_used = true;
+ }
}
void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transform2D p_transform, RenderingServerCanvas::Item *p_material_owner, RenderingServerCanvas::Item **r_items, int &r_index) {
@@ -301,6 +305,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo
void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) {
RENDER_TIMESTAMP(">Render Canvas");
+ sdf_used = false;
snapping_2d_transforms_to_pixel = p_snap_2d_transforms_to_pixel;
if (p_canvas->children_order_dirty) {
@@ -347,6 +352,10 @@ void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas,
RENDER_TIMESTAMP("<End Render Canvas");
}
+bool RenderingServerCanvas::was_sdf_used() {
+ return sdf_used;
+}
+
RID RenderingServerCanvas::canvas_create() {
Canvas *canvas = memnew(Canvas);
ERR_FAIL_COND_V(!canvas, RID());
@@ -1266,6 +1275,11 @@ void RenderingServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RI
}
}
+void RenderingServerCanvas::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) {
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+}
+
void RenderingServerCanvas::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
ERR_FAIL_COND(!occluder);
@@ -1287,53 +1301,24 @@ RID RenderingServerCanvas::canvas_occluder_polygon_create() {
}
void RenderingServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
- if (p_shape.size() < 3) {
- canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, p_shape);
- return;
- }
-
- Vector<Vector2> lines;
- int lc = p_shape.size() * 2;
-
- lines.resize(lc - (p_closed ? 0 : 2));
- {
- Vector2 *w = lines.ptrw();
- const Vector2 *r = p_shape.ptr();
-
- int max = lc / 2;
- if (!p_closed) {
- max--;
- }
- for (int i = 0; i < max; i++) {
- Vector2 a = r[i];
- Vector2 b = r[(i + 1) % (lc / 2)];
- w[i * 2 + 0] = a;
- w[i * 2 + 1] = b;
- }
- }
-
- canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, lines);
-}
-
-void RenderingServerCanvas::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) {
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
ERR_FAIL_COND(!occluder_poly);
- ERR_FAIL_COND(p_shape.size() & 1);
- int lc = p_shape.size();
+ uint32_t pc = p_shape.size();
+ ERR_FAIL_COND(pc < 2);
+
occluder_poly->aabb = Rect2();
- {
- const Vector2 *r = p_shape.ptr();
- for (int i = 0; i < lc; i++) {
- if (i == 0) {
- occluder_poly->aabb.position = r[i];
- } else {
- occluder_poly->aabb.expand_to(r[i]);
- }
+ const Vector2 *r = p_shape.ptr();
+ for (uint32_t i = 0; i < pc; i++) {
+ if (i == 0) {
+ occluder_poly->aabb.position = r[i];
+ } else {
+ occluder_poly->aabb.expand_to(r[i]);
}
}
- RSG::canvas_render->occluder_polygon_set_shape_as_lines(occluder_poly->occluder, p_shape);
+ RSG::canvas_render->occluder_polygon_set_shape(occluder_poly->occluder, p_shape, p_closed);
+
for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
E->get()->aabb_cache = occluder_poly->aabb;
}
diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/rendering_server_canvas.h
index 36e2f77e95..83b76539c4 100644
--- a/servers/rendering/rendering_server_canvas.h
+++ b/servers/rendering/rendering_server_canvas.h
@@ -153,6 +153,7 @@ public:
RID_PtrOwner<RasterizerCanvas::Light> canvas_light_owner;
bool disable_scale;
+ bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
private:
@@ -165,6 +166,8 @@ private:
public:
void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel);
+ bool was_sdf_used();
+
RID canvas_create();
void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring);
void canvas_set_modulate(RID p_canvas, const Color &p_color);
@@ -247,12 +250,12 @@ public:
void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas);
void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled);
void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon);
+ void canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable);
void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform);
void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask);
RID canvas_occluder_polygon_create();
void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed);
- void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape);
void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode);
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index 60b25f1b94..413fcda581 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -536,6 +536,7 @@ public:
BIND2(viewport_set_global_canvas_transform, RID, const Transform2D &)
BIND4(viewport_set_canvas_stacking, RID, RID, int, int)
BIND2(viewport_set_shadow_atlas_size, RID, int)
+ BIND3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale)
BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
BIND2(viewport_set_msaa, RID, ViewportMSAA)
BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
@@ -776,12 +777,12 @@ public:
BIND2(canvas_light_occluder_attach_to_canvas, RID, RID)
BIND2(canvas_light_occluder_set_enabled, RID, bool)
BIND2(canvas_light_occluder_set_polygon, RID, RID)
+ BIND2(canvas_light_occluder_set_as_sdf_collision, RID, bool)
BIND2(canvas_light_occluder_set_transform, RID, const Transform2D &)
BIND2(canvas_light_occluder_set_light_mask, RID, int)
BIND0R(RID, canvas_occluder_polygon_create)
BIND3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
- BIND2(canvas_occluder_polygon_set_shape_as_lines, RID, const Vector<Vector2> &)
BIND2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/rendering_server_viewport.cpp
index c6682b1fcd..c048aa381f 100644
--- a/servers/rendering/rendering_server_viewport.cpp
+++ b/servers/rendering/rendering_server_viewport.cpp
@@ -146,6 +146,36 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
RasterizerCanvas::Light *directional_lights = nullptr;
RasterizerCanvas::Light *directional_lights_with_shadow = nullptr;
+ if (p_viewport->sdf_active) {
+ //process SDF
+
+ Rect2 sdf_rect = RSG::storage->render_target_get_sdf_rect(p_viewport->render_target);
+
+ RasterizerCanvas::LightOccluderInstance *occluders = nullptr;
+
+ //make list of occluders
+ for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
+ RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+
+ for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
+ if (!F->get()->enabled) {
+ continue;
+ }
+ F->get()->xform_cache = xf * F->get()->xform;
+
+ if (sdf_rect.intersects_transformed(F->get()->xform_cache, F->get()->aabb_cache)) {
+ F->get()->next = occluders;
+ occluders = F->get();
+ }
+ }
+ }
+
+ RSG::canvas_render->render_sdf(p_viewport->render_target, occluders);
+
+ p_viewport->sdf_active = false; // if used, gets set active again
+ }
+
Rect2 shadow_rect;
int light_count = 0;
@@ -195,7 +225,6 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
}
//guess this is not needed, but keeping because it may be
- //RSG::canvas_render->light_internal_update(cl->light_internal, cl);
}
}
@@ -256,7 +285,6 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
light = light->shadows_next_ptr;
}
- //RSG::canvas_render->reset_canvas();
RENDER_TIMESTAMP("<End rendering 2D Shadows");
}
@@ -340,7 +368,6 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
light = light->shadows_next_ptr;
}
- //RSG::canvas_render->reset_canvas();
RENDER_TIMESTAMP("<Render Directional 2D Shadows");
}
@@ -380,6 +407,9 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
}
RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, canvas_directional_lights, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel);
+ if (RSG::canvas->was_sdf_used()) {
+ p_viewport->sdf_active = true;
+ }
i++;
if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
@@ -400,8 +430,6 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
_draw_3d(p_viewport, p_eye);
}
}
-
- //RSG::canvas_render->canvas_debug_viewport_shadows(lights_with_shadow);
}
if (RSG::storage->render_target_is_clear_requested(p_viewport->render_target)) {
@@ -925,6 +953,13 @@ void RenderingServerViewport::viewport_set_default_canvas_item_texture_repeat(RI
viewport->texture_repeat = p_repeat;
}
+void RenderingServerViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ RSG::storage->render_target_set_sdf_size_and_scale(viewport->render_target, p_size, p_scale);
+}
+
bool RenderingServerViewport::free(RID p_rid) {
if (viewport_owner.owns(p_rid)) {
Viewport *viewport = viewport_owner.getornull(p_rid);
diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/rendering_server_viewport.h
index 081f63690b..ba55b2e66e 100644
--- a/servers/rendering/rendering_server_viewport.h
+++ b/servers/rendering/rendering_server_viewport.h
@@ -82,6 +82,8 @@ public:
RID shadow_atlas;
int shadow_atlas_size;
+ bool sdf_active;
+
uint64_t last_pass = 0;
int render_info[RS::VIEWPORT_RENDER_INFO_MAX];
@@ -146,6 +148,7 @@ public:
render_info[i] = 0;
}
use_xr = false;
+ sdf_active = false;
time_cpu_begin = 0;
time_cpu_end = 0;
@@ -232,6 +235,8 @@ public:
void viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter);
void viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat);
+ void viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_over_size, RS::ViewportSDFScale p_scale);
+
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);
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index d27b851d1d..d33bdb043a 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -440,6 +440,8 @@ public:
FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &)
FUNC4(viewport_set_canvas_stacking, RID, RID, int, int)
FUNC2(viewport_set_shadow_atlas_size, RID, int)
+ FUNC3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale)
+
FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
FUNC2(viewport_set_msaa, RID, ViewportMSAA)
FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
@@ -676,12 +678,12 @@ public:
FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID)
FUNC2(canvas_light_occluder_set_enabled, RID, bool)
FUNC2(canvas_light_occluder_set_polygon, RID, RID)
+ FUNC2(canvas_light_occluder_set_as_sdf_collision, RID, bool)
FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &)
FUNC2(canvas_light_occluder_set_light_mask, RID, int)
FUNCRID(canvas_occluder_polygon)
FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
- FUNC2(canvas_occluder_polygon_set_shape_as_lines, RID, const Vector<Vector2> &)
FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 4d21807735..bd61f2a549 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -252,6 +252,27 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
+ {
+ ShaderLanguage::StageFunctionInfo func;
+ func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("sdf_pos", ShaderLanguage::TYPE_VEC2));
+ func.return_type = ShaderLanguage::TYPE_FLOAT; //whether it could emit
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf"] = func;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["texture_sdf"] = func;
+ func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["sdf_to_screen_uv"] = func;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["sdf_to_screen_uv"] = func;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf_normal"] = func;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["texture_sdf_normal"] = func;
+ }
+
+ {
+ ShaderLanguage::StageFunctionInfo func;
+ func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("uv", ShaderLanguage::TYPE_VEC2));
+ func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["screen_uv_to_sdf"] = func;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["screen_uv_to_sdf"] = func;
+ }
+
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index bd501f8bc5..ea37e0c143 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1858,7 +1858,6 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &RenderingServer::canvas_occluder_polygon_create);
ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &RenderingServer::canvas_occluder_polygon_set_shape);
- ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape_as_lines", "occluder_polygon", "shape"), &RenderingServer::canvas_occluder_polygon_set_shape_as_lines);
ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_cull_mode", "occluder_polygon", "mode"), &RenderingServer::canvas_occluder_polygon_set_cull_mode);
ClassDB::bind_method(D_METHOD("global_variable_add", "name", "type", "default_value"), &RenderingServer::global_variable_add);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index d676a1ba01..236112c3fb 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -730,6 +730,23 @@ public:
virtual void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) = 0;
virtual void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) = 0;
+ enum ViewportSDFOversize {
+ VIEWPORT_SDF_OVERSIZE_100_PERCENT,
+ VIEWPORT_SDF_OVERSIZE_120_PERCENT,
+ VIEWPORT_SDF_OVERSIZE_150_PERCENT,
+ VIEWPORT_SDF_OVERSIZE_200_PERCENT,
+ VIEWPORT_SDF_OVERSIZE_MAX
+ };
+
+ enum ViewportSDFScale {
+ VIEWPORT_SDF_SCALE_100_PERCENT,
+ VIEWPORT_SDF_SCALE_50_PERCENT,
+ VIEWPORT_SDF_SCALE_25_PERCENT,
+ VIEWPORT_SDF_SCALE_MAX
+ };
+
+ virtual void viewport_set_sdf_oversize_and_scale(RID p_viewport, ViewportSDFOversize p_oversize, ViewportSDFScale p_scale) = 0;
+
virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0;
virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0;
@@ -1245,12 +1262,12 @@ public:
virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) = 0;
virtual void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) = 0;
virtual void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) = 0;
+ virtual void canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) = 0;
virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0;
virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0;
virtual RID canvas_occluder_polygon_create() = 0;
virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) = 0;
- virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) = 0;
enum CanvasOccluderPolygonCullMode {
CANVAS_OCCLUDER_POLYGON_CULL_DISABLED,