Merge pull request #1466 from dsnopek/4.1-cherrypicks-10

Cherry-picks for the godot-cpp 4.1 branch - 10th batch
4.1
David Snopek 2024-05-28 08:35:20 -05:00 committed by GitHub
commit 32becf6a13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 272 additions and 27 deletions

View File

@ -178,6 +178,10 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
generate_utility_functions(api, target_dir) generate_utility_functions(api, target_dir)
CLASS_ALIASES = {
"ClassDB": "ClassDBSingleton",
}
builtin_classes = [] builtin_classes = []
# Key is class name, value is boolean where True means the class is refcounted. # Key is class name, value is boolean where True means the class is refcounted.
@ -1079,9 +1083,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
# First create map of classes and singletons. # First create map of classes and singletons.
for class_api in api["classes"]: for class_api in api["classes"]:
# Generate code for the ClassDB singleton under a different name. # Generate code for the ClassDB singleton under a different name.
if class_api["name"] == "ClassDB": if class_api["name"] in CLASS_ALIASES:
class_api["name"] = "ClassDBSingleton" class_api["alias_for"] = class_api["name"]
class_api["alias_for"] = "ClassDB" class_api["name"] = CLASS_ALIASES[class_api["alias_for"]]
engine_classes[class_api["name"]] = class_api["is_refcounted"] engine_classes[class_api["name"]] = class_api["is_refcounted"]
for native_struct in api["native_structures"]: for native_struct in api["native_structures"]:
engine_classes[native_struct["name"]] = False engine_classes[native_struct["name"]] = False
@ -1089,9 +1093,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
for singleton in api["singletons"]: for singleton in api["singletons"]:
# Generate code for the ClassDB singleton under a different name. # Generate code for the ClassDB singleton under a different name.
if singleton["name"] == "ClassDB": if singleton["name"] in CLASS_ALIASES:
singleton["name"] = "ClassDBSingleton" singleton["alias_for"] = singleton["name"]
singleton["alias_for"] = "ClassDB" singleton["name"] = CLASS_ALIASES[singleton["name"]]
singletons.append(singleton["name"]) singletons.append(singleton["name"])
for class_api in api["classes"]: for class_api in api["classes"]:
@ -1294,6 +1298,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("#include <type_traits>") result.append("#include <type_traits>")
result.append("") result.append("")
if class_name == "ClassDBSingleton":
result.append("#include <godot_cpp/core/binder_common.hpp>")
result.append("")
result.append("namespace godot {") result.append("namespace godot {")
result.append("") result.append("")
@ -1448,6 +1456,19 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
if class_name == "ClassDBSingleton": if class_name == "ClassDBSingleton":
result.append("#define CLASSDB_SINGLETON_FORWARD_METHODS \\") result.append("#define CLASSDB_SINGLETON_FORWARD_METHODS \\")
if "enums" in class_api:
for enum_api in class_api["enums"]:
if enum_api["is_bitfield"]:
result.append(f'\tenum {enum_api["name"]} : uint64_t {{ \\')
else:
result.append(f'\tenum {enum_api["name"]} {{ \\')
for value in enum_api["values"]:
result.append(f'\t\t{value["name"]} = {value["value"]}, \\')
result.append("\t}; \\")
result.append("\t \\")
for method in class_api["methods"]: for method in class_api["methods"]:
# ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them. # ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them.
if vararg: if vararg:
@ -1456,12 +1477,17 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
continue continue
method_signature = "\tstatic " method_signature = "\tstatic "
return_type = None
if "return_type" in method: if "return_type" in method:
method_signature += f'{correct_type(method["return_type"])} ' return_type = correct_type(method["return_type"].replace("ClassDBSingleton", "ClassDB"), None, False)
elif "return_value" in method: elif "return_value" in method:
method_signature += ( return_type = correct_type(
correct_type(method["return_value"]["type"], method["return_value"].get("meta", None)) + " " method["return_value"]["type"].replace("ClassDBSingleton", "ClassDB"),
method["return_value"].get("meta", None),
False,
) )
if return_type is not None:
method_signature += return_type + " "
else: else:
method_signature += "void " method_signature += "void "
@ -1480,8 +1506,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append(method_signature) result.append(method_signature)
method_body = "\t\t" method_body = "\t\t"
if "return_type" in method or "return_value" in method: if return_type is not None:
method_body += "return " method_body += "return "
if "alias_for" in class_api and return_type.startswith(class_api["alias_for"] + "::"):
method_body += f"({return_type})"
method_body += f'ClassDBSingleton::get_singleton()->{method["name"]}(' method_body += f'ClassDBSingleton::get_singleton()->{method["name"]}('
method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments)) method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments))
method_body += "); \\" method_body += "); \\"
@ -1491,6 +1519,18 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("\t;") result.append("\t;")
result.append("") result.append("")
result.append("#define CLASSDB_SINGLETON_VARIANT_CAST \\")
if "enums" in class_api:
for enum_api in class_api["enums"]:
if enum_api["is_bitfield"]:
result.append(f'\tVARIANT_BITFIELD_CAST({class_api["alias_for"]}::{enum_api["name"]}); \\')
else:
result.append(f'\tVARIANT_ENUM_CAST({class_api["alias_for"]}::{enum_api["name"]}); \\')
result.append("\t;")
result.append("")
result.append(f"#endif // ! {header_guard}") result.append(f"#endif // ! {header_guard}")
return "\n".join(result) return "\n".join(result)
@ -2285,7 +2325,7 @@ def correct_typed_array(type_name):
return type_name return type_name
def correct_type(type_name, meta=None): def correct_type(type_name, meta=None, use_alias=True):
type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"} type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"}
if meta != None: if meta != None:
if "int" in meta: if "int" in meta:
@ -2301,11 +2341,15 @@ def correct_type(type_name, meta=None):
if is_enum(type_name): if is_enum(type_name):
if is_bitfield(type_name): if is_bitfield(type_name):
base_class = get_enum_class(type_name) base_class = get_enum_class(type_name)
if use_alias and base_class in CLASS_ALIASES:
base_class = CLASS_ALIASES[base_class]
if base_class == "GlobalConstants": if base_class == "GlobalConstants":
return f"BitField<{get_enum_name(type_name)}>" return f"BitField<{get_enum_name(type_name)}>"
return f"BitField<{base_class}::{get_enum_name(type_name)}>" return f"BitField<{base_class}::{get_enum_name(type_name)}>"
else: else:
base_class = get_enum_class(type_name) base_class = get_enum_class(type_name)
if use_alias and base_class in CLASS_ALIASES:
base_class = CLASS_ALIASES[base_class]
if base_class == "GlobalConstants": if base_class == "GlobalConstants":
return f"{get_enum_name(type_name)}" return f"{get_enum_name(type_name)}"
return f"{base_class}::{get_enum_name(type_name)}" return f"{base_class}::{get_enum_name(type_name)}"

