Merge pull request #783 from bruvzg/bitfields

pull/788/head
Rémi Verschelde 2022-07-14 23:49:27 +02:00 committed by GitHub
commit 9fc3fd7196
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 2692 additions and 2528 deletions

View File

@ -1064,7 +1064,10 @@ 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"]:
result.append(f'VARIANT_ENUM_CAST({class_name}, {class_name}::{enum_api["name"]});')
if enum_api["is_bitfield"]:
result.append(f'VARIANT_BITFIELD_CAST({class_name}, {class_name}::{enum_api["name"]});')
else:
result.append(f'VARIANT_ENUM_CAST({class_name}, {class_name}::{enum_api["name"]});')
result.append("")
result.append(f"#endif // ! {header_guard}")
@ -1194,7 +1197,7 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
result.append(method_call)
if vararg and ("return_value" in method and method["return_value"]["type"] != "void"):
return_type = method["return_value"]["type"].replace("enum::", "")
return_type = get_enum_fullname(method["return_value"]["type"])
if return_type != "Variant":
result.append(f"\treturn VariantCaster<{return_type}>::cast(ret);")
else:
@ -1712,18 +1715,35 @@ def needs_copy_instead_of_move(type_name):
def is_enum(type_name):
return type_name.startswith("enum::")
return type_name.startswith("enum::") or type_name.startswith("bitfield::")
def is_bitfield(type_name):
return type_name.startswith("bitfield::")
def get_enum_class(enum_name: str):
if "." in enum_name:
return enum_name.replace("enum::", "").split(".")[0]
if is_bitfield(enum_name):
return enum_name.replace("bitfield::", "").split(".")[0]
else:
return enum_name.replace("enum::", "").split(".")[0]
else:
return "GlobalConstants"
def get_enum_fullname(enum_name: str):
if is_bitfield(enum_name):
return enum_name.replace("bitfield::", "BitField<") + ">"
else:
return enum_name.replace("enum::", "")
def get_enum_name(enum_name: str):
return enum_name.replace("enum::", "").split(".")[-1]
if is_bitfield(enum_name):
return enum_name.replace("bitfield::", "").split(".")[-1]
else:
return enum_name.replace("enum::", "").split(".")[-1]
def is_variant(type_name):
@ -1781,10 +1801,16 @@ def correct_type(type_name, meta=None):
if type_name in type_conversion:
return type_conversion[type_name]
if is_enum(type_name):
base_class = get_enum_class(type_name)
if base_class == "GlobalConstants":
return f"{get_enum_name(type_name)}"
return f"{base_class}::{get_enum_name(type_name)}"
if is_bitfield(type_name):
base_class = get_enum_class(type_name)
if base_class == "GlobalConstants":
return f"BitField<{get_enum_name(type_name)}>"
return f"BitField<{base_class}::{get_enum_name(type_name)}>"
else:
base_class = get_enum_class(type_name)
if base_class == "GlobalConstants":
return f"{get_enum_name(type_name)}"
return f"{base_class}::{get_enum_name(type_name)}"
if is_refcounted(type_name):
return f"Ref<{type_name}>"
if type_name == "Object" or is_engine_class(type_name):
@ -1807,6 +1833,9 @@ def get_gdnative_type(type_name):
"float": "double",
}
if type_name.startswith("BitField<"):
return "int64_t"
if type_name in type_conversion_map:
return type_conversion_map[type_name]
return type_name

File diff suppressed because it is too large Load Diff

View File

@ -540,7 +540,7 @@ typedef struct {
void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value);
void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, bool p_is_bitfield);
void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);

View File

