summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/core/Array.hpp5
-rw-r--r--include/core/CameraMatrix.hpp103
-rw-r--r--include/core/Color.hpp18
-rw-r--r--include/core/Defs.hpp8
-rw-r--r--include/core/Dictionary.hpp5
-rw-r--r--include/core/Godot.hpp253
-rw-r--r--include/core/Math.hpp250
-rw-r--r--include/core/RID.hpp4
-rw-r--r--include/core/String.hpp3
-rw-r--r--include/core/Vector2.hpp41
-rw-r--r--include/core/Vector3.hpp30
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);