View File

@ -76,14 +76,15 @@ protected:
uint32_t plist_size = 0; uint32_t plist_size = 0;
void _postinitialize(); void _postinitialize();
virtual void _notificationv(int32_t p_what) {}
Wrapped(const StringName p_godot_class); Wrapped(const StringName p_godot_class);
Wrapped(GodotObject *p_godot_object); Wrapped(GodotObject *p_godot_object);
virtual ~Wrapped() {} virtual ~Wrapped() {}
public: public:
static StringName &get_class_static() { static const StringName &get_class_static() {
static StringName string_name = StringName("Wrapped"); static const StringName string_name = StringName("Wrapped");
return string_name; return string_name;
} }
@ -171,6 +172,7 @@ protected:
\ \
public: \ public: \
typedef m_class self_type; \ typedef m_class self_type; \
typedef m_inherits parent_type; \
\ \
static void initialize_class() { \ static void initialize_class() { \
static bool initialized = false; \ static bool initialized = false; \
@ -185,12 +187,12 @@ public:
initialized = true; \ initialized = true; \
} \ } \
\ \
static ::godot::StringName &get_class_static() { \ static const ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_class); \ static const ::godot::StringName string_name = ::godot::StringName(#m_class); \
return string_name; \ return string_name; \
} \ } \
\ \
static ::godot::StringName &get_parent_class_static() { \ static const ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \ return m_inherits::get_class_static(); \
} \ } \
\ \
@ -327,6 +329,11 @@ public:
_gde_binding_reference_callback, \ _gde_binding_reference_callback, \
}; \ }; \
\ \
protected: \
virtual void _notificationv(int32_t p_what) override { \
m_class::notification_bind(this, p_what); \
} \
\
private: private:
// Don't use this for your classes, use GDCLASS() instead. // Don't use this for your classes, use GDCLASS() instead.
@ -334,6 +341,7 @@ private:
private: \ private: \
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \ inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
void operator=(const m_class &p_rval) {} \ void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
\ \
protected: \ protected: \
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
@ -343,6 +351,8 @@ protected:
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \ m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \ m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\ \
static void _bind_methods() {} \
\
static void (*_get_bind_methods())() { \ static void (*_get_bind_methods())() { \
return nullptr; \ return nullptr; \
} \ } \
@ -385,15 +395,16 @@ protected:
\ \
public: \ public: \
typedef m_class self_type; \ typedef m_class self_type; \
typedef m_inherits parent_type; \
\ \
static void initialize_class() {} \ static void initialize_class() {} \
\ \
static ::godot::StringName &get_class_static() { \ static const ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \ static const ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
return string_name; \ return string_name; \
} \ } \
\ \
static ::godot::StringName &get_parent_class_static() { \ static const ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \ return m_inherits::get_class_static(); \
} \ } \
\ \