@ -62,6 +62,27 @@ namespace godot {
}; \
}
#define VARIANT_BITFIELD_CAST(m_class, m_enum) \
namespace godot { \
MAKE_BITFIELD_TYPE_INFO(m_class, m_enum) \
template <> \
struct VariantCaster<BitField<m_class::m_enum>> { \
static _FORCE_INLINE_ BitField<m_class::m_enum> cast(const Variant &p_variant) { \
return BitField<m_class::m_enum>(p_variant.operator int64_t()); \
} \
}; \
template <> \
struct PtrToArg<BitField<m_class::m_enum>> { \
_FORCE_INLINE_ static BitField<m_class::m_enum> convert(const void *p_ptr) { \
return BitField<m_class::m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
typedef int64_t EncodeT; \
_FORCE_INLINE_ static void encode(BitField<m_class::m_enum> p_val, const void *p_ptr) { \
*(int64_t *)p_ptr = p_val; \
} \
}; \
}
template <class T>
struct VariantCaster {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {

View File

@ -116,7 +116,7 @@ public:
static void add_property_subgroup(const char *p_class, const char *p_name, const char *p_prefix);
static void add_property(const char *p_class, const PropertyInfo &p_pinfo, const char *p_setter, const char *p_getter, int p_index = -1);
static void add_signal(const char *p_class, const MethodInfo &p_signal);
static void bind_integer_constant(const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value);
static void bind_integer_constant(const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, bool p_is_bitfield = false);
static void bind_virtual_method(const char *p_class, const char *p_method, GDNativeExtensionClassCallVirtual p_call);
static MethodBind *get_method(const char *p_class, const char *p_method);
@ -133,6 +133,9 @@ public:
#define BIND_ENUM_CONSTANT(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), godot::__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
#define BIND_BITFIELD_FLAG(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), godot::__constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
{ \
auto ___call##m_method = [](GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr p_ret) -> void { \

View File

@ -219,6 +219,53 @@ inline const char *__constant_get_enum_name(T param, const char *p_constant) {
return GetTypeInfo<T>::get_class_info().class_name;
}
template <class T>
class BitField {
uint32_t value = 0;
public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
_FORCE_INLINE_ BitField(uint32_t p_value) { value = p_value; }
_FORCE_INLINE_ operator uint32_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
};
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_class, m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDNativeExtensionClassMethodArgumentMetadata METADATA = GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline GDNativePropertyInfo get_class_info() { \
return PropertyInfo(GDNATIVE_VARIANT_TYPE_INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
#m_class "." #m_enum); \
} \
}; \
template <> \
struct GetTypeInfo<BitField<m_impl>> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDNativeExtensionClassMethodArgumentMetadata METADATA = GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline GDNativePropertyInfo get_class_info() { \
return PropertyInfo(GDNATIVE_VARIANT_TYPE_INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
#m_class "." #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 &)
template <typename T>
inline const char *__constant_get_bitfield_name(T param, const char *p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's bitfield: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
} // namespace godot

View File

@ -249,7 +249,7 @@ void ClassDB::add_signal(const char *p_class, const MethodInfo &p_signal) {
internal::gdn_interface->classdb_register_extension_class_signal(internal::library, cl.name, p_signal.name, parameters.data(), parameters.size());
}
void ClassDB::bind_integer_constant(const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value) {
void ClassDB::bind_integer_constant(const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, bool p_is_bitfield) {
std::unordered_map<std::string, ClassInfo>::iterator type_it = classes.find(p_class_name);
ERR_FAIL_COND_MSG(type_it == classes.end(), "Class doesn't exist.");
@ -263,7 +263,7 @@ void ClassDB::bind_integer_constant(const char *p_class_name, const char *p_enum
type.constant_names.insert(p_constant_name);
// Register it with Godot
internal::gdn_interface->classdb_register_extension_class_integer_constant(internal::library, p_class_name, p_enum_name, p_constant_name, p_constant_value);
internal::gdn_interface->classdb_register_extension_class_integer_constant(internal::library, p_class_name, p_enum_name, p_constant_name, p_constant_value, p_is_bitfield);
}
GDNativeExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, const char *p_name) {

View File

@ -12,8 +12,8 @@ config_version=5
config/name="GDExtension Test Project"
run/main_scene="res://main.tscn"
config/icon="res://icon.png"
config/features=PackedStringArray("4.0")
config/icon="res://icon.png"
[native_extensions]