summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/core_constants.cpp34
-rw-r--r--core/extension/extension_api_dump.cpp149
-rw-r--r--core/extension/gdnative_interface.cpp176
-rw-r--r--core/extension/gdnative_interface.h32
-rw-r--r--core/extension/native_extension.cpp25
-rw-r--r--core/extension/native_extension.h4
-rw-r--r--core/input/input_event.cpp24
-rw-r--r--core/input/input_event.h16
-rw-r--r--core/object/class_db.cpp6
-rw-r--r--core/object/class_db.h2
-rw-r--r--core/object/object.cpp4
-rw-r--r--core/object/object.h1
-rw-r--r--core/register_core_types.cpp8
-rw-r--r--core/variant/variant.cpp3
-rw-r--r--core/variant/variant.h12
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--core/variant/variant_destruct.cpp78
-rw-r--r--core/variant/variant_destruct.h76
-rw-r--r--core/variant/variant_internal.h20
-rw-r--r--doc/classes/@GlobalScope.xml64
-rw-r--r--doc/classes/EditorCommandPalette.xml31
-rw-r--r--doc/classes/EditorInterface.xml5
-rw-r--r--doc/classes/NativeExtension.xml2
-rw-r--r--doc/classes/RenderingDevice.xml6
-rw-r--r--doc/classes/Transform2D.xml2
-rw-r--r--doc/classes/Viewport.xml2
-rw-r--r--editor/editor_command_palette.cpp300
-rw-r--r--editor/editor_command_palette.h95
-rw-r--r--editor/editor_node.cpp127
-rw-r--r--editor/editor_node.h6
-rw-r--r--editor/editor_plugin.cpp5
-rw-r--r--editor/editor_plugin.h3
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/script_text_editor.cpp7
-rw-r--r--modules/gdscript/gdscript_parser.cpp4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp4
-rw-r--r--scene/3d/listener_3d.cpp16
-rw-r--r--scene/debugger/scene_debugger.cpp8
-rw-r--r--scene/gui/base_button.cpp3
-rw-r--r--scene/gui/menu_button.cpp2
-rw-r--r--scene/gui/shortcut.cpp8
-rw-r--r--scene/main/scene_tree.cpp2
-rw-r--r--scene/main/viewport.cpp901
-rw-r--r--scene/main/viewport.h150
-rw-r--r--servers/rendering/rendering_device.cpp6
45 files changed, 1722 insertions, 719 deletions
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index cd8096c610..b09e78d653 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -545,8 +545,26 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_METHOD_OF_VARIANT_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_METHOD_OF_BASE_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_METHOD_OF_INSTANCE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_METHOD_OF_SCRIPT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PROPERTY_OF_BASE_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PROPERTY_OF_INSTANCE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PROPERTY_OF_SCRIPT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_TOO_BIG);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_STORAGE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NETWORK);
@@ -562,6 +580,22 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NULL);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_ANIMATE_AS_TRIGGER);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CLASS_IS_ENUM);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NIL_IS_VARIANT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_INTERNAL);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_HIGH_END_GFX);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_KEYING_INCREMENTS);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFERRED_SET_RESOURCE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_BASIC_SETTING);
+
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT_INTL);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NOEDITOR);
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 660e215478..49570cd1c1 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -38,6 +38,25 @@
#ifdef TOOLS_ENABLED
+static String get_type_name(const PropertyInfo &p_info) {
+ if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM)) {
+ return String("enum::") + String(p_info.class_name);
+ }
+ if (p_info.class_name != StringName()) {
+ return p_info.class_name;
+ }
+ if (p_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ return p_info.hint_string;
+ }
+ if (p_info.type == Variant::NIL && (p_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) {
+ return "Variant";
+ }
+ if (p_info.type == Variant::NIL) {
+ return "void";
+ }
+ return Variant::get_type_name(p_info.type);
+}
+
Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary api_dump;
@@ -60,20 +79,38 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
const uint32_t vec3_elems = 3;
const uint32_t ptrsize_32 = 4;
- const uint32_t ptrsize_64 = 4;
+ const uint32_t ptrsize_64 = 8;
static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" };
{
//type sizes
- struct {
+ constexpr struct {
Variant::Type type;
uint32_t size_32_bits_real_float;
uint32_t size_64_bits_real_float;
uint32_t size_32_bits_real_double;
uint32_t size_64_bits_real_double;
+
+ // For compile-time size check.
+ constexpr uint32_t operator[](int index) const {
+ switch (index) {
+#ifndef REAL_T_IS_DOUBLE
+ case sizeof(uint32_t):
+ return size_32_bits_real_float;
+ case sizeof(uint64_t):
+ return size_64_bits_real_float;
+#else // REAL_T_IS_DOUBLE
+ case sizeof(uint32_t):
+ return size_32_bits_real_double;
+ case sizeof(uint64_t):
+ return size_64_bits_real_double;
+#endif
+ }
+ return -1;
+ }
} type_size_array[Variant::VARIANT_MAX + 1] = {
{ Variant::NIL, 0, 0, 0, 0 },
- { Variant::BOOL, sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) },
+ { Variant::BOOL, sizeof(uint8_t), sizeof(uint8_t), sizeof(uint8_t), sizeof(uint8_t) },
{ Variant::INT, sizeof(int64_t), sizeof(int64_t), sizeof(int64_t), sizeof(int64_t) },
{ Variant::FLOAT, sizeof(double), sizeof(double), sizeof(double), sizeof(double) },
{ Variant::STRING, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
@@ -98,25 +135,62 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{ Variant::SIGNAL, sizeof(Signal), sizeof(Signal), sizeof(Signal), sizeof(Signal) }, // Hardcoded align.
{ Variant::DICTIONARY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_BYTE_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_INT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_INT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_FLOAT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_FLOAT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_STRING_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_VECTOR2_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_VECTOR3_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
- { Variant::PACKED_COLOR_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
+ { Variant::PACKED_BYTE_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_INT32_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_INT64_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_FLOAT32_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_FLOAT64_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_STRING_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_VECTOR2_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_VECTOR3_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
+ { Variant::PACKED_COLOR_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 },
{ Variant::VARIANT_MAX, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(double) * 4, sizeof(uint64_t) + sizeof(double) * 4 },
};
+ // Validate sizes at compile time for the current build configuration.
+ static_assert(type_size_array[Variant::BOOL][sizeof(void *)] == sizeof(GDNativeBool), "Size of bool mismatch");
+ static_assert(type_size_array[Variant::INT][sizeof(void *)] == sizeof(GDNativeInt), "Size of int mismatch");
+ static_assert(type_size_array[Variant::FLOAT][sizeof(void *)] == sizeof(double), "Size of float mismatch");
+ static_assert(type_size_array[Variant::STRING][sizeof(void *)] == sizeof(String), "Size of String mismatch");
+ static_assert(type_size_array[Variant::VECTOR2][sizeof(void *)] == sizeof(Vector2), "Size of Vector2 mismatch");
+ static_assert(type_size_array[Variant::VECTOR2I][sizeof(void *)] == sizeof(Vector2i), "Size of Vector2i mismatch");
+ static_assert(type_size_array[Variant::RECT2][sizeof(void *)] == sizeof(Rect2), "Size of Rect2 mismatch");
+ static_assert(type_size_array[Variant::RECT2I][sizeof(void *)] == sizeof(Rect2i), "Size of Rect2i mismatch");
+ static_assert(type_size_array[Variant::VECTOR3][sizeof(void *)] == sizeof(Vector3), "Size of Vector3 mismatch");
+ static_assert(type_size_array[Variant::VECTOR3I][sizeof(void *)] == sizeof(Vector3i), "Size of Vector3i mismatch");
+ static_assert(type_size_array[Variant::TRANSFORM2D][sizeof(void *)] == sizeof(Transform2D), "Size of Transform2D mismatch");
+ static_assert(type_size_array[Variant::PLANE][sizeof(void *)] == sizeof(Plane), "Size of Plane mismatch");
+ static_assert(type_size_array[Variant::QUATERNION][sizeof(void *)] == sizeof(Quaternion), "Size of Quaternion mismatch");
+ static_assert(type_size_array[Variant::AABB][sizeof(void *)] == sizeof(AABB), "Size of AABB mismatch");
+ static_assert(type_size_array[Variant::BASIS][sizeof(void *)] == sizeof(Basis), "Size of Basis mismatch");
+ static_assert(type_size_array[Variant::TRANSFORM3D][sizeof(void *)] == sizeof(Transform3D), "Size of Transform3D mismatch");
+ static_assert(type_size_array[Variant::COLOR][sizeof(void *)] == sizeof(Color), "Size of Color mismatch");
+ static_assert(type_size_array[Variant::STRING_NAME][sizeof(void *)] == sizeof(StringName), "Size of StringName mismatch");
+ static_assert(type_size_array[Variant::NODE_PATH][sizeof(void *)] == sizeof(NodePath), "Size of NodePath mismatch");
+ static_assert(type_size_array[Variant::RID][sizeof(void *)] == sizeof(RID), "Size of RID mismatch");
+ static_assert(type_size_array[Variant::OBJECT][sizeof(void *)] == sizeof(Object *), "Size of Object mismatch");
+ static_assert(type_size_array[Variant::CALLABLE][sizeof(void *)] == sizeof(Callable), "Size of Callable mismatch");
+ static_assert(type_size_array[Variant::SIGNAL][sizeof(void *)] == sizeof(Signal), "Size of Signal mismatch");
+ static_assert(type_size_array[Variant::DICTIONARY][sizeof(void *)] == sizeof(Dictionary), "Size of Dictionary mismatch");
+ static_assert(type_size_array[Variant::ARRAY][sizeof(void *)] == sizeof(Array), "Size of Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_BYTE_ARRAY][sizeof(void *)] == sizeof(PackedByteArray), "Size of PackedByteArray mismatch");
+ static_assert(type_size_array[Variant::PACKED_INT32_ARRAY][sizeof(void *)] == sizeof(PackedInt32Array), "Size of PackedInt32Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_INT64_ARRAY][sizeof(void *)] == sizeof(PackedInt64Array), "Size of PackedInt64Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_FLOAT32_ARRAY][sizeof(void *)] == sizeof(PackedFloat32Array), "Size of PackedFloat32Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_FLOAT64_ARRAY][sizeof(void *)] == sizeof(PackedFloat64Array), "Size of PackedFloat64Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_STRING_ARRAY][sizeof(void *)] == sizeof(PackedStringArray), "Size of PackedStringArray mismatch");
+ static_assert(type_size_array[Variant::PACKED_VECTOR2_ARRAY][sizeof(void *)] == sizeof(PackedVector2Array), "Size of PackedVector2Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_VECTOR3_ARRAY][sizeof(void *)] == sizeof(PackedVector3Array), "Size of PackedVector3Array mismatch");
+ static_assert(type_size_array[Variant::PACKED_COLOR_ARRAY][sizeof(void *)] == sizeof(PackedColorArray), "Size of PackedColorArray mismatch");
+ static_assert(type_size_array[Variant::VARIANT_MAX][sizeof(void *)] == sizeof(Variant), "Size of Variant mismatch");
+
Array core_type_sizes;
for (int i = 0; i < 4; i++) {
Dictionary d;
d["build_configuration"] = build_config_name[i];
Array sizes;
- for (int j = 0; j < Variant::VARIANT_MAX; j++) {
+ for (int j = 0; j <= Variant::VARIANT_MAX; j++) {
Variant::Type t = type_size_array[j].type;
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
Dictionary d2;
@@ -356,6 +430,8 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
}
+ d["is_keyed"] = Variant::ValidatedKeyedSetter(type);
+
{
//members
Array members;
@@ -403,6 +479,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) {
d2["right_type"] = Variant::get_type_name(Variant::Type(j));
}
+ d2["return_type"] = Variant::get_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
operators.push_back(d2);
}
}
@@ -482,6 +559,10 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d["constructors"] = constructors;
}
}
+ {
+ //destructor
+ d["has_destructor"] = Variant::has_destructor(type);
+ }
builtins.push_back(d);
}
@@ -590,16 +671,8 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
if (i >= 0) {
d3["name"] = pinfo.name;
}
- if (pinfo.class_name != StringName()) {
- d3["type"] = String(pinfo.class_name);
- } else {
- Variant::Type type = pinfo.type;
- if (type == Variant::NIL) {
- d3["type"] = "Variant";
- } else {
- d3["type"] = Variant::get_type_name(type);
- }
- }
+
+ d3["type"] = get_type_name(pinfo);
if (i == -1) {
d2["return_value"] = d3;
@@ -641,16 +714,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
if (i >= 0) {
d3["name"] = pinfo.name;
}
- if (pinfo.class_name != StringName()) {
- d3["type"] = String(pinfo.class_name);
- } else {
- Variant::Type type = pinfo.type;
- if (type == Variant::NIL) {
- d3["type"] = "Variant";
- } else {
- d3["type"] = Variant::get_type_name(type);
- }
- }
+ d3["type"] = get_type_name(pinfo);
if (method->get_argument_meta(i) > 0) {
static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" };
@@ -697,14 +761,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int i = 0; i < F.arguments.size(); i++) {
Dictionary d3;
d3["name"] = F.arguments[i].name;
- Variant::Type type = F.arguments[i].type;
- if (F.arguments[i].class_name != StringName()) {
- d3["type"] = String(F.arguments[i].class_name);
- } else if (type == Variant::NIL) {
- d3["type"] = "Variant";
- } else {
- d3["type"] = Variant::get_type_name(type);
- }
+ d3["type"] = get_type_name(F.arguments[i]);
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -732,16 +789,8 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
StringName property_name = F.name;
Dictionary d2;
+ d2["type"] = get_type_name(F);
d2["name"] = String(property_name);
-
- if (F.class_name != StringName()) {
- d2["type"] = String(F.class_name);
- } else if (F.type == Variant::NIL && F.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
- d2["type"] = "Variant";
- } else {
- d2["type"] = Variant::get_type_name(F.type);
- }
-
d2["setter"] = ClassDB::get_property_setter(class_name, F.name);
d2["getter"] = ClassDB::get_property_getter(class_name, F.name);
d2["index"] = ClassDB::get_property_index(class_name, F.name);
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 88fff342ee..a444b2e18e 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -299,6 +299,161 @@ static GDNativeBool gdnative_variant_can_convert_strict(GDNativeVariantType p_fr
return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to);
}
+// Variant interaction.
+static GDNativeVariantFromTypeConstructorFunc gdnative_get_variant_from_type_constructor(GDNativeVariantType p_type) {
+ switch (p_type) {
+ case GDNATIVE_VARIANT_TYPE_BOOL:
+ return VariantTypeConstructor<bool>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_INT:
+ return VariantTypeConstructor<int64_t>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_FLOAT:
+ return VariantTypeConstructor<double>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_STRING:
+ return VariantTypeConstructor<String>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_VECTOR2:
+ return VariantTypeConstructor<Vector2>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_VECTOR2I:
+ return VariantTypeConstructor<Vector2i>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_RECT2:
+ return VariantTypeConstructor<Rect2>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_RECT2I:
+ return VariantTypeConstructor<Rect2i>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_VECTOR3:
+ return VariantTypeConstructor<Vector3>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_VECTOR3I:
+ return VariantTypeConstructor<Vector3i>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_TRANSFORM2D:
+ return VariantTypeConstructor<Transform2D>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PLANE:
+ return VariantTypeConstructor<Plane>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_QUATERNION:
+ return VariantTypeConstructor<Quaternion>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_AABB:
+ return VariantTypeConstructor<AABB>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_BASIS:
+ return VariantTypeConstructor<Basis>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_TRANSFORM3D:
+ return VariantTypeConstructor<Transform3D>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_COLOR:
+ return VariantTypeConstructor<Color>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_STRING_NAME:
+ return VariantTypeConstructor<StringName>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_NODE_PATH:
+ return VariantTypeConstructor<NodePath>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_RID:
+ return VariantTypeConstructor<RID>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_OBJECT:
+ return VariantTypeConstructor<Object *>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_CALLABLE:
+ return VariantTypeConstructor<Callable>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_SIGNAL:
+ return VariantTypeConstructor<Signal>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_DICTIONARY:
+ return VariantTypeConstructor<Dictionary>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_ARRAY:
+ return VariantTypeConstructor<Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY:
+ return VariantTypeConstructor<PackedByteArray>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY:
+ return VariantTypeConstructor<PackedInt32Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY:
+ return VariantTypeConstructor<PackedInt64Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
+ return VariantTypeConstructor<PackedFloat32Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
+ return VariantTypeConstructor<PackedFloat64Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY:
+ return VariantTypeConstructor<PackedStringArray>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
+ return VariantTypeConstructor<PackedVector2Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
+ return VariantTypeConstructor<PackedVector3Array>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY:
+ return VariantTypeConstructor<PackedColorArray>::variant_from_type;
+ case GDNATIVE_VARIANT_TYPE_NIL:
+ case GDNATIVE_VARIANT_TYPE_VARIANT_MAX:
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+ }
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+}
+
+static GDNativeTypeFromVariantConstructorFunc gdnative_get_type_from_variant_constructor(GDNativeVariantType p_type) {
+ switch (p_type) {
+ case GDNATIVE_VARIANT_TYPE_BOOL:
+ return VariantTypeConstructor<bool>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_INT:
+ return VariantTypeConstructor<int64_t>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_FLOAT:
+ return VariantTypeConstructor<double>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_STRING:
+ return VariantTypeConstructor<String>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_VECTOR2:
+ return VariantTypeConstructor<Vector2>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_VECTOR2I:
+ return VariantTypeConstructor<Vector2i>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_RECT2:
+ return VariantTypeConstructor<Rect2>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_RECT2I:
+ return VariantTypeConstructor<Rect2i>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_VECTOR3:
+ return VariantTypeConstructor<Vector3>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_VECTOR3I:
+ return VariantTypeConstructor<Vector3i>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_TRANSFORM2D:
+ return VariantTypeConstructor<Transform2D>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PLANE:
+ return VariantTypeConstructor<Plane>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_QUATERNION:
+ return VariantTypeConstructor<Quaternion>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_AABB:
+ return VariantTypeConstructor<AABB>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_BASIS:
+ return VariantTypeConstructor<Basis>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_TRANSFORM3D:
+ return VariantTypeConstructor<Transform3D>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_COLOR:
+ return VariantTypeConstructor<Color>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_STRING_NAME:
+ return VariantTypeConstructor<StringName>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_NODE_PATH:
+ return VariantTypeConstructor<NodePath>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_RID:
+ return VariantTypeConstructor<RID>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_OBJECT:
+ return VariantTypeConstructor<Object *>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_CALLABLE:
+ return VariantTypeConstructor<Callable>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_SIGNAL:
+ return VariantTypeConstructor<Signal>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_DICTIONARY:
+ return VariantTypeConstructor<Dictionary>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_ARRAY:
+ return VariantTypeConstructor<Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY:
+ return VariantTypeConstructor<PackedByteArray>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY:
+ return VariantTypeConstructor<PackedInt32Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY:
+ return VariantTypeConstructor<PackedInt64Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
+ return VariantTypeConstructor<PackedFloat32Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
+ return VariantTypeConstructor<PackedFloat64Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY:
+ return VariantTypeConstructor<PackedStringArray>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
+ return VariantTypeConstructor<PackedVector2Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
+ return VariantTypeConstructor<PackedVector3Array>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY:
+ return VariantTypeConstructor<PackedColorArray>::type_from_variant;
+ case GDNATIVE_VARIANT_TYPE_NIL:
+ case GDNATIVE_VARIANT_TYPE_VARIANT_MAX:
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+ }
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+}
+
// ptrcalls
static GDNativePtrOperatorEvaluator gdnative_variant_get_ptr_operator_evaluator(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b) {
return (GDNativePtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
@@ -316,6 +471,9 @@ static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNative
static GDNativePtrConstructor gdnative_variant_get_ptr_constructor(GDNativeVariantType p_type, int32_t p_constructor) {
return (GDNativePtrConstructor)Variant::get_ptr_constructor(Variant::Type(p_type), p_constructor);
}
+static GDNativePtrDestructor gdnative_variant_get_ptr_destructor(GDNativeVariantType p_type) {
+ return (GDNativePtrDestructor)Variant::get_ptr_destructor(Variant::Type(p_type));
+}
static void gdnative_variant_construct(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error) {
memnew_placement(p_base, Variant);
@@ -521,11 +679,16 @@ static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
}
-static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_instance, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks) {
+static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_instance, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
Object *o = (Object *)p_instance;
return o->get_instance_binding(p_token, p_callbacks);
}
+static void gdnative_object_set_instance_binding(GDNativeObjectPtr p_instance, void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks) {
+ Object *o = (Object *)p_instance;
+ o->set_instance_binding(p_token, p_binding, p_callbacks);
+}
+
static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
}
@@ -626,15 +789,15 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_can_convert = gdnative_variant_can_convert;
gdni.variant_can_convert_strict = gdnative_variant_can_convert_strict;
- //ptrcalls
-#if 0
- GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type);
- GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type);
-#endif
+ gdni.get_variant_from_type_constructor = gdnative_get_variant_from_type_constructor;
+ gdni.get_variant_to_type_constructor = gdnative_get_type_from_variant_constructor;
+
+ // ptrcalls.
gdni.variant_get_ptr_operator_evaluator = gdnative_variant_get_ptr_operator_evaluator;
gdni.variant_get_ptr_builtin_method = gdnative_variant_get_ptr_builtin_method;
gdni.variant_get_ptr_constructor = gdnative_variant_get_ptr_constructor;
+ gdni.variant_get_ptr_destructor = gdnative_variant_get_ptr_destructor;
gdni.variant_construct = gdnative_variant_construct;
gdni.variant_get_ptr_setter = gdnative_variant_get_ptr_setter;
gdni.variant_get_ptr_getter = gdnative_variant_get_ptr_getter;
@@ -672,6 +835,7 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.object_destroy = gdnative_object_destroy;
gdni.global_get_singleton = gdnative_global_get_singleton;
gdni.object_get_instance_binding = gdnative_object_get_instance_binding;
+ gdni.object_set_instance_binding = gdnative_object_set_instance_binding;
gdni.object_cast_to = gdnative_object_cast_to;
gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 3e69a28d59..3432d8fabe 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -39,6 +39,11 @@
#include <stdint.h>
#include <stdio.h>
+#ifndef __cplusplus
+typedef uint32_t char32_t;
+typedef uint16_t char16_t;
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -140,12 +145,12 @@ typedef uint64_t GDObjectInstanceID;
/* VARIANT DATA I/O */
typedef enum {
- NATIVE_CALL_OK,
- NATIVE_CALL_ERROR_INVALID_METHOD,
- NATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */
- NATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
- NATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
- NATIVE_CALL_ERROR_INSTANCE_IS_NULL,
+ GDNATIVE_CALL_OK,
+ GDNATIVE_CALL_ERROR_INVALID_METHOD,
+ GDNATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */
+ GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
+ GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
+ GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL,
} GDNativeCallErrorType;
@@ -160,6 +165,7 @@ typedef void (*GDNativeTypeFromVariantConstructorFunc)(GDNativeTypePtr, GDNative
typedef void (*GDNativePtrOperatorEvaluator)(const GDNativeTypePtr p_left, const GDNativeTypePtr p_right, GDNativeTypePtr r_result);
typedef void (*GDNativePtrBuiltInMethod)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args, GDNativeTypePtr r_return, int p_argument_count);
typedef void (*GDNativePtrConstructor)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args);
+typedef void (*GDNativePtrDestructor)(GDNativeTypePtr p_base);
typedef void (*GDNativePtrSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_value);
typedef void (*GDNativePtrGetter)(const GDNativeTypePtr p_base, GDNativeTypePtr r_value);
typedef void (*GDNativePtrIndexedSetter)(GDNativeTypePtr p_base, GDNativeInt p_index, const GDNativeTypePtr p_value);
@@ -173,7 +179,7 @@ typedef GDNativeObjectPtr (*GDNativeClassConstructor)();
typedef void *(*GDNativeInstanceBindingCreateCallback)(void *p_token, void *p_instance);
typedef void (*GDNativeInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding);
-typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_instance, GDNativeBool p_reference);
+typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_binding, GDNativeBool p_reference);
struct GDNativeInstanceBindingCallbacks {
GDNativeInstanceBindingCreateCallback create_callback;
@@ -206,6 +212,7 @@ typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_
typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
typedef GDExtensionClassInstancePtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata);
typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
+typedef void (*GDNativeExtensionClassObjectInstance)(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance);
typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name);
typedef struct {
@@ -219,7 +226,8 @@ typedef struct {
GDNativeExtensionClassUnreference unreference_func;
GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
- GDNativeExtensionClassGetVirtual get_firtual_func;
+ GDNativeExtensionClassObjectInstance object_instance_func; /* this one is mandatory */
+ GDNativeExtensionClassGetVirtual get_virtual_func;
void *class_userdata;
} GDNativeExtensionClassCreationInfo;
@@ -256,8 +264,8 @@ typedef enum {
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE
} GDNativeExtensionClassMethodArgumentMetadata;
-typedef void (*GDNativeExtensionClassMethodCall)(GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
-typedef void (*GDNativeExtensionClassMethodPtrCall)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
+typedef void (*GDNativeExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
+typedef void (*GDNativeExtensionClassMethodPtrCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
/* passing -1 as argument in the following functions refers to the return type */
typedef GDNativeVariantType (*GDNativeExtensionClassMethodGetArgumentType)(void *p_method_userdata, int32_t p_argument);
@@ -339,6 +347,7 @@ typedef struct {
GDNativePtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b);
GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash);
GDNativePtrConstructor (*variant_get_ptr_constructor)(GDNativeVariantType p_type, int32_t p_constructor);
+ GDNativePtrDestructor (*variant_get_ptr_destructor)(GDNativeVariantType p_type);
void (*variant_construct)(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error);
GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const char *p_member);
GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const char *p_member);
@@ -383,7 +392,8 @@ typedef struct {
void (*object_method_bind_ptrcall)(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
void (*object_destroy)(GDNativeObjectPtr p_o);
GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
- void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks);
+ void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
+ void (*object_set_instance_binding)(GDNativeObjectPtr p_o, void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index 16bc28e0a2..91d304627a 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "native_extension.h"
+#include "core/config/project_settings.h"
#include "core/io/config_file.h"
#include "core/object/class_db.h"
#include "core/object/method_bind.h"
@@ -69,7 +70,7 @@ public:
Variant ret;
GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
GDNativeCallError ce;
- call_func(extension_instance, (const GDNativeVariantPtr *)p_args, p_arg_count, (GDNativeVariantPtr)&ret, &ce);
+ call_func(method_userdata, extension_instance, (const GDNativeVariantPtr *)p_args, p_arg_count, (GDNativeVariantPtr)&ret, &ce);
r_error.error = Callable::CallError::Error(ce.error);
r_error.argument = ce.argument;
r_error.expected = ce.expected;
@@ -78,7 +79,7 @@ public:
virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
- ptrcall_func(extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret);
+ ptrcall_func(method_userdata, extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret);
}
virtual bool is_vararg() const {
@@ -91,6 +92,7 @@ public:
get_argument_type_func = p_method_info->get_argument_type_func;
get_argument_info_func = p_method_info->get_argument_info_func;
get_argument_metadata_func = p_method_info->get_argument_metadata_func;
+ set_name(p_method_info->name);
vararg = p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_VARARG;
@@ -109,7 +111,7 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(String(class_name).is_valid_identifier(), "Attempt to register extension clas '" + class_name + "', which is not a valid class identifier.");
+ ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
Extension *parent_extension = nullptr;
@@ -150,6 +152,7 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.unreference = p_extension_funcs->unreference_func;
extension->native_extension.class_userdata = p_extension_funcs->class_userdata;
extension->native_extension.create_instance = p_extension_funcs->create_instance_func;
+ extension->native_extension.set_object_instance = p_extension_funcs->object_instance_func;
extension->native_extension.free_instance = p_extension_funcs->free_instance_func;
ClassDB::register_extension_class(&extension->native_extension);
@@ -159,11 +162,12 @@ void NativeExtension::_register_extension_class_method(const GDNativeExtensionCl
StringName class_name = p_class_name;
StringName method_name = p_method_info->name;
- ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
NativeExtensionMethodBind *method = memnew(NativeExtensionMethodBind(p_method_info));
+ method->set_instance_class(class_name);
ClassDB::bind_method_custom(class_name, method);
}
@@ -171,7 +175,7 @@ void NativeExtension::_register_extension_class_integer_constant(const GDNativeE
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
@@ -181,7 +185,7 @@ void NativeExtension::_register_extension_class_property(const GDNativeExtension
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension class property '" + String(p_info->name) + "' for unexisting class '" + class_name + "'.");
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + String(p_info->name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
PropertyInfo pinfo;
@@ -199,7 +203,7 @@ void NativeExtension::_register_extension_class_signal(const GDNativeExtensionCl
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
MethodInfo s;
s.name = p_signal_name;
@@ -220,7 +224,7 @@ void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLi
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
Extension *ext = &self->extension_classes[class_name];
ERR_FAIL_COND_MSG(ext->native_extension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
@@ -368,7 +372,7 @@ RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_or
}
}
- if (library_path != String()) {
+ if (library_path == String()) {
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
@@ -381,7 +385,8 @@ RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_or
Ref<NativeExtension> lib;
lib.instantiate();
- err = lib->open_library(library_path, entry_symbol);
+ String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
+ err = lib->open_library(abs_path, entry_symbol);
if (r_error) {
*r_error = err;
diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h
index 0a23848eb2..8bd95b2867 100644
--- a/core/extension/native_extension.h
+++ b/core/extension/native_extension.h
@@ -35,8 +35,8 @@
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
-class NativeExtension : public RefCounted {
- GDCLASS(NativeExtension, RefCounted)
+class NativeExtension : public Resource {
+ GDCLASS(NativeExtension, Resource)
void *library = nullptr; // pointer if valid,
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 4a2abffae8..1715fca9e8 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -32,6 +32,7 @@
#include "core/input/input_map.h"
#include "core/os/keyboard.h"
+#include "scene/gui/shortcut.h"
const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1;
const int InputEvent::DEVICE_ID_INTERNAL = -2;
@@ -1512,3 +1513,26 @@ void InputEventMIDI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_number"), "set_controller_number", "get_controller_number");
ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_value"), "set_controller_value", "get_controller_value");
}
+
+///////////////////////////////////
+
+void InputEventShortcut::set_shortcut(Ref<Shortcut> p_shortcut) {
+ shortcut = p_shortcut;
+ emit_changed();
+}
+
+Ref<Shortcut> InputEventShortcut::get_shortcut() {
+ return shortcut;
+}
+
+bool InputEventShortcut::is_pressed() const {
+ return true;
+}
+
+String InputEventShortcut::as_text() const {
+ return vformat(RTR("Input Event with Shortcut=%s"), shortcut->get_as_text());
+}
+
+String InputEventShortcut::to_string() {
+ return vformat("InputEventShortcut: shortcut=%s", shortcut->get_as_text());
+}
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 76a45c04a4..98d204fe13 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -42,6 +42,8 @@
* The events are pretty obvious.
*/
+class Shortcut;
+
/**
* Input Modifier Status
* for keyboard/mouse events.
@@ -538,4 +540,18 @@ public:
InputEventMIDI() {}
};
+class InputEventShortcut : public InputEvent {
+ GDCLASS(InputEventShortcut, InputEvent);
+
+ Ref<Shortcut> shortcut;
+
+public:
+ void set_shortcut(Ref<Shortcut> p_shortcut);
+ Ref<Shortcut> get_shortcut();
+ virtual bool is_pressed() const override;
+
+ virtual String as_text() const override;
+ virtual String to_string() override;
+};
+
#endif // INPUT_EVENT_H
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index c6ba39be94..c58fe7bc24 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -505,11 +505,12 @@ thread_local bool initializing_with_extension = false;
thread_local ObjectNativeExtension *initializing_extension = nullptr;
thread_local GDExtensionClassInstancePtr initializing_extension_instance = nullptr;
-void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance) {
+void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance, Object *p_base) {
if (initializing_with_extension) {
*r_extension = initializing_extension;
*r_extension_instance = initializing_extension_instance;
initializing_with_extension = false;
+ initializing_extension->set_object_instance(*r_extension_instance, p_base);
} else {
*r_extension = nullptr;
*r_extension_instance = nullptr;
@@ -1592,7 +1593,7 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
GLOBAL_LOCK_FUNCTION;
ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name));
- ERR_FAIL_COND_MSG(classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name));
+ ERR_FAIL_COND_MSG(!classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name));
ClassInfo *parent = classes.getptr(p_extension->parent_class_name);
@@ -1604,6 +1605,7 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
+ c.exposed = true;
classes[p_extension->class_name] = c;
}
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 3a84e9ab38..bfc9d6f283 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -233,7 +233,7 @@ public:
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
static bool can_instantiate(const StringName &p_class);
static Object *instantiate(const StringName &p_class);
- static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance);
+ static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance, Object *p_base);
static APIType get_api_type(const StringName &p_class);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index d552d5e5e0..c191109a8f 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1815,7 +1815,7 @@ void Object::_construct_object(bool p_reference) {
type_is_reference = p_reference;
_instance_id = ObjectDB::add_instance(this);
- ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance);
+ ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance, this);
#ifdef DEBUG_ENABLED
_lock_index.init(1);
@@ -1876,7 +1876,7 @@ Object::~Object() {
if (_instance_bindings != nullptr) {
for (uint32_t i = 0; i < _instance_binding_count; i++) {
if (_instance_bindings[i].free_callback) {
- _instance_bindings[i].free_callback(_instance_bindings[i].token, _instance_bindings[i].binding, this);
+ _instance_bindings[i].free_callback(_instance_bindings[i].token, this, _instance_bindings[i].binding);
}
}
memfree(_instance_bindings);
diff --git a/core/object/object.h b/core/object/object.h
index b7d0916a54..1f5e17c99f 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -272,6 +272,7 @@ struct ObjectNativeExtension {
GDNativeExtensionClassCreateInstance create_instance;
GDNativeExtensionClassFreeInstance free_instance;
+ GDNativeExtensionClassObjectInstance set_object_instance;
GDNativeExtensionClassGetVirtual get_virtual;
};
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 3d1cb4a8e1..f801be3db3 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -82,6 +82,7 @@ static Ref<ResourceFormatLoaderImage> resource_format_image;
static Ref<TranslationLoaderPO> resource_format_po;
static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto;
static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto;
+static Ref<NativeExtensionResourceLoader> resource_loader_native_extension;
static _ResourceLoader *_resource_loader = nullptr;
static _ResourceSaver *_resource_saver = nullptr;
@@ -234,6 +235,9 @@ void register_core_types() {
native_extension_manager = memnew(NativeExtensionManager);
+ resource_loader_native_extension.instantiate();
+ ResourceLoader::add_resource_format_loader(resource_loader_native_extension);
+
ip = IP::create();
_geometry_2d = memnew(_Geometry2D);
@@ -298,6 +302,7 @@ void register_core_singletons() {
void register_core_extensions() {
// Hardcoded for now.
+ NativeExtension::initialize_native_extensions();
if (ProjectSettings::get_singleton()->has_setting("native_extensions/paths")) {
Vector<String> paths = ProjectSettings::get_singleton()->get("native_extensions/paths");
for (int i = 0; i < paths.size(); i++) {
@@ -349,6 +354,9 @@ void unregister_core_types() {
memdelete(ip);
}
+ ResourceLoader::remove_resource_format_loader(resource_loader_native_extension);
+ resource_loader_native_extension.unref();
+
ResourceLoader::finalize();
ClassDB::cleanup_defaults();
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 97a1b4c02a..d538b9faff 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3533,12 +3533,13 @@ void Variant::register_types() {
_register_variant_methods();
_register_variant_setters_getters();
_register_variant_constructors();
+ _register_variant_destructors();
_register_variant_utility_functions();
}
void Variant::unregister_types() {
_unregister_variant_operators();
_unregister_variant_methods();
_unregister_variant_setters_getters();
- _unregister_variant_constructors();
+ _unregister_variant_destructors();
_unregister_variant_utility_functions();
}
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 780f9b4e70..9ec131a1b8 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -208,7 +208,7 @@ private:
Transform3D *_transform3d;
PackedArrayRefBase *packed_array;
void *_ptr; //generic pointer
- uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)];
+ uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]{ 0 };
} _data alignas(8);
void reference(const Variant &p_variant);
@@ -271,6 +271,8 @@ private:
static void _register_variant_setters_getters();
static void _unregister_variant_setters_getters();
static void _register_variant_constructors();
+ static void _unregister_variant_destructors();
+ static void _register_variant_destructors();
static void _unregister_variant_constructors();
static void _register_variant_utility_functions();
static void _unregister_variant_utility_functions();
@@ -534,6 +536,14 @@ public:
static void get_constructor_list(Type p_type, List<MethodInfo> *r_list); //convenience
+ /* Destructors */
+
+ // Only ptrcall is available.
+ typedef void (*PTRDestructor)(void *base);
+
+ static PTRDestructor get_ptr_destructor(Variant::Type p_type);
+ static bool has_destructor(Variant::Type p_type);
+
/* Properties */
void set_named(const StringName &p_member, const Variant &p_value, bool &r_valid);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 14840f0d8a..c3481d4896 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1709,7 +1709,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
bind_method(Transform2D, set_rotation, sarray("rotation"), varray());
- bind_method(Transform2D, looking_at, sarray("target"), varray(Transform2D()));
+ bind_method(Transform2D, looking_at, sarray("target"), varray(Vector2()));
/* Basis */
diff --git a/core/variant/variant_destruct.cpp b/core/variant/variant_destruct.cpp
new file mode 100644
index 0000000000..366b71df3a
--- /dev/null
+++ b/core/variant/variant_destruct.cpp
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* variant_destruct.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "variant_destruct.h"
+
+#include "core/templates/local_vector.h"
+
+static Variant::PTRDestructor destruct_pointers[Variant::VARIANT_MAX] = { nullptr };
+
+template <class T>
+static void add_destructor() {
+ destruct_pointers[T::get_base_type()] = T::ptr_destruct;
+}
+
+void Variant::_register_variant_destructors() {
+ add_destructor<VariantDestruct<String>>();
+ add_destructor<VariantDestruct<Transform2D>>();
+ add_destructor<VariantDestruct<::AABB>>();
+ add_destructor<VariantDestruct<Basis>>();
+ add_destructor<VariantDestruct<Transform3D>>();
+ add_destructor<VariantDestruct<StringName>>();
+ add_destructor<VariantDestruct<NodePath>>();
+ add_destructor<VariantDestruct<::RID>>();
+ add_destructor<VariantDestruct<Callable>>();
+ add_destructor<VariantDestruct<Signal>>();
+ add_destructor<VariantDestruct<Dictionary>>();
+ add_destructor<VariantDestruct<Array>>();
+ add_destructor<VariantDestruct<PackedByteArray>>();
+ add_destructor<VariantDestruct<PackedInt32Array>>();
+ add_destructor<VariantDestruct<PackedInt64Array>>();
+ add_destructor<VariantDestruct<PackedFloat32Array>>();
+ add_destructor<VariantDestruct<PackedFloat64Array>>();
+ add_destructor<VariantDestruct<PackedStringArray>>();
+ add_destructor<VariantDestruct<PackedVector2Array>>();
+ add_destructor<VariantDestruct<PackedVector3Array>>();
+ add_destructor<VariantDestruct<PackedColorArray>>();
+}
+
+void Variant::_unregister_variant_destructors() {
+ // Nothing to be done.
+}
+
+Variant::PTRDestructor Variant::get_ptr_destructor(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return destruct_pointers[p_type];
+}
+
+bool Variant::has_destructor(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ return destruct_pointers[p_type] != nullptr;
+}
diff --git a/core/variant/variant_destruct.h b/core/variant/variant_destruct.h
new file mode 100644
index 0000000000..7356e42201
--- /dev/null
+++ b/core/variant/variant_destruct.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* variant_destruct.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef VARIANT_DESTRUCT_H
+#define VARIANT_DESTRUCT_H
+
+#include "core/variant/variant.h"
+
+#include "core/object/class_db.h"
+
+template <class T>
+struct VariantDestruct {};
+
+#define MAKE_PTRDESTRUCT(m_type) \
+ template <> \
+ struct VariantDestruct<m_type> { \
+ _FORCE_INLINE_ static void ptr_destruct(void *p_ptr) { \
+ reinterpret_cast<m_type *>(p_ptr)->~m_type(); \
+ } \
+ _FORCE_INLINE_ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_type>::VARIANT_TYPE; \
+ } \
+ }
+
+MAKE_PTRDESTRUCT(String);
+MAKE_PTRDESTRUCT(Transform2D);
+MAKE_PTRDESTRUCT(AABB);
+MAKE_PTRDESTRUCT(Basis);
+MAKE_PTRDESTRUCT(Transform3D);
+MAKE_PTRDESTRUCT(StringName);
+MAKE_PTRDESTRUCT(NodePath);
+MAKE_PTRDESTRUCT(RID);
+MAKE_PTRDESTRUCT(Callable);
+MAKE_PTRDESTRUCT(Signal);
+MAKE_PTRDESTRUCT(Dictionary);
+MAKE_PTRDESTRUCT(Array);
+MAKE_PTRDESTRUCT(PackedByteArray);
+MAKE_PTRDESTRUCT(PackedInt32Array);
+MAKE_PTRDESTRUCT(PackedInt64Array);
+MAKE_PTRDESTRUCT(PackedFloat32Array);
+MAKE_PTRDESTRUCT(PackedFloat64Array);
+MAKE_PTRDESTRUCT(PackedStringArray);
+MAKE_PTRDESTRUCT(PackedVector2Array);
+MAKE_PTRDESTRUCT(PackedVector3Array);
+MAKE_PTRDESTRUCT(PackedColorArray);
+
+#undef MAKE_PTRDESTRUCT
+
+#endif // VARIANT_DESTRUCT_H
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 78e1ad06ae..566b14736e 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -1171,6 +1171,11 @@ struct VariantInitializer<PackedColorArray> {
static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_color_array(v); }
};
+template <>
+struct VariantInitializer<Object *> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::object_assign_null(v); }
+};
+
template <class T>
struct VariantZeroAssigner {
};
@@ -1385,4 +1390,19 @@ struct VariantTypeAdjust<Object *> {
}
};
+// GDNative extension helpers.
+
+template <class T>
+struct VariantTypeConstructor {
+ _FORCE_INLINE_ static void variant_from_type(void *p_variant, void *p_value) {
+ Variant *variant = reinterpret_cast<Variant *>(p_variant);
+ VariantInitializer<T>::init(variant);
+ VariantInternalAccessor<T>::set(variant, *((T *)p_value));
+ }
+
+ _FORCE_INLINE_ static void type_from_variant(void *p_value, void *p_variant) {
+ *((T *)p_value) = VariantInternalAccessor<T>::get(reinterpret_cast<Variant *>(p_variant));
+ }
+};
+
#endif // VARIANT_INTERNAL_H
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 7edcf6da82..e78c3d97ae 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2306,6 +2306,8 @@
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="23" enum="PropertyHint">
Hints that an image is compressed using lossless compression.
</constant>
+ <constant name="PROPERTY_HINT_OBJECT_ID" value="24" enum="PropertyHint">
+ </constant>
<constant name="PROPERTY_HINT_TYPE_STRING" value="25" 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]
@@ -2316,6 +2318,38 @@
[/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>
+ <constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="27" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="28" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="29" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="30" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="31" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="32" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="33" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="34" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="35" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="36" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_SAVE_FILE" value="37" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="38" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_ARRAY_TYPE" value="39" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_HINT_MAX" value="40" enum="PropertyHint">
+ </constant>
+ <constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
+ </constant>
<constant name="PROPERTY_USAGE_STORAGE" value="1" enum="PropertyUsageFlags">
The property is serialized and saved in the scene file (default).
</constant>
@@ -2355,6 +2389,36 @@
<constant name="PROPERTY_USAGE_SCRIPT_VARIABLE" value="8192" enum="PropertyUsageFlags">
The property is a script variable which should be serialized and saved in the scene file.
</constant>
+ <constant name="PROPERTY_USAGE_STORE_IF_NULL" value="16384" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_ANIMATE_AS_TRIGGER" value="32768" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED" value="65536" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE" value="131072" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_CLASS_IS_ENUM" value="262144" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_NIL_IS_VARIANT" value="524288" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_INTERNAL" value="1048576" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE" value="2097152" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_HIGH_END_GFX" value="4194304" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT" value="8388608" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT" value="16777216" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_KEYING_INCREMENTS" value="33554432" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_DEFERRED_SET_RESOURCE" value="67108864" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT" value="134217728" enum="PropertyUsageFlags">
+ </constant>
+ <constant name="PROPERTY_USAGE_EDITOR_BASIC_SETTING" value="268435456" enum="PropertyUsageFlags">
+ </constant>
<constant name="PROPERTY_USAGE_DEFAULT" value="7" enum="PropertyUsageFlags">
Default usage (storage, editor and network).
</constant>
diff --git a/doc/classes/EditorCommandPalette.xml b/doc/classes/EditorCommandPalette.xml
new file mode 100644
index 0000000000..743c59eec2
--- /dev/null
+++ b/doc/classes/EditorCommandPalette.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorCommandPalette" inherits="ConfirmationDialog" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_command">
+ <return type="void" />
+ <argument index="0" name="command_name" type="String" />
+ <argument index="1" name="key_name" type="String" />
+ <argument index="2" name="binded_callable" type="Callable" />
+ <argument index="3" name="shortcut_text" type="String" default="&quot;None&quot;" />
+ <description>
+ </description>
+ </method>
+ <method name="remove_command">
+ <return type="void" />
+ <argument index="0" name="key_name" type="String" />
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok" override="true" default="false" />
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 185b4f8c39..91e1dfbf57 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -30,6 +30,11 @@
Returns the main container of Godot editor's window. For example, you can use it to retrieve the size of the container and place your controls accordingly.
</description>
</method>
+ <method name="get_command_palette" qualifiers="const">
+ <return type="EditorCommandPalette" />
+ <description>
+ </description>
+ </method>
<method name="get_current_path" qualifiers="const">
<return type="String" />
<description>
diff --git a/doc/classes/NativeExtension.xml b/doc/classes/NativeExtension.xml
index fa8575383c..ac3e8d53d8 100644
--- a/doc/classes/NativeExtension.xml
+++ b/doc/classes/NativeExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NativeExtension" inherits="RefCounted" version="4.0">
+<class name="NativeExtension" inherits="Resource" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 43778df195..c329821646 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -142,7 +142,7 @@
<argument index="5" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()" />
<argument index="6" name="clear_depth" type="float" default="1.0" />
<argument index="7" name="clear_stencil" type="int" default="0" />
- <argument index="8" name="region" type="Rect2" default="Rect2i(0, 0, 0, 0)" />
+ <argument index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<argument index="9" name="storage_textures" type="Array" default="[]" />
<description>
</description>
@@ -165,7 +165,7 @@
<argument index="6" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()" />
<argument index="7" name="clear_depth" type="float" default="1.0" />
<argument index="8" name="clear_stencil" type="int" default="0" />
- <argument index="9" name="region" type="Rect2" default="Rect2i(0, 0, 0, 0)" />
+ <argument index="9" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<argument index="10" name="storage_textures" type="RID[]" default="[]" />
<description>
</description>
@@ -217,7 +217,7 @@
<method name="draw_list_enable_scissor">
<return type="void" />
<argument index="0" name="draw_list" type="int" />
- <argument index="1" name="rect" type="Rect2" default="Rect2i(0, 0, 0, 0)" />
+ <argument index="1" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<description>
</description>
</method>
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index b9d3951b0a..948585aecb 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -107,7 +107,7 @@
</method>
<method name="looking_at" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="target" type="Vector2" default="Transform2D(1, 0, 0, 1, 0, 0)" />
+ <argument index="0" name="target" type="Vector2" default="Vector2(0, 0)" />
<description>
Returns a copy of the transform rotated such that it's rotation on the X-axis points towards the [code]target[/code] position.
Operations take place in global space.
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index c2edab7e82..7b5cb2c459 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -169,7 +169,7 @@
<member name="audio_listener_enable_2d" type="bool" setter="set_as_audio_listener_2d" getter="is_audio_listener_2d" default="false">
If [code]true[/code], the viewport will process 2D audio streams.
</member>
- <member name="audio_listener_enable_3d" type="bool" setter="set_as_audio_listener" getter="is_audio_listener" default="false">
+ <member name="audio_listener_enable_3d" type="bool" setter="set_as_audio_listener_3d" getter="is_audio_listener_3d" default="false">
If [code]true[/code], the viewport will process 3D audio streams.
</member>
<member name="canvas_item_default_texture_filter" type="int" setter="set_default_canvas_item_texture_filter" getter="get_default_canvas_item_texture_filter" enum="Viewport.DefaultCanvasItemTextureFilter" default="1">
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
new file mode 100644
index 0000000000..5a4fcff0f8
--- /dev/null
+++ b/editor/editor_command_palette.cpp
@@ -0,0 +1,300 @@
+/*************************************************************************/
+/* editor_command_palette.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor/editor_command_palette.h"
+#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "scene/gui/control.h"
+#include "scene/gui/tree.h"
+
+EditorCommandPalette *EditorCommandPalette::singleton = nullptr;
+
+float EditorCommandPalette::_score_path(const String &p_search, const String &p_path) {
+ float score = 0.9f + .1f * (p_search.length() / (float)p_path.length());
+
+ // Positive bias for matches close to the beginning of the file name.
+ int pos = p_path.findn(p_search);
+ if (pos != -1) {
+ return score * (1.0f - 0.1f * (float(pos) / p_path.length()));
+ }
+
+ // Positive bias for matches close to the end of the path.
+ pos = p_path.rfindn(p_search);
+ if (pos != -1) {
+ return score * (0.8f - 0.1f * (float(p_path.length() - pos) / p_path.length()));
+ }
+
+ // Remaining results belong to the same class of results.
+ return score * 0.69f;
+}
+
+void EditorCommandPalette::_update_command_search(const String &search_text) {
+ commands.get_key_list(&command_keys);
+ ERR_FAIL_COND(command_keys.is_empty());
+
+ const bool empty_search = search_text.is_empty();
+ Map<String, TreeItem *> sections;
+ TreeItem *first_section = nullptr;
+
+ // Filter possible candidates.
+ Vector<CommandEntry> entries;
+ for (int i = 0; i < command_keys.size(); i++) {
+ CommandEntry r;
+ r.key_name = command_keys[i];
+ r.display_name = commands[r.key_name].name;
+ r.shortcut_text = commands[r.key_name].shortcut;
+ if (!empty_search && search_text.is_subsequence_ofi(r.display_name)) {
+ r.score = _score_path(search_text, r.display_name.to_lower());
+ entries.push_back(r);
+ }
+ }
+
+ command_keys.clear();
+
+ TreeItem *root = search_options->get_root();
+ root->clear_children();
+
+ if (entries.size() > 0) {
+ if (!empty_search) {
+ SortArray<CommandEntry, CommandEntryComparator> sorter;
+ sorter.sort(entries.ptrw(), entries.size());
+ }
+
+ const int entry_limit = MIN(entries.size(), 300);
+ for (int i = 0; i < entry_limit; i++) {
+ String section_name = entries[i].key_name.get_slice("/", 0);
+ TreeItem *section;
+
+ if (sections.has(section_name)) {
+ section = sections[section_name];
+ } else {
+ section = search_options->create_item(root);
+
+ if (!first_section) {
+ first_section = section;
+ }
+
+ String item_name = section_name.capitalize();
+ section->set_text(0, item_name);
+
+ sections[section_name] = section;
+ section->set_custom_bg_color(0, search_options->get_theme_color("prop_subsection", "Editor"));
+ section->set_custom_bg_color(1, search_options->get_theme_color("prop_subsection", "Editor"));
+ }
+
+ TreeItem *ti = search_options->create_item(section);
+ String shortcut_text = entries[i].shortcut_text == "None" ? "" : entries[i].shortcut_text;
+ ti->set_text(0, entries[i].display_name);
+ ti->set_metadata(0, entries[i].key_name);
+ ti->set_text_align(1, TreeItem::TextAlign::ALIGN_RIGHT);
+ ti->set_text(1, shortcut_text);
+ Color c = Color(1, 1, 1, 0.5);
+ ti->set_custom_color(1, c);
+ }
+
+ TreeItem *to_select = first_section->get_first_child();
+ to_select->select(0);
+ to_select->set_as_cursor(0);
+ search_options->scroll_to_item(to_select);
+
+ get_ok_button()->set_disabled(false);
+ } else {
+ TreeItem *ti = search_options->create_item(root);
+ ti->set_text(0, TTR("No Matching Command"));
+ ti->set_metadata(0, "");
+ Color c = Color(0.5, 0.5, 0.5, 0.5);
+ ti->set_custom_color(0, c);
+ search_options->deselect_all();
+
+ get_ok_button()->set_disabled(true);
+ }
+}
+
+void EditorCommandPalette::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_command", "command_name", "key_name", "binded_callable", "shortcut_text"), &EditorCommandPalette::_add_command, DEFVAL("None"));
+ ClassDB::bind_method(D_METHOD("remove_command", "key_name"), &EditorCommandPalette::remove_command);
+}
+
+void EditorCommandPalette::_sbox_input(const Ref<InputEvent> &p_ie) {
+ Ref<InputEventKey> k = p_ie;
+ if (k.is_valid()) {
+ switch (k->get_keycode()) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+ search_options->call("_gui_input", k);
+ } break;
+ }
+ }
+}
+
+void EditorCommandPalette::_confirmed() {
+ TreeItem *selected_option = search_options->get_selected();
+ String command_key = selected_option != nullptr ? selected_option->get_metadata(0) : "";
+ if (command_key != "") {
+ hide();
+ execute_command(command_key);
+ }
+}
+
+void EditorCommandPalette::open_popup() {
+ popup_centered_clamped(Size2i(600, 440), 0.8f);
+ command_search_box->clear();
+ command_search_box->grab_focus();
+}
+
+void EditorCommandPalette::get_actions_list(List<String> *p_list) const {
+ commands.get_key_list(p_list);
+}
+
+void EditorCommandPalette::remove_command(String p_key_name) {
+ ERR_FAIL_COND_MSG(!commands.has(p_key_name), "The EditorAction '" + String(p_key_name) + "' Doesn't exists. Unable to remove it.");
+
+ commands.erase(p_key_name);
+}
+
+void EditorCommandPalette::add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, String p_shortcut_text) {
+ ERR_FAIL_COND_MSG(commands.has(p_key_name), "The EditorAction '" + String(p_command_name) + "' already exists. Unable to add it.");
+
+ const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * arguments.size());
+ for (int i = 0; i < arguments.size(); i++) {
+ argptrs[i] = &arguments[i];
+ }
+ Command p_command;
+ p_command.name = p_command_name;
+ p_command.callable = p_action.bind(argptrs, arguments.size());
+ p_command.shortcut = p_shortcut_text;
+
+ commands[p_key_name] = p_command;
+}
+
+void EditorCommandPalette::_add_command(String p_command_name, String p_key_name, Callable p_binded_action, String p_shortcut_text) {
+ ERR_FAIL_COND_MSG(commands.has(p_key_name), "The EditorAction '" + String(p_command_name) + "' already exists. Unable to add it.");
+
+ Command p_command;
+ p_command.name = p_command_name;
+ p_command.callable = p_binded_action;
+ p_command.shortcut = p_shortcut_text;
+
+ commands[p_key_name] = p_command;
+}
+
+void EditorCommandPalette::execute_command(String &p_command_key) {
+ ERR_FAIL_COND_MSG(!commands.has(p_command_key), p_command_key + " not found.");
+ commands[p_command_key].callable.call_deferred(nullptr, 0);
+}
+
+void EditorCommandPalette::register_shortcuts_as_command() {
+ const String *p_key = nullptr;
+ p_key = unregistered_shortcuts.next(p_key);
+ while (p_key != nullptr) {
+ String command_name = unregistered_shortcuts[*p_key].first;
+ Ref<Shortcut> p_shortcut = unregistered_shortcuts[*p_key].second;
+ Ref<InputEventShortcut> ev;
+ ev.instantiate();
+ ev->set_shortcut(p_shortcut);
+ String shortcut_text = String(p_shortcut->get_as_text());
+ add_command(command_name, *p_key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::unhandled_input), varray(ev, false), shortcut_text);
+ p_key = unregistered_shortcuts.next(p_key);
+ }
+ unregistered_shortcuts.clear();
+}
+
+Ref<Shortcut> EditorCommandPalette::add_shortcut_command(const String &p_command, const String &p_key, Ref<Shortcut> p_shortcut) {
+ if (is_inside_tree()) {
+ Ref<InputEventShortcut> ev;
+ ev.instantiate();
+ ev->set_shortcut(p_shortcut);
+ String shortcut_text = String(p_shortcut->get_as_text());
+ add_command(p_command, p_key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::unhandled_input), varray(ev, false), shortcut_text);
+ } else {
+ const String key_name = String(p_key);
+ const String command_name = String(p_command);
+ Pair p_pair = Pair(command_name, p_shortcut);
+ unregistered_shortcuts[key_name] = p_pair;
+ }
+ return p_shortcut;
+}
+
+void EditorCommandPalette::_theme_changed() {
+ command_search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons"));
+}
+
+EditorCommandPalette *EditorCommandPalette::get_singleton() {
+ if (singleton == nullptr) {
+ singleton = memnew(EditorCommandPalette);
+ }
+ return singleton;
+}
+
+EditorCommandPalette::EditorCommandPalette() {
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ vbc->connect("theme_changed", callable_mp(this, &EditorCommandPalette::_theme_changed));
+ add_child(vbc);
+
+ command_search_box = memnew(LineEdit);
+ command_search_box->set_placeholder("search for a command");
+ command_search_box->set_placeholder_alpha(0.5);
+ command_search_box->connect("gui_input", callable_mp(this, &EditorCommandPalette::_sbox_input));
+ command_search_box->connect("text_changed", callable_mp(this, &EditorCommandPalette::_update_command_search));
+ command_search_box->connect("text_submitted", callable_mp(this, &EditorCommandPalette::_confirmed).unbind(1));
+ command_search_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ MarginContainer *margin_container_csb = memnew(MarginContainer);
+ margin_container_csb->add_child(command_search_box);
+ vbc->add_child(margin_container_csb);
+ register_text_enter(command_search_box);
+
+ search_options = memnew(Tree);
+ search_options->connect("item_activated", callable_mp(this, &EditorCommandPalette::_confirmed));
+ search_options->create_item();
+ search_options->set_hide_root(true);
+ search_options->set_hide_folding(true);
+ search_options->add_theme_constant_override("draw_guides", 1);
+ search_options->set_columns(2);
+ search_options->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ search_options->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_options->set_column_custom_minimum_width(0, int(8 * EDSCALE));
+
+ vbc->add_child(search_options, true);
+
+ set_hide_on_ok(false);
+}
+
+Ref<Shortcut> ED_SHORTCUT_AND_COMMAND(const String &p_path, const String &p_name, uint32_t p_keycode, String p_command_name) {
+ if (p_command_name.is_empty()) {
+ p_command_name = p_name;
+ }
+
+ Ref<Shortcut> p_shortcut = ED_SHORTCUT(p_path, p_name, p_keycode);
+ EditorCommandPalette::get_singleton()->add_shortcut_command(p_command_name, p_path, p_shortcut);
+ return p_shortcut;
+}
diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h
new file mode 100644
index 0000000000..ddf897c250
--- /dev/null
+++ b/editor/editor_command_palette.h
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* editor_command_palette.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_COMMAND_PALETTE_H
+#define EDITOR_COMMAND_PALETTE_H
+
+#include "core/os/thread_safe.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/shortcut.h"
+#include "scene/gui/tree.h"
+
+class EditorCommandPalette : public ConfirmationDialog {
+ GDCLASS(EditorCommandPalette, ConfirmationDialog);
+
+ static EditorCommandPalette *singleton;
+ LineEdit *command_search_box;
+ Tree *search_options;
+
+ struct Command {
+ Callable callable;
+ String name;
+ String shortcut;
+ };
+
+ struct CommandEntry {
+ String key_name;
+ String display_name;
+ String shortcut_text;
+ float score;
+ };
+
+ struct CommandEntryComparator {
+ _FORCE_INLINE_ bool operator()(const CommandEntry &A, const CommandEntry &B) const {
+ return A.score > B.score;
+ }
+ };
+
+ HashMap<String, Command> commands;
+ HashMap<String, Pair<String, Ref<Shortcut>>> unregistered_shortcuts;
+
+ List<String> command_keys;
+
+ void _update_command_search(const String &search_text);
+ float _score_path(const String &p_search, const String &p_path);
+ void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _confirmed();
+ void _update_command_keys();
+ void _add_command(String p_command_name, String p_key_name, Callable p_binded_action, String p_shortcut_text = "None");
+ void _theme_changed();
+ EditorCommandPalette();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void open_popup();
+ void get_actions_list(List<String> *p_list) const;
+ void add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, String p_shortcut_text = "None");
+ void execute_command(String &p_command_name);
+ void register_shortcuts_as_command();
+ Ref<Shortcut> add_shortcut_command(const String &p_command, const String &p_key, Ref<Shortcut> p_shortcut);
+ void remove_command(String p_key_name);
+ static EditorCommandPalette *get_singleton();
+};
+
+Ref<Shortcut> ED_SHORTCUT_AND_COMMAND(const String &p_path, const String &p_name, uint32_t p_keycode = 0, String p_command = "");
+
+#endif //EDITOR_COMMAND_PALETTE_H
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 2126a7b8be..52672e9cc8 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -75,6 +75,7 @@
#include "editor/dependency_editor.h"
#include "editor/editor_about.h"
#include "editor/editor_audio_buses.h"
+#include "editor/editor_command_palette.h"
#include "editor/editor_export.h"
#include "editor/editor_feature_profile.h"
#include "editor/editor_file_system.h"
@@ -404,7 +405,7 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
+ if ((k.is_valid() && k->is_pressed() && !k->is_echo()) || Object::cast_to<InputEventShortcut>(*p_event)) {
EditorPlugin *old_editor = editor_plugin_screen;
if (ED_IS_SHORTCUT("editor/next_tab", p_event)) {
@@ -435,6 +436,9 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
_editor_select_next();
} else if (ED_IS_SHORTCUT("editor/editor_prev", p_event)) {
_editor_select_prev();
+ } else if (ED_IS_SHORTCUT("editor/command_palette", p_event)) {
+ _open_command_palette();
+ } else {
}
if (old_editor != editor_plugin_screen) {
@@ -565,13 +569,15 @@ void EditorNode::_notification(int p_what) {
Engine::get_singleton()->set_editor_hint(true);
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
- get_tree()->get_root()->set_as_audio_listener(false);
+ get_tree()->get_root()->set_as_audio_listener_3d(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
get_tree()->get_root()->set_snap_2d_transforms_to_pixel(false);
get_tree()->get_root()->set_snap_2d_vertices_to_pixel(false);
get_tree()->set_auto_accept_quit(false);
get_tree()->get_root()->connect("files_dropped", callable_mp(this, &EditorNode::_dropped_files));
+ command_palette->register_shortcuts_as_command();
+
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -1063,6 +1069,10 @@ void EditorNode::_editor_select_next() {
_editor_select(editor);
}
+void EditorNode::_open_command_palette() {
+ command_palette->open_popup();
+}
+
void EditorNode::_editor_select_prev() {
int editor = _get_current_main_editor();
@@ -2815,6 +2825,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case HELP_SEARCH: {
emit_signal(SNAME("request_help_search"), "");
} break;
+ case HELP_COMMAND_PALETTE: {
+ command_palette->open_popup();
+ } break;
case HELP_DOCS: {
OS::get_singleton()->shell_open("https://docs.godotengine.org/");
} break;
@@ -3802,6 +3815,7 @@ void EditorNode::register_editor_types() {
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
GDREGISTER_CLASS(EditorScenePostImport);
//ClassDB::register_type<EditorImportExport>();
+ GDREGISTER_CLASS(EditorCommandPalette);
GDREGISTER_CLASS(EditorDebuggerPlugin);
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR);
@@ -6129,9 +6143,9 @@ EditorNode::EditorNode() {
distraction_free = memnew(Button);
distraction_free->set_flat(true);
#ifdef OSX_ENABLED
- distraction_free->set_shortcut(ED_SHORTCUT("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_D));
+ distraction_free->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_D));
#else
- distraction_free->set_shortcut(ED_SHORTCUT("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F11));
+ distraction_free->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F11));
#endif
distraction_free->set_tooltip(TTR("Toggle distraction-free mode."));
distraction_free->connect("pressed", callable_mp(this, &EditorNode::_toggle_distraction_free_mode));
@@ -6225,28 +6239,33 @@ EditorNode::EditorNode() {
ED_SHORTCUT("editor/next_tab", TTR("Next tab"), KEY_MASK_CMD + KEY_TAB);
ED_SHORTCUT("editor/prev_tab", TTR("Previous tab"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_TAB);
ED_SHORTCUT("editor/filter_files", TTR("Filter Files..."), KEY_MASK_CMD + KEY_MASK_ALT + KEY_P);
+
+ command_palette = EditorCommandPalette::get_singleton();
+ command_palette->set_title(TTR("Command Palette"));
+ gui_base->add_child(command_palette);
+
PopupMenu *p;
file_menu->set_tooltip(TTR("Operations with scene files."));
p = file_menu->get_popup();
- p->add_shortcut(ED_SHORTCUT("editor/new_scene", TTR("New Scene"), KEY_MASK_CMD + KEY_N), FILE_NEW_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/new_inherited_scene", TTR("New Inherited Scene..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_N), FILE_NEW_INHERITED_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/open_scene", TTR("Open Scene..."), KEY_MASK_CMD + KEY_O), FILE_OPEN_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_T), FILE_OPEN_PREV);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KEY_MASK_CMD + KEY_N), FILE_NEW_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_N), FILE_NEW_INHERITED_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KEY_MASK_CMD + KEY_O), FILE_OPEN_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_T), FILE_OPEN_PREV);
p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/save_scene", TTR("Save Scene"), KEY_MASK_CMD + KEY_S), FILE_SAVE_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/save_scene_as", TTR("Save Scene As..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_S), FILE_SAVE_AS_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/save_all_scenes", TTR("Save All Scenes"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_S), FILE_SAVE_ALL_SCENES);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KEY_MASK_CMD + KEY_S), FILE_SAVE_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_S), FILE_SAVE_AS_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_S), FILE_SAVE_ALL_SCENES);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/quick_open", TTR("Quick Open..."), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN);
- p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene", TTR("Quick Open Scene..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_O), FILE_QUICK_OPEN_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/quick_open_script", TTR("Quick Open Script..."), KEY_MASK_CMD + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN_SCRIPT);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_O), FILE_QUICK_OPEN_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KEY_MASK_CMD + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN_SCRIPT);
p->add_separator();
PopupMenu *pm_export = memnew(PopupMenu);
@@ -6261,8 +6280,8 @@ EditorNode::EditorNode() {
p->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/close_scene", TTR("Close Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_W), FILE_CLOSE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_W), FILE_CLOSE);
recent_scenes = memnew(PopupMenu);
recent_scenes->set_name("RecentScenes");
@@ -6270,7 +6289,7 @@ EditorNode::EditorNode() {
recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene));
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/file_quit", TTR("Quit"), KEY_MASK_CMD + KEY_Q), FILE_QUIT, true);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KEY_MASK_CMD + KEY_Q), FILE_QUIT, true);
project_menu = memnew(MenuButton);
project_menu->set_flat(false);
@@ -6282,7 +6301,7 @@ EditorNode::EditorNode() {
p = project_menu->get_popup();
- p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings...")), RUN_SETTINGS);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), 0, TTR("Project Settings")), RUN_SETTINGS);
p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel();
@@ -6295,7 +6314,7 @@ EditorNode::EditorNode() {
vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export...")), FILE_EXPORT_PROJECT);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), 0, TTR("Export")), FILE_EXPORT_PROJECT);
p->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE);
p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER);
@@ -6313,9 +6332,9 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RUN_RELOAD_CURRENT_PROJECT);
#ifdef OSX_ENABLED
- p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q), RUN_PROJECT_MANAGER, true);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q), RUN_PROJECT_MANAGER, true);
#else
- p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_Q), RUN_PROJECT_MANAGER, true);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_Q), RUN_PROJECT_MANAGER, true);
#endif
menu_hb->add_spacer();
@@ -6342,9 +6361,9 @@ EditorNode::EditorNode() {
p = settings_menu->get_popup();
#ifdef OSX_ENABLED
- p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings..."), KEY_MASK_CMD + KEY_COMMA), SETTINGS_PREFERENCES);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings..."), KEY_MASK_CMD + KEY_COMMA), SETTINGS_PREFERENCES);
#else
- p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings...")), SETTINGS_PREFERENCES);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings...")), SETTINGS_PREFERENCES);
#endif
p->add_separator();
@@ -6355,15 +6374,15 @@ EditorNode::EditorNode() {
p->add_submenu_item(TTR("Editor Layout"), "Layouts");
p->add_separator();
#ifdef OSX_ENABLED
- p->add_shortcut(ED_SHORTCUT("editor/take_screenshot", TTR("Take Screenshot"), KEY_MASK_CMD | KEY_F12), EDITOR_SCREENSHOT);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KEY_MASK_CMD | KEY_F12), EDITOR_SCREENSHOT);
#else
- p->add_shortcut(ED_SHORTCUT("editor/take_screenshot", TTR("Take Screenshot"), KEY_MASK_CTRL | KEY_F12), EDITOR_SCREENSHOT);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KEY_MASK_CTRL | KEY_F12), EDITOR_SCREENSHOT);
#endif
p->set_item_tooltip(p->get_item_count() - 1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
#ifdef OSX_ENABLED
- p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_F), SETTINGS_TOGGLE_FULLSCREEN);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_F), SETTINGS_TOGGLE_FULLSCREEN);
#else
- p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN);
+ p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN);
#endif
#if defined(WINDOWS_ENABLED) && defined(WINDOWS_SUBSYSTEM_CONSOLE)
// The console can only be toggled if the application was built for the console subsystem,
@@ -6396,20 +6415,20 @@ EditorNode::EditorNode() {
p = help_menu->get_popup();
p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
#ifdef OSX_ENABLED
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_MASK_ALT | KEY_SPACE), HELP_SEARCH);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/editor_help", TTR("Search Help"), KEY_MASK_ALT | KEY_SPACE), HELP_SEARCH);
#else
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_F1), HELP_SEARCH);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/editor_help", TTR("Search Help"), KEY_F1), HELP_SEARCH);
#endif
p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT("editor/q&a", TTR("Questions & Answers")), HELP_QA);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY);
p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT("editor/about", TTR("About Godot")), HELP_ABOUT);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT);
+ p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb);
@@ -6423,9 +6442,9 @@ EditorNode::EditorNode() {
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_PLAY));
play_button->set_tooltip(TTR("Play the project."));
#ifdef OSX_ENABLED
- play_button->set_shortcut(ED_SHORTCUT("editor/play", TTR("Play"), KEY_MASK_CMD | KEY_B));
+ play_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), KEY_MASK_CMD | KEY_B));
#else
- play_button->set_shortcut(ED_SHORTCUT("editor/play", TTR("Play"), KEY_F5));
+ play_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), KEY_F5));
#endif
pause_button = memnew(Button);
@@ -6469,9 +6488,9 @@ EditorNode::EditorNode() {
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_PLAY_SCENE));
play_scene_button->set_tooltip(TTR("Play the edited scene."));
#ifdef OSX_ENABLED
- play_scene_button->set_shortcut(ED_SHORTCUT("editor/play_scene", TTR("Play Scene"), KEY_MASK_CMD | KEY_R));
+ play_scene_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), KEY_MASK_CMD | KEY_R));
#else
- play_scene_button->set_shortcut(ED_SHORTCUT("editor/play_scene", TTR("Play Scene"), KEY_F6));
+ play_scene_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), KEY_F6));
#endif
play_custom_scene_button = memnew(Button);
@@ -6483,9 +6502,9 @@ EditorNode::EditorNode() {
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_PLAY_CUSTOM_SCENE));
play_custom_scene_button->set_tooltip(TTR("Play custom scene"));
#ifdef OSX_ENABLED
- play_custom_scene_button->set_shortcut(ED_SHORTCUT("editor/play_custom_scene", TTR("Play Custom Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R));
+ play_custom_scene_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R));
#else
- play_custom_scene_button->set_shortcut(ED_SHORTCUT("editor/play_custom_scene", TTR("Play Custom Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F5));
+ play_custom_scene_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F5));
#endif
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
@@ -7020,19 +7039,21 @@ EditorNode::EditorNode() {
ResourceLoader::set_load_callback(_resource_loaded);
#ifdef OSX_ENABLED
- ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_ALT | KEY_1);
- ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_ALT | KEY_2);
- ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_ALT | KEY_3);
- ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_ALT | KEY_4);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_ALT | KEY_1);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_ALT | KEY_2);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_ALT | KEY_3);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_ALT | KEY_4);
+ ED_SHORTCUT("editor/command_palette", TTR("Open Command Palette"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_P);
#else
// Use the Ctrl modifier so F2 can be used to rename nodes in the scene tree dock.
- ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_CTRL | KEY_F1);
- ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_CTRL | KEY_F2);
- ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_CTRL | KEY_F3);
- ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_CTRL | KEY_F4);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_CTRL | KEY_F1);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_CTRL | KEY_F2);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_CTRL | KEY_F3);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_CTRL | KEY_F4);
+ ED_SHORTCUT("editor/command_palette", TTR("Open Command Palette"), KEY_MASK_CTRL | KEY_MASK_SHIFT | KEY_P);
#endif
- ED_SHORTCUT("editor/editor_next", TTR("Open the next Editor"));
- ED_SHORTCUT("editor/editor_prev", TTR("Open the previous Editor"));
+ ED_SHORTCUT_AND_COMMAND("editor/editor_next", TTR("Open the next Editor"));
+ ED_SHORTCUT_AND_COMMAND("editor/editor_prev", TTR("Open the previous Editor"));
screenshot_timer = memnew(Timer);
screenshot_timer->set_one_shot(true);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 6b91856a59..fed4d23704 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -32,6 +32,7 @@
#define EDITOR_NODE_H
#include "core/templates/safe_refcount.h"
+#include "editor/editor_command_palette.h"
#include "editor/editor_data.h"
#include "editor/editor_export.h"
#include "editor/editor_folding.h"
@@ -55,6 +56,7 @@ class Control;
class DependencyEditor;
class DependencyErrorDialog;
class EditorAbout;
+class EditorCommandPalette;
class EditorExport;
class EditorFeatureProfileManager;
class EditorFileServer;
@@ -192,6 +194,7 @@ private:
EDITOR_OPEN_SCREENSHOT,
HELP_SEARCH,
+ HELP_COMMAND_PALETTE,
HELP_DOCS,
HELP_QA,
HELP_REPORT_A_BUG,
@@ -342,6 +345,7 @@ private:
CenterContainer *tabs_center;
EditorQuickOpen *quick_open;
EditorQuickOpen *quick_run;
+ EditorCommandPalette *command_palette;
HBoxContainer *main_editor_button_vb;
Vector<Button *> main_editor_buttons;
@@ -505,6 +509,7 @@ private:
void _quick_opened();
void _quick_run();
+ void _open_command_palette();
void _run(bool p_current = false, const String &p_custom = "");
void _run_native(const Ref<EditorExportPreset> &p_preset);
@@ -703,6 +708,7 @@ public:
EditorInspector *get_inspector() { return inspector_dock->get_inspector(); }
Container *get_inspector_dock_addon_area() { return inspector_dock->get_addon_area(); }
ScriptCreateDialog *get_script_create_dialog() { return scene_tree_dock->get_script_create_dialog(); }
+ EditorCommandPalette *get_editor_command_palette() { return command_palette; }
ProjectSettingsEditor *get_project_settings() { return project_settings; }
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 07e9357e67..b71a3944fc 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -310,6 +310,10 @@ bool EditorInterface::is_distraction_free_mode_enabled() const {
return EditorNode::get_singleton()->is_distraction_free_mode_enabled();
}
+EditorCommandPalette *EditorInterface::get_command_palette() const {
+ return EditorNode::get_singleton()->get_editor_command_palette();
+}
+
EditorInterface *EditorInterface::singleton = nullptr;
void EditorInterface::_bind_methods() {
@@ -340,6 +344,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path);
ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock);
ClassDB::bind_method(D_METHOD("get_editor_paths"), &EditorInterface::get_editor_paths);
+ ClassDB::bind_method(D_METHOD("get_command_palette"), &EditorInterface::get_command_palette);
ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled);
ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 2e1dd0a0c1..d665278144 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -45,6 +45,7 @@
class EditorNode;
class Node3D;
class Camera3D;
+class EditorCommandPalette;
class EditorSelection;
class EditorExport;
class EditorSettings;
@@ -87,6 +88,8 @@ public:
Array get_open_scenes() const;
ScriptEditor *get_script_editor();
+ EditorCommandPalette *get_command_palette() const;
+
void select_file(const String &p_file);
String get_selected_path() const;
String get_current_path() const;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 4cb11cc5f1..7acf5c2013 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3187,7 +3187,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
bool current = view_menu->get_popup()->is_item_checked(idx);
current = !current;
- viewport->set_as_audio_listener(current);
+ viewport->set_as_audio_listener_3d(current);
view_menu->get_popup()->set_item_checked(idx, current);
} break;
@@ -3634,7 +3634,7 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) {
bool listener = p_state["listener"];
int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
- viewport->set_as_audio_listener(listener);
+ viewport->set_as_audio_listener_3d(listener);
view_menu->get_popup()->set_item_checked(idx, listener);
}
if (p_state.has("doppler")) {
@@ -3718,7 +3718,7 @@ Dictionary Node3DEditorViewport::get_state() const {
} else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS))) {
d["display_mode"] = VIEW_DISPLAY_SHADELESS;
}
- d["listener"] = viewport->is_audio_listener();
+ d["listener"] = viewport->is_audio_listener_3d();
d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
@@ -4363,7 +4363,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
if (p_index == 0) {
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER), true);
- viewport->set_as_audio_listener(true);
+ viewport->set_as_audio_listener_3d(true);
}
name = "";
@@ -6820,7 +6820,7 @@ void Node3DEditor::clear() {
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
- viewports[i]->viewport->set_as_audio_listener(i == 0);
+ viewports[i]->viewport->set_as_audio_listener_3d(i == 0);
}
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5bbe56a800..bb8b87ed83 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -33,6 +33,7 @@
#include "core/math/expression.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
+#include "editor/editor_command_palette.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -1941,15 +1942,15 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_I);
ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD | KEY_I);
- ED_SHORTCUT("script_text_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F);
+ ED_SHORTCUT_AND_COMMAND("script_text_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F);
#ifdef OSX_ENABLED
ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_MASK_CMD | KEY_G);
ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G);
- ED_SHORTCUT("script_text_editor/replace", TTR("Replace..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
+ ED_SHORTCUT_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
#else
ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3);
ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3);
- ED_SHORTCUT("script_text_editor/replace", TTR("Replace..."), KEY_MASK_CMD | KEY_R);
+ ED_SHORTCUT_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KEY_MASK_CMD | KEY_R);
#endif
ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a500dfd51a..a21167ad95 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -2480,7 +2480,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
switch (dictionary->style) {
case DictionaryNode::LUA_TABLE:
if (key != nullptr && key->type != Node::IDENTIFIER) {
- push_error("Expected identifier as dictionary key.");
+ push_error("Expected identifier as LUA-style dictionary key.");
+ advance();
+ break;
}
if (!match(GDScriptTokenizer::Token::EQUAL)) {
if (match(GDScriptTokenizer::Token::COLON)) {
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index bb8f9f8ccb..6318aad08e 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -407,14 +407,14 @@ void AudioStreamPlayer3D::_notification(int p_what) {
for (const Set<Camera3D *>::Element *E = world_3d->get_cameras().front(); E; E = E->next()) {
Camera3D *camera = E->get();
Viewport *vp = camera->get_viewport();
- if (!vp->is_audio_listener()) {
+ if (!vp->is_audio_listener_3d()) {
continue;
}
bool listener_is_camera = true;
Node3D *listener_node = camera;
- Listener3D *listener = vp->get_listener();
+ Listener3D *listener = vp->get_listener_3d();
if (listener) {
listener_node = listener;
listener_is_camera = false;
diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp
index 636be083ab..43d6f262d8 100644
--- a/scene/3d/listener_3d.cpp
+++ b/scene/3d/listener_3d.cpp
@@ -73,14 +73,14 @@ void Listener3D::_get_property_list(List<PropertyInfo> *p_list) const {
void Listener3D::_update_listener() {
if (is_inside_tree() && is_current()) {
- get_viewport()->_listener_transform_changed_notify();
+ get_viewport()->_listener_transform_3d_changed_notify();
}
}
void Listener3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
- bool first_listener = get_viewport()->_listener_add(this);
+ bool first_listener = get_viewport()->_listener_3d_add(this);
if (!get_tree()->is_node_being_edited(this) && (current || first_listener)) {
make_current();
}
@@ -99,7 +99,7 @@ void Listener3D::_notification(int p_what) {
}
}
- get_viewport()->_listener_remove(this);
+ get_viewport()->_listener_3d_remove(this);
} break;
}
@@ -116,7 +116,7 @@ void Listener3D::make_current() {
return;
}
- get_viewport()->_listener_set(this);
+ get_viewport()->_listener_3d_set(this);
}
void Listener3D::clear_current() {
@@ -125,15 +125,15 @@ void Listener3D::clear_current() {
return;
}
- if (get_viewport()->get_listener() == this) {
- get_viewport()->_listener_set(nullptr);
- get_viewport()->_listener_make_next_current(this);
+ if (get_viewport()->get_listener_3d() == this) {
+ get_viewport()->_listener_3d_set(nullptr);
+ get_viewport()->_listener_3d_make_next_current(this);
}
}
bool Listener3D::is_current() const {
if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
- return get_viewport()->get_listener() == this;
+ return get_viewport()->get_listener_3d() == this;
} else {
return current;
}
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index ce2b320c96..869f2f68f7 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -94,7 +94,7 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
} else if (p_msg == "override_camera_3D:set") {
ERR_FAIL_COND_V(p_args.size() < 1, ERR_INVALID_DATA);
bool enable = p_args[0];
- scene_tree->get_root()->enable_camera_override(enable);
+ scene_tree->get_root()->enable_camera_3d_override(enable);
} else if (p_msg == "override_camera_3D:transform") {
ERR_FAIL_COND_V(p_args.size() < 5, ERR_INVALID_DATA);
@@ -104,11 +104,11 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
float near = p_args[3];
float far = p_args[4];
if (is_perspective) {
- scene_tree->get_root()->set_camera_override_perspective(size_or_fov, near, far);
+ scene_tree->get_root()->set_camera_3d_override_perspective(size_or_fov, near, far);
} else {
- scene_tree->get_root()->set_camera_override_orthogonal(size_or_fov, near, far);
+ scene_tree->get_root()->set_camera_3d_override_orthogonal(size_or_fov, near, far);
}
- scene_tree->get_root()->set_camera_override_transform(transform);
+ scene_tree->get_root()->set_camera_3d_override_transform(transform);
} else if (p_msg == "set_object_property") {
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 82f4a216b8..871ad889ca 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -145,6 +145,9 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
if (status.press_attempt && status.pressing_inside) {
if (toggle_mode) {
+ if (Object::cast_to<InputEventShortcut>(*p_event)) {
+ action_mode = ACTION_MODE_BUTTON_PRESS; // HACK.
+ }
if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) {
if (action_mode == ACTION_MODE_BUTTON_PRESS) {
status.press_attempt = false;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index cf1f41d0fc..63b5793b3e 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -44,7 +44,7 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
return;
}
- if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event))) {
+ if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event) || Object::cast_to<InputEventShortcut>(*p_event))) {
if (!get_parent() || !is_visible_in_tree() || is_disabled()) {
return;
}
diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp
index 885a51e058..1c29870682 100644
--- a/scene/gui/shortcut.cpp
+++ b/scene/gui/shortcut.cpp
@@ -29,10 +29,10 @@
/*************************************************************************/
#include "shortcut.h"
-
#include "core/os/keyboard.h"
void Shortcut::set_event(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(Object::cast_to<InputEventShortcut>(*p_event));
event = p_event;
emit_changed();
}
@@ -42,6 +42,12 @@ Ref<InputEvent> Shortcut::get_event() const {
}
bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
+ Ref<InputEventShortcut> ies = p_event;
+ if (ies != nullptr) {
+ if (ies->get_shortcut().ptr() == this) {
+ return true;
+ }
+ }
return event.is_valid() && event->is_match(p_event, true);
}
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index dcbbebbc55..420516cbcd 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1341,7 +1341,7 @@ SceneTree::SceneTree() {
set_multiplayer(Ref<MultiplayerAPI>(memnew(MultiplayerAPI)));
//root->set_world_2d( Ref<World2D>( memnew( World2D )));
- root->set_as_audio_listener(true);
+ root->set_as_audio_listener_3d(true);
root->set_as_audio_listener_2d(true);
current_scene = nullptr;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 8e7182df46..908950a714 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -184,24 +184,6 @@ public:
/////////////////////////////////////
-void Viewport::_collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
- Transform3D object_transform = p_object->get_global_transform();
- Transform3D camera_transform = p_camera->get_global_transform();
- ObjectID id = p_object->get_instance_id();
-
- //avoid sending the fake event unnecessarily if nothing really changed in the context
- if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
- Ref<InputEventMouseMotion> mm = p_input_event;
- if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
- return; //discarded
- }
- }
- p_object->_input_event(camera_3d, p_input_event, p_pos, p_normal, p_shape);
- physics_last_object_transform = object_transform;
- physics_last_camera_transform = camera_transform;
- physics_last_id = id;
-}
-
void Viewport::_sub_window_update_order() {
for (int i = 0; i < gui.sub_windows.size(); i++) {
RS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i);
@@ -388,27 +370,6 @@ void Viewport::_sub_window_remove(Window *p_window) {
RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
}
-void Viewport::_own_world_3d_changed() {
- ERR_FAIL_COND(world_3d.is_null());
- ERR_FAIL_COND(own_world_3d.is_null());
-
- if (is_inside_tree()) {
- _propagate_exit_world(this);
- }
-
- own_world_3d = world_3d->duplicate();
-
- if (is_inside_tree()) {
- _propagate_enter_world(this);
- }
-
- if (is_inside_tree()) {
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
- }
-
- _update_listener();
-}
-
void Viewport::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -422,19 +383,16 @@ void Viewport::_notification(int p_what) {
}
current_canvas = find_world_2d()->get_canvas();
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
-
- _update_listener();
_update_listener_2d();
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ _update_listener_3d();
add_to_group("_viewports");
if (get_tree()->is_debugging_collisions_hint()) {
- //2D
PhysicsServer2D::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_2d_debug = RenderingServer::get_singleton()->canvas_item_create();
RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
- //3D
PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create();
RenderingServer::get_singleton()->multimesh_allocate_data(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true);
@@ -444,15 +402,13 @@ void Viewport::_notification(int p_what) {
RenderingServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world_3d()->get_scenario());
//RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
- set_physics_process_internal(true);
}
} break;
case NOTIFICATION_READY: {
-#ifndef _3D_DISABLED
- if (listeners.size() && !listener) {
+ if (listener_3d_set.size() && !listener_3d) {
Listener3D *first = nullptr;
- for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
+ for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) {
if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
@@ -463,10 +419,10 @@ void Viewport::_notification(int p_what) {
}
}
- if (cameras.size() && !camera_3d) {
+ if (camera_3d_set.size() && !camera_3d) {
//there are cameras but no current camera, pick first in tree and make it current
Camera3D *first = nullptr;
- for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
+ for (Set<Camera3D *>::Element *E = camera_3d_set.front(); E; E = E->next()) {
if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
@@ -476,7 +432,6 @@ void Viewport::_notification(int p_what) {
first->make_current();
}
}
-#endif
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -515,7 +470,6 @@ void Viewport::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
}
}
-
if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world_3d()->get_space());
int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world_3d()->get_space());
@@ -560,11 +514,9 @@ void Viewport::_process_picking() {
_drop_physics_mouseover(true);
-#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
CollisionObject3D *last_object = nullptr;
ObjectID last_id;
-#endif
PhysicsDirectSpaceState3D::RayResult result;
PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
@@ -725,13 +677,12 @@ void Viewport::_process_picking() {
}
}
-#ifndef _3D_DISABLED
bool captured = false;
if (physics_object_capture.is_valid()) {
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
if (co && camera_3d) {
- _collision_object_input_event(co, camera_3d, ev, Vector3(), Vector3(), 0);
+ _collision_object_3d_input_event(co, camera_3d, ev, Vector3(), Vector3(), 0);
captured = true;
if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) {
physics_object_capture = ObjectID();
@@ -748,7 +699,7 @@ void Viewport::_process_picking() {
if (last_id.is_valid()) {
if (ObjectDB::get_instance(last_id) && last_object) {
//good, exists
- _collision_object_input_event(last_object, camera_3d, ev, result.position, result.normal, result.shape);
+ _collision_object_3d_input_event(last_object, camera_3d, ev, result.position, result.normal, result.shape);
if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
physics_object_capture = last_id;
}
@@ -765,8 +716,8 @@ void Viewport::_process_picking() {
ObjectID new_collider;
if (col) {
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
- if (co) {
- _collision_object_input_event(co, camera_3d, ev, result.position, result.normal, result.shape);
+ if (co && co->can_process()) {
+ _collision_object_3d_input_event(co, camera_3d, ev, result.position, result.normal, result.shape);
last_object = co;
last_id = result.collider_id;
new_collider = last_id;
@@ -798,7 +749,6 @@ void Viewport::_process_picking() {
last_pos = pos;
}
}
-#endif
}
}
@@ -865,31 +815,15 @@ Rect2 Viewport::get_visible_rect() const {
return r;
}
-void Viewport::_update_listener() {
-}
-
void Viewport::_update_listener_2d() {
/*
- if (is_inside_tree() && audio_listener && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree())))
+ if (is_inside_tree() && audio_listener_3d && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree())))
SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space());
else
SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID());
*/
}
-void Viewport::set_as_audio_listener(bool p_enable) {
- if (p_enable == audio_listener) {
- return;
- }
-
- audio_listener = p_enable;
- _update_listener();
-}
-
-bool Viewport::is_audio_listener() const {
- return audio_listener;
-}
-
void Viewport::set_as_audio_listener_2d(bool p_enable) {
if (p_enable == audio_listener_2d) {
return;
@@ -904,15 +838,6 @@ bool Viewport::is_audio_listener_2d() const {
return audio_listener_2d;
}
-void Viewport::set_disable_3d(bool p_disable) {
- disable_3d = p_disable;
- RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d);
-}
-
-bool Viewport::is_3d_disabled() const {
- return disable_3d;
-}
-
void Viewport::enable_canvas_transform_override(bool p_enable) {
if (override_canvas_transform == p_enable) {
return;
@@ -973,131 +898,10 @@ Transform2D Viewport::get_global_canvas_transform() const {
return global_canvas_transform;
}
-void Viewport::_listener_transform_changed_notify() {
-}
-
-void Viewport::_listener_set(Listener3D *p_listener) {
-#ifndef _3D_DISABLED
-
- if (listener == p_listener) {
- return;
- }
-
- listener = p_listener;
-
- _update_listener();
- _listener_transform_changed_notify();
-#endif
-}
-
-bool Viewport::_listener_add(Listener3D *p_listener) {
- listeners.insert(p_listener);
- return listeners.size() == 1;
-}
-
-void Viewport::_listener_remove(Listener3D *p_listener) {
- listeners.erase(p_listener);
- if (listener == p_listener) {
- listener = nullptr;
- }
-}
-
-#ifndef _3D_DISABLED
-void Viewport::_listener_make_next_current(Listener3D *p_exclude) {
- if (listeners.size() > 0) {
- for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
- if (p_exclude == E->get()) {
- continue;
- }
- if (!E->get()->is_inside_tree()) {
- continue;
- }
- if (listener != nullptr) {
- return;
- }
-
- E->get()->make_current();
- }
- } else {
- // Attempt to reset listener to the camera position
- if (camera_3d != nullptr) {
- _update_listener();
- _camera_3d_transform_changed_notify();
- }
- }
-}
-#endif
-
-void Viewport::_camera_3d_transform_changed_notify() {
-#ifndef _3D_DISABLED
-#endif
-}
-
-void Viewport::_camera_3d_set(Camera3D *p_camera) {
-#ifndef _3D_DISABLED
-
- if (camera_3d == p_camera) {
- return;
- }
-
- if (camera_3d) {
- camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
- }
-
- camera_3d = p_camera;
-
- if (!camera_override) {
- if (camera_3d) {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
- } else {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
- }
- }
-
- if (camera_3d) {
- camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
- }
-
- _update_listener();
- _camera_3d_transform_changed_notify();
-#endif
-}
-
void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
camera_2d = p_camera_2d;
}
-bool Viewport::_camera_3d_add(Camera3D *p_camera) {
- cameras.insert(p_camera);
- return cameras.size() == 1;
-}
-
-void Viewport::_camera_3d_remove(Camera3D *p_camera) {
- cameras.erase(p_camera);
- if (camera_3d == p_camera) {
- camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
- camera_3d = nullptr;
- }
-}
-
-#ifndef _3D_DISABLED
-void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) {
- for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
- if (p_exclude == E->get()) {
- continue;
- }
- if (!E->get()->is_inside_tree()) {
- continue;
- }
- if (camera_3d != nullptr) {
- return;
- }
-
- E->get()->make_current();
- }
-}
-#endif
-
void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) {
canvas_layers.insert(p_canvas_layer);
}
@@ -1121,7 +925,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
}
if (parent && parent->find_world_2d() == p_world_2d) {
- WARN_PRINT("Unable to use parent world_3d as world_2d");
+ WARN_PRINT("Unable to use parent world_2d as world_2d");
return;
}
@@ -1154,33 +958,6 @@ Ref<World2D> Viewport::find_world_2d() const {
}
}
-void Viewport::_propagate_enter_world(Node *p_node) {
- if (p_node != this) {
- if (!p_node->is_inside_tree()) { //may not have entered scene yet
- return;
- }
-
-#ifndef _3D_DISABLED
- if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
- p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD);
- } else {
-#endif
- Viewport *v = Object::cast_to<Viewport>(p_node);
- if (v) {
- if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) {
- return;
- }
- }
-#ifndef _3D_DISABLED
- }
-#endif
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _propagate_enter_world(p_node->get_child(i));
- }
-}
-
void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) {
p_node->notification(p_what);
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -1192,174 +969,14 @@ void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) {
}
}
-void Viewport::_propagate_exit_world(Node *p_node) {
- if (p_node != this) {
- if (!p_node->is_inside_tree()) { //may have exited scene already
- return;
- }
-
-#ifndef _3D_DISABLED
- if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
- p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD);
- } else {
-#endif
- Viewport *v = Object::cast_to<Viewport>(p_node);
- if (v) {
- if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) {
- return;
- }
- }
-#ifndef _3D_DISABLED
- }
-#endif
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _propagate_exit_world(p_node->get_child(i));
- }
-}
-
-void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
- if (world_3d == p_world_3d) {
- return;
- }
-
- if (is_inside_tree()) {
- _propagate_exit_world(this);
- }
-
- if (own_world_3d.is_valid() && world_3d.is_valid()) {
- world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
- }
-
- world_3d = p_world_3d;
-
- if (own_world_3d.is_valid()) {
- if (world_3d.is_valid()) {
- own_world_3d = world_3d->duplicate();
- world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
- } else {
- own_world_3d = Ref<World3D>(memnew(World3D));
- }
- }
-
- if (is_inside_tree()) {
- _propagate_enter_world(this);
- }
-
- if (is_inside_tree()) {
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
- }
-
- _update_listener();
-}
-
-Ref<World3D> Viewport::get_world_3d() const {
- return world_3d;
-}
-
Ref<World2D> Viewport::get_world_2d() const {
return world_2d;
}
-Ref<World3D> Viewport::find_world_3d() const {
- if (own_world_3d.is_valid()) {
- return own_world_3d;
- } else if (world_3d.is_valid()) {
- return world_3d;
- } else if (parent) {
- return parent->find_world_3d();
- } else {
- return Ref<World3D>();
- }
-}
-
-Listener3D *Viewport::get_listener() const {
- return listener;
-}
-
-Camera3D *Viewport::get_camera_3d() const {
- return camera_3d;
-}
-
Camera2D *Viewport::get_camera_2d() const {
return camera_2d;
}
-void Viewport::enable_camera_override(bool p_enable) {
-#ifndef _3D_DISABLED
- if (p_enable == camera_override) {
- return;
- }
-
- if (p_enable) {
- camera_override.rid = RenderingServer::get_singleton()->camera_create();
- } else {
- RenderingServer::get_singleton()->free(camera_override.rid);
- camera_override.rid = RID();
- }
-
- if (p_enable) {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
- } else if (camera_3d) {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
- } else {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
- }
-#endif
-}
-
-bool Viewport::is_camera_override_enabled() const {
- return camera_override;
-}
-
-void Viewport::set_camera_override_transform(const Transform3D &p_transform) {
- if (camera_override) {
- camera_override.transform = p_transform;
- RenderingServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
- }
-}
-
-Transform3D Viewport::get_camera_override_transform() const {
- if (camera_override) {
- return camera_override.transform;
- }
-
- return Transform3D();
-}
-
-void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
- if (camera_override) {
- if (camera_override.fov == p_fovy_degrees && camera_override.z_near == p_z_near &&
- camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_PERSPECTIVE) {
- return;
- }
-
- camera_override.fov = p_fovy_degrees;
- camera_override.z_near = p_z_near;
- camera_override.z_far = p_z_far;
- camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE;
-
- RenderingServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
- }
-}
-
-void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far) {
- if (camera_override) {
- if (camera_override.size == p_size && camera_override.z_near == p_z_near &&
- camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_ORTHOGONAL) {
- return;
- }
-
- camera_override.size = p_size;
- camera_override.z_near = p_z_near;
- camera_override.z_far = p_z_far;
- camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL;
-
- RenderingServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
- }
-}
-
Transform2D Viewport::get_final_transform() const {
return stretch_transform * global_canvas_transform;
}
@@ -1384,16 +1001,6 @@ void Viewport::_update_canvas_items(Node *p_node) {
}
}
-void Viewport::set_use_xr(bool p_use_xr) {
- use_xr = p_use_xr;
-
- RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
-}
-
-bool Viewport::is_using_xr() {
- return use_xr;
-}
-
Ref<ViewportTexture> Viewport::get_texture() const {
return default_texture;
}
@@ -2605,7 +2212,6 @@ void Viewport::_drop_physics_mouseover(bool p_paused_only) {
_cleanup_mouseover_colliders(true, p_paused_only);
-#ifndef _3D_DISABLED
if (physics_object_over.is_valid()) {
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
if (co) {
@@ -2616,7 +2222,6 @@ void Viewport::_drop_physics_mouseover(bool p_paused_only) {
}
}
}
-#endif
}
void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference) {
@@ -3099,6 +2704,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!is_inside_tree());
+ local_input_handled = false;
if (disable_input || !_can_consume_input_events()) {
return;
@@ -3118,8 +2724,8 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor
// Unhandled Input
get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this);
- // Unhandled key Input - used for performance reasons - This is called a lot less then _unhandled_input since it ignores MouseMotion, etc
- if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) {
+ // Unhandled key Input - used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, etc
+ if (!is_input_handled() && (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr)) {
get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this);
}
@@ -3137,44 +2743,6 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor
}
}
-void Viewport::set_use_own_world_3d(bool p_world_3d) {
- if (p_world_3d == own_world_3d.is_valid()) {
- return;
- }
-
- if (is_inside_tree()) {
- _propagate_exit_world(this);
- }
-
- if (!p_world_3d) {
- own_world_3d = Ref<World3D>();
- if (world_3d.is_valid()) {
- world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
- }
- } else {
- if (world_3d.is_valid()) {
- own_world_3d = world_3d->duplicate();
- world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
- } else {
- own_world_3d = Ref<World3D>(memnew(World3D));
- }
- }
-
- if (is_inside_tree()) {
- _propagate_enter_world(this);
- }
-
- if (is_inside_tree()) {
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
- }
-
- _update_listener();
-}
-
-bool Viewport::is_using_own_world_3d() const {
- return own_world_3d.is_valid();
-}
-
void Viewport::set_physics_object_picking(bool p_enable) {
physics_object_picking = p_enable;
if (physics_object_picking) {
@@ -3275,6 +2843,7 @@ void Viewport::set_lod_threshold(float p_pixels) {
lod_threshold = p_pixels;
RS::get_singleton()->viewport_set_lod_threshold(viewport, lod_threshold);
}
+
float Viewport::get_lod_threshold() const {
return lod_threshold;
}
@@ -3487,6 +3056,7 @@ void Viewport::set_sdf_oversize(SDFOversize p_sdf_oversize) {
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;
}
@@ -3496,17 +3066,413 @@ void Viewport::set_sdf_scale(SDFScale p_sdf_scale) {
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;
}
+Listener3D *Viewport::get_listener_3d() const {
+ return listener_3d;
+}
+
+void Viewport::set_as_audio_listener_3d(bool p_enable) {
+ if (p_enable == audio_listener_3d) {
+ return;
+ }
+
+ audio_listener_3d = p_enable;
+ _update_listener_3d();
+}
+
+bool Viewport::is_audio_listener_3d() const {
+ return audio_listener_3d;
+}
+
+void Viewport::_update_listener_3d() {
+}
+
+void Viewport::_listener_transform_3d_changed_notify() {
+}
+
+void Viewport::_listener_3d_set(Listener3D *p_listener) {
+ if (listener_3d == p_listener) {
+ return;
+ }
+
+ listener_3d = p_listener;
+
+ _update_listener_3d();
+ _listener_transform_3d_changed_notify();
+}
+
+bool Viewport::_listener_3d_add(Listener3D *p_listener) {
+ listener_3d_set.insert(p_listener);
+ return listener_3d_set.size() == 1;
+}
+
+void Viewport::_listener_3d_remove(Listener3D *p_listener) {
+ listener_3d_set.erase(p_listener);
+ if (listener_3d == p_listener) {
+ listener_3d = nullptr;
+ }
+}
+
+void Viewport::_listener_3d_make_next_current(Listener3D *p_exclude) {
+ if (listener_3d_set.size() > 0) {
+ for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) {
+ if (p_exclude == E->get()) {
+ continue;
+ }
+ if (!E->get()->is_inside_tree()) {
+ continue;
+ }
+ if (listener_3d != nullptr) {
+ return;
+ }
+
+ E->get()->make_current();
+ }
+ } else {
+ // Attempt to reset listener to the camera position
+ if (camera_3d != nullptr) {
+ _update_listener_3d();
+ _camera_3d_transform_changed_notify();
+ }
+ }
+}
+
+void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
+ Transform3D object_transform = p_object->get_global_transform();
+ Transform3D camera_transform = p_camera->get_global_transform();
+ ObjectID id = p_object->get_instance_id();
+
+ //avoid sending the fake event unnecessarily if nothing really changed in the context
+ if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
+ Ref<InputEventMouseMotion> mm = p_input_event;
+ if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
+ return; //discarded
+ }
+ }
+ p_object->_input_event(camera_3d, p_input_event, p_pos, p_normal, p_shape);
+ physics_last_object_transform = object_transform;
+ physics_last_camera_transform = camera_transform;
+ physics_last_id = id;
+}
+
+Camera3D *Viewport::get_camera_3d() const {
+ return camera_3d;
+}
+
+void Viewport::_camera_3d_transform_changed_notify() {
+}
+
+void Viewport::_camera_3d_set(Camera3D *p_camera) {
+ if (camera_3d == p_camera) {
+ return;
+ }
+
+ if (camera_3d) {
+ camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ }
+
+ camera_3d = p_camera;
+
+ if (!camera_3d_override) {
+ if (camera_3d) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
+ } else {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ }
+ }
+
+ if (camera_3d) {
+ camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
+ }
+
+ _update_listener_3d();
+ _camera_3d_transform_changed_notify();
+}
+
+bool Viewport::_camera_3d_add(Camera3D *p_camera) {
+ camera_3d_set.insert(p_camera);
+ return camera_3d_set.size() == 1;
+}
+
+void Viewport::_camera_3d_remove(Camera3D *p_camera) {
+ camera_3d_set.erase(p_camera);
+ if (camera_3d == p_camera) {
+ camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ camera_3d = nullptr;
+ }
+}
+
+void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) {
+ for (Set<Camera3D *>::Element *E = camera_3d_set.front(); E; E = E->next()) {
+ if (p_exclude == E->get()) {
+ continue;
+ }
+ if (!E->get()->is_inside_tree()) {
+ continue;
+ }
+ if (camera_3d != nullptr) {
+ return;
+ }
+
+ E->get()->make_current();
+ }
+}
+
+void Viewport::enable_camera_3d_override(bool p_enable) {
+ if (p_enable == camera_3d_override) {
+ return;
+ }
+
+ if (p_enable) {
+ camera_3d_override.rid = RenderingServer::get_singleton()->camera_create();
+ } else {
+ RenderingServer::get_singleton()->free(camera_3d_override.rid);
+ camera_3d_override.rid = RID();
+ }
+
+ if (p_enable) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d_override.rid);
+ } else if (camera_3d) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
+ } else {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ }
+}
+
+void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) {
+ if (camera_3d_override) {
+ if (camera_3d_override.fov == p_fovy_degrees && camera_3d_override.z_near == p_z_near &&
+ camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_PERSPECTIVE) {
+ return;
+ }
+
+ camera_3d_override.fov = p_fovy_degrees;
+ camera_3d_override.z_near = p_z_near;
+ camera_3d_override.z_far = p_z_far;
+ camera_3d_override.projection = Camera3DOverrideData::PROJECTION_PERSPECTIVE;
+
+ RenderingServer::get_singleton()->camera_set_perspective(camera_3d_override.rid, camera_3d_override.fov, camera_3d_override.z_near, camera_3d_override.z_far);
+ }
+}
+
+void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) {
+ if (camera_3d_override) {
+ if (camera_3d_override.size == p_size && camera_3d_override.z_near == p_z_near &&
+ camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
+ return;
+ }
+
+ camera_3d_override.size = p_size;
+ camera_3d_override.z_near = p_z_near;
+ camera_3d_override.z_far = p_z_far;
+ camera_3d_override.projection = Camera3DOverrideData::PROJECTION_ORTHOGONAL;
+
+ RenderingServer::get_singleton()->camera_set_orthogonal(camera_3d_override.rid, camera_3d_override.size, camera_3d_override.z_near, camera_3d_override.z_far);
+ }
+}
+
+void Viewport::set_disable_3d(bool p_disable) {
+ disable_3d = p_disable;
+ RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d);
+}
+
+bool Viewport::is_3d_disabled() const {
+ return disable_3d;
+}
+
+bool Viewport::is_camera_3d_override_enabled() const {
+ return camera_3d_override;
+}
+
+void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform) {
+ if (camera_3d_override) {
+ camera_3d_override.transform = p_transform;
+ RenderingServer::get_singleton()->camera_set_transform(camera_3d_override.rid, p_transform);
+ }
+}
+
+Transform3D Viewport::get_camera_3d_override_transform() const {
+ if (camera_3d_override) {
+ return camera_3d_override.transform;
+ }
+
+ return Transform3D();
+}
+
+Ref<World3D> Viewport::get_world_3d() const {
+ return world_3d;
+}
+
+Ref<World3D> Viewport::find_world_3d() const {
+ if (own_world_3d.is_valid()) {
+ return own_world_3d;
+ } else if (world_3d.is_valid()) {
+ return world_3d;
+ } else if (parent) {
+ return parent->find_world_3d();
+ } else {
+ return Ref<World3D>();
+ }
+}
+
+void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
+ if (world_3d == p_world_3d) {
+ return;
+ }
+
+ if (is_inside_tree()) {
+ _propagate_exit_world_3d(this);
+ }
+
+ if (own_world_3d.is_valid() && world_3d.is_valid()) {
+ world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ }
+
+ world_3d = p_world_3d;
+
+ if (own_world_3d.is_valid()) {
+ if (world_3d.is_valid()) {
+ own_world_3d = world_3d->duplicate();
+ world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ } else {
+ own_world_3d = Ref<World3D>(memnew(World3D));
+ }
+ }
+
+ if (is_inside_tree()) {
+ _propagate_enter_world_3d(this);
+ }
+
+ if (is_inside_tree()) {
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ }
+
+ _update_listener_3d();
+}
+
+void Viewport::_own_world_3d_changed() {
+ ERR_FAIL_COND(world_3d.is_null());
+ ERR_FAIL_COND(own_world_3d.is_null());
+
+ if (is_inside_tree()) {
+ _propagate_exit_world_3d(this);
+ }
+
+ own_world_3d = world_3d->duplicate();
+
+ if (is_inside_tree()) {
+ _propagate_enter_world_3d(this);
+ }
+
+ if (is_inside_tree()) {
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ }
+
+ _update_listener_3d();
+}
+
+void Viewport::set_use_own_world_3d(bool p_world_3d) {
+ if (p_world_3d == own_world_3d.is_valid()) {
+ return;
+ }
+
+ if (is_inside_tree()) {
+ _propagate_exit_world_3d(this);
+ }
+
+ if (!p_world_3d) {
+ own_world_3d = Ref<World3D>();
+ if (world_3d.is_valid()) {
+ world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ }
+ } else {
+ if (world_3d.is_valid()) {
+ own_world_3d = world_3d->duplicate();
+ world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ } else {
+ own_world_3d = Ref<World3D>(memnew(World3D));
+ }
+ }
+
+ if (is_inside_tree()) {
+ _propagate_enter_world_3d(this);
+ }
+
+ if (is_inside_tree()) {
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ }
+
+ _update_listener_3d();
+}
+
+bool Viewport::is_using_own_world_3d() const {
+ return own_world_3d.is_valid();
+}
+
+void Viewport::_propagate_enter_world_3d(Node *p_node) {
+ if (p_node != this) {
+ if (!p_node->is_inside_tree()) { //may not have entered scene yet
+ return;
+ }
+
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD);
+ } else {
+ Viewport *v = Object::cast_to<Viewport>(p_node);
+ if (v) {
+ if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) {
+ return;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _propagate_enter_world_3d(p_node->get_child(i));
+ }
+}
+
+void Viewport::_propagate_exit_world_3d(Node *p_node) {
+ if (p_node != this) {
+ if (!p_node->is_inside_tree()) { //may have exited scene already
+ return;
+ }
+
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD);
+ } else {
+ Viewport *v = Object::cast_to<Viewport>(p_node);
+ if (v) {
+ if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) {
+ return;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _propagate_exit_world_3d(p_node->get_child(i));
+ }
+}
+
+void Viewport::set_use_xr(bool p_use_xr) {
+ use_xr = p_use_xr;
+
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+}
+
+bool Viewport::is_using_xr() {
+ return use_xr;
+}
+
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);
ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d);
- ClassDB::bind_method(D_METHOD("set_world_3d", "world_3d"), &Viewport::set_world_3d);
- ClassDB::bind_method(D_METHOD("get_world_3d"), &Viewport::get_world_3d);
- ClassDB::bind_method(D_METHOD("find_world_3d"), &Viewport::find_world_3d);
ClassDB::bind_method(D_METHOD("set_canvas_transform", "xform"), &Viewport::set_canvas_transform);
ClassDB::bind_method(D_METHOD("get_canvas_transform"), &Viewport::get_canvas_transform);
@@ -3536,9 +3502,6 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_render_info", "type", "info"), &Viewport::get_render_info);
- ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
- ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
-
ClassDB::bind_method(D_METHOD("get_texture"), &Viewport::get_texture);
ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking);
@@ -3549,21 +3512,10 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false));
ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d);
- ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d);
-
- ClassDB::bind_method(D_METHOD("get_camera_3d"), &Viewport::get_camera_3d);
ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d);
-
- ClassDB::bind_method(D_METHOD("set_as_audio_listener", "enable"), &Viewport::set_as_audio_listener);
- ClassDB::bind_method(D_METHOD("is_audio_listener"), &Viewport::is_audio_listener);
-
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
- ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d);
- ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled);
-
ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse);
@@ -3621,7 +3573,26 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
+ ClassDB::bind_method(D_METHOD("set_world_3d", "world_3d"), &Viewport::set_world_3d);
+ ClassDB::bind_method(D_METHOD("get_world_3d"), &Viewport::get_world_3d);
+ ClassDB::bind_method(D_METHOD("find_world_3d"), &Viewport::find_world_3d);
+
+ ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d);
+ ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d);
+
+ ClassDB::bind_method(D_METHOD("get_camera_3d"), &Viewport::get_camera_3d);
+ ClassDB::bind_method(D_METHOD("set_as_audio_listener_3d", "enable"), &Viewport::set_as_audio_listener_3d);
+ ClassDB::bind_method(D_METHOD("is_audio_listener_3d"), &Viewport::is_audio_listener_3d);
+
+ ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d);
+ ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled);
+
+ ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
+ ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener_3d", "is_audio_listener_3d");
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", PROPERTY_USAGE_NONE), "set_world_2d", "get_world_2d");
@@ -3630,7 +3601,6 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
ADD_GROUP("Rendering", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
@@ -3642,7 +3612,6 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
ADD_GROUP("Audio Listener", "audio_listener_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener", "is_audio_listener");
ADD_GROUP("Physics", "physics_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking");
ADD_GROUP("GUI", "gui_");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index c836f50bf2..7a25f5aa00 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -194,39 +194,13 @@ private:
Viewport *parent = nullptr;
- Listener3D *listener = nullptr;
- Set<Listener3D *> listeners;
-
- struct CameraOverrideData {
- Transform3D transform;
- enum Projection {
- PROJECTION_PERSPECTIVE,
- PROJECTION_ORTHOGONAL
- };
- Projection projection = Projection::PROJECTION_PERSPECTIVE;
- float fov = 0.0;
- float size = 0.0;
- float z_near = 0.0;
- float z_far = 0.0;
- RID rid;
-
- operator bool() const {
- return rid != RID();
- }
- } camera_override;
-
- Camera3D *camera_3d = nullptr;
Camera2D *camera_2d = nullptr;
- Set<Camera3D *> cameras;
Set<CanvasLayer *> canvas_layers;
RID viewport;
RID current_canvas;
RID subwindow_canvas;
- bool audio_listener = false;
- RID internal_listener;
-
bool audio_listener_2d = false;
RID internal_listener_2d;
@@ -240,7 +214,6 @@ private:
Size2i size = Size2i(512, 512);
Size2i size_2d_override;
bool size_allocated = false;
- bool use_xr = false;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
@@ -274,8 +247,6 @@ private:
} physics_last_mouse_state;
- void _collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
-
bool handle_input_locally = true;
bool local_input_handled = false;
@@ -287,8 +258,6 @@ private:
void _cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference = 0);
Ref<World2D> world_2d;
- Ref<World3D> world_3d;
- Ref<World3D> own_world_3d;
Rect2i to_screen_rect;
StringName input_group;
@@ -296,13 +265,10 @@ private:
StringName unhandled_input_group;
StringName unhandled_key_input_group;
- void _update_listener();
void _update_listener_2d();
bool disable_3d = false;
- void _propagate_enter_world(Node *p_node);
- void _propagate_exit_world(Node *p_node);
void _propagate_viewport_notification(Node *p_node, int p_what);
void _update_global_transform();
@@ -443,20 +409,6 @@ private:
bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
- friend class Listener3D;
- void _listener_transform_changed_notify();
- void _listener_set(Listener3D *p_listener);
- bool _listener_add(Listener3D *p_listener); //true if first
- void _listener_remove(Listener3D *p_listener);
- void _listener_make_next_current(Listener3D *p_exclude);
-
- friend class Camera3D;
- void _camera_3d_transform_changed_notify();
- void _camera_3d_set(Camera3D *p_camera);
- bool _camera_3d_add(Camera3D *p_camera); //true if first
- void _camera_3d_remove(Camera3D *p_camera);
- void _camera_3d_make_next_current(Camera3D *p_exclude);
-
friend class Camera2D;
void _camera_2d_set(Camera2D *p_camera_2d);
@@ -471,8 +423,6 @@ private:
void _gui_set_root_order_dirty();
- void _own_world_3d_changed();
-
friend class Window;
void _sub_window_update_order();
@@ -500,38 +450,16 @@ protected:
public:
uint64_t get_processed_events_count() const { return event_count; }
- Listener3D *get_listener() const;
- Camera3D *get_camera_3d() const;
Camera2D *get_camera_2d() const;
-
- void enable_camera_override(bool p_enable);
- bool is_camera_override_enabled() const;
-
- void set_camera_override_transform(const Transform3D &p_transform);
- Transform3D get_camera_override_transform() const;
-
- void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
- void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far);
-
- void set_as_audio_listener(bool p_enable);
- bool is_audio_listener() const;
-
void set_as_audio_listener_2d(bool p_enable);
bool is_audio_listener_2d() const;
- void set_disable_3d(bool p_disable);
- bool is_3d_disabled() const;
-
void update_canvas_items();
Rect2 get_visible_rect() const;
RID get_viewport_rid() const;
- void set_world_3d(const Ref<World3D> &p_world_3d);
void set_world_2d(const Ref<World2D> &p_world_2d);
- Ref<World3D> get_world_3d() const;
- Ref<World3D> find_world_3d() const;
-
Ref<World2D> get_world_2d() const;
Ref<World2D> find_world_2d() const;
@@ -552,9 +480,6 @@ public:
void set_transparent_background(bool p_enable);
bool has_transparent_background() const;
- void set_use_xr(bool p_use_xr);
- bool is_using_xr();
-
Ref<ViewportTexture> get_texture() const;
void set_shadow_atlas_size(int p_size);
@@ -584,9 +509,6 @@ public:
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
- void set_use_own_world_3d(bool p_world_3d);
- bool is_using_own_world_3d() const;
-
void input_text(const String &p_text);
void input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
@@ -654,6 +576,78 @@ public:
void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control);
+ bool use_xr = false;
+ friend class Listener3D;
+ Listener3D *listener_3d = nullptr;
+ Set<Listener3D *> listener_3d_set;
+ bool audio_listener_3d = false;
+ RID internal_listener_3d;
+ Listener3D *get_listener_3d() const;
+ void set_as_audio_listener_3d(bool p_enable);
+ bool is_audio_listener_3d() const;
+ void _update_listener_3d();
+ void _listener_transform_3d_changed_notify();
+ void _listener_3d_set(Listener3D *p_listener);
+ bool _listener_3d_add(Listener3D *p_listener); //true if first
+ void _listener_3d_remove(Listener3D *p_listener);
+ void _listener_3d_make_next_current(Listener3D *p_exclude);
+
+ void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+
+ struct Camera3DOverrideData {
+ Transform3D transform;
+ enum Projection {
+ PROJECTION_PERSPECTIVE,
+ PROJECTION_ORTHOGONAL
+ };
+ Projection projection = Projection::PROJECTION_PERSPECTIVE;
+ real_t fov = 0.0;
+ real_t size = 0.0;
+ real_t z_near = 0.0;
+ real_t z_far = 0.0;
+ RID rid;
+
+ operator bool() const {
+ return rid != RID();
+ }
+ } camera_3d_override;
+
+ friend class Camera3D;
+ Camera3D *camera_3d = nullptr;
+ Set<Camera3D *> camera_3d_set;
+ Camera3D *get_camera_3d() const;
+ void _camera_3d_transform_changed_notify();
+ void _camera_3d_set(Camera3D *p_camera);
+ bool _camera_3d_add(Camera3D *p_camera); //true if first
+ void _camera_3d_remove(Camera3D *p_camera);
+ void _camera_3d_make_next_current(Camera3D *p_exclude);
+
+ void enable_camera_3d_override(bool p_enable);
+ bool is_camera_3d_override_enabled() const;
+
+ void set_camera_3d_override_transform(const Transform3D &p_transform);
+ Transform3D get_camera_3d_override_transform() const;
+
+ void set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
+ void set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
+
+ void set_disable_3d(bool p_disable);
+ bool is_3d_disabled() const;
+
+ Ref<World3D> world_3d;
+ Ref<World3D> own_world_3d;
+ void set_world_3d(const Ref<World3D> &p_world_3d);
+ Ref<World3D> get_world_3d() const;
+ Ref<World3D> find_world_3d() const;
+ void _own_world_3d_changed();
+ void set_use_own_world_3d(bool p_world_3d);
+ bool is_using_own_world_3d() const;
+ void _propagate_enter_world_3d(Node *p_node);
+ void _propagate_exit_world_3d(Node *p_node);
+
+ void set_use_xr(bool p_use_xr);
+ bool is_using_xr();
+
Viewport();
~Viewport();
};
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 0297724a22..bb9ffffe8a 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -420,8 +420,8 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color()));
- ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2i()), DEFVAL(TypedArray<RID>()));
- ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2i()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline);
ClassDB::bind_method(D_METHOD("draw_list_bind_uniform_set", "draw_list", "uniform_set", "set_index"), &RenderingDevice::draw_list_bind_uniform_set);
@@ -431,7 +431,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2i()));
+ ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2()));
ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);
ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass);