Merge branch 'master' into master
This commit is contained in:
@@ -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);
|
||||
|
||||
103
include/core/CameraMatrix.hpp
Normal file
103
include/core/CameraMatrix.hpp
Normal file
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -17,60 +17,113 @@
|
||||
|
||||
#include "GodotGlobal.hpp"
|
||||
|
||||
#include <GDNativeLibrary.hpp>
|
||||
#include <NativeScript.hpp>
|
||||
|
||||
namespace godot {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
T *as(const Object *obj) {
|
||||
return (obj) ? (T *)godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner) : nullptr;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#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)); } \
|
||||
\
|
||||
// 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 *get_custom_class_instance(const Object *obj) {
|
||||
return (obj) ? (T *)godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner) : nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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);
|
||||
}
|
||||
|
||||
} // 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 (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) {
|
||||
if (!godot::_TagDB::is_type_known((size_t)have_tag)) {
|
||||
have_tag = 0;
|
||||
if (!have_tag) {
|
||||
have_tag = obj->_type_tag;
|
||||
}
|
||||
|
||||
if (godot::_TagDB::is_type_compatible(T::___get_id(), have_tag)) {
|
||||
return detail::get_custom_class_instance<T>(obj);
|
||||
}
|
||||
} else {
|
||||
if (godot::core_1_2_api->godot_object_cast_to(obj->_owner, (void *)T::___get_id())) {
|
||||
return (T *)obj;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_H
|
||||
#endif // GODOT_HPP
|
||||
|
||||
250
include/core/Math.hpp
Normal file
250
include/core/Math.hpp
Normal file
@@ -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
|
||||
@@ -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...
|
||||
|
||||
@@ -29,6 +29,9 @@ public:
|
||||
class String {
|
||||
godot_string _godot_string;
|
||||
|
||||
String(godot_string contents) :
|
||||
_godot_string(contents) {}
|
||||
|
||||
public:
|
||||
String();
|
||||
String(const char *contents);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user