View File

@ -174,6 +174,8 @@ public:
template <typename T, bool is_abstract> template <typename T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual) { void ClassDB::_register_class(bool p_virtual) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS."); static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
static_assert(!FunctionsAreSame<T::self_type::_bind_methods, T::parent_type::_bind_methods>::value, "Class must declare 'static void _bind_methods'.");
static_assert(!std::is_abstract_v<T> || is_abstract, "Class is abstract, please use GDREGISTER_ABSTRACT_CLASS.");
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks; instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
// Register this class within our plugin // Register this class within our plugin
@ -290,4 +292,6 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
} // namespace godot } // namespace godot
CLASSDB_SINGLETON_VARIANT_CAST;
#endif // GODOT_CLASS_DB_HPP #endif // GODOT_CLASS_DB_HPP

View File

@ -613,6 +613,14 @@ inline bool is_inf(double p_val) {
return std::isinf(p_val); return std::isinf(p_val);
} }
inline bool is_finite(float p_val) {
return std::isfinite(p_val);
}
inline bool is_finite(double p_val) {
return std::isfinite(p_val);
}
inline bool is_equal_approx(float a, float b) { inline bool is_equal_approx(float a, float b) {
// Check for exact equality first, required to handle "infinity" values. // Check for exact equality first, required to handle "infinity" values.
if (a == b) { if (a == b) {

View File

@ -412,6 +412,7 @@ public:
method = p_method; method = p_method;
generate_argument_types(sizeof...(P)); generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P)); set_argument_count(sizeof...(P));
set_const(true);
} }
}; };
@ -578,6 +579,7 @@ public:
generate_argument_types(sizeof...(P)); generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P)); set_argument_count(sizeof...(P));
set_return(true); set_return(true);
set_const(true);
} }
}; };

View File

