summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp18
-rw-r--r--core/core_bind.cpp39
-rw-r--r--core/core_bind.h3
-rw-r--r--core/core_constants.cpp4
-rw-r--r--core/error/error_macros.h22
-rw-r--r--core/extension/extension_api_dump.cpp25
-rw-r--r--core/extension/gdnative_interface.cpp10
-rw-r--r--core/extension/gdnative_interface.h6
-rw-r--r--core/extension/native_extension.cpp5
-rw-r--r--core/extension/native_extension.h2
-rw-r--r--core/input/input_map.cpp2
-rw-r--r--core/io/dir_access.cpp14
-rw-r--r--core/io/dir_access.h2
-rw-r--r--core/io/image.cpp8
-rw-r--r--core/io/image.h16
-rw-r--r--core/io/logger.cpp10
-rw-r--r--core/io/pck_packer.cpp5
-rw-r--r--core/io/resource.cpp20
-rw-r--r--core/io/resource_format_binary.cpp22
-rw-r--r--core/io/resource_saver.h3
-rw-r--r--core/math/basis.cpp28
-rw-r--r--core/math/bvh.h264
-rw-r--r--core/math/bvh_abb.h64
-rw-r--r--core/math/bvh_cull.inc95
-rw-r--r--core/math/bvh_debug.inc4
-rw-r--r--core/math/bvh_logic.inc16
-rw-r--r--core/math/bvh_misc.inc6
-rw-r--r--core/math/bvh_pair.inc14
-rw-r--r--core/math/bvh_public.inc146
-rw-r--r--core/math/bvh_split.inc18
-rw-r--r--core/math/bvh_structs.inc69
-rw-r--r--core/math/bvh_tree.h50
-rw-r--r--core/math/camera_matrix.cpp12
-rw-r--r--core/math/color.h2
-rw-r--r--core/math/color_names.inc292
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/face3.cpp4
-rw-r--r--core/math/geometry_2d.cpp18
-rw-r--r--core/math/geometry_2d.h10
-rw-r--r--core/math/geometry_3d.cpp2
-rw-r--r--core/math/geometry_3d.h30
-rw-r--r--core/math/math_funcs.h26
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/quaternion.cpp21
-rw-r--r--core/math/quaternion.h4
-rw-r--r--core/math/random_pcg.h2
-rw-r--r--core/math/transform_2d.cpp4
-rw-r--r--core/math/vector2.cpp2
-rw-r--r--core/math/vector2.h3
-rw-r--r--core/math/vector2i.h3
-rw-r--r--core/math/vector3.cpp2
-rw-r--r--core/math/vector3.h2
-rw-r--r--core/math/vector3i.h3
-rw-r--r--core/object/class_db.cpp48
-rw-r--r--core/object/class_db.h31
-rw-r--r--core/object/make_virtuals.py10
-rw-r--r--core/object/message_queue.cpp41
-rw-r--r--core/object/message_queue.h43
-rw-r--r--core/object/object.cpp60
-rw-r--r--core/object/object.h53
-rw-r--r--core/object/script_language.cpp14
-rw-r--r--core/object/script_language.h20
-rw-r--r--core/object/undo_redo.cpp99
-rw-r--r--core/object/undo_redo.h34
-rw-r--r--core/os/os.cpp8
-rw-r--r--core/os/thread.cpp1
-rw-r--r--core/os/thread.h1
-rw-r--r--core/os/time.cpp20
-rw-r--r--core/os/time.h5
-rw-r--r--core/register_core_types.cpp45
-rw-r--r--core/register_core_types.h1
-rw-r--r--core/string/string_name.cpp16
-rw-r--r--core/string/ustring.cpp89
-rw-r--r--core/string/ustring.h1
-rw-r--r--core/templates/oa_hash_map.h4
-rw-r--r--core/templates/paged_allocator.h2
-rw-r--r--core/templates/pooled_list.h149
-rw-r--r--core/typedefs.h45
-rw-r--r--core/variant/binder_common.h10
-rw-r--r--core/variant/callable.cpp6
-rw-r--r--core/variant/native_ptr.h1
-rw-r--r--core/variant/type_info.h34
-rw-r--r--core/variant/variant.cpp20
-rw-r--r--core/variant/variant.h27
-rw-r--r--core/variant/variant_call.cpp8
-rw-r--r--core/variant/variant_op.cpp1
-rw-r--r--core/variant/variant_setget.cpp6
-rw-r--r--core/variant/variant_utility.cpp5
88 files changed, 1521 insertions, 895 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 3a7fc828aa..93c1abe7b5 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -145,7 +145,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
return p_path.simplify_path();
}
- DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String path = p_path.replace("\\", "/").simplify_path();
@@ -153,8 +153,6 @@ String ProjectSettings::localize_path(const String &p_path) const {
String cwd = dir->get_current_dir();
cwd = cwd.replace("\\", "/");
- memdelete(dir);
-
// Ensure that we end with a '/'.
// This is important to ensure that we do not wrongly localize the resource path
// in an absolute path that just happens to contain this string but points to a
@@ -173,8 +171,6 @@ String ProjectSettings::localize_path(const String &p_path) const {
return cwd.replace_first(res_path, "res://");
} else {
- memdelete(dir);
-
int sep = path.rfind("/");
if (sep == -1) {
return "res://" + path;
@@ -541,7 +537,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Nothing was found, try to find a project file in provided path (`p_path`)
// or, if requested (`p_upwards`) in parent directories.
- DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V_MSG(!d, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'.");
d->change_dir(p_path);
@@ -573,8 +569,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
}
- memdelete(d);
-
if (!found) {
return err;
}
@@ -614,11 +608,7 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
bool ProjectSettings::has_setting(String p_var) const {
_THREAD_SAFE_METHOD_
- StringName name = p_var;
- if (!disable_feature_overrides && feature_overrides.has(name)) {
- name = feature_overrides[name];
- }
- return props.has(name);
+ return props.has(p_var);
}
Error ProjectSettings::_load_settings_binary(const String &p_path) {
@@ -1203,6 +1193,8 @@ ProjectSettings::ProjectSettings() {
singleton = this;
GLOBAL_DEF_BASIC("application/config/name", "");
+ GLOBAL_DEF_BASIC("application/config/name_localized", Dictionary());
+ custom_prop_info["application/config/name_localized"] = PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING);
GLOBAL_DEF_BASIC("application/config/description", "");
custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT);
GLOBAL_DEF_BASIC("application/run/main_scene", "");
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index bb4b49d9cd..2d0eaadbdf 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -137,7 +137,7 @@ void ResourceLoader::_bind_methods() {
////// ResourceSaver //////
-Error ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) {
+Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + String(p_path) + "'.");
return ::ResourceSaver::save(p_path, p_resource, p_flags);
}
@@ -156,9 +156,10 @@ Vector<String> ResourceSaver::get_recognized_extensions(const RES &p_resource) {
ResourceSaver *ResourceSaver::singleton = nullptr;
void ResourceSaver::_bind_methods() {
- ClassDB::bind_method(D_METHOD("save", "path", "resource", "flags"), &ResourceSaver::save, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("save", "path", "resource", "flags"), &ResourceSaver::save, DEFVAL((uint32_t)FLAG_NONE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions);
+ BIND_ENUM_CONSTANT(FLAG_NONE);
BIND_ENUM_CONSTANT(FLAG_RELATIVE_PATHS);
BIND_ENUM_CONSTANT(FLAG_BUNDLE_RESOURCES);
BIND_ENUM_CONSTANT(FLAG_CHANGE_PATH);
@@ -1568,10 +1569,8 @@ String Directory::get_current_dir() {
Error Directory::make_dir(String p_dir) {
ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_dir);
- Error err = d->make_dir(p_dir);
- memdelete(d);
- return err;
+ DirAccessRef da = DirAccess::create_for_path(p_dir);
+ return da->make_dir(p_dir);
}
return d->make_dir(p_dir);
}
@@ -1579,10 +1578,8 @@ Error Directory::make_dir(String p_dir) {
Error Directory::make_dir_recursive(String p_dir) {
ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_dir);
- Error err = d->make_dir_recursive(p_dir);
- memdelete(d);
- return err;
+ DirAccessRef da = DirAccess::create_for_path(p_dir);
+ return da->make_dir_recursive(p_dir);
}
return d->make_dir_recursive(p_dir);
}
@@ -1592,19 +1589,14 @@ bool Directory::file_exists(String p_file) {
if (!p_file.is_relative_path()) {
return FileAccess::exists(p_file);
}
-
return d->file_exists(p_file);
}
bool Directory::dir_exists(String p_dir) {
ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_dir);
- bool exists = d->dir_exists(p_dir);
- memdelete(d);
- return exists;
+ return DirAccess::exists(p_dir);
}
-
return d->dir_exists(p_dir);
}
@@ -1623,11 +1615,9 @@ Error Directory::rename(String p_from, String p_to) {
ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename.");
if (!p_from.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_from);
- ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- Error err = d->rename(p_from, p_to);
- memdelete(d);
- return err;
+ DirAccessRef da = DirAccess::create_for_path(p_from);
+ ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
+ return da->rename(p_from, p_to);
}
ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
@@ -1637,10 +1627,8 @@ Error Directory::rename(String p_from, String p_to) {
Error Directory::remove(String p_name) {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
if (!p_name.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_name);
- Error err = d->remove(p_name);
- memdelete(d);
- return err;
+ DirAccessRef da = DirAccess::create_for_path(p_name);
+ return da->remove(p_name);
}
return d->remove(p_name);
@@ -1663,7 +1651,6 @@ void Directory::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive);
ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists);
ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists);
- //ClassDB::bind_method(D_METHOD("get_modified_time","file"),&Directory::get_modified_time);
ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left);
ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy);
ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename);
diff --git a/core/core_bind.h b/core/core_bind.h
index 1ed243206b..4a7eb718f1 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -94,6 +94,7 @@ protected:
public:
enum SaverFlags {
+ FLAG_NONE = 0,
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
@@ -105,7 +106,7 @@ public:
static ResourceSaver *get_singleton() { return singleton; }
- Error save(const String &p_path, const RES &p_resource, SaverFlags p_flags);
+ Error save(const String &p_path, const RES &p_resource, uint32_t p_flags);
Vector<String> get_recognized_extensions(const RES &p_resource);
ResourceSaver() { singleton = this; }
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 63e7323f7a..98b720ab65 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -168,6 +168,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TAB);
@@ -422,6 +423,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, KPAD);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
+ BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, MIDDLE);
@@ -472,6 +474,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, SDL_MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, MAX);
+ BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_OFF);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_ON);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, AFTERTOUCH);
@@ -588,6 +591,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 7b032fb4cd..01e22e84b7 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -194,6 +194,7 @@ void _err_flush_stdout();
#define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -208,6 +209,7 @@ void _err_flush_stdout();
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -296,6 +298,7 @@ void _err_flush_stdout();
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -310,6 +313,7 @@ void _err_flush_stdout();
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -559,6 +563,7 @@ void _err_flush_stdout();
#define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -573,6 +578,7 @@ void _err_flush_stdout();
#define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -808,4 +814,20 @@ void _err_flush_stdout();
} else \
((void)0)
+/**
+ * This should be a 'free' assert for program flow and should not be needed in any releases,
+ * only used in dev builds.
+ */
+#ifdef DEV_ENABLED
+#define DEV_ASSERT(m_cond) \
+ if (unlikely(!(m_cond))) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
+ _err_flush_stdout(); \
+ GENERATE_TRAP(); \
+ } else \
+ ((void)0)
+#else
+#define DEV_ASSERT(m_cond)
+#endif
+
#endif // ERROR_MACROS_H
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 3687e4f7e5..31af28b783 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -841,27 +841,16 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{
Array native_structures;
- // AudioStream structures
- {
- Dictionary d;
- d["name"] = "AudioFrame";
- d["format"] = "float left,float right";
+ List<StringName> native_structs;
+ ClassDB::get_native_struct_list(&native_structs);
+ native_structs.sort_custom<StringName::AlphCompare>();
- native_structures.push_back(d);
- }
+ for (const StringName &E : native_structs) {
+ String code = ClassDB::get_native_struct_code(E);
- // TextServer structures
- {
- Dictionary d;
- d["name"] = "Glyph";
- d["format"] = "int start,int end,uint8_t count,uint8_t repeat,uint16_t flags,float x_off,float y_off,float advance,RID font_rid,int font_size,int32_t index";
-
- native_structures.push_back(d);
- }
- {
Dictionary d;
- d["name"] = "CaretInfo";
- d["format"] = "Rect2 leading_caret,Rect2 trailing_caret,TextServer::Direction leading_direction,TextServer::Direction trailing_direction";
+ d["name"] = String(E);
+ d["format"] = code;
native_structures.push_back(d);
}
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 385117eed1..d0461611ec 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -60,6 +60,10 @@ static void gdnative_print_script_error(const char *p_description, const char *p
_err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
}
+uint64_t gdnative_get_native_struct_size(const char *p_name) {
+ return ClassDB::get_native_struct_size(p_name);
+}
+
// Variant functions
static void gdnative_variant_new_copy(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src) {
@@ -80,7 +84,7 @@ static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStrin
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
- self->call(*method, args, p_argcount, ret, error);
+ self->callp(*method, args, p_argcount, ret, error);
memnew_placement(r_return, Variant(ret));
if (r_error) {
@@ -152,7 +156,7 @@ static void gdnative_variant_set_indexed(GDNativeVariantPtr p_self, GDNativeInt
bool valid;
bool oob;
- self->set_indexed(p_index, value, valid, oob);
+ self->set_indexed(p_index, *value, valid, oob);
*r_valid = valid;
*r_oob = oob;
}
@@ -902,6 +906,8 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.print_warning = gdnative_print_warning;
gdni.print_script_error = gdnative_print_script_error;
+ gdni.get_native_struct_size = gdnative_get_native_struct_size;
+
/* GODOT VARIANT */
// variant general
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index a2e0c7cc73..cc2957ec56 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -194,6 +194,7 @@ typedef void *GDExtensionClassInstancePtr;
typedef GDNativeBool (*GDNativeExtensionClassSet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
+typedef uint64_t (*GDNativeExtensionClassGetRID)(GDExtensionClassInstancePtr p_instance);
typedef struct {
uint32_t type;
@@ -228,6 +229,7 @@ typedef struct {
GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
GDNativeExtensionClassGetVirtual get_virtual_func;
+ GDNativeExtensionClassGetRID get_rid_func;
void *class_userdata;
} GDNativeExtensionClassCreationInfo;
@@ -304,6 +306,8 @@ typedef struct {
void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
+ uint64_t (*get_native_struct_size)(const char *p_name);
+
/* GODOT VARIANT */
/* variant general */
@@ -460,8 +464,8 @@ typedef enum {
GDNATIVE_INITIALIZATION_CORE,
GDNATIVE_INITIALIZATION_SERVERS,
GDNATIVE_INITIALIZATION_SCENE,
- GDNATIVE_INITIALIZATION_EDITOR,
GDNATIVE_INITIALIZATION_DRIVER,
+ GDNATIVE_INITIALIZATION_EDITOR,
GDNATIVE_MAX_INITIALIZATION_LEVEL,
} GDNativeInitializationLevel;
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index 1512852234..1a39c937e8 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -158,6 +158,7 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.create_instance = p_extension_funcs->create_instance_func;
extension->native_extension.free_instance = p_extension_funcs->free_instance_func;
extension->native_extension.get_virtual = p_extension_funcs->get_virtual_func;
+ extension->native_extension.get_rid = p_extension_funcs->get_rid_func;
ClassDB::register_extension_class(&extension->native_extension);
}
@@ -295,9 +296,10 @@ NativeExtension::InitializationLevel NativeExtension::get_minimum_library_initia
ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE);
return InitializationLevel(initialization.minimum_initialization_level);
}
+
void NativeExtension::initialize_library(InitializationLevel p_level) {
ERR_FAIL_COND(library == nullptr);
- ERR_FAIL_COND(p_level <= int32_t(level_initialized));
+ ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
level_initialized = int32_t(p_level);
@@ -324,6 +326,7 @@ void NativeExtension::_bind_methods() {
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_CORE);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SERVERS);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SCENE);
+ BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_DRIVER);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_EDITOR);
}
diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h
index b98e4925d2..ebfedfb29a 100644
--- a/core/extension/native_extension.h
+++ b/core/extension/native_extension.h
@@ -71,8 +71,8 @@ public:
INITIALIZATION_LEVEL_CORE,
INITIALIZATION_LEVEL_SERVERS,
INITIALIZATION_LEVEL_SCENE,
- INITIALIZATION_LEVEL_EDITOR,
INITIALIZATION_LEVEL_DRIVER,
+ INITIALIZATION_LEVEL_EDITOR,
};
bool is_library_open() const;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 41083b4c47..ab94c00999 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -344,7 +344,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_filedialog_refresh", TTRC("Refresh") },
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
- { "", TTRC("")}
+ { "", ""}
/* clang-format on */
};
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index 86d8dea3d9..73efdeb38e 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -250,6 +250,14 @@ DirAccess *DirAccess::create(AccessType p_access) {
DirAccess *da = create_func[p_access] ? create_func[p_access]() : nullptr;
if (da) {
da->_access_type = p_access;
+
+ // for ACCESS_RESOURCES and ACCESS_FILESYSTEM, current_dir already defaults to where game was started
+ // in case current directory is force changed elsewhere for ACCESS_RESOURCES
+ if (p_access == ACCESS_RESOURCES) {
+ da->change_dir("res://");
+ } else if (p_access == ACCESS_USERDATA) {
+ da->change_dir("user://");
+ }
}
return da;
@@ -414,8 +422,6 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_
}
bool DirAccess::exists(String p_dir) {
- DirAccess *da = DirAccess::create_for_path(p_dir);
- bool valid = da->change_dir(p_dir) == OK;
- memdelete(da);
- return valid;
+ DirAccessRef da = DirAccess::create_for_path(p_dir);
+ return da->change_dir(p_dir) == OK;
}
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index 8154f5366c..d63453e947 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -134,7 +134,7 @@ struct DirAccessRef {
operator bool() const { return f != nullptr; }
- DirAccess *f;
+ DirAccess *f = nullptr;
DirAccessRef(DirAccess *fa) { f = fa; }
~DirAccessRef() {
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 577fc59807..5376b78a89 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -1465,8 +1465,8 @@ template <class Component, int CC, bool renormalize,
void (*renormalize_func)(Component *)>
static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) {
//fast power of 2 mipmap generation
- uint32_t dst_w = MAX(p_width >> 1, 1);
- uint32_t dst_h = MAX(p_height >> 1, 1);
+ uint32_t dst_w = MAX(p_width >> 1, 1u);
+ uint32_t dst_h = MAX(p_height >> 1, 1u);
int right_step = (p_width == 1) ? 0 : CC;
int down_step = (p_height == 1) ? 0 : (p_width * CC);
@@ -3112,8 +3112,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
- ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty);
- ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::_create_from_data);
+ ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
+ ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
diff --git a/core/io/image.h b/core/io/image.h
index 53bfa0881f..39c700565b 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -155,14 +155,6 @@ protected:
static void _bind_methods();
private:
- void _create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
- create(p_width, p_height, p_use_mipmaps, p_format);
- }
-
- void _create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
- create(p_width, p_height, p_use_mipmaps, p_format, p_data);
- }
-
Format format = FORMAT_L8;
Vector<uint8_t> data;
int width = 0;
@@ -289,6 +281,14 @@ public:
Vector<uint8_t> save_png_to_buffer() const;
Error save_exr(const String &p_path, bool p_grayscale) const;
+ void create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+ create(p_width, p_height, p_use_mipmaps, p_format);
+ }
+
+ void create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ create(p_width, p_height, p_use_mipmaps, p_format, p_data);
+ }
+
/**
* create an empty image
*/
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index cb6369ae3d..2b6f230434 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -128,7 +128,7 @@ void RotatedFileLogger::clear_old_backups() {
String basename = base_path.get_file().get_basename();
String extension = base_path.get_extension();
- DirAccess *da = DirAccess::open(base_path.get_base_dir());
+ DirAccessRef da = DirAccess::open(base_path.get_base_dir());
if (!da) {
return;
}
@@ -152,8 +152,6 @@ void RotatedFileLogger::clear_old_backups() {
da->remove(E->get());
}
}
-
- memdelete(da);
}
void RotatedFileLogger::rotate_file() {
@@ -167,18 +165,16 @@ void RotatedFileLogger::rotate_file() {
backup_name += "." + base_path.get_extension();
}
- DirAccess *da = DirAccess::open(base_path.get_base_dir());
+ DirAccessRef da = DirAccess::open(base_path.get_base_dir());
if (da) {
da->copy(base_path, backup_name);
- memdelete(da);
}
clear_old_backups();
}
} else {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_USERDATA);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_USERDATA);
if (da) {
da->make_dir_recursive(base_path.get_base_dir());
- memdelete(da);
}
}
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index 272ace3438..b3bf0cff2d 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -257,10 +257,7 @@ Error PCKPacker::flush(bool p_verbose) {
count += 1;
const int file_num = files.size();
if (p_verbose && (file_num > 0)) {
- if (count % 100 == 0) {
- printf("%i/%i (%.2f)\r", count, file_num, float(count) / file_num * 100);
- fflush(stdout);
- }
+ print_line(vformat("[%d/%d - %d%%] PCKPacker flush: %s -> %s", count, file_num, float(count) / file_num * 100, files[i].src_path, files[i].path));
}
}
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 66d5c54b53..f90a6e9304 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -290,6 +290,21 @@ void Resource::_take_over_path(const String &p_path) {
}
RID Resource::get_rid() const {
+ if (get_script_instance()) {
+ Callable::CallError ce;
+ RID ret = get_script_instance()->callp(SNAME("_get_rid"), nullptr, 0, ce);
+ if (ce.error == Callable::CallError::CALL_OK && ret.is_valid()) {
+ return ret;
+ }
+ }
+ if (_get_extension() && _get_extension()->get_rid) {
+ RID ret;
+ ret.from_uint64(_get_extension()->get_rid(_get_extension_instance()));
+ if (ret.is_valid()) {
+ return ret;
+ }
+ }
+
return RID();
}
@@ -428,6 +443,11 @@ void Resource::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "resource_name"), "set_name", "get_name");
+
+ MethodInfo get_rid_bind("_get_rid");
+ get_rid_bind.return_val.type = Variant::RID;
+
+ ::ClassDB::add_virtual_method(get_class_static(), get_rid_bind, true, Vector<String>(), true);
}
Resource::Resource() :
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index ee59a916f1..b65993e3dd 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1032,7 +1032,6 @@ RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_origi
String path = !p_original_path.is_empty() ? p_original_path : p_path;
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.open(f);
err = loader.load();
@@ -1086,17 +1085,14 @@ void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<Str
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.get_dependencies(f, p_dependencies, p_add_types);
}
Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
- //Error error=OK;
-
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_path + "'.");
- FileAccess *fw = nullptr; //=FileAccess::open(p_path+".depren");
+ FileAccess *fw = nullptr;
String local_path = p_path.get_base_dir();
@@ -1158,10 +1154,12 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
if (ver_format < FORMAT_VERSION_CAN_RENAME_DEPS) {
memdelete(f);
memdelete(fw);
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->remove(p_path + ".depren");
- memdelete(da);
- //use the old approach
+ {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->remove(p_path + ".depren");
+ }
+
+ // Use the old approach.
WARN_PRINT("This file is old, so it can't refactor dependencies, opening and resaving '" + p_path + "'.");
@@ -1174,7 +1172,6 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
loader.remaps = p_map;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.open(f);
err = loader.load();
@@ -1304,10 +1301,9 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
return ERR_CANT_CREATE;
}
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
da->remove(p_path);
da->rename(p_path + ".depren", p_path);
- memdelete(da);
return OK;
}
@@ -1320,7 +1316,6 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
String r = loader.recognize(f);
return ClassDB::get_compatibility_remapped_class(r);
}
@@ -1339,7 +1334,6 @@ ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_pat
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.open(f, true);
if (loader.error != OK) {
return ResourceUID::INVALID_ID; //could not read
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 2919a4cec0..ebc3be91a1 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -71,6 +71,7 @@ class ResourceSaver {
public:
enum SaverFlags {
+ FLAG_NONE = 0,
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
@@ -80,7 +81,7 @@ public:
FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
};
- static Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ static Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = (uint32_t)FLAG_NONE);
static void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions);
static void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front = false);
static void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index e34c1c1315..84f9d12bb1 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -37,7 +37,7 @@
(elements[row1][col1] * elements[row2][col2] - elements[row1][col2] * elements[row2][col1])
void Basis::from_z(const Vector3 &p_z) {
- if (Math::abs(p_z.z) > Math_SQRT12) {
+ if (Math::abs(p_z.z) > (real_t)Math_SQRT12) {
// choose p in y-z plane
real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2];
real_t k = 1.0f / Math::sqrt(a);
@@ -153,7 +153,7 @@ Basis Basis::diagonalize() {
int ite = 0;
Basis acc_rot;
- while (off_matrix_norm_2 > CMP_EPSILON2 && ite++ < ite_max) {
+ while (off_matrix_norm_2 > (real_t)CMP_EPSILON2 && ite++ < ite_max) {
real_t el01_2 = elements[0][1] * elements[0][1];
real_t el02_2 = elements[0][2] * elements[0][2];
real_t el12_2 = elements[1][2] * elements[1][2];
@@ -463,8 +463,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sy = elements[0][2];
- if (sy < (1.0f - CMP_EPSILON)) {
- if (sy > -(1.0f - CMP_EPSILON)) {
+ if (sy < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
// is this a pure Y rotation?
if (elements[1][0] == 0 && elements[0][1] == 0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) {
// return the simplest form (human friendlier in editor and scripts)
@@ -498,8 +498,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sz = elements[0][1];
- if (sz < (1.0f - CMP_EPSILON)) {
- if (sz > -(1.0f - CMP_EPSILON)) {
+ if (sz < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::atan2(elements[2][1], elements[1][1]);
euler.y = Math::atan2(elements[0][2], elements[0][0]);
euler.z = Math::asin(-sz);
@@ -529,8 +529,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
real_t m12 = elements[1][2];
- if (m12 < (1 - CMP_EPSILON)) {
- if (m12 > -(1 - CMP_EPSILON)) {
+ if (m12 < (1 - (real_t)CMP_EPSILON)) {
+ if (m12 > -(1 - (real_t)CMP_EPSILON)) {
// is this a pure X rotation?
if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) {
// return the simplest form (human friendlier in editor and scripts)
@@ -565,8 +565,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sz = elements[1][0];
- if (sz < (1.0f - CMP_EPSILON)) {
- if (sz > -(1.0f - CMP_EPSILON)) {
+ if (sz < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::atan2(-elements[1][2], elements[1][1]);
euler.y = Math::atan2(-elements[2][0], elements[0][0]);
euler.z = Math::asin(sz);
@@ -593,8 +593,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -cx*sy sx cx*cy
Vector3 euler;
real_t sx = elements[2][1];
- if (sx < (1.0f - CMP_EPSILON)) {
- if (sx > -(1.0f - CMP_EPSILON)) {
+ if (sx < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sx > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::asin(sx);
euler.y = Math::atan2(-elements[2][0], elements[2][2]);
euler.z = Math::atan2(-elements[0][1], elements[1][1]);
@@ -621,8 +621,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -sy cy*sx cy*cx
Vector3 euler;
real_t sy = elements[2][0];
- if (sy < (1.0f - CMP_EPSILON)) {
- if (sy > -(1.0f - CMP_EPSILON)) {
+ if (sy < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::atan2(elements[2][1], elements[2][2]);
euler.y = Math::asin(-sy);
euler.z = Math::atan2(elements[1][0], elements[0][0]);
diff --git a/core/math/bvh.h b/core/math/bvh.h
index a8e3cc7bbe..e686e27445 100644
--- a/core/math/bvh.h
+++ b/core/math/bvh.h
@@ -46,21 +46,35 @@
// Layer masks are implemented in the renderers as a later step, and light_cull_mask appears to be
// implemented in GLES3 but not GLES2. Layer masks are not yet implemented for directional lights.
+// In the physics, the pairable_type is based on 1 << p_object->get_type() where:
+// TYPE_AREA,
+// TYPE_BODY
+// and pairable_mask is either 0 if static, or set to all if non static
+
#include "bvh_tree.h"
+#include "core/os/mutex.h"
-#define BVHTREE_CLASS BVH_Tree<T, 2, MAX_ITEMS, USE_PAIRS, Bounds, Point>
+#define BVHTREE_CLASS BVH_Tree<T, NUM_TREES, 2, MAX_ITEMS, USER_PAIR_TEST_FUNCTION, USER_CULL_TEST_FUNCTION, USE_PAIRS, BOUNDS, POINT>
+#define BVH_LOCKED_FUNCTION BVHLockedFunction(&_mutex, BVH_THREAD_SAFE &&_thread_safe);
-template <class T, bool USE_PAIRS = false, int MAX_ITEMS = 32, class Bounds = AABB, class Point = Vector3>
+template <class T, int NUM_TREES = 1, bool USE_PAIRS = false, int MAX_ITEMS = 32, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, class BOUNDS = AABB, class POINT = Vector3, bool BVH_THREAD_SAFE = true>
class BVH_Manager {
public:
// note we are using uint32_t instead of BVHHandle, losing type safety, but this
// is for compatibility with octree
typedef void *(*PairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int);
typedef void (*UnpairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *);
+ typedef void *(*CheckPairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *);
+
+ // allow locally toggling thread safety if the template has been compiled with BVH_THREAD_SAFE
+ void params_set_thread_safe(bool p_enable) {
+ _thread_safe = p_enable;
+ }
// these 2 are crucial for fine tuning, and can be applied manually
// see the variable declarations for more info.
void params_set_node_expansion(real_t p_value) {
+ BVH_LOCKED_FUNCTION
if (p_value >= 0.0) {
tree._node_expansion = p_value;
tree._auto_node_expansion = false;
@@ -70,43 +84,40 @@ public:
}
void params_set_pairing_expansion(real_t p_value) {
- if (p_value >= 0.0) {
- tree._pairing_expansion = p_value;
- tree._auto_pairing_expansion = false;
- } else {
- tree._auto_pairing_expansion = true;
- }
+ BVH_LOCKED_FUNCTION
+ tree.params_set_pairing_expansion(p_value);
}
void set_pair_callback(PairCallback p_callback, void *p_userdata) {
+ BVH_LOCKED_FUNCTION
pair_callback = p_callback;
pair_callback_userdata = p_userdata;
}
void set_unpair_callback(UnpairCallback p_callback, void *p_userdata) {
+ BVH_LOCKED_FUNCTION
unpair_callback = p_callback;
unpair_callback_userdata = p_userdata;
}
+ void set_check_pair_callback(CheckPairCallback p_callback, void *p_userdata) {
+ BVH_LOCKED_FUNCTION
+ check_pair_callback = p_callback;
+ check_pair_callback_userdata = p_userdata;
+ }
+
+ BVHHandle create(T *p_userdata, bool p_active = true, uint32_t p_tree_id = 0, uint32_t p_tree_collision_mask = 1, const BOUNDS &p_aabb = BOUNDS(), int p_subindex = 0) {
+ BVH_LOCKED_FUNCTION
- BVHHandle create(T *p_userdata, bool p_active, const Bounds &p_aabb = Bounds(), int p_subindex = 0, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t p_pairable_mask = 1) {
// not sure if absolutely necessary to flush collisions here. It will cost performance to, instead
// of waiting for update, so only uncomment this if there are bugs.
if (USE_PAIRS) {
//_check_for_collisions();
}
-#ifdef TOOLS_ENABLED
- if (!USE_PAIRS) {
- if (p_pairable) {
- WARN_PRINT_ONCE("creating pairable item in BVH with USE_PAIRS set to false");
- }
- }
-#endif
-
- BVHHandle h = tree.item_add(p_userdata, p_active, p_aabb, p_subindex, p_pairable, p_pairable_type, p_pairable_mask);
+ BVHHandle h = tree.item_add(p_userdata, p_active, p_aabb, p_subindex, p_tree_id, p_tree_collision_mask);
if (USE_PAIRS) {
// for safety initialize the expanded AABB
- Bounds &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
+ BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
expanded_aabb = p_aabb;
expanded_aabb.grow_by(tree._pairing_expansion);
@@ -123,12 +134,18 @@ public:
////////////////////////////////////////////////////
// wrapper versions that use uint32_t instead of handle
// for backward compatibility. Less type safe
- void move(uint32_t p_handle, const Bounds &p_aabb) {
+ void move(uint32_t p_handle, const BOUNDS &p_aabb) {
BVHHandle h;
h.set(p_handle);
move(h, p_aabb);
}
+ void recheck_pairs(uint32_t p_handle) {
+ BVHHandle h;
+ h.set(p_handle);
+ recheck_pairs(h);
+ }
+
void erase(uint32_t p_handle) {
BVHHandle h;
h.set(p_handle);
@@ -141,7 +158,7 @@ public:
force_collision_check(h);
}
- bool activate(uint32_t p_handle, const Bounds &p_aabb, bool p_delay_collision_check = false) {
+ bool activate(uint32_t p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) {
BVHHandle h;
h.set(p_handle);
return activate(h, p_aabb, p_delay_collision_check);
@@ -153,16 +170,16 @@ public:
return deactivate(h);
}
- void set_pairable(uint32_t p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_force_collision_check = true) {
+ void set_tree(uint32_t p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) {
BVHHandle h;
h.set(p_handle);
- set_pairable(h, p_pairable, p_pairable_type, p_pairable_mask, p_force_collision_check);
+ set_tree(h, p_tree_id, p_tree_collision_mask, p_force_collision_check);
}
- bool is_pairable(uint32_t p_handle) const {
+ uint32_t get_tree_id(uint32_t p_handle) const {
BVHHandle h;
h.set(p_handle);
- return item_is_pairable(h);
+ return item_get_tree_id(h);
}
int get_subindex(uint32_t p_handle) const {
BVHHandle h;
@@ -178,7 +195,8 @@ public:
////////////////////////////////////////////////////
- void move(BVHHandle p_handle, const Bounds &p_aabb) {
+ void move(BVHHandle p_handle, const BOUNDS &p_aabb) {
+ BVH_LOCKED_FUNCTION
if (tree.item_move(p_handle, p_aabb)) {
if (USE_PAIRS) {
_add_changed_item(p_handle, p_aabb);
@@ -186,7 +204,12 @@ public:
}
}
+ void recheck_pairs(BVHHandle p_handle) {
+ force_collision_check(p_handle);
+ }
+
void erase(BVHHandle p_handle) {
+ BVH_LOCKED_FUNCTION
// call unpair and remove all references to the item
// before deleting from the tree
if (USE_PAIRS) {
@@ -200,11 +223,12 @@ public:
// use in conjunction with activate if you have deferred the collision check, and
// set pairable has never been called.
- // (deferred collision checks are a workaround for rendering server for historical reasons)
+ // (deferred collision checks are a workaround for visual server for historical reasons)
void force_collision_check(BVHHandle p_handle) {
+ BVH_LOCKED_FUNCTION
if (USE_PAIRS) {
// the aabb should already be up to date in the BVH
- Bounds aabb;
+ BOUNDS aabb;
item_get_AABB(p_handle, aabb);
// add it as changed even if aabb not different
@@ -218,7 +242,8 @@ public:
// these should be read as set_visible for render trees,
// but generically this makes items add or remove from the
// tree internally, to speed things up by ignoring inactive items
- bool activate(BVHHandle p_handle, const Bounds &p_aabb, bool p_delay_collision_check = false) {
+ bool activate(BVHHandle p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) {
+ BVH_LOCKED_FUNCTION
// sending the aabb here prevents the need for the BVH to maintain
// a redundant copy of the aabb.
// returns success
@@ -242,6 +267,7 @@ public:
}
bool deactivate(BVHHandle p_handle) {
+ BVH_LOCKED_FUNCTION
// returns success
if (tree.item_deactivate(p_handle)) {
// call unpair and remove all references to the item
@@ -258,12 +284,14 @@ public:
return false;
}
- bool get_active(BVHHandle p_handle) const {
+ bool get_active(BVHHandle p_handle) {
+ BVH_LOCKED_FUNCTION
return tree.item_get_active(p_handle);
}
// call e.g. once per frame (this does a trickle optimize)
void update() {
+ BVH_LOCKED_FUNCTION
tree.update();
_check_for_collisions();
#ifdef BVH_INTEGRITY_CHECKS
@@ -273,24 +301,26 @@ public:
// this can be called more frequently than per frame if necessary
void update_collisions() {
+ BVH_LOCKED_FUNCTION
_check_for_collisions();
}
// prefer calling this directly as type safe
- void set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_force_collision_check = true) {
+ void set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) {
+ BVH_LOCKED_FUNCTION
// Returns true if the pairing state has changed.
- bool state_changed = tree.item_set_pairable(p_handle, p_pairable, p_pairable_type, p_pairable_mask);
+ bool state_changed = tree.item_set_tree(p_handle, p_tree_id, p_tree_collision_mask);
if (USE_PAIRS) {
// not sure if absolutely necessary to flush collisions here. It will cost performance to, instead
// of waiting for update, so only uncomment this if there are bugs.
//_check_for_collisions();
- if ((p_force_collision_check || state_changed) && get_active(p_handle)) {
+ if ((p_force_collision_check || state_changed) && tree.item_get_active(p_handle)) {
// when the pairable state changes, we need to force a collision check because newly pairable
// items may be in collision, and unpairable items might move out of collision.
// We cannot depend on waiting for the next update, because that may come much later.
- Bounds aabb;
+ BOUNDS aabb;
item_get_AABB(p_handle, aabb);
// passing false disables the optimization which prevents collision checks if
@@ -307,32 +337,33 @@ public:
}
// cull tests
- int cull_aabb(const Bounds &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_aabb(const BOUNDS &p_aabb, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) {
+ BVH_LOCKED_FUNCTION
typename BVHTREE_CLASS::CullParams params;
params.result_count_overall = 0;
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = p_subindex_array;
- params.mask = p_mask;
- params.pairable_type = 0;
- params.test_pairable_only = false;
+ params.tree_collision_mask = p_tree_collision_mask;
params.abb.from(p_aabb);
+ params.tester = p_tester;
tree.cull_aabb(params);
return params.result_count_overall;
}
- int cull_segment(const Point &p_from, const Point &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_segment(const POINT &p_from, const POINT &p_to, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) {
+ BVH_LOCKED_FUNCTION
typename BVHTREE_CLASS::CullParams params;
params.result_count_overall = 0;
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = p_subindex_array;
- params.mask = p_mask;
- params.pairable_type = 0;
+ params.tester = p_tester;
+ params.tree_collision_mask = p_tree_collision_mask;
params.segment.from = p_from;
params.segment.to = p_to;
@@ -342,15 +373,16 @@ public:
return params.result_count_overall;
}
- int cull_point(const Point &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_point(const POINT &p_point, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) {
+ BVH_LOCKED_FUNCTION
typename BVHTREE_CLASS::CullParams params;
params.result_count_overall = 0;
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = p_subindex_array;
- params.mask = p_mask;
- params.pairable_type = 0;
+ params.tester = p_tester;
+ params.tree_collision_mask = p_tree_collision_mask;
params.point = p_point;
@@ -358,7 +390,8 @@ public:
return params.result_count_overall;
}
- int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF) {
+ BVH_LOCKED_FUNCTION
if (!p_convex.size()) {
return 0;
}
@@ -373,8 +406,8 @@ public:
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = nullptr;
- params.mask = p_mask;
- params.pairable_type = 0;
+ params.tester = p_tester;
+ params.tree_collision_mask = p_tree_collision_mask;
params.hull.planes = &p_convex[0];
params.hull.num_planes = p_convex.size();
@@ -394,7 +427,7 @@ private:
return;
}
- Bounds bb;
+ BOUNDS bb;
typename BVHTREE_CLASS::CullParams params;
@@ -402,28 +435,23 @@ private:
params.result_max = INT_MAX;
params.result_array = nullptr;
params.subindex_array = nullptr;
- params.mask = 0xFFFFFFFF;
- params.pairable_type = 0;
for (unsigned int n = 0; n < changed_items.size(); n++) {
const BVHHandle &h = changed_items[n];
// use the expanded aabb for pairing
- const Bounds &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
+ const BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
BVHABB_CLASS abb;
abb.from(expanded_aabb);
+ tree.item_fill_cullparams(h, params);
+
// find all the existing paired aabbs that are no longer
// paired, and send callbacks
_find_leavers(h, abb, p_full_check);
uint32_t changed_item_ref_id = h.id();
- // set up the test from this item.
- // this includes whether to test the non pairable tree,
- // and the item mask.
- tree.item_fill_cullparams(h, params);
-
params.abb = abb;
params.result_count_overall = 0; // might not be needed
@@ -456,7 +484,7 @@ private:
}
public:
- void item_get_AABB(BVHHandle p_handle, Bounds &r_aabb) {
+ void item_get_AABB(BVHHandle p_handle, BOUNDS &r_aabb) {
BVHABB_CLASS abb;
tree.item_get_ABB(p_handle, abb);
abb.to(r_aabb);
@@ -464,7 +492,7 @@ public:
private:
// supplemental funcs
- bool item_is_pairable(BVHHandle p_handle) const { return _get_extra(p_handle).pairable; }
+ uint32_t item_get_tree_id(BVHHandle p_handle) const { return _get_extra(p_handle).tree_id; }
T *item_get_userdata(BVHHandle p_handle) const { return _get_extra(p_handle).userdata; }
int item_get_subindex(BVHHandle p_handle) const { return _get_extra(p_handle).subindex; }
@@ -485,12 +513,35 @@ private:
void *ud_from = pairs_from.remove_pair_to(p_to);
pairs_to.remove_pair_to(p_from);
+#ifdef BVH_VERBOSE_PAIRING
+ print_line("_unpair " + itos(p_from.id()) + " from " + itos(p_to.id()));
+#endif
+
// callback
if (unpair_callback) {
unpair_callback(pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, ud_from);
}
}
+ void *_recheck_pair(BVHHandle p_from, BVHHandle p_to, void *p_pair_data) {
+ tree._handle_sort(p_from, p_to);
+
+ typename BVHTREE_CLASS::ItemExtra &exa = tree._extra[p_from.id()];
+ typename BVHTREE_CLASS::ItemExtra &exb = tree._extra[p_to.id()];
+
+ // if the userdata is the same, no collisions should occur
+ if ((exa.userdata == exb.userdata) && exa.userdata) {
+ return p_pair_data;
+ }
+
+ // callback
+ if (check_pair_callback) {
+ return check_pair_callback(check_pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, p_pair_data);
+ }
+
+ return p_pair_data;
+ }
+
// returns true if unpair
bool _find_leavers_process_pair(typename BVHTREE_CLASS::ItemPairs &p_pairs_from, const BVHABB_CLASS &p_abb_from, BVHHandle p_from, BVHHandle p_to, bool p_full_check) {
BVHABB_CLASS abb_to;
@@ -498,8 +549,8 @@ private:
// do they overlap?
if (p_abb_from.intersects(abb_to)) {
- // the full check for pairable / non pairable and mask changes is extra expense
- // this need not be done in most cases (for speed) except in the case where set_pairable is called
+ // the full check for pairable / non pairable (i.e. tree_id and tree_masks) and mask changes is extra expense
+ // this need not be done in most cases (for speed) except in the case where set_tree is called
// where the masks etc of the objects in question may have changed
if (!p_full_check) {
return false;
@@ -507,12 +558,13 @@ private:
const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_from);
const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_to);
- // one of the two must be pairable to still pair
- // if neither are pairable, we always unpair
- if (exa.pairable || exb.pairable) {
+ // Checking tree_ids and tree_collision_masks
+ if (exa.are_item_trees_compatible(exb)) {
+ bool pair_allowed = USER_PAIR_TEST_FUNCTION::user_pair_check(exa.userdata, exb.userdata);
+
// the masks must still be compatible to pair
- // i.e. if there is a hit between the two, then they should stay paired
- if (tree._cull_pairing_mask_test_hit(exa.pairable_mask, exa.pairable_type, exb.pairable_mask, exb.pairable_type)) {
+ // i.e. if there is a hit between the two and they intersect, then they should stay paired
+ if (pair_allowed) {
return false;
}
}
@@ -550,6 +602,11 @@ private:
const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_ha);
const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_hb);
+ // user collision callback
+ if (!USER_PAIR_TEST_FUNCTION::user_pair_check(exa.userdata, exb.userdata)) {
+ return;
+ }
+
// if the userdata is the same, no collisions should occur
if ((exa.userdata == exb.userdata) && exa.userdata) {
return;
@@ -573,6 +630,10 @@ private:
// callback
void *callback_userdata = nullptr;
+#ifdef BVH_VERBOSE_PAIRING
+ print_line("_pair " + itos(p_ha.id()) + " to " + itos(p_hb.id()));
+#endif
+
if (pair_callback) {
callback_userdata = pair_callback(pair_callback_userdata, p_ha, exa.userdata, exa.subindex, p_hb, exb.userdata, exb.subindex);
}
@@ -594,6 +655,32 @@ private:
}
}
+ // Send pair callbacks again for all existing pairs for the given handle.
+ void _recheck_pairs(BVHHandle p_handle) {
+ typename BVHTREE_CLASS::ItemPairs &from = tree._pairs[p_handle.id()];
+
+ // checking pair for every partner.
+ for (unsigned int n = 0; n < from.extended_pairs.size(); n++) {
+ typename BVHTREE_CLASS::ItemPairs::Link &pair = from.extended_pairs[n];
+ BVHHandle h_to = pair.handle;
+ void *new_pair_data = _recheck_pair(p_handle, h_to, pair.userdata);
+
+ if (new_pair_data != pair.userdata) {
+ pair.userdata = new_pair_data;
+
+ // Update pair data for the second item.
+ typename BVHTREE_CLASS::ItemPairs &to = tree._pairs[h_to.id()];
+ for (unsigned int to_index = 0; to_index < to.extended_pairs.size(); to_index++) {
+ typename BVHTREE_CLASS::ItemPairs::Link &to_pair = to.extended_pairs[to_index];
+ if (to_pair.handle == p_handle) {
+ to_pair.userdata = new_pair_data;
+ break;
+ }
+ }
+ }
+ }
+ }
+
private:
const typename BVHTREE_CLASS::ItemExtra &_get_extra(BVHHandle p_handle) const {
return tree._extra[p_handle.id()];
@@ -607,19 +694,24 @@ private:
_tick++;
}
- void _add_changed_item(BVHHandle p_handle, const Bounds &aabb, bool p_check_aabb = true) {
+ void _add_changed_item(BVHHandle p_handle, const BOUNDS &aabb, bool p_check_aabb = true) {
// Note that non pairable items can pair with pairable,
// so all types must be added to the list
+#ifdef BVH_EXPAND_LEAF_AABBS
+ // if using expanded AABB in the leaf, the redundancy check will already have been made
+ BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
+ item_get_AABB(p_handle, expanded_aabb);
+#else
// aabb check with expanded aabb. This greatly decreases processing
// at the cost of slightly less accurate pairing checks
// Note this pairing AABB is separate from the AABB in the actual tree
- Bounds &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
+ BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
// passing p_check_aabb false disables the optimization which prevents collision checks if
// the aabb hasn't changed. This is needed where set_pairable has been called, but the position
// has not changed.
- if (p_check_aabb && expanded_aabb.encloses(aabb)) {
+ if (p_check_aabb && tree.expanded_aabb_encloses_not_shrink(expanded_aabb, aabb)) {
return;
}
@@ -627,6 +719,7 @@ private:
// this tick, because it is vital that the AABB is kept up to date
expanded_aabb = aabb;
expanded_aabb.grow_by(tree._pairing_expansion);
+#endif
// this code is to ensure that changed items only appear once on the updated list
// collision checking them multiple times is not needed, and repeats the same thing
@@ -670,8 +763,10 @@ private:
PairCallback pair_callback;
UnpairCallback unpair_callback;
+ CheckPairCallback check_pair_callback;
void *pair_callback_userdata;
void *unpair_callback_userdata;
+ void *check_pair_callback_userdata;
BVHTREE_CLASS tree;
@@ -680,6 +775,38 @@ private:
LocalVector<BVHHandle, uint32_t, true> changed_items;
uint32_t _tick;
+ class BVHLockedFunction {
+ public:
+ BVHLockedFunction(Mutex *p_mutex, bool p_thread_safe) {
+ // will be compiled out if not set in template
+ if (p_thread_safe) {
+ _mutex = p_mutex;
+
+ if (_mutex->try_lock() != OK) {
+ WARN_PRINT("Info : multithread BVH access detected (benign)");
+ _mutex->lock();
+ }
+
+ } else {
+ _mutex = nullptr;
+ }
+ }
+ ~BVHLockedFunction() {
+ // will be compiled out if not set in template
+ if (_mutex) {
+ _mutex->unlock();
+ }
+ }
+
+ private:
+ Mutex *_mutex;
+ };
+
+ Mutex _mutex;
+
+ // local toggle for turning on and off thread safety in project settings
+ bool _thread_safe;
+
public:
BVH_Manager() {
_tick = 1; // start from 1 so items with 0 indicate never updated
@@ -687,6 +814,7 @@ public:
unpair_callback = nullptr;
pair_callback_userdata = nullptr;
unpair_callback_userdata = nullptr;
+ _thread_safe = BVH_THREAD_SAFE;
}
};
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
index 009032d34d..8a44f1c4da 100644
--- a/core/math/bvh_abb.h
+++ b/core/math/bvh_abb.h
@@ -32,7 +32,7 @@
#define BVH_ABB_H
// special optimized version of axis aligned bounding box
-template <class Bounds = AABB, class Point = Vector3>
+template <class BOUNDS = AABB, class POINT = Vector3>
struct BVH_ABB {
struct ConvexHull {
// convex hulls (optional)
@@ -43,8 +43,8 @@ struct BVH_ABB {
};
struct Segment {
- Point from;
- Point to;
+ POINT from;
+ POINT to;
};
enum IntersectResult {
@@ -54,47 +54,47 @@ struct BVH_ABB {
};
// we store mins with a negative value in order to test them with SIMD
- Point min;
- Point neg_max;
+ POINT min;
+ POINT neg_max;
bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); }
bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; }
- void set(const Point &_min, const Point &_max) {
+ void set(const POINT &_min, const POINT &_max) {
min = _min;
neg_max = -_max;
}
// to and from standard AABB
- void from(const Bounds &p_aabb) {
+ void from(const BOUNDS &p_aabb) {
min = p_aabb.position;
neg_max = -(p_aabb.position + p_aabb.size);
}
- void to(Bounds &r_aabb) const {
+ void to(BOUNDS &r_aabb) const {
r_aabb.position = min;
r_aabb.size = calculate_size();
}
void merge(const BVH_ABB &p_o) {
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
neg_max[axis] = MIN(neg_max[axis], p_o.neg_max[axis]);
min[axis] = MIN(min[axis], p_o.min[axis]);
}
}
- Point calculate_size() const {
+ POINT calculate_size() const {
return -neg_max - min;
}
- Point calculate_centre() const {
- return Point((calculate_size() * 0.5) + min);
+ POINT calculate_centre() const {
+ return POINT((calculate_size() * 0.5) + min);
}
real_t get_proximity_to(const BVH_ABB &p_b) const {
- const Point d = (min - neg_max) - (p_b.min - p_b.neg_max);
+ const POINT d = (min - neg_max) - (p_b.min - p_b.neg_max);
real_t proximity = 0.0;
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
proximity += Math::abs(d[axis]);
}
return proximity;
@@ -104,7 +104,7 @@ struct BVH_ABB {
return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1);
}
- uint32_t find_cutting_planes(const BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
+ uint32_t find_cutting_planes(const typename BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
uint32_t count = 0;
for (int n = 0; n < p_hull.num_planes; n++) {
@@ -162,7 +162,7 @@ struct BVH_ABB {
}
bool intersects_convex_partial(const ConvexHull &p_hull) const {
- Bounds bb;
+ BOUNDS bb;
to(bb);
return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points);
}
@@ -182,7 +182,7 @@ struct BVH_ABB {
bool is_within_convex(const ConvexHull &p_hull) const {
// use half extents routine
- Bounds bb;
+ BOUNDS bb;
to(bb);
return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes);
}
@@ -197,12 +197,12 @@ struct BVH_ABB {
}
bool intersects_segment(const Segment &p_s) const {
- Bounds bb;
+ BOUNDS bb;
to(bb);
return bb.intersects_segment(p_s.from, p_s.to);
}
- bool intersects_point(const Point &p_pt) const {
+ bool intersects_point(const POINT &p_pt) const {
if (_any_lessthan(-p_pt, neg_max)) {
return false;
}
@@ -212,6 +212,7 @@ struct BVH_ABB {
return true;
}
+ // Very hot in profiling, make sure optimized
bool intersects(const BVH_ABB &p_o) const {
if (_any_morethan(p_o.min, -neg_max)) {
return false;
@@ -222,6 +223,17 @@ struct BVH_ABB {
return true;
}
+ // for pre-swizzled tester (this object)
+ bool intersects_swizzled(const BVH_ABB &p_o) const {
+ if (_any_lessthan(min, p_o.min)) {
+ return false;
+ }
+ if (_any_lessthan(neg_max, p_o.neg_max)) {
+ return false;
+ }
+ return true;
+ }
+
bool is_other_within(const BVH_ABB &p_o) const {
if (_any_lessthan(p_o.neg_max, neg_max)) {
return false;
@@ -232,20 +244,20 @@ struct BVH_ABB {
return true;
}
- void grow(const Point &p_change) {
+ void grow(const POINT &p_change) {
neg_max -= p_change;
min -= p_change;
}
void expand(real_t p_change) {
- Point change;
+ POINT change;
change.set_all(p_change);
grow(change);
}
// Actually surface area metric.
float get_area() const {
- Point d = calculate_size();
+ POINT d = calculate_size();
return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
}
@@ -254,8 +266,8 @@ struct BVH_ABB {
min = neg_max;
}
- bool _any_morethan(const Point &p_a, const Point &p_b) const {
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ bool _any_morethan(const POINT &p_a, const POINT &p_b) const {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
if (p_a[axis] > p_b[axis]) {
return true;
}
@@ -263,8 +275,8 @@ struct BVH_ABB {
return false;
}
- bool _any_lessthan(const Point &p_a, const Point &p_b) const {
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ bool _any_lessthan(const POINT &p_a, const POINT &p_b) const {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
if (p_a[axis] < p_b[axis]) {
return true;
}
diff --git a/core/math/bvh_cull.inc b/core/math/bvh_cull.inc
index ab468bfd29..11f50e41e6 100644
--- a/core/math/bvh_cull.inc
+++ b/core/math/bvh_cull.inc
@@ -9,20 +9,22 @@ struct CullParams {
T **result_array;
int *subindex_array;
- // nobody truly understands how masks are intended to work.
- uint32_t mask;
- uint32_t pairable_type;
+ // We now process masks etc in a user template function,
+ // and these for simplicity assume even for cull tests there is a
+ // testing object (which has masks etc) for the user cull checks.
+ // This means for cull tests on their own, the client will usually
+ // want to create a dummy object, just in order to specify masks etc.
+ const T *tester;
// optional components for different tests
- Point point;
+ POINT point;
BVHABB_CLASS abb;
typename BVHABB_CLASS::ConvexHull hull;
typename BVHABB_CLASS::Segment segment;
- // when collision testing, non pairable moving items
- // only need to be tested against the pairable tree.
- // collisions with other non pairable items are irrelevant.
- bool test_pairable_only;
+ // When collision testing, we can specify which tree ids
+ // to collide test against with the tree_collision_mask.
+ uint32_t tree_collision_mask;
};
private:
@@ -58,11 +60,22 @@ int cull_convex(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
+ continue;
+ }
+
_cull_convex_iterative(_root_node_id[n], r_params);
}
@@ -77,11 +90,22 @@ int cull_segment(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
+ continue;
+ }
+
_cull_segment_iterative(_root_node_id[n], r_params);
}
@@ -96,11 +120,22 @@ int cull_point(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
+ continue;
+ }
+
_cull_point_iterative(_root_node_id[n], r_params);
}
@@ -115,12 +150,20 @@ int cull_aabb(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
- if ((n == 0) && r_params.test_pairable_only) {
+ // the tree collision mask determines which trees to collide test against
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
continue;
}
@@ -142,22 +185,6 @@ bool _cull_hits_full(const CullParams &p) {
return (int)_cull_hits.size() >= p.result_max;
}
-// write this logic once for use in all routines
-// double check this as a possible source of bugs in future.
-bool _cull_pairing_mask_test_hit(uint32_t p_maskA, uint32_t p_typeA, uint32_t p_maskB, uint32_t p_typeB) const {
- // double check this as a possible source of bugs in future.
- bool A_match_B = p_maskA & p_typeB;
-
- if (!A_match_B) {
- bool B_match_A = p_maskB & p_typeA;
- if (!B_match_A) {
- return false;
- }
- }
-
- return true;
-}
-
void _cull_hit(uint32_t p_ref_id, CullParams &p) {
// take into account masks etc
// this would be more efficient to do before plane checks,
@@ -165,7 +192,8 @@ void _cull_hit(uint32_t p_ref_id, CullParams &p) {
if (USE_PAIRS) {
const ItemExtra &ex = _extra[p_ref_id];
- if (!_cull_pairing_mask_test_hit(p.mask, p.pairable_type, ex.pairable_mask, ex.pairable_type)) {
+ // user supplied function (for e.g. pairable types and pairable masks in the render tree)
+ if (!USER_CULL_TEST_FUNCTION::user_cull_check(p.tester, ex.userdata)) {
return;
}
}
@@ -294,6 +322,7 @@ bool _cull_point_iterative(uint32_t p_node_id, CullParams &r_params) {
return true;
}
+// Note: This is a very hot loop profiling wise. Take care when changing this and profile.
bool _cull_aabb_iterative(uint32_t p_node_id, CullParams &r_params, bool p_fully_within = false) {
// our function parameters to keep on a stack
struct CullAABBParams {
@@ -336,16 +365,26 @@ bool _cull_aabb_iterative(uint32_t p_node_id, CullParams &r_params, bool p_fully
_cull_hit(child_id, r_params);
}
} else {
- for (int n = 0; n < leaf.num_items; n++) {
+ // This section is the hottest area in profiling, so
+ // is optimized highly
+ // get this into a local register and preconverted to correct type
+ int leaf_num_items = leaf.num_items;
+
+ BVHABB_CLASS swizzled_tester;
+ swizzled_tester.min = -r_params.abb.neg_max;
+ swizzled_tester.neg_max = -r_params.abb.min;
+
+ for (int n = 0; n < leaf_num_items; n++) {
const BVHABB_CLASS &aabb = leaf.get_aabb(n);
- if (aabb.intersects(r_params.abb)) {
+ if (swizzled_tester.intersects_swizzled(aabb)) {
uint32_t child_id = leaf.get_item_ref_id(n);
// register hit
_cull_hit(child_id, r_params);
}
}
+
} // not fully within
} else {
if (!cap.fully_within) {
diff --git a/core/math/bvh_debug.inc b/core/math/bvh_debug.inc
index 896c36ecf1..2e519ceb3d 100644
--- a/core/math/bvh_debug.inc
+++ b/core/math/bvh_debug.inc
@@ -7,12 +7,12 @@ void _debug_recursive_print_tree(int p_tree_id) const {
}
String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const {
- Point size = aabb.calculate_size();
+ POINT size = aabb.calculate_size();
String sz;
float vol = 0.0;
- for (int i = 0; i < Point::AXES_COUNT; ++i) {
+ for (int i = 0; i < POINT::AXIS_COUNT; ++i) {
sz += "(";
sz += itos(aabb.min[i]);
sz += " ~ ";
diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc
index c65002a9fd..dd3b135bb5 100644
--- a/core/math/bvh_logic.inc
+++ b/core/math/bvh_logic.inc
@@ -42,9 +42,9 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) {
//--------------------------------------------------------------------------------------------------
/**
- * @file q3DynamicAABBTree.h
- * @author Randy Gaul
- * @date 10/10/2014
+ * @file q3DynamicAABBTree.h
+ * @author Randy Gaul
+ * @date 10/10/2014
* Copyright (c) 2014 Randy Gaul http://www.randygaul.net
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -75,11 +75,11 @@ int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) {
return iA;
}
- /* A
- * / \
- * B C
- * / \ / \
- * D E F G
+ /* A
+ * / \
+ * B C
+ * / \ / \
+ * D E F G
*/
CRASH_COND(A->num_children != 2);
diff --git a/core/math/bvh_misc.inc b/core/math/bvh_misc.inc
index 71aa0e4fe0..9b35a1d36d 100644
--- a/core/math/bvh_misc.inc
+++ b/core/math/bvh_misc.inc
@@ -1,11 +1,7 @@
int _handle_get_tree_id(BVHHandle p_handle) const {
if (USE_PAIRS) {
- int tree = 0;
- if (_extra[p_handle.id()].pairable) {
- tree = 1;
- }
- return tree;
+ return _extra[p_handle.id()].tree_id;
}
return 0;
}
diff --git a/core/math/bvh_pair.inc b/core/math/bvh_pair.inc
index a12acec2b6..7b9c7ce6ae 100644
--- a/core/math/bvh_pair.inc
+++ b/core/math/bvh_pair.inc
@@ -14,10 +14,10 @@ struct ItemPairs {
void clear() {
num_pairs = 0;
extended_pairs.reset();
- expanded_aabb = Bounds();
+ expanded_aabb = BOUNDS();
}
- Bounds expanded_aabb;
+ BOUNDS expanded_aabb;
// maybe we can just use the number in the vector TODO
int32_t num_pairs;
@@ -59,4 +59,14 @@ struct ItemPairs {
return userdata;
}
+
+ // experiment : scale the pairing expansion by the number of pairs.
+ // when the number of pairs is high, the density is high and a lower collision margin is better.
+ // when there are few local pairs, a larger margin is more optimal.
+ real_t scale_expansion_margin(real_t p_margin) const {
+ real_t x = real_t(num_pairs) * (1.0 / 9.0);
+ x = MIN(x, 1.0);
+ x = 1.0 - x;
+ return p_margin * x;
+ }
};
diff --git a/core/math/bvh_public.inc b/core/math/bvh_public.inc
index 2c1e406712..36b0bfeb13 100644
--- a/core/math/bvh_public.inc
+++ b/core/math/bvh_public.inc
@@ -1,5 +1,5 @@
public:
-BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p_subindex, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_invisible = false) {
+BVHHandle item_add(T *p_userdata, bool p_active, const BOUNDS &p_aabb, int32_t p_subindex, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_invisible = false) {
#ifdef BVH_VERBOSE_TREE
VERBOSE_PRINT("\nitem_add BEFORE");
_debug_recursive_print_tree(0);
@@ -9,6 +9,13 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p
BVHABB_CLASS abb;
abb.from(p_aabb);
+ // NOTE that we do not expand the AABB for the first create even if
+ // leaf expansion is switched on. This is for two reasons:
+ // (1) We don't know if this object will move in future, in which case a non-expanded
+ // bound would be better...
+ // (2) We don't yet know how many objects will be paired, which is used to modify
+ // the expansion margin.
+
// handle to be filled with the new item ref
BVHHandle handle;
@@ -40,29 +47,17 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p
extra->active_ref_id = _active_refs.size();
_active_refs.push_back(ref_id);
- if (USE_PAIRS) {
- extra->pairable_mask = p_pairable_mask;
- extra->pairable_type = p_pairable_type;
- extra->pairable = p_pairable;
- } else {
- // just for safety, in case this gets queried etc
- extra->pairable = 0;
- p_pairable = false;
- }
+ extra->tree_id = p_tree_id;
+ extra->tree_collision_mask = p_tree_collision_mask;
// assign to handle to return
handle.set_id(ref_id);
- uint32_t tree_id = 0;
- if (p_pairable) {
- tree_id = 1;
- }
-
- create_root_node(tree_id);
+ create_root_node(p_tree_id);
// we must choose where to add to tree
if (p_active) {
- ref->tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+ ref->tnode_id = _logic_choose_item_add_node(_root_node_id[p_tree_id], abb);
bool refit = _node_add_item(ref->tnode_id, ref_id, abb);
@@ -70,7 +65,7 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p
// only need to refit from the parent
const TNode &add_node = _nodes[ref->tnode_id];
if (add_node.parent_id != BVHCommon::INVALID) {
- refit_upward_and_balance(add_node.parent_id, tree_id);
+ refit_upward_and_balance(add_node.parent_id, p_tree_id);
}
}
} else {
@@ -103,7 +98,7 @@ void _debug_print_refs() {
}
// returns false if noop
-bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
+bool item_move(BVHHandle p_handle, const BOUNDS &p_aabb) {
uint32_t ref_id = p_handle.id();
// get the reference
@@ -115,10 +110,19 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
BVHABB_CLASS abb;
abb.from(p_aabb);
+#ifdef BVH_EXPAND_LEAF_AABBS
+ if (USE_PAIRS) {
+ // scale the pairing expansion by the number of pairs.
+ abb.expand(_pairs[ref_id].scale_expansion_margin(_pairing_expansion));
+ } else {
+ abb.expand(_pairing_expansion);
+ }
+#endif
+
BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID);
TNode &tnode = _nodes[ref.tnode_id];
- // does it fit within the current aabb?
+ // does it fit within the current leaf aabb?
if (tnode.aabb.is_other_within(abb)) {
// do nothing .. fast path .. not moved enough to need refit
@@ -129,9 +133,24 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
BVHABB_CLASS &leaf_abb = leaf.get_aabb(ref.item_id);
// no change?
+#ifdef BVH_EXPAND_LEAF_AABBS
+ BOUNDS leaf_aabb;
+ leaf_abb.to(leaf_aabb);
+
+ // This test should pass in a lot of cases, and by returning false we can avoid
+ // collision pairing checks later, which greatly reduces processing.
+ if (expanded_aabb_encloses_not_shrink(leaf_aabb, p_aabb)) {
+ return false;
+ }
+#else
if (leaf_abb == abb) {
return false;
}
+#endif
+
+#ifdef BVH_VERBOSE_MOVES
+ print_line("item_move " + itos(p_handle.id()) + "(within tnode aabb) : " + _debug_aabb_to_string(abb));
+#endif
leaf_abb = abb;
_integrity_check_all();
@@ -139,6 +158,10 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
return true;
}
+#ifdef BVH_VERBOSE_MOVES
+ print_line("item_move " + itos(p_handle.id()) + "(outside tnode aabb) : " + _debug_aabb_to_string(abb));
+#endif
+
uint32_t tree_id = _handle_get_tree_id(p_handle);
// remove and reinsert
@@ -206,7 +229,7 @@ void item_remove(BVHHandle p_handle) {
}
// returns success
-bool item_activate(BVHHandle p_handle, const Bounds &p_aabb) {
+bool item_activate(BVHHandle p_handle, const BOUNDS &p_aabb) {
uint32_t ref_id = p_handle.id();
ItemRef &ref = _refs[ref_id];
if (ref.is_active()) {
@@ -260,12 +283,14 @@ void item_fill_cullparams(BVHHandle p_handle, CullParams &r_params) const {
uint32_t ref_id = p_handle.id();
const ItemExtra &extra = _extra[ref_id];
- // testing from a non pairable item, we only want to test pairable items
- r_params.test_pairable_only = extra.pairable == 0;
+ // which trees does this item want to collide detect against?
+ r_params.tree_collision_mask = extra.tree_collision_mask;
- // we take into account the mask of the item testing from
- r_params.mask = extra.pairable_mask;
- r_params.pairable_type = extra.pairable_type;
+ // The testing user defined object is passed to the user defined cull check function
+ // for masks etc. This is usually a dummy object of type T with masks set.
+ // However, if not using the cull_check callback (i.e. returning true), you can pass
+ // a nullptr instead of dummy object, as it will not be used.
+ r_params.tester = extra.userdata;
}
bool item_is_pairable(const BVHHandle &p_handle) {
@@ -285,7 +310,7 @@ void item_get_ABB(const BVHHandle &p_handle, BVHABB_CLASS &r_abb) {
r_abb = leaf.get_aabb(ref.item_id);
}
-bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) {
+bool item_set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask) {
// change tree?
uint32_t ref_id = p_handle.id();
@@ -293,13 +318,15 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa
ItemRef &ref = _refs[ref_id];
bool active = ref.is_active();
- bool pairable_changed = (ex.pairable != 0) != p_pairable;
- bool state_changed = pairable_changed || (ex.pairable_type != p_pairable_type) || (ex.pairable_mask != p_pairable_mask);
+ bool tree_changed = ex.tree_id != p_tree_id;
+ bool mask_changed = ex.tree_collision_mask != p_tree_collision_mask;
+ bool state_changed = tree_changed | mask_changed;
- ex.pairable_type = p_pairable_type;
- ex.pairable_mask = p_pairable_mask;
+ // Keep an eye on this for bugs of not noticing changes to objects,
+ // especially when changing client user masks that will not be detected as a change
+ // in the BVH. You may need to force a collision check in this case with recheck_pairs().
- if (active && pairable_changed) {
+ if (active && (tree_changed | mask_changed)) {
// record abb
TNode &tnode = _nodes[ref.tnode_id];
TLeaf &leaf = _node_get_leaf(tnode);
@@ -313,7 +340,8 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa
// we must set the pairable AFTER getting the current tree
// because the pairable status determines which tree
- ex.pairable = p_pairable;
+ ex.tree_id = p_tree_id;
+ ex.tree_collision_mask = p_tree_collision_mask;
// add to new tree
tree_id = _handle_get_tree_id(p_handle);
@@ -333,7 +361,8 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa
}
} else {
// always keep this up to date
- ex.pairable = p_pairable;
+ ex.tree_id = p_tree_id;
+ ex.tree_collision_mask = p_tree_collision_mask;
}
return state_changed;
@@ -403,7 +432,7 @@ void update() {
// if there are no nodes, do nothing, but if there are...
if (bound_valid) {
- Bounds bb;
+ BOUNDS bb;
world_bound.to(bb);
real_t size = bb.get_longest_axis_size();
@@ -421,3 +450,50 @@ void update() {
}
#endif
}
+
+void params_set_pairing_expansion(real_t p_value) {
+ if (p_value < 0.0) {
+#ifdef BVH_ALLOW_AUTO_EXPANSION
+ _auto_pairing_expansion = true;
+#endif
+ return;
+ }
+#ifdef BVH_ALLOW_AUTO_EXPANSION
+ _auto_pairing_expansion = false;
+#endif
+
+ _pairing_expansion = p_value;
+
+ // calculate shrinking threshold
+ const real_t fudge_factor = 1.1;
+ _aabb_shrinkage_threshold = _pairing_expansion * POINT::AXIS_COUNT * 2.0 * fudge_factor;
+}
+
+// This routine is not just an enclose check, it also checks for special case of shrinkage
+bool expanded_aabb_encloses_not_shrink(const BOUNDS &p_expanded_aabb, const BOUNDS &p_aabb) const {
+ if (!p_expanded_aabb.encloses(p_aabb)) {
+ return false;
+ }
+
+ // Check for special case of shrinkage. If the aabb has shrunk
+ // significantly we want to create a new expanded bound, because
+ // the previous expanded bound will have diverged significantly.
+ const POINT &exp_size = p_expanded_aabb.size;
+ const POINT &new_size = p_aabb.size;
+
+ real_t exp_l = 0.0;
+ real_t new_l = 0.0;
+
+ for (int i = 0; i < POINT::AXIS_COUNT; ++i) {
+ exp_l += exp_size[i];
+ new_l += new_size[i];
+ }
+
+ // is difference above some metric
+ real_t diff = exp_l - new_l;
+ if (diff < _aabb_shrinkage_threshold) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc
index f19ee8a7da..ff07166d4a 100644
--- a/core/math/bvh_split.inc
+++ b/core/math/bvh_split.inc
@@ -25,16 +25,16 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
return;
}
- Point centre = full_bound.calculate_centre();
- Point size = full_bound.calculate_size();
+ POINT centre = full_bound.calculate_centre();
+ POINT size = full_bound.calculate_size();
- int order[Point::AXIS_COUNT];
+ int order[POINT::AXIS_COUNT];
order[0] = size.min_axis_index();
- order[Point::AXIS_COUNT - 1] = size.max_axis_index();
+ order[POINT::AXIS_COUNT - 1] = size.max_axis_index();
- static_assert(Point::AXIS_COUNT <= 3);
- if (Point::AXIS_COUNT == 3) {
+ static_assert(POINT::AXIS_COUNT <= 3, "BVH POINT::AXIS_COUNT has unexpected size");
+ if (POINT::AXIS_COUNT == 3) {
order[1] = 3 - (order[0] + order[2]);
}
@@ -58,7 +58,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
// detect when split on longest axis failed
int min_threshold = MAX_ITEMS / 4;
- int min_group_size[Point::AXIS_COUNT];
+ int min_group_size[POINT::AXIS_COUNT];
min_group_size[0] = MIN(num_a, num_b);
if (min_group_size[0] < min_threshold) {
// slow but sure .. first move everything back into a
@@ -68,7 +68,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
num_b = 0;
// now calculate the best split
- for (int axis = 1; axis < Point::AXIS_COUNT; axis++) {
+ for (int axis = 1; axis < POINT::AXIS_COUNT; axis++) {
split_axis = order[axis];
int count = 0;
@@ -86,7 +86,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
// best axis
int best_axis = 0;
int best_min = min_group_size[0];
- for (int axis = 1; axis < Point::AXIS_COUNT; axis++) {
+ for (int axis = 1; axis < POINT::AXIS_COUNT; axis++) {
if (min_group_size[axis] > best_min) {
best_min = min_group_size[axis];
best_axis = axis;
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
index 1d1e0e6468..b0d9ae3615 100644
--- a/core/math/bvh_structs.inc
+++ b/core/math/bvh_structs.inc
@@ -14,25 +14,38 @@ struct ItemRef {
// extra info kept in separate parallel list to the references,
// as this is less used as keeps cache better
struct ItemExtra {
- uint32_t last_updated_tick;
- uint32_t pairable;
- uint32_t pairable_mask;
- uint32_t pairable_type;
+ // Before doing user defined pairing checks (especially in the find_leavers function),
+ // we may want to check that two items have compatible tree ids and tree masks,
+ // as if they are incompatible they should not pair / collide.
+ bool are_item_trees_compatible(const ItemExtra &p_other) const {
+ uint32_t other_type = 1 << p_other.tree_id;
+ if (tree_collision_mask & other_type) {
+ return true;
+ }
+ uint32_t our_type = 1 << tree_id;
+ if (p_other.tree_collision_mask & our_type) {
+ return true;
+ }
+ return false;
+ }
+
+ // There can be multiple user defined trees
+ uint32_t tree_id;
+ // Defines which trees this item should collision check against.
+ // 1 << tree_id, and normally items would collide against there own
+ // tree (but not always).
+ uint32_t tree_collision_mask;
+
+ uint32_t last_updated_tick;
int32_t subindex;
+ T *userdata;
+
// the active reference is a separate list of which references
// are active so that we can slowly iterate through it over many frames for
// slow optimize.
uint32_t active_ref_id;
-
- T *userdata;
-};
-
-// this is an item OR a child node depending on whether a leaf node
-struct Item {
- BVHABB_CLASS aabb;
- uint32_t item_ref_id;
};
// tree leaf
@@ -133,13 +146,13 @@ struct TNode {
// instead of using linked list we maintain
// item references (for quick lookup)
-PooledList<ItemRef, true> _refs;
-PooledList<ItemExtra, true> _extra;
+PooledList<ItemRef, uint32_t, true> _refs;
+PooledList<ItemExtra, uint32_t, true> _extra;
PooledList<ItemPairs> _pairs;
// these 2 are not in sync .. nodes != leaves!
-PooledList<TNode, true> _nodes;
-PooledList<TLeaf, true> _leaves;
+PooledList<TNode, uint32_t, true> _nodes;
+PooledList<TLeaf, uint32_t, true> _leaves;
// we can maintain an un-ordered list of which references are active,
// in order to do a slow incremental optimize of the tree over each frame.
@@ -152,15 +165,11 @@ uint32_t _current_active_ref = 0;
// for pairing collision detection
LocalVector<uint32_t, uint32_t, true> _cull_hits;
-// we now have multiple root nodes, allowing us to store
-// more than 1 tree. This can be more efficient, while sharing the same
-// common lists
-enum { NUM_TREES = 2,
-};
-
-// Tree 0 - Non pairable
-// Tree 1 - Pairable
-// This is more efficient because in physics we only need check non pairable against the pairable tree.
+// We can now have a user definable number of trees.
+// This allows using e.g. a non-pairable and pairable tree,
+// which can be more efficient for example, if we only need check non pairable against the pairable tree.
+// It also may be more efficient in terms of separating static from dynamic objects, by reducing housekeeping.
+// However this is a trade off, as there is a cost of traversing two trees.
uint32_t _root_node_id[NUM_TREES];
// these values may need tweaking according to the project
@@ -177,4 +186,14 @@ bool _auto_node_expansion = true;
// larger values gives more 'sticky' pairing, and is less likely to exhibit tunneling
// we can either use auto mode, where the expansion is based on the root node size, or specify manually
real_t _pairing_expansion = 0.1;
+
+#ifdef BVH_ALLOW_AUTO_EXPANSION
bool _auto_pairing_expansion = true;
+#endif
+
+// when using an expanded bound, we must detect the condition where a new AABB
+// is significantly smaller than the expanded bound, as this is a special case where we
+// should override the optimization and create a new expanded bound.
+// This threshold is derived from the _pairing_expansion, and should be recalculated
+// if _pairing_expansion is changed.
+real_t _aabb_shrinkage_threshold = 0.0;
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
index c948d83456..da9b307778 100644
--- a/core/math/bvh_tree.h
+++ b/core/math/bvh_tree.h
@@ -48,12 +48,17 @@
#include "core/templates/pooled_list.h"
#include <limits.h>
-#define BVHABB_CLASS BVH_ABB<Bounds, Point>
+#define BVHABB_CLASS BVH_ABB<BOUNDS, POINT>
+
+// not sure if this is better yet so making optional
+#define BVH_EXPAND_LEAF_AABBS
// never do these checks in release
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
//#define BVH_VERBOSE
//#define BVH_VERBOSE_TREE
+//#define BVH_VERBOSE_PAIRING
+//#define BVH_VERBOSE_MOVES
//#define BVH_VERBOSE_FRAME
//#define BVH_CHECKS
@@ -148,7 +153,25 @@ public:
}
};
-template <class T, int MAX_CHILDREN, int MAX_ITEMS, bool USE_PAIRS = false, class Bounds = AABB, class Point = Vector3>
+template <class T>
+class BVH_DummyPairTestFunction {
+public:
+ static bool user_collision_check(T *p_a, T *p_b) {
+ // return false if no collision, decided by masks etc
+ return true;
+ }
+};
+
+template <class T>
+class BVH_DummyCullTestFunction {
+public:
+ static bool user_cull_check(T *p_a, T *p_b) {
+ // return false if no collision
+ return true;
+ }
+};
+
+template <class T, int NUM_TREES, int MAX_CHILDREN, int MAX_ITEMS, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, bool USE_PAIRS = false, class BOUNDS = AABB, class POINT = Vector3>
class BVH_Tree {
friend class BVH;
@@ -165,6 +188,11 @@ public:
// (as these ids are stored as negative numbers in the node)
uint32_t dummy_leaf_id;
_leaves.request(dummy_leaf_id);
+
+ // In many cases you may want to change this default in the client code,
+ // or expose this value to the user.
+ // This default may make sense for a typically scaled 3d game, but maybe not for 2d on a pixel scale.
+ params_set_pairing_expansion(0.1);
}
private:
@@ -234,7 +262,7 @@ private:
change_root_node(sibling_id, p_tree_id);
// delete the old root node as no longer needed
- _nodes.free(p_parent_id);
+ node_free_node_and_leaf(p_parent_id);
}
return;
@@ -247,7 +275,19 @@ private:
}
// put the node on the free list to recycle
- _nodes.free(p_parent_id);
+ node_free_node_and_leaf(p_parent_id);
+ }
+
+ // A node can either be a node, or a node AND a leaf combo.
+ // Both must be deleted to prevent a leak.
+ void node_free_node_and_leaf(uint32_t p_node_id) {
+ TNode &node = _nodes[p_node_id];
+ if (node.is_leaf()) {
+ int leaf_id = node.get_leaf_id();
+ _leaves.free(leaf_id);
+ }
+
+ _nodes.free(p_node_id);
}
void change_root_node(uint32_t p_new_root_id, uint32_t p_tree_id) {
@@ -339,7 +379,7 @@ private:
refit_upward(parent_id);
// put the node on the free list to recycle
- _nodes.free(owner_node_id);
+ node_free_node_and_leaf(owner_node_id);
}
// else if no parent, it is the root node. Do not delete
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index f5d746ef0f..f4392c74b7 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -436,9 +436,7 @@ void CameraMatrix::invert() {
int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
real_t pvt_val; /* Value of current pivot element */
real_t hold; /* Temporary storage */
- real_t determinat; /* Determinant */
-
- determinat = 1.0;
+ real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
pvt_val = matrix[k][k]; /** Initialize for search **/
@@ -446,7 +444,7 @@ void CameraMatrix::invert() {
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
- if (Math::absd(matrix[i][j]) > Math::absd(pvt_val)) {
+ if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
pvt_val = matrix[i][j];
@@ -455,9 +453,9 @@ void CameraMatrix::invert() {
}
/** Product of pivots, gives determinant when finished **/
- determinat *= pvt_val;
- if (Math::absd(determinat) < 1e-7) {
- return; //(false); /** Matrix is singular (zero determinant). **/
+ determinant *= pvt_val;
+ if (Math::is_zero_approx(determinant)) {
+ return; /** Matrix is singular (zero determinant). **/
}
/** "Interchange" rows (with sign change stuff) **/
diff --git a/core/math/color.h b/core/math/color.h
index 429807e4a6..b90a0f33a2 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -138,7 +138,7 @@ struct _NO_DISCARD_ Color {
float cMax = MAX(cRed, MAX(cGreen, cBlue));
- float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B;
+ float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
diff --git a/core/math/color_names.inc b/core/math/color_names.inc
index 2020bdbfca..654fa83877 100644
--- a/core/math/color_names.inc
+++ b/core/math/color_names.inc
@@ -13,151 +13,151 @@ struct NamedColor {
// modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
static NamedColor named_colors[] = {
- { "ALICE_BLUE", Color(0.94, 0.97, 1.00) },
- { "ANTIQUE_WHITE", Color(0.98, 0.92, 0.84) },
- { "AQUA", Color(0.00, 1.00, 1.00) },
- { "AQUAMARINE", Color(0.50, 1.00, 0.83) },
- { "AZURE", Color(0.94, 1.00, 1.00) },
- { "BEIGE", Color(0.96, 0.96, 0.86) },
- { "BISQUE", Color(1.00, 0.89, 0.77) },
- { "BLACK", Color(0.00, 0.00, 0.00) },
- { "BLANCHED_ALMOND", Color(1.00, 0.92, 0.80) },
- { "BLUE", Color(0.00, 0.00, 1.00) },
- { "BLUE_VIOLET", Color(0.54, 0.17, 0.89) },
- { "BROWN", Color(0.65, 0.16, 0.16) },
- { "BURLYWOOD", Color(0.87, 0.72, 0.53) },
- { "CADET_BLUE", Color(0.37, 0.62, 0.63) },
- { "CHARTREUSE", Color(0.50, 1.00, 0.00) },
- { "CHOCOLATE", Color(0.82, 0.41, 0.12) },
- { "CORAL", Color(1.00, 0.50, 0.31) },
- { "CORNFLOWER_BLUE", Color(0.39, 0.58, 0.93) },
- { "CORNSILK", Color(1.00, 0.97, 0.86) },
- { "CRIMSON", Color(0.86, 0.08, 0.24) },
- { "CYAN", Color(0.00, 1.00, 1.00) },
- { "DARK_BLUE", Color(0.00, 0.00, 0.55) },
- { "DARK_CYAN", Color(0.00, 0.55, 0.55) },
- { "DARK_GOLDENROD", Color(0.72, 0.53, 0.04) },
- { "DARK_GRAY", Color(0.66, 0.66, 0.66) },
- { "DARK_GREEN", Color(0.00, 0.39, 0.00) },
- { "DARK_KHAKI", Color(0.74, 0.72, 0.42) },
- { "DARK_MAGENTA", Color(0.55, 0.00, 0.55) },
- { "DARK_OLIVE_GREEN", Color(0.33, 0.42, 0.18) },
- { "DARK_ORANGE", Color(1.00, 0.55, 0.00) },
- { "DARK_ORCHID", Color(0.60, 0.20, 0.80) },
- { "DARK_RED", Color(0.55, 0.00, 0.00) },
- { "DARK_SALMON", Color(0.91, 0.59, 0.48) },
- { "DARK_SEA_GREEN", Color(0.56, 0.74, 0.56) },
- { "DARK_SLATE_BLUE", Color(0.28, 0.24, 0.55) },
- { "DARK_SLATE_GRAY", Color(0.18, 0.31, 0.31) },
- { "DARK_TURQUOISE", Color(0.00, 0.81, 0.82) },
- { "DARK_VIOLET", Color(0.58, 0.00, 0.83) },
- { "DEEP_PINK", Color(1.00, 0.08, 0.58) },
- { "DEEP_SKY_BLUE", Color(0.00, 0.75, 1.00) },
- { "DIM_GRAY", Color(0.41, 0.41, 0.41) },
- { "DODGER_BLUE", Color(0.12, 0.56, 1.00) },
- { "FIREBRICK", Color(0.70, 0.13, 0.13) },
- { "FLORAL_WHITE", Color(1.00, 0.98, 0.94) },
- { "FOREST_GREEN", Color(0.13, 0.55, 0.13) },
- { "FUCHSIA", Color(1.00, 0.00, 1.00) },
- { "GAINSBORO", Color(0.86, 0.86, 0.86) },
- { "GHOST_WHITE", Color(0.97, 0.97, 1.00) },
- { "GOLD", Color(1.00, 0.84, 0.00) },
- { "GOLDENROD", Color(0.85, 0.65, 0.13) },
- { "GRAY", Color(0.75, 0.75, 0.75) },
- { "GREEN", Color(0.00, 1.00, 0.00) },
- { "GREEN_YELLOW", Color(0.68, 1.00, 0.18) },
- { "HONEYDEW", Color(0.94, 1.00, 0.94) },
- { "HOT_PINK", Color(1.00, 0.41, 0.71) },
- { "INDIAN_RED", Color(0.80, 0.36, 0.36) },
- { "INDIGO", Color(0.29, 0.00, 0.51) },
- { "IVORY", Color(1.00, 1.00, 0.94) },
- { "KHAKI", Color(0.94, 0.90, 0.55) },
- { "LAVENDER", Color(0.90, 0.90, 0.98) },
- { "LAVENDER_BLUSH", Color(1.00, 0.94, 0.96) },
- { "LAWN_GREEN", Color(0.49, 0.99, 0.00) },
- { "LEMON_CHIFFON", Color(1.00, 0.98, 0.80) },
- { "LIGHT_BLUE", Color(0.68, 0.85, 0.90) },
- { "LIGHT_CORAL", Color(0.94, 0.50, 0.50) },
- { "LIGHT_CYAN", Color(0.88, 1.00, 1.00) },
- { "LIGHT_GOLDENROD", Color(0.98, 0.98, 0.82) },
- { "LIGHT_GRAY", Color(0.83, 0.83, 0.83) },
- { "LIGHT_GREEN", Color(0.56, 0.93, 0.56) },
- { "LIGHT_PINK", Color(1.00, 0.71, 0.76) },
- { "LIGHT_SALMON", Color(1.00, 0.63, 0.48) },
- { "LIGHT_SEA_GREEN", Color(0.13, 0.70, 0.67) },
- { "LIGHT_SKY_BLUE", Color(0.53, 0.81, 0.98) },
- { "LIGHT_SLATE_GRAY", Color(0.47, 0.53, 0.60) },
- { "LIGHT_STEEL_BLUE", Color(0.69, 0.77, 0.87) },
- { "LIGHT_YELLOW", Color(1.00, 1.00, 0.88) },
- { "LIME", Color(0.00, 1.00, 0.00) },
- { "LIME_GREEN", Color(0.20, 0.80, 0.20) },
- { "LINEN", Color(0.98, 0.94, 0.90) },
- { "MAGENTA", Color(1.00, 0.00, 1.00) },
- { "MAROON", Color(0.69, 0.19, 0.38) },
- { "MEDIUM_AQUAMARINE", Color(0.40, 0.80, 0.67) },
- { "MEDIUM_BLUE", Color(0.00, 0.00, 0.80) },
- { "MEDIUM_ORCHID", Color(0.73, 0.33, 0.83) },
- { "MEDIUM_PURPLE", Color(0.58, 0.44, 0.86) },
- { "MEDIUM_SEA_GREEN", Color(0.24, 0.70, 0.44) },
- { "MEDIUM_SLATE_BLUE", Color(0.48, 0.41, 0.93) },
- { "MEDIUM_SPRING_GREEN", Color(0.00, 0.98, 0.60) },
- { "MEDIUM_TURQUOISE", Color(0.28, 0.82, 0.80) },
- { "MEDIUM_VIOLET_RED", Color(0.78, 0.08, 0.52) },
- { "MIDNIGHT_BLUE", Color(0.10, 0.10, 0.44) },
- { "MINT_CREAM", Color(0.96, 1.00, 0.98) },
- { "MISTY_ROSE", Color(1.00, 0.89, 0.88) },
- { "MOCCASIN", Color(1.00, 0.89, 0.71) },
- { "NAVAJO_WHITE", Color(1.00, 0.87, 0.68) },
- { "NAVY_BLUE", Color(0.00, 0.00, 0.50) },
- { "OLD_LACE", Color(0.99, 0.96, 0.90) },
- { "OLIVE", Color(0.50, 0.50, 0.00) },
- { "OLIVE_DRAB", Color(0.42, 0.56, 0.14) },
- { "ORANGE", Color(1.00, 0.65, 0.00) },
- { "ORANGE_RED", Color(1.00, 0.27, 0.00) },
- { "ORCHID", Color(0.85, 0.44, 0.84) },
- { "PALE_GOLDENROD", Color(0.93, 0.91, 0.67) },
- { "PALE_GREEN", Color(0.60, 0.98, 0.60) },
- { "PALE_TURQUOISE", Color(0.69, 0.93, 0.93) },
- { "PALE_VIOLET_RED", Color(0.86, 0.44, 0.58) },
- { "PAPAYA_WHIP", Color(1.00, 0.94, 0.84) },
- { "PEACH_PUFF", Color(1.00, 0.85, 0.73) },
- { "PERU", Color(0.80, 0.52, 0.25) },
- { "PINK", Color(1.00, 0.75, 0.80) },
- { "PLUM", Color(0.87, 0.63, 0.87) },
- { "POWDER_BLUE", Color(0.69, 0.88, 0.90) },
- { "PURPLE", Color(0.63, 0.13, 0.94) },
- { "REBECCA_PURPLE", Color(0.40, 0.20, 0.60) },
- { "RED", Color(1.00, 0.00, 0.00) },
- { "ROSY_BROWN", Color(0.74, 0.56, 0.56) },
- { "ROYAL_BLUE", Color(0.25, 0.41, 0.88) },
- { "SADDLE_BROWN", Color(0.55, 0.27, 0.07) },
- { "SALMON", Color(0.98, 0.50, 0.45) },
- { "SANDY_BROWN", Color(0.96, 0.64, 0.38) },
- { "SEA_GREEN", Color(0.18, 0.55, 0.34) },
- { "SEASHELL", Color(1.00, 0.96, 0.93) },
- { "SIENNA", Color(0.63, 0.32, 0.18) },
- { "SILVER", Color(0.75, 0.75, 0.75) },
- { "SKY_BLUE", Color(0.53, 0.81, 0.92) },
- { "SLATE_BLUE", Color(0.42, 0.35, 0.80) },
- { "SLATE_GRAY", Color(0.44, 0.50, 0.56) },
- { "SNOW", Color(1.00, 0.98, 0.98) },
- { "SPRING_GREEN", Color(0.00, 1.00, 0.50) },
- { "STEEL_BLUE", Color(0.27, 0.51, 0.71) },
- { "TAN", Color(0.82, 0.71, 0.55) },
- { "TEAL", Color(0.00, 0.50, 0.50) },
- { "THISTLE", Color(0.85, 0.75, 0.85) },
- { "TOMATO", Color(1.00, 0.39, 0.28) },
- { "TRANSPARENT", Color(1.00, 1.00, 1.00, 0.00) },
- { "TURQUOISE", Color(0.25, 0.88, 0.82) },
- { "VIOLET", Color(0.93, 0.51, 0.93) },
- { "WEB_GRAY", Color(0.50, 0.50, 0.50) },
- { "WEB_GREEN", Color(0.00, 0.50, 0.00) },
- { "WEB_MAROON", Color(0.50, 0.00, 0.00) },
- { "WEB_PURPLE", Color(0.50, 0.00, 0.50) },
- { "WHEAT", Color(0.96, 0.87, 0.70) },
- { "WHITE", Color(1.00, 1.00, 1.00) },
- { "WHITE_SMOKE", Color(0.96, 0.96, 0.96) },
- { "YELLOW", Color(1.00, 1.00, 0.00) },
- { "YELLOW_GREEN", Color(0.60, 0.80, 0.20) },
+ { "ALICE_BLUE", Color::hex(0xF0F8FFFF) },
+ { "ANTIQUE_WHITE", Color::hex(0xFAEBD7FF) },
+ { "AQUA", Color::hex(0x00FFFFFF) },
+ { "AQUAMARINE", Color::hex(0x7FFFD4FF) },
+ { "AZURE", Color::hex(0xF0FFFFFF) },
+ { "BEIGE", Color::hex(0xF5F5DCFF) },
+ { "BISQUE", Color::hex(0xFFE4C4FF) },
+ { "BLACK", Color::hex(0x000000FF) },
+ { "BLANCHED_ALMOND", Color::hex(0xFFEBCDFF) },
+ { "BLUE", Color::hex(0x0000FFFF) },
+ { "BLUE_VIOLET", Color::hex(0x8A2BE2FF) },
+ { "BROWN", Color::hex(0xA52A2AFF) },
+ { "BURLYWOOD", Color::hex(0xDEB887FF) },
+ { "CADET_BLUE", Color::hex(0x5F9EA0FF) },
+ { "CHARTREUSE", Color::hex(0x7FFF00FF) },
+ { "CHOCOLATE", Color::hex(0xD2691EFF) },
+ { "CORAL", Color::hex(0xFF7F50FF) },
+ { "CORNFLOWER_BLUE", Color::hex(0x6495EDFF) },
+ { "CORNSILK", Color::hex(0xFFF8DCFF) },
+ { "CRIMSON", Color::hex(0xDC143CFF) },
+ { "CYAN", Color::hex(0x00FFFFFF) },
+ { "DARK_BLUE", Color::hex(0x00008BFF) },
+ { "DARK_CYAN", Color::hex(0x008B8BFF) },
+ { "DARK_GOLDENROD", Color::hex(0xB8860BFF) },
+ { "DARK_GRAY", Color::hex(0xA9A9A9FF) },
+ { "DARK_GREEN", Color::hex(0x006400FF) },
+ { "DARK_KHAKI", Color::hex(0xBDB76BFF) },
+ { "DARK_MAGENTA", Color::hex(0x8B008BFF) },
+ { "DARK_OLIVE_GREEN", Color::hex(0x556B2FFF) },
+ { "DARK_ORANGE", Color::hex(0xFF8C00FF) },
+ { "DARK_ORCHID", Color::hex(0x9932CCFF) },
+ { "DARK_RED", Color::hex(0x8B0000FF) },
+ { "DARK_SALMON", Color::hex(0xE9967AFF) },
+ { "DARK_SEA_GREEN", Color::hex(0x8FBC8FFF) },
+ { "DARK_SLATE_BLUE", Color::hex(0x483D8BFF) },
+ { "DARK_SLATE_GRAY", Color::hex(0x2F4F4FFF) },
+ { "DARK_TURQUOISE", Color::hex(0x00CED1FF) },
+ { "DARK_VIOLET", Color::hex(0x9400D3FF) },
+ { "DEEP_PINK", Color::hex(0xFF1493FF) },
+ { "DEEP_SKY_BLUE", Color::hex(0x00BFFFFF) },
+ { "DIM_GRAY", Color::hex(0x696969FF) },
+ { "DODGER_BLUE", Color::hex(0x1E90FFFF) },
+ { "FIREBRICK", Color::hex(0xB22222FF) },
+ { "FLORAL_WHITE", Color::hex(0xFFFAF0FF) },
+ { "FOREST_GREEN", Color::hex(0x228B22FF) },
+ { "FUCHSIA", Color::hex(0xFF00FFFF) },
+ { "GAINSBORO", Color::hex(0xDCDCDCFF) },
+ { "GHOST_WHITE", Color::hex(0xF8F8FFFF) },
+ { "GOLD", Color::hex(0xFFD700FF) },
+ { "GOLDENROD", Color::hex(0xDAA520FF) },
+ { "GRAY", Color::hex(0xBEBEBEFF) },
+ { "GREEN", Color::hex(0x00FF00FF) },
+ { "GREEN_YELLOW", Color::hex(0xADFF2FFF) },
+ { "HONEYDEW", Color::hex(0xF0FFF0FF) },
+ { "HOT_PINK", Color::hex(0xFF69B4FF) },
+ { "INDIAN_RED", Color::hex(0xCD5C5CFF) },
+ { "INDIGO", Color::hex(0x4B0082FF) },
+ { "IVORY", Color::hex(0xFFFFF0FF) },
+ { "KHAKI", Color::hex(0xF0E68CFF) },
+ { "LAVENDER", Color::hex(0xE6E6FAFF) },
+ { "LAVENDER_BLUSH", Color::hex(0xFFF0F5FF) },
+ { "LAWN_GREEN", Color::hex(0x7CFC00FF) },
+ { "LEMON_CHIFFON", Color::hex(0xFFFACDFF) },
+ { "LIGHT_BLUE", Color::hex(0xADD8E6FF) },
+ { "LIGHT_CORAL", Color::hex(0xF08080FF) },
+ { "LIGHT_CYAN", Color::hex(0xE0FFFFFF) },
+ { "LIGHT_GOLDENROD", Color::hex(0xFAFAD2FF) },
+ { "LIGHT_GRAY", Color::hex(0xD3D3D3FF) },
+ { "LIGHT_GREEN", Color::hex(0x90EE90FF) },
+ { "LIGHT_PINK", Color::hex(0xFFB6C1FF) },
+ { "LIGHT_SALMON", Color::hex(0xFFA07AFF) },
+ { "LIGHT_SEA_GREEN", Color::hex(0x20B2AAFF) },
+ { "LIGHT_SKY_BLUE", Color::hex(0x87CEFAFF) },
+ { "LIGHT_SLATE_GRAY", Color::hex(0x778899FF) },
+ { "LIGHT_STEEL_BLUE", Color::hex(0xB0C4DEFF) },
+ { "LIGHT_YELLOW", Color::hex(0xFFFFE0FF) },
+ { "LIME", Color::hex(0x00FF00FF) },
+ { "LIME_GREEN", Color::hex(0x32CD32FF) },
+ { "LINEN", Color::hex(0xFAF0E6FF) },
+ { "MAGENTA", Color::hex(0xFF00FFFF) },
+ { "MAROON", Color::hex(0xB03060FF) },
+ { "MEDIUM_AQUAMARINE", Color::hex(0x66CDAAFF) },
+ { "MEDIUM_BLUE", Color::hex(0x0000CDFF) },
+ { "MEDIUM_ORCHID", Color::hex(0xBA55D3FF) },
+ { "MEDIUM_PURPLE", Color::hex(0x9370DBFF) },
+ { "MEDIUM_SEA_GREEN", Color::hex(0x3CB371FF) },
+ { "MEDIUM_SLATE_BLUE", Color::hex(0x7B68EEFF) },
+ { "MEDIUM_SPRING_GREEN", Color::hex(0x00FA9AFF) },
+ { "MEDIUM_TURQUOISE", Color::hex(0x48D1CCFF) },
+ { "MEDIUM_VIOLET_RED", Color::hex(0xC71585FF) },
+ { "MIDNIGHT_BLUE", Color::hex(0x191970FF) },
+ { "MINT_CREAM", Color::hex(0xF5FFFAFF) },
+ { "MISTY_ROSE", Color::hex(0xFFE4E1FF) },
+ { "MOCCASIN", Color::hex(0xFFE4B5FF) },
+ { "NAVAJO_WHITE", Color::hex(0xFFDEADFF) },
+ { "NAVY_BLUE", Color::hex(0x000080FF) },
+ { "OLD_LACE", Color::hex(0xFDF5E6FF) },
+ { "OLIVE", Color::hex(0x808000FF) },
+ { "OLIVE_DRAB", Color::hex(0x6B8E23FF) },
+ { "ORANGE", Color::hex(0xFFA500FF) },
+ { "ORANGE_RED", Color::hex(0xFF4500FF) },
+ { "ORCHID", Color::hex(0xDA70D6FF) },
+ { "PALE_GOLDENROD", Color::hex(0xEEE8AAFF) },
+ { "PALE_GREEN", Color::hex(0x98FB98FF) },
+ { "PALE_TURQUOISE", Color::hex(0xAFEEEEFF) },
+ { "PALE_VIOLET_RED", Color::hex(0xDB7093FF) },
+ { "PAPAYA_WHIP", Color::hex(0xFFEFD5FF) },
+ { "PEACH_PUFF", Color::hex(0xFFDAB9FF) },
+ { "PERU", Color::hex(0xCD853FFF) },
+ { "PINK", Color::hex(0xFFC0CBFF) },
+ { "PLUM", Color::hex(0xDDA0DDFF) },
+ { "POWDER_BLUE", Color::hex(0xB0E0E6FF) },
+ { "PURPLE", Color::hex(0xA020F0FF) },
+ { "REBECCA_PURPLE", Color::hex(0x663399FF) },
+ { "RED", Color::hex(0xFF0000FF) },
+ { "ROSY_BROWN", Color::hex(0xBC8F8FFF) },
+ { "ROYAL_BLUE", Color::hex(0x4169E1FF) },
+ { "SADDLE_BROWN", Color::hex(0x8B4513FF) },
+ { "SALMON", Color::hex(0xFA8072FF) },
+ { "SANDY_BROWN", Color::hex(0xF4A460FF) },
+ { "SEA_GREEN", Color::hex(0x2E8B57FF) },
+ { "SEASHELL", Color::hex(0xFFF5EEFF) },
+ { "SIENNA", Color::hex(0xA0522DFF) },
+ { "SILVER", Color::hex(0xC0C0C0FF) },
+ { "SKY_BLUE", Color::hex(0x87CEEBFF) },
+ { "SLATE_BLUE", Color::hex(0x6A5ACDFF) },
+ { "SLATE_GRAY", Color::hex(0x708090FF) },
+ { "SNOW", Color::hex(0xFFFAFAFF) },
+ { "SPRING_GREEN", Color::hex(0x00FF7FFF) },
+ { "STEEL_BLUE", Color::hex(0x4682B4FF) },
+ { "TAN", Color::hex(0xD2B48CFF) },
+ { "TEAL", Color::hex(0x008080FF) },
+ { "THISTLE", Color::hex(0xD8BFD8FF) },
+ { "TOMATO", Color::hex(0xFF6347FF) },
+ { "TRANSPARENT", Color::hex(0xFFFFFF00) },
+ { "TURQUOISE", Color::hex(0x40E0D0FF) },
+ { "VIOLET", Color::hex(0xEE82EEFF) },
+ { "WEB_GRAY", Color::hex(0x808080FF) },
+ { "WEB_GREEN", Color::hex(0x008000FF) },
+ { "WEB_MAROON", Color::hex(0x800000FF) },
+ { "WEB_PURPLE", Color::hex(0x800080FF) },
+ { "WHEAT", Color::hex(0xF5DEB3FF) },
+ { "WHITE", Color::hex(0xFFFFFFFF) },
+ { "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
+ { "YELLOW", Color::hex(0xFFFF00FF) },
+ { "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
{ nullptr, Color() },
};
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 0ddac9744e..9dd1257474 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -1440,7 +1440,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}
Callable::CallError ce;
- base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
+ base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index 9c968df19b..5bc1bc25e6 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -42,7 +42,7 @@ int Face3::split_by_plane(const Plane &p_plane, Face3 p_res[3], bool p_is_point_
int below_count = 0;
for (int i = 0; i < 3; i++) {
- if (p_plane.has_point(vertex[i], CMP_EPSILON)) { // point is in plane
+ if (p_plane.has_point(vertex[i], (real_t)CMP_EPSILON)) { // point is in plane
ERR_FAIL_COND_V(above_count >= 4, 0);
above[above_count++] = vertex[i];
@@ -117,7 +117,7 @@ bool Face3::intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vect
bool Face3::is_degenerate() const {
Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]);
- return (normal.length_squared() < CMP_EPSILON2);
+ return (normal.length_squared() < (real_t)CMP_EPSILON2);
}
Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const {
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index b1af91c49c..46b7d99b43 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -218,10 +218,10 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath_a.size(); ++i) {
- path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR);
+ path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR);
}
for (int i = 0; i != p_polypath_b.size(); ++i) {
- path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR);
+ path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR);
}
Clipper clp;
clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0.
@@ -246,8 +246,8 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
}
polypaths.push_back(polypath);
}
@@ -290,17 +290,17 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
et = etOpenRound;
break;
}
- ClipperOffset co(2.0, 0.25f * SCALE_FACTOR); // Defaults from ClipperOffset.
+ ClipperOffset co(2.0, 0.25f * (real_t)SCALE_FACTOR); // Defaults from ClipperOffset.
Path path;
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath.size(); ++i) {
- path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR);
+ path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR);
}
co.AddPath(path, jt, et);
Paths paths;
- co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate.
+ co.Execute(paths, p_delta * (real_t)SCALE_FACTOR); // Inflate/deflate.
// Have to scale points down now.
Vector<Vector<Point2>> polypaths;
@@ -312,8 +312,8 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
}
polypaths.push_back(polypath);
}
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 4fdb8ee36a..62786d69be 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -51,20 +51,20 @@ public:
real_t f = d2.dot(r);
real_t s, t;
// Check if either or both segments degenerate into points.
- if (a <= CMP_EPSILON && e <= CMP_EPSILON) {
+ if (a <= (real_t)CMP_EPSILON && e <= (real_t)CMP_EPSILON) {
// Both segments degenerate into points.
c1 = p1;
c2 = p2;
return Math::sqrt((c1 - c2).dot(c1 - c2));
}
- if (a <= CMP_EPSILON) {
+ if (a <= (real_t)CMP_EPSILON) {
// First segment degenerates into a point.
s = 0.0;
t = f / e; // s = 0 => t = (b*s + f) / e = f / e
t = CLAMP(t, 0.0f, 1.0f);
} else {
real_t c = d1.dot(r);
- if (e <= CMP_EPSILON) {
+ if (e <= (real_t)CMP_EPSILON) {
// Second segment degenerates into a point.
t = 0.0;
s = CLAMP(-c / a, 0.0f, 1.0f); // t = 0 => s = (b*t - c) / a = -c / a
@@ -185,7 +185,7 @@ public:
D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y);
// Fail if C x B and D x B have the same sign (segments don't intersect).
- if ((C.y < -CMP_EPSILON && D.y < -CMP_EPSILON) || (C.y > CMP_EPSILON && D.y > CMP_EPSILON)) {
+ if ((C.y < (real_t)-CMP_EPSILON && D.y < (real_t)-CMP_EPSILON) || (C.y > (real_t)CMP_EPSILON && D.y > (real_t)CMP_EPSILON)) {
return false;
}
@@ -198,7 +198,7 @@ public:
real_t ABpos = D.x + (C.x - D.x) * D.y / (D.y - C.y);
// Fail if segment C-D crosses line A-B outside of segment A-B.
- if (ABpos < 0 || ABpos > 1.0f) {
+ if ((ABpos < 0) || (ABpos > 1)) {
return false;
}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 7eeb37df46..bd22bffb1f 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -879,7 +879,7 @@ Vector<Vector3> Geometry3D::compute_convex_mesh_points(const Plane *p_planes, in
for (int n = 0; n < p_plane_count; n++) {
if (n != i && n != j && n != k) {
real_t dp = p_planes[n].normal.dot(convex_shape_point);
- if (dp - p_planes[n].d > CMP_EPSILON) {
+ if (dp - p_planes[n].d > (real_t)CMP_EPSILON) {
excluded = true;
break;
}
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 482c7ea604..59c56906f4 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -76,7 +76,7 @@ public:
real_t tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
// Compute the line parameters of the two closest points.
- if (D < CMP_EPSILON) { // The lines are almost parallel.
+ if (D < (real_t)CMP_EPSILON) { // The lines are almost parallel.
sN = 0.0f; // Force using point P0 on segment S1
sD = 1.0f; // to prevent possible division by 0.0 later.
tN = e;
@@ -142,7 +142,7 @@ public:
Vector3 s = p_from - p_v0;
real_t u = f * s.dot(h);
- if (u < 0.0f || u > 1.0f) {
+ if ((u < 0.0f) || (u > 1.0f)) {
return false;
}
@@ -150,7 +150,7 @@ public:
real_t v = f * p_dir.dot(q);
- if (v < 0.0f || u + v > 1.0f) {
+ if ((v < 0.0f) || (u + v > 1.0f)) {
return false;
}
@@ -183,7 +183,7 @@ public:
Vector3 s = p_from - p_v0;
real_t u = f * s.dot(h);
- if (u < 0.0f || u > 1.0f) {
+ if ((u < 0.0f) || (u > 1.0f)) {
return false;
}
@@ -191,7 +191,7 @@ public:
real_t v = f * rel.dot(q);
- if (v < 0.0f || u + v > 1.0f) {
+ if ((v < 0.0f) || (u + v > 1.0f)) {
return false;
}
@@ -199,7 +199,7 @@ public:
// the intersection point is on the line.
real_t t = f * e2.dot(q);
- if (t > CMP_EPSILON && t <= 1.0f) { // Ray intersection.
+ if (t > (real_t)CMP_EPSILON && t <= 1.0f) { // Ray intersection.
if (r_res) {
*r_res = p_from + rel * t;
}
@@ -213,7 +213,7 @@ public:
Vector3 sphere_pos = p_sphere_pos - p_from;
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false; // Both points are the same.
}
Vector3 normal = rel / rel_l;
@@ -229,7 +229,7 @@ public:
real_t inters_d2 = p_sphere_radius * p_sphere_radius - ray_distance * ray_distance;
real_t inters_d = sphere_d;
- if (inters_d2 >= CMP_EPSILON) {
+ if (inters_d2 >= (real_t)CMP_EPSILON) {
inters_d -= Math::sqrt(inters_d2);
}
@@ -253,7 +253,7 @@ public:
static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr, int p_cylinder_axis = 2) {
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false; // Both points are the same.
}
@@ -269,7 +269,7 @@ public:
Vector3 axis_dir;
- if (crs_l < CMP_EPSILON) {
+ if (crs_l < (real_t)CMP_EPSILON) {
Vector3 side_axis;
side_axis[(p_cylinder_axis + 1) % 3] = 1.0f; // Any side axis OK.
axis_dir = side_axis;
@@ -285,7 +285,7 @@ public:
// Convert to 2D.
real_t w2 = p_radius * p_radius - dist * dist;
- if (w2 < CMP_EPSILON) {
+ if (w2 < (real_t)CMP_EPSILON) {
return false; // Avoid numerical error.
}
Size2 size(Math::sqrt(w2), p_height * 0.5f);
@@ -366,7 +366,7 @@ public:
Vector3 rel = p_to - p_from;
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false;
}
@@ -379,7 +379,7 @@ public:
real_t den = p.normal.dot(dir);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::abs(den) <= (real_t)CMP_EPSILON) {
continue; // Ignore parallel plane.
}
@@ -564,11 +564,11 @@ public:
for (int a = 0; a < polygon.size(); a++) {
real_t dist = p_plane.distance_to(polygon[a]);
- if (dist < -CMP_POINT_IN_PLANE_EPSILON) {
+ if (dist < (real_t)-CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_INSIDE;
inside_count++;
} else {
- if (dist > CMP_POINT_IN_PLANE_EPSILON) {
+ if (dist > (real_t)CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_OUTSIDE;
outside_count++;
} else {
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 47e5ab2709..44340b97ae 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -64,7 +64,7 @@ public:
static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
- static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc(Math_PI * p_x); }
+ static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc((float)Math_PI * p_x); }
static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
@@ -187,7 +187,7 @@ public:
static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) {
double value = Math::fmod(p_x, p_y);
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0;
@@ -195,7 +195,7 @@ public:
}
static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) {
float value = Math::fmod(p_x, p_y);
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0f;
@@ -220,17 +220,17 @@ public:
static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) {
int64_t value = p_x % p_y;
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
return value;
}
static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * (Math_PI / 180.0); }
- static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * (180.0 / Math_PI); }
- static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; }
@@ -285,10 +285,10 @@ public:
static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
@@ -322,7 +322,7 @@ public:
// double only, as these functions are mainly used by the editor and not performance-critical,
static double ease(double p_x, double p_c);
static int step_decimals(double p_step);
- static int range_step_decimals(double p_step);
+ static int range_step_decimals(double p_step); // For editor use only.
static double snapped(double p_value, double p_step);
static uint32_t larger_prime(uint32_t p_val);
@@ -345,9 +345,9 @@ public:
return true;
}
// Then check for approximate equality.
- float tolerance = CMP_EPSILON * abs(a);
- if (tolerance < CMP_EPSILON) {
- tolerance = CMP_EPSILON;
+ float tolerance = (float)CMP_EPSILON * abs(a);
+ if (tolerance < (float)CMP_EPSILON) {
+ tolerance = (float)CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
@@ -362,7 +362,7 @@ public:
}
static _ALWAYS_INLINE_ bool is_zero_approx(float s) {
- return abs(s) < CMP_EPSILON;
+ return abs(s) < (float)CMP_EPSILON;
}
static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 0ce8aed51c..6881ad4014 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -106,7 +106,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t dist = (normal.dot(p_from) - d) / den;
//printf("dist is %i\n",dist);
- if (dist > CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
+ if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
return false;
}
@@ -129,7 +129,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t dist = (normal.dot(p_begin) - d) / den;
//printf("dist is %i\n",dist);
- if (dist < -CMP_EPSILON || dist > (1.0f + CMP_EPSILON)) {
+ if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) {
return false;
}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index ade252d628..11bfcc1a6f 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -102,6 +102,22 @@ Quaternion Quaternion::inverse() const {
return Quaternion(-x, -y, -z, w);
}
+Quaternion Quaternion::log() const {
+ Quaternion src = *this;
+ Vector3 src_v = src.get_axis() * src.get_angle();
+ return Quaternion(src_v.x, src_v.y, src_v.z, 0);
+}
+
+Quaternion Quaternion::exp() const {
+ Quaternion src = *this;
+ Vector3 src_v = Vector3(src.x, src.y, src.z);
+ float theta = src_v.length();
+ if (theta < CMP_EPSILON) {
+ return Quaternion(0, 0, 0, 1);
+ }
+ return Quaternion(src_v.normalized(), theta);
+}
+
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
@@ -129,7 +145,7 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con
// calculate coefficients
- if ((1.0f - cosom) > CMP_EPSILON) {
+ if ((1.0f - cosom) > (real_t)CMP_EPSILON) {
// standard case (slerp)
omega = Math::acos(cosom);
sinom = Math::sin(omega);
@@ -190,6 +206,9 @@ Quaternion::operator String() const {
}
Vector3 Quaternion::get_axis() const {
+ if (Math::abs(w) > 1 - CMP_EPSILON) {
+ return Vector3(x, y, z);
+ }
real_t r = ((real_t)1) / Math::sqrt(1 - w * w);
return Vector3(x * r, y * r, z * r);
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index f8a2c6456e..9801746659 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -60,6 +60,8 @@ struct _NO_DISCARD_ Quaternion {
Quaternion normalized() const;
bool is_normalized() const;
Quaternion inverse() const;
+ Quaternion log() const;
+ Quaternion exp() const;
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
@@ -145,7 +147,7 @@ struct _NO_DISCARD_ Quaternion {
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
- if (d < -1.0f + CMP_EPSILON) {
+ if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
y = 1;
z = 0;
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 974dbbfc2e..65fcf67664 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -129,7 +129,7 @@ public:
return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(randd()))); // Box-Muller transform
}
_FORCE_INLINE_ float randfn(float p_mean, float p_deviation) {
- return p_mean + p_deviation * (cos(Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
+ return p_mean + p_deviation * (cos((float)Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
}
double random(double p_from, double p_to);
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 55c1f06ff5..71953e4130 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -71,12 +71,12 @@ void Transform2D::rotate(const real_t p_phi) {
real_t Transform2D::get_skew() const {
real_t det = basis_determinant();
- return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - Math_PI * 0.5f;
+ return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - (real_t)Math_PI * 0.5f;
}
void Transform2D::set_skew(const real_t p_angle) {
real_t det = basis_determinant();
- elements[1] = SIGN(det) * elements[0].rotated((Math_PI * 0.5f + p_angle)).normalized() * elements[1].length();
+ elements[1] = SIGN(det) * elements[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * elements[1].length();
}
real_t Transform2D::get_rotation() const {
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index ed4266b115..a27227905c 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -163,7 +163,7 @@ Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const {
Vector2 v = *this;
Vector2 vd = p_to - v;
real_t len = vd.length();
- return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+ return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
// slide returns the component of the vector along the given plane, specified by its normal vector.
diff --git a/core/math/vector2.h b/core/math/vector2.h
index a2680b84fc..bd67299f33 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -31,6 +31,7 @@
#ifndef VECTOR2_H
#define VECTOR2_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
class String;
@@ -60,9 +61,11 @@ struct _NO_DISCARD_ Vector2 {
};
_FORCE_INLINE_ real_t &operator[](int p_idx) {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 3f5f12d4dd..13b70031bd 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -31,6 +31,7 @@
#ifndef VECTOR2I_H
#define VECTOR2I_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
class String;
@@ -58,9 +59,11 @@ struct _NO_DISCARD_ Vector2i {
};
_FORCE_INLINE_ int32_t &operator[](int p_idx) {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ const int32_t &operator[](int p_idx) const {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 9b3902346e..87b2ac7104 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -97,7 +97,7 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const {
Vector3 v = *this;
Vector3 vd = p_to - v;
real_t len = vd.length();
- return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+ return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
Vector2 Vector3::octahedron_encode() const {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 89b0095741..b22ebeaf0a 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -59,10 +59,12 @@ struct _NO_DISCARD_ Vector3 {
};
_FORCE_INLINE_ const real_t &operator[](const int p_axis) const {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
_FORCE_INLINE_ real_t &operator[](const int p_axis) {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 2a4c7e2e97..b49c1142ed 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -31,6 +31,7 @@
#ifndef VECTOR3I_H
#define VECTOR3I_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
class String;
@@ -54,10 +55,12 @@ struct _NO_DISCARD_ Vector3i {
};
_FORCE_INLINE_ const int32_t &operator[](const int p_axis) const {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
_FORCE_INLINE_ int32_t &operator[](const int p_axis) {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index c29316c089..e09c6cb97c 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -557,6 +557,19 @@ bool ClassDB::can_instantiate(const StringName &p_class) {
return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance));
}
+bool ClassDB::is_virtual(const StringName &p_class) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *ti = classes.getptr(p_class);
+ ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+#ifdef TOOLS_ENABLED
+ if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
+ return false;
+ }
+#endif
+ return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance) && ti->is_virtual);
+}
+
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
OBJTYPE_WLOCK;
@@ -1197,7 +1210,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
if (psg->_setptr) {
psg->_setptr->call(p_object, arg, 2, ce);
} else {
- p_object->call(psg->setter, arg, 2, ce);
+ p_object->callp(psg->setter, arg, 2, ce);
}
} else {
@@ -1205,7 +1218,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
if (psg->_setptr) {
psg->_setptr->call(p_object, arg, 1, ce);
} else {
- p_object->call(psg->setter, arg, 1, ce);
+ p_object->callp(psg->setter, arg, 1, ce);
}
}
@@ -1238,14 +1251,14 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia
Variant index = psg->index;
const Variant *arg[1] = { &index };
Callable::CallError ce;
- r_value = p_object->call(psg->getter, arg, 1, ce);
+ r_value = p_object->callp(psg->getter, arg, 1, ce);
} else {
Callable::CallError ce;
if (psg->_getptr) {
r_value = psg->_getptr->call(p_object, nullptr, 0, ce);
} else {
- r_value = p_object->call(psg->getter, nullptr, 0, ce);
+ r_value = p_object->callp(psg->getter, nullptr, 0, ce);
}
}
return true;
@@ -1593,7 +1606,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
if (Engine::get_singleton()->has_singleton(p_class)) {
c = Engine::get_singleton()->get_singleton_object(p_class);
cleanup_c = false;
- } else if (ClassDB::can_instantiate(p_class)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
@@ -1681,6 +1694,30 @@ void ClassDB::unregister_extension_class(const StringName &p_class) {
classes.erase(p_class);
}
+Map<StringName, ClassDB::NativeStruct> ClassDB::native_structs;
+void ClassDB::register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size) {
+ NativeStruct ns;
+ ns.ccode = p_code;
+ ns.struct_size = p_current_size;
+ native_structs[p_name] = ns;
+}
+
+void ClassDB::get_native_struct_list(List<StringName> *r_names) {
+ for (const KeyValue<StringName, NativeStruct> &E : native_structs) {
+ r_names->push_back(E.key);
+ }
+}
+
+String ClassDB::get_native_struct_code(const StringName &p_name) {
+ ERR_FAIL_COND_V(!native_structs.has(p_name), String());
+ return native_structs[p_name].ccode;
+}
+
+uint64_t ClassDB::get_native_struct_size(const StringName &p_name) {
+ ERR_FAIL_COND_V(!native_structs.has(p_name), 0);
+ return native_structs[p_name].struct_size;
+}
+
RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {
@@ -1704,6 +1741,7 @@ void ClassDB::cleanup() {
classes.clear();
resource_base_extensions.clear();
compat_classes.clear();
+ native_structs.clear();
}
//
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 5d258a29bf..32e4bf7644 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -118,6 +118,7 @@ public:
StringName name;
bool disabled = false;
bool exposed = false;
+ bool is_virtual = false;
Object *(*creation_func)() = nullptr;
ClassInfo() {}
@@ -143,6 +144,13 @@ public:
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static Set<StringName> default_values_cached;
+ // Native structs, used by binder
+ struct NativeStruct {
+ String ccode; // C code to create the native struct, fields separated by ; Arrays accepted (even containing other structs), also function pointers. All types must be Godot types.
+ uint64_t struct_size; // local size of struct, for comparison
+ };
+ static Map<StringName, NativeStruct> native_structs;
+
private:
// Non-locking variants of get_parent_class and is_parent_class.
static StringName _get_parent_class(const StringName &p_class);
@@ -156,20 +164,21 @@ public:
}
template <class T>
- static void register_class() {
+ static void register_class(bool p_virtual = false) {
GLOBAL_LOCK_FUNCTION;
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_COND(!t);
t->creation_func = &creator<T>;
t->exposed = true;
+ t->is_virtual = p_virtual;
t->class_ptr = T::get_class_ptr_static();
t->api = current_api;
T::register_custom_data_to_otdb();
}
template <class T>
- static void register_virtual_class() {
+ static void register_abstract_class() {
GLOBAL_LOCK_FUNCTION;
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@@ -210,6 +219,7 @@ public:
static bool class_exists(const StringName &p_class);
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
static bool can_instantiate(const StringName &p_class);
+ static bool is_virtual(const StringName &p_class);
static Object *instantiate(const StringName &p_class);
static void set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance);
@@ -387,6 +397,11 @@ public:
static APIType get_current_api();
static void cleanup_defaults();
static void cleanup();
+
+ static void register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size);
+ static void get_native_struct_list(List<StringName> *r_names);
+ static String get_native_struct_code(const StringName &p_name);
+ static uint64_t get_native_struct_size(const StringName &p_name); // Used for asserting
};
#ifdef DEBUG_METHODS_ENABLED
@@ -436,11 +451,17 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
::ClassDB::register_class<m_class>(); \
}
-#define GDREGISTER_VIRTUAL_CLASS(m_class) \
- if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
- ::ClassDB::register_virtual_class<m_class>(); \
+#define GDREGISTER_VIRTUAL_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ::ClassDB::register_class<m_class>(true); \
+ }
+#define GDREGISTER_ABSTRACT_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ::ClassDB::register_abstract_class<m_class>(); \
}
+#define GDREGISTER_NATIVE_STRUCT(m_class, m_code) ClassDB::register_native_struct(#m_class, m_code, sizeof(m_class))
+
#include "core/disabled_classes.gen.h"
#endif // CLASS_DB_H
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 5de1b49026..64ee5940b0 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -3,12 +3,13 @@ proto = """
StringName _gdvirtual_##m_name##_sn = #m_name;\\
mutable bool _gdvirtual_##m_name##_initialized = false;\\
mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
+template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
if (script_instance) {\\
Callable::CallError ce; \\
$CALLSIARGS\\
- $CALLSIBEGINscript_instance->call(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
+ $CALLSIBEGINscript_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
if (ce.error == Callable::CallError::CALL_OK) {\\
$CALLSIRET\\
return true;\\
@@ -25,6 +26,11 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
$CALLPTRRET\\
return true;\\
}\\
+ \\
+ if (required) {\\
+ ERR_PRINT_ONCE("Required virtual method: "+get_class()+"::" + #m_name + " must be overriden before calling.");\\
+ $RVOID\\
+ }\\
\\
return false;\\
}\\
@@ -61,10 +67,12 @@ def generate_version(argcount, const=False, returns=False):
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret, ")
+ s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
else:
s = s.replace("$RET", "")
+ s = s.replace("$RVOID", "")
s = s.replace("$CALLPTRRETDEF", "")
if const:
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index 3c828eabd9..79c36ac81f 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
+#include "core/object/class_db.h"
#include "core/object/script_language.h"
MessageQueue *MessageQueue::singleton = nullptr;
@@ -40,23 +41,8 @@ MessageQueue *MessageQueue::get_singleton() {
return singleton;
}
-Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
- return push_callable(Callable(p_id, p_method), p_args, p_argcount, p_show_error);
-}
-
-Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return push_call(p_id, p_method, argptr, argc, false);
+Error MessageQueue::push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
+ return push_callablep(Callable(p_id, p_method), p_args, p_argcount, p_show_error);
}
Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value) {
@@ -113,8 +99,8 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
return OK;
}
-Error MessageQueue::push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- return push_call(p_object->get_instance_id(), p_method, VARIANT_ARG_PASS);
+Error MessageQueue::push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
+ return push_callp(p_object->get_instance_id(), p_method, p_args, p_argcount, p_show_error);
}
Error MessageQueue::push_notification(Object *p_object, int p_notification) {
@@ -125,7 +111,7 @@ Error MessageQueue::push_set(Object *p_object, const StringName &p_prop, const V
return push_set(p_object->get_instance_id(), p_prop, p_value);
}
-Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) {
+Error MessageQueue::push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) {
_THREAD_SAFE_METHOD_
int room_needed = sizeof(Message) + sizeof(Variant) * p_argcount;
@@ -155,21 +141,6 @@ Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_
return OK;
}
-Error MessageQueue::push_callable(const Callable &p_callable, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return push_callable(p_callable, argptr, argc);
-}
-
void MessageQueue::statistics() {
Map<StringName, int> set_count;
Map<int, int> notify_count;
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index a4449cf473..eaab01d0aa 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -31,8 +31,11 @@
#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H
-#include "core/object/class_db.h"
+#include "core/object/object_id.h"
#include "core/os/thread_safe.h"
+#include "core/variant/variant.h"
+
+class Object;
class MessageQueue {
_THREAD_SAFE_CLASS_
@@ -73,14 +76,42 @@ class MessageQueue {
public:
static MessageQueue *get_singleton();
- Error push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
- Error push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_LIST);
+ Error push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ template <typename... VarArgs>
+ Error push_call(ObjectID p_id, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callp(p_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
Error push_notification(ObjectID p_id, int p_notification);
Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value);
- Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
- Error push_callable(const Callable &p_callable, VARIANT_ARG_LIST);
+ Error push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
+
+ template <typename... VarArgs>
+ Error push_callable(const Callable &p_callable, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callablep(p_callable, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ Error push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ template <typename... VarArgs>
+ Error push_call(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
- Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
Error push_notification(Object *p_object, int p_notification);
Error push_set(Object *p_object, const StringName &p_prop, const Variant &p_value);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index a8a49bd22e..096edd4e60 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -624,8 +624,12 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (_extension) {
- p_list->push_back(PropertyInfo(Variant::NIL, _extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
- ClassDB::get_property_list(_extension->class_name, p_list, true, this);
+ const ObjectNativeExtension *current_extension = _extension;
+ while (current_extension) {
+ p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
+ ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
+ current_extension = current_extension->parent;
+ }
}
if (_extension && _extension->get_property_list) {
@@ -679,7 +683,7 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal
StringName method = *p_args[0];
- return call(method, &p_args[1], p_argcount - 1, r_error);
+ return callp(method, &p_args[1], p_argcount - 1, r_error);
}
Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -700,7 +704,7 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call
StringName method = *p_args[0];
- MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
+ MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
return Variant();
}
@@ -750,31 +754,14 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) {
}
Callable::CallError ce;
- Variant ret = call(p_method, argptrs, p_args.size(), ce);
+ Variant ret = callp(p_method, argptrs, p_args.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + ".");
}
return ret;
}
-Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
-
- Variant ret = call(p_name, argptr, argc, error);
- return ret;
-}
-
-Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
if (p_method == CoreStringNames::get_singleton()->_free) {
@@ -808,7 +795,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
OBJ_DEBUG_LOCK
if (script_instance) {
- ret = script_instance->call(p_method, p_args, p_argcount, r_error);
+ ret = script_instance->callp(p_method, p_args, p_argcount, r_error);
//force jumptable
switch (r_error.error) {
case Callable::CallError::CALL_OK:
@@ -1027,12 +1014,12 @@ Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::C
args = &p_args[1];
}
- emit_signal(signal, args, argc);
+ emit_signalp(signal, args, argc);
return Variant();
}
-Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount) {
+Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
if (_block_signals) {
return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked
}
@@ -1091,7 +1078,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
}
if (c.flags & CONNECT_DEFERRED) {
- MessageQueue::get_singleton()->push_callable(c.callable, args, argc, true);
+ MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
} else {
Callable::CallError ce;
_emitting = true;
@@ -1139,21 +1126,6 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
return err;
}
-Error Object::emit_signal(const StringName &p_name, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return emit_signal(p_name, argptr, argc);
-}
-
void Object::_add_user_signal(const String &p_name, const Array &p_args) {
// this version of add_user_signal is meant to be used from scripts or external apis
// without access to ADD_SIGNAL in bind_methods
@@ -1648,10 +1620,6 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
-void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) {
- MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS);
-}
-
void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
MessageQueue::get_singleton()->push_set(this, p_property, p_value);
}
diff --git a/core/object/object.h b/core/object/object.h
index b5be1cf0e7..6b4f1c81e6 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -32,6 +32,7 @@
#define OBJECT_H
#include "core/extension/gdnative_interface.h"
+#include "core/object/message_queue.h"
#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
#include "core/os/spin_lock.h"
@@ -44,14 +45,6 @@
#include "core/variant/callable_bind.h"
#include "core/variant/variant.h"
-#define VARIANT_ARG_LIST const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant()
-#define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5, p_arg6, p_arg7, p_arg8
-#define VARIANT_ARG_DECLARE const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8
-#define VARIANT_ARG_MAX 8
-#define VARIANT_ARGPTRS const Variant *argptr[8] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5, &p_arg6, &p_arg7, &p_arg8 };
-#define VARIANT_ARGPTRS_PASS *argptr[0], *argptr[1], *argptr[2], *argptr[3], *argptr[4], *argptr[5], *argptr[6]], *argptr[7]
-#define VARIANT_ARGS_FROM_ARRAY(m_arr) m_arr[0], m_arr[1], m_arr[2], m_arr[3], m_arr[4], m_arr[5], m_arr[6], m_arr[7]
-
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range.
@@ -95,6 +88,7 @@ enum PropertyHint {
PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
PROPERTY_HINT_LOCALE_ID,
+ PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -262,6 +256,7 @@ struct ObjectNativeExtension {
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
GDNativeExtensionClassReference unreference;
+ GDNativeExtensionClassGetRID get_rid;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
const ObjectNativeExtension *e = this;
@@ -280,8 +275,12 @@ struct ObjectNativeExtension {
GDNativeExtensionClassGetVirtual get_virtual;
};
-#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
-#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call(__VA_ARGS__)
+#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
+#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__)
+
+#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__)
+#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__)
+
#ifdef DEBUG_METHODS_ENABLED
#define GDVIRTUAL_BIND(m_name, ...) ::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), true, sarray(__VA_ARGS__));
#else
@@ -734,8 +733,18 @@ public:
bool has_method(const StringName &p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName &p_method, const Array &p_args);
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
+ }
void notification(int p_notification, bool p_reversed = false);
virtual String to_string();
@@ -769,8 +778,18 @@ public:
void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance);
void add_user_signal(const MethodInfo &p_signal);
- Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST);
- Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ Error emit_signal(const StringName &p_name, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
bool has_signal(const StringName &p_name) const;
void get_signal_list(List<MethodInfo> *p_signals) const;
void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
@@ -782,7 +801,11 @@ public:
void disconnect(const StringName &p_signal, const Callable &p_callable);
bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
- void call_deferred(const StringName &p_method, VARIANT_ARG_LIST);
+ template <typename... VarArgs>
+ void call_deferred(const StringName &p_name, VarArgs... p_args) {
+ MessageQueue::get_singleton()->push_call(this, p_name, p_args...);
+ }
+
void set_deferred(const StringName &p_property, const Variant &p_value);
void set_block_signals(bool p_block);
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index b14296b815..11440c37fe 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -310,20 +310,6 @@ void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state)
}
}
-Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
- return call(p_method, argptr, argc, error);
-}
-
void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) {
if (r_valid) {
*r_valid = false;
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 4b18d9a5e8..2122f785b6 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -176,8 +176,20 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const = 0;
virtual bool has_method(const StringName &p_method) const = 0;
- virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST);
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
+ }
+
virtual void notification(int p_notification) = 0;
virtual String to_string(bool *r_valid) {
if (r_valid) {
@@ -419,8 +431,8 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
- virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); }
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index f72dec8edf..ee8eb97a93 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -34,6 +34,20 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+void UndoRedo::Operation::delete_reference() {
+ if (type != Operation::TYPE_REFERENCE) {
+ return;
+ }
+ if (ref.is_valid()) {
+ ref.unref();
+ } else {
+ Object *obj = ObjectDB::get_instance(object);
+ if (obj) {
+ memdelete(obj);
+ }
+ }
+}
+
void UndoRedo::_discard_redo() {
if (current_action == actions.size() - 1) {
return;
@@ -41,16 +55,7 @@ void UndoRedo::_discard_redo() {
for (int i = current_action + 1; i < actions.size(); i++) {
for (Operation &E : actions.write[i].do_ops) {
- if (E.type == Operation::TYPE_REFERENCE) {
- if (E.ref.is_valid()) {
- E.ref.unref();
- } else {
- Object *obj = ObjectDB::get_instance(E.object);
- if (obj) {
- memdelete(obj);
- }
- }
- }
+ E.delete_reference();
}
//ERASE do data
}
@@ -97,13 +102,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
for (unsigned int i = 0; i < to_remove.size(); i++) {
List<Operation>::Element *E = to_remove[i];
// Delete all object references
- if (E->get().type == Operation::TYPE_REFERENCE) {
- Object *obj = ObjectDB::get_instance(E->get().object);
-
- if (obj) {
- memdelete(obj);
- }
- }
+ E->get().delete_reference();
E->erase();
}
}
@@ -127,8 +126,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
force_keep_in_merge_ends = false;
}
-void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS
+void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -141,14 +139,13 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA
do_op.type = Operation::TYPE_METHOD;
do_op.name = p_method;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- do_op.args[i] = *argptr[i];
+ for (int i = 0; i < p_argcount; i++) {
+ do_op.args.push_back(*p_args[i]);
}
actions.write[current_action + 1].do_ops.push_back(do_op);
}
-void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS
+void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -168,8 +165,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_method;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- undo_op.args[i] = *argptr[i];
+ for (int i = 0; i < p_argcount; i++) {
+ undo_op.args.push_back(*p_args[i]);
}
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -186,7 +183,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
do_op.type = Operation::TYPE_PROPERTY;
do_op.name = p_property;
- do_op.args[0] = p_value;
+ do_op.args.push_back(p_value);
actions.write[current_action + 1].do_ops.push_back(do_op);
}
@@ -209,7 +206,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
undo_op.type = Operation::TYPE_PROPERTY;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_property;
- undo_op.args[0] = p_value;
+ undo_op.args.push_back(p_value);
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -270,16 +267,7 @@ void UndoRedo::_pop_history_tail() {
}
for (Operation &E : actions.write[0].undo_ops) {
- if (E.type == Operation::TYPE_REFERENCE) {
- if (E.ref.is_valid()) {
- E.ref.unref();
- } else {
- Object *obj = ObjectDB::get_instance(E.object);
- if (obj) {
- memdelete(obj);
- }
- }
- }
+ E.delete_reference();
}
actions.remove_at(0);
@@ -324,23 +312,18 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
switch (op.type) {
case Operation::TYPE_METHOD: {
+ int argc = op.args.size();
Vector<const Variant *> argptrs;
- argptrs.resize(VARIANT_ARG_MAX);
- int argc = 0;
+ argptrs.resize(argc);
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (op.args[i].get_type() == Variant::NIL) {
- break;
- }
+ for (int i = 0; i < argc; i++) {
argptrs.write[i] = &op.args[i];
- argc++;
}
- argptrs.resize(argc);
Callable::CallError ce;
- obj->call(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+ obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT("Error calling method from signal '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+ ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
}
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
@@ -351,7 +334,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
#endif
if (method_callback) {
- method_callback(method_callbck_ud, obj, op.name, VARIANT_ARGS_FROM_ARRAY(op.args));
+ method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
}
} break;
case Operation::TYPE_PROPERTY: {
@@ -449,7 +432,7 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback, void
void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback, void *p_ud) {
method_callback = p_method_callback;
- method_callbck_ud = p_ud;
+ method_callback_ud = p_ud;
}
void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback, void *p_ud) {
@@ -487,14 +470,7 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callabl
Object *object = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) {
- v[i] = *p_args[i + 2];
- }
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- add_do_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ add_do_methodp(object, method, p_args + 2, p_argcount - 2);
return Variant();
}
@@ -524,14 +500,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla
Object *object = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) {
- v[i] = *p_args[i + 2];
- }
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- add_undo_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
return Variant();
}
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 75639f8abf..ecd7a21167 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -49,7 +49,7 @@ public:
Variant _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, VARIANT_ARG_DECLARE);
+ typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
private:
@@ -65,7 +65,9 @@ private:
Ref<RefCounted> ref;
ObjectID object;
StringName name;
- Variant args[VARIANT_ARG_MAX];
+ Vector<Variant> args;
+
+ void delete_reference();
};
struct Action {
@@ -90,7 +92,7 @@ private:
CommitNotifyCallback callback = nullptr;
void *callback_ud = nullptr;
- void *method_callbck_ud = nullptr;
+ void *method_callback_ud = nullptr;
void *prop_callback_ud = nullptr;
MethodNotifyCallback method_callback = nullptr;
@@ -104,8 +106,30 @@ protected:
public:
void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
- void add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
- void add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
+ void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+ void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+ template <typename... VarArgs>
+ void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_do_reference(Object *p_object);
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 9837b6e0aa..2e5db145a4 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -328,17 +328,13 @@ void OS::yield() {
void OS::ensure_user_data_dir() {
String dd = get_user_data_dir();
- DirAccess *da = DirAccess::open(dd);
- if (da) {
- memdelete(da);
+ if (DirAccess::exists(dd)) {
return;
}
- da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = da->make_dir_recursive(dd);
ERR_FAIL_COND_MSG(err != OK, "Error attempting to create data dir: " + dd + ".");
-
- memdelete(da);
}
String OS::get_model_name() const {
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index f80e8f4bb3..c8072b7280 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "platform_config.h"
#ifndef PLATFORM_THREAD_OVERRIDE // See details in thread.h
#include "thread.h"
diff --git a/core/os/thread.h b/core/os/thread.h
index f4e46059ad..3382dd81f9 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "platform_config.h"
// Define PLATFORM_THREAD_OVERRIDE in your platform's `platform_config.h`
// to use a custom Thread implementation defined in `platform/[your_platform]/platform_thread.h`
// Overriding the platform implementation is required in some proprietary platforms
diff --git a/core/os/time.cpp b/core/os/time.cpp
index 5eae94279a..e339805475 100644
--- a/core/os/time.cpp
+++ b/core/os/time.cpp
@@ -270,7 +270,7 @@ Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday
return dict;
}
-String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const {
+String Time::get_datetime_string_from_dict(const Dictionary p_datetime, bool p_use_space) const {
ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty.");
EXTRACT_FROM_DICTIONARY
// vformat only supports up to 6 arguments, so we need to split this up into 2 parts.
@@ -283,7 +283,7 @@ String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_spa
return timestamp;
}
-int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const {
+int64_t Time::get_unix_time_from_datetime_dict(const Dictionary p_datetime) const {
ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
EXTRACT_FROM_DICTIONARY
VALIDATE_YMDHMS
@@ -298,6 +298,21 @@ int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const {
return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
}
+String Time::get_offset_string_from_offset_minutes(int64_t p_offset_minutes) const {
+ String sign;
+ if (p_offset_minutes < 0) {
+ sign = "-";
+ p_offset_minutes = -p_offset_minutes;
+ } else {
+ sign = "+";
+ }
+ // These two lines can be optimized to one instruction on x86 and others.
+ // Note that % is acceptable here only because we ensure it's positive.
+ int64_t offset_hours = p_offset_minutes / 60;
+ int64_t offset_minutes = p_offset_minutes % 60;
+ return vformat("%s%02d:%02d", sign, offset_hours, offset_minutes);
+}
+
Dictionary Time::get_datetime_dict_from_system(bool p_utc) const {
OS::Date date = OS::get_singleton()->get_date(p_utc);
OS::Time time = OS::get_singleton()->get_time(p_utc);
@@ -389,6 +404,7 @@ void Time::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string);
+ ClassDB::bind_method(D_METHOD("get_offset_string_from_offset_minutes", "offset_minutes"), &Time::get_offset_string_from_offset_minutes);
ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false));
diff --git a/core/os/time.h b/core/os/time.h
index 3f00ba1478..0021c0ac6f 100644
--- a/core/os/time.h
+++ b/core/os/time.h
@@ -86,9 +86,10 @@ public:
String get_date_string_from_unix_time(int64_t p_unix_time_val) const;
String get_time_string_from_unix_time(int64_t p_unix_time_val) const;
Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const;
- String get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space = false) const;
- int64_t get_unix_time_from_datetime_dict(Dictionary p_datetime) const;
+ String get_datetime_string_from_dict(const Dictionary p_datetime, bool p_use_space = false) const;
+ int64_t get_unix_time_from_datetime_dict(const Dictionary p_datetime) const;
int64_t get_unix_time_from_datetime_string(String p_datetime) const;
+ String get_offset_string_from_offset_minutes(int64_t p_offset_minutes) const;
// Methods that get information from OS.
Dictionary get_datetime_dict_from_system(bool p_utc = false) const;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index a4b6a589f3..d05280f6a5 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -108,6 +108,8 @@ extern void unregister_global_constants();
static ResourceUID *resource_uid = nullptr;
+static bool _is_core_extensions_registered = false;
+
void register_core_types() {
//consistency check
static_assert(sizeof(Callable) <= 16);
@@ -139,7 +141,7 @@ void register_core_types() {
GDREGISTER_CLASS(Object);
- GDREGISTER_VIRTUAL_CLASS(Script);
+ GDREGISTER_ABSTRACT_CLASS(Script);
GDREGISTER_CLASS(RefCounted);
GDREGISTER_CLASS(WeakRef);
@@ -147,12 +149,12 @@ void register_core_types() {
GDREGISTER_CLASS(Image);
GDREGISTER_CLASS(Shortcut);
- GDREGISTER_VIRTUAL_CLASS(InputEvent);
- GDREGISTER_VIRTUAL_CLASS(InputEventWithModifiers);
- GDREGISTER_VIRTUAL_CLASS(InputEventFromWindow);
+ GDREGISTER_ABSTRACT_CLASS(InputEvent);
+ GDREGISTER_ABSTRACT_CLASS(InputEventWithModifiers);
+ GDREGISTER_ABSTRACT_CLASS(InputEventFromWindow);
GDREGISTER_CLASS(InputEventKey);
GDREGISTER_CLASS(InputEventShortcut);
- GDREGISTER_VIRTUAL_CLASS(InputEventMouse);
+ GDREGISTER_ABSTRACT_CLASS(InputEventMouse);
GDREGISTER_CLASS(InputEventMouseButton);
GDREGISTER_CLASS(InputEventMouseMotion);
GDREGISTER_CLASS(InputEventJoypadButton);
@@ -160,21 +162,21 @@ void register_core_types() {
GDREGISTER_CLASS(InputEventScreenDrag);
GDREGISTER_CLASS(InputEventScreenTouch);
GDREGISTER_CLASS(InputEventAction);
- GDREGISTER_VIRTUAL_CLASS(InputEventGesture);
+ GDREGISTER_ABSTRACT_CLASS(InputEventGesture);
GDREGISTER_CLASS(InputEventMagnifyGesture);
GDREGISTER_CLASS(InputEventPanGesture);
GDREGISTER_CLASS(InputEventMIDI);
// Network
- GDREGISTER_VIRTUAL_CLASS(IP);
+ GDREGISTER_ABSTRACT_CLASS(IP);
- GDREGISTER_VIRTUAL_CLASS(StreamPeer);
+ GDREGISTER_ABSTRACT_CLASS(StreamPeer);
GDREGISTER_CLASS(StreamPeerExtension);
GDREGISTER_CLASS(StreamPeerBuffer);
GDREGISTER_CLASS(StreamPeerTCP);
GDREGISTER_CLASS(TCPServer);
- GDREGISTER_VIRTUAL_CLASS(PacketPeer);
+ GDREGISTER_ABSTRACT_CLASS(PacketPeer);
GDREGISTER_CLASS(PacketPeerExtension);
GDREGISTER_CLASS(PacketPeerStream);
GDREGISTER_CLASS(PacketPeerUDP);
@@ -198,7 +200,7 @@ void register_core_types() {
resource_format_loader_crypto.instantiate();
ResourceLoader::add_resource_format_loader(resource_format_loader_crypto);
- GDREGISTER_VIRTUAL_CLASS(MultiplayerPeer);
+ GDREGISTER_ABSTRACT_CLASS(MultiplayerPeer);
GDREGISTER_CLASS(MultiplayerPeerExtension);
GDREGISTER_CLASS(MultiplayerAPI);
GDREGISTER_CLASS(MainLoop);
@@ -224,19 +226,19 @@ void register_core_types() {
GDREGISTER_CLASS(PCKPacker);
GDREGISTER_CLASS(PackedDataContainer);
- GDREGISTER_VIRTUAL_CLASS(PackedDataContainerRef);
+ GDREGISTER_ABSTRACT_CLASS(PackedDataContainerRef);
GDREGISTER_CLASS(AStar);
GDREGISTER_CLASS(AStar2D);
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
- GDREGISTER_VIRTUAL_CLASS(ResourceImporter);
+ GDREGISTER_ABSTRACT_CLASS(ResourceImporter);
GDREGISTER_CLASS(NativeExtension);
- GDREGISTER_VIRTUAL_CLASS(NativeExtensionManager);
+ GDREGISTER_ABSTRACT_CLASS(NativeExtensionManager);
- GDREGISTER_VIRTUAL_CLASS(ResourceUID);
+ GDREGISTER_ABSTRACT_CLASS(ResourceUID);
GDREGISTER_CLASS(EngineProfiler);
@@ -259,6 +261,8 @@ void register_core_types() {
_classdb = memnew(core_bind::special::ClassDB);
_marshalls = memnew(core_bind::Marshalls);
_engine_debugger = memnew(core_bind::EngineDebugger);
+
+ GDREGISTER_NATIVE_STRUCT(AudioFrame, "float left;float right");
}
void register_core_settings() {
@@ -274,7 +278,7 @@ void register_core_settings() {
void register_core_singletons() {
GDREGISTER_CLASS(ProjectSettings);
- GDREGISTER_VIRTUAL_CLASS(IP);
+ GDREGISTER_ABSTRACT_CLASS(IP);
GDREGISTER_CLASS(core_bind::Geometry2D);
GDREGISTER_CLASS(core_bind::Geometry3D);
GDREGISTER_CLASS(core_bind::ResourceLoader);
@@ -284,7 +288,7 @@ void register_core_singletons() {
GDREGISTER_CLASS(core_bind::special::ClassDB);
GDREGISTER_CLASS(core_bind::Marshalls);
GDREGISTER_CLASS(TranslationServer);
- GDREGISTER_VIRTUAL_CLASS(Input);
+ GDREGISTER_ABSTRACT_CLASS(Input);
GDREGISTER_CLASS(InputMap);
GDREGISTER_CLASS(Expression);
GDREGISTER_CLASS(core_bind::EngineDebugger);
@@ -314,11 +318,16 @@ void register_core_extensions() {
NativeExtension::initialize_native_extensions();
native_extension_manager->load_extensions();
native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+ _is_core_extensions_registered = true;
}
-void unregister_core_types() {
- native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+void unregister_core_extensions() {
+ if (_is_core_extensions_registered) {
+ native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+ }
+}
+void unregister_core_types() {
memdelete(native_extension_manager);
memdelete(resource_uid);
diff --git a/core/register_core_types.h b/core/register_core_types.h
index 0fd4e73c40..dfb2d8ac80 100644
--- a/core/register_core_types.h
+++ b/core/register_core_types.h
@@ -36,5 +36,6 @@ void register_core_settings();
void register_core_extensions();
void register_core_singletons();
void unregister_core_types();
+void unregister_core_extensions();
#endif // REGISTER_CORE_TYPES_H
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index 11674629fc..2e941b8037 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -73,11 +73,23 @@ void StringName::cleanup() {
d = d->next;
}
}
- print_line("\nStringName Reference Ranking:\n");
+
+ print_line("\nStringName reference ranking (from most to least referenced):\n");
+
data.sort_custom<DebugSortReferences>();
- for (int i = 0; i < MIN(100, data.size()); i++) {
+ int unreferenced_stringnames = 0;
+ int rarely_referenced_stringnames = 0;
+ for (int i = 0; i < data.size(); i++) {
print_line(itos(i + 1) + ": " + data[i]->get_name() + " - " + itos(data[i]->debug_references));
+ if (data[i]->debug_references == 0) {
+ unreferenced_stringnames += 1;
+ } else if (data[i]->debug_references < 5) {
+ rarely_referenced_stringnames += 1;
+ }
}
+
+ print_line(vformat("\nOut of %d StringNames, %d StringNames were never referenced during this run (0 times) (%.2f%%).", data.size(), unreferenced_stringnames, unreferenced_stringnames / float(data.size()) * 100));
+ print_line(vformat("Out of %d StringNames, %d StringNames were rarely referenced during this run (1-4 times) (%.2f%%).", data.size(), rarely_referenced_stringnames, rarely_referenced_stringnames / float(data.size()) * 100));
}
#endif
int lost_strings = 0;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index c4edc8c086..7cfd34b53e 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -103,9 +103,12 @@ bool Char16String::operator<(const Char16String &p_right) const {
}
Char16String &Char16String::operator+=(char16_t p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
- set(length() - 1, p_char);
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+
+ char16_t *dst = ptrw();
+ dst[lhs_len] = p_char;
+ dst[lhs_len + 1] = 0;
return *this;
}
@@ -158,9 +161,12 @@ bool CharString::operator<(const CharString &p_right) const {
}
CharString &CharString::operator+=(char p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
- set(length() - 1, p_char);
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+
+ char *dst = ptrw();
+ dst[lhs_len] = p_char;
+ dst[lhs_len + 1] = 0;
return *this;
}
@@ -304,11 +310,7 @@ void String::copy_from(const char *p_cstr) {
return;
}
- int len = 0;
- const char *ptr = p_cstr;
- while (*(ptr++) != 0) {
- len++;
- }
+ const size_t len = strlen(p_cstr);
if (len == 0) {
resize(0);
@@ -319,7 +321,7 @@ void String::copy_from(const char *p_cstr) {
char32_t *dst = this->ptrw();
- for (int i = 0; i < len + 1; i++) {
+ for (size_t i = 0; i <= len; i++) {
dst[i] = p_cstr[i];
}
}
@@ -374,13 +376,14 @@ void String::copy_from(const wchar_t *p_cstr, const int p_clip_to) {
void String::copy_from(const char32_t &p_char) {
resize(2);
+ char32_t *dst = ptrw();
if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
- set(0, 0xfffd);
+ dst[0] = 0xfffd;
} else {
- set(0, p_char);
+ dst[0] = p_char;
}
- set(1, 0);
+ dst[1] = 0;
}
void String::copy_from(const char32_t *p_cstr) {
@@ -429,9 +432,8 @@ void String::copy_from(const char32_t *p_cstr, const int p_clip_to) {
// p_length <= p_char strlen
void String::copy_from_unchecked(const char32_t *p_char, const int p_length) {
resize(p_length + 1);
- set(p_length, 0);
-
char32_t *dst = ptrw();
+ dst[p_length] = 0;
for (int i = 0; i < p_length; i++) {
if ((p_char[i] >= 0xd800 && p_char[i] <= 0xdfff) || (p_char[i] > 0x10ffff)) {
@@ -461,6 +463,12 @@ String String::operator+(const String &p_str) const {
return res;
}
+String String::operator+(char32_t p_char) const {
+ String res = *this;
+ res += p_char;
+ return res;
+}
+
String operator+(const char *p_chr, const String &p_str) {
String tmp = p_chr;
tmp += p_str;
@@ -484,27 +492,23 @@ String operator+(char32_t p_chr, const String &p_str) {
}
String &String::operator+=(const String &p_str) {
- if (is_empty()) {
+ const int lhs_len = length();
+ if (lhs_len == 0) {
*this = p_str;
return *this;
}
- if (p_str.is_empty()) {
+ const int rhs_len = p_str.length();
+ if (rhs_len == 0) {
return *this;
}
- int from = length();
-
- resize(length() + p_str.size());
+ resize(lhs_len + rhs_len + 1);
const char32_t *src = p_str.get_data();
- char32_t *dst = ptrw();
+ char32_t *dst = ptrw() + lhs_len;
- set(length(), 0);
-
- for (int i = 0; i < p_str.length(); i++) {
- dst[from + i] = src[i];
- }
+ memcpy(dst, src, (rhs_len + 1) * sizeof(char32_t));
return *this;
}
@@ -514,22 +518,15 @@ String &String::operator+=(const char *p_str) {
return *this;
}
- int src_len = 0;
- const char *ptr = p_str;
- while (*(ptr++) != 0) {
- src_len++;
- }
-
- int from = length();
+ const int lhs_len = length();
+ const size_t rhs_len = strlen(p_str);
- resize(from + src_len + 1);
+ resize(lhs_len + rhs_len + 1);
- char32_t *dst = ptrw();
-
- set(length(), 0);
+ char32_t *dst = ptrw() + lhs_len;
- for (int i = 0; i < src_len; i++) {
- dst[from + i] = p_str[i];
+ for (size_t i = 0; i <= rhs_len; i++) {
+ dst[i] = p_str[i];
}
return *this;
@@ -552,14 +549,16 @@ String &String::operator+=(const char32_t *p_str) {
}
String &String::operator+=(char32_t p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+ char32_t *dst = ptrw();
if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
- set(length() - 1, 0xfffd);
+ dst[lhs_len] = 0xfffd;
} else {
- set(length() - 1, p_char);
+ dst[lhs_len] = p_char;
}
+ dst[lhs_len + 1] = 0;
return *this;
}
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 1d302b65a7..5e7904d827 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -225,6 +225,7 @@ public:
bool operator==(const String &p_str) const;
bool operator!=(const String &p_str) const;
String operator+(const String &p_str) const;
+ String operator+(char32_t p_char) const;
String &operator+=(const String &);
String &operator+=(char32_t p_char);
diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h
index c91d27ebe1..4e712fccf2 100644
--- a/core/templates/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -145,7 +145,7 @@ private:
uint32_t old_capacity = capacity;
// Capacity can't be 0.
- capacity = MAX(1, p_new_capacity);
+ capacity = MAX(1u, p_new_capacity);
TKey *old_keys = keys;
TValue *old_values = values;
@@ -367,7 +367,7 @@ public:
OAHashMap(uint32_t p_initial_capacity = 64) {
// Capacity can't be 0.
- capacity = MAX(1, p_initial_capacity);
+ capacity = MAX(1u, p_initial_capacity);
keys = static_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
values = static_cast<TValue *>(Memory::alloc_static(sizeof(TValue) * capacity));
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index 5bc723787f..b9067e2edd 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -86,10 +86,10 @@ public:
}
p_mem->~T();
available_pool[allocs_available >> page_shift][allocs_available & page_mask] = p_mem;
+ allocs_available++;
if (thread_safe) {
spin_lock.unlock();
}
- allocs_available++;
}
void reset(bool p_allow_unfreed = false) {
diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h
index 360fda81f8..f13156b292 100644
--- a/core/templates/pooled_list.h
+++ b/core/templates/pooled_list.h
@@ -28,16 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef POOLED_LIST_H
-#define POOLED_LIST_H
-
-#include "core/templates/local_vector.h"
+#pragma once
// Simple template to provide a pool with O(1) allocate and free.
// The freelist could alternatively be a linked list placed within the unused elements
// to use less memory, however a separate freelist is probably more cache friendly.
-//
-// NOTE: Take great care when using this with non POD types. The construction and destruction
+
+// NOTE : Take great care when using this with non POD types. The construction and destruction
// is done in the LocalVector, NOT as part of the pool. So requesting a new item does not guarantee
// a constructor is run, and free does not guarantee a destructor.
// You should generally handle clearing
@@ -45,33 +42,60 @@
// This is by design for fastest use in the BVH. If you want a more general pool
// that does call constructors / destructors on request / free, this should probably be
// a separate template.
-template <class T, bool force_trivial = false>
+
+// The zero_on_first_request feature is optional and is useful for e.g. pools of handles,
+// which may use a ref count which we want to be initialized to zero the first time a handle is created,
+// but left alone on subsequent allocations (as will typically be incremented).
+
+// Note that there is no function to compact the pool - this would
+// invalidate any existing pool IDs held externally.
+// Compaction can be done but would rely on a more complex method
+// of preferentially giving out lower IDs in the freelist first.
+
+#include "core/templates/local_vector.h"
+
+template <class T, class U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
class PooledList {
- LocalVector<T, uint32_t, force_trivial> list;
- LocalVector<uint32_t, uint32_t, true> freelist;
+ LocalVector<T, U, force_trivial> list;
+ LocalVector<U, U, true> freelist;
// not all list members are necessarily used
- int _used_size;
+ U _used_size;
public:
PooledList() {
_used_size = 0;
}
- int estimate_memory_use() const {
- return (list.size() * sizeof(T)) + (freelist.size() * sizeof(uint32_t));
+ // Use with care, in most cases you should make sure to
+ // free all elements first (i.e. _used_size would be zero),
+ // although it could also be used without this as an optimization
+ // in some cases.
+ void clear() {
+ list.clear();
+ freelist.clear();
+ _used_size = 0;
+ }
+
+ uint64_t estimate_memory_use() const {
+ return ((uint64_t)list.size() * sizeof(T)) + ((uint64_t)freelist.size() * sizeof(U));
}
- const T &operator[](uint32_t p_index) const {
+ const T &operator[](U p_index) const {
return list[p_index];
}
- T &operator[](uint32_t p_index) {
+ T &operator[](U p_index) {
return list[p_index];
}
- int size() const { return _used_size; }
+ // To be explicit in a pool there is a distinction
+ // between the number of elements that are currently
+ // in use, and the number of elements that have been reserved.
+ // Using size() would be vague.
+ U used_size() const { return _used_size; }
+ U reserved_size() const { return list.size(); }
- T *request(uint32_t &r_id) {
+ T *request(U &r_id) {
_used_size++;
if (freelist.size()) {
@@ -79,19 +103,106 @@ public:
int new_size = freelist.size() - 1;
r_id = freelist[new_size];
freelist.resize(new_size);
+
return &list[r_id];
}
r_id = list.size();
list.resize(r_id + 1);
+
+ static_assert((!zero_on_first_request) || (__is_pod(T)), "zero_on_first_request requires trivial type");
+ if (zero_on_first_request && __is_pod(T)) {
+ list[r_id] = {};
+ }
+
return &list[r_id];
}
- void free(const uint32_t &p_id) {
+ void free(const U &p_id) {
// should not be on free list already
- CRASH_COND(p_id >= list.size());
+ ERR_FAIL_UNSIGNED_INDEX(p_id, list.size());
freelist.push_back(p_id);
+ ERR_FAIL_COND_MSG(!_used_size, "_used_size has become out of sync, have you double freed an item?");
_used_size--;
}
};
-#endif // POOLED_LIST_H
+// a pooled list which automatically keeps a list of the active members
+template <class T, class U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
+class TrackedPooledList {
+public:
+ U pool_used_size() const { return _pool.used_size(); }
+ U pool_reserved_size() const { return _pool.reserved_size(); }
+ U active_size() const { return _active_list.size(); }
+
+ // use with care, see the earlier notes in the PooledList clear()
+ void clear() {
+ _pool.clear();
+ _active_list.clear();
+ _active_map.clear();
+ }
+
+ U get_active_id(U p_index) const {
+ return _active_list[p_index];
+ }
+
+ const T &get_active(U p_index) const {
+ return _pool[get_active_id(p_index)];
+ }
+
+ T &get_active(U p_index) {
+ return _pool[get_active_id(p_index)];
+ }
+
+ const T &operator[](U p_index) const {
+ return _pool[p_index];
+ }
+ T &operator[](U p_index) {
+ return _pool[p_index];
+ }
+
+ T *request(U &r_id) {
+ T *item = _pool.request(r_id);
+
+ // add to the active list
+ U active_list_id = _active_list.size();
+ _active_list.push_back(r_id);
+
+ // expand the active map (this should be in sync with the pool list
+ if (_pool.used_size() > _active_map.size()) {
+ _active_map.resize(_pool.used_size());
+ }
+
+ // store in the active map
+ _active_map[r_id] = active_list_id;
+
+ return item;
+ }
+
+ void free(const U &p_id) {
+ _pool.free(p_id);
+
+ // remove from the active list.
+ U list_id = _active_map[p_id];
+
+ // zero the _active map to detect bugs (only in debug?)
+ _active_map[p_id] = -1;
+
+ _active_list.remove_unordered(list_id);
+
+ // keep the replacement in sync with the correct list Id
+ if (list_id < _active_list.size()) {
+ // which pool id has been replaced in the active list
+ U replacement_id = _active_list[list_id];
+
+ // keep that replacements map up to date with the new position
+ _active_map[replacement_id] = list_id;
+ }
+ }
+
+ const LocalVector<U, U> &get_active_list() const { return _active_list; }
+
+private:
+ PooledList<T, U, force_trivial, zero_on_first_request> _pool;
+ LocalVector<U, U> _active_map;
+ LocalVector<U, U> _active_list;
+};
diff --git a/core/typedefs.h b/core/typedefs.h
index 5929b5123b..510b39177c 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -89,34 +89,43 @@
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
-#undef MIN // override standard definition
-#undef MAX // override standard definition
-#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
+// Make room for our constexpr's below by overriding potential system-specific macros.
+#undef ABS
+#undef SIGN
+#undef MIN
+#undef MAX
+#undef CLAMP
+
// Generic ABS function, for math uses please use Math::abs.
-#ifndef ABS
-#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
-#endif
+template <typename T>
+constexpr T ABS(T m_v) {
+ return m_v < 0 ? -m_v : m_v;
+}
-#ifndef SIGN
-#define SIGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0)))
-#endif
+template <typename T>
+constexpr const T SIGN(const T m_v) {
+ return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
+}
-#ifndef MIN
-#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
-#endif
+template <typename T, typename T2>
+constexpr auto MIN(const T m_a, const T2 m_b) {
+ return m_a < m_b ? m_a : m_b;
+}
-#ifndef MAX
-#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
-#endif
+template <typename T, typename T2>
+constexpr auto MAX(const T m_a, const T2 m_b) {
+ return m_a > m_b ? m_a : m_b;
+}
-#ifndef CLAMP
-#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
-#endif
+template <typename T, typename T2, typename T3>
+constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
+ return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
+}
// Generic swap template.
#ifndef SWAP
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index b6fdb4d902..22a13b0fab 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -100,6 +100,10 @@ struct VariantCaster<const T &> {
_FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
*(int64_t *)p_ptr = (int64_t)p_val; \
} \
+ }; \
+ template <> \
+ struct ZeroInitializer<m_enum> { \
+ static void initialize(m_enum &value) { value = (m_enum)0; } \
};
// Object enum casts must go here
@@ -182,7 +186,7 @@ struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
- !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
@@ -197,7 +201,7 @@ struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
- !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
@@ -212,7 +216,7 @@ struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
- !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 27792ce111..48ed48d120 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -37,7 +37,7 @@
#include "core/object/script_language.h"
void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const {
- MessageQueue::get_singleton()->push_callable(*this, p_arguments, p_argcount);
+ MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount);
}
void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const {
@@ -59,7 +59,7 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu
return;
}
#endif
- r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error);
+ r_return_value = obj->callp(method, p_arguments, p_argcount, r_call_error);
}
}
@@ -379,7 +379,7 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
return ERR_INVALID_DATA;
}
- return obj->emit_signal(name, p_arguments, p_argcount);
+ return obj->emit_signalp(name, p_arguments, p_argcount);
}
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h
index 8e9fbbc0a4..ed68e0f6c9 100644
--- a/core/variant/native_ptr.h
+++ b/core/variant/native_ptr.h
@@ -124,6 +124,7 @@ struct PtrToArg<GDNativePtr<T>> {
}
};
+GDVIRTUAL_NATIVE_PTR(void)
GDVIRTUAL_NATIVE_PTR(AudioFrame)
GDVIRTUAL_NATIVE_PTR(bool)
GDVIRTUAL_NATIVE_PTR(char)
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index ee050cff4f..bacd0d19ce 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -281,4 +281,38 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) {
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
+template <typename T>
+struct ZeroInitializer {
+ static void initialize(T &value) {} //no initialization by default
+};
+
+template <>
+struct ZeroInitializer<bool> {
+ static void initialize(bool &value) { value = false; }
+};
+
+template <typename T>
+struct ZeroInitializer<T *> {
+ static void initialize(T *&value) { value = nullptr; }
+};
+
+#define ZERO_INITIALIZER_NUMBER(m_type) \
+ template <> \
+ struct ZeroInitializer<m_type> { \
+ static void initialize(m_type &value) { value = 0; } \
+ };
+
+ZERO_INITIALIZER_NUMBER(uint8_t)
+ZERO_INITIALIZER_NUMBER(int8_t)
+ZERO_INITIALIZER_NUMBER(uint16_t)
+ZERO_INITIALIZER_NUMBER(int16_t)
+ZERO_INITIALIZER_NUMBER(uint32_t)
+ZERO_INITIALIZER_NUMBER(int32_t)
+ZERO_INITIALIZER_NUMBER(uint64_t)
+ZERO_INITIALIZER_NUMBER(int64_t)
+ZERO_INITIALIZER_NUMBER(char16_t)
+ZERO_INITIALIZER_NUMBER(char32_t)
+ZERO_INITIALIZER_NUMBER(float)
+ZERO_INITIALIZER_NUMBER(double)
+
#endif // TYPE_INFO_H
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 3d11ed6303..b3e909b489 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1972,7 +1972,7 @@ Variant::operator ::RID() const {
}
#endif
Callable::CallError ce;
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::RID) {
return ret;
}
@@ -3309,21 +3309,7 @@ bool Variant::is_shared() const {
return false;
}
-Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
-
- Variant ret;
- call(p_method, argptr, argc, ret, error);
-
+void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) {
switch (error.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(Variant::Type(error.expected)) + "'.";
@@ -3341,8 +3327,6 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
default: {
}
}
-
- return ret;
}
void Variant::construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct, void *p_construct_ud) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 836a67d942..ca18249f36 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -282,6 +282,14 @@ private:
static void _register_variant_utility_functions();
static void _unregister_variant_utility_functions();
+ void _variant_call_error(const String &p_method, Callable::CallError &error);
+
+ // Avoid accidental conversion. If you reached this point, it's because you most likely forgot to dereference
+ // a Variant pointer (so add * like this: *variant_pointer).
+
+ Variant(const Variant *) {}
+ Variant(const Variant **) {}
+
public:
_FORCE_INLINE_ Type get_type() const {
return type;
@@ -527,8 +535,23 @@ public:
static int get_builtin_method_count(Variant::Type p_type);
static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method);
- void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
- Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant());
+ void callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ Variant ret;
+ callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), ret, cerr);
+ if (cerr.error != Callable::CallError::CALL_OK) {
+ _variant_call_error(p_method, cerr);
+ }
+ return ret;
+ }
static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index a5e89eec80..a02f9c5823 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1003,7 +1003,7 @@ static void register_builtin_method(const Vector<String> &p_argnames, const Vect
builtin_method_names[T::get_base_type()].push_back(name);
}
-void Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+void Variant::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
if (type == Variant::OBJECT) {
//call object
Object *obj = _get_obj().obj;
@@ -1018,7 +1018,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg
}
#endif
- r_ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error);
+ r_ret = _get_obj().obj->callp(p_method, p_args, p_argcount, r_error);
//else if (type==Variant::METHOD) {
} else {
@@ -1467,6 +1467,8 @@ static void _register_variant_builtin_methods() {
bind_static_method(String, num_scientific, sarray("number"), varray());
bind_static_method(String, num, sarray("number", "decimals"), varray(-1));
+ bind_static_method(String, num_int64, sarray("number", "base", "capitalize_hex"), varray(10, false));
+ bind_static_method(String, num_uint64, sarray("number", "base", "capitalize_hex"), varray(10, false));
bind_static_method(String, chr, sarray("char"), varray());
bind_static_method(String, humanize_size, sarray("size"), varray());
@@ -1626,6 +1628,8 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, is_normalized, sarray(), varray());
bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
bind_method(Quaternion, inverse, sarray(), varray());
+ bind_method(Quaternion, log, sarray(), varray());
+ bind_method(Quaternion, exp, sarray(), varray());
bind_method(Quaternion, angle_to, sarray("to"), varray());
bind_method(Quaternion, dot, sarray("with"), varray());
bind_method(Quaternion, slerp, sarray("to", "weight"), varray());
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index cd1ae9f41f..35e0319aa3 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -177,6 +177,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT);
register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING);
register_op<OperatorEvaluatorAdd<String, char32_t, String>>(Variant::OP_ADD, Variant::INT, Variant::STRING);
+ register_op<OperatorEvaluatorAdd<String, String, char32_t>>(Variant::OP_ADD, Variant::STRING, Variant::INT);
register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index fa8d26a72b..e604ff9567 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -1277,7 +1277,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
ref.push_back(r_iter);
Variant vref = ref;
const Variant *refp[] = { &vref };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
valid = false;
@@ -1504,7 +1504,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const {
ref.push_back(r_iter);
Variant vref = ref;
const Variant *refp[] = { &vref };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
valid = false;
@@ -1686,7 +1686,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
Callable::CallError ce;
ce.error = Callable::CallError::CALL_OK;
const Variant *refp[] = { &r_iter };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_valid = false;
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index e83c71098d..05fb577e2c 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -219,10 +219,6 @@ struct VariantUtilityFunctions {
return Math::step_decimals(step);
}
- static inline int range_step_decimals(float step) {
- return Math::range_step_decimals(step);
- }
-
static inline double snapped(double value, double step) {
return Math::snapped(value, step);
}
@@ -1204,7 +1200,6 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(range_step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);