diff options
95 files changed, 1159 insertions, 542 deletions
diff --git a/core/make_binders.py b/core/make_binders.py index 4c61b90d99..5c1c66cab6 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -9,6 +9,12 @@ public: $ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$; #ifdef DEBUG_METHODS_ENABLED virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); } + virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const { + $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$ + $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA; + $ + return GodotTypeInfo::METADATA_NONE; + } Variant::Type _get_argument_type(int p_argument) const { $ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$ $arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE; @@ -94,6 +100,12 @@ public: #ifdef DEBUG_METHODS_ENABLED virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); } + virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const { + $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$ + $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA; + $ + return GodotTypeInfo::METADATA_NONE; + } Variant::Type _get_argument_type(int p_argument) const { $ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$ diff --git a/core/math/delaunay.h b/core/math/delaunay.h index bd0cf97937..ed52c506db 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -80,11 +80,11 @@ public: } static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) { - if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON) { + if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) { return true; } - if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON) { + if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) { return true; } diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index a84b5a16c7..0ab8707d3a 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -836,7 +836,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes Vector3 rel = edge1_A - edge0_A; real_t den = clip.normal.dot(rel); - if (Math::abs(den) < CMP_EPSILON) + if (Math::is_zero_approx(den)) continue; // point too short real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den; diff --git a/core/math/geometry.h b/core/math/geometry.h index 7347cb742a..f3a671aa9a 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -181,8 +181,8 @@ public: } } // finally do the division to get sc and tc - sc = (Math::abs(sN) < CMP_EPSILON ? 0.0 : sN / sD); - tc = (Math::abs(tN) < CMP_EPSILON ? 0.0 : tN / tD); + sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD); + tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD); // get the difference of the two closest points Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) @@ -195,7 +195,7 @@ public: Vector3 e2 = p_v2 - p_v0; Vector3 h = p_dir.cross(e2); real_t a = e1.dot(h); - if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test + if (Math::is_zero_approx(a)) // parallel test return false; real_t f = 1.0 / a; @@ -233,7 +233,7 @@ public: Vector3 e2 = p_v2 - p_v0; Vector3 h = rel.cross(e2); real_t a = e1.dot(h); - if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test + if (Math::is_zero_approx(a)) // parallel test return false; real_t f = 1.0 / a; @@ -535,7 +535,7 @@ public: // see http://paulbourke.net/geometry/pointlineplane/ const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y; - if (Math::abs(denom) < CMP_EPSILON) { // parallel? + if (Math::is_zero_approx(denom)) { // parallel? return false; } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 0d209402dd..a75f2fb4ab 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -272,13 +272,20 @@ public: return diff < epsilon; } - static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) { - // TODO: Comparing floats for approximate-equality is non-trivial. - // Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators. - // A proper implementation in terms of ULPs should eventually replace the contents of this function. - // See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details. + static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) { + real_t tolerance = CMP_EPSILON * abs(a); + if (tolerance < CMP_EPSILON) { + tolerance = CMP_EPSILON; + } + return abs(a - b) < tolerance; + } + + static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) { + return abs(a - b) < tolerance; + } - return abs(a - b) < epsilon; + static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) { + return abs(s) < CMP_EPSILON; } static _ALWAYS_INLINE_ float absf(float g) { diff --git a/core/math/plane.cpp b/core/math/plane.cpp index cd3cbce300..b01853c4ac 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -110,7 +110,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 real_t den = normal.dot(segment); //printf("den is %i\n",den); - if (Math::abs(den) <= CMP_EPSILON) { + if (Math::is_zero_approx(den)) { return false; } @@ -135,7 +135,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec real_t den = normal.dot(segment); //printf("den is %i\n",den); - if (Math::abs(den) <= CMP_EPSILON) { + if (Math::is_zero_approx(den)) { return false; } diff --git a/core/math/plane.h b/core/math/plane.h index 1c6e4b816b..ec817edd2c 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_ bool Plane::operator==(const Plane &p_plane) const { - return normal == p_plane.normal && d == p_plane.d; + return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d); } bool Plane::operator!=(const Plane &p_plane) const { - return normal != p_plane.normal || d != p_plane.d; + return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d); } #endif // PLANE_H diff --git a/core/math/vector2.h b/core/math/vector2.h index 9a214ef9b5..a0c6024c9f 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -106,8 +106,8 @@ struct Vector2 { bool operator==(const Vector2 &p_vec2) const; bool operator!=(const Vector2 &p_vec2) const; - bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); } + bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); } real_t angle() const; @@ -213,11 +213,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const { _FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { - return x == p_vec2.x && y == p_vec2.y; + return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y); } _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { - return x != p_vec2.x || y != p_vec2.y; + return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y); } Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const { diff --git a/core/math/vector3.h b/core/math/vector3.h index e9074c5bd4..21fc09653f 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -341,17 +341,17 @@ Vector3 Vector3::operator-() const { bool Vector3::operator==(const Vector3 &p_v) const { - return (x == p_v.x && y == p_v.y && z == p_v.z); + return (Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z)); } bool Vector3::operator!=(const Vector3 &p_v) const { - return (x != p_v.x || y != p_v.y || z != p_v.z); + return (!Math::is_equal_approx(x, p_v.x) || !Math::is_equal_approx(y, p_v.y) || !Math::is_equal_approx(z, p_v.z)); } bool Vector3::operator<(const Vector3 &p_v) const { - if (x == p_v.x) { - if (y == p_v.y) + if (Math::is_equal_approx(x, p_v.x)) { + if (Math::is_equal_approx(y, p_v.y)) return z < p_v.z; else return y < p_v.y; @@ -362,8 +362,8 @@ bool Vector3::operator<(const Vector3 &p_v) const { bool Vector3::operator<=(const Vector3 &p_v) const { - if (x == p_v.x) { - if (y == p_v.y) + if (Math::is_equal_approx(x, p_v.x)) { + if (Math::is_equal_approx(y, p_v.y)) return z <= p_v.z; else return y < p_v.y; @@ -402,13 +402,14 @@ real_t Vector3::length_squared() const { void Vector3::normalize() { - real_t l = length(); - if (l == 0) { + real_t lengthsq = length_squared(); + if (lengthsq == 0) { x = y = z = 0; } else { - x /= l; - y /= l; - z /= l; + real_t length = Math::sqrt(lengthsq); + x /= length; + y /= length; + z /= length; } } diff --git a/core/method_bind.h b/core/method_bind.h index 5ea8adb7e0..1b0c3b27c0 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -273,6 +273,8 @@ public: void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise Vector<StringName> get_argument_names() const; + virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0; + #endif void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; } uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); } @@ -329,6 +331,10 @@ public: return _gen_argument_type_info(p_arg).type; } + virtual GodotTypeInfo::Metadata get_argument_meta(int) const { + return GodotTypeInfo::METADATA_NONE; + } + #else virtual Variant::Type _gen_argument_type(int p_arg) const { diff --git a/core/object.cpp b/core/object.cpp index 039f556c87..f860423a27 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1059,6 +1059,10 @@ Variant Object::get_meta(const String &p_name) const { return metadata[p_name]; } +void Object::remove_meta(const String &p_name) { + metadata.erase(p_name); +} + Array Object::_get_property_list_bind() const { List<PropertyInfo> lpi; @@ -1691,6 +1695,7 @@ void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script); ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta); + ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta); ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta); ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta); ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind); diff --git a/core/object.h b/core/object.h index 3730af1ad4..94abaacdcc 100644 --- a/core/object.h +++ b/core/object.h @@ -673,6 +673,7 @@ public: bool has_meta(const String &p_name) const; void set_meta(const String &p_name, const Variant &p_value); + void remove_meta(const String &p_name); Variant get_meta(const String &p_name) const; void get_meta_list(List<String> *p_list) const; diff --git a/core/reference.h b/core/reference.h index 9105dbbd58..8a19f846c7 100644 --- a/core/reference.h +++ b/core/reference.h @@ -375,7 +375,8 @@ struct PtrToArg<const RefPtr &> { template <class T> struct GetTypeInfo<Ref<T> > { - enum { VARIANT_TYPE = Variant::OBJECT }; + static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static()); @@ -384,7 +385,8 @@ struct GetTypeInfo<Ref<T> > { template <class T> struct GetTypeInfo<const Ref<T> &> { - enum { VARIANT_TYPE = Variant::OBJECT }; + static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static()); diff --git a/core/type_info.h b/core/type_info.h index c38688fea1..d85a63ee42 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -67,43 +67,80 @@ struct TypeInherits { !TypesAreSame<B volatile const, void volatile const>::value; }; +namespace GodotTypeInfo { +enum Metadata { + METADATA_NONE, + METADATA_INT_IS_INT8, + METADATA_INT_IS_INT16, + METADATA_INT_IS_INT32, + METADATA_INT_IS_INT64, + METADATA_INT_IS_UINT8, + METADATA_INT_IS_UINT16, + METADATA_INT_IS_UINT32, + METADATA_INT_IS_UINT64, + METADATA_REAL_IS_FLOAT, + METADATA_REAL_IS_DOUBLE +}; +} + template <class T, typename = void> struct GetTypeInfo { static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { ERR_PRINT("GetTypeInfo fallback. Bug!"); return PropertyInfo(); // Not "Nil", this is an error } }; -#define MAKE_TYPE_INFO(m_type, m_var_type) \ - template <> \ - struct GetTypeInfo<m_type> { \ - static const Variant::Type VARIANT_TYPE = m_var_type; \ - static inline PropertyInfo get_class_info() { \ - return PropertyInfo(VARIANT_TYPE, String()); \ - } \ - }; \ - template <> \ - struct GetTypeInfo<const m_type &> { \ - static const Variant::Type VARIANT_TYPE = m_var_type; \ - static inline PropertyInfo get_class_info() { \ - return PropertyInfo(VARIANT_TYPE, String()); \ - } \ +#define MAKE_TYPE_INFO(m_type, m_var_type) \ + template <> \ + struct GetTypeInfo<m_type> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; \ + template <> \ + struct GetTypeInfo<const m_type &> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; + +#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \ + template <> \ + struct GetTypeInfo<m_type> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const GodotTypeInfo::Metadata METADATA = m_metadata; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; \ + template <> \ + struct GetTypeInfo<const m_type &> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const GodotTypeInfo::Metadata METADATA = m_metadata; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ }; MAKE_TYPE_INFO(bool, Variant::BOOL) -MAKE_TYPE_INFO(uint8_t, Variant::INT) -MAKE_TYPE_INFO(int8_t, Variant::INT) -MAKE_TYPE_INFO(uint16_t, Variant::INT) -MAKE_TYPE_INFO(int16_t, Variant::INT) -MAKE_TYPE_INFO(uint32_t, Variant::INT) -MAKE_TYPE_INFO(int32_t, Variant::INT) -MAKE_TYPE_INFO(int64_t, Variant::INT) -MAKE_TYPE_INFO(uint64_t, Variant::INT) +MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8) +MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8) +MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16) +MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16) +MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32) +MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32) +MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64) +MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64) MAKE_TYPE_INFO(wchar_t, Variant::INT) -MAKE_TYPE_INFO(float, Variant::REAL) -MAKE_TYPE_INFO(double, Variant::REAL) +MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_FLOAT) +MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_DOUBLE) MAKE_TYPE_INFO(String, Variant::STRING) MAKE_TYPE_INFO(Vector2, Variant::VECTOR2) @@ -138,6 +175,7 @@ MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY) template <> struct GetTypeInfo<RefPtr> { static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference"); } @@ -145,6 +183,7 @@ struct GetTypeInfo<RefPtr> { template <> struct GetTypeInfo<const RefPtr &> { static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference"); } @@ -154,6 +193,7 @@ struct GetTypeInfo<const RefPtr &> { template <> struct GetTypeInfo<Variant> { static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT); } @@ -162,25 +202,28 @@ struct GetTypeInfo<Variant> { template <> struct GetTypeInfo<const Variant &> { static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT); } }; -#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \ - template <> \ - struct GetTypeInfo<m_template<m_type> > { \ - static const Variant::Type VARIANT_TYPE = m_var_type; \ - static inline PropertyInfo get_class_info() { \ - return PropertyInfo(VARIANT_TYPE, String()); \ - } \ - }; \ - template <> \ - struct GetTypeInfo<const m_template<m_type> &> { \ - static const Variant::Type VARIANT_TYPE = m_var_type; \ - static inline PropertyInfo get_class_info() { \ - return PropertyInfo(VARIANT_TYPE, String()); \ - } \ +#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \ + template <> \ + struct GetTypeInfo<m_template<m_type> > { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; \ + template <> \ + struct GetTypeInfo<const m_template<m_type> &> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ }; MAKE_TEMPLATE_TYPE_INFO(Vector, uint8_t, Variant::POOL_BYTE_ARRAY) @@ -202,6 +245,7 @@ MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY) template <typename T> struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> { static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(StringName(T::get_class_static())); } @@ -210,6 +254,7 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> template <typename T> struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> { static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { return PropertyInfo(StringName(T::get_class_static())); } @@ -219,6 +264,7 @@ struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>: template <> \ struct GetTypeInfo<m_impl> { \ static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ static inline PropertyInfo get_class_info() { \ return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \ } \ diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml index 29bf9b62ce..22834a4c81 100644 --- a/doc/classes/@GDScript.xml +++ b/doc/classes/@GDScript.xml @@ -498,6 +498,17 @@ [/codeblock] </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="a" type="float"> + </argument> + <argument index="1" name="b" type="float"> + </argument> + <description> + Returns True/False whether [code]a[/code] and [code]b[/code] are approximately equal to each other. + </description> + </method> <method name="is_inf"> <return type="bool"> </return> @@ -525,6 +536,15 @@ Returns whether [code]s[/code] is a NaN (Not-A-Number) value. </description> </method> + <method name="is_zero_approx"> + <return type="bool"> + </return> + <argument index="0" name="s" type="float"> + </argument> + <description> + Returns True/False whether [code]s[/code] is zero or almost zero. + </description> + </method> <method name="len"> <return type="int"> </return> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 1817055bab..fa78fbe305 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -41,6 +41,7 @@ <argument index="0" name="line" type="int"> </argument> <description> + Returns if the given line is foldable, that is, it has indented lines right below it. </description> </method> <method name="clear_colors"> @@ -120,6 +121,7 @@ <return type="void"> </return> <description> + Folds all lines that are possible to be folded (see [method can_fold]). </description> </method> <method name="fold_line"> @@ -128,6 +130,7 @@ <argument index="0" name="line" type="int"> </argument> <description> + Folds the given line, if possible (see [method can_fold]). </description> </method> <method name="get_breakpoints" qualifiers="const"> @@ -165,6 +168,7 @@ <return type="PopupMenu"> </return> <description> + Returns the [PopupMenu] of this [TextEdit]. By default, this menu is displayed when right-clicking on the [TextEdit]. </description> </method> <method name="get_selection_from_column" qualifiers="const"> @@ -231,6 +235,7 @@ <argument index="0" name="line" type="int"> </argument> <description> + Returns if the given line is folded. </description> </method> <method name="is_line_hidden" qualifiers="const"> @@ -346,6 +351,7 @@ <argument index="0" name="line" type="int"> </argument> <description> + Unfolds the given line, if folded. </description> </method> <method name="unhide_all_lines"> @@ -376,6 +382,12 @@ <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled"> If [code]true[/code], a right click displays the context menu. </member> + <member name="draw_tabs" type="bool" setter="set_draw_tabs" getter="is_drawing_tabs"> + If [code]true[/code], the "tab" character will have a visible representation. + </member> + <member name="fold_gutter" type="bool" setter="set_fold_gutter_enabled" getter="is_fold_gutter_enabled"> + If [code]true[/code], the fold gutter is visible. This enables folding groups of indented lines. + </member> <member name="hiding_enabled" type="int" setter="set_hiding_enabled" getter="is_hiding_enabled"> </member> <member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled"> diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 5d21c679ba..1c35b455c4 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -1545,6 +1545,11 @@ FRAGMENT_SHADER_CODE #ifdef BASE_PASS //none + +#ifdef AMBIENT_LIGHT_DISABLED + ambient_light = vec3(0.0, 0.0, 0.0); +#else + #ifdef USE_RADIANCE_MAP vec3 ref_vec = reflect(-eye_position, N); @@ -1567,6 +1572,7 @@ FRAGMENT_SHADER_CODE #endif +#endif // AMBIENT_LIGHT_DISABLED ambient_light *= ambient_energy; #if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 2376d08077..def55d6057 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -544,7 +544,7 @@ public: if (use_fps && animation->get_step() > 0) { float max_frame = animation->get_length() / animation->get_step(); - p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1")); } else { p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01")); } @@ -4122,6 +4122,7 @@ void AnimationTrackEditor::_update_key_edit() { key_edit = memnew(AnimationTrackKeyEdit); key_edit->animation = animation; key_edit->track = selection.front()->key().track; + key_edit->use_fps = timeline->is_using_fps(); float ofs = animation->track_get_key_time(key_edit->track, selection.front()->key().key); key_edit->key_ofs = ofs; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index a9ec776693..d655f52f5d 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1177,6 +1177,14 @@ void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { text_editor->select(p_line, p_begin, p_line, p_end); } +void CodeTextEditor::set_executing_line(int p_line) { + text_editor->set_executing_line(p_line); +} + +void CodeTextEditor::clear_executing_line() { + text_editor->clear_executing_line(); +} + Variant CodeTextEditor::get_edit_state() { Dictionary state; diff --git a/editor/code_editor.h b/editor/code_editor.h index e3dbfe1ce0..b98af377ce 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -217,6 +217,8 @@ public: void goto_line(int p_line); void goto_line_selection(int p_line, int p_begin, int p_end); + void set_executing_line(int p_line); + void clear_executing_line(); Variant get_edit_state(); void set_edit_state(const Variant &p_state); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 03a71f3248..a9a96da7b1 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -113,14 +113,14 @@ Signal automatically called by parent dialog. void ConnectDialog::ok_pressed() { if (dst_method->get_text() == "") { - error->set_text(TTR("Method in target Node must be specified!")); + error->set_text(TTR("Method in target node must be specified.")); error->popup_centered_minsize(); return; } Node *target = tree->get_selected(); if (target->get_script().is_null()) { if (!target->has_method(dst_method->get_text())) { - error->set_text(TTR("Target method not found! Specify a valid method or attach a script to target Node.")); + error->set_text(TTR("Target method not found. Specify a valid method or attach a script to the target node.")); error->popup_centered_minsize(); return; } @@ -444,8 +444,9 @@ ConnectDialog::ConnectDialog() { cdbinds = memnew(ConnectDialogBinds); - error = memnew(ConfirmationDialog); + error = memnew(AcceptDialog); add_child(error); + error->set_title(TTR("Cannot connect signal")); error->get_ok()->set_text(TTR("Close")); get_ok()->set_text(TTR("Connect")); } diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 59fe6dacfe..9b35d84426 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -64,7 +64,7 @@ class ConnectDialog : public ConfirmationDialog { VBoxContainer *vbc_right; SceneTreeEditor *tree; - ConfirmationDialog *error; + AcceptDialog *error; EditorInspector *bind_editor; OptionButton *type_list; CheckButton *deferred; diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index e0a2bbf477..5917869988 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -97,8 +97,10 @@ void EditorHelp::_class_desc_select(const String &p_select) { emit_signal("go_to_help", "class_name:" + p_select.substr(1, p_select.length())); return; } else if (p_select.begins_with("@")) { - String tag = p_select.substr(1, 8).rstrip(" "); - String link = p_select.substr(9, p_select.length()); + int tag_end = p_select.find(" "); + + String tag = p_select.substr(1, tag_end - 1); + String link = p_select.substr(tag_end + 1, p_select.length()).lstrip(" "); String topic; Map<String, int> *table = NULL; @@ -230,7 +232,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview } if (p_overview && p_method.description != "") { - class_desc->push_meta("@method" + p_method.name); + class_desc->push_meta("@method " + p_method.name); } class_desc->push_color(headline_color); @@ -468,7 +470,7 @@ void EditorHelp::_update_doc() { } class_desc->push_cell(); if (describe) { - class_desc->push_meta("@member" + cd.properties[i].name); + class_desc->push_meta("@member " + cd.properties[i].name); } class_desc->push_font(doc_code_font); @@ -1192,10 +1194,13 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) { - String link_target = tag.substr(tag.find(" ") + 1, tag.length()); - String link_tag = tag.substr(0, tag.find(" ")).rpad(8); + int tag_end = tag.find(" "); + + String link_tag = tag.substr(0, tag_end); + String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" "); + p_rt->push_color(link_color); - p_rt->push_meta("@" + link_tag + link_target); + p_rt->push_meta("@" + link_tag + " " + link_target); p_rt->add_text(link_target + (tag.begins_with("method ") ? "()" : "")); p_rt->pop(); p_rt->pop(); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index b0a1331b2e..ecb9ea5f35 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -434,7 +434,7 @@ bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Varian float a = p_current; float b = p_orig; - return Math::abs(a - b) > CMP_EPSILON; //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error + return !Math::is_equal_approx(a, b); //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error } return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig)); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index cbb7994635..df653d6d03 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2451,7 +2451,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case SETTINGS_MANAGE_FEATURE_PROFILES: { - feature_profile_manager->popup_centered_ratio(); + Size2 popup_size = Size2(900, 800) * editor_get_scale(); + Size2 window_size = get_viewport()->get_size(); + + popup_size.x = MIN(window_size.x * 0.8, popup_size.x); + popup_size.y = MIN(window_size.y * 0.8, popup_size.y); + + feature_profile_manager->popup_centered(popup_size); } break; case SETTINGS_TOGGLE_FULLSCREEN: { diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index 7e9d3a889e..12510e27de 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -56,122 +56,67 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) { Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(obj); - int index = popup->get_item_count(); - popup->add_icon_item(icon, E->get().name.capitalize(), objects.size()); - popup->set_item_h_offset(index, p_depth * 10 * EDSCALE); + int index = get_popup()->get_item_count(); + get_popup()->add_icon_item(icon, E->get().name.capitalize(), objects.size()); + get_popup()->set_item_h_offset(index, p_depth * 10 * EDSCALE); objects.push_back(obj->get_instance_id()); _add_children_to_popup(obj, p_depth + 1); } } -void EditorPath::_gui_input(const Ref<InputEvent> &p_event) { +void EditorPath::_about_to_show() { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - - Object *obj = ObjectDB::get_instance(history->get_path_object(history->get_path_size() - 1)); - if (!obj) - return; - - objects.clear(); - popup->clear(); - _add_children_to_popup(obj); - popup->set_position(get_global_position() + Vector2(0, get_size().height)); - popup->set_size(Size2(get_size().width, 1)); - popup->popup(); - } -} + Object *obj = ObjectDB::get_instance(history->get_path_object(history->get_path_size() - 1)); + if (!obj) + return; -void EditorPath::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_MOUSE_ENTER: { - mouse_over = true; - update(); - } break; - case NOTIFICATION_MOUSE_EXIT: { - mouse_over = false; - update(); - } break; - case NOTIFICATION_DRAW: { - - RID ci = get_canvas_item(); - Ref<Font> label_font = get_font("font", "Label"); - Size2i size = get_size(); - Ref<Texture> sn = get_icon("SmallNext", "EditorIcons"); - Ref<StyleBox> sb = get_stylebox("pressed", "Button"); - - int ofs = sb->get_margin(MARGIN_LEFT); - - if (mouse_over) { - draw_style_box(sb, Rect2(Point2(), get_size())); - } - - for (int i = 0; i < history->get_path_size(); i++) { - - Object *obj = ObjectDB::get_instance(history->get_path_object(i)); - if (!obj) - continue; - - String type = obj->get_class(); - - Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(obj); - - if (icon.is_valid()) { - icon->draw(ci, Point2i(ofs, (size.height - icon->get_height()) / 2)); - ofs += icon->get_width(); - } - - if (i == history->get_path_size() - 1) { - //add name - ofs += 4; - int left = size.width - ofs; - if (left < 0) - continue; - String name; - if (Object::cast_to<Resource>(obj)) { - - Resource *r = Object::cast_to<Resource>(obj); - if (r->get_path().is_resource_file()) - name = r->get_path().get_file(); - else - name = r->get_name(); - - if (name == "") - name = r->get_class(); - } else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) - name = obj->call("get_title"); - else if (Object::cast_to<Node>(obj)) - name = Object::cast_to<Node>(obj)->get_name(); - else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") - name = Object::cast_to<Resource>(obj)->get_name(); - else - name = obj->get_class(); - - set_tooltip(obj->get_class()); - - label_font->draw(ci, Point2i(ofs, (size.height - label_font->get_height()) / 2 + label_font->get_ascent()), name, get_color("font_color", "Label"), left); - } else { - //add arrow - - //sn->draw(ci,Point2i(ofs,(size.height-sn->get_height())/2)); - //ofs+=sn->get_width(); - ofs += 5; //just looks better! somehow - } - } - - } break; - } + objects.clear(); + get_popup()->clear(); + get_popup()->set_size(Size2(get_size().width, 1)); + _add_children_to_popup(obj); } void EditorPath::update_path() { - update(); + for (int i = 0; i < history->get_path_size(); i++) { + + Object *obj = ObjectDB::get_instance(history->get_path_object(i)); + if (!obj) + continue; + + Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(obj); + if (icon.is_valid()) + set_icon(icon); + + if (i == history->get_path_size() - 1) { + String name; + if (Object::cast_to<Resource>(obj)) { + + Resource *r = Object::cast_to<Resource>(obj); + if (r->get_path().is_resource_file()) + name = r->get_path().get_file(); + else + name = r->get_name(); + + if (name == "") + name = r->get_class(); + } else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) + name = obj->call("get_title"); + else if (Object::cast_to<Node>(obj)) + name = Object::cast_to<Node>(obj)->get_name(); + else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") + name = Object::cast_to<Resource>(obj)->get_name(); + else + name = obj->get_class(); + + set_text(" " + name); // An extra space so the text is not too close of the icon. + set_tooltip(obj->get_class()); + } + } } -void EditorPath::_popup_select(int p_idx) { +void EditorPath::_id_pressed(int p_idx) { ERR_FAIL_INDEX(p_idx, objects.size()); @@ -184,15 +129,14 @@ void EditorPath::_popup_select(int p_idx) { void EditorPath::_bind_methods() { - ClassDB::bind_method("_gui_input", &EditorPath::_gui_input); - ClassDB::bind_method("_popup_select", &EditorPath::_popup_select); + ClassDB::bind_method("_about_to_show", &EditorPath::_about_to_show); + ClassDB::bind_method("_id_pressed", &EditorPath::_id_pressed); } EditorPath::EditorPath(EditorHistory *p_history) { history = p_history; - mouse_over = false; - popup = memnew(PopupMenu); - popup->connect("id_pressed", this, "_popup_select"); - add_child(popup); + set_text_align(ALIGN_LEFT); + get_popup()->connect("about_to_show", this, "_about_to_show"); + get_popup()->connect("id_pressed", this, "_id_pressed"); } diff --git a/editor/editor_path.h b/editor/editor_path.h index e12ca02534..2dc4d21f9b 100644 --- a/editor/editor_path.h +++ b/editor/editor_path.h @@ -32,27 +32,23 @@ #define EDITOR_PATH_H #include "editor_data.h" -#include "scene/gui/control.h" -#include "scene/gui/popup_menu.h" +#include "scene/gui/menu_button.h" -class EditorPath : public Control { +class EditorPath : public MenuButton { - GDCLASS(EditorPath, Control); + GDCLASS(EditorPath, MenuButton); EditorHistory *history; Vector<ObjectID> objects; - PopupMenu *popup; - bool mouse_over; EditorPath(); - void _popup_select(int p_idx); - void _gui_input(const Ref<InputEvent> &p_event); + void _id_pressed(int p_idx); + void _about_to_show(); void _add_children_to_popup(Object *p_obj, int p_depth = 0); protected: static void _bind_methods(); - void _notification(int p_what); public: void update_path(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 54bd9cae20..bf582ca004 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -645,6 +645,7 @@ void EditorSettings::_load_default_text_editor_theme() { _initial_set("text_editor/highlighting/member_variable_color", Color::html("e64e59")); _initial_set("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4)); _initial_set("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2)); + _initial_set("text_editor/highlighting/executing_line_color", Color(0.2, 0.8, 0.2, 0.4)); _initial_set("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8)); _initial_set("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1)); _initial_set("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1)); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 9641e10114..b8dd29cecc 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -831,6 +831,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("read_only", "TextEdit", style_widget_disabled); theme->set_constant("side_margin", "TabContainer", 0); theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons")); + theme->set_icon("folded", "TextEdit", theme->get_icon("GuiTreeArrowRight", "EditorIcons")); + theme->set_icon("fold", "TextEdit", theme->get_icon("GuiTreeArrowDown", "EditorIcons")); theme->set_color("font_color", "TextEdit", font_color); theme->set_color("caret_color", "TextEdit", font_color); theme->set_color("selection_color", "TextEdit", font_color_selection); @@ -1114,6 +1116,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color member_variable_color = main_color.linear_interpolate(mono_color, 0.6); const Color mark_color = Color(error_color.r, error_color.g, error_color.b, 0.3); const Color breakpoint_color = error_color; + const Color executing_line_color = Color(0.2, 0.8, 0.2, 0.4); const Color code_folding_color = alpha3; const Color search_result_color = alpha1; const Color search_result_border_color = alpha3; @@ -1149,6 +1152,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { setting->set_initial_value("text_editor/highlighting/member_variable_color", member_variable_color, true); setting->set_initial_value("text_editor/highlighting/mark_color", mark_color, true); setting->set_initial_value("text_editor/highlighting/breakpoint_color", breakpoint_color, true); + setting->set_initial_value("text_editor/highlighting/executing_line_color", executing_line_color, true); setting->set_initial_value("text_editor/highlighting/code_folding_color", code_folding_color, true); setting->set_initial_value("text_editor/highlighting/search_result_color", search_result_color, true); setting->set_initial_value("text_editor/highlighting/search_result_border_color", search_result_border_color, true); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index ab515785da..8f66cce39a 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1127,7 +1127,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), "")); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), animations_out ? true : false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), animations_out ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05)); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index e5228ff1e7..ab5ff7dee4 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3916,6 +3916,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { viewport->update(); } break; case LOCK_SELECTED: { + undo_redo->create_action(TTR("Lock Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3924,12 +3926,18 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_lock_", true); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(canvas_item, "set_meta", "_edit_lock_", true); + undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_lock_"); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case UNLOCK_SELECTED: { + undo_redo->create_action(TTR("Unlock Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3938,12 +3946,18 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_lock_", Variant()); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_lock_"); + undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_lock_", true); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case GROUP_SELECTED: { + undo_redo->create_action(TTR("Group Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3952,12 +3966,18 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_group_", true); - emit_signal("item_group_status_changed"); + undo_redo->add_do_method(canvas_item, "set_meta", "_edit_group_", true); + undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_group_"); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case UNGROUP_SELECTED: { + undo_redo->create_action(TTR("Ungroup Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3966,10 +3986,14 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_group_", Variant()); - emit_signal("item_group_status_changed"); + undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_group_"); + undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_group_", true); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case ANCHORS_AND_MARGINS_PRESET_TOP_LEFT: { _set_anchors_and_margins_preset(PRESET_TOP_LEFT); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 3d76b5da21..2c0dd5f1db 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -194,7 +194,7 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Vector2 dir = (control_pos - point_pos).normalized(); real_t tangent; - if (Math::abs(dir.x) > CMP_EPSILON) + if (!Math::is_zero_approx(dir.x)) tangent = dir.y / dir.x; else tangent = 9999 * (dir.y >= 0 ? 1 : -1); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 03287b8cf9..d84a5a1e48 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -312,6 +312,38 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) { } } +void ScriptEditor::_set_execution(REF p_script, int p_line) { + Ref<Script> script = Object::cast_to<Script>(*p_script); + if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { + for (int i = 0; i < tab_container->get_child_count(); i++) { + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) + continue; + + if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { + se->set_executing_line(p_line); + } + } + } +} + +void ScriptEditor::_clear_execution(REF p_script) { + Ref<Script> script = Object::cast_to<Script>(*p_script); + if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { + for (int i = 0; i < tab_container->get_child_count(); i++) { + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) + continue; + + if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { + se->clear_executing_line(); + } + } + } +} + ScriptEditorBase *ScriptEditor::_get_current_editor() const { int selected = tab_container->get_current_tab(); @@ -2878,6 +2910,8 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_res_saved_callback", &ScriptEditor::_res_saved_callback); ClassDB::bind_method("_goto_script_line", &ScriptEditor::_goto_script_line); ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2); + ClassDB::bind_method("_set_execution", &ScriptEditor::_set_execution); + ClassDB::bind_method("_clear_execution", &ScriptEditor::_clear_execution); ClassDB::bind_method("_help_search", &ScriptEditor::_help_search); ClassDB::bind_method("_save_history", &ScriptEditor::_save_history); ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path); @@ -3168,6 +3202,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { debugger = memnew(ScriptEditorDebugger(editor)); debugger->connect("goto_script_line", this, "_goto_script_line"); + debugger->connect("set_execution", this, "_set_execution"); + debugger->connect("clear_execution", this, "_clear_execution"); debugger->connect("show_debugger", this, "_show_debugger"); disk_changed = memnew(ConfirmationDialog); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index f13308dec7..a17fed1e06 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -96,6 +96,8 @@ public: virtual Variant get_edit_state() = 0; virtual void set_edit_state(const Variant &p_state) = 0; virtual void goto_line(int p_line, bool p_with_error = false) = 0; + virtual void set_executing_line(int p_line) = 0; + virtual void clear_executing_line() = 0; virtual void trim_trailing_whitespace() = 0; virtual void convert_indent_to_spaces() = 0; virtual void convert_indent_to_tabs() = 0; @@ -318,6 +320,8 @@ class ScriptEditor : public PanelContainer { void _goto_script_line2(int p_line); void _goto_script_line(REF p_script, int p_line); + void _set_execution(REF p_script, int p_line); + void _clear_execution(REF p_script); void _breaked(bool p_breaked, bool p_can_debug); void _show_debugger(bool p_show); void _update_window_menu(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 46b2e8a5f8..d40e67cc8c 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -214,6 +214,7 @@ void ScriptTextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color"); Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); @@ -245,6 +246,7 @@ void ScriptTextEditor::_load_theme_settings() { text_edit->add_color_override("function_color", function_color); text_edit->add_color_override("member_variable_color", member_variable_color); text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("executing_line_color", executing_line_color); text_edit->add_color_override("mark_color", mark_color); text_edit->add_color_override("code_folding_color", code_folding_color); text_edit->add_color_override("search_result_color", search_result_color); @@ -479,6 +481,14 @@ void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { code_editor->goto_line_selection(p_line, p_begin, p_end); } +void ScriptTextEditor::set_executing_line(int p_line) { + code_editor->set_executing_line(p_line); +} + +void ScriptTextEditor::clear_executing_line() { + code_editor->clear_executing_line(); +} + void ScriptTextEditor::ensure_focus() { code_editor->get_text_edit()->grab_focus(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 4edb1c3c67..0dbc884594 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -196,6 +196,8 @@ public: virtual void goto_line(int p_line, bool p_with_error = false); void goto_line_selection(int p_line, int p_begin, int p_end); + virtual void set_executing_line(int p_line); + virtual void clear_executing_line(); virtual void reload(bool p_soft); virtual void get_breakpoints(List<int> *p_breakpoints); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d39e521113..31660a9e19 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -85,6 +85,7 @@ void ShaderTextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color"); Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); @@ -113,6 +114,7 @@ void ShaderTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("member_variable_color", member_variable_color); get_text_edit()->add_color_override("mark_color", mark_color); get_text_edit()->add_color_override("breakpoint_color", breakpoint_color); + get_text_edit()->add_color_override("executing_line_color", executing_line_color); get_text_edit()->add_color_override("code_folding_color", code_folding_color); get_text_edit()->add_color_override("search_result_color", search_result_color); get_text_edit()->add_color_override("search_result_border_color", search_result_border_color); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 47f00dc480..5a733f6509 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2473,7 +2473,7 @@ void SpatialEditorViewport::_draw() { real_t max_speed = camera->get_zfar(); real_t scale_length = (max_speed - min_speed); - if (Math::abs(scale_length) > CMP_EPSILON) { + if (!Math::is_zero_approx(scale_length)) { real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length); // There is no real maximum speed so that factor can become negative, @@ -2491,7 +2491,7 @@ void SpatialEditorViewport::_draw() { real_t max_distance = camera->get_zfar(); real_t scale_length = (max_distance - min_distance); - if (Math::abs(scale_length) > CMP_EPSILON) { + if (!Math::is_zero_approx(scale_length)) { real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length); // There is no real maximum distance so that factor can become negative, @@ -4515,6 +4515,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { snap_selected_nodes_to_floor(); } break; case MENU_LOCK_SELECTED: { + undo_redo->create_action(TTR("Lock Selected")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4527,13 +4528,18 @@ void SpatialEditor::_menu_item_pressed(int p_option) { if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - spatial->set_meta("_edit_lock_", true); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true); + undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_"); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - _refresh_menu_icons(); + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); } break; case MENU_UNLOCK_SELECTED: { + undo_redo->create_action(TTR("Unlock Selected")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4546,13 +4552,18 @@ void SpatialEditor::_menu_item_pressed(int p_option) { if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - spatial->set_meta("_edit_lock_", Variant()); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_"); + undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - _refresh_menu_icons(); + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); } break; case MENU_GROUP_SELECTED: { + undo_redo->create_action(TTR("Group Selected")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4565,14 +4576,18 @@ void SpatialEditor::_menu_item_pressed(int p_option) { if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - spatial->set_meta("_edit_group_", true); - emit_signal("item_group_status_changed"); + undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true); + undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_"); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - _refresh_menu_icons(); + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); } break; case MENU_UNGROUP_SELECTED: { - + undo_redo->create_action(TTR("Ungroup Selected")); List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { @@ -4584,11 +4599,15 @@ void SpatialEditor::_menu_item_pressed(int p_option) { if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - spatial->set_meta("_edit_group_", Variant()); - emit_signal("item_group_status_changed"); + undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_"); + undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - _refresh_menu_icons(); + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); } break; } } diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index afe0b23fd9..6edd19901b 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -89,10 +89,10 @@ void SpriteFramesEditor::_sheet_preview_draw() { if (frames_selected.size() == 0) { split_sheet_dialog->get_ok()->set_disabled(true); - split_sheet_dialog->get_ok()->set_text(TTR("No frames selected")); + split_sheet_dialog->get_ok()->set_text(TTR("No Frames Selected")); } else { split_sheet_dialog->get_ok()->set_disabled(false); - split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d frame(s)"), frames_selected.size())); + split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size())); } } void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { @@ -168,7 +168,24 @@ void SpriteFramesEditor::_sheet_add_frames() { undo_redo->commit_action(); } +void SpriteFramesEditor::_sheet_select_clear_all_frames() { + + bool should_clear = true; + for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) { + if (!frames_selected.has(i)) { + frames_selected.insert(i); + should_clear = false; + } + } + if (should_clear) { + frames_selected.clear(); + } + + split_sheet_preview->update(); +} + void SpriteFramesEditor::_sheet_spin_changed(double) { + frames_selected.clear(); last_frame_selected = -1; split_sheet_preview->update(); @@ -195,22 +212,26 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { void SpriteFramesEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - - load->set_icon(get_icon("Load", "EditorIcons")); - load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons")); - copy->set_icon(get_icon("ActionCopy", "EditorIcons")); - paste->set_icon(get_icon("ActionPaste", "EditorIcons")); - empty->set_icon(get_icon("InsertBefore", "EditorIcons")); - empty2->set_icon(get_icon("InsertAfter", "EditorIcons")); - move_up->set_icon(get_icon("MoveLeft", "EditorIcons")); - move_down->set_icon(get_icon("MoveRight", "EditorIcons")); - _delete->set_icon(get_icon("Remove", "EditorIcons")); - new_anim->set_icon(get_icon("New", "EditorIcons")); - remove_anim->set_icon(get_icon("Remove", "EditorIcons")); - } else if (p_what == NOTIFICATION_READY) { - - add_constant_override("autohide", 1); // Fixes the dragger always showing up. + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + load->set_icon(get_icon("Load", "EditorIcons")); + load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons")); + copy->set_icon(get_icon("ActionCopy", "EditorIcons")); + paste->set_icon(get_icon("ActionPaste", "EditorIcons")); + empty->set_icon(get_icon("InsertBefore", "EditorIcons")); + empty2->set_icon(get_icon("InsertAfter", "EditorIcons")); + move_up->set_icon(get_icon("MoveLeft", "EditorIcons")); + move_down->set_icon(get_icon("MoveRight", "EditorIcons")); + _delete->set_icon(get_icon("Remove", "EditorIcons")); + new_anim->set_icon(get_icon("New", "EditorIcons")); + remove_anim->set_icon(get_icon("Remove", "EditorIcons")); + } // Fallthrough. + case NOTIFICATION_THEME_CHANGED: { + splite_sheet_scroll->add_style_override("bg", get_stylebox("bg", "Tree")); + } break; + case NOTIFICATION_READY: { + add_constant_override("autohide", 1); // Fixes the dragger always showing up. + } break; } } @@ -818,6 +839,7 @@ void SpriteFramesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_sheet_preview_input"), &SpriteFramesEditor::_sheet_preview_input); ClassDB::bind_method(D_METHOD("_sheet_spin_changed"), &SpriteFramesEditor::_sheet_spin_changed); ClassDB::bind_method(D_METHOD("_sheet_add_frames"), &SpriteFramesEditor::_sheet_add_frames); + ClassDB::bind_method(D_METHOD("_sheet_select_clear_all_frames"), &SpriteFramesEditor::_sheet_select_clear_all_frames); } SpriteFramesEditor::SpriteFramesEditor() { @@ -879,7 +901,7 @@ SpriteFramesEditor::SpriteFramesEditor() { hbc->add_child(load); load_sheet = memnew(ToolButton); - load_sheet->set_tooltip(TTR("Add frames from a Sprite Sheet")); + load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet")); hbc->add_child(load_sheet); hbc->add_child(memnew(VSeparator)); @@ -960,25 +982,8 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_dialog->set_title(TTR("Select Frames")); split_sheet_dialog->connect("confirmed", this, "_sheet_add_frames"); - ScrollContainer *scroll = memnew(ScrollContainer); - split_sheet_preview = memnew(TextureRect); - split_sheet_preview->set_expand(false); - split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS); - split_sheet_preview->connect("draw", this, "_sheet_preview_draw"); - split_sheet_preview->connect("gui_input", this, "_sheet_preview_input"); - - scroll->set_enable_h_scroll(true); - scroll->set_enable_v_scroll(true); - CenterContainer *cc = memnew(CenterContainer); - cc->add_child(split_sheet_preview); - cc->set_h_size_flags(SIZE_EXPAND_FILL); - cc->set_v_size_flags(SIZE_EXPAND_FILL); - scroll->add_child(cc); - - split_sheet_vb->add_margin_child(TTR("Base Image:"), scroll, true); - HBoxContainer *split_sheet_hb = memnew(HBoxContainer); - split_sheet_hb->add_spacer(); + Label *ss_label = memnew(Label(TTR("Horizontal:"))); split_sheet_hb->add_child(ss_label); split_sheet_h = memnew(SpinBox); @@ -986,7 +991,6 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_h->set_max(128); split_sheet_h->set_step(1); split_sheet_hb->add_child(split_sheet_h); - split_sheet_hb->add_spacer(); split_sheet_h->connect("value_changed", this, "_sheet_spin_changed"); ss_label = memnew(Label(TTR("Vertical:"))); @@ -996,13 +1000,37 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_v->set_max(128); split_sheet_v->set_step(1); split_sheet_hb->add_child(split_sheet_v); - split_sheet_hb->add_spacer(); split_sheet_v->connect("value_changed", this, "_sheet_spin_changed"); - split_sheet_vb->add_margin_child(TTR("Split Settings:"), split_sheet_hb); + split_sheet_hb->add_spacer(); + + Button *select_clear_all = memnew(Button); + select_clear_all->set_text(TTR("Select/Clear All Frames")); + select_clear_all->connect("pressed", this, "_sheet_select_clear_all_frames"); + split_sheet_hb->add_child(select_clear_all); + + split_sheet_vb->add_child(split_sheet_hb); + + split_sheet_preview = memnew(TextureRect); + split_sheet_preview->set_expand(false); + split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS); + split_sheet_preview->connect("draw", this, "_sheet_preview_draw"); + split_sheet_preview->connect("gui_input", this, "_sheet_preview_input"); + + splite_sheet_scroll = memnew(ScrollContainer); + splite_sheet_scroll->set_enable_h_scroll(true); + splite_sheet_scroll->set_enable_v_scroll(true); + splite_sheet_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + CenterContainer *cc = memnew(CenterContainer); + cc->add_child(split_sheet_preview); + cc->set_h_size_flags(SIZE_EXPAND_FILL); + cc->set_v_size_flags(SIZE_EXPAND_FILL); + splite_sheet_scroll->add_child(cc); + + split_sheet_vb->add_child(splite_sheet_scroll); file_split_sheet = memnew(EditorFileDialog); - file_split_sheet->set_title(TTR("Create frames from Sprite Sheet")); + file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet")); file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE); add_child(file_split_sheet); file_split_sheet->connect("file_selected", this, "_prepare_sprite_sheet"); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 383e99f87e..d64431cde7 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -74,6 +74,7 @@ class SpriteFramesEditor : public HSplitContainer { StringName edited_anim; ConfirmationDialog *split_sheet_dialog; + ScrollContainer *splite_sheet_scroll; TextureRect *split_sheet_preview; SpinBox *split_sheet_h; SpinBox *split_sheet_v; @@ -115,6 +116,7 @@ class SpriteFramesEditor : public HSplitContainer { void _sheet_spin_changed(double); void _sheet_preview_input(const Ref<InputEvent> &p_event); void _sheet_add_frames(); + void _sheet_select_clear_all_frames(); protected: void _notification(int p_what); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 2886b3dc51..becaae3567 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -94,6 +94,7 @@ void TextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color"); Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); @@ -124,6 +125,7 @@ void TextEditor::_load_theme_settings() { text_edit->add_color_override("function_color", function_color); text_edit->add_color_override("member_variable_color", member_variable_color); text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("executing_line_color", executing_line_color); text_edit->add_color_override("mark_color", mark_color); text_edit->add_color_override("code_folding_color", code_folding_color); text_edit->add_color_override("search_result_color", search_result_color); @@ -268,6 +270,15 @@ void TextEditor::goto_line(int p_line, bool p_with_error) { code_editor->goto_line(p_line); } +void TextEditor::set_executing_line(int p_line) { + + code_editor->set_executing_line(p_line); +} + +void TextEditor::clear_executing_line() { + code_editor->clear_executing_line(); +} + void TextEditor::ensure_focus() { code_editor->get_text_edit()->grab_focus(); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 3c136277df..767001e2f6 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -123,6 +123,8 @@ public: virtual Vector<String> get_functions(); virtual void get_breakpoints(List<int> *p_breakpoints); virtual void goto_line(int p_line, bool p_with_error = false); + virtual void set_executing_line(int p_line); + virtual void clear_executing_line(); virtual void trim_trailing_whitespace(); virtual void convert_indent_to_spaces(); virtual void convert_indent_to_tabs(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 879d072b10..62845bfb9b 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -88,12 +88,18 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i } undo_redo->commit_action(); } else if (p_id == BUTTON_LOCK) { + undo_redo->create_action(TTR("Unlock Node")); if (n->is_class("CanvasItem") || n->is_class("Spatial")) { - n->set_meta("_edit_lock_", Variant()); - _update_tree(); - emit_signal("node_changed"); + + undo_redo->add_do_method(n, "remove_meta", "_edit_lock_"); + undo_redo->add_undo_method(n, "set_meta", "_edit_lock_", true); + undo_redo->add_do_method(this, "_update_tree", Variant()); + undo_redo->add_undo_method(this, "_update_tree", Variant()); + undo_redo->add_do_method(this, "emit_signal", "node_changed"); + undo_redo->add_undo_method(this, "emit_signal", "node_changed"); } + undo_redo->commit_action(); } else if (p_id == BUTTON_PIN) { if (n->is_class("AnimationPlayer")) { @@ -102,11 +108,18 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i } } else if (p_id == BUTTON_GROUP) { + undo_redo->create_action(TTR("Button Group")); + if (n->is_class("CanvasItem") || n->is_class("Spatial")) { - n->set_meta("_edit_group_", Variant()); - _update_tree(); - emit_signal("node_changed"); + + undo_redo->add_do_method(n, "remove_meta", "_edit_group_"); + undo_redo->add_undo_method(n, "set_meta", "_edit_group_", true); + undo_redo->add_do_method(this, "_update_tree", Variant()); + undo_redo->add_undo_method(this, "_update_tree", Variant()); + undo_redo->add_do_method(this, "emit_signal", "node_changed"); + undo_redo->add_undo_method(this, "emit_signal", "node_changed"); } + undo_redo->commit_action(); } else if (p_id == BUTTON_WARNING) { String config_err = n->get_configuration_warning(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 717d6bc8f6..1da8bf874c 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -209,8 +209,8 @@ void ScriptEditorDebugger::debug_next() { Array msg; msg.push_back("next"); ppeer->put_var(msg); + _clear_execution(); stack_dump->clear(); - inspector->edit(NULL); } void ScriptEditorDebugger::debug_step() { @@ -221,8 +221,8 @@ void ScriptEditorDebugger::debug_step() { Array msg; msg.push_back("step"); ppeer->put_var(msg); + _clear_execution(); stack_dump->clear(); - inspector->edit(NULL); } void ScriptEditorDebugger::debug_break() { @@ -245,6 +245,7 @@ void ScriptEditorDebugger::debug_continue() { OS::get_singleton()->enable_for_stealing_focus(EditorNode::get_singleton()->get_child_process_id()); Array msg; + _clear_execution(); msg.push_back("continue"); ppeer->put_var(msg); } @@ -424,6 +425,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da } else if (p_msg == "debug_exit") { breaked = false; + _clear_execution(); copy->set_disabled(true); step->set_disabled(true); next->set_disabled(true); @@ -436,7 +438,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da emit_signal("breaked", false, false, Variant()); profiler->set_enabled(true); profiler->disable_seeking(); - inspector->edit(NULL); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); } else if (p_msg == "message:click_ctrl") { @@ -1273,6 +1274,18 @@ void ScriptEditorDebugger::_notification(int p_what) { } } +void ScriptEditorDebugger::_clear_execution() { + TreeItem *ti = stack_dump->get_selected(); + if (!ti) + return; + + Dictionary d = ti->get_metadata(0); + + stack_script = ResourceLoader::load(d["file"]); + emit_signal("clear_execution", stack_script); + stack_script.unref(); +} + void ScriptEditorDebugger::start() { stop(); @@ -1313,6 +1326,7 @@ void ScriptEditorDebugger::stop() { set_process(false); breaked = false; + _clear_execution(); server->stop(); _clear_remote_objects(); @@ -1337,7 +1351,7 @@ void ScriptEditorDebugger::stop() { profiler->set_enabled(true); inspect_scene_tree->clear(); - + inspector->edit(NULL); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); EditorNode::get_singleton()->get_pause_button()->set_disabled(true); EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree(); @@ -1393,6 +1407,7 @@ void ScriptEditorDebugger::_stack_dump_frame_selected() { stack_script = ResourceLoader::load(d["file"]); emit_signal("goto_script_line", stack_script, int(d["line"]) - 1); + emit_signal("set_execution", stack_script, int(d["line"]) - 1); stack_script.unref(); if (connection.is_valid() && connection->is_connected_to_host()) { @@ -1966,6 +1981,8 @@ void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_scene_tree_property_value_edited"), &ScriptEditorDebugger::_scene_tree_property_value_edited); ADD_SIGNAL(MethodInfo("goto_script_line")); + ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line"))); + ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script"))); ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug"))); ADD_SIGNAL(MethodInfo("show_debugger", PropertyInfo(Variant::BOOL, "reallydid"))); } diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index 5f21602579..f7afe6bf72 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -205,6 +205,8 @@ class ScriptEditorDebugger : public Control { void _export_csv(); + void _clear_execution(); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/main/input_default.cpp b/main/input_default.cpp index 6c3252ad1a..a939d77a1e 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -677,6 +677,19 @@ void InputDefault::set_use_accumulated_input(bool p_enable) { use_accumulated_input = p_enable; } +void InputDefault::release_pressed_events() { + + flush_accumulated_events(); // this is needed to release actions strengths + + keys_pressed.clear(); + joy_buttons_pressed.clear(); + _joy_axis.clear(); + + for (Map<StringName, InputDefault::Action>::Element *E = action_state.front(); E; E = E->next()) { + action_release(E->key()); + } +} + InputDefault::InputDefault() { use_accumulated_input = true; diff --git a/main/input_default.h b/main/input_default.h index f9b4cbbd57..80ee17656c 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -272,6 +272,7 @@ public: virtual void flush_accumulated_events(); virtual void set_use_accumulated_input(bool p_enable); + virtual void release_pressed_events(); InputDefault(); }; diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 0eb539b182..7e1cc937cd 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -242,7 +242,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_ //check if edge and poly share a vertex, of so, assign it to segment_idx for (int i = 0; i < points.size(); i++) { for (int j = 0; j < 2; j++) { - if (segment[j].distance_to(points[i].point) < CMP_EPSILON) { + if (Math::is_zero_approx(segment[j].distance_to(points[i].point))) { segment_idx[j] = i; inserted_points.push_back(i); break; @@ -310,7 +310,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_ Vector2 edgeseg[2] = { points[edges[i].points[0]].point, points[edges[i].points[1]].point }; Vector2 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg); - if (closest.distance_to(segment[j]) < CMP_EPSILON) { + if (Math::is_zero_approx(closest.distance_to(segment[j]))) { //point rest of this edge res = closest; found = true; @@ -439,7 +439,7 @@ void CSGBrushOperation::BuildPoly::clip(const CSGBrush *p_brush, int p_face, Mes //transform A points to 2D - if (segment[0].distance_to(segment[1]) < CMP_EPSILON) + if (Math::is_zero_approx(segment[0].distance_to(segment[1]))) return; //too small _clip_segment(p_brush, p_face, segment, mesh_merge, p_for_B); @@ -461,10 +461,10 @@ void CSGBrushOperation::_collision_callback(const CSGBrush *A, int p_face_a, Map { //check if either is a degenerate - if (va[0].distance_to(va[1]) < CMP_EPSILON || va[0].distance_to(va[2]) < CMP_EPSILON || va[1].distance_to(va[2]) < CMP_EPSILON) + if (Math::is_zero_approx(va[0].distance_to(va[1])) || Math::is_zero_approx(va[0].distance_to(va[2])) || Math::is_zero_approx(va[1].distance_to(va[2]))) return; - if (vb[0].distance_to(vb[1]) < CMP_EPSILON || vb[0].distance_to(vb[2]) < CMP_EPSILON || vb[1].distance_to(vb[2]) < CMP_EPSILON) + if (Math::is_zero_approx(vb[0].distance_to(vb[1])) || Math::is_zero_approx(vb[0].distance_to(vb[2])) || Math::is_zero_approx(vb[1].distance_to(vb[2]))) return; } diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 4fd136d5cc..7552bc6bff 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -68,6 +68,8 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "exp", "is_nan", "is_inf", + "is_equal_approx", + "is_zero_approx", "ease", "decimals", "stepify", @@ -316,6 +318,17 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(0); r_ret = Math::is_inf((double)*p_args[0]); } break; + case MATH_ISEQUALAPPROX: { + VALIDATE_ARG_COUNT(2); + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]); + } break; + case MATH_ISZEROAPPROX: { + VALIDATE_ARG_COUNT(1); + VALIDATE_ARG_NUM(0); + r_ret = Math::is_zero_approx((real_t)*p_args[0]); + } break; case MATH_EASE: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); @@ -1596,6 +1609,16 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { mi.return_val.type = Variant::BOOL; return mi; } break; + case MATH_ISEQUALAPPROX: { + MethodInfo mi("is_equal_approx", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b")); + mi.return_val.type = Variant::BOOL; + return mi; + } break; + case MATH_ISZEROAPPROX: { + MethodInfo mi("is_zero_approx", PropertyInfo(Variant::REAL, "s")); + mi.return_val.type = Variant::BOOL; + return mi; + } break; case MATH_EASE: { MethodInfo mi("ease", PropertyInfo(Variant::REAL, "s"), PropertyInfo(Variant::REAL, "curve")); mi.return_val.type = Variant::REAL; diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h index 14bf3d7560..0dbd172acf 100644 --- a/modules/gdscript/gdscript_functions.h +++ b/modules/gdscript/gdscript_functions.h @@ -59,6 +59,8 @@ public: MATH_EXP, MATH_ISNAN, MATH_ISINF, + MATH_ISEQUALAPPROX, + MATH_ISZEROAPPROX, MATH_EASE, MATH_DECIMALS, MATH_STEPIFY, diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 31d6421a4c..27e579935f 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -131,14 +131,6 @@ void CSharpLanguage::finish() { finalizing = true; -#ifdef TOOLS_ENABLED - // Must be here, to avoid StringName leaks - if (BindingsGenerator::singleton) { - memdelete(BindingsGenerator::singleton); - BindingsGenerator::singleton = NULL; - } -#endif - // Make sure all script binding gchandles are released before finalizing GDMono for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { CSharpScriptBinding &script_binding = E->value(); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 259c0ffece..a408716641 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -97,14 +97,10 @@ #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array" -#define BINDINGS_GENERATOR_VERSION UINT32_C(8) +#define BINDINGS_GENERATOR_VERSION UINT32_C(9) const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n"); -bool BindingsGenerator::verbose_output = false; - -BindingsGenerator *BindingsGenerator::singleton = NULL; - static String fix_doc_description(const String &p_bbcode) { // This seems to be the correct way to do this. It's the same EditorHelp does. @@ -816,9 +812,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { CRASH_COND(enum_class_name != "Variant"); // Hard-coded... - if (verbose_output) { - WARN_PRINTS("Declaring global enum `" + enum_proxy_name + "` inside static class `" + enum_class_name + "`"); - } + _log("Declaring global enum `%s` inside static class `%s`\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data()); p_output.append("\n" INDENT1 "public static partial class "); p_output.append(enum_class_name); @@ -867,9 +861,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { p_output.append("\n#pragma warning restore CS1591\n"); } -Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) { - - verbose_output = p_verbose_output; +Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution) { String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME); @@ -1001,15 +993,12 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info); - if (verbose_output) - OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n"); + _log("The solution and C# project for the Core API was generated successfully\n"); return OK; } -Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) { - - verbose_output = p_verbose_output; +Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution) { String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME); @@ -1100,13 +1089,12 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info); - if (verbose_output) - OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n"); + _log("The solution and C# project for the Editor API was generated successfully\n"); return OK; } -Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verbose_output) { +Error BindingsGenerator::generate_cs_api(const String &p_output_dir) { DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); @@ -1123,13 +1111,13 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verb Error proj_err; - proj_err = generate_cs_core_project(p_output_dir, solution, p_verbose_output); + proj_err = generate_cs_core_project(p_output_dir, solution); if (proj_err != OK) { ERR_PRINT("Generation of the Core API C# project failed"); return proj_err; } - proj_err = generate_cs_editor_project(p_output_dir, solution, p_verbose_output); + proj_err = generate_cs_editor_project(p_output_dir, solution); if (proj_err != OK) { ERR_PRINT("Generation of the Editor API C# project failed"); return proj_err; @@ -1168,8 +1156,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls; - if (verbose_output) - OS::get_singleton()->print("Generating %s.cs...\n", itype.proxy_name.utf8().get_data()); + _log("Generating %s.cs...\n", itype.proxy_name.utf8().get_data()); String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types @@ -1477,7 +1464,13 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append("\n" INDENT2 OPEN_BLOCK); if (getter) { - p_output.append(INDENT3 "get\n" OPEN_BLOCK_L3); + p_output.append(INDENT3 "get\n" + + // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) + "#pragma warning disable CS0618 // Disable warning about obsolete method\n" + + OPEN_BLOCK_L3); + p_output.append("return "); p_output.append(getter->proxy_name + "("); if (p_iprop.index != -1) { @@ -1491,11 +1484,22 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(itos(p_iprop.index)); } } - p_output.append(");\n" CLOSE_BLOCK_L3); + p_output.append(");\n" + + CLOSE_BLOCK_L3 + + // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) + "#pragma warning restore CS0618\n"); } if (setter) { - p_output.append(INDENT3 "set\n" OPEN_BLOCK_L3); + p_output.append(INDENT3 "set\n" + + // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) + "#pragma warning disable CS0618 // Disable warning about obsolete method\n" + + OPEN_BLOCK_L3); + p_output.append(setter->proxy_name + "("); if (p_iprop.index != -1) { const ArgumentInterface &idx_arg = setter->arguments.front()->get(); @@ -1508,7 +1512,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(itos(p_iprop.index) + ", "); } } - p_output.append("value);\n" CLOSE_BLOCK_L3); + p_output.append("value);\n" + + CLOSE_BLOCK_L3 + + // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) + "#pragma warning restore CS0618\n"); } p_output.append(CLOSE_BLOCK_L2); @@ -1636,6 +1645,15 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output.append("\")]"); } + if (p_imethod.is_deprecated) { + if (p_imethod.deprecation_message.empty()) + WARN_PRINTS("An empty deprecation message is discouraged. Method: " + p_imethod.proxy_name); + + p_output.append(MEMBER_BEGIN "[Obsolete(\""); + p_output.append(p_imethod.deprecation_message); + p_output.append("\")]"); + } + p_output.append(MEMBER_BEGIN); p_output.append(p_imethod.is_internal ? "internal " : "public "); @@ -1710,8 +1728,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf Error BindingsGenerator::generate_glue(const String &p_output_dir) { - verbose_output = true; - bool dir_exists = DirAccess::exists(p_output_dir); ERR_EXPLAIN("The output directory does not exist."); ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH); @@ -2109,6 +2125,58 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol return &placeholder_types.insert(placeholder.cname, placeholder)->get(); } +StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) { + + switch (p_meta) { + case GodotTypeInfo::METADATA_INT_IS_INT8: + return "sbyte"; + break; + case GodotTypeInfo::METADATA_INT_IS_INT16: + return "short"; + break; + case GodotTypeInfo::METADATA_INT_IS_INT32: + return "int"; + break; + case GodotTypeInfo::METADATA_INT_IS_INT64: + return "long"; + break; + case GodotTypeInfo::METADATA_INT_IS_UINT8: + return "byte"; + break; + case GodotTypeInfo::METADATA_INT_IS_UINT16: + return "ushort"; + break; + case GodotTypeInfo::METADATA_INT_IS_UINT32: + return "uint"; + break; + case GodotTypeInfo::METADATA_INT_IS_UINT64: + return "ulong"; + break; + default: + // Assume INT32 + return "int"; + } +} + +StringName BindingsGenerator::_get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta) { + + switch (p_meta) { + case GodotTypeInfo::METADATA_REAL_IS_FLOAT: + return "float"; + break; + case GodotTypeInfo::METADATA_REAL_IS_DOUBLE: + return "double"; + break; + default: + // Assume real_t (float or double depending of REAL_T_IS_DOUBLE) +#ifdef REAL_T_IS_DOUBLE + return "double"; +#else + return "float"; +#endif + } +} + void BindingsGenerator::_populate_object_type_interfaces() { obj_types.clear(); @@ -2128,15 +2196,13 @@ void BindingsGenerator::_populate_object_type_interfaces() { } if (!ClassDB::is_class_exposed(type_cname)) { - if (verbose_output) - WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not exposed"); + _log("Ignoring type `%s` because it's not exposed\n", String(type_cname).utf8().get_data()); class_list.pop_front(); continue; } if (!ClassDB::is_class_enabled(type_cname)) { - if (verbose_output) - WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not enabled"); + _log("Ignoring type `%s` because it's not enabled\n", String(type_cname).utf8().get_data()); class_list.pop_front(); continue; } @@ -2164,10 +2230,12 @@ void BindingsGenerator::_populate_object_type_interfaces() { itype.im_type_in = "IntPtr"; itype.im_type_out = itype.proxy_name; + // Populate properties + List<PropertyInfo> property_list; ClassDB::get_property_list(type_cname, &property_list, true); - // Populate properties + Map<StringName, StringName> accessor_methods; for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { const PropertyInfo &property = E->get(); @@ -2180,18 +2248,21 @@ void BindingsGenerator::_populate_object_type_interfaces() { iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname); iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname); + if (iprop.setter != StringName()) + accessor_methods[iprop.setter] = iprop.cname; + if (iprop.getter != StringName()) + accessor_methods[iprop.getter] = iprop.cname; + bool valid = false; iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid); ERR_FAIL_COND(!valid); iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname)); - // Prevent property and enclosing type from sharing the same name + // Prevent the property and its enclosing type from sharing the same name if (iprop.proxy_name == itype.proxy_name) { - if (verbose_output) { - WARN_PRINTS("Name of property `" + iprop.proxy_name + "` is ambiguous with the name of its class `" + - itype.proxy_name + "`. Renaming property to `" + iprop.proxy_name + "_`"); - } + _log("Name of property `%s` is ambiguous with the name of its enclosing class `%s`. Renaming property to `%s_`\n", + iprop.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), iprop.proxy_name.utf8().get_data()); iprop.proxy_name += "_"; } @@ -2258,14 +2329,13 @@ void BindingsGenerator::_populate_object_type_interfaces() { // which could actually will return something different. // Let's put this to notify us if that ever happens. if (itype.cname != name_cache.type_Object || imethod.name != "free") { - if (verbose_output) { - WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n" - "We only expected Object.free, but found " + - itype.name + "." + imethod.name); - } + ERR_PRINTS("Notification: New unexpected virtual non-overridable method found.\n" + "We only expected Object.free, but found " + + itype.name + "." + imethod.name); } } else { - ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name); + ERR_EXPLAIN("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name); + ERR_FAIL(); } } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { imethod.return_type.cname = return_info.class_name; @@ -2279,7 +2349,13 @@ void BindingsGenerator::_populate_object_type_interfaces() { } else if (return_info.type == Variant::NIL) { imethod.return_type.cname = name_cache.type_void; } else { - imethod.return_type.cname = Variant::get_type_name(return_info.type); + if (return_info.type == Variant::INT) { + imethod.return_type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE); + } else if (return_info.type == Variant::REAL) { + imethod.return_type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE); + } else { + imethod.return_type.cname = Variant::get_type_name(return_info.type); + } } for (int i = 0; i < argc; i++) { @@ -2298,7 +2374,13 @@ void BindingsGenerator::_populate_object_type_interfaces() { } else if (arginfo.type == Variant::NIL) { iarg.type.cname = name_cache.type_Variant; } else { - iarg.type.cname = Variant::get_type_name(arginfo.type); + if (arginfo.type == Variant::INT) { + iarg.type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE); + } else if (arginfo.type == Variant::REAL) { + iarg.type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE); + } else { + iarg.type.cname = Variant::get_type_name(arginfo.type); + } } iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); @@ -2319,16 +2401,24 @@ void BindingsGenerator::_populate_object_type_interfaces() { imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(imethod.name)); - // Prevent naming the property and its enclosing type from sharing the same name + // Prevent the method and its enclosing type from sharing the same name if (imethod.proxy_name == itype.proxy_name) { - if (verbose_output) { - WARN_PRINTS("Name of method `" + imethod.proxy_name + "` is ambiguous with the name of its class `" + - itype.proxy_name + "`. Renaming method to `" + imethod.proxy_name + "_`"); - } + _log("Name of method `%s` is ambiguous with the name of its enclosing class `%s`. Renaming method to `%s_`\n", + imethod.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), imethod.proxy_name.utf8().get_data()); imethod.proxy_name += "_"; } + Map<StringName, StringName>::Element *accessor = accessor_methods.find(imethod.cname); + if (accessor) { + const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value()); + + // We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also + // we don't know if an accessor method in a different class could have other purposes, so better leave those untouched. + imethod.is_deprecated = true; + imethod.deprecation_message = imethod.proxy_name + " is deprecated. Use the " + accessor_property->proxy_name + " property instead."; + } + if (itype.class_doc) { for (int i = 0; i < itype.class_doc->methods.size(); i++) { if (itype.class_doc->methods[i].name == imethod.name) { @@ -2556,7 +2646,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { // bool itype = TypeInterface::create_value_type(String("bool")); - { // MonoBoolean <---> bool itype.c_in = "\t%0 %1_in = (%0)%1;\n"; @@ -2570,45 +2659,73 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = itype.name; builtin_types.insert(itype.cname, itype); - // int - // C interface is the same as that of enums. Remember to apply any - // changes done here to TypeInterface::postsetup_enum_type as well - itype = TypeInterface::create_value_type(String("int")); - itype.c_arg_in = "&%s_in"; + // Integer types { - // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'. - itype.c_in = "\t%0 %1_in = (%0)%1;\n"; - itype.c_out = "\treturn (%0)%1;\n"; - itype.c_type = "int64_t"; + // C interface for 'uint32_t' is the same as that of enums. Remember to apply + // any of the changes done here to 'TypeInterface::postsetup_enum_type' as well. +#define INSERT_INT_TYPE(m_name, m_c_type_in_out, m_c_type) \ + { \ + itype = TypeInterface::create_value_type(String(m_name)); \ + { \ + itype.c_in = "\t%0 %1_in = (%0)%1;\n"; \ + itype.c_out = "\treturn (%0)%1;\n"; \ + itype.c_type = #m_c_type; \ + itype.c_arg_in = "&%s_in"; \ + } \ + itype.c_type_in = #m_c_type_in_out; \ + itype.c_type_out = itype.c_type_in; \ + itype.im_type_in = itype.name; \ + itype.im_type_out = itype.name; \ + builtin_types.insert(itype.cname, itype); \ } - itype.c_type_in = "int32_t"; - itype.c_type_out = itype.c_type_in; - itype.im_type_in = itype.name; - itype.im_type_out = itype.name; - builtin_types.insert(itype.cname, itype); - // real_t - itype = TypeInterface(); - itype.name = "float"; // The name is always "float" in Variant, even with REAL_T_IS_DOUBLE. - itype.cname = itype.name; -#ifdef REAL_T_IS_DOUBLE - itype.proxy_name = "double"; -#else - itype.proxy_name = "float"; -#endif + // The expected type for all integers in ptrcall is 'int64_t', so that's what we use for 'c_type' + + INSERT_INT_TYPE("sbyte", int8_t, int64_t); + INSERT_INT_TYPE("short", int16_t, int64_t); + INSERT_INT_TYPE("int", int32_t, int64_t); + INSERT_INT_TYPE("long", int64_t, int64_t); + INSERT_INT_TYPE("byte", uint8_t, int64_t); + INSERT_INT_TYPE("ushort", uint16_t, int64_t); + INSERT_INT_TYPE("uint", uint32_t, int64_t); + INSERT_INT_TYPE("ulong", uint64_t, int64_t); + } + + // Floating point types { - // The expected type for parameters and return value in ptrcall is 'double'. - itype.c_in = "\t%0 %1_in = (%0)%1;\n"; - itype.c_out = "\treturn (%0)%1;\n"; + // float + itype = TypeInterface(); + itype.name = "float"; + itype.cname = itype.name; + itype.proxy_name = "float"; + { + // The expected type for 'float' in ptrcall is 'double' + itype.c_in = "\t%0 %1_in = (%0)%1;\n"; + itype.c_out = "\treturn (%0)%1;\n"; + itype.c_type = "double"; + itype.c_type_in = "float"; + itype.c_type_out = "float"; + itype.c_arg_in = "&%s_in"; + } + itype.cs_type = itype.proxy_name; + itype.im_type_in = itype.proxy_name; + itype.im_type_out = itype.proxy_name; + builtin_types.insert(itype.cname, itype); + + // double + itype = TypeInterface(); + itype.name = "double"; + itype.cname = itype.name; + itype.proxy_name = "double"; itype.c_type = "double"; - itype.c_type_in = "real_t"; - itype.c_type_out = "real_t"; - itype.c_arg_in = "&%s_in"; + itype.c_type_in = "double"; + itype.c_type_out = "double"; + itype.c_arg_in = "&%s"; + itype.cs_type = itype.proxy_name; + itype.im_type_in = itype.proxy_name; + itype.im_type_out = itype.proxy_name; + builtin_types.insert(itype.cname, itype); } - itype.cs_type = itype.proxy_name; - itype.im_type_in = itype.proxy_name; - itype.im_type_out = itype.proxy_name; - builtin_types.insert(itype.cname, itype); // String itype = TypeInterface(); @@ -2858,7 +2975,18 @@ void BindingsGenerator::_populate_global_constants() { } } -void BindingsGenerator::initialize() { +void BindingsGenerator::_log(const char *p_format, ...) { + + if (log_print_enabled) { + va_list list; + + va_start(list, p_format); + OS::get_singleton()->print("%s", str_format(p_format, list).utf8().get_data()); + va_end(list); + } +} + +void BindingsGenerator::_initialize() { EditorHelp::generate_doc(); @@ -2881,12 +3009,13 @@ void BindingsGenerator::initialize() { void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) { const int NUM_OPTIONS = 2; - int options_left = NUM_OPTIONS; - String mono_glue_option = "--generate-mono-glue"; String cs_api_option = "--generate-cs-api"; - verbose_output = true; + String mono_glue_path; + String cs_api_path; + + int options_left = NUM_OPTIONS; const List<String>::Element *elem = p_cmdline_args.front(); @@ -2895,8 +3024,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) const List<String>::Element *path_elem = elem->next(); if (path_elem) { - if (get_singleton()->generate_glue(path_elem->get()) != OK) - ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue"); + mono_glue_path = path_elem->get(); elem = elem->next(); } else { ERR_PRINTS(mono_glue_option + ": No output directory specified"); @@ -2907,8 +3035,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) const List<String>::Element *path_elem = elem->next(); if (path_elem) { - if (get_singleton()->generate_cs_api(path_elem->get()) != OK) - ERR_PRINTS(cs_api_option + ": Failed to generate the C# API"); + cs_api_path = path_elem->get(); elem = elem->next(); } else { ERR_PRINTS(cs_api_option + ": No output directory specified"); @@ -2920,10 +3047,23 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) elem = elem->next(); } - verbose_output = false; + if (mono_glue_path.length() || cs_api_path.length()) { + BindingsGenerator bindings_generator; + bindings_generator.set_log_print_enabled(true); + + if (mono_glue_path.length()) { + if (bindings_generator.generate_glue(mono_glue_path) != OK) + ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue"); + } + + if (cs_api_path.length()) { + if (bindings_generator.generate_cs_api(cs_api_path) != OK) + ERR_PRINTS(cs_api_option + ": Failed to generate the C# API"); + } - if (options_left != NUM_OPTIONS) + // Exit once done ::exit(0); + } } #endif diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index a073c09910..bdba28c267 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -159,17 +159,20 @@ class BindingsGenerator { const DocData::MethodDoc *method_doc; + bool is_deprecated; + String deprecation_message; + void add_argument(const ArgumentInterface &argument) { arguments.push_back(argument); } MethodInterface() { - return_type.cname = BindingsGenerator::get_singleton()->name_cache.type_void; is_vararg = false; is_virtual = false; requires_object_call = false; is_internal = false; method_doc = NULL; + is_deprecated = false; } }; @@ -400,8 +403,8 @@ class BindingsGenerator { } static void postsetup_enum_type(TypeInterface &r_enum_itype) { - // C interface is the same as that of 'int'. Remember to apply any - // changes done here to the 'int' type interface as well + // C interface for enums is the same as that of 'uint32_t'. Remember to apply + // any of the changes done here to the 'uint32_t' type interface as well. r_enum_itype.c_arg_in = "&%s_in"; { @@ -469,7 +472,7 @@ class BindingsGenerator { } }; - static bool verbose_output; + bool log_print_enabled; OrderedHashMap<StringName, TypeInterface> obj_types; @@ -490,7 +493,6 @@ class BindingsGenerator { struct NameCache { StringName type_void; - StringName type_int; StringName type_Array; StringName type_Dictionary; StringName type_Variant; @@ -501,9 +503,19 @@ class BindingsGenerator { StringName type_at_GlobalScope; StringName enum_Error; + StringName type_sbyte; + StringName type_short; + StringName type_int; + StringName type_long; + StringName type_byte; + StringName type_ushort; + StringName type_uint; + StringName type_ulong; + StringName type_float; + StringName type_double; + NameCache() { type_void = StaticCString::create("void"); - type_int = StaticCString::create("int"); type_Array = StaticCString::create("Array"); type_Dictionary = StaticCString::create("Dictionary"); type_Variant = StaticCString::create("Variant"); @@ -513,8 +525,20 @@ class BindingsGenerator { type_String = StaticCString::create("String"); type_at_GlobalScope = StaticCString::create("@GlobalScope"); enum_Error = StaticCString::create("Error"); + + type_sbyte = StaticCString::create("sbyte"); + type_short = StaticCString::create("short"); + type_int = StaticCString::create("int"); + type_long = StaticCString::create("long"); + type_byte = StaticCString::create("byte"); + type_ushort = StaticCString::create("ushort"); + type_uint = StaticCString::create("uint"); + type_ulong = StaticCString::create("ulong"); + type_float = StaticCString::create("float"); + type_double = StaticCString::create("double"); } + private: NameCache(const NameCache &); NameCache &operator=(const NameCache &); }; @@ -560,6 +584,9 @@ class BindingsGenerator { const TypeInterface *_get_type_or_null(const TypeReference &p_typeref); const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref); + StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta); + StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta); + void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg); void _populate_object_type_interfaces(); @@ -578,33 +605,26 @@ class BindingsGenerator { Error _save_file(const String &p_path, const StringBuilder &p_content); - BindingsGenerator() {} - - BindingsGenerator(const BindingsGenerator &); - BindingsGenerator &operator=(const BindingsGenerator &); + void _log(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; - friend class CSharpLanguage; - static BindingsGenerator *singleton; + void _initialize(); public: - Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true); - Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true); - Error generate_cs_api(const String &p_output_dir, bool p_verbose_output = true); + Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution); + Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution); + Error generate_cs_api(const String &p_output_dir); Error generate_glue(const String &p_output_dir); + void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; } + static uint32_t get_version(); - void initialize(); + static void handle_cmdline_args(const List<String> &p_cmdline_args); - _FORCE_INLINE_ static BindingsGenerator *get_singleton() { - if (!singleton) { - singleton = memnew(BindingsGenerator); - singleton->initialize(); - } - return singleton; + BindingsGenerator() : + log_print_enabled(true) { + _initialize(); } - - static void handle_cmdline_args(const List<String> &p_cmdline_args); }; #endif diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 00c780d1b7..de3fd91223 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -323,10 +323,13 @@ bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) { String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln"); if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) { - BindingsGenerator *gen = BindingsGenerator::get_singleton(); - bool gen_verbose = OS::get_singleton()->is_stdout_verbose(); + BindingsGenerator bindings_generator; - Error err = gen->generate_cs_api(api_sln_dir, gen_verbose); + if (!OS::get_singleton()->is_stdout_verbose()) { + bindings_generator.set_log_print_enabled(false); + } + + Error err = bindings_generator.generate_cs_api(api_sln_dir); if (err != OK) { show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err)); return false; diff --git a/modules/mono/glue/Managed/Files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs index 88fa3323c2..84ff19fc54 100644 --- a/modules/mono/glue/Managed/Files/Color.cs +++ b/modules/mono/glue/Managed/Files/Color.cs @@ -168,7 +168,7 @@ namespace Godot int max = Mathf.Max(color.r8, Mathf.Max(color.g8, color.b8)); int min = Mathf.Min(color.r8, Mathf.Min(color.g8, color.b8)); - float delta = max - min; + int delta = max - min; if (delta == 0) { @@ -591,11 +591,11 @@ namespace Godot public static bool operator <(Color left, Color right) { - if (left.r == right.r) + if (Mathf.IsEqualApprox(left.r, right.r)) { - if (left.g == right.g) + if (Mathf.IsEqualApprox(left.g, right.g)) { - if (left.b == right.b) + if (Mathf.IsEqualApprox(left.b, right.b)) return left.a < right.a; return left.b < right.b; } @@ -608,11 +608,11 @@ namespace Godot public static bool operator >(Color left, Color right) { - if (left.r == right.r) + if (Mathf.IsEqualApprox(left.r, right.r)) { - if (left.g == right.g) + if (Mathf.IsEqualApprox(left.g, right.g)) { - if (left.b == right.b) + if (Mathf.IsEqualApprox(left.b, right.b)) return left.a > right.a; return left.b > right.b; } @@ -635,7 +635,7 @@ namespace Godot public bool Equals(Color other) { - return r == other.r && g == other.g && b == other.b && a == other.a; + return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a); } public override int GetHashCode() diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs index 5b591646ea..2068099ac6 100644 --- a/modules/mono/glue/Managed/Files/GD.cs +++ b/modules/mono/glue/Managed/Files/GD.cs @@ -111,7 +111,7 @@ namespace Godot godot_icall_GD_printt(Array.ConvertAll(what, x => x.ToString())); } - public static double Randf() + public static float Randf() { return godot_icall_GD_randf(); } @@ -224,7 +224,7 @@ namespace Godot internal extern static void godot_icall_GD_printt(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static double godot_icall_GD_randf(); + internal extern static float godot_icall_GD_randf(); [MethodImpl(MethodImplOptions.InternalCall)] internal extern static uint godot_icall_GD_randi(); @@ -232,6 +232,7 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_GD_randomize(); + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static double godot_icall_GD_rand_range(double from, double to); diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index a064278237..947fbb6665 100644 --- a/modules/mono/glue/Managed/Files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs @@ -143,6 +143,15 @@ namespace Godot return (weight - from) / (to - from); } + public static bool IsEqualApprox(real_t a, real_t b) + { + real_t tolerance = Epsilon * Abs(a); + if (tolerance < Epsilon) { + tolerance = Epsilon; + } + return Abs(a - b) < tolerance; + } + public static bool IsInf(real_t s) { return real_t.IsInfinity(s); @@ -153,6 +162,11 @@ namespace Godot return real_t.IsNaN(s); } + public static bool IsZeroApprox(real_t s) + { + return Abs(s) < Epsilon; + } + public static real_t Lerp(real_t from, real_t to, real_t weight) { return from + (to - from) * weight; diff --git a/modules/mono/glue/Managed/Files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs index 414762f7b1..d6eb65b097 100644 --- a/modules/mono/glue/Managed/Files/MathfEx.cs +++ b/modules/mono/glue/Managed/Files/MathfEx.cs @@ -36,9 +36,9 @@ namespace Godot return (int)Math.Round(s); } - public static bool IsEqualApprox(real_t a, real_t b, real_t ratio = Mathf.Epsilon) + public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance) { - return Abs(a - b) < ratio; + return Abs(a - b) < tolerance; } } }
\ No newline at end of file diff --git a/modules/mono/glue/Managed/Files/Plane.cs b/modules/mono/glue/Managed/Files/Plane.cs index f11cd490a9..e16d4315be 100644 --- a/modules/mono/glue/Managed/Files/Plane.cs +++ b/modules/mono/glue/Managed/Files/Plane.cs @@ -200,7 +200,7 @@ namespace Godot public bool Equals(Plane other) { - return _normal == other._normal && D == other.D; + return _normal == other._normal && Mathf.IsEqualApprox(D, other.D); } public override int GetHashCode() diff --git a/modules/mono/glue/Managed/Files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs index d0c15146a5..0d4349084a 100644 --- a/modules/mono/glue/Managed/Files/Quat.cs +++ b/modules/mono/glue/Managed/Files/Quat.cs @@ -358,7 +358,7 @@ namespace Godot public bool Equals(Quat other) { - return x == other.x && y == other.y && z == other.z && w == other.w; + return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); } public override int GetHashCode() diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs index 908162ec45..bb1950e1a8 100644 --- a/modules/mono/glue/Managed/Files/Vector2.cs +++ b/modules/mono/glue/Managed/Files/Vector2.cs @@ -52,11 +52,15 @@ namespace Godot internal void Normalize() { - real_t length = x * x + y * y; + real_t lengthsq = LengthSquared(); - if (length != 0f) + if (lengthsq == 0) { - length = Mathf.Sqrt(length); + x = y = 0f; + } + else + { + real_t length = Mathf.Sqrt(lengthsq); x /= length; y /= length; } @@ -184,9 +188,9 @@ namespace Godot public Vector2 Normalized() { - var result = this; - result.Normalize(); - return result; + var v = this; + v.Normalize(); + return v; } public Vector2 Project(Vector2 onNormal) @@ -343,7 +347,7 @@ namespace Godot public static bool operator <(Vector2 left, Vector2 right) { - if (left.x.Equals(right.x)) + if (Mathf.IsEqualApprox(left.x, right.x)) { return left.y < right.y; } @@ -353,7 +357,7 @@ namespace Godot public static bool operator >(Vector2 left, Vector2 right) { - if (left.x.Equals(right.x)) + if (Mathf.IsEqualApprox(left.x, right.x)) { return left.y > right.y; } @@ -363,7 +367,7 @@ namespace Godot public static bool operator <=(Vector2 left, Vector2 right) { - if (left.x.Equals(right.x)) + if (Mathf.IsEqualApprox(left.x, right.x)) { return left.y <= right.y; } @@ -373,7 +377,7 @@ namespace Godot public static bool operator >=(Vector2 left, Vector2 right) { - if (left.x.Equals(right.x)) + if (Mathf.IsEqualApprox(left.x, right.x)) { return left.y >= right.y; } @@ -393,7 +397,7 @@ namespace Godot public bool Equals(Vector2 other) { - return x == other.x && y == other.y; + return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y); } public override int GetHashCode() diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs index 0c96d346a9..283cb6341a 100644 --- a/modules/mono/glue/Managed/Files/Vector3.cs +++ b/modules/mono/glue/Managed/Files/Vector3.cs @@ -65,14 +65,15 @@ namespace Godot internal void Normalize() { - real_t length = Length(); + real_t lengthsq = LengthSquared(); - if (length == 0f) + if (lengthsq == 0) { x = y = z = 0f; } else { + real_t length = Mathf.Sqrt(lengthsq); x /= length; y /= length; z /= length; @@ -397,9 +398,9 @@ namespace Godot public static bool operator <(Vector3 left, Vector3 right) { - if (left.x == right.x) + if (Mathf.IsEqualApprox(left.x, right.x)) { - if (left.y == right.y) + if (Mathf.IsEqualApprox(left.y, right.y)) return left.z < right.z; return left.y < right.y; } @@ -409,9 +410,9 @@ namespace Godot public static bool operator >(Vector3 left, Vector3 right) { - if (left.x == right.x) + if (Mathf.IsEqualApprox(left.x, right.x)) { - if (left.y == right.y) + if (Mathf.IsEqualApprox(left.y, right.y)) return left.z > right.z; return left.y > right.y; } @@ -421,9 +422,9 @@ namespace Godot public static bool operator <=(Vector3 left, Vector3 right) { - if (left.x == right.x) + if (Mathf.IsEqualApprox(left.x, right.x)) { - if (left.y == right.y) + if (Mathf.IsEqualApprox(left.y, right.y)) return left.z <= right.z; return left.y < right.y; } @@ -433,9 +434,9 @@ namespace Godot public static bool operator >=(Vector3 left, Vector3 right) { - if (left.x == right.x) + if (Mathf.IsEqualApprox(left.x, right.x)) { - if (left.y == right.y) + if (Mathf.IsEqualApprox(left.y, right.y)) return left.z >= right.z; return left.y > right.y; } @@ -455,7 +456,7 @@ namespace Godot public bool Equals(Vector3 other) { - return x == other.x && y == other.y && z == other.z; + return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z); } public override int GetHashCode() diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp index d756131ac9..7c30092855 100644 --- a/modules/mono/glue/gd_glue.cpp +++ b/modules/mono/glue/gd_glue.cpp @@ -115,7 +115,7 @@ void godot_icall_GD_printt(MonoArray *p_what) { print_line(str); } -double godot_icall_GD_randf() { +float godot_icall_GD_randf() { return Math::randf(); } diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h index 910979aae3..d4e20e2887 100644 --- a/modules/mono/glue/gd_glue.h +++ b/modules/mono/glue/gd_glue.h @@ -53,7 +53,7 @@ void godot_icall_GD_prints(MonoArray *p_what); void godot_icall_GD_printt(MonoArray *p_what); -double godot_icall_GD_randf(); +float godot_icall_GD_randf(); uint32_t godot_icall_GD_randi(); diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index 087a7a2e5c..a6e04e561d 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -37,6 +37,7 @@ #include "core/os/os.h" #include "../godotsharp_dirs.h" +#include "../utils/string_utils.h" static int log_level_get_id(const char *p_log_level) { @@ -125,27 +126,6 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { da->list_dir_end(); } -static String format(const char *p_fmt, ...) { - va_list args; - - va_start(args, p_fmt); - int len = vsnprintf(NULL, 0, p_fmt, args); - va_end(args); - - len += 1; // for the trailing '/0' - - char *buffer(memnew_arr(char, len)); - - va_start(args, p_fmt); - vsnprintf(buffer, len, p_fmt, args); - va_end(args); - - String res(buffer); - memdelete_arr(buffer); - - return res; -} - void GDMonoLog::initialize() { CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8(); @@ -172,7 +152,7 @@ void GDMonoLog::initialize() { OS::Time time_now = OS::get_singleton()->get_time(); int pid = OS::get_singleton()->get_process_id(); - String log_file_name = format("%d_%02d_%02d %02d.%02d.%02d (%d).txt", + String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt", date_now.year, date_now.month, date_now.day, time_now.hour, time_now.min, time_now.sec, pid); diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index c390f8b9c2..0ef66577fe 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -32,6 +32,8 @@ #include "core/os/file_access.h" +#include <stdio.h> + namespace { int sfind(const String &p_text, int p_from) { @@ -184,3 +186,50 @@ Error read_all_file_utf8(const String &p_path, String &r_content) { r_content = source; return OK; } + +// TODO: Move to variadic templates once we upgrade to C++11 + +String str_format(const char *p_format, ...) { + va_list list; + + va_start(list, p_format); + String res = str_format(p_format, list); + va_end(list); + + return res; +} +// va_copy was defined in the C99, but not in C++ standards before C++11. +// When you compile C++ without --std=c++<XX> option, compilers still define +// va_copy, otherwise you have to use the internal version (__va_copy). +#if !defined(va_copy) +#if defined(__GNUC__) +#define va_copy(d, s) __va_copy((d), (s)) +#else +#define va_copy(d, s) ((d) = (s)) +#endif +#endif + +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define vsnprintf vsnprintf_s +#endif + +String str_format(const char *p_format, va_list p_list) { + va_list list; + + va_copy(list, p_list); + int len = vsnprintf(NULL, 0, p_format, list); + va_end(list); + + len += 1; // for the trailing '/0' + + char *buffer(memnew_arr(char, len)); + + va_copy(list, p_list); + vsnprintf(buffer, len, p_format, list); + va_end(list); + + String res(buffer); + memdelete_arr(buffer); + + return res; +} diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h index 61765ccfd8..565b9bb644 100644 --- a/modules/mono/utils/string_utils.h +++ b/modules/mono/utils/string_utils.h @@ -34,6 +34,8 @@ #include "core/ustring.h" #include "core/variant.h" +#include <stdarg.h> + String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant()); #ifdef TOOLS_ENABLED @@ -44,4 +46,15 @@ String escape_csharp_keyword(const String &p_name); Error read_all_file_utf8(const String &p_path, String &r_content); +#if defined(__GNUC__) +#define _PRINTF_FORMAT_ATTRIBUTE_1_0 __attribute__((format(printf, 1, 0))) +#define _PRINTF_FORMAT_ATTRIBUTE_1_2 __attribute__((format(printf, 1, 2))) +#else +#define _PRINTF_FORMAT_ATTRIBUTE_1_0 +#define _PRINTF_FORMAT_ATTRIBUTE_1_2 +#endif + +String str_format(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_1_2; +String str_format(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE_1_0; + #endif // STRING_FORMAT_H diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index efd471eed1..b50c99932d 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2101,6 +2101,14 @@ void VisualScriptEditor::goto_line(int p_line, bool p_with_error) { } } +void VisualScriptEditor::set_executing_line(int p_line) { + // todo: add a way to show which node is executing right now. +} + +void VisualScriptEditor::clear_executing_line() { + // todo: add a way to show which node is executing right now. +} + void VisualScriptEditor::trim_trailing_whitespace() { } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index f4b4a6981d..9387a09c78 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -263,6 +263,8 @@ public: virtual Variant get_edit_state(); virtual void set_edit_state(const Variant &p_state); virtual void goto_line(int p_line, bool p_with_error = false); + virtual void set_executing_line(int p_line); + virtual void clear_executing_line(); virtual void trim_trailing_whitespace(); virtual void convert_indent_to_spaces(); virtual void convert_indent_to_tabs(); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 5a4c0593bc..fec524c04b 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -337,6 +337,11 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt } - (void)windowDidMove:(NSNotification *)notification { + + if (OS_OSX::singleton->get_main_loop()) { + OS_OSX::singleton->input->release_pressed_events(); + } + /* [window->nsgl.context update]; @@ -965,10 +970,10 @@ static const _KeyCodeMap _keycodes[55] = { { 'i', KEY_I }, { 'o', KEY_O }, { 'p', KEY_P }, - { '[', KEY_BRACERIGHT }, - { ']', KEY_BRACELEFT }, - { '{', KEY_BRACERIGHT }, - { '}', KEY_BRACELEFT }, + { '[', KEY_BRACELEFT }, + { ']', KEY_BRACERIGHT }, + { '{', KEY_BRACELEFT }, + { '}', KEY_BRACERIGHT }, { 'a', KEY_A }, { 's', KEY_S }, { 'd', KEY_D }, diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 193a3fa2c6..0b61770d87 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -346,6 +346,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) control_mem = false; shift_mem = false; } else { // WM_INACTIVE + input->release_pressed_events(); main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT); alt_mem = false; }; @@ -786,6 +787,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } break; case WM_ENTERSIZEMOVE: { + input->release_pressed_events(); move_timer_id = SetTimer(hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC)NULL); } break; case WM_EXITSIZEMOVE: { @@ -1411,26 +1413,29 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int void OS_Windows::set_clipboard(const String &p_text) { + // Convert LF line endings to CRLF in clipboard content + // Otherwise, line endings won't be visible when pasted in other software + String text = p_text.replace("\n", "\r\n"); + if (!OpenClipboard(hWnd)) { ERR_EXPLAIN("Unable to open clipboard."); ERR_FAIL(); }; EmptyClipboard(); - HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (p_text.length() + 1) * sizeof(CharType)); + HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType)); if (mem == NULL) { ERR_EXPLAIN("Unable to allocate memory for clipboard contents."); ERR_FAIL(); }; LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem); - memcpy(lptstrCopy, p_text.c_str(), (p_text.length() + 1) * sizeof(CharType)); - //memset((lptstrCopy + p_text.length()), 0, sizeof(CharType)); + memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType)); GlobalUnlock(mem); SetClipboardData(CF_UNICODETEXT, mem); // set the CF_TEXT version (not needed?) - CharString utf8 = p_text.utf8(); + CharString utf8 = text.utf8(); mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1); if (mem == NULL) { ERR_EXPLAIN("Unable to allocate memory for clipboard contents."); diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 91639a0db2..f8ae5e9acb 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -1,7 +1,7 @@ import os import platform import sys -from methods import get_compiler_version, using_gcc +from methods import get_compiler_version, using_gcc, using_clang def is_active(): @@ -184,6 +184,12 @@ def configure(env): if version != None and version[0] >= '6': env.Append(CCFLAGS=['-fpie']) env.Append(LINKFLAGS=['-no-pie']) + # Do the same for clang should be fine with Clang 4 and higher + if using_clang(env): + version = get_compiler_version(env) + if version != None and version[0] >= '4': + env.Append(CCFLAGS=['-fpie']) + env.Append(LINKFLAGS=['-no-pie']) ## Dependencies diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index f6161a9485..8d857de239 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -2076,7 +2076,9 @@ void OS_X11::process_xevents() { case FocusOut: window_has_focus = false; + input->release_pressed_events(); main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT); + if (mouse_mode_grab) { //dear X11, I try, I really try, but you never work, you do whathever you want. if (mouse_mode == MOUSE_MODE_CAPTURED) { diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp index 57e0a5b118..72b5f2fb12 100644 --- a/scene/2d/navigation_2d.cpp +++ b/scene/2d/navigation_2d.cpp @@ -542,7 +542,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) { //process - if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) { + if (Math::is_zero_approx(portal_left.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) { left_poly = p; portal_left = left; } else { @@ -552,7 +552,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect left_poly = p; portal_left = apex_point; portal_right = apex_point; - if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) + if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point))) path.push_back(apex_point); skip = true; } @@ -560,7 +560,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) { //process - if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) { + if (Math::is_zero_approx(portal_right.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) { right_poly = p; portal_right = right; } else { @@ -570,7 +570,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect right_poly = p; portal_right = apex_point; portal_left = apex_point; - if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) + if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point))) path.push_back(apex_point); } } @@ -596,7 +596,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect } } - if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) { + if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(begin_point))) { path.push_back(begin_point); // Add the begin point } else { path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point @@ -604,7 +604,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect path.invert(); - if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) { + if (path.size() <= 1 || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(end_point))) { path.push_back(end_point); // Add the end point } else { path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index 190967d76c..84078911cb 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -173,7 +173,7 @@ void PathFollow::_update_transform() { float dot = t_prev.dot(t_cur); float angle = Math::acos(CLAMP(dot, -1, 1)); - if (likely(Math::abs(angle) > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(angle))) { if (rotation_mode == ROTATION_Y) { // assuming we're referring to global Y-axis. is this correct? axis.x = 0; @@ -184,7 +184,7 @@ void PathFollow::_update_transform() { // all components are allowed } - if (likely(axis.length() > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(axis.length()))) { t.rotate_basis(axis.normalized(), angle); } } @@ -193,7 +193,7 @@ void PathFollow::_update_transform() { float tilt_angle = c->interpolate_baked_tilt(o); Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? - if (likely(Math::abs(tilt_angle) > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { if (rotation_mode == ROTATION_Y) { tilt_axis.x = 0; tilt_axis.z = 0; @@ -203,7 +203,7 @@ void PathFollow::_update_transform() { // all components are allowed } - if (likely(tilt_axis.length() > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(tilt_axis.length()))) { t.rotate_basis(tilt_axis.normalized(), tilt_angle); } } diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 750ed97ae6..75b419ca58 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -835,7 +835,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C for (int i = 0; i < 3; i++) { - if (ABS(light_axis[i]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[i])) continue; clip[clip_planes].normal[i] = 1.0; @@ -978,7 +978,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color for (int c = 0; c < 3; c++) { - if (ABS(light_axis[c]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[c])) continue; clip[clip_planes].normal[c] = 1.0; @@ -1113,7 +1113,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi for (int c = 0; c < 3; c++) { - if (ABS(light_axis[c]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[c])) continue; clip[clip_planes].normal[c] = 1.0; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index c78f29dd50..accf8aa7c2 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -776,6 +776,12 @@ void ColorPickerButton::_notification(int p_what) { if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) { popup->hide(); } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (popup && !is_visible_in_tree()) { + popup->hide(); + } + } } void ColorPickerButton::set_pick_color(const Color &p_color) { diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 30ad81bb2e..dabff08fea 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1053,7 +1053,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) { - if (ABS(E->get().activity - p_activity) < CMP_EPSILON) { + if (Math::is_equal_approx(E->get().activity, p_activity)) { //update only if changed top_layer->update(); connections_layer->update(); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index a011b793de..5f21d73ab2 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -91,6 +91,16 @@ bool MenuButton::is_switch_on_hover() { return switch_on_hover; } +void MenuButton::_notification(int p_what) { + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + + if (!is_visible_in_tree()) { + popup->hide(); + } + } +} + void MenuButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_popup"), &MenuButton::get_popup); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 794840035e..42e909d991 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -52,6 +52,7 @@ class MenuButton : public Button { void _gui_input(Ref<InputEvent> p_event); protected: + void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index cb5fb0263b..8c75393d01 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -72,6 +72,11 @@ void OptionButton::_notification(int p_what) { Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); arrow->draw(ci, ofs, clr); + } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + + if (!is_visible_in_tree()) { + popup->hide(); + } } } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index d6b5c0b82d..101eb2ac88 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -753,6 +753,8 @@ void RichTextLabel::_scroll_changed(double) { else scroll_following = false; + scroll_updated = true; + update(); } @@ -778,7 +780,6 @@ void RichTextLabel::_update_scroll() { main->first_invalid_line = 0; //invalidate ALL _validate_line_caches(main); } - scroll_updated = true; } void RichTextLabel::_notification(int p_what) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1f498ea16e..c77705f35f 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -988,6 +988,24 @@ void TextEdit::_notification(int p_what) { draw_texture_rect(info_icon, Rect2(icon_pos, icon_size)); } + // draw execution marker + if (executing_line == line) { + if (draw_breakpoint_gutter) { + int icon_extra_size = 4; + int vertical_gap = (get_row_height() * 40) / 100; + int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; + int marker_height = get_row_height() - (vertical_gap * 2) + icon_extra_size; + int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2) + icon_extra_size; + cache.executing_icon->draw_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 - icon_extra_size / 2, ofs_y + vertical_gap - icon_extra_size / 2, marker_width, marker_height), false, Color(cache.executing_line_color.r, cache.executing_line_color.g, cache.executing_line_color.b)); + } else { +#ifdef TOOLS_ENABLED + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color); +#else + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color); +#endif + } + } + // draw fold markers if (draw_fold_gutter) { int horizontal_gap = (cache.fold_gutter_width * 30) / 100; @@ -4414,6 +4432,7 @@ void TextEdit::_update_caches() { cache.current_line_color = get_color("current_line_color"); cache.line_length_guideline_color = get_color("line_length_guideline_color"); cache.breakpoint_color = get_color("breakpoint_color"); + cache.executing_line_color = get_color("executing_line_color"); cache.code_folding_color = get_color("code_folding_color"); cache.brace_mismatch_color = get_color("brace_mismatch_color"); cache.word_highlighted_color = get_color("word_highlighted_color"); @@ -4428,9 +4447,10 @@ void TextEdit::_update_caches() { #endif cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon = get_icon("tab"); - cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons"); - cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons"); + cache.folded_icon = get_icon("folded"); + cache.can_fold_icon = get_icon("fold"); cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons"); + cache.executing_icon = get_icon("MainPlay", "EditorIcons"); text.set_font(cache.font); if (syntax_highlighter) { @@ -4996,6 +5016,17 @@ bool TextEdit::is_line_set_as_safe(int p_line) const { return text.is_safe(p_line); } +void TextEdit::set_executing_line(int p_line) { + ERR_FAIL_INDEX(p_line, text.size()); + executing_line = p_line; + update(); +} + +void TextEdit::clear_executing_line() { + executing_line = -1; + update(); +} + bool TextEdit::is_line_set_as_breakpoint(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), false); @@ -5415,6 +5446,9 @@ void TextEdit::undo() { TextOperation op = undo_stack_pos->get(); _do_text_op(op, true); + if (op.from_line != op.to_line || op.to_column != op.from_column + 1) + select(op.from_line, op.from_column, op.to_line, op.to_column); + current_op.version = op.prev_version; if (undo_stack_pos->get().chain_backward) { while (true) { @@ -5541,6 +5575,7 @@ int TextEdit::get_indent_size() { void TextEdit::set_draw_tabs(bool p_draw) { draw_tabs = p_draw; + update(); } bool TextEdit::is_drawing_tabs() const { @@ -6259,8 +6294,12 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers); ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled); + ClassDB::bind_method(D_METHOD("set_draw_tabs"), &TextEdit::set_draw_tabs); + ClassDB::bind_method(D_METHOD("is_drawing_tabs"), &TextEdit::is_drawing_tabs); ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled); ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled); + ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter); + ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter); ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); @@ -6307,7 +6346,9 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_tabs"), "set_draw_tabs", "is_drawing_tabs"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); @@ -6471,6 +6512,8 @@ TextEdit::TextEdit() { menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z); menu->connect("id_pressed", this, "menu_option"); first_draw = true; + + executing_line = -1; } TextEdit::~TextEdit() { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index e854032159..4badd85e07 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -166,6 +166,7 @@ private: Ref<Texture> can_fold_icon; Ref<Texture> folded_icon; Ref<Texture> folded_eol_icon; + Ref<Texture> executing_icon; Ref<StyleBox> style_normal; Ref<StyleBox> style_focus; Ref<StyleBox> style_readonly; @@ -187,6 +188,7 @@ private: Color selection_color; Color mark_color; Color breakpoint_color; + Color executing_line_color; Color code_folding_color; Color current_line_color; Color line_length_guideline_color; @@ -345,6 +347,8 @@ private: bool context_menu_enabled; + int executing_line; + int get_visible_rows() const; int get_total_visible_rows() const; @@ -486,6 +490,8 @@ public: void set_line_as_marked(int p_line, bool p_marked); void set_line_as_breakpoint(int p_line, bool p_breakpoint); bool is_line_set_as_breakpoint(int p_line) const; + void set_executing_line(int p_line); + void clear_executing_line(); void set_line_as_safe(int p_line, bool p_safe); bool is_line_set_as_safe(int p_line) const; void get_breakpoints(List<int> *p_breakpoints) const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 81c38cec89..125e0a2882 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1160,7 +1160,7 @@ void SceneTree::_update_root_rect() { WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'."); } - if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) { + if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { //same aspect or ignore aspect viewport_size = desired_res; screen_size = video_mode; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index e58ec9d71e..9c79b2ba3b 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1477,7 +1477,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const { middle = (low + high) / 2; - if (Math::abs(p_time - keys[middle].time) < CMP_EPSILON) { //match + if (Math::is_equal_approx(p_time, keys[middle].time)) { //match return middle; } else if (p_time < keys[middle].time) high = middle - 1; //search low end of array @@ -1680,10 +1680,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = p_keys[next].time - p_keys[idx].time; float from = p_time - p_keys[idx].time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } else { @@ -1691,10 +1691,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = (length - p_keys[idx].time) + p_keys[next].time; float from = p_time - p_keys[idx].time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } } else { @@ -1707,10 +1707,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = endtime + p_keys[next].time; float from = endtime + p_time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } } else { // no loop @@ -1723,10 +1723,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = p_keys[next].time - p_keys[idx].time; float from = p_time - p_keys[idx].time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } else { @@ -2774,9 +2774,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons const Vector3 &v1 = t1.value.loc; const Vector3 &v2 = t2.value.loc; - if (v0.distance_to(v2) < CMP_EPSILON) { + if (Math::is_zero_approx(v0.distance_to(v2))) { //0 and 2 are close, let's see if 1 is close - if (v0.distance_to(v1) > CMP_EPSILON) { + if (!Math::is_zero_approx(v0.distance_to(v1))) { //not close, not optimizable return false; } @@ -2813,9 +2813,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons //localize both to rotation from q0 - if ((q0 - q2).length() < CMP_EPSILON) { + if (Math::is_zero_approx((q0 - q2).length())) { - if ((q0 - q1).length() > CMP_EPSILON) + if (!Math::is_zero_approx((q0 - q1).length())) return false; } else { @@ -2863,9 +2863,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons const Vector3 &v1 = t1.value.scale; const Vector3 &v2 = t2.value.scale; - if (v0.distance_to(v2) < CMP_EPSILON) { + if (Math::is_zero_approx(v0.distance_to(v2))) { //0 and 2 are close, let's see if 1 is close - if (v0.distance_to(v1) > CMP_EPSILON) { + if (!Math::is_zero_approx(v0.distance_to(v1))) { //not close, not optimizable return false; } diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index f425972183..79d93113b3 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -423,6 +423,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); theme->set_icon("tab", "TextEdit", make_icon(tab_png)); + theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png)); + theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png)); theme->set_font("font", "TextEdit", default_font); @@ -437,6 +439,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("selection_color", "TextEdit", font_color_selection); theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4)); theme->set_color("breakpoint_color", "TextEdit", Color(0.8, 0.8, 0.4, 0.2)); + theme->set_color("executing_line_color", "TextEdit", Color(0.2, 0.8, 0.2, 0.4)); theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8)); theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8)); theme->set_color("caret_color", "TextEdit", control_font_color); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 626ed9f5b4..2c6f30f429 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -535,7 +535,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map float a = value; float b = original; - if (Math::abs(a - b) < CMP_EPSILON) + if (Math::is_equal_approx(a, b)) continue; } else if (bool(Variant::evaluate(Variant::OP_EQUAL, value, original))) { diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp index baf7431e28..3073cc8b11 100644 --- a/servers/physics/collision_solver_sat.cpp +++ b/servers/physics/collision_solver_sat.cpp @@ -98,7 +98,7 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ Vector3 c = rel_A.cross(rel_B).cross(rel_B); - if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) { + if (Math::is_zero_approx(rel_A.dot(c))) { // should handle somehow.. //ERR_PRINT("TODO FIX"); @@ -678,7 +678,7 @@ static void _collision_box_box(const ShapeSW *p_a, const Transform &p_transform_ Vector3 axis = p_transform_a.basis.get_axis(i).cross(p_transform_b.basis.get_axis(j)); - if (axis.length_squared() < CMP_EPSILON) + if (Math::is_zero_approx(axis.length_squared())) continue; axis.normalize(); @@ -767,7 +767,7 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf // cylinder Vector3 box_axis = p_transform_a.basis.get_axis(i); Vector3 axis = box_axis.cross(cyl_axis); - if (axis.length_squared() < CMP_EPSILON) + if (Math::is_zero_approx(axis.length_squared())) continue; if (!separator.test_axis(axis.normalized())) diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp index 268b9eefeb..1b3de3e913 100644 --- a/servers/physics/joints/cone_twist_joint_sw.cpp +++ b/servers/physics/joints/cone_twist_joint_sw.cpp @@ -127,10 +127,10 @@ bool ConeTwistJointSW::setup(real_t p_timestep) { Vector3 relPos = pivotBInW - pivotAInW; Vector3 normal[3]; - if (relPos.length_squared() > CMP_EPSILON) { - normal[0] = relPos.normalized(); - } else { + if (Math::is_zero_approx(relPos.length_squared())) { normal[0] = Vector3(real_t(1.0), 0, 0); + } else { + normal[0] = relPos.normalized(); } plane_space(normal[0], normal[1], normal[2]); diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp index 756348f448..813d9b7704 100644 --- a/servers/physics/joints/generic_6dof_joint_sw.cpp +++ b/servers/physics/joints/generic_6dof_joint_sw.cpp @@ -107,7 +107,7 @@ real_t G6DOFRotationalLimitMotorSW::solveAngularLimits( // correction velocity real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel); - if (motor_relvel < CMP_EPSILON && motor_relvel > -CMP_EPSILON) { + if (Math::is_zero_approx(motor_relvel)) { return 0.0f; //no need for applying force } diff --git a/servers/physics/joints/hinge_joint_sw.cpp b/servers/physics/joints/hinge_joint_sw.cpp index e972496b2b..1d1b30286e 100644 --- a/servers/physics/joints/hinge_joint_sw.cpp +++ b/servers/physics/joints/hinge_joint_sw.cpp @@ -167,10 +167,10 @@ bool HingeJointSW::setup(real_t p_step) { Vector3 relPos = pivotBInW - pivotAInW; Vector3 normal[3]; - if (relPos.length_squared() > CMP_EPSILON) { - normal[0] = relPos.normalized(); - } else { + if (Math::is_zero_approx(relPos.length_squared())) { normal[0] = Vector3(real_t(1.0), 0, 0); + } else { + normal[0] = relPos.normalized(); } plane_space(normal[0], normal[1], normal[2]); diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index d6c3fff421..f4bff66389 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -237,8 +237,8 @@ public: Vector2 axis = p_axis; - if (Math::abs(axis.x) < CMP_EPSILON && - Math::abs(axis.y) < CMP_EPSILON) { + if (Math::is_zero_approx(axis.x) && + Math::is_zero_approx(axis.y)) { // strange case, try an upwards separator axis = Vector2(0.0, 1.0); } diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 4e99bb3676..26424f927e 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -82,7 +82,7 @@ public: _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const { - if (Math::abs(p_left->ysort_pos.y - p_right->ysort_pos.y) < CMP_EPSILON) + if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y)) return p_left->ysort_pos.x < p_right->ysort_pos.x; else return p_left->ysort_pos.y < p_right->ysort_pos.y; diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index c1dc94daa2..af580d6794 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2654,7 +2654,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co for (int i = 0; i < 3; i++) { - if (ABS(light_axis[i]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[i])) continue; clip[clip_planes].normal[i] = 1.0; @@ -2789,7 +2789,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co for (int c = 0; c < 3; c++) { - if (ABS(light_axis[c]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[c])) continue; clip[clip_planes].normal[c] = 1.0; |