diff options
35 files changed, 920 insertions, 56 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8925852..08a9228 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -173,7 +173,7 @@ jobs: ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version cd test # Need to run the editor so .godot is generated... but it crashes! Ignore that :-) - (cd project && (timeout 10 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true)) + (cd project && (timeout 30 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --import --headless >/dev/null 2>&1 || true)) GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh - name: Upload artifact @@ -22,7 +22,7 @@ This repository contains the *C++ bindings* for the [**Godot Engine**](https:// - [**Compatibility**](#compatibility) - [**Contributing**](#contributing) - [**Getting started**](#getting-started) -- [**Included example**](#included-example) +- [**Examples and templates**](#examples-and-templates) ## Versioning diff --git a/binding_generator.py b/binding_generator.py index 972cbf9..71d9e6b 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -545,6 +545,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl result.append("#include <godot_cpp/variant/vector2.hpp>") if class_name == "PackedVector3Array": result.append("#include <godot_cpp/variant/vector3.hpp>") + if class_name == "PackedVector4Array": + result.append("#include <godot_cpp/variant/vector4.hpp>") if is_packed_array(class_name): result.append("#include <godot_cpp/core/error_macros.hpp>") @@ -1504,6 +1506,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append(f"\tGDEXTENSION_CLASS({class_name}, {inherits})") result.append("") + if is_singleton: + result.append(f"\tstatic {class_name} *singleton;") + result.append("") + result.append("public:") result.append("") @@ -1584,6 +1590,11 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("\t}") result.append("") + + if is_singleton: + result.append(f"\t~{class_name}();") + result.append("") + result.append("public:") # Special cases. @@ -1733,6 +1744,7 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us result.append(f"#include <godot_cpp/classes/{snake_class_name}.hpp>") result.append("") + result.append("#include <godot_cpp/core/class_db.hpp>") result.append("#include <godot_cpp/core/engine_ptrcall.hpp>") result.append("#include <godot_cpp/core/error_macros.hpp>") result.append("") @@ -1747,9 +1759,10 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us result.append("") if is_singleton: + result.append(f"{class_name} *{class_name}::singleton = nullptr;") + result.append("") result.append(f"{class_name} *{class_name}::get_singleton() {{") # We assume multi-threaded access is OK because each assignment will assign the same value every time - result.append(f"\tstatic {class_name} *singleton = nullptr;") result.append("\tif (unlikely(singleton == nullptr)) {") result.append( f"\t\tGDExtensionObjectPtr singleton_obj = internal::gdextension_interface_global_get_singleton({class_name}::get_class_static()._native_ptr());" @@ -1763,11 +1776,22 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us result.append("#ifdef DEBUG_ENABLED") result.append("\t\tERR_FAIL_NULL_V(singleton, nullptr);") result.append("#endif // DEBUG_ENABLED") + result.append("\t\tif (likely(singleton)) {") + result.append(f"\t\t\tClassDB::_register_engine_singleton({class_name}::get_class_static(), singleton);") + result.append("\t\t}") result.append("\t}") result.append("\treturn singleton;") result.append("}") result.append("") + result.append(f"{class_name}::~{class_name}() {{") + result.append("\tif (singleton == this) {") + result.append(f"\t\tClassDB::_unregister_engine_singleton({class_name}::get_class_static());") + result.append("\t\tsingleton = nullptr;") + result.append("\t}") + result.append("}") + result.append("") + if "methods" in class_api: for method in class_api["methods"]: if method["is_virtual"]: @@ -2445,6 +2469,7 @@ def is_packed_array(type_name): "PackedStringArray", "PackedVector2Array", "PackedVector3Array", + "PackedVector4Array", ] diff --git a/gdextension/extension_api.json b/gdextension/extension_api.json index cfd5ebe..ca9d02b 100644 --- a/gdextension/extension_api.json +++ b/gdextension/extension_api.json @@ -164,6 +164,10 @@ "size": 8 }, { + "name": "PackedVector4Array", + "size": 8 + }, + { "name": "Variant", "size": 24 } @@ -325,6 +329,10 @@ "size": 16 }, { + "name": "PackedVector4Array", + "size": 16 + }, + { "name": "Variant", "size": 24 } @@ -486,6 +494,10 @@ "size": 8 }, { + "name": "PackedVector4Array", + "size": 8 + }, + { "name": "Variant", "size": 40 } @@ -647,6 +659,10 @@ "size": 16 }, { + "name": "PackedVector4Array", + "size": 16 + }, + { "name": "Variant", "size": 40 } @@ -3932,8 +3948,12 @@ "value": 37 }, { - "name": "TYPE_MAX", + "name": "TYPE_PACKED_VECTOR4_ARRAY", "value": 38 + }, + { + "name": "TYPE_MAX", + "value": 39 } ] }, @@ -6292,6 +6312,16 @@ "name": "!=", "right_type": "PackedColorArray", "return_type": "bool" + }, + { + "name": "==", + "right_type": "PackedVector4Array", + "return_type": "bool" + }, + { + "name": "!=", + "right_type": "PackedVector4Array", + "return_type": "bool" } ], "constructors": [ @@ -7445,6 +7475,11 @@ "name": "%", "right_type": "PackedColorArray", "return_type": "String" + }, + { + "name": "%", + "right_type": "PackedVector4Array", + "return_type": "String" } ], "methods": [ @@ -12334,6 +12369,11 @@ "name": "in", "right_type": "Array", "return_type": "bool" + }, + { + "name": "in", + "right_type": "PackedVector4Array", + "return_type": "bool" } ], "methods": [ @@ -17144,6 +17184,11 @@ "name": "%", "right_type": "PackedColorArray", "return_type": "String" + }, + { + "name": "%", + "right_type": "PackedVector4Array", + "return_type": "String" } ], "methods": [ @@ -19972,6 +20017,15 @@ "type": "PackedColorArray" } ] + }, + { + "index": 12, + "arguments": [ + { + "name": "from", + "type": "PackedVector4Array" + } + ] } ], "has_destructor": true @@ -23636,6 +23690,351 @@ } ], "has_destructor": true + }, + { + "name": "PackedVector4Array", + "indexing_return_type": "Vector4", + "is_keyed": false, + "operators": [ + { + "name": "==", + "right_type": "Variant", + "return_type": "bool" + }, + { + "name": "!=", + "right_type": "Variant", + "return_type": "bool" + }, + { + "name": "not", + "return_type": "bool" + }, + { + "name": "in", + "right_type": "Dictionary", + "return_type": "bool" + }, + { + "name": "in", + "right_type": "Array", + "return_type": "bool" + }, + { + "name": "==", + "right_type": "PackedVector4Array", + "return_type": "bool" + }, + { + "name": "!=", + "right_type": "PackedVector4Array", + "return_type": "bool" + }, + { + "name": "+", + "right_type": "PackedVector4Array", + "return_type": "PackedVector4Array" + } + ], + "methods": [ + { + "name": "size", + "return_type": "int", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 3173160232 + }, + { + "name": "is_empty", + "return_type": "bool", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 3918633141 + }, + { + "name": "set", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 1350366223, + "arguments": [ + { + "name": "index", + "type": "int" + }, + { + "name": "value", + "type": "Vector4" + } + ] + }, + { + "name": "push_back", + "return_type": "bool", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3289167688, + "arguments": [ + { + "name": "value", + "type": "Vector4" + } + ] + }, + { + "name": "append", + "return_type": "bool", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3289167688, + "arguments": [ + { + "name": "value", + "type": "Vector4" + } + ] + }, + { + "name": "append_array", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 537428395, + "arguments": [ + { + "name": "array", + "type": "PackedVector4Array" + } + ] + }, + { + "name": "remove_at", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 2823966027, + "arguments": [ + { + "name": "index", + "type": "int" + } + ] + }, + { + "name": "insert", + "return_type": "int", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 11085009, + "arguments": [ + { + "name": "at_index", + "type": "int" + }, + { + "name": "value", + "type": "Vector4" + } + ] + }, + { + "name": "fill", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3761353134, + "arguments": [ + { + "name": "value", + "type": "Vector4" + } + ] + }, + { + "name": "resize", + "return_type": "int", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 848867239, + "arguments": [ + { + "name": "new_size", + "type": "int" + } + ] + }, + { + "name": "clear", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3218959716 + }, + { + "name": "has", + "return_type": "bool", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 88913544, + "arguments": [ + { + "name": "value", + "type": "Vector4" + } + ] + }, + { + "name": "reverse", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3218959716 + }, + { + "name": "slice", + "return_type": "PackedVector4Array", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 2942803855, + "arguments": [ + { + "name": "begin", + "type": "int" + }, + { + "name": "end", + "type": "int", + "default_value": "2147483647" + } + ] + }, + { + "name": "to_byte_array", + "return_type": "PackedByteArray", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 247621236 + }, + { + "name": "sort", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3218959716 + }, + { + "name": "bsearch", + "return_type": "int", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 735671678, + "arguments": [ + { + "name": "value", + "type": "Vector4" + }, + { + "name": "before", + "type": "bool", + "default_value": "true" + } + ] + }, + { + "name": "duplicate", + "return_type": "PackedVector4Array", + "is_vararg": false, + "is_const": false, + "is_static": false, + "hash": 3186305013 + }, + { + "name": "find", + "return_type": "int", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 3091171314, + "arguments": [ + { + "name": "value", + "type": "Vector4" + }, + { + "name": "from", + "type": "int", + "default_value": "0" + } + ] + }, + { + "name": "rfind", + "return_type": "int", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 3091171314, + "arguments": [ + { + "name": "value", + "type": "Vector4" + }, + { + "name": "from", + "type": "int", + "default_value": "-1" + } + ] + }, + { + "name": "count", + "return_type": "int", + "is_vararg": false, + "is_const": true, + "is_static": false, + "hash": 3956594488, + "arguments": [ + { + "name": "value", + "type": "Vector4" + } + ] + } + ], + "constructors": [ + { + "index": 0 + }, + { + "index": 1, + "arguments": [ + { + "name": "from", + "type": "PackedVector4Array" + } + ] + }, + { + "index": 2, + "arguments": [ + { + "name": "from", + "type": "Array" + } + ] + } + ], + "has_destructor": true } ], "classes": [ diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 60ec8d4..2ed31da 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -96,6 +96,7 @@ typedef enum { GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY, + GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY, GDEXTENSION_VARIANT_TYPE_VARIANT_MAX } GDExtensionVariantType; @@ -256,6 +257,7 @@ typedef struct { typedef const GDExtensionPropertyInfo *(*GDExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); typedef void (*GDExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list); +typedef void (*GDExtensionClassFreePropertyList2)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count); typedef GDExtensionBool (*GDExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name); typedef GDExtensionBool (*GDExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret); typedef GDExtensionBool (*GDExtensionClassValidateProperty)(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property); @@ -333,7 +335,7 @@ typedef struct { GDExtensionClassSet set_func; GDExtensionClassGet get_func; GDExtensionClassGetPropertyList get_property_list_func; - GDExtensionClassFreePropertyList free_property_list_func; + GDExtensionClassFreePropertyList2 free_property_list_func; GDExtensionClassPropertyCanRevert property_can_revert_func; GDExtensionClassPropertyGetRevert property_get_revert_func; GDExtensionClassValidateProperty validate_property_func; @@ -1963,32 +1965,6 @@ typedef uint8_t *(*GDExtensionInterfacePackedByteArrayOperatorIndex)(GDExtension typedef const uint8_t *(*GDExtensionInterfacePackedByteArrayOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); /** - * @name packed_color_array_operator_index - * @since 4.1 - * - * Gets a pointer to a color in a PackedColorArray. - * - * @param p_self A pointer to a PackedColorArray object. - * @param p_index The index of the Color to get. - * - * @return A pointer to the requested Color. - */ -typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndex)(GDExtensionTypePtr p_self, GDExtensionInt p_index); - -/** - * @name packed_color_array_operator_index_const - * @since 4.1 - * - * Gets a const pointer to a color in a PackedColorArray. - * - * @param p_self A const pointer to a const PackedColorArray object. - * @param p_index The index of the Color to get. - * - * @return A const pointer to the requested Color. - */ -typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); - -/** * @name packed_float32_array_operator_index * @since 4.1 * @@ -2171,6 +2147,58 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector3ArrayOperatorIndex typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector3ArrayOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); /** + * @name packed_vector4_array_operator_index + * @since 4.3 + * + * Gets a pointer to a Vector4 in a PackedVector4Array. + * + * @param p_self A pointer to a PackedVector4Array object. + * @param p_index The index of the Vector4 to get. + * + * @return A pointer to the requested Vector4. + */ +typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector4ArrayOperatorIndex)(GDExtensionTypePtr p_self, GDExtensionInt p_index); + +/** + * @name packed_vector4_array_operator_index_const + * @since 4.3 + * + * Gets a const pointer to a Vector4 in a PackedVector4Array. + * + * @param p_self A const pointer to a PackedVector4Array object. + * @param p_index The index of the Vector4 to get. + * + * @return A const pointer to the requested Vector4. + */ +typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector4ArrayOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); + +/** + * @name packed_color_array_operator_index + * @since 4.1 + * + * Gets a pointer to a color in a PackedColorArray. + * + * @param p_self A pointer to a PackedColorArray object. + * @param p_index The index of the Color to get. + * + * @return A pointer to the requested Color. + */ +typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndex)(GDExtensionTypePtr p_self, GDExtensionInt p_index); + +/** + * @name packed_color_array_operator_index_const + * @since 4.1 + * + * Gets a const pointer to a color in a PackedColorArray. + * + * @param p_self A const pointer to a PackedColorArray object. + * @param p_index The index of the Color to get. + * + * @return A const pointer to the requested Color. + */ +typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); + +/** * @name array_operator_index * @since 4.1 * @@ -2835,6 +2863,31 @@ typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePt */ typedef void (*GDExtensionInterfaceEditorRemovePlugin)(GDExtensionConstStringNamePtr p_class_name); +/** + * @name editor_help_load_xml_from_utf8_chars + * @since 4.3 + * + * Loads new XML-formatted documentation data in the editor. + * + * The provided pointer can be immediately freed once the function returns. + * + * @param p_data A pointer to a UTF-8 encoded C string (null terminated). + */ +typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *p_data); + +/** + * @name editor_help_load_xml_from_utf8_chars_and_len + * @since 4.3 + * + * Loads new XML-formatted documentation data in the editor. + * + * The provided pointer can be immediately freed once the function returns. + * + * @param p_data A pointer to a UTF-8 encoded C string. + * @param p_size The number of bytes (not code units). + */ +typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size); + #ifdef __cplusplus } #endif diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index ce8c968..ceed378 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -78,7 +78,7 @@ protected: static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; } static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; } static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; } - static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) {} + static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {} static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { return false; } static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; } static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { return false; } @@ -292,11 +292,10 @@ public: return ::godot::internal::create_c_property_list(plist_cpp, r_count); \ } \ \ - static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { \ + static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) { \ if (p_instance) { \ m_class *cls = reinterpret_cast<m_class *>(p_instance); \ cls->plist_owned.clear(); \ - /* TODO `GDExtensionClassFreePropertyList` is ill-defined, we need a non-const pointer to free this. */ \ ::godot::internal::free_c_property_list(const_cast<GDExtensionPropertyInfo *>(p_list)); \ } \ } \ diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 31ebddc..8ef7f8e 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -45,6 +45,7 @@ #include <godot_cpp/variant/callable_method_pointer.hpp> #include <list> +#include <mutex> #include <set> #include <string> #include <unordered_map> @@ -104,6 +105,8 @@ private: static std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks; // Used to remember the custom class registration order. static std::vector<StringName> class_register_order; + static std::unordered_map<StringName, Object *> engine_singletons; + static std::mutex engine_singletons_mutex; static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount); static void initialize_class(const ClassInfo &cl); @@ -153,6 +156,21 @@ public: instance_binding_callbacks[p_name] = p_callbacks; } + static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) { + std::lock_guard<std::mutex> lock(engine_singletons_mutex); + std::unordered_map<StringName, Object *>::const_iterator i = engine_singletons.find(p_class_name); + if (i != engine_singletons.end()) { + ERR_FAIL_COND((*i).second != p_singleton); + return; + } + engine_singletons[p_class_name] = p_singleton; + } + + static void _unregister_engine_singleton(const StringName &p_class_name) { + std::lock_guard<std::mutex> lock(engine_singletons_mutex); + engine_singletons.erase(p_class_name); + } + template <typename N, typename M, typename... VarArgs> static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args); @@ -229,7 +247,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) { T::set_bind, // GDExtensionClassSet set_func; T::get_bind, // GDExtensionClassGet get_func; T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func; - T::free_property_list_bind, // GDExtensionClassFreePropertyList free_property_list_func; + T::free_property_list_bind, // GDExtensionClassFreePropertyList2 free_property_list_func; T::property_can_revert_bind, // GDExtensionClassPropertyCanRevert property_can_revert_func; T::property_get_revert_bind, // GDExtensionClassPropertyGetRevert property_get_revert_func; T::validate_property_bind, // GDExtensionClassValidateProperty validate_property_func; diff --git a/include/godot_cpp/core/method_bind.hpp b/include/godot_cpp/core/method_bind.hpp index 4afd7b8..eabd6ec 100644 --- a/include/godot_cpp/core/method_bind.hpp +++ b/include/godot_cpp/core/method_bind.hpp @@ -412,6 +412,7 @@ public: method = p_method; generate_argument_types(sizeof...(P)); set_argument_count(sizeof...(P)); + set_const(true); } }; @@ -578,6 +579,7 @@ public: generate_argument_types(sizeof...(P)); set_argument_count(sizeof...(P)); set_return(true); + set_const(true); } }; diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 5a62930..822363d 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -148,6 +148,8 @@ extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_inter extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const; extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index; extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const; +extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed_vector4_array_operator_index; +extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const; extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index; extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const; extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref; @@ -160,6 +162,7 @@ extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destro extern "C" GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton; extern "C" GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding; extern "C" GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding; +extern "C" GDExtensionInterfaceObjectFreeInstanceBinding gdextension_interface_object_free_instance_binding; extern "C" GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance; extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name; extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to; @@ -190,6 +193,13 @@ extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_inter extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path; extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin; extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin; +extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars; +extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len; + +class DocDataRegistration { +public: + DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data); +}; } // namespace internal diff --git a/include/godot_cpp/templates/local_vector.hpp b/include/godot_cpp/templates/local_vector.hpp index 5dad32e..10af2a9 100644 --- a/include/godot_cpp/templates/local_vector.hpp +++ b/include/godot_cpp/templates/local_vector.hpp @@ -257,6 +257,10 @@ public: return -1; } + bool has(const T &p_val) const { + return find(p_val) != -1; + } + template <typename C> void sort_custom() { U len = count; diff --git a/include/godot_cpp/variant/aabb.hpp b/include/godot_cpp/variant/aabb.hpp index f344f2c..b827112 100644 --- a/include/godot_cpp/variant/aabb.hpp +++ b/include/godot_cpp/variant/aabb.hpp @@ -103,7 +103,7 @@ struct _NO_DISCARD_ AABB { _FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */ _FORCE_INLINE_ AABB abs() const { - return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs()); + return AABB(position + size.minf(0), size.abs()); } Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const; diff --git a/include/godot_cpp/variant/rect2.hpp b/include/godot_cpp/variant/rect2.hpp index c37134d..e643035 100644 --- a/include/godot_cpp/variant/rect2.hpp +++ b/include/godot_cpp/variant/rect2.hpp @@ -154,14 +154,12 @@ struct _NO_DISCARD_ Rect2 { return Rect2(); } - new_rect.position.x = Math::max(p_rect.position.x, position.x); - new_rect.position.y = Math::max(p_rect.position.y, position.y); + new_rect.position = p_rect.position.max(position); Point2 p_rect_end = p_rect.position + p_rect.size; Point2 end = position + size; - new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x; - new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y; + new_rect.size = p_rect_end.min(end) - new_rect.position; return new_rect; } @@ -174,11 +172,9 @@ struct _NO_DISCARD_ Rect2 { #endif Rect2 new_rect; - new_rect.position.x = Math::min(p_rect.position.x, position.x); - new_rect.position.y = Math::min(p_rect.position.y, position.y); + new_rect.position = p_rect.position.min(position); - new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y); + new_rect.size = (p_rect.position + p_rect.size).max(position + size); new_rect.size = new_rect.size - new_rect.position; // Make relative again. @@ -284,7 +280,7 @@ struct _NO_DISCARD_ Rect2 { } _FORCE_INLINE_ Rect2 abs() const { - return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs()); + return Rect2(position + size.minf(0), size.abs()); } Vector2 get_support(const Vector2 &p_normal) const { diff --git a/include/godot_cpp/variant/rect2i.hpp b/include/godot_cpp/variant/rect2i.hpp index c2a15ac..eff4958 100644 --- a/include/godot_cpp/variant/rect2i.hpp +++ b/include/godot_cpp/variant/rect2i.hpp @@ -97,14 +97,12 @@ struct _NO_DISCARD_ Rect2i { return Rect2i(); } - new_rect.position.x = Math::max(p_rect.position.x, position.x); - new_rect.position.y = Math::max(p_rect.position.y, position.y); + new_rect.position = p_rect.position.max(position); Point2i p_rect_end = p_rect.position + p_rect.size; Point2i end = position + size; - new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x; - new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y; + new_rect.size = p_rect_end.min(end) - new_rect.position; return new_rect; } @@ -117,11 +115,9 @@ struct _NO_DISCARD_ Rect2i { #endif Rect2i new_rect; - new_rect.position.x = Math::min(p_rect.position.x, position.x); - new_rect.position.y = Math::min(p_rect.position.y, position.y); + new_rect.position = p_rect.position.min(position); - new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y); + new_rect.size = (p_rect.position + p_rect.size).max(position + size); new_rect.size = new_rect.size - new_rect.position; // Make relative again. @@ -219,7 +215,7 @@ struct _NO_DISCARD_ Rect2i { } _FORCE_INLINE_ Rect2i abs() const { - return Rect2i(Point2i(position.x + Math::min(size.x, 0), position.y + Math::min(size.y, 0)), size.abs()); + return Rect2i(position + size.mini(0), size.abs()); } _FORCE_INLINE_ void set_end(const Vector2i &p_end) { diff --git a/include/godot_cpp/variant/vector2.hpp b/include/godot_cpp/variant/vector2.hpp index fe4d05a..8f08985 100644 --- a/include/godot_cpp/variant/vector2.hpp +++ b/include/godot_cpp/variant/vector2.hpp @@ -91,10 +91,18 @@ struct _NO_DISCARD_ Vector2 { return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y)); } + Vector2 minf(real_t p_scalar) const { + return Vector2(MIN(x, p_scalar), MIN(y, p_scalar)); + } + Vector2 max(const Vector2 &p_vector2) const { return Vector2(MAX(x, p_vector2.x), MAX(y, p_vector2.y)); } + Vector2 maxf(real_t p_scalar) const { + return Vector2(MAX(x, p_scalar), MAX(y, p_scalar)); + } + real_t distance_to(const Vector2 &p_vector2) const; real_t distance_squared_to(const Vector2 &p_vector2) const; real_t angle_to(const Vector2 &p_vector2) const; @@ -169,7 +177,9 @@ struct _NO_DISCARD_ Vector2 { Vector2 ceil() const; Vector2 round() const; Vector2 snapped(const Vector2 &p_by) const; + Vector2 snappedf(real_t p_by) const; Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const; + Vector2 clampf(real_t p_min, real_t p_max) const; real_t aspect() const { return width / height; } operator String() const; diff --git a/include/godot_cpp/variant/vector2i.hpp b/include/godot_cpp/variant/vector2i.hpp index afeaeea..0d787c3 100644 --- a/include/godot_cpp/variant/vector2i.hpp +++ b/include/godot_cpp/variant/vector2i.hpp @@ -83,10 +83,18 @@ struct _NO_DISCARD_ Vector2i { return Vector2i(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y)); } + Vector2i mini(int32_t p_scalar) const { + return Vector2i(MIN(x, p_scalar), MIN(y, p_scalar)); + } + Vector2i max(const Vector2i &p_vector2i) const { return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y)); } + Vector2i maxi(int32_t p_scalar) const { + return Vector2i(MAX(x, p_scalar), MAX(y, p_scalar)); + } + Vector2i operator+(const Vector2i &p_v) const; void operator+=(const Vector2i &p_v); Vector2i operator-(const Vector2i &p_v) const; @@ -123,7 +131,10 @@ struct _NO_DISCARD_ Vector2i { real_t aspect() const { return width / (real_t)height; } Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); } Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); } + Vector2i snapped(const Vector2i &p_step) const; + Vector2i snappedi(int32_t p_step) const; Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; + Vector2i clampi(int32_t p_min, int32_t p_max) const; operator String() const; operator Vector2() const; diff --git a/include/godot_cpp/variant/vector3.hpp b/include/godot_cpp/variant/vector3.hpp index 1107bca..f256c38 100644 --- a/include/godot_cpp/variant/vector3.hpp +++ b/include/godot_cpp/variant/vector3.hpp @@ -82,10 +82,18 @@ struct _NO_DISCARD_ Vector3 { return Vector3(MIN(x, p_vector3.x), MIN(y, p_vector3.y), MIN(z, p_vector3.z)); } + Vector3 minf(real_t p_scalar) const { + return Vector3(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar)); + } + Vector3 max(const Vector3 &p_vector3) const { return Vector3(MAX(x, p_vector3.x), MAX(y, p_vector3.y), MAX(z, p_vector3.z)); } + Vector3 maxf(real_t p_scalar) const { + return Vector3(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar)); + } + _FORCE_INLINE_ real_t length() const; _FORCE_INLINE_ real_t length_squared() const; @@ -98,7 +106,9 @@ struct _NO_DISCARD_ Vector3 { _FORCE_INLINE_ void zero(); void snap(const Vector3 p_val); + void snapf(real_t p_val); Vector3 snapped(const Vector3 p_val) const; + Vector3 snappedf(real_t p_val) const; void rotate(const Vector3 &p_axis, const real_t p_angle); Vector3 rotated(const Vector3 &p_axis, const real_t p_angle) const; @@ -128,6 +138,7 @@ struct _NO_DISCARD_ Vector3 { _FORCE_INLINE_ Vector3 ceil() const; _FORCE_INLINE_ Vector3 round() const; Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const; + Vector3 clampf(real_t p_min, real_t p_max) const; _FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const; diff --git a/include/godot_cpp/variant/vector3i.hpp b/include/godot_cpp/variant/vector3i.hpp index ae5148f..b2cdbbd 100644 --- a/include/godot_cpp/variant/vector3i.hpp +++ b/include/godot_cpp/variant/vector3i.hpp @@ -75,10 +75,18 @@ struct _NO_DISCARD_ Vector3i { return Vector3i(MIN(x, p_vector3i.x), MIN(y, p_vector3i.y), MIN(z, p_vector3i.z)); } + Vector3i mini(int32_t p_scalar) const { + return Vector3i(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar)); + } + Vector3i max(const Vector3i &p_vector3i) const { return Vector3i(MAX(x, p_vector3i.x), MAX(y, p_vector3i.y), MAX(z, p_vector3i.z)); } + Vector3i maxi(int32_t p_scalar) const { + return Vector3i(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar)); + } + _FORCE_INLINE_ int64_t length_squared() const; _FORCE_INLINE_ double length() const; @@ -89,7 +97,10 @@ struct _NO_DISCARD_ Vector3i { _FORCE_INLINE_ Vector3i abs() const; _FORCE_INLINE_ Vector3i sign() const; + Vector3i snapped(const Vector3i &p_step) const; + Vector3i snappedi(int32_t p_step) const; Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const; + Vector3i clampi(int32_t p_min, int32_t p_max) const; /* Operators */ diff --git a/include/godot_cpp/variant/vector4.hpp b/include/godot_cpp/variant/vector4.hpp index b20915a..866e522 100644 --- a/include/godot_cpp/variant/vector4.hpp +++ b/include/godot_cpp/variant/vector4.hpp @@ -74,10 +74,18 @@ struct _NO_DISCARD_ Vector4 { return Vector4(MIN(x, p_vector4.x), MIN(y, p_vector4.y), MIN(z, p_vector4.z), MIN(w, p_vector4.w)); } + Vector4 minf(real_t p_scalar) const { + return Vector4(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar), MIN(w, p_scalar)); + } + Vector4 max(const Vector4 &p_vector4) const { return Vector4(MAX(x, p_vector4.x), MAX(y, p_vector4.y), MAX(z, p_vector4.z), MAX(w, p_vector4.w)); } + Vector4 maxf(real_t p_scalar) const { + return Vector4(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar), MAX(w, p_scalar)); + } + _FORCE_INLINE_ real_t length_squared() const; bool is_equal_approx(const Vector4 &p_vec4) const; bool is_zero_approx() const; @@ -103,8 +111,11 @@ struct _NO_DISCARD_ Vector4 { Vector4 posmod(const real_t p_mod) const; Vector4 posmodv(const Vector4 &p_modv) const; void snap(const Vector4 &p_step); + void snapf(real_t p_step); Vector4 snapped(const Vector4 &p_step) const; + Vector4 snappedf(real_t p_step) const; Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const; + Vector4 clampf(real_t p_min, real_t p_max) const; Vector4 inverse() const; _FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const; diff --git a/include/godot_cpp/variant/vector4i.hpp b/include/godot_cpp/variant/vector4i.hpp index 36f2855..8e9510f 100644 --- a/include/godot_cpp/variant/vector4i.hpp +++ b/include/godot_cpp/variant/vector4i.hpp @@ -77,10 +77,18 @@ struct _NO_DISCARD_ Vector4i { return Vector4i(MIN(x, p_vector4i.x), MIN(y, p_vector4i.y), MIN(z, p_vector4i.z), MIN(w, p_vector4i.w)); } + Vector4i mini(int32_t p_scalar) const { + return Vector4i(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar), MIN(w, p_scalar)); + } + Vector4i max(const Vector4i &p_vector4i) const { return Vector4i(MAX(x, p_vector4i.x), MAX(y, p_vector4i.y), MAX(z, p_vector4i.z), MAX(w, p_vector4i.w)); } + Vector4i maxi(int32_t p_scalar) const { + return Vector4i(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar), MAX(w, p_scalar)); + } + _FORCE_INLINE_ int64_t length_squared() const; _FORCE_INLINE_ double length() const; @@ -91,7 +99,10 @@ struct _NO_DISCARD_ Vector4i { _FORCE_INLINE_ Vector4i abs() const; _FORCE_INLINE_ Vector4i sign() const; + Vector4i snapped(const Vector4i &p_step) const; + Vector4i snappedi(int32_t p_step) const; Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const; + Vector4i clampi(int32_t p_min, int32_t p_max) const; /* Operators */ diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index acead8b..d9a8bf9 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -43,6 +43,8 @@ namespace godot { std::unordered_map<StringName, ClassDB::ClassInfo> ClassDB::classes; std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> ClassDB::instance_binding_callbacks; std::vector<StringName> ClassDB::class_register_order; +std::unordered_map<StringName, Object *> ClassDB::engine_singletons; +std::mutex ClassDB::engine_singletons_mutex; GDExtensionInitializationLevel ClassDB::current_level = GDEXTENSION_INITIALIZATION_CORE; MethodDefinition D_METHOD(StringName p_name) { @@ -419,6 +421,22 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { }); class_register_order.erase(it, class_register_order.end()); } + + if (p_level == GDEXTENSION_INITIALIZATION_CORE) { + // Make a new list of the singleton objects, since freeing the instance bindings will lead to + // elements getting removed from engine_singletons. + std::vector<Object *> singleton_objects; + { + std::lock_guard<std::mutex> lock(engine_singletons_mutex); + singleton_objects.reserve(engine_singletons.size()); + for (const std::pair<StringName, Object *> &pair : engine_singletons) { + singleton_objects.push_back(pair.second); + } + } + for (std::vector<Object *>::iterator i = singleton_objects.begin(); i != singleton_objects.end(); i++) { + internal::gdextension_interface_object_free_instance_binding((*i)->_owner, internal::token); + } + } } } // namespace godot diff --git a/src/godot.cpp b/src/godot.cpp index 8a031be..a5cefbf 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -154,6 +154,8 @@ GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_interface_packed GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const = nullptr; GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index = nullptr; GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const = nullptr; +GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed_vector4_array_operator_index = nullptr; +GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const = nullptr; GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index = nullptr; GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const = nullptr; GDExtensionInterfaceArrayRef gdextension_interface_array_ref = nullptr; @@ -166,6 +168,7 @@ GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy = nullptr GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton = nullptr; GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding = nullptr; GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding = nullptr; +GDExtensionInterfaceObjectFreeInstanceBinding gdextension_interface_object_free_instance_binding = nullptr; GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance = nullptr; GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name = nullptr; GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to = nullptr; @@ -196,6 +199,38 @@ GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classd GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path = nullptr; GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin = nullptr; GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin = nullptr; +GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars = nullptr; +GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len = nullptr; + +struct DocData { + const char *hash = nullptr; + int uncompressed_size = 0; + int compressed_size = 0; + const unsigned char *data = nullptr; + + inline bool is_valid() const { + return hash != nullptr && uncompressed_size > 0 && compressed_size > 0 && data != nullptr; + } + + void load_data() const; +}; + +static DocData &get_doc_data() { + static DocData doc_data; + return doc_data; +} + +DocDataRegistration::DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data) { + DocData &doc_data = get_doc_data(); + if (doc_data.is_valid()) { + printf("ERROR: Attempting to register documentation data when we already have some - discarding.\n"); + return; + } + doc_data.hash = p_hash; + doc_data.uncompressed_size = p_uncompressed_size; + doc_data.compressed_size = p_compressed_size; + doc_data.data = p_data; +} } // namespace internal @@ -394,6 +429,8 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(packed_vector2_array_operator_index_const, GDExtensionInterfacePackedVector2ArrayOperatorIndexConst); LOAD_PROC_ADDRESS(packed_vector3_array_operator_index, GDExtensionInterfacePackedVector3ArrayOperatorIndex); LOAD_PROC_ADDRESS(packed_vector3_array_operator_index_const, GDExtensionInterfacePackedVector3ArrayOperatorIndexConst); + LOAD_PROC_ADDRESS(packed_vector4_array_operator_index, GDExtensionInterfacePackedVector4ArrayOperatorIndex); + LOAD_PROC_ADDRESS(packed_vector4_array_operator_index_const, GDExtensionInterfacePackedVector4ArrayOperatorIndexConst); LOAD_PROC_ADDRESS(array_operator_index, GDExtensionInterfaceArrayOperatorIndex); LOAD_PROC_ADDRESS(array_operator_index_const, GDExtensionInterfaceArrayOperatorIndexConst); LOAD_PROC_ADDRESS(array_ref, GDExtensionInterfaceArrayRef); @@ -406,6 +443,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(global_get_singleton, GDExtensionInterfaceGlobalGetSingleton); LOAD_PROC_ADDRESS(object_get_instance_binding, GDExtensionInterfaceObjectGetInstanceBinding); LOAD_PROC_ADDRESS(object_set_instance_binding, GDExtensionInterfaceObjectSetInstanceBinding); + LOAD_PROC_ADDRESS(object_free_instance_binding, GDExtensionInterfaceObjectFreeInstanceBinding); LOAD_PROC_ADDRESS(object_set_instance, GDExtensionInterfaceObjectSetInstance); LOAD_PROC_ADDRESS(object_get_class_name, GDExtensionInterfaceObjectGetClassName); LOAD_PROC_ADDRESS(object_cast_to, GDExtensionInterfaceObjectCastTo); @@ -436,6 +474,8 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(get_library_path, GDExtensionInterfaceGetLibraryPath); LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin); LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin); + LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars); + LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars_and_len, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen); r_initialization->initialize = initialize_level; r_initialization->deinitialize = deinitialize_level; @@ -465,6 +505,13 @@ void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializ ClassDB::initialize(p_level); } level_initialized[p_level]++; + + if ((ModuleInitializationLevel)p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + const internal::DocData &doc_data = internal::get_doc_data(); + if (doc_data.is_valid()) { + doc_data.load_data(); + } + } } void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) { @@ -531,4 +578,15 @@ GDExtensionBool GDExtensionBinding::InitObject::init() const { return GDExtensionBinding::init(get_proc_address, library, init_data, initialization); } +void internal::DocData::load_data() const { + PackedByteArray compressed; + compressed.resize(compressed_size); + memcpy(compressed.ptrw(), data, compressed_size); + + // FileAccess::COMPRESSION_DEFLATE = 1 + PackedByteArray decompressed = compressed.decompress(uncompressed_size, 1); + + internal::gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len(reinterpret_cast<const char *>(decompressed.ptr()), uncompressed_size); +} + } // namespace godot diff --git a/src/variant/packed_arrays.cpp b/src/variant/packed_arrays.cpp index fe8b359..4384f7a 100644 --- a/src/variant/packed_arrays.cpp +++ b/src/variant/packed_arrays.cpp @@ -43,6 +43,7 @@ #include <godot_cpp/variant/packed_string_array.hpp> #include <godot_cpp/variant/packed_vector2_array.hpp> #include <godot_cpp/variant/packed_vector3_array.hpp> +#include <godot_cpp/variant/packed_vector4_array.hpp> namespace godot { @@ -198,6 +199,24 @@ Vector3 *PackedVector3Array::ptrw() { return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0); } +const Vector4 &PackedVector4Array::operator[](int64_t p_index) const { + const Vector4 *vec = (const Vector4 *)internal::gdextension_interface_packed_vector4_array_operator_index_const((GDExtensionTypePtr *)this, p_index); + return *vec; +} + +Vector4 &PackedVector4Array::operator[](int64_t p_index) { + Vector4 *vec = (Vector4 *)internal::gdextension_interface_packed_vector4_array_operator_index((GDExtensionTypePtr *)this, p_index); + return *vec; +} + +const Vector4 *PackedVector4Array::ptr() const { + return (const Vector4 *)internal::gdextension_interface_packed_vector4_array_operator_index_const((GDExtensionTypePtr *)this, 0); +} + +Vector4 *PackedVector4Array::ptrw() { + return (Vector4 *)internal::gdextension_interface_packed_vector4_array_operator_index((GDExtensionTypePtr *)this, 0); +} + const Variant &Array::operator[](int64_t p_index) const { const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *var; diff --git a/src/variant/vector2.cpp b/src/variant/vector2.cpp index ca1ab8f..12201f1 100644 --- a/src/variant/vector2.cpp +++ b/src/variant/vector2.cpp @@ -137,12 +137,24 @@ Vector2 Vector2::clamp(const Vector2 &p_min, const Vector2 &p_max) const { CLAMP(y, p_min.y, p_max.y)); } +Vector2 Vector2::clampf(real_t p_min, real_t p_max) const { + return Vector2( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max)); +} + Vector2 Vector2::snapped(const Vector2 &p_step) const { return Vector2( Math::snapped(x, p_step.x), Math::snapped(y, p_step.y)); } +Vector2 Vector2::snappedf(real_t p_step) const { + return Vector2( + Math::snapped(x, p_step), + Math::snapped(y, p_step)); +} + Vector2 Vector2::limit_length(const real_t p_len) const { const real_t l = length(); Vector2 v = *this; diff --git a/src/variant/vector2i.cpp b/src/variant/vector2i.cpp index c1c1ab0..4baff3b 100644 --- a/src/variant/vector2i.cpp +++ b/src/variant/vector2i.cpp @@ -35,12 +35,30 @@ namespace godot { +Vector2i Vector2i::snapped(const Vector2i &p_step) const { + return Vector2i( + Math::snapped(x, p_step.x), + Math::snapped(y, p_step.y)); +} + +Vector2i Vector2i::snappedi(int32_t p_step) const { + return Vector2i( + Math::snapped(x, p_step), + Math::snapped(y, p_step)); +} + Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const { return Vector2i( CLAMP(x, p_min.x, p_max.x), CLAMP(y, p_min.y, p_max.y)); } +Vector2i Vector2i::clampi(int32_t p_min, int32_t p_max) const { + return Vector2i( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max)); +} + int64_t Vector2i::length_squared() const { return x * (int64_t)x + y * (int64_t)y; } diff --git a/src/variant/vector3.cpp b/src/variant/vector3.cpp index 9f04340..d2ad6a9 100644 --- a/src/variant/vector3.cpp +++ b/src/variant/vector3.cpp @@ -54,18 +54,37 @@ Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const { CLAMP(z, p_min.z, p_max.z)); } +Vector3 Vector3::clampf(real_t p_min, real_t p_max) const { + return Vector3( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max), + CLAMP(z, p_min, p_max)); +} + void Vector3::snap(const Vector3 p_step) { x = Math::snapped(x, p_step.x); y = Math::snapped(y, p_step.y); z = Math::snapped(z, p_step.z); } +void Vector3::snapf(real_t p_step) { + x = Math::snapped(x, p_step); + y = Math::snapped(y, p_step); + z = Math::snapped(z, p_step); +} + Vector3 Vector3::snapped(const Vector3 p_step) const { Vector3 v = *this; v.snap(p_step); return v; } +Vector3 Vector3::snappedf(real_t p_step) const { + Vector3 v = *this; + v.snapf(p_step); + return v; +} + Vector3 Vector3::limit_length(const real_t p_len) const { const real_t l = length(); Vector3 v = *this; diff --git a/src/variant/vector3i.cpp b/src/variant/vector3i.cpp index eef05b8..7b25d89 100644 --- a/src/variant/vector3i.cpp +++ b/src/variant/vector3i.cpp @@ -35,6 +35,20 @@ namespace godot { +Vector3i Vector3i::snapped(const Vector3i &p_step) const { + return Vector3i( + Math::snapped(x, p_step.x), + Math::snapped(y, p_step.y), + Math::snapped(z, p_step.z)); +} + +Vector3i Vector3i::snappedi(int32_t p_step) const { + return Vector3i( + Math::snapped(x, p_step), + Math::snapped(y, p_step), + Math::snapped(z, p_step)); +} + Vector3i::Axis Vector3i::min_axis_index() const { return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z); } @@ -50,6 +64,13 @@ Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { CLAMP(z, p_min.z, p_max.z)); } +Vector3i Vector3i::clampi(int32_t p_min, int32_t p_max) const { + return Vector3i( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max), + CLAMP(z, p_min, p_max)); +} + Vector3i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; } diff --git a/src/variant/vector4.cpp b/src/variant/vector4.cpp index 483545e..2f1bb59 100644 --- a/src/variant/vector4.cpp +++ b/src/variant/vector4.cpp @@ -173,12 +173,25 @@ void Vector4::snap(const Vector4 &p_step) { w = Math::snapped(w, p_step.w); } +void Vector4::snapf(real_t p_step) { + x = Math::snapped(x, p_step); + y = Math::snapped(y, p_step); + z = Math::snapped(z, p_step); + w = Math::snapped(w, p_step); +} + Vector4 Vector4::snapped(const Vector4 &p_step) const { Vector4 v = *this; v.snap(p_step); return v; } +Vector4 Vector4::snappedf(real_t p_step) const { + Vector4 v = *this; + v.snapf(p_step); + return v; +} + Vector4 Vector4::inverse() const { return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w); } @@ -191,6 +204,14 @@ Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const { CLAMP(w, p_min.w, p_max.w)); } +Vector4 Vector4::clampf(real_t p_min, real_t p_max) const { + return Vector4( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max), + CLAMP(z, p_min, p_max), + CLAMP(w, p_min, p_max)); +} + Vector4::operator String() const { return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } diff --git a/src/variant/vector4i.cpp b/src/variant/vector4i.cpp index f1817dc..b0e330c 100644 --- a/src/variant/vector4i.cpp +++ b/src/variant/vector4i.cpp @@ -35,6 +35,22 @@ namespace godot { +Vector4i Vector4i::snapped(const Vector4i &p_step) const { + return Vector4i( + Math::snapped(x, p_step.x), + Math::snapped(y, p_step.y), + Math::snapped(z, p_step.z), + Math::snapped(w, p_step.w)); +} + +Vector4i Vector4i::snappedi(int32_t p_step) const { + return Vector4i( + Math::snapped(x, p_step), + Math::snapped(y, p_step), + Math::snapped(z, p_step), + Math::snapped(w, p_step)); +} + Vector4i::Axis Vector4i::min_axis_index() const { uint32_t min_index = 0; int32_t min_value = x; @@ -67,6 +83,14 @@ Vector4i Vector4i::clamp(const Vector4i &p_min, const Vector4i &p_max) const { CLAMP(w, p_min.w, p_max.w)); } +Vector4i Vector4i::clampi(int32_t p_min, int32_t p_max) const { + return Vector4i( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max), + CLAMP(z, p_min, p_max), + CLAMP(w, p_min, p_max)); +} + Vector4i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")"; } diff --git a/test/SConstruct b/test/SConstruct index 9c25917..7cb25be 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -16,6 +16,10 @@ env = SConscript("../SConstruct") env.Append(CPPPATH=["src/"]) sources = Glob("src/*.cpp") +if env["target"] in ["editor", "template_debug"]: + doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml")) + sources.append(doc_data) + if env["platform"] == "macos": library = env.SharedLibrary( "project/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format( diff --git a/test/doc_classes/Example.xml b/test/doc_classes/Example.xml new file mode 100644 index 0000000..457709d --- /dev/null +++ b/test/doc_classes/Example.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="Example" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd"> + <brief_description> + A test control defined in GDExtension. + </brief_description> + <description> + A control used for the automated GDExtension tests. + </description> + <tutorials> + </tutorials> + <methods> + <method name="simple_func"> + <return type="void" /> + <description> + Tests a simple function call. + </description> + </method> + </methods> + <members> + </members> + <signals> + </signals> + <constants> + </constants> +</class> diff --git a/test/project/main.gd b/test/project/main.gd index 0cfba19..665582f 100644 --- a/test/project/main.gd +++ b/test/project/main.gd @@ -256,6 +256,9 @@ func _ready(): assert_equal(example.test_virtual_implemented_in_script("Virtual", 939), "Implemented") assert_equal(custom_signal_emitted, ["Virtual", 939]) + # Test that we can access an engine singleton. + assert_equal(example.test_use_engine_singleton(), OS.get_name()) + # Test that notifications happen on both parent and child classes. var example_child = $ExampleChild assert_equal(example_child.get_value1(), 11) diff --git a/test/project/project.godot b/test/project/project.godot index 4f51c07..df3dd70 100644 --- a/test/project/project.godot +++ b/test/project/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="GDExtension Test Project" run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.2") +config/features=PackedStringArray("4.3") config/icon="res://icon.png" [native_extensions] diff --git a/test/src/example.cpp b/test/src/example.cpp index 3ec8bca..78d7062 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -11,6 +11,7 @@ #include <godot_cpp/classes/label.hpp> #include <godot_cpp/classes/multiplayer_api.hpp> #include <godot_cpp/classes/multiplayer_peer.hpp> +#include <godot_cpp/classes/os.hpp> #include <godot_cpp/variant/utility_functions.hpp> using namespace godot; @@ -239,6 +240,8 @@ void Example::_bind_methods() { GDVIRTUAL_BIND(_do_something_virtual, "name", "value"); ClassDB::bind_method(D_METHOD("test_virtual_implemented_in_script"), &Example::test_virtual_implemented_in_script); + ClassDB::bind_method(D_METHOD("test_use_engine_singleton"), &Example::test_use_engine_singleton); + ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static); ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2); @@ -671,6 +674,10 @@ String Example::test_virtual_implemented_in_script(const String &p_name, int p_v return "Unimplemented"; } +String Example::test_use_engine_singleton() const { + return OS::get_singleton()->get_name(); +} + void ExampleRuntime::_bind_methods() { ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleRuntime::set_prop_value); ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleRuntime::get_prop_value); diff --git a/test/src/example.h b/test/src/example.h index 0ad9493..1af4e5f 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -186,6 +186,8 @@ public: GDVIRTUAL2R(String, _do_something_virtual, String, int); String test_virtual_implemented_in_script(const String &p_name, int p_value); + + String test_use_engine_singleton() const; }; VARIANT_ENUM_CAST(Example::Constants); diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 13a57e9..2e61e2b 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -325,6 +325,51 @@ def options(opts, env): tool.options(opts) +def make_doc_source(target, source, env): + import zlib + + dst = str(target[0]) + g = open(dst, "w", encoding="utf-8") + buf = "" + docbegin = "" + docend = "" + for src in source: + src_path = str(src) + if not src_path.endswith(".xml"): + continue + with open(src_path, "r", encoding="utf-8") as f: + content = f.read() + buf += content + + buf = (docbegin + buf + docend).encode("utf-8") + decomp_size = len(buf) + + # Use maximum zlib compression level to further reduce file size + # (at the cost of initial build times). + buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("\n") + g.write("#include <godot_cpp/godot.hpp>\n") + g.write("\n") + + g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n') + g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n") + g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n") + g.write("static const unsigned char _doc_data_compressed[] = {\n") + for i in range(len(buf)): + g.write("\t" + str(buf[i]) + ",\n") + g.write("};\n") + g.write("\n") + + g.write( + "static godot::internal::DocDataRegistration _doc_data_registration(_doc_data_hash, _doc_data_uncompressed_size, _doc_data_compressed_size, _doc_data_compressed);\n" + ) + g.write("\n") + + g.close() + + def generate(env): # Default num_jobs to local cpu count if not user specified. # SCons has a peculiarity where user-specified options won't be overridden @@ -451,7 +496,8 @@ def generate(env): # Builders env.Append( BUILDERS={ - "GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files) + "GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files), + "GodotCPPDocData": Builder(action=make_doc_source), } ) env.AddMethod(_godot_cpp, "GodotCPP") |