summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/object/object.cpp6
-rw-r--r--core/object/object.h7
-rw-r--r--doc/classes/@GlobalScope.xml79
-rw-r--r--doc/classes/Object.xml6
-rw-r--r--editor/editor_properties.cpp264
-rw-r--r--editor/editor_properties.h34
-rw-r--r--editor/icons/Unlinked.svg1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--modules/navigation/rvo_agent.cpp3
-rw-r--r--platform/javascript/SCsub6
-rw-r--r--platform/javascript/detect.py17
-rw-r--r--platform/javascript/emscripten_helpers.py6
-rw-r--r--platform/javascript/export/export_plugin.cpp9
-rw-r--r--platform/javascript/export/export_plugin.h15
-rw-r--r--scene/2d/node_2d.cpp2
-rw-r--r--scene/3d/lightmap_gi.cpp157
-rw-r--r--scene/3d/lightmap_gi.h2
-rw-r--r--scene/3d/node_3d.cpp2
-rw-r--r--scene/gui/control.cpp4
20 files changed, 463 insertions, 160 deletions
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index bbc937d575..4f22c99656 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -552,6 +552,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LINK);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 0912ea55f0..9dec417b11 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1196,7 +1196,7 @@ Array Object::_get_signal_list() const {
return ret;
}
-Array Object::_get_signal_connection_list(const String &p_signal) const {
+Array Object::_get_signal_connection_list(const StringName &p_signal) const {
List<Connection> conns;
get_all_signal_connections(&conns);
@@ -1422,11 +1422,11 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
}
}
-void Object::_set_bind(const String &p_set, const Variant &p_value) {
+void Object::_set_bind(const StringName &p_set, const Variant &p_value) {
set(p_set, p_value);
}
-Variant Object::_get_bind(const String &p_name) const {
+Variant Object::_get_bind(const StringName &p_name) const {
return get(p_name);
}
diff --git a/core/object/object.h b/core/object/object.h
index 988d261d77..7cbedd29d9 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -52,6 +52,7 @@ enum PropertyHint {
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
+ PROPERTY_HINT_LINK,
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
@@ -523,10 +524,10 @@ private:
bool _has_user_signal(const StringName &p_name) const;
Error _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Array _get_signal_list() const;
- Array _get_signal_connection_list(const String &p_signal) const;
+ Array _get_signal_connection_list(const StringName &p_signal) const;
Array _get_incoming_connections() const;
- void _set_bind(const String &p_set, const Variant &p_value);
- Variant _get_bind(const String &p_name) const;
+ void _set_bind(const StringName &p_set, const Variant &p_value);
+ Variant _get_bind(const StringName &p_name) const;
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
Variant _get_indexed_bind(const NodePath &p_name) const;
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index dce96fb315..18ea29857b 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2419,63 +2419,66 @@
<constant name="PROPERTY_HINT_LENGTH" value="5" enum="PropertyHint">
Deprecated hint, unused.
</constant>
- <constant name="PROPERTY_HINT_KEY_ACCEL" value="6" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LINK" value="6" enum="PropertyHint">
+ Hints that a vector property should allow linking values (e.g. to edit both [code]x[/code] and [code]y[/code] together).
+ </constant>
+ <constant name="PROPERTY_HINT_KEY_ACCEL" value="7" enum="PropertyHint">
Deprecated hint, unused.
</constant>
- <constant name="PROPERTY_HINT_FLAGS" value="7" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_FLAGS" value="8" enum="PropertyHint">
Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
</constant>
- <constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="8" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="9" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 2D render layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="9" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="10" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 2D physics layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="10" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="11" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="11" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="12" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 3D render layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="12" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="13" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 3D physics layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="13" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="14" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
</constant>
- <constant name="PROPERTY_HINT_FILE" value="14" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_FILE" value="15" enum="PropertyHint">
Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
</constant>
- <constant name="PROPERTY_HINT_DIR" value="15" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_DIR" value="16" enum="PropertyHint">
Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path.
</constant>
- <constant name="PROPERTY_HINT_GLOBAL_FILE" value="16" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_GLOBAL_FILE" value="17" enum="PropertyHint">
Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
</constant>
- <constant name="PROPERTY_HINT_GLOBAL_DIR" value="17" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_GLOBAL_DIR" value="18" enum="PropertyHint">
Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
</constant>
- <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="18" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="19" enum="PropertyHint">
Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture2D"[/code]). Editing it will show a popup menu of valid resource types to instantiate.
</constant>
- <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="19" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="20" enum="PropertyHint">
Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
</constant>
- <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="20" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="21" enum="PropertyHint">
Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
</constant>
- <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="21" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="22" enum="PropertyHint">
Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
</constant>
- <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="22" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="23" enum="PropertyHint">
Hints that an image is compressed using lossy compression.
</constant>
- <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="23" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="24" enum="PropertyHint">
Hints that an image is compressed using lossless compression.
</constant>
- <constant name="PROPERTY_HINT_OBJECT_ID" value="24" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_OBJECT_ID" value="25" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_TYPE_STRING" value="25" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_TYPE_STRING" value="26" enum="PropertyHint">
Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
[codeblock]
hint_string = "%s:" % [TYPE_INT] # Array of inteters.
@@ -2485,43 +2488,43 @@
[/codeblock]
[b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
</constant>
- <constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="26" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="27" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="27" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="28" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="28" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="29" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="29" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="30" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="30" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="31" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="31" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="32" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="32" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="33" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="33" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="34" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="34" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="35" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="35" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="36" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="36" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="37" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_SAVE_FILE" value="37" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_SAVE_FILE" value="38" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="38" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="39" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_INT_IS_POINTER" value="40" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_INT_IS_POINTER" value="41" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_ARRAY_TYPE" value="39" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_ARRAY_TYPE" value="40" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_LOCALE_ID" value="41" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LOCALE_ID" value="42" enum="PropertyHint">
Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
</constant>
- <constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="42" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="43" enum="PropertyHint">
Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
</constant>
- <constant name="PROPERTY_HINT_MAX" value="43" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_MAX" value="44" enum="PropertyHint">
</constant>
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
</constant>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 42844794b0..11ae7cc2b0 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -325,7 +325,7 @@
</method>
<method name="get" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="property" type="String" />
+ <argument index="0" name="property" type="StringName" />
<description>
Returns the [Variant] value of the given [code]property[/code]. If the [code]property[/code] doesn't exist, this will return [code]null[/code].
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
@@ -399,7 +399,7 @@
</method>
<method name="get_signal_connection_list" qualifiers="const">
<return type="Array" />
- <argument index="0" name="signal" type="String" />
+ <argument index="0" name="signal" type="StringName" />
<description>
Returns an [Array] of connections for the given [code]signal[/code].
</description>
@@ -490,7 +490,7 @@
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="property" type="String" />
+ <argument index="0" name="property" type="StringName" />
<argument index="1" name="value" type="Variant" />
<description>
Assigns a new value to the given property. If the [code]property[/code] does not exist or the given value's type doesn't match, nothing will happen.
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index ddf1974070..a5c02c70d9 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1597,6 +1597,18 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) {
return;
}
+ if (linked->is_pressed()) {
+ setting = true;
+ if (p_name == "x") {
+ spin[1]->set_value(spin[0]->get_value() * ratio_yx);
+ }
+
+ if (p_name == "y") {
+ spin[0]->set_value(spin[1]->get_value() * ratio_xy);
+ }
+ setting = false;
+ }
+
Vector2 v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
@@ -1609,12 +1621,28 @@ void EditorPropertyVector2::update_property() {
spin[0]->set_value(val.x);
spin[1]->set_value(val.y);
setting = false;
+ _update_ratio();
+}
+
+void EditorPropertyVector2::_update_ratio() {
+ linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5));
+
+ if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) {
+ ratio_xy = spin[0]->get_value() / spin[1]->get_value();
+ ratio_yx = spin[1]->get_value() / spin[0]->get_value();
+ } else {
+ ratio_xy = 1.0;
+ ratio_yx = 1.0;
+ }
}
void EditorPropertyVector2::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
+ linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
+ linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
+
const Color *colors = _get_property_colors();
for (int i = 0; i < 2; i++) {
spin[i]->add_theme_color_override("label_color", colors[i]);
@@ -1623,10 +1651,7 @@ void EditorPropertyVector2::_notification(int p_what) {
}
}
-void EditorPropertyVector2::_bind_methods() {
-}
-
-void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link, const String &p_suffix) {
for (int i = 0; i < 2; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -1636,24 +1661,34 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
}
+
+ if (!p_link) {
+ linked->hide();
+ } else {
+ linked->set_pressed(true);
+ }
}
EditorPropertyVector2::EditorPropertyVector2(bool p_force_wide) {
bool horizontal = p_force_wide || bool(EDITOR_GET("interface/inspector/horizontal_vector2_editing"));
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
BoxContainer *bc;
if (p_force_wide) {
bc = memnew(HBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
} else if (horizontal) {
bc = memnew(HBoxContainer);
- add_child(bc);
- set_bottom_editor(bc);
+ hb->add_child(bc);
+ set_bottom_editor(hb);
} else {
bc = memnew(VBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
}
+ bc->set_h_size_flags(SIZE_EXPAND_FILL);
static const char *desc[2] = { "x", "y" };
for (int i = 0; i < 2; i++) {
@@ -1668,6 +1703,13 @@ EditorPropertyVector2::EditorPropertyVector2(bool p_force_wide) {
}
}
+ linked = memnew(TextureButton);
+ linked->set_toggle_mode(true);
+ linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
+ linked->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyVector2::_update_ratio));
+ hb->add_child(linked);
+
+ add_child(hb);
if (!horizontal) {
set_label_reference(spin[0]); //show text and buttons around this
}
@@ -1789,6 +1831,25 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
return;
}
+ if (linked->is_pressed()) {
+ setting = true;
+ if (p_name == "x") {
+ spin[1]->set_value(spin[0]->get_value() * ratio_yx);
+ spin[2]->set_value(spin[0]->get_value() * ratio_zx);
+ }
+
+ if (p_name == "y") {
+ spin[0]->set_value(spin[1]->get_value() * ratio_xy);
+ spin[2]->set_value(spin[1]->get_value() * ratio_zy);
+ }
+
+ if (p_name == "z") {
+ spin[0]->set_value(spin[2]->get_value() * ratio_xz);
+ spin[1]->set_value(spin[2]->get_value() * ratio_yz);
+ }
+ setting = false;
+ }
+
Vector3 v3;
v3.x = spin[0]->get_value();
v3.y = spin[1]->get_value();
@@ -1803,6 +1864,27 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
void EditorPropertyVector3::update_property() {
update_using_vector(get_edited_object()->get(get_edited_property()));
+ _update_ratio();
+}
+
+void EditorPropertyVector3::_update_ratio() {
+ linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5));
+
+ if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) {
+ ratio_yx = spin[1]->get_value() / spin[0]->get_value();
+ ratio_zx = spin[2]->get_value() / spin[0]->get_value();
+ ratio_xy = spin[0]->get_value() / spin[1]->get_value();
+ ratio_zy = spin[2]->get_value() / spin[1]->get_value();
+ ratio_xz = spin[0]->get_value() / spin[2]->get_value();
+ ratio_yz = spin[1]->get_value() / spin[2]->get_value();
+ } else {
+ ratio_yx = 1.0;
+ ratio_zx = 1.0;
+ ratio_xy = 1.0;
+ ratio_zy = 1.0;
+ ratio_xz = 1.0;
+ ratio_yz = 1.0;
+ }
}
void EditorPropertyVector3::update_using_vector(Vector3 p_vector) {
@@ -1836,6 +1918,9 @@ void EditorPropertyVector3::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
+ linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
+ linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
+
const Color *colors = _get_property_colors();
for (int i = 0; i < 3; i++) {
spin[i]->add_theme_color_override("label_color", colors[i]);
@@ -1847,7 +1932,7 @@ void EditorPropertyVector3::_notification(int p_what) {
void EditorPropertyVector3::_bind_methods() {
}
-void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix, bool p_angle_in_radians) {
+void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link, const String &p_suffix, bool p_angle_in_radians) {
angle_in_radians = p_angle_in_radians;
for (int i = 0; i < 3; i++) {
spin[i]->set_min(p_min);
@@ -1858,24 +1943,34 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
}
+
+ if (!p_link) {
+ linked->hide();
+ } else {
+ linked->set_pressed(true);
+ }
}
EditorPropertyVector3::EditorPropertyVector3(bool p_force_wide) {
bool horizontal = p_force_wide || bool(EDITOR_GET("interface/inspector/horizontal_vector_types_editing"));
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
BoxContainer *bc;
if (p_force_wide) {
bc = memnew(HBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
} else if (horizontal) {
bc = memnew(HBoxContainer);
- add_child(bc);
- set_bottom_editor(bc);
+ hb->add_child(bc);
+ set_bottom_editor(hb);
} else {
bc = memnew(VBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
}
+ bc->set_h_size_flags(SIZE_EXPAND_FILL);
static const char *desc[3] = { "x", "y", "z" };
for (int i = 0; i < 3; i++) {
@@ -1890,6 +1985,13 @@ EditorPropertyVector3::EditorPropertyVector3(bool p_force_wide) {
}
}
+ linked = memnew(TextureButton);
+ linked->set_toggle_mode(true);
+ linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
+ linked->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyVector3::_update_ratio));
+ hb->add_child(linked);
+
+ add_child(hb);
if (!horizontal) {
set_label_reference(spin[0]); //show text and buttons around this
}
@@ -1908,6 +2010,18 @@ void EditorPropertyVector2i::_value_changed(double val, const String &p_name) {
return;
}
+ if (linked->is_pressed()) {
+ setting = true;
+ if (p_name == "x") {
+ spin[1]->set_value(spin[0]->get_value() * ratio_yx);
+ }
+
+ if (p_name == "y") {
+ spin[0]->set_value(spin[1]->get_value() * ratio_xy);
+ }
+ setting = false;
+ }
+
Vector2i v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
@@ -1920,12 +2034,28 @@ void EditorPropertyVector2i::update_property() {
spin[0]->set_value(val.x);
spin[1]->set_value(val.y);
setting = false;
+ _update_ratio();
+}
+
+void EditorPropertyVector2i::_update_ratio() {
+ linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5));
+
+ if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) {
+ ratio_xy = spin[0]->get_value() / spin[1]->get_value();
+ ratio_yx = spin[1]->get_value() / spin[0]->get_value();
+ } else {
+ ratio_xy = 1.0;
+ ratio_yx = 1.0;
+ }
}
void EditorPropertyVector2i::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
+ linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
+ linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
+
const Color *colors = _get_property_colors();
for (int i = 0; i < 2; i++) {
spin[i]->add_theme_color_override("label_color", colors[i]);
@@ -1934,10 +2064,7 @@ void EditorPropertyVector2i::_notification(int p_what) {
}
}
-void EditorPropertyVector2i::_bind_methods() {
-}
-
-void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider, bool p_link, const String &p_suffix) {
for (int i = 0; i < 2; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -1947,24 +2074,34 @@ void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider, const
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
}
+
+ if (!p_link) {
+ linked->hide();
+ } else {
+ linked->set_pressed(true);
+ }
}
EditorPropertyVector2i::EditorPropertyVector2i(bool p_force_wide) {
bool horizontal = p_force_wide || bool(EDITOR_GET("interface/inspector/horizontal_vector2_editing"));
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
BoxContainer *bc;
if (p_force_wide) {
bc = memnew(HBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
} else if (horizontal) {
bc = memnew(HBoxContainer);
- add_child(bc);
- set_bottom_editor(bc);
+ hb->add_child(bc);
+ set_bottom_editor(hb);
} else {
bc = memnew(VBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
}
+ bc->set_h_size_flags(SIZE_EXPAND_FILL);
static const char *desc[2] = { "x", "y" };
for (int i = 0; i < 2; i++) {
@@ -1979,6 +2116,13 @@ EditorPropertyVector2i::EditorPropertyVector2i(bool p_force_wide) {
}
}
+ linked = memnew(TextureButton);
+ linked->set_toggle_mode(true);
+ linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
+ linked->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyVector2i::_update_ratio));
+ hb->add_child(linked);
+
+ add_child(hb);
if (!horizontal) {
set_label_reference(spin[0]); //show text and buttons around this
}
@@ -2100,6 +2244,25 @@ void EditorPropertyVector3i::_value_changed(double val, const String &p_name) {
return;
}
+ if (linked->is_pressed()) {
+ setting = true;
+ if (p_name == "x") {
+ spin[1]->set_value(spin[0]->get_value() * ratio_yx);
+ spin[2]->set_value(spin[0]->get_value() * ratio_zx);
+ }
+
+ if (p_name == "y") {
+ spin[0]->set_value(spin[1]->get_value() * ratio_xy);
+ spin[2]->set_value(spin[1]->get_value() * ratio_zy);
+ }
+
+ if (p_name == "z") {
+ spin[0]->set_value(spin[2]->get_value() * ratio_xz);
+ spin[1]->set_value(spin[2]->get_value() * ratio_yz);
+ }
+ setting = false;
+ }
+
Vector3i v3;
v3.x = spin[0]->get_value();
v3.y = spin[1]->get_value();
@@ -2114,12 +2277,36 @@ void EditorPropertyVector3i::update_property() {
spin[1]->set_value(val.y);
spin[2]->set_value(val.z);
setting = false;
+ _update_ratio();
+}
+
+void EditorPropertyVector3i::_update_ratio() {
+ linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5));
+
+ if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) {
+ ratio_yx = spin[1]->get_value() / spin[0]->get_value();
+ ratio_zx = spin[2]->get_value() / spin[0]->get_value();
+ ratio_xy = spin[0]->get_value() / spin[1]->get_value();
+ ratio_zy = spin[2]->get_value() / spin[1]->get_value();
+ ratio_xz = spin[0]->get_value() / spin[2]->get_value();
+ ratio_yz = spin[1]->get_value() / spin[2]->get_value();
+ } else {
+ ratio_yx = 1.0;
+ ratio_zx = 1.0;
+ ratio_xy = 1.0;
+ ratio_zy = 1.0;
+ ratio_xz = 1.0;
+ ratio_yz = 1.0;
+ }
}
void EditorPropertyVector3i::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
+ linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
+ linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
+
const Color *colors = _get_property_colors();
for (int i = 0; i < 3; i++) {
spin[i]->add_theme_color_override("label_color", colors[i]);
@@ -2131,7 +2318,7 @@ void EditorPropertyVector3i::_notification(int p_what) {
void EditorPropertyVector3i::_bind_methods() {
}
-void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider, bool p_link, const String &p_suffix) {
for (int i = 0; i < 3; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -2141,22 +2328,31 @@ void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider, const
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
}
+
+ if (!p_link) {
+ linked->hide();
+ } else {
+ linked->set_pressed(true);
+ }
}
EditorPropertyVector3i::EditorPropertyVector3i(bool p_force_wide) {
bool horizontal = p_force_wide || bool(EDITOR_GET("interface/inspector/horizontal_vector_types_editing"));
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
BoxContainer *bc;
if (p_force_wide) {
bc = memnew(HBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
} else if (horizontal) {
bc = memnew(HBoxContainer);
- add_child(bc);
- set_bottom_editor(bc);
+ hb->add_child(bc);
+ set_bottom_editor(hb);
} else {
bc = memnew(VBoxContainer);
- add_child(bc);
+ hb->add_child(bc);
}
static const char *desc[3] = { "x", "y", "z" };
@@ -2171,7 +2367,15 @@ EditorPropertyVector3i::EditorPropertyVector3i(bool p_force_wide) {
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
}
}
+ bc->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ linked = memnew(TextureButton);
+ linked->set_toggle_mode(true);
+ linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
+ linked->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyVector3i::_update_ratio));
+ hb->add_child(linked);
+ add_child(hb);
if (!horizontal) {
set_label_reference(spin[0]); //show text and buttons around this
}
@@ -3608,14 +3812,14 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyVector2 *editor = memnew(EditorPropertyVector2(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
- editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor;
} break;
case Variant::VECTOR2I: {
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor;
} break;
@@ -3635,14 +3839,14 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR3: {
EditorPropertyVector3 *editor = memnew(EditorPropertyVector3(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
- editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix, hint.radians);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix, hint.radians);
return editor;
} break;
case Variant::VECTOR3I: {
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor;
} break;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 6513eb0390..a3b98b7724 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -451,16 +451,19 @@ class EditorPropertyVector2 : public EditorProperty {
GDCLASS(EditorPropertyVector2, EditorProperty);
EditorSpinSlider *spin[2];
bool setting = false;
+ double ratio_xy = 1.0;
+ double ratio_yx = 1.0;
+ TextureButton *linked = nullptr;
+ void _update_ratio();
void _value_changed(double p_val, const String &p_name);
protected:
virtual void _set_read_only(bool p_read_only) override;
void _notification(int p_what);
- static void _bind_methods();
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector2(bool p_force_wide = false);
};
@@ -486,6 +489,14 @@ class EditorPropertyVector3 : public EditorProperty {
EditorSpinSlider *spin[3];
bool setting = false;
bool angle_in_radians = false;
+ double ratio_yx = 1.0;
+ double ratio_zx = 1.0;
+ double ratio_xy = 1.0;
+ double ratio_zy = 1.0;
+ double ratio_xz = 1.0;
+ double ratio_yz = 1.0;
+ TextureButton *linked = nullptr;
+ void _update_ratio();
void _value_changed(double p_val, const String &p_name);
protected:
@@ -497,7 +508,7 @@ public:
virtual void update_property() override;
virtual void update_using_vector(Vector3 p_vector);
virtual Vector3 get_vector();
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String(), bool p_angle_in_radians = false);
+ void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false, const String &p_suffix = String(), bool p_angle_in_radians = false);
EditorPropertyVector3(bool p_force_wide = false);
};
@@ -505,16 +516,19 @@ class EditorPropertyVector2i : public EditorProperty {
GDCLASS(EditorPropertyVector2i, EditorProperty);
EditorSpinSlider *spin[2];
bool setting = false;
+ double ratio_xy = 1.0;
+ double ratio_yx = 1.0;
+ TextureButton *linked = nullptr;
+ void _update_ratio();
void _value_changed(double p_val, const String &p_name);
protected:
virtual void _set_read_only(bool p_read_only) override;
void _notification(int p_what);
- static void _bind_methods();
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_no_slider, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector2i(bool p_force_wide = false);
};
@@ -539,6 +553,14 @@ class EditorPropertyVector3i : public EditorProperty {
GDCLASS(EditorPropertyVector3i, EditorProperty);
EditorSpinSlider *spin[3];
bool setting = false;
+ double ratio_yx = 1.0;
+ double ratio_zx = 1.0;
+ double ratio_xy = 1.0;
+ double ratio_zy = 1.0;
+ double ratio_xz = 1.0;
+ double ratio_yz = 1.0;
+ TextureButton *linked = nullptr;
+ void _update_ratio();
void _value_changed(double p_val, const String &p_name);
protected:
@@ -548,7 +570,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_no_slider, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector3i(bool p_force_wide = false);
};
diff --git a/editor/icons/Unlinked.svg b/editor/icons/Unlinked.svg
new file mode 100644
index 0000000000..6c831eacad
--- /dev/null
+++ b/editor/icons/Unlinked.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)" fill="#e0e0e0"><path d="M1.136 12.036a3.994 3.994 0 0 1-.137-1.047 4.007 4.007 0 0 1 2.965-3.853 1 1 0 0 1 1.225.707 1 1 0 0 1 .034.25 1 1 0 0 1-.741.975 2 2 0 0 0-1.483 1.926 1.994 1.994 0 0 0 .068.523 2 2 0 0 0 2.45 1.415 2 2 0 0 0 1.484-1.931 2 2 0 0 0-.068-.523 1 1 0 0 1-.034-.25 1 1 0 0 1 .742-.975 1 1 0 0 1 1.225.707 3.991 3.991 0 0 1 .137 1.046 4.007 4.007 0 0 1-2.965 3.852 3.993 3.993 0 0 1-1.035.137 4.006 4.006 0 0 1-3.867-2.959zM9.965 8.863a1 1 0 0 1-.742-.975 1 1 0 0 1 .034-.25 1 1 0 0 1 1.225-.706 2 2 0 0 0 2.449-1.415A1.994 1.994 0 0 0 13 4.994a2 2 0 0 0-1.483-1.926 2 2 0 0 0-2.45 1.414 1 1 0 0 1-1.224.707 1 1 0 0 1-.742-.975 1 1 0 0 1 .034-.25 4 4 0 0 1 4.9-2.829A4.008 4.008 0 0 1 15 4.988a3.993 3.993 0 0 1-.137 1.047 4.006 4.006 0 0 1-3.862 2.966 3.989 3.989 0 0 1-1.036-.138zM5.5 4a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5zM4.5 5a.5.5 0 0 1-.354-.146l-2-2a.5.5 0 0 1 0-.707.5.5 0 0 1 .707 0l2 2A.5.5 0 0 1 4.5 5zM3.5 6h-2a.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5.5.5 0 0 1-.5.5z"/></g></svg>
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 83b0d74dd2..1ea0299d4e 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1289,7 +1289,7 @@ void CanvasItemEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bo
zoom_widget->set_zoom_by_increments(-scroll_sign, p_alt);
if (!Math::is_equal_approx(ABS(p_scroll_vec.y), (real_t)1.0)) {
// Handle high-precision (analog) scrolling.
- zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * p_scroll_vec.y + 1.f));
+ zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * ABS(p_scroll_vec.y) + 1.f));
}
_zoom_on_position(zoom_widget->get_zoom(), p_origin);
}
diff --git a/modules/navigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp
index a6a5660c0c..4ec72ad43f 100644
--- a/modules/navigation/rvo_agent.cpp
+++ b/modules/navigation/rvo_agent.cpp
@@ -65,8 +65,9 @@ void RvoAgent::dispatch_callback() {
return;
}
Object *obj = ObjectDB::get_instance(callback.id);
- if (obj == nullptr) {
+ if (!obj) {
callback.id = ObjectID();
+ return;
}
Callable::CallError responseCallError;
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 8d9ba82fd4..4827dc4627 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -37,6 +37,8 @@ for ext in env["JS_EXTERNS"]:
build = []
if env["gdnative_enabled"]:
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
+ if env["threads_enabled"]:
+ build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
# Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
sys_env["LIBS"] = []
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
@@ -58,7 +60,7 @@ if env["gdnative_enabled"]:
wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files)
- build = [sys[0], sys[1], wasm[0]]
+ build = sys + [wasm[0]]
else:
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
if env["threads_enabled"]:
@@ -87,5 +89,5 @@ wrap_list = [
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
# Extra will be the thread worker, or the GDNative side, or None
-extra = build[2] if len(build) > 2 else None
+extra = build[2:] if len(build) > 2 else None
env.CreateTemplateZip(js_wrapped, build[1], extra)
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 4a9652fc1c..15fd63811c 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -185,10 +185,6 @@ def configure(env):
if env["javascript_eval"]:
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
- if env["threads_enabled"] and env["gdnative_enabled"]:
- print("Threads and GDNative support can't be both enabled due to WebAssembly limitations")
- sys.exit(255)
-
# Thread support (via SharedArrayBuffer).
if env["threads_enabled"]:
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
@@ -201,10 +197,21 @@ def configure(env):
env.Append(CPPDEFINES=["NO_THREADS"])
if env["gdnative_enabled"]:
- major, minor, patch = get_compiler_version(env)
+ emcc_version = get_compiler_version(env)
+ major = int(emcc_version["major"])
+ minor = int(emcc_version["minor"])
+ patch = int(emcc_version["patch"])
if major < 2 or (major == 2 and minor == 0 and patch < 10):
print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % (major, minor, patch))
sys.exit(255)
+ if (
+ env["threads_enabled"]
+ and major < 3
+ or (major == 3 and minor < 1)
+ or (major == 3 and minor == 1 and patch < 14)
+ ):
+ print("Threads and GDNative requires emscripten => 3.1.14, detected: %s.%s.%s" % (major, minor, patch))
+ sys.exit(255)
env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
# Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index 4dad2d5204..3cb1d75e52 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -52,10 +52,10 @@ def create_template_zip(env, js, wasm, extra):
]
# GDNative/Threads specific
if env["gdnative_enabled"]:
- in_files.append(extra) # Runtime
+ in_files.append(extra.pop()) # Runtime
out_files.append(zip_dir.File(binary_name + ".side.wasm"))
- elif env["threads_enabled"]:
- in_files.append(extra) # Worker
+ if env["threads_enabled"]:
+ in_files.append(extra.pop()) # Worker
out_files.append(zip_dir.File(binary_name + ".worker.js"))
service_worker = "#misc/dist/html/service-worker.js"
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index 128834c90f..901580c140 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -215,7 +215,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
cache_files.push_back(name + ".icon.png");
cache_files.push_back(name + ".apple-touch-icon.png");
}
- if (mode == EXPORT_MODE_THREADS) {
+ if (mode & EXPORT_MODE_THREADS) {
cache_files.push_back(name + ".worker.js");
cache_files.push_back(name + ".audio.worklet.js");
}
@@ -225,7 +225,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
Array opt_cache_files;
opt_cache_files.push_back(name + ".wasm");
opt_cache_files.push_back(name + ".pck");
- if (mode == EXPORT_MODE_GDNATIVE) {
+ if (mode & EXPORT_MODE_GDNATIVE) {
opt_cache_files.push_back(name + ".side.wasm");
for (int i = 0; i < p_shared_objects.size(); i++) {
opt_cache_files.push_back(p_shared_objects[i].path.get_file());
@@ -317,9 +317,10 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
}
}
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- if (mode == EXPORT_MODE_THREADS) {
+ if (mode & EXPORT_MODE_THREADS) {
r_features->push_back("threads");
- } else if (mode == EXPORT_MODE_GDNATIVE) {
+ }
+ if (mode & EXPORT_MODE_GDNATIVE) {
r_features->push_back("wasm32");
}
}
diff --git a/platform/javascript/export/export_plugin.h b/platform/javascript/export/export_plugin.h
index 2d6cbfde38..1aaec5454d 100644
--- a/platform/javascript/export/export_plugin.h
+++ b/platform/javascript/export/export_plugin.h
@@ -61,19 +61,16 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
EXPORT_MODE_NORMAL = 0,
EXPORT_MODE_THREADS = 1,
EXPORT_MODE_GDNATIVE = 2,
+ EXPORT_MODE_THREADS_GDNATIVE = 3,
};
String _get_template_name(ExportMode p_mode, bool p_debug) const {
String name = "webassembly";
- switch (p_mode) {
- case EXPORT_MODE_THREADS:
- name += "_threads";
- break;
- case EXPORT_MODE_GDNATIVE:
- name += "_gdnative";
- break;
- default:
- break;
+ if (p_mode & EXPORT_MODE_GDNATIVE) {
+ name += "_gdnative";
+ }
+ if (p_mode & EXPORT_MODE_THREADS) {
+ name += "_threads";
}
if (p_debug) {
name += "_debug.zip";
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 6fa18d393e..b2b848d380 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -439,7 +439,7 @@ void Node2D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform");
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 5c63bdcf1d..9d1d8721e6 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -73,7 +73,7 @@ void LightmapGIData::clear_users() {
}
void LightmapGIData::_set_user_data(const Array &p_data) {
- ERR_FAIL_COND(p_data.size() <= 0);
+ ERR_FAIL_COND(p_data.is_empty());
ERR_FAIL_COND((p_data.size() % 4) != 0);
for (int i = 0; i < p_data.size(); i += 4) {
@@ -92,6 +92,95 @@ Array LightmapGIData::_get_user_data() const {
return ret;
}
+void LightmapGIData::_set_light_textures_data(const Array &p_data) {
+ ERR_FAIL_COND(p_data.is_empty());
+
+ if (p_data.size() == 1) {
+ set_light_texture(p_data[0]);
+ } else {
+ Vector<Ref<Image>> images;
+ for (int i = 0; i < p_data.size(); i++) {
+ Ref<TextureLayered> texture = p_data[i];
+ for (int j = 0; j < texture->get_layers(); j++) {
+ images.push_back(texture->get_layer_data(j));
+ }
+ }
+
+ Ref<Texture2DArray> combined_texture;
+ combined_texture.instantiate();
+
+ combined_texture->create_from_images(images);
+ set_light_texture(combined_texture);
+ }
+}
+
+Array LightmapGIData::_get_light_textures_data() const {
+ Array ret;
+ if (light_texture.is_null()) {
+ return ret;
+ }
+
+ Vector<Ref<Image>> images;
+ for (int i = 0; i < light_texture->get_layers(); i++) {
+ images.push_back(light_texture->get_layer_data(i));
+ }
+
+ int slice_count = images.size();
+ int slice_width = images[0]->get_width();
+ int slice_height = images[0]->get_height();
+
+ int slices_per_texture = Image::MAX_HEIGHT / slice_height;
+ int texture_count = Math::ceil(slice_count / (float)slices_per_texture);
+
+ ret.resize(texture_count);
+
+ String base_name = get_path().get_basename();
+
+ int last_count = slice_count % slices_per_texture;
+ for (int i = 0; i < texture_count; i++) {
+ int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
+
+ Ref<Image> texture_image;
+ texture_image.instantiate();
+
+ texture_image->create(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
+
+ for (int j = 0; j < texture_slice_count; j++) {
+ texture_image->blit_rect(images[i * slices_per_texture + j], Rect2(0, 0, slice_width, slice_height), Point2(0, slice_height * j));
+ }
+
+ String texture_path = texture_count > 1 ? base_name + "_" + itos(i) + ".exr" : base_name + ".exr";
+
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ if (FileAccess::exists(texture_path + ".import")) {
+ config->load(texture_path + ".import");
+ }
+
+ config->set_value("remap", "importer", "2d_array_texture");
+ config->set_value("remap", "type", "CompressedTexture2DArray");
+ if (!config->has_section_key("params", "compress/mode")) {
+ config->set_value("params", "compress/mode", 2); //user may want another compression, so leave it be
+ }
+ config->set_value("params", "compress/channel_pack", 1);
+ config->set_value("params", "mipmaps/generate", false);
+ config->set_value("params", "slices/horizontal", 1);
+ config->set_value("params", "slices/vertical", texture_slice_count);
+
+ config->save(texture_path + ".import");
+
+ Error err = texture_image->save_exr(texture_path, false);
+ ERR_FAIL_COND_V(err, ret);
+ ResourceLoader::import(texture_path);
+ Ref<TextureLayered> t = ResourceLoader::load(texture_path); //if already loaded, it will be updated on refocus?
+ ERR_FAIL_COND_V(t.is_null(), ret);
+ ret[i] = t;
+ }
+
+ return ret;
+}
+
RID LightmapGIData::get_rid() const {
return lightmap;
}
@@ -188,6 +277,9 @@ void LightmapGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture);
+ ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data);
+ ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data);
+
ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
@@ -199,7 +291,8 @@ void LightmapGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered"), "set_light_texture", "get_light_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK), "set_light_texture", "get_light_texture"); // property usage default but no save
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
@@ -953,53 +1046,6 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
return BAKE_ERROR_MESHES_INVALID;
}
- /* POSTBAKE: Save Textures */
-
- Ref<TextureLayered> texture;
- {
- Vector<Ref<Image>> images;
- for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
- images.push_back(lightmapper->get_bake_texture(i));
- }
- //we assume they are all the same, so let's create a large one for saving
- Ref<Image> large_image;
- large_image.instantiate();
-
- large_image->create(images[0]->get_width(), images[0]->get_height() * images.size(), false, images[0]->get_format());
-
- for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
- large_image->blit_rect(images[i], Rect2(0, 0, images[i]->get_width(), images[i]->get_height()), Point2(0, images[i]->get_height() * i));
- }
-
- String base_path = p_image_data_path.get_basename() + ".exr";
-
- Ref<ConfigFile> config;
-
- config.instantiate();
- if (FileAccess::exists(base_path + ".import")) {
- config->load(base_path + ".import");
- }
-
- config->set_value("remap", "importer", "2d_array_texture");
- config->set_value("remap", "type", "CompressedTexture2DArray");
- if (!config->has_section_key("params", "compress/mode")) {
- config->set_value("params", "compress/mode", 2); //user may want another compression, so leave it be
- }
- config->set_value("params", "compress/channel_pack", 1);
- config->set_value("params", "mipmaps/generate", false);
- config->set_value("params", "slices/horizontal", 1);
- config->set_value("params", "slices/vertical", images.size());
-
- config->save(base_path + ".import");
-
- Error err = large_image->save_exr(base_path, false);
- ERR_FAIL_COND_V(err, BAKE_ERROR_CANT_CREATE_IMAGE);
- ResourceLoader::import(base_path);
- Ref<Texture> t = ResourceLoader::load(base_path); //if already loaded, it will be updated on refocus?
- ERR_FAIL_COND_V(t.is_null(), BAKE_ERROR_CANT_CREATE_IMAGE);
- texture = t;
- }
-
/* POSTBAKE: Save Light Data */
Ref<LightmapGIData> data;
@@ -1011,6 +1057,17 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
data.instantiate();
}
+ Ref<Texture2DArray> texture;
+ {
+ Vector<Ref<Image>> images;
+ for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
+ images.push_back(lightmapper->get_bake_texture(i));
+ }
+
+ texture.instantiate();
+ texture->create_from_images(images);
+ }
+
data->set_light_texture(texture);
data->set_uses_spherical_harmonics(directional);
@@ -1161,8 +1218,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
/* Compute a BSP tree of the simplices, so it's easy to find the exact one */
}
- Error err = ResourceSaver::save(p_image_data_path, data);
data->set_path(p_image_data_path);
+ Error err = ResourceSaver::save(p_image_data_path, data);
if (err != OK) {
return BAKE_ERROR_CANT_CREATE_IMAGE;
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index d29d7a7c28..b39cde429d 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -61,6 +61,8 @@ class LightmapGIData : public Resource {
Array _get_user_data() const;
void _set_probe_data(const Dictionary &p_data);
Dictionary _get_probe_data() const;
+ void _set_light_textures_data(const Array &p_data);
+ Array _get_light_textures_data() const;
protected:
static void _bind_methods();
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index a76d57a09f..6e36815f2b 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -984,7 +984,7 @@ void Node3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_edit_mode", PROPERTY_HINT_ENUM, "Euler,Quaternion,Basis"), "set_rotation_edit_mode", "get_rotation_edit_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_order", PROPERTY_HINT_ENUM, "XYZ,XZY,YXZ,YZX,ZXY,ZYX"), "set_rotation_order", "get_rotation_order");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 3db1719226..5ddc38a0b9 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -478,6 +478,10 @@ void Control::_validate_property(PropertyInfo &property) const {
}
}
+ if (property.name == "scale") {
+ property.hint = PROPERTY_HINT_LINK;
+ }
+
// Validate which positioning properties should be displayed depending on the parent and the layout mode.
Node *parent_node = get_parent_control();
if (!parent_node) {