@ -170,11 +170,11 @@ template <typename T>
struct PtrToArg<T *> { struct PtrToArg<T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object"); static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static T *convert(const void *p_ptr) { _FORCE_INLINE_ static T *convert(const void *p_ptr) {
return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))); return likely(p_ptr) ? reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
} }
typedef Object *EncodeT; typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr; *reinterpret_cast<const void **>(p_ptr) = likely(p_var) ? p_var->_owner : nullptr;
} }
}; };
@ -182,11 +182,11 @@ template <typename T>
struct PtrToArg<const T *> { struct PtrToArg<const T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object"); static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static const T *convert(const void *p_ptr) { _FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))); return likely(p_ptr) ? reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
} }
typedef const Object *EncodeT; typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr; *reinterpret_cast<const void **>(p_ptr) = likely(p_var) ? p_var->_owner : nullptr;
} }
}; };

View File

@ -68,6 +68,63 @@ struct PropertyInfo {
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") : PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {} PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
PropertyInfo(const GDExtensionPropertyInfo *p_info) :
PropertyInfo(p_info->type, *reinterpret_cast<StringName *>(p_info->name), (PropertyHint)p_info->hint, *reinterpret_cast<String *>(p_info->hint_string), p_info->usage, *reinterpret_cast<StringName *>(p_info->class_name)) {}
operator Dictionary() const {
Dictionary dict;
dict["name"] = name;
dict["class_name"] = class_name;
dict["type"] = type;
dict["hint"] = hint;
dict["hint_string"] = hint_string;
dict["usage"] = usage;
return dict;
}
static PropertyInfo from_dict(const Dictionary &p_dict) {
PropertyInfo pi;
if (p_dict.has("type")) {
pi.type = Variant::Type(int(p_dict["type"]));
}
if (p_dict.has("name")) {
pi.name = p_dict["name"];
}
if (p_dict.has("class_name")) {
pi.class_name = p_dict["class_name"];
}
if (p_dict.has("hint")) {
pi.hint = PropertyHint(int(p_dict["hint"]));
}
if (p_dict.has("hint_string")) {
pi.hint_string = p_dict["hint_string"];
}
if (p_dict.has("usage")) {
pi.usage = p_dict["usage"];
}
return pi;
}
void _update(GDExtensionPropertyInfo *p_info) {
p_info->type = (GDExtensionVariantType)type;
*(reinterpret_cast<StringName *>(p_info->name)) = name;
p_info->hint = hint;
*(reinterpret_cast<String *>(p_info->hint_string)) = hint_string;
p_info->usage = usage;
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
}
GDExtensionPropertyInfo _to_gdextension() const {
return {
(GDExtensionVariantType)type,
name._native_ptr(),
class_name._native_ptr(),
hint,
hint_string._native_ptr(),
usage,
};
}
}; };
} // namespace godot } // namespace godot

View File

@ -58,6 +58,16 @@ struct TypesAreSame<A, A> {
static bool const value = true; static bool const value = true;
}; };
template <auto A, auto B>
struct FunctionsAreSame {
static bool const value = false;
};
template <auto A>
struct FunctionsAreSame<A, A> {
static bool const value = true;
};
template <typename B, typename D> template <typename B, typename D>
struct TypeInherits { struct TypeInherits {
static D *get_d(); static D *get_d();

View File

@ -65,6 +65,7 @@ struct _NO_DISCARD_ AABB {
bool operator!=(const AABB &p_rval) const; bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const; bool is_equal_approx(const AABB &p_aabb) const;
bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap _FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap _FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this _FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this

View File

@ -128,6 +128,7 @@ struct _NO_DISCARD_ Basis {
} }
bool is_equal_approx(const Basis &p_basis) const; bool is_equal_approx(const Basis &p_basis) const;
bool is_finite() const;
bool operator==(const Basis &p_matrix) const; bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const; bool operator!=(const Basis &p_matrix) const;

View File

@ -77,6 +77,7 @@ struct _NO_DISCARD_ Plane {
Plane operator-() const { return Plane(-normal, -d); } Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const; bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const; bool is_equal_approx_any_side(const Plane &p_plane) const;
bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const; _FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const; _FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;

View File

@ -55,6 +55,7 @@ struct _NO_DISCARD_ Quaternion {
} }
_FORCE_INLINE_ real_t length_squared() const; _FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const; bool is_equal_approx(const Quaternion &p_quaternion) const;
bool is_finite() const;
real_t length() const; real_t length() const;
void normalize(); void normalize();
Quaternion normalized() const; Quaternion normalized() const;

View File

@ -209,6 +209,7 @@ struct _NO_DISCARD_ Rect2 {
} }
bool is_equal_approx(const Rect2 &p_rect) const; bool is_equal_approx(const Rect2 &p_rect) const;
bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }

