From 6528c7177fa96bfcc81805e97a0a03290816cb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=A1=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= Date: Thu, 8 Dec 2022 08:34:19 +0300 Subject: [PATCH] Fixed variant casting for enum and bitfield --- binding_generator.py | 8 +-- include/godot_cpp/core/binder_common.hpp | 76 ++++++++++++------------ include/godot_cpp/core/type_info.hpp | 52 +++++++++------- test/demo/main.gd | 6 ++ test/src/example.cpp | 11 ++++ test/src/example.h | 15 ++++- 6 files changed, 104 insertions(+), 64 deletions(-) diff --git a/binding_generator.py b/binding_generator.py index 9919b735..dca2384a 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -336,7 +336,7 @@ def generate_builtin_bindings(api, output_dir, build_config): if is_included_type(builtin_api["name"]): if "enums" in builtin_api: for enum_api in builtin_api["enums"]: - builtin_binds.append(f"VARIANT_ENUM_CAST({builtin_api['name']}, {enum_api['name']});") + builtin_binds.append(f"VARIANT_ENUM_CAST({builtin_api['name']}::{enum_api['name']});") builtin_binds.append("") builtin_binds.append("#endif // ! GODOT_CPP_BUILTIN_BINDS_HPP") @@ -1381,9 +1381,9 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us if "enums" in class_api and class_name != "Object": for enum_api in class_api["enums"]: if enum_api["is_bitfield"]: - result.append(f'VARIANT_BITFIELD_CAST({class_name}, {class_name}::{enum_api["name"]});') + result.append(f'VARIANT_BITFIELD_CAST({class_name}::{enum_api["name"]});') else: - result.append(f'VARIANT_ENUM_CAST({class_name}, {class_name}::{enum_api["name"]});') + result.append(f'VARIANT_ENUM_CAST({class_name}::{enum_api["name"]});') result.append("") result.append(f"#endif // ! {header_guard}") @@ -1621,7 +1621,7 @@ def generate_global_constant_binds(api, output_dir): if enum_def["name"].startswith("Variant."): continue - header.append(f'VARIANT_ENUM_CAST(, godot::{enum_def["name"]});') + header.append(f'VARIANT_ENUM_CAST(godot::{enum_def["name"]});') header.append("") diff --git a/include/godot_cpp/core/binder_common.hpp b/include/godot_cpp/core/binder_common.hpp index c96498f6..ed7c487d 100644 --- a/include/godot_cpp/core/binder_common.hpp +++ b/include/godot_cpp/core/binder_common.hpp @@ -41,46 +41,46 @@ namespace godot { -#define VARIANT_ENUM_CAST(m_class, m_enum) \ - namespace godot { \ - MAKE_ENUM_TYPE_INFO(m_class, m_enum) \ - template <> \ - struct VariantCaster { \ - static _FORCE_INLINE_ m_class::m_enum cast(const Variant &p_variant) { \ - return (m_class::m_enum)p_variant.operator int64_t(); \ - } \ - }; \ - template <> \ - struct PtrToArg { \ - _FORCE_INLINE_ static m_class::m_enum convert(const void *p_ptr) { \ - return m_class::m_enum(*reinterpret_cast(p_ptr)); \ - } \ - typedef int64_t EncodeT; \ - _FORCE_INLINE_ static void encode(m_class::m_enum p_val, void *p_ptr) { \ - *reinterpret_cast(p_ptr) = p_val; \ - } \ - }; \ +#define VARIANT_ENUM_CAST(m_enum) \ + namespace godot { \ + MAKE_ENUM_TYPE_INFO(m_enum) \ + template <> \ + struct VariantCaster { \ + static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \ + return (m_enum)p_variant.operator int64_t(); \ + } \ + }; \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \ + return m_enum(*reinterpret_cast(p_ptr)); \ + } \ + typedef int64_t EncodeT; \ + _FORCE_INLINE_ static void encode(m_enum p_val, void *p_ptr) { \ + *reinterpret_cast(p_ptr) = p_val; \ + } \ + }; \ } -#define VARIANT_BITFIELD_CAST(m_class, m_enum) \ - namespace godot { \ - MAKE_BITFIELD_TYPE_INFO(m_class, m_enum) \ - template <> \ - struct VariantCaster> { \ - static _FORCE_INLINE_ BitField cast(const Variant &p_variant) { \ - return BitField(p_variant.operator int64_t()); \ - } \ - }; \ - template <> \ - struct PtrToArg> { \ - _FORCE_INLINE_ static BitField convert(const void *p_ptr) { \ - return BitField(*reinterpret_cast(p_ptr)); \ - } \ - typedef int64_t EncodeT; \ - _FORCE_INLINE_ static void encode(BitField p_val, void *p_ptr) { \ - *reinterpret_cast(p_ptr) = p_val; \ - } \ - }; \ +#define VARIANT_BITFIELD_CAST(m_enum) \ + namespace godot { \ + MAKE_BITFIELD_TYPE_INFO(m_enum) \ + template <> \ + struct VariantCaster> { \ + static _FORCE_INLINE_ BitField cast(const Variant &p_variant) { \ + return BitField(p_variant.operator int64_t()); \ + } \ + }; \ + template <> \ + struct PtrToArg> { \ + _FORCE_INLINE_ static BitField convert(const void *p_ptr) { \ + return BitField(*reinterpret_cast(p_ptr)); \ + } \ + typedef int64_t EncodeT; \ + _FORCE_INLINE_ static void encode(BitField p_val, void *p_ptr) { \ + *reinterpret_cast(p_ptr) = p_val; \ + } \ + }; \ } template diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp index 509bfb7b..039cb2e6 100644 --- a/include/godot_cpp/core/type_info.hpp +++ b/include/godot_cpp/core/type_info.hpp @@ -214,21 +214,31 @@ struct GetTypeInfo::value>: } }; -#define TEMPL_MAKE_ENUM_TYPE_INFO(m_class, m_enum, m_impl) \ - template <> \ - struct GetTypeInfo { \ - static const Variant::Type VARIANT_TYPE = Variant::INT; \ - static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ - static inline PropertyInfo get_class_info() { \ - return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, #m_class "." #m_enum); \ - } \ +inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) { + PackedStringArray parts = p_qualified_name.split("::", false); + if (parts.size() <= 2) { + return String(".").join(parts); + } + // Contains namespace. We only want the class and enum names. + return parts[parts.size() - 2] + "." + parts[parts.size() - 1]; +} + +#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \ + template <> \ + struct GetTypeInfo { \ + static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \ + enum_qualified_name_to_class_info_name(#m_enum)); \ + } \ }; -#define MAKE_ENUM_TYPE_INFO(m_class, m_enum) \ - TEMPL_MAKE_ENUM_TYPE_INFO(m_class, m_enum, m_class::m_enum) \ - TEMPL_MAKE_ENUM_TYPE_INFO(m_class, m_enum, m_class::m_enum const) \ - TEMPL_MAKE_ENUM_TYPE_INFO(m_class, m_enum, m_class::m_enum &) \ - TEMPL_MAKE_ENUM_TYPE_INFO(m_class, m_enum, const m_class::m_enum &) +#define MAKE_ENUM_TYPE_INFO(m_enum) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &) template inline StringName __constant_get_enum_name(T param, StringName p_constant) { @@ -251,14 +261,14 @@ public: _FORCE_INLINE_ operator Variant() const { return value; } }; -#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_class, m_enum, m_impl) \ +#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \ template <> \ struct GetTypeInfo { \ static const Variant::Type VARIANT_TYPE = Variant::INT; \ static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ static inline PropertyInfo get_class_info() { \ return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \ - #m_class "." #m_enum); \ + enum_qualified_name_to_class_info_name(#m_enum)); \ } \ }; \ template <> \ @@ -267,15 +277,15 @@ public: static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \ static inline PropertyInfo get_class_info() { \ return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \ - #m_class "." #m_enum); \ + enum_qualified_name_to_class_info_name(#m_enum)); \ } \ }; -#define MAKE_BITFIELD_TYPE_INFO(m_class, m_enum) \ - TEMPL_MAKE_BITFIELD_TYPE_INFO(m_class, m_enum, m_enum) \ - TEMPL_MAKE_BITFIELD_TYPE_INFO(m_class, m_enum, m_enum const) \ - TEMPL_MAKE_BITFIELD_TYPE_INFO(m_class, m_enum, m_enum &) \ - TEMPL_MAKE_BITFIELD_TYPE_INFO(m_class, m_enum, const m_enum &) +#define MAKE_BITFIELD_TYPE_INFO(m_enum) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &) template inline StringName __constant_get_bitfield_name(T param, StringName p_constant) { diff --git a/test/demo/main.gd b/test/demo/main.gd index 7ef3ace0..9b74d14a 100644 --- a/test/demo/main.gd +++ b/test/demo/main.gd @@ -73,5 +73,11 @@ func _ready(): prints(" ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING) prints(" CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM) + prints("BitFields") + prints(" FLAG_ONE", Example.FLAG_ONE) + prints(" FLAG_TWO", Example.FLAG_TWO) + prints(" returned BitField", $Example.test_bitfield(0)) + prints(" returned BitField", $Example.test_bitfield(Example.FLAG_ONE | Example.FLAG_TWO)) + func _on_Example_custom_signal(signal_name, value): prints("Example emitted:", signal_name, value) diff --git a/test/src/example.cpp b/test/src/example.cpp index dec8f57d..f0fce6c6 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -126,6 +126,8 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops); ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops); + ClassDB::bind_method(D_METHOD("test_bitfield", "flags"), &Example::test_bitfield); + ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200)); ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static); @@ -169,7 +171,11 @@ void Example::_bind_methods() { BIND_ENUM_CONSTANT(FIRST); BIND_ENUM_CONSTANT(ANSWER_TO_EVERYTHING); + BIND_BITFIELD_FLAG(FLAG_ONE); + BIND_BITFIELD_FLAG(FLAG_TWO); + BIND_CONSTANT(CONSTANT_WITHOUT_ENUM); + BIND_ENUM_CONSTANT(OUTSIDE_OF_CLASS); } Example::Example() { @@ -304,6 +310,11 @@ Dictionary Example::test_dictionary() const { return dict; } +BitField Example::test_bitfield(BitField flags) { + UtilityFunctions::print(" Got BitField: ", String::num(flags)); + return flags; +} + // Properties. void Example::set_custom_position(const Vector2 &pos) { custom_position = pos; diff --git a/test/src/example.h b/test/src/example.h index 2d4a6b03..afde0f7a 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -75,6 +75,11 @@ public: ANSWER_TO_EVERYTHING = 42, }; + enum Flags { + FLAG_ONE = 1, + FLAG_TWO = 2, + }; + enum { CONSTANT_WITHOUT_ENUM = 314, }; @@ -104,6 +109,8 @@ public: String test_string_ops() const; int test_vector_ops() const; + BitField test_bitfield(BitField flags); + // Property. void set_custom_position(const Vector2 &pos); Vector2 get_custom_position() const; @@ -117,7 +124,13 @@ public: virtual bool _has_point(const Vector2 &point) const override; }; -VARIANT_ENUM_CAST(Example, Constants); +VARIANT_ENUM_CAST(Example::Constants); +VARIANT_BITFIELD_CAST(Example::Flags); + +enum EnumWithoutClass { + OUTSIDE_OF_CLASS = 512 +}; +VARIANT_ENUM_CAST(EnumWithoutClass); class ExampleVirtual : public Object { GDCLASS(ExampleVirtual, Object);