diff options
| author | Marc <marc.gilleron@gmail.com> | 2021-01-31 19:32:56 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-31 19:32:56 +0000 |
| commit | 1aab5e3962e311caebae04f44fff9c4e1cd7d9c0 (patch) | |
| tree | c55e3435691883c62bed6375c6b236a9715c85c7 /include | |
| parent | 2559c70e274f9239cd29c434ab262c46f6dc8552 (diff) | |
| parent | 35f78dea5196d4d676946a84c10206a5cb1a1fa0 (diff) | |
| download | redot-cpp-1aab5e3962e311caebae04f44fff9c4e1cd7d9c0.tar.gz | |
Merge branch 'master' into master
Diffstat (limited to 'include')
| -rw-r--r-- | include/core/Array.hpp | 5 | ||||
| -rw-r--r-- | include/core/CameraMatrix.hpp | 103 | ||||
| -rw-r--r-- | include/core/Color.hpp | 18 | ||||
| -rw-r--r-- | include/core/Defs.hpp | 8 | ||||
| -rw-r--r-- | include/core/Dictionary.hpp | 5 | ||||
| -rw-r--r-- | include/core/Godot.hpp | 253 | ||||
| -rw-r--r-- | include/core/Math.hpp | 250 | ||||
| -rw-r--r-- | include/core/RID.hpp | 4 | ||||
| -rw-r--r-- | include/core/String.hpp | 3 | ||||
| -rw-r--r-- | include/core/Vector2.hpp | 41 | ||||
| -rw-r--r-- | include/core/Vector3.hpp | 30 |
11 files changed, 635 insertions, 85 deletions
diff --git a/include/core/Array.hpp b/include/core/Array.hpp index d766c54..3d13914 100644 --- a/include/core/Array.hpp +++ b/include/core/Array.hpp @@ -57,6 +57,11 @@ class Object; class Array { godot_array _godot_array; + friend class Variant; + inline explicit Array(const godot_array &other) { + _godot_array = other; + } + public: Array(); Array(const Array &other); diff --git a/include/core/CameraMatrix.hpp b/include/core/CameraMatrix.hpp new file mode 100644 index 0000000..d9bff7f --- /dev/null +++ b/include/core/CameraMatrix.hpp @@ -0,0 +1,103 @@ +#ifndef CAMERA_MATRIX_H +#define CAMERA_MATRIX_H + +#include "Defs.hpp" +#include "Plane.hpp" +#include "Rect2.hpp" +#include "Transform.hpp" + +#include <vector> + +namespace { +using namespace godot; +} // namespace + +struct CameraMatrix { + + enum Planes { + PLANE_NEAR, + PLANE_FAR, + PLANE_LEFT, + PLANE_TOP, + PLANE_RIGHT, + PLANE_BOTTOM + }; + + real_t matrix[4][4]; + + void set_identity(); + void set_zero(); + void set_light_bias(); + void set_light_atlas_rect(const Rect2 &p_rect); + void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); + void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); + void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far); + void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); + void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); + void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far); + void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); + + static real_t get_fovy(real_t p_fovx, real_t p_aspect) { + + return rad2deg(atan(p_aspect * tan(deg2rad(p_fovx) * 0.5)) * 2.0); + } + + static inline double deg2rad(double p_y) { return p_y * Math_PI / 180.0; } + static inline float deg2rad(float p_y) { return p_y * Math_PI / 180.0; } + + static inline double rad2deg(double p_y) { return p_y * 180.0 / Math_PI; } + static inline float rad2deg(float p_y) { return p_y * 180.0 / Math_PI; } + + static inline double absd(double g) { + + union { + double d; + uint64_t i; + } u; + u.d = g; + u.i &= (uint64_t)9223372036854775807ll; + return u.d; + } + + real_t get_z_far() const; + real_t get_z_near() const; + real_t get_aspect() const; + real_t get_fov() const; + bool is_orthogonal() const; + + std::vector<Plane> get_projection_planes(const Transform &p_transform) const; + + bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const; + Vector2 get_viewport_half_extents() const; + + void invert(); + CameraMatrix inverse() const; + + CameraMatrix operator*(const CameraMatrix &p_matrix) const; + + Plane xform4(const Plane &p_vec4) const; + inline Vector3 xform(const Vector3 &p_vec3) const; + + operator String() const; + + void scale_translate_to_fit(const AABB &p_aabb); + void make_scale(const Vector3 &p_scale); + int get_pixels_per_meter(int p_for_pixel_width) const; + operator Transform() const; + + CameraMatrix(); + CameraMatrix(const Transform &p_transform); + ~CameraMatrix(); +}; + +Vector3 CameraMatrix::xform(const Vector3 &p_vec3) const { + + Vector3 ret; + ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0]; + ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1]; + ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2]; + real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3]; + return ret / w; +} + +#endif diff --git a/include/core/Color.hpp b/include/core/Color.hpp index 0f93a55..e4116f2 100644 --- a/include/core/Color.hpp +++ b/include/core/Color.hpp @@ -5,6 +5,7 @@ #include <cmath> +#include "Defs.hpp" #include "String.hpp" namespace godot { @@ -73,6 +74,23 @@ public: return components[idx]; } + Color operator+(const Color &p_color) const; + void operator+=(const Color &p_color); + + Color operator-() const; + Color operator-(const Color &p_color) const; + void operator-=(const Color &p_color); + + Color operator*(const Color &p_color) const; + Color operator*(const real_t &rvalue) const; + void operator*=(const Color &p_color); + void operator*=(const real_t &rvalue); + + Color operator/(const Color &p_color) const; + Color operator/(const real_t &rvalue) const; + void operator/=(const Color &p_color); + void operator/=(const real_t &rvalue); + void invert(); void contrast(); diff --git a/include/core/Defs.hpp b/include/core/Defs.hpp index fb0a18b..67e3279 100644 --- a/include/core/Defs.hpp +++ b/include/core/Defs.hpp @@ -61,11 +61,19 @@ enum class Error { #include <GodotGlobal.hpp> +// alloca() is non-standard. When using MSVC, it's in malloc.h. +#if defined(__linux__) || defined(__APPLE__) +#include <alloca.h> +#else +#include <malloc.h> +#endif + typedef float real_t; #define CMP_EPSILON 0.00001 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON) #define Math_PI 3.14159265358979323846 +#define Math_TAU 6.2831853071795864769252867666 #define _PLANE_EQ_DOT_EPSILON 0.999 #define _PLANE_EQ_D_EPSILON 0.0001 diff --git a/include/core/Dictionary.hpp b/include/core/Dictionary.hpp index ec97602..7f40adc 100644 --- a/include/core/Dictionary.hpp +++ b/include/core/Dictionary.hpp @@ -12,6 +12,11 @@ namespace godot { class Dictionary { godot_dictionary _godot_dictionary; + friend Variant::operator Dictionary() const; + inline explicit Dictionary(const godot_dictionary &other) { + _godot_dictionary = other; + } + public: Dictionary(); Dictionary(const Dictionary &other); diff --git a/include/core/Godot.hpp b/include/core/Godot.hpp index 8983e00..db5a871 100644 --- a/include/core/Godot.hpp +++ b/include/core/Godot.hpp @@ -17,60 +17,113 @@ #include "GodotGlobal.hpp" -#include <GDNativeLibrary.hpp> -#include <NativeScript.hpp> - namespace godot { +namespace detail { + +// Godot classes are wrapped by heap-allocated instances mimicking them through the C API. +// They all inherit `_Wrapped`. +template <class T> +T *get_wrapper(godot_object *obj) { + return (T *)godot::nativescript_1_1_api->godot_nativescript_get_instance_binding_data(godot::_RegisterState::language_index, obj); +} +// Custom class instances are not obtainable by just casting the pointer to the base class they inherit, +// partly because in Godot, scripts are not instances of the classes themselves, they are only attached to them. +// Yet we want to "fake" it as if they were the same entity. template <class T> -T *as(const Object *obj) { +T *get_custom_class_instance(const Object *obj) { return (obj) ? (T *)godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner) : nullptr; } template <class T> -T *get_wrapper(godot_object *obj) { - return (T *)godot::nativescript_1_1_api->godot_nativescript_get_instance_binding_data(godot::_RegisterState::language_index, obj); +inline T *create_custom_class_instance() { + // Usually, script instances hold a reference to their NativeScript resource. + // that resource is obtained from a `.gdns` file, which in turn exists because + // of the resource system of Godot. We can't cleanly hardcode that here, + // so the easiest for now (though not really clean) is to create new resource instances, + // individually attached to the script instances. + + // We cannot use wrappers because of https://github.com/godotengine/godot/issues/39181 + // godot::NativeScript *script = godot::NativeScript::_new(); + // script->set_library(get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib)); + // script->set_class_name(T::___get_class_name()); + + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + + // So we use the C API directly. + static godot_class_constructor script_constructor = godot::api->godot_get_class_constructor("NativeScript"); + static godot_method_bind *mb_set_library = godot::api->godot_method_bind_get_method("NativeScript", "set_library"); + static godot_method_bind *mb_set_class_name = godot::api->godot_method_bind_get_method("NativeScript", "set_class_name"); + godot_object *script = script_constructor(); + { + const void *args[] = { godot::gdnlib }; + godot::api->godot_method_bind_ptrcall(mb_set_library, script, args, nullptr); + } + { + const String class_name = T::___get_class_name(); + const void *args[] = { &class_name }; + godot::api->godot_method_bind_ptrcall(mb_set_class_name, script, args, nullptr); + } + + // Now to instanciate T, we initially did this, however in case of Reference it returns a variant with refcount + // already initialized, which woud cause inconsistent behavior compared to other classes (we still have to return a pointer). + //Variant instance_variant = script->new_(); + //T *instance = godot::get_custom_class_instance<T>(instance_variant); + + // So we should do this instead, however while convenient, it uses unnecessary wrapper objects. + // Object *base_obj = T::___new_godot_base(); + // base_obj->set_script(script); + // return get_custom_class_instance<T>(base_obj); + + // Again using the C API to do exactly what we have to do. + static godot_class_constructor base_constructor = godot::api->godot_get_class_constructor(T::___get_godot_class_name()); + static godot_method_bind *mb_set_script = godot::api->godot_method_bind_get_method("Object", "set_script"); + godot_object *base_obj = base_constructor(); + { + const void *args[] = { script }; + godot::api->godot_method_bind_ptrcall(mb_set_script, base_obj, args, nullptr); + } + + return (T *)godot::nativescript_api->godot_nativescript_get_userdata(base_obj); } -#define GODOT_CLASS(Name, Base) \ - \ -public: \ - inline static const char *___get_type_name() { return static_cast<const char *>(#Name); } \ - enum { ___CLASS_IS_SCRIPT = 1, \ - }; \ - inline static Name *_new() { \ - godot::NativeScript *script = godot::NativeScript::_new(); \ - script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib)); \ - script->set_class_name(#Name); \ - Name *instance = godot::as<Name>(script->new_()); \ - return instance; \ - } \ - inline static size_t ___get_id() { return typeid(Name).hash_code(); } \ - inline static size_t ___get_base_id() { return typeid(Base).hash_code(); } \ - inline static const char *___get_base_type_name() { return Base::___get_class_name(); } \ - inline static Object *___get_from_variant(godot::Variant a) { return (godot::Object *)godot::as<Name>(godot::Object::___get_from_variant(a)); } \ - \ +} // namespace detail + +// Used in the definition of a custom class. +// +// Name: Name of your class, without namespace +// Base: Name of the direct base class, with namespace if necessary +// +// ___get_class_name: Name of the class +// ___get_godot_class_name: Name of the Godot base class this class inherits from (i.e not direct) +// _new: Creates a new instance of the class +// ___get_id: Gets the unique ID of the class. Godot and custom classes are both within that set. +// ___get_base_id: Gets the ID of the direct base class, as returned by ___get_id +// ___get_base_class_name: Name of the direct base class +// ___get_from_variant: Converts a Variant into an Object*. Will be non-null if the class matches. +#define GODOT_CLASS(Name, Base) \ + \ +public: \ + inline static const char *___get_class_name() { return #Name; } \ + enum { ___CLASS_IS_SCRIPT = 1 }; \ + inline static const char *___get_godot_class_name() { \ + return Base::___get_godot_class_name(); \ + } \ + inline static Name *_new() { \ + return godot::detail::create_custom_class_instance<Name>(); \ + } \ + inline static size_t ___get_id() { return typeid(Name).hash_code(); } \ + inline static size_t ___get_base_id() { return Base::___get_id(); } \ + inline static const char *___get_base_class_name() { return Base::___get_class_name(); } \ + inline static godot::Object *___get_from_variant(godot::Variant a) { \ + return (godot::Object *)godot::detail::get_custom_class_instance<Name>( \ + godot::Object::___get_from_variant(a)); \ + } \ + \ private: -#define GODOT_SUBCLASS(Name, Base) \ - \ -public: \ - inline static const char *___get_type_name() { return static_cast<const char *>(#Name); } \ - enum { ___CLASS_IS_SCRIPT = 1, \ - }; \ - inline static Name *_new() { \ - godot::NativeScript *script = godot::NativeScript::_new(); \ - script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib)); \ - script->set_class_name(#Name); \ - Name *instance = godot::as<Name>(script->new_()); \ - return instance; \ - } \ - inline static size_t ___get_id() { return typeid(Name).hash_code(); }; \ - inline static size_t ___get_base_id() { return typeid(Base).hash_code(); }; \ - inline static const char *___get_base_type_name() { return #Base; } \ - inline static Object *___get_from_variant(godot::Variant a) { return (godot::Object *)godot::as<Name>(godot::Object::___get_from_variant(a)); } \ - \ -private: +// Legacy compatibility +#define GODOT_SUBCLASS(Name, Base) GODOT_CLASS(Name, Base) template <class T> struct _ArgCast { @@ -112,6 +165,8 @@ void _godot_class_destroy_func(godot_object * /*p*/, void * /*method_data*/, voi template <class T> void register_class() { + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + godot_instance_create_func create = {}; create.create_func = _godot_class_instance_func<T>; @@ -120,13 +175,19 @@ void register_class() { _TagDB::register_type(T::___get_id(), T::___get_base_id()); - godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy); - godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), (const void *)typeid(T).hash_code()); + godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), T::___get_base_class_name(), create, destroy); + + godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), (const void *)T::___get_id()); + T::_register_methods(); } template <class T> void register_tool_class() { + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + godot_instance_create_func create = {}; create.create_func = _godot_class_instance_func<T>; @@ -135,8 +196,12 @@ void register_tool_class() { _TagDB::register_type(T::___get_id(), T::___get_base_id()); - godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy); - godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), (const void *)typeid(T).hash_code()); + godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), T::___get_base_class_name(), create, destroy); + + godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), (const void *)T::___get_id()); + T::_register_methods(); } @@ -145,13 +210,15 @@ void register_tool_class() { typedef godot_variant (*__godot_wrapper_method)(godot_object *, void *, void *, int, godot_variant **); template <class T, class R, class... args> -const char *___get_method_class_name(R (T::* /*p*/)(args... a)) { - return T::___get_type_name(); +const char *___get_method_class_name(R (T::*/*p*/)(args... a)) { + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + return T::___get_class_name(); } template <class T, class R, class... args> -const char *___get_method_class_name(R (T::* /*p*/)(args... a) const) { - return T::___get_type_name(); +const char *___get_method_class_name(R (T::*/*p*/)(args... a) const) { + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + return T::___get_class_name(); } // Okay, time for some template magic. @@ -243,7 +310,17 @@ void register_method(const char *name, M method_ptr, godot_method_rpc_mode rpc_t godot_method_attributes attr = {}; attr.rpc_type = rpc_type; - godot::nativescript_api->godot_nativescript_register_method(godot::_RegisterState::nativescript_handle, ___get_method_class_name(method_ptr), name, attr, method); + godot::nativescript_api->godot_nativescript_register_method(godot::_RegisterState::nativescript_handle, + ___get_method_class_name(method_ptr), name, attr, method); +} + +// User can specify a derived class D to register the method for, instead of it being inferred. +template <class D, class B, class R, class... As> +void register_method_explicit(const char *name, R (B::*method_ptr)(As...), + godot_method_rpc_mode rpc_type = GODOT_METHOD_RPC_MODE_DISABLED) { + + static_assert(std::is_base_of<B, D>::value, "Explicit class must derive from method class"); + register_method(name, static_cast<R (D::*)(As...)>(method_ptr), rpc_type); } template <class T, class P> @@ -310,13 +387,19 @@ struct _PropertyDefaultGetFunc { }; template <class T, class P> -void register_property(const char *name, P(T::*var), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { +void register_property(const char *name, P(T::*var), P default_value, + godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, + godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, + godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { + + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + Variant def_val = default_value; usage = (godot_property_usage_flags)((int)usage | GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE); if (def_val.get_type() == Variant::OBJECT) { - Object *o = get_wrapper<Object>(def_val.operator godot_object *()); + Object *o = detail::get_wrapper<Object>(def_val.operator godot_object *()); if (o && o->is_class("Resource")) { hint = (godot_property_hint)((int)hint | GODOT_PROPERTY_HINT_RESOURCE_TYPE); hint_string = o->get_class(); @@ -338,10 +421,12 @@ void register_property(const char *name, P(T::*var), P default_value, godot_meth attr.usage = usage; attr.hint_string = *_hint_string; - _PropertyDefaultSetFunc<T, P> *wrapped_set = (_PropertyDefaultSetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultSetFunc<T, P>)); + _PropertyDefaultSetFunc<T, P> *wrapped_set = + (_PropertyDefaultSetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultSetFunc<T, P>)); wrapped_set->f = var; - _PropertyDefaultGetFunc<T, P> *wrapped_get = (_PropertyDefaultGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultGetFunc<T, P>)); + _PropertyDefaultGetFunc<T, P> *wrapped_get = + (_PropertyDefaultGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultGetFunc<T, P>)); wrapped_get->f = var; godot_property_set_func set_func = {}; @@ -354,11 +439,18 @@ void register_property(const char *name, P(T::*var), P default_value, godot_meth get_func.free_func = godot::api->godot_free; get_func.get_func = &_PropertyDefaultGetFunc<T, P>::_wrapped_getter; - godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle, T::___get_type_name(), name, &attr, set_func, get_func); + godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), name, &attr, set_func, get_func); } template <class T, class P> -void register_property(const char *name, void (T::*setter)(P), P (T::*getter)(), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { +void register_property(const char *name, void (T::*setter)(P), P (T::*getter)(), P default_value, + godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, + godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, + godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { + + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + Variant def_val = default_value; godot_string *_hint_string = (godot_string *)&hint_string; @@ -391,16 +483,23 @@ void register_property(const char *name, void (T::*setter)(P), P (T::*getter)(), get_func.free_func = godot::api->godot_free; get_func.get_func = &_PropertyGetFunc<T, P>::_wrapped_getter; - godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle, T::___get_type_name(), name, &attr, set_func, get_func); + godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), name, &attr, set_func, get_func); } template <class T, class P> -void register_property(const char *name, void (T::*setter)(P), P (T::*getter)() const, P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { +void register_property(const char *name, void (T::*setter)(P), P (T::*getter)() const, P default_value, + godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, + godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, + godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { + register_property(name, setter, (P(T::*)())getter, default_value, rpc_mode, usage, hint, hint_string); } template <class T> void register_signal(String name, Dictionary args = Dictionary()) { + static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes"); + godot_signal signal = {}; signal.name = *(godot_string *)&name; signal.num_args = args.size(); @@ -425,7 +524,8 @@ void register_signal(String name, Dictionary args = Dictionary()) { signal.args[i].type = args.values()[i]; } - godot::nativescript_api->godot_nativescript_register_signal(godot::_RegisterState::nativescript_handle, T::___get_type_name(), &signal); + godot::nativescript_api->godot_nativescript_register_signal(godot::_RegisterState::nativescript_handle, + T::___get_class_name(), &signal); for (int i = 0; i < signal.num_args; i++) { godot::api->godot_string_destroy(&signal.args[i].name); @@ -447,26 +547,31 @@ T *Object::cast_to(const Object *obj) { if (!obj) return nullptr; - size_t have_tag = (size_t)godot::nativescript_1_1_api->godot_nativescript_get_type_tag(obj->_owner); - - if (have_tag) { - if (!godot::_TagDB::is_type_known((size_t)have_tag)) { - have_tag = 0; + if (T::___CLASS_IS_SCRIPT) { + size_t have_tag = (size_t)godot::nativescript_1_1_api->godot_nativescript_get_type_tag(obj->_owner); + if (have_tag) { + if (!godot::_TagDB::is_type_known((size_t)have_tag)) { + have_tag = 0; + } } - } - if (!have_tag) { - have_tag = obj->_type_tag; - } + if (!have_tag) { + have_tag = obj->_type_tag; + } - if (godot::_TagDB::is_type_compatible(typeid(T).hash_code(), have_tag)) { - return (T::___CLASS_IS_SCRIPT) ? godot::as<T>(obj) : (T *)obj; + if (godot::_TagDB::is_type_compatible(T::___get_id(), have_tag)) { + return detail::get_custom_class_instance<T>(obj); + } } else { - return nullptr; + if (godot::core_1_2_api->godot_object_cast_to(obj->_owner, (void *)T::___get_id())) { + return (T *)obj; + } } + + return nullptr; } #endif } // namespace godot -#endif // GODOT_H +#endif // GODOT_HPP diff --git a/include/core/Math.hpp b/include/core/Math.hpp new file mode 100644 index 0000000..4d0d32e --- /dev/null +++ b/include/core/Math.hpp @@ -0,0 +1,250 @@ +#ifndef GODOT_MATH_H
+#define GODOT_MATH_H
+
+#include "Defs.hpp"
+#include <cmath>
+
+namespace godot {
+namespace Math {
+
+// Functions reproduced as in Godot's source code `math_funcs.h`.
+// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
+
+inline double fmod(double p_x, double p_y) {
+ return ::fmod(p_x, p_y);
+}
+inline float fmod(float p_x, float p_y) {
+ return ::fmodf(p_x, p_y);
+}
+
+inline double floor(double p_x) {
+ return ::floor(p_x);
+}
+inline float floor(float p_x) {
+ return ::floorf(p_x);
+}
+
+inline double exp(double p_x) {
+ return ::exp(p_x);
+}
+inline float exp(float p_x) {
+ return ::expf(p_x);
+}
+
+inline double sin(double p_x) {
+ return ::sin(p_x);
+}
+inline float sin(float p_x) {
+ return ::sinf(p_x);
+}
+
+inline double cos(double p_x) {
+ return ::cos(p_x);
+}
+inline float cos(float p_x) {
+ return ::cosf(p_x);
+}
+
+inline double tan(double p_x) {
+ return ::tan(p_x);
+}
+inline float tan(float p_x) {
+ return ::tanf(p_x);
+}
+
+inline double atan2(double p_y, double p_x) {
+ return ::atan2(p_y, p_x);
+}
+inline float atan2(float p_y, float p_x) {
+ return ::atan2f(p_y, p_x);
+}
+
+inline double sqrt(double p_x) {
+ return ::sqrt(p_x);
+}
+inline float sqrt(float p_x) {
+ return ::sqrtf(p_x);
+}
+
+inline float lerp(float minv, float maxv, float t) {
+ return minv + t * (maxv - minv);
+}
+inline double lerp(double minv, double maxv, double t) {
+ return minv + t * (maxv - minv);
+}
+
+inline double lerp_angle(double p_from, double p_to, double p_weight) {
+ double difference = fmod(p_to - p_from, Math_TAU);
+ double distance = fmod(2.0 * difference, Math_TAU) - difference;
+ return p_from + distance * p_weight;
+}
+inline float lerp_angle(float p_from, float p_to, float p_weight) {
+ float difference = fmod(p_to - p_from, (float)Math_TAU);
+ float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
+ return p_from + distance * p_weight;
+}
+
+template <typename T>
+inline T clamp(T x, T minv, T maxv) {
+ if (x < minv) {
+ return minv;
+ }
+ if (x > maxv) {
+ return maxv;
+ }
+ return x;
+}
+
+template <typename T>
+inline T min(T a, T b) {
+ return a < b ? a : b;
+}
+
+template <typename T>
+inline T max(T a, T b) {
+ return a > b ? a : b;
+}
+
+template <typename T>
+inline T sign(T x) {
+ return x < 0 ? -1 : 1;
+}
+
+inline double deg2rad(double p_y) {
+ return p_y * Math_PI / 180.0;
+}
+inline float deg2rad(float p_y) {
+ return p_y * Math_PI / 180.0;
+}
+
+inline double rad2deg(double p_y) {
+ return p_y * 180.0 / Math_PI;
+}
+inline float rad2deg(float p_y) {
+ return p_y * 180.0 / Math_PI;
+}
+
+inline double inverse_lerp(double p_from, double p_to, double p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+}
+inline float inverse_lerp(float p_from, float p_to, float p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+}
+
+inline double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+}
+inline float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+}
+
+inline bool is_equal_approx(real_t a, real_t b) {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b) {
+ return true;
+ }
+ // Then check for approximate equality.
+ real_t tolerance = CMP_EPSILON * std::abs(a);
+ if (tolerance < CMP_EPSILON) {
+ tolerance = CMP_EPSILON;
+ }
+ return std::abs(a - b) < tolerance;
+}
+
+inline bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b) {
+ return true;
+ }
+ // Then check for approximate equality.
+ return std::abs(a - b) < tolerance;
+}
+
+inline bool is_zero_approx(real_t s) {
+ return std::abs(s) < CMP_EPSILON;
+}
+
+inline double smoothstep(double p_from, double p_to, double p_weight) {
+ if (is_equal_approx(p_from, p_to)) {
+ return p_from;
+ }
+ double x = clamp((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
+ return x * x * (3.0 - 2.0 * x);
+}
+inline float smoothstep(float p_from, float p_to, float p_weight) {
+ if (is_equal_approx(p_from, p_to)) {
+ return p_from;
+ }
+ float x = clamp((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
+ return x * x * (3.0f - 2.0f * x);
+}
+
+inline double move_toward(double p_from, double p_to, double p_delta) {
+ return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
+}
+
+inline float move_toward(float p_from, float p_to, float p_delta) {
+ return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
+}
+
+inline double linear2db(double p_linear) {
+ return log(p_linear) * 8.6858896380650365530225783783321;
+}
+inline float linear2db(float p_linear) {
+ return log(p_linear) * 8.6858896380650365530225783783321f;
+}
+
+inline double db2linear(double p_db) {
+ return exp(p_db * 0.11512925464970228420089957273422);
+}
+inline float db2linear(float p_db) {
+ return exp(p_db * 0.11512925464970228420089957273422f);
+}
+
+inline double round(double p_val) {
+ return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
+}
+inline float round(float p_val) {
+ return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
+}
+
+inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
+ int64_t range = max - min;
+ return range == 0 ? min : min + ((((value - min) % range) + range) % range);
+}
+
+inline double wrapf(double value, double min, double max) {
+ double range = max - min;
+ return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
+}
+inline float wrapf(float value, float min, float max) {
+ float range = max - min;
+ return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
+}
+
+inline real_t stepify(real_t p_value, real_t p_step) {
+ if (p_step != 0) {
+ p_value = floor(p_value / p_step + 0.5) * p_step;
+ }
+ return p_value;
+}
+
+inline unsigned int next_power_of_2(unsigned int x) {
+
+ if (x == 0)
+ return 0;
+
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+
+ return ++x;
+}
+
+} // namespace Math
+} // namespace godot
+
+#endif // GODOT_MATH_H
diff --git a/include/core/RID.hpp b/include/core/RID.hpp index d89823b..2191bbf 100644 --- a/include/core/RID.hpp +++ b/include/core/RID.hpp @@ -15,7 +15,9 @@ public: RID(Object *p); - int32_t get_rid() const; + godot_rid _get_godot_rid() const; + + int32_t get_id() const; inline bool is_valid() const { // is_valid() is not available in the C API... diff --git a/include/core/String.hpp b/include/core/String.hpp index d448567..ebf161a 100644 --- a/include/core/String.hpp +++ b/include/core/String.hpp @@ -29,6 +29,9 @@ public: class String { godot_string _godot_string; + String(godot_string contents) : + _godot_string(contents) {} + public: String(); String(const char *contents); diff --git a/include/core/Vector2.hpp b/include/core/Vector2.hpp index 99ac60f..031d47f 100644 --- a/include/core/Vector2.hpp +++ b/include/core/Vector2.hpp @@ -5,7 +5,7 @@ #include "Defs.hpp" -#include <cmath> +#include <Math.hpp> namespace godot { @@ -138,6 +138,12 @@ struct Vector2 { return atan2(y - p_vector2.y, x - p_vector2.x); } + inline Vector2 direction_to(const Vector2 &p_b) const { + Vector2 ret(p_b.x - x, p_b.y - y); + ret.normalize(); + return ret; + } + inline real_t dot(const Vector2 &p_other) const { return x * p_other.x + y * p_other.y; } @@ -172,6 +178,13 @@ struct Vector2 { Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const; + Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const { + Vector2 v = *this; + Vector2 vd = p_to - v; + real_t len = vd.length(); + return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta; + } + inline Vector2 slide(const Vector2 &p_vec) const { return p_vec - *this * this->dot(p_vec); } @@ -180,8 +193,8 @@ struct Vector2 { return -reflect(p_normal); } - inline Vector2 reflect(const Vector2 &p_vec) const { - return p_vec - *this * this->dot(p_vec) * 2.0; + inline Vector2 reflect(const Vector2 &p_normal) const { + return -(*this - p_normal * this->dot(p_normal) * 2.0); } inline real_t angle() const { @@ -209,13 +222,13 @@ struct Vector2 { } inline Vector2 floor() const { - return Vector2(::floor(x), ::floor(y)); + return Vector2(Math::floor(x), Math::floor(y)); } inline Vector2 snapped(const Vector2 &p_by) const { return Vector2( - p_by.x != 0 ? ::floor(x / p_by.x + 0.5) * p_by.x : x, - p_by.y != 0 ? ::floor(y / p_by.y + 0.5) * p_by.y : y); + Math::stepify(x, p_by.x), + Math::stepify(y, p_by.y)); } inline real_t aspect() const { return width / height; } @@ -227,6 +240,22 @@ inline Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } +namespace Math { + +// Convenience, since they exist in GDScript + +inline Vector2 cartesian2polar(Vector2 v) { + return Vector2(Math::sqrt(v.x * v.x + v.y * v.y), Math::atan2(v.y, v.x)); +} + +inline Vector2 polar2cartesian(Vector2 v) { + // x == radius + // y == angle + return Vector2(v.x * Math::cos(v.y), v.x * Math::sin(v.y)); +} + +} // namespace Math + } // namespace godot #endif // VECTOR2_H diff --git a/include/core/Vector3.hpp b/include/core/Vector3.hpp index 2d78f21..5971787 100644 --- a/include/core/Vector3.hpp +++ b/include/core/Vector3.hpp @@ -7,7 +7,7 @@ #include "String.hpp" -#include <cmath> +#include <Math.hpp> namespace godot { @@ -165,8 +165,20 @@ struct Vector3 { z + (p_t * (p_b.z - z))); } + inline Vector3 slerp(const Vector3 &p_b, real_t p_t) const { + real_t theta = angle_to(p_b); + return rotated(cross(p_b).normalized(), theta * p_t); + } + Vector3 cubic_interpolate(const Vector3 &b, const Vector3 &pre_a, const Vector3 &post_b, const real_t t) const; + Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const { + Vector3 v = *this; + Vector3 vd = p_to - v; + real_t len = vd.length(); + return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta; + } + Vector3 bounce(const Vector3 &p_normal) const { return -reflect(p_normal); } @@ -199,10 +211,20 @@ struct Vector3 { return x * b.x + y * b.y + z * b.z; } + inline Vector3 project(const Vector3 &p_b) const { + return p_b * (dot(p_b) / p_b.length_squared()); + } + inline real_t angle_to(const Vector3 &b) const { return std::atan2(cross(b).length(), dot(b)); } + inline Vector3 direction_to(const Vector3 &p_b) const { + Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z); + ret.normalize(); + return ret; + } + inline Vector3 floor() const { return Vector3(::floor(x), ::floor(y), ::floor(z)); } @@ -238,8 +260,8 @@ struct Vector3 { return v; } - inline Vector3 reflect(const Vector3 &by) const { - return by - *this * this->dot(by) * 2.f; + inline Vector3 reflect(const Vector3 &p_normal) const { + return -(*this - p_normal * this->dot(p_normal) * 2.0); } inline Vector3 rotated(const Vector3 &axis, const real_t phi) const { @@ -251,7 +273,7 @@ struct Vector3 { void rotate(const Vector3 &p_axis, real_t p_phi); inline Vector3 slide(const Vector3 &by) const { - return by - *this * this->dot(by); + return *this - by * this->dot(by); } void snap(real_t p_val); |