View File

@ -99,6 +99,7 @@ struct _NO_DISCARD_ Transform2D {
void orthonormalize(); void orthonormalize();
Transform2D orthonormalized() const; Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const; bool is_equal_approx(const Transform2D &p_transform) const;
bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const; Transform2D looking_at(const Vector2 &p_target) const;

View File

@ -78,6 +78,7 @@ struct _NO_DISCARD_ Transform3D {
void orthogonalize(); void orthogonalize();
Transform3D orthogonalized() const; Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const; bool is_equal_approx(const Transform3D &p_transform) const;
bool is_finite() const;
bool operator==(const Transform3D &p_transform) const; bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const; bool operator!=(const Transform3D &p_transform) const;

View File

@ -123,6 +123,7 @@ struct _NO_DISCARD_ Vector2 {
bool is_equal_approx(const Vector2 &p_v) const; bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const; bool is_zero_approx() const;
bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const; Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v); void operator+=(const Vector2 &p_v);

View File

@ -146,6 +146,7 @@ struct _NO_DISCARD_ Vector3 {
bool is_equal_approx(const Vector3 &p_v) const; bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const; bool is_zero_approx() const;
bool is_finite() const;
/* Operators */ /* Operators */

View File

@ -81,6 +81,7 @@ struct _NO_DISCARD_ Vector4 {
_FORCE_INLINE_ real_t length_squared() const; _FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const; bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const; bool is_zero_approx() const;
bool is_finite() const;
real_t length() const; real_t length() const;
void normalize(); void normalize();
Vector4 normalized() const; Vector4 normalized() const;

View File

@ -51,10 +51,7 @@ void Wrapped::_postinitialize() {
} }
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks()); godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
if (extension_class) { if (extension_class) {
Object *obj = dynamic_cast<Object *>(this); _notificationv(Object::NOTIFICATION_POSTINITIALIZE);
if (obj) {
obj->notification(Object::NOTIFICATION_POSTINITIALIZE);
}
} }
} }

View File

@ -60,8 +60,66 @@ Object *get_object_instance_binding(GodotObject *p_engine_object) {
return reinterpret_cast<Object *>(gdextension_interface_object_get_instance_binding(p_engine_object, token, binding_callbacks)); return reinterpret_cast<Object *>(gdextension_interface_object_get_instance_binding(p_engine_object, token, binding_callbacks));
} }
TypedArray<Dictionary> convert_property_list(const std::vector<PropertyInfo> &p_list) {
TypedArray<Dictionary> va;
for (const PropertyInfo &pi : p_list) {
va.push_back(Dictionary(pi));
}
return va;
}
} // namespace internal } // namespace internal
MethodInfo::operator Dictionary() const {
Dictionary dict;
dict["name"] = name;
dict["args"] = internal::convert_property_list(arguments);
Array da;
for (int i = 0; i < default_arguments.size(); i++) {
da.push_back(default_arguments[i]);
}
dict["default_args"] = da;
dict["flags"] = flags;
dict["id"] = id;
Dictionary r = return_val;
dict["return"] = r;
return dict;
}
MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
MethodInfo mi;
if (p_dict.has("name")) {
mi.name = p_dict["name"];
}
Array args;
if (p_dict.has("args")) {
args = p_dict["args"];
}
for (int i = 0; i < args.size(); i++) {
Dictionary d = args[i];
mi.arguments.push_back(PropertyInfo::from_dict(d));
}
Array defargs;
if (p_dict.has("default_args")) {
defargs = p_dict["default_args"];
}
for (int i = 0; i < defargs.size(); i++) {
mi.default_arguments.push_back(defargs[i]);
}
if (p_dict.has("return")) {
mi.return_val = PropertyInfo::from_dict(p_dict["return"]);
}
if (p_dict.has("flags")) {
mi.flags = p_dict["flags"];
}
return mi;
}
MethodInfo::MethodInfo() : MethodInfo::MethodInfo() :
flags(GDEXTENSION_METHOD_FLAG_NORMAL) {} flags(GDEXTENSION_METHOD_FLAG_NORMAL) {}

