Skip to content

Commit

Permalink
Make extension instances create the corresponding godot object in the…
Browse files Browse the repository at this point in the history
…ir constructor
  • Loading branch information
groud committed Dec 3, 2021
1 parent 50512f0 commit 7b60561
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 90 deletions.
1 change: 1 addition & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ if should_generate_bindings:
# Sources to compile
sources = []
add_sources(sources, "src", "cpp")
add_sources(sources, "src/classes", "cpp")
add_sources(sources, "src/core", "cpp")
add_sources(sources, "src/variant", "cpp")
add_sources(sources, "gen/src/variant", "cpp")
Expand Down
3 changes: 0 additions & 3 deletions binding_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,9 +914,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("")

result.append("public:")

# Constructor override, since parent Wrapped has protected constructor.
result.append(f"\t{class_name}() = default;")
result.append("")

if "enums" in class_api:
Expand Down
2 changes: 1 addition & 1 deletion godot-headers
99 changes: 38 additions & 61 deletions include/godot_cpp/classes/wrapped.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,53 +34,30 @@
#include <godot_cpp/core/memory.hpp>

#include <godot_cpp/godot.hpp>

namespace godot {

typedef void GodotObject;

// Base for all engine classes, to contain the pointer to the engine instance.
class Wrapped {
friend class GDExtensionBinding;

// Private constructor, this should not be created directly by users.
Wrapped(GodotObject *p_owner) :
_owner(p_owner) {}
friend void postinitialize_handler(Wrapped *);

protected:
Wrapped() = default;
virtual const char *_get_class() const = 0; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const GDNativeInstanceBindingCallbacks*_get_bindings_callbacks() const = 0;

void _postinitialize();

Wrapped(const char *p_godot_class);
Wrapped(GodotObject *p_godot_object);

public:
// Must be public but you should not touch this.
GodotObject *_owner = nullptr;

static Wrapped *_new() {
return nullptr;
}
};

namespace internal {

template <class T, class Enable = void>
struct Creator {
static T *_new() { return nullptr; }
};

template <class T>
struct Creator<T, typename std::enable_if<std::is_base_of_v<godot::Wrapped, T>>::type> {
static T *_new() { return T::_new(); }
};

// template <class T>
// struct Creator<T, std::false_type> {
// };

// template <class T>
// struct Creator<T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool>> {
// static T *_new() { return T::_new(); }
// };

}; // namespace internal

} // namespace godot

#ifdef DEBUG_ENABLED
Expand All @@ -96,11 +73,20 @@ struct Creator<T, typename std::enable_if<std::is_base_of_v<godot::Wrapped, T>>:

#define GDCLASS(m_class, m_inherits) \
private: \
void operator=(const m_class &p_rval) {} \
friend class ClassDB; \
\
using SelfType = m_class; \
\
protected: \
virtual const char *_get_class() const override { \
return get_class_static(); \
} \
\
virtual const GDNativeInstanceBindingCallbacks*_get_bindings_callbacks() const override { \
return &___binding_callbacks; \
} \
\
static void (*_get_bind_methods())() { \
return &m_class::_bind_methods; \
} \
Expand Down Expand Up @@ -132,8 +118,9 @@ public:
return #m_inherits; \
} \
\
static GDExtensionClassInstancePtr create(void *data) { \
return reinterpret_cast<GDExtensionClassInstancePtr>(new ("") m_class); \
static GDNativeObjectPtr create(void *data) { \
m_class *new_object = memnew(m_class); \
return new_object->_owner; \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
Expand All @@ -144,11 +131,6 @@ public:
} \
} \
\
static void set_object_instance(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance) { \
godot::internal::gdn_interface->object_set_instance_binding(p_object_instance, godot::internal::token, p_instance, &m_class::___binding_callbacks); \
reinterpret_cast<m_class *>(p_instance)->_owner = reinterpret_cast<godot::GodotObject *>(p_object_instance); \
} \
\
static void *___binding_create_callback(void *p_token, void *p_instance) { \
return nullptr; \
} \
Expand All @@ -162,20 +144,24 @@ public:
___binding_free_callback, \
___binding_reference_callback, \
}; \
\
static m_class *_new() { \
static GDNativeExtensionPtr ___extension = nullptr; \
static GDNativeClassConstructor ___constructor = godot::internal::gdn_interface->classdb_get_constructor(#m_class, &___extension); \
CHECK_CLASS_CONSTRUCTOR(___constructor, m_class); \
GDNativeObjectPtr obj = godot::internal::gdn_interface->classdb_construct_object(___constructor, ___extension); \
return reinterpret_cast<m_class *>(godot::internal::gdn_interface->object_get_instance_binding(obj, godot::internal::token, &m_class::___binding_callbacks)); \
} \
\
private:

// Don't use this for your classes, use GDCLASS() instead.
#define GDNATIVE_CLASS(m_class, m_inherits) \
protected: \
private: \
void operator=(const m_class &p_rval) {} \
\
protected: \
virtual const char *_get_class() const override { \
return get_class_static(); \
} \
\
virtual const GDNativeInstanceBindingCallbacks*_get_bindings_callbacks() const override { \
return &___binding_callbacks; \
} \
\
m_class(const char * p_godot_class) : m_inherits(p_godot_class) {} \
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\
static void (*_get_bind_methods())() { \
return nullptr; \
} \
Expand All @@ -192,9 +178,7 @@ public:
} \
\
static void *___binding_create_callback(void *p_token, void *p_instance) { \
m_class *obj = new ("") m_class; \
obj->_owner = (godot::GodotObject *)p_instance; \
return obj; \
return memnew(m_class((GodotObject *)p_instance)); \
} \
static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
Expand All @@ -207,13 +191,6 @@ public:
___binding_free_callback, \
___binding_reference_callback, \
}; \
static m_class *_new() { \
static GDNativeClassConstructor ___constructor = godot::internal::gdn_interface->classdb_get_constructor(#m_class, nullptr); \
CHECK_CLASS_CONSTRUCTOR(___constructor, m_class); \
GDNativeObjectPtr obj = ___constructor(); \
return reinterpret_cast<m_class *>(godot::internal::gdn_interface->object_get_instance_binding(obj, godot::internal::token, &m_class::___binding_callbacks)); \
} \
\
private:
m_class() : m_class(#m_class) {}

#endif // ! GODOT_CPP_WRAPPED_HPP
1 change: 0 additions & 1 deletion include/godot_cpp/core/class_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ void ClassDB::register_class() {
nullptr, // GDNativeExtensionClassUnreference
T::create, // GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
T::set_object_instance, // GDNativeExtensionClassObjectInstance object_instance_func; /* this one is mandatory */
&ClassDB::get_virtual_func, // GDNativeExtensionClassGetVirtual get_virtual_func;
(void *)cl.name, //void *class_userdata;
};
Expand Down
21 changes: 11 additions & 10 deletions include/godot_cpp/core/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,17 @@ class Memory {
static void free_static(void *p_ptr);
};

#define memnew(m_v) \
([&]() { \
if constexpr (std::is_base_of<godot::Object, decltype(m_v)>::value) { \
return godot::internal::Creator<decltype(m_v)>::_new(); \
} else { \
return new ("") m_v; \
} \
}())

#define memnew_placement(m_placement, m_class) (new (m_placement, sizeof(m_class), "") m_class)
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}

template <class T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
}

#define memnew(m_class) _post_initialize(new ("") m_class)

#define memnew_placement(m_placement, m_class) _post_initialize(new (m_placement, sizeof(m_class), "") m_class)

template <class T>
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = 0) {
Expand Down
3 changes: 0 additions & 3 deletions include/godot_cpp/godot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ class GDExtensionBinding {
static void initialize_level(void *userdata, GDNativeInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDNativeInitializationLevel p_level);

static void *create_instance_callback(void *p_token, void *p_instance);
static void free_instance_callback(void *p_token, void *p_instance, void *p_binding);

class InitObject {
const GDNativeInterface *gdn_interface;
const GDNativeExtensionClassLibraryPtr library;
Expand Down
Loading

0 comments on commit 7b60561

Please sign in to comment.