Skip to content

Commit

Permalink
Rework GDCLASS macro to allow pure virtual functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Naros committed Jan 19, 2024
1 parent 0ddef6e commit 5f350e2
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 33 deletions.
29 changes: 1 addition & 28 deletions include/godot_cpp/classes/wrapped.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ typedef void GodotObject;
// Base for all engine classes, to contain the pointer to the engine instance.
class Wrapped {
friend class GDExtensionBinding;
friend class ClassDB;
friend void postinitialize_handler(Wrapped *);

protected:
Expand Down Expand Up @@ -131,17 +132,6 @@ struct EngineClassRegistration {

} // namespace godot

#ifdef HOT_RELOAD_ENABLED
#define _GDCLASS_RECREATE(m_class, m_inherits) \
m_class *new_instance = (m_class *)memalloc(sizeof(m_class)); \
Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; \
Wrapped::recreate_instance = &recreate_data; \
memnew_placement(new_instance, m_class); \
return new_instance;
#else
#define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr;
#endif

// Use this on top of your own classes.
// Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
// every line of the macro different
Expand Down Expand Up @@ -226,15 +216,6 @@ public:
return m_inherits::get_class_static(); \
} \
\
static GDExtensionObjectPtr create(void *data) { \
m_class *new_object = memnew(m_class); \
return new_object->_owner; \
} \
\
static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \
_GDCLASS_RECREATE(m_class, m_inherits); \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
if (p_instance && m_class::_get_notification()) { \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
Expand Down Expand Up @@ -437,14 +418,6 @@ public:
return m_inherits::get_class_static(); \
} \
\
static GDExtensionObjectPtr create(void *data) { \
return nullptr; \
} \
\
static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \
return nullptr; \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
} \
\
Expand Down
31 changes: 29 additions & 2 deletions include/godot_cpp/core/class_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,33 @@ class ClassDB {
template <class T, bool is_abstract>
static void _register_class(bool p_virtual = false, bool p_exposed = true);

template <class T>
static GDExtensionObjectPtr _create_instance_func(void *data) {
if constexpr (!std::is_abstract_v<T>) {
T *new_object = memnew(T);
return new_object->_owner;
} else {
return nullptr;
}
}

template <class T>
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) {
#ifdef HOT_RELOAD_ENABLED
T *new_instance = (T *)memalloc(sizeof(T));
Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance };
Wrapped::recreate_instance = &recreate_data;
memnew_placement(new_instance, T);
return new_instance;
#else
return nullptr;
#endif
} else {
return nullptr;
}
}

public:
template <class T>
static void register_class(bool p_virtual = false);
Expand Down Expand Up @@ -202,9 +229,9 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
T::to_string_bind, // GDExtensionClassToString to_string_func;
nullptr, // GDExtensionClassReference reference_func;
nullptr, // GDExtensionClassUnreference unreference_func;
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
&_create_instance_func<T>, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
T::recreate, // GDExtensionClassRecreateInstance recreate_instance_func;
&_recreate_instance_func<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
Expand Down
15 changes: 13 additions & 2 deletions test/src/example.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,22 @@ class ExampleVirtual : public Object {
static void _bind_methods() {}
};

class ExampleAbstract : public Object {
GDCLASS(ExampleAbstract, Object);
class ExampleAbstractBase : public Object {
GDCLASS(ExampleAbstractBase, Object);

protected:
static void _bind_methods() {}

virtual int test_function() = 0;
};

class ExampleConcrete : public ExampleAbstractBase {
GDCLASS(ExampleConcrete, ExampleAbstractBase);

protected:
static void _bind_methods() {}

virtual int test_function() override { return 25; }
};

#endif // EXAMPLE_CLASS_H
3 changes: 2 additions & 1 deletion test/src/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<ExampleMin>();
ClassDB::register_class<Example>();
ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstract>();
ClassDB::register_abstract_class<ExampleAbstractBase>();
ClassDB::register_class<ExampleConcrete>();
}

void uninitialize_example_module(ModuleInitializationLevel p_level) {
Expand Down

0 comments on commit 5f350e2

Please sign in to comment.