View File

@ -78,6 +78,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size); return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
} }
bool AABB::is_finite() const {
return position.is_finite() && size.is_finite();
}
AABB AABB::intersection(const AABB &p_aabb) const { AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS #ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) { if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {

View File

@ -692,6 +692,10 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]); return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
} }
bool Basis::is_finite() const {
return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite();
}
bool Basis::operator==(const Basis &p_matrix) const { bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {

View File

@ -178,6 +178,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d); return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
} }
bool Plane::is_finite() const {
return normal.is_finite() && Math::is_finite(d);
}
Plane::operator String() const { Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]"; return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
} }

View File

@ -81,6 +81,10 @@ bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w); return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
} }
bool Quaternion::is_finite() const {
return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
}
real_t Quaternion::length() const { real_t Quaternion::length() const {
return Math::sqrt(length_squared()); return Math::sqrt(length_squared());
} }

View File

@ -40,6 +40,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size); return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
} }
bool Rect2::is_finite() const {
return position.is_finite() && size.is_finite();
}
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const { bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS #ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) { if (unlikely(size.x < 0 || size.y < 0)) {

View File

@ -170,6 +170,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]); return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
} }
bool Transform2D::is_finite() const {
return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite();
}
Transform2D Transform2D::looking_at(const Vector2 &p_target) const { Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin()); Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target); Vector2 target_position = affine_inverse().xform(p_target);

View File

@ -175,6 +175,10 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
} }
bool Transform3D::is_finite() const {
return basis.is_finite() && origin.is_finite();
}
bool Transform3D::operator==(const Transform3D &p_transform) const { bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin); return (basis == p_transform.basis && origin == p_transform.origin);
} }

View File

@ -188,6 +188,10 @@ bool Vector2::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y); return Math::is_zero_approx(x) && Math::is_zero_approx(y);
} }
bool Vector2::is_finite() const {
return Math::is_finite(x) && Math::is_finite(y);
}
Vector2::operator String() const { Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")"; return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
} }

View File

@ -141,6 +141,10 @@ bool Vector3::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z); return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
} }
bool Vector3::is_finite() const {
return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z);
}
Vector3::operator String() const { Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")"; return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
} }

View File

@ -67,6 +67,10 @@ bool Vector4::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w); return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
} }
bool Vector4::is_finite() const {
return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
}
real_t Vector4::length() const { real_t Vector4::length() const {
return Math::sqrt(length_squared()); return Math::sqrt(length_squared());
} }

View File

@ -122,6 +122,10 @@ func _ready():
control.queue_free() control.queue_free()
sprite.queue_free() sprite.queue_free()
# Test that passing null for objects works as expected too.
var example_null : Example = null
assert_equal(example.test_object_cast_to_node(example_null), false)
# Test conversions to and from Variant. # Test conversions to and from Variant.
assert_equal(example.test_variant_vector2i_conversion(Vector2i(1, 1)), Vector2i(1, 1)) assert_equal(example.test_variant_vector2i_conversion(Vector2i(1, 1)), Vector2i(1, 1))
assert_equal(example.test_variant_vector2i_conversion(Vector2(1.0, 1.0)), Vector2i(1, 1)) assert_equal(example.test_variant_vector2i_conversion(Vector2(1.0, 1.0)), Vector2i(1, 1))