diff options
47 files changed, 1620 insertions, 97 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 3b43492bc5..234d71cb68 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -179,10 +179,10 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p print_line("load resource: " + local_path); bool found = false; + // Try all loaders and pick the first match for the type hint for (int i = 0; i < loader_count; i++) { if (!loader[i]->recognize_path(local_path, p_type_hint)) { - print_line("path not recognized"); continue; } found = true; diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp index 20b916ee3b..962a42acb9 100644 --- a/core/math/math_2d.cpp +++ b/core/math/math_2d.cpp @@ -63,7 +63,8 @@ Vector2 Vector2::normalized() const { } bool Vector2::is_normalized() const { - return Math::isequal_approx(length(), (real_t)1.0); + // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. + return Math::is_equal_approx(length_squared(), 1.0); } real_t Vector2::distance_to(const Vector2 &p_vector2) const { @@ -281,7 +282,7 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c // slide returns the component of the vector along the given plane, specified by its normal vector. Vector2 Vector2::slide(const Vector2 &p_n) const { -#ifdef DEBUG_ENABLED +#ifdef MATH_CHECKS ERR_FAIL_COND_V(p_n.is_normalized() == false, Vector2()); #endif return *this - p_n * this->dot(p_n); @@ -292,7 +293,7 @@ Vector2 Vector2::bounce(const Vector2 &p_n) const { } Vector2 Vector2::reflect(const Vector2 &p_n) const { -#ifdef DEBUG_ENABLED +#ifdef MATH_CHECKS ERR_FAIL_COND_V(p_n.is_normalized() == false, Vector2()); #endif return 2.0 * p_n * this->dot(p_n) - *this; @@ -439,7 +440,9 @@ Transform2D Transform2D::inverse() const { void Transform2D::affine_invert() { real_t det = basis_determinant(); +#ifdef MATH_CHECKS ERR_FAIL_COND(det == 0); +#endif real_t idet = 1.0 / det; SWAP(elements[0][0], elements[1][1]); diff --git a/core/math/math_defs.h b/core/math/math_defs.h index 1a5768e515..3d9eb63e11 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -35,6 +35,10 @@ #define CMP_NORMALIZE_TOLERANCE 0.000001 #define CMP_POINT_IN_PLANE_EPSILON 0.00001 +#ifdef DEBUG_ENABLED +#define MATH_CHECKS +#endif + #define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0) /** * "Real" is a type that will be translated to either floats or fixed depending diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index d71d9bd792..5bfbc1005f 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -168,7 +168,7 @@ public: static float random(float from, float to); static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); } - static _ALWAYS_INLINE_ bool isequal_approx(real_t a, real_t b) { + static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) { // 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. diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index ef368009d1..c733251c3c 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -62,8 +62,9 @@ void Basis::invert() { real_t det = elements[0][0] * co[0] + elements[0][1] * co[1] + elements[0][2] * co[2]; - +#ifdef MATH_CHECKS ERR_FAIL_COND(det == 0); +#endif real_t s = 1.0 / det; set(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, @@ -72,8 +73,9 @@ void Basis::invert() { } void Basis::orthonormalize() { +#ifdef MATH_CHECKS ERR_FAIL_COND(determinant() == 0); - +#endif // Gram-Schmidt Process Vector3 x = get_axis(0); @@ -102,20 +104,20 @@ bool Basis::is_orthogonal() const { Basis id; Basis m = (*this) * transposed(); - return isequal_approx(id, m); + return is_equal_approx(id, m); } bool Basis::is_rotation() const { - return Math::isequal_approx(determinant(), 1) && is_orthogonal(); + return Math::is_equal_approx(determinant(), 1) && is_orthogonal(); } bool Basis::is_symmetric() const { - if (Math::abs(elements[0][1] - elements[1][0]) > CMP_EPSILON) + if (!Math::is_equal_approx(elements[0][1], elements[1][0])) return false; - if (Math::abs(elements[0][2] - elements[2][0]) > CMP_EPSILON) + if (!Math::is_equal_approx(elements[0][2], elements[2][0])) return false; - if (Math::abs(elements[1][2] - elements[2][1]) > CMP_EPSILON) + if (!Math::is_equal_approx(elements[1][2], elements[2][1])) return false; return true; @@ -123,11 +125,11 @@ bool Basis::is_symmetric() const { Basis Basis::diagonalize() { - //NOTE: only implemented for symmetric matrices - //with the Jacobi iterative method method - +//NOTE: only implemented for symmetric matrices +//with the Jacobi iterative method method +#ifdef MATH_CHECKS ERR_FAIL_COND_V(!is_symmetric(), Basis()); - +#endif const int ite_max = 1024; real_t off_matrix_norm_2 = elements[0][1] * elements[0][1] + elements[0][2] * elements[0][2] + elements[1][2] * elements[1][2]; @@ -160,7 +162,7 @@ Basis Basis::diagonalize() { // Compute the rotation angle real_t angle; - if (Math::abs(elements[j][j] - elements[i][i]) < CMP_EPSILON) { + if (Math::is_equal_approx(elements[j][j], elements[i][i])) { angle = Math_PI / 4; } else { angle = 0.5 * Math::atan(2 * elements[i][j] / (elements[j][j] - elements[i][i])); @@ -226,11 +228,25 @@ Basis Basis::scaled(const Vector3 &p_scale) const { } Vector3 Basis::get_scale() const { - // We are assuming M = R.S, and performing a polar decomposition to extract R and S. - // FIXME: We eventually need a proper polar decomposition. - // As a cheap workaround until then, to ensure that R is a proper rotation matrix with determinant +1 - // (such that it can be represented by a Quat or Euler angles), we absorb the sign flip into the scaling matrix. - // As such, it works in conjunction with get_rotation(). + // FIXME: We are assuming M = R.S (R is rotation and S is scaling), and use polar decomposition to extract R and S. + // A polar decomposition is M = O.P, where O is an orthogonal matrix (meaning rotation and reflection) and + // P is a positive semi-definite matrix (meaning it contains absolute values of scaling along its diagonal). + // + // Despite being different from what we want to achieve, we can nevertheless make use of polar decomposition + // here as follows. We can split O into a rotation and a reflection as O = R.Q, and obtain M = R.S where + // we defined S = Q.P. Now, R is a proper rotation matrix and S is a (signed) scaling matrix, + // which can involve negative scalings. However, there is a catch: unlike the polar decomposition of M = O.P, + // the decomposition of O into a rotation and reflection matrix as O = R.Q is not unique. + // Therefore, we are going to do this decomposition by sticking to a particular convention. + // This may lead to confusion for some users though. + // + // The convention we use here is to absorb the sign flip into the scaling matrix. + // The same convention is also used in other similar functions such as set_scale, + // get_rotation_axis_angle, get_rotation, set_rotation_axis_angle, set_rotation_euler, ... + // + // A proper way to get rid of this issue would be to store the scaling values (or at least their signs) + // as a part of Basis. However, if we go that path, we need to disable direct (write) access to the + // matrix elements. real_t det_sign = determinant() > 0 ? 1 : -1; return det_sign * Vector3( Vector3(elements[0][0], elements[1][0], elements[2][0]).length(), @@ -238,6 +254,17 @@ Vector3 Basis::get_scale() const { Vector3(elements[0][2], elements[1][2], elements[2][2]).length()); } +// Sets scaling while preserving rotation. +// This requires some care when working with matrices with negative determinant, +// since we're using a particular convention for "polar" decomposition in get_scale and get_rotation. +// For details, see the explanation in get_scale. +void Basis::set_scale(const Vector3 &p_scale) { + Vector3 e = get_euler(); + Basis(); // reset to identity + scale(p_scale); + rotate(e); +} + // Multiplies the matrix from left by the rotation matrix: M -> R.M // Note that this does *not* rotate the matrix itself. // @@ -260,6 +287,7 @@ void Basis::rotate(const Vector3 &p_euler) { *this = rotated(p_euler); } +// TODO: rename this to get_rotation_euler Vector3 Basis::get_rotation() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). @@ -274,6 +302,42 @@ Vector3 Basis::get_rotation() const { return m.get_euler(); } +void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = orthonormalized(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + m.get_axis_angle(p_axis, p_angle); +} + +// Sets rotation while preserving scaling. +// This requires some care when working with matrices with negative determinant, +// since we're using a particular convention for "polar" decomposition in get_scale and get_rotation. +// For details, see the explanation in get_scale. +void Basis::set_rotation_euler(const Vector3 &p_euler) { + Vector3 s = get_scale(); + Basis(); // reset to identity + scale(s); + rotate(p_euler); +} + +// Sets rotation while preserving scaling. +// This requires some care when working with matrices with negative determinant, +// since we're using a particular convention for "polar" decomposition in get_scale and get_rotation. +// For details, see the explanation in get_scale. +void Basis::set_rotation_axis_angle(const Vector3 &p_axis, real_t p_angle) { + Vector3 s = get_scale(); + Basis(); // reset to identity + scale(s); + rotate(p_axis, p_angle); +} + // get_euler returns a vector containing the Euler angles in the format // (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last // (following the convention they are commonly defined in the literature). @@ -294,9 +358,9 @@ Vector3 Basis::get_euler() const { // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy Vector3 euler; - +#ifdef MATH_CHECKS ERR_FAIL_COND_V(is_rotation() == false, euler); - +#endif euler.y = Math::asin(elements[0][2]); if (euler.y < Math_PI * 0.5) { if (euler.y > -Math_PI * 0.5) { @@ -340,11 +404,11 @@ void Basis::set_euler(const Vector3 &p_euler) { *this = xmat * (ymat * zmat); } -bool Basis::isequal_approx(const Basis &a, const Basis &b) const { +bool Basis::is_equal_approx(const Basis &a, const Basis &b) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - if (Math::isequal_approx(a.elements[i][j], b.elements[i][j]) == false) + if (Math::is_equal_approx(a.elements[i][j], b.elements[i][j]) == false) return false; } } @@ -387,8 +451,9 @@ Basis::operator String() const { } Basis::operator Quat() const { +#ifdef MATH_CHECKS ERR_FAIL_COND_V(is_rotation() == false, Quat()); - +#endif real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; real_t temp[4]; @@ -482,9 +547,10 @@ void Basis::set_orthogonal_index(int p_index) { *this = _ortho_bases[p_index]; } -void Basis::get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const { +void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { +#ifdef MATH_CHECKS ERR_FAIL_COND(is_rotation() == false); - +#endif real_t angle, x, y, z; // variables for result real_t epsilon = 0.01; // margin to allow for rounding errors real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees @@ -573,11 +639,11 @@ Basis::Basis(const Quat &p_quat) { xz - wy, yz + wx, 1.0 - (xx + yy)); } -Basis::Basis(const Vector3 &p_axis, real_t p_phi) { - // Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle - +void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { +// Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_angle +#ifdef MATH_CHECKS ERR_FAIL_COND(p_axis.is_normalized() == false); - +#endif Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z); real_t cosine = Math::cos(p_phi); @@ -595,3 +661,7 @@ Basis::Basis(const Vector3 &p_axis, real_t p_phi) { elements[2][1] = p_axis.y * p_axis.z * (1.0 - cosine) + p_axis.x * sine; elements[2][2] = axis_sq.z + cosine * (1.0 - axis_sq.z); } + +Basis::Basis(const Vector3 &p_axis, real_t p_phi) { + set_axis_angle(p_axis, p_phi); +} diff --git a/core/math/matrix3.h b/core/math/matrix3.h index 08e963f56e..c3eeb1f705 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -77,15 +77,25 @@ public: void rotate(const Vector3 &p_euler); Basis rotated(const Vector3 &p_euler) const; + Vector3 get_rotation() const; + void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; - void scale(const Vector3 &p_scale); - Basis scaled(const Vector3 &p_scale) const; - Vector3 get_scale() const; + void set_rotation_euler(const Vector3 &p_euler); + void set_rotation_axis_angle(const Vector3 &p_axis, real_t p_angle); Vector3 get_euler() const; void set_euler(const Vector3 &p_euler); + void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const; + void set_axis_angle(const Vector3 &p_axis, real_t p_phi); + + void scale(const Vector3 &p_scale); + Basis scaled(const Vector3 &p_scale) const; + + Vector3 get_scale() const; + void set_scale(const Vector3 &p_scale); + // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { return elements[0][0] * v[0] + elements[1][0] * v[1] + elements[2][0] * v[2]; @@ -97,7 +107,7 @@ public: return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2]; } - bool isequal_approx(const Basis &a, const Basis &b) const; + bool is_equal_approx(const Basis &a, const Basis &b) const; bool operator==(const Basis &p_matrix) const; bool operator!=(const Basis &p_matrix) const; @@ -121,8 +131,6 @@ public: operator String() const; - void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const; - /* create / set */ _FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { diff --git a/core/math/quat.cpp b/core/math/quat.cpp index 9662542224..0bea97c2e8 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -92,6 +92,10 @@ Quat Quat::normalized() const { return *this / length(); } +bool Quat::is_normalized() const { + return Math::is_equal_approx(length(), 1.0); +} + Quat Quat::inverse() const { return Quat(-x, -y, -z, w); } diff --git a/core/math/quat.h b/core/math/quat.h index 76b3cde2a3..f22275b457 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -48,6 +48,7 @@ public: real_t length() const; void normalize(); Quat normalized() const; + bool is_normalized() const; Quat inverse() const; _FORCE_INLINE_ real_t dot(const Quat &q) const; void set_euler(const Vector3 &p_euler); @@ -56,7 +57,7 @@ public: Quat slerpni(const Quat &q, const real_t &t) const; Quat cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const; - _FORCE_INLINE_ void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const { + _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = 2 * Math::acos(w); r_axis.x = x / Math::sqrt(1 - w * w); r_axis.y = y / Math::sqrt(1 - w * w); diff --git a/core/math/vector3.h b/core/math/vector3.h index a6bc20ccb2..5f4390fbd1 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -389,7 +389,8 @@ Vector3 Vector3::normalized() const { } bool Vector3::is_normalized() const { - return Math::isequal_approx(length(), (real_t)1.0); + // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. + return Math::is_equal_approx(length_squared(), 1.0); } Vector3 Vector3::inverse() const { @@ -404,7 +405,7 @@ void Vector3::zero() { // slide returns the component of the vector along the given plane, specified by its normal vector. Vector3 Vector3::slide(const Vector3 &p_n) const { -#ifdef DEBUG_ENABLED +#ifdef MATH_CHECKS ERR_FAIL_COND_V(p_n.is_normalized() == false, Vector3()); #endif return *this - p_n * this->dot(p_n); @@ -415,7 +416,7 @@ Vector3 Vector3::bounce(const Vector3 &p_n) const { } Vector3 Vector3::reflect(const Vector3 &p_n) const { -#ifdef DEBUG_ENABLED +#ifdef MATH_CHECKS ERR_FAIL_COND_V(p_n.is_normalized() == false, Vector3()); #endif return 2.0 * p_n * this->dot(p_n) - *this; diff --git a/core/script_language.h b/core/script_language.h index 1ec02f5845..115ab59dca 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -199,6 +199,7 @@ public: virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const = 0; virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; + virtual bool can_inherit_from_file() { return false; } virtual int find_function(const String &p_function, const String &p_code) const = 0; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const = 0; virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } diff --git a/core/ustring.cpp b/core/ustring.cpp index d2d4b6507f..b01f680dd6 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -513,14 +513,16 @@ String String::camelcase_to_underscore(bool lowercase) const { for (size_t i = 1; i < this->size(); i++) { bool is_upper = cstr[i] >= A && cstr[i] <= Z; + bool is_number = cstr[i] >= '0' && cstr[i] <= '9'; bool are_next_2_lower = false; bool was_precedent_upper = cstr[i - 1] >= A && cstr[i - 1] <= Z; + bool was_precedent_number = cstr[i - 1] >= '0' && cstr[i - 1] <= '9'; if (i + 2 < this->size()) { are_next_2_lower = cstr[i + 1] >= a && cstr[i + 1] <= z && cstr[i + 2] >= a && cstr[i + 2] <= z; } - bool should_split = ((is_upper && !was_precedent_upper) || (was_precedent_upper && is_upper && are_next_2_lower)); + bool should_split = ((is_upper && !was_precedent_upper && !was_precedent_number) || (was_precedent_upper && is_upper && are_next_2_lower) || (is_number && !was_precedent_number)); if (should_split) { new_string += this->substr(start_index, i - start_index) + "_"; start_index = i; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index e87dfd2768..beaee188eb 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -328,6 +328,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector2, normalized); VCALL_LOCALMEM0R(Vector2, length); VCALL_LOCALMEM0R(Vector2, length_squared); + VCALL_LOCALMEM0R(Vector2, is_normalized); VCALL_LOCALMEM1R(Vector2, distance_to); VCALL_LOCALMEM1R(Vector2, distance_squared_to); VCALL_LOCALMEM1R(Vector2, angle_to); @@ -362,6 +363,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector3, max_axis); VCALL_LOCALMEM0R(Vector3, length); VCALL_LOCALMEM0R(Vector3, length_squared); + VCALL_LOCALMEM0R(Vector3, is_normalized); VCALL_LOCALMEM0R(Vector3, normalized); VCALL_LOCALMEM0R(Vector3, inverse); VCALL_LOCALMEM1R(Vector3, snapped); @@ -418,6 +420,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Quat, length); VCALL_LOCALMEM0R(Quat, length_squared); VCALL_LOCALMEM0R(Quat, normalized); + VCALL_LOCALMEM0R(Quat, is_normalized); VCALL_LOCALMEM0R(Quat, inverse); VCALL_LOCALMEM1R(Quat, dot); VCALL_LOCALMEM1R(Quat, xform); @@ -704,6 +707,9 @@ struct _VariantCall { VCALL_PTR1R(Basis, scaled); VCALL_PTR0R(Basis, get_scale); VCALL_PTR0R(Basis, get_euler); + VCALL_PTR1(Basis, set_scale); + VCALL_PTR1(Basis, set_rotation_euler); + VCALL_PTR2(Basis, set_rotation_axis_angle); VCALL_PTR1R(Basis, tdotx); VCALL_PTR1R(Basis, tdoty); VCALL_PTR1R(Basis, tdotz); @@ -875,6 +881,11 @@ struct _VariantCall { r_ret = Basis(p_args[0]->operator Vector3(), p_args[1]->operator real_t()); } + static void Basis_init3(Variant &r_ret, const Variant **p_args) { + + r_ret = Basis(p_args[0]->operator Vector3()); + } + static void Transform_init1(Variant &r_ret, const Variant **p_args) { Transform t; @@ -1429,6 +1440,7 @@ void register_variant_methods() { ADDFUNC0(VECTOR2, REAL, Vector2, length, varray()); ADDFUNC0(VECTOR2, REAL, Vector2, angle, varray()); ADDFUNC0(VECTOR2, REAL, Vector2, length_squared, varray()); + ADDFUNC0(VECTOR2, BOOL, Vector2, is_normalized, varray()); ADDFUNC1(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray()); ADDFUNC1(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray()); ADDFUNC1(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); @@ -1462,6 +1474,7 @@ void register_variant_methods() { ADDFUNC0(VECTOR3, INT, Vector3, max_axis, varray()); ADDFUNC0(VECTOR3, REAL, Vector3, length, varray()); ADDFUNC0(VECTOR3, REAL, Vector3, length_squared, varray()); + ADDFUNC0(VECTOR3, BOOL, Vector3, is_normalized, varray()); ADDFUNC0(VECTOR3, VECTOR3, Vector3, normalized, varray()); ADDFUNC0(VECTOR3, VECTOR3, Vector3, inverse, varray()); ADDFUNC1(VECTOR3, VECTOR3, Vector3, snapped, REAL, "by", varray()); @@ -1497,6 +1510,7 @@ void register_variant_methods() { ADDFUNC0(QUAT, REAL, Quat, length, varray()); ADDFUNC0(QUAT, REAL, Quat, length_squared, varray()); ADDFUNC0(QUAT, QUAT, Quat, normalized, varray()); + ADDFUNC0(QUAT, BOOL, Quat, is_normalized, varray()); ADDFUNC0(QUAT, QUAT, Quat, inverse, varray()); ADDFUNC1(QUAT, REAL, Quat, dot, QUAT, "b", varray()); ADDFUNC1(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray()); @@ -1692,6 +1706,9 @@ void register_variant_methods() { ADDFUNC0(BASIS, REAL, Basis, determinant, varray()); ADDFUNC2(BASIS, BASIS, Basis, rotated, VECTOR3, "axis", REAL, "phi", varray()); ADDFUNC1(BASIS, BASIS, Basis, scaled, VECTOR3, "scale", varray()); + ADDFUNC1(BASIS, NIL, Basis, set_scale, VECTOR3, "scale", varray()); + ADDFUNC1(BASIS, NIL, Basis, set_rotation_euler, VECTOR3, "euler", varray()); + ADDFUNC2(BASIS, NIL, Basis, set_rotation_axis_angle, VECTOR3, "axis", REAL, "angle", varray()); ADDFUNC0(BASIS, VECTOR3, Basis, get_scale, varray()); ADDFUNC0(BASIS, VECTOR3, Basis, get_euler, varray()); ADDFUNC1(BASIS, REAL, Basis, tdotx, VECTOR3, "with", varray()); @@ -1749,6 +1766,7 @@ void register_variant_methods() { _VariantCall::add_constructor(_VariantCall::Basis_init1, Variant::BASIS, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3); _VariantCall::add_constructor(_VariantCall::Basis_init2, Variant::BASIS, "axis", Variant::VECTOR3, "phi", Variant::REAL); + _VariantCall::add_constructor(_VariantCall::Basis_init3, Variant::BASIS, "euler", Variant::VECTOR3); _VariantCall::add_constructor(_VariantCall::Transform_init1, Variant::TRANSFORM, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3, "origin", Variant::VECTOR3); _VariantCall::add_constructor(_VariantCall::Transform_init2, Variant::TRANSFORM, "basis", Variant::BASIS, "origin", Variant::VECTOR3); diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 9b1f8c788b..e0e88ef348 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -6868,6 +6868,15 @@ <method name="Basis"> <return type="Basis"> </return> + <argument index="0" name="euler" type="Vector3"> + </argument> + <description> + Create a rotation matrix (in the XYZ convention: first Z, then Y, and X last) from the specified Euler angles, given in the vector format as (third,second,first). + </description> + </method> + <method name="Basis"> + <return type="Basis"> + </return> <argument index="0" name="x_axis" type="Vector3"> </argument> <argument index="1" name="y_axis" type="Vector3"> @@ -6889,8 +6898,7 @@ <return type="Vector3"> </return> <description> - Return Euler angles (in the XYZ convention: first Z, then Y, and X last) from the matrix. Returned vector contains the rotation angles in the format (third,second,first). - This function only works if the matrix represents a proper rotation. + Assuming that the matrix is a proper rotation matrix (orthonormal matrix with determinant +1), return Euler angles (in the XYZ convention: first Z, then Y, and X last). Returned vector contains the rotation angles in the format (third,second,first). </description> </method> <method name="get_orthogonal_index"> @@ -6932,6 +6940,26 @@ Introduce an additional rotation around the given axis by phi (radians). Only relevant when the matrix is being used as a part of [Transform]. The axis must be a normalized vector. </description> </method> + <method name="set_rotation_euler"> + <return type="Basis"> + </return> + <argument index="0" name="euler" type="Vector3"> + </argument> + <description> + Changes only the rotation part of the [Basis] to a rotation corresponding to given Euler angles, while preserving the scaling part (as determined by get_scale). + </description> + </method> + <method name="set_rotation_axis_angle"> + <return type="Basis"> + </return> + <argument index="0" name="axis" type="Vector3"> + </argument> + <argument index="1" name="phi" type="float"> + </argument> + <description> + Changes only the rotation part of the [Basis] to a rotation around given axis by phi, while preserving the scaling part (as determined by get_scale). + </description> + </method> <method name="scaled"> <return type="Basis"> </return> @@ -6941,6 +6969,15 @@ Introduce an additional scaling specified by the given 3D scaling factor. Only relevant when the matrix is being used as a part of [Transform]. </description> </method> + <method name="set_scale"> + <return type="Basis"> + </return> + <argument index="0" name="scale" type="Vector3"> + </argument> + <description> + Changes only the scaling part of the Basis to the specified scaling, while preserving the rotation part (as determined by get_rotation). + </description> + </method> <method name="tdotx"> <return type="float"> </return> @@ -35148,6 +35185,13 @@ Returns a copy of the quaternion, normalized to unit length. </description> </method> + <method name="is_normalized"> + <return type="bool"> + </return> + <description> + Returns whether the quaternion is normalized or not. + </description> + </method> <method name="slerp"> <return type="Quat"> </return> @@ -48048,6 +48092,13 @@ do_property]. Returns a normalized vector to unit length. </description> </method> + <method name="is_normalized"> + <return type="bool"> + </return> + <description> + Returns whether the vector is normalized or not. + </description> + </method> <method name="reflect"> <return type="Vector2"> </return> @@ -48272,6 +48323,13 @@ do_property]. Return a copy of the normalized vector to unit length. This is the same as v / v.length(). </description> </method> + <method name="is_normalized"> + <return type="bool"> + </return> + <description> + Returns whether the vector is normalized or not. + </description> + </method> <method name="outer"> <return type="Basis"> </return> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 9cb44349bf..a7996b09d3 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -125,14 +125,13 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas, int p_size) { if (p_size == shadow_atlas->size) return; + // erasing atlas if (shadow_atlas->fbo) { glDeleteTextures(1, &shadow_atlas->depth); glDeleteFramebuffers(1, &shadow_atlas->fbo); shadow_atlas->depth = 0; shadow_atlas->fbo = 0; - - print_line("erasing atlas"); } for (int i = 0; i < 4; i++) { //clear subdivisions @@ -4678,7 +4677,7 @@ void RasterizerSceneGLES3::initialize() { const int ubo_light_size = 160; state.ubo_light_size = ubo_light_size; state.max_ubo_lights = MIN(RenderList::MAX_LIGHTS, max_ubo_size / ubo_light_size); - print_line("max ubo light: " + itos(state.max_ubo_lights)); + print_line("GLES3: max ubo light: " + itos(state.max_ubo_lights)); state.spot_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); state.omni_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); @@ -4704,7 +4703,7 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS " + itos(state.max_forward_lights_per_object) + "\n"); state.max_ubo_reflections = MIN(RenderList::MAX_REFLECTIONS, max_ubo_size / sizeof(ReflectionProbeDataUBO)); - print_line("max ubo reflections: " + itos(state.max_ubo_reflections) + " ubo size: " + itos(sizeof(ReflectionProbeDataUBO))); + print_line("GLES3: max ubo reflections: " + itos(state.max_ubo_reflections) + ", ubo size: " + itos(sizeof(ReflectionProbeDataUBO))); state.reflection_array_tmp = (uint8_t *)memalloc(sizeof(ReflectionProbeDataUBO) * state.max_ubo_reflections); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 9316b025eb..73547b5a16 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -825,7 +825,6 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSide p_ if (!texture->images[p_cube_side].empty()) { return texture->images[p_cube_side]; } - print_line("GETTING FROM GL "); #ifdef GLES_OVER_GL @@ -842,7 +841,7 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSide p_ glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - print_line("GET FORMAT: " + Image::get_format_name(texture->format) + " mipmaps: " + itos(texture->mipmaps)); + //print_line("GET FORMAT: " + Image::get_format_name(texture->format) + " mipmaps: " + itos(texture->mipmaps)); for (int i = 0; i < texture->mipmaps; i++) { @@ -4777,7 +4776,6 @@ RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width, int p_heig min_size = 4; } - print_line("dyndata create"); while (true) { if (gipd->compression == GI_PROBE_S3TC) { @@ -6270,7 +6268,6 @@ bool RasterizerStorageGLES3::free(RID p_rid) { // delete the texture GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid); - print_line("dyndata delete"); glDeleteTextures(1, &gi_probe_data->tex_id); gi_probe_owner.free(p_rid); memdelete(gi_probe_data); @@ -6333,9 +6330,8 @@ void RasterizerStorageGLES3::initialize() { { int max_extensions = 0; - print_line("getting extensions"); glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions); - print_line("total " + itos(max_extensions)); + print_line("GLES3: max extensions: " + itos(max_extensions)); for (int i = 0; i < max_extensions; i++) { const GLubyte *s = glGetStringi(GL_EXTENSIONS, i); if (!s) diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 6aeb3af2cd..89b056df84 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -410,7 +410,6 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener if (fnode->name == "vertex") { - print_line("vertex uses functions: " + itos(pnode->functions[i].uses_function.size())); _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx); r_gen_code.vertex = function_code["vertex"]; } diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 9aaf5c129b..45827ee4f7 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -102,7 +102,6 @@ float AudioDriverPulseAudio::get_latency() { void AudioDriverPulseAudio::thread_func(void *p_udata) { - print_line("thread"); AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata; while (!ad->exit_thread) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index cc7ee44902..04d369fed4 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -435,7 +435,7 @@ void EditorNode::_sources_changed(bool p_exist) { if (defer_load_scene != "") { - print_line("loading scene DEFERED"); + print_line("loading scene DEFERRED"); load_scene(defer_load_scene); defer_load_scene = ""; } @@ -6051,7 +6051,10 @@ EditorNode::EditorNode() { { _initializing_addons = true; - Vector<String> addons = GlobalConfig::get_singleton()->get("editor_plugins/enabled"); + Vector<String> addons; + if (GlobalConfig::get_singleton()->has("editor_plugins/enabled")) { + addons = GlobalConfig::get_singleton()->get("editor_plugins/enabled"); + } for (int i = 0; i < addons.size(); i++) { set_addon_plugin_enabled(addons[i], true); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 35373eb815..9beffa3c67 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -407,7 +407,7 @@ void EditorSettings::setup_network() { IP::get_singleton()->get_local_addresses(&local_ip); String lip; String hint; - String current = get("network/debug_host"); + String current = has("network/debug_host") ? get("network/debug_host") : ""; for (List<IP_Address>::Element *E = local_ip.front(); E; E = E->next()) { @@ -557,6 +557,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["text_editor/theme/font"] = PropertyInfo(Variant::STRING, "text_editor/theme/font", PROPERTY_HINT_GLOBAL_FILE, "*.fnt"); set("text_editor/completion/auto_brace_complete", false); set("text_editor/files/restore_scripts_on_load", true); + set("text_editor/completion/complete_file_paths", true); //set("docks/scene_tree/display_old_action_buttons",false); set("docks/scene_tree/start_create_dialog_fully_expanded", false); @@ -591,9 +592,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("editors/2d/bone_color2", Color(0.75, 0.75, 0.75, 0.9)); set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.9)); set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.9)); - set("editors/2d/keep_margins_when_changing_anchors", false); - set("editors/2d/warped_mouse_panning", true); set("run/window_placement/rect", 0); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 3bdc742354..1a4a36fa18 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1211,7 +1211,7 @@ ProjectManager::ProjectManager() { } } - FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesytem/file_dialog/show_hidden_files")); + FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); set_area_as_parent_rect(); set_theme(create_editor_theme()); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 7808cae0cd..15c540e132 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -55,6 +55,8 @@ bool ScriptCreateDialog::_validate(const String &p_string) { if (p_string.length() == 0) return false; + String path_chars = "\"res://"; + bool is_val_path = ScriptServer::get_language(language_menu->get_selected())->can_inherit_from_file(); for (int i = 0; i < p_string.length(); i++) { if (i == 0) { @@ -62,7 +64,17 @@ bool ScriptCreateDialog::_validate(const String &p_string) { return false; // no start with number plz } - bool valid_char = (p_string[i] >= '0' && p_string[i] <= '9') || (p_string[i] >= 'a' && p_string[i] <= 'z') || (p_string[i] >= 'A' && p_string[i] <= 'Z') || p_string[i] == '_'; + if (i == p_string.length() - 1 && is_val_path) + return p_string[i] == '\"'; + + if (is_val_path && i < path_chars.length()) { + if (p_string[i] != path_chars[i]) + is_val_path = false; + else + continue; + } + + bool valid_char = (p_string[i] >= '0' && p_string[i] <= '9') || (p_string[i] >= 'a' && p_string[i] <= 'z') || (p_string[i] >= 'A' && p_string[i] <= 'Z') || p_string[i] == '_' || (is_val_path && (p_string[i] == '/' || p_string[i] == '.')); if (!valid_char) return false; @@ -74,7 +86,7 @@ bool ScriptCreateDialog::_validate(const String &p_string) { void ScriptCreateDialog::_class_name_changed(const String &p_name) { if (!_validate(parent_name->get_text())) { - error_label->set_text(TTR("Invalid parent class name")); + error_label->set_text(TTR("Invalid parent class name or path")); error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); } else if (class_name->is_editable()) { if (class_name->get_text() == "") { @@ -175,6 +187,12 @@ void ScriptCreateDialog::_lang_changed(int l) { class_name->set_editable(false); } + if (ScriptServer::get_language(l)->can_inherit_from_file()) { + parent_browse_button->show(); + } else { + parent_browse_button->hide(); + } + String selected_ext = "." + ScriptServer::get_language(l)->get_extension(); String path = file_path->get_text(); String extension = ""; @@ -215,7 +233,9 @@ void ScriptCreateDialog::_built_in_pressed() { } } -void ScriptCreateDialog::_browse_path() { +void ScriptCreateDialog::_browse_path(bool browse_parent) { + + is_browsing_parent = browse_parent; file_browse->set_mode(EditorFileDialog::MODE_SAVE_FILE); file_browse->set_disable_overwrite_warning(true); @@ -238,8 +258,13 @@ void ScriptCreateDialog::_browse_path() { void ScriptCreateDialog::_file_selected(const String &p_file) { String p = GlobalConfig::get_singleton()->localize_path(p_file); - file_path->set_text(p); - _path_changed(p); + if (is_browsing_parent) { + parent_name->set_text("\"" + p + "\""); + _class_name_changed("\"" + p + "\""); + } else { + file_path->set_text(p); + _path_changed(p); + } } void ScriptCreateDialog::_path_changed(const String &p_path) { @@ -353,9 +378,18 @@ ScriptCreateDialog::ScriptCreateDialog() { vb2->add_child(error_label); vb->add_margin_child(TTR("Class Name:"), vb2); + HBoxContainer *hb1 = memnew(HBoxContainer); parent_name = memnew(LineEdit); - vb->add_margin_child(TTR("Inherits:"), parent_name); parent_name->connect("text_changed", this, "_class_name_changed"); + parent_name->set_h_size_flags(SIZE_EXPAND_FILL); + hb1->add_child(parent_name); + parent_browse_button = memnew(Button); + parent_browse_button->set_text(" .. "); + parent_browse_button->connect("pressed", this, "_browse_path", varray(true)); + hb1->add_child(parent_browse_button); + parent_browse_button->hide(); + vb->add_margin_child(TTR("Inherits:"), hb1); + is_browsing_parent = false; language_menu = memnew(OptionButton); vb->add_margin_child(TTR("Language"), language_menu); @@ -398,7 +432,7 @@ ScriptCreateDialog::ScriptCreateDialog() { file_path->set_h_size_flags(SIZE_EXPAND_FILL); Button *b = memnew(Button); b->set_text(" .. "); - b->connect("pressed", this, "_browse_path"); + b->connect("pressed", this, "_browse_path", varray(false)); hbc->add_child(b); path_vb->add_child(hbc); path_error_label = memnew(Label); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 499886facd..113d4a468c 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -44,6 +44,7 @@ class ScriptCreateDialog : public ConfirmationDialog { Label *error_label; Label *path_error_label; LineEdit *parent_name; + Button *parent_browse_button; OptionButton *language_menu; LineEdit *file_path; EditorFileDialog *file_browse; @@ -52,6 +53,7 @@ class ScriptCreateDialog : public ConfirmationDialog { AcceptDialog *alert; bool path_valid; bool create_new; + bool is_browsing_parent; String initial_bp; EditorSettings *editor_settings; @@ -60,7 +62,7 @@ class ScriptCreateDialog : public ConfirmationDialog { void _built_in_pressed(); bool _validate(const String &p_strin); void _class_name_changed(const String &p_name); - void _browse_path(); + void _browse_path(bool browse_parent); void _file_selected(const String &p_file); virtual void ok_pressed(); void _create_new(); diff --git a/main/main.cpp b/main/main.cpp index c294926045..377d15f5f4 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -697,7 +697,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph video_mode.width = globals->get("display/window/width"); if (!force_res && use_custom_res && globals->has("display/window/height")) video_mode.height = globals->get("display/window/height"); - if (!editor && (!bool(globals->get("display/window/allow_hidpi")) || force_lowdpi)) { + if (!editor && ((globals->has("display/window/allow_hidpi") && !globals->get("display/window/allow_hidpi")) || force_lowdpi)) { OS::get_singleton()->_allow_hidpi = false; } if (use_custom_res && globals->has("display/window/fullscreen")) diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp index cb75dcec13..95a1672e67 100644 --- a/main/tests/test_math.cpp +++ b/main/tests/test_math.cpp @@ -602,7 +602,7 @@ MainLoop *test() { print_line(q3); print_line("before v: " + v + " a: " + rtos(a)); - q.get_axis_and_angle(v, a); + q.get_axis_angle(v, a); print_line("after v: " + v + " a: " + rtos(a)); } diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index f80e6e501e..d79b7685d1 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -144,12 +144,14 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, f->get_32(); f->get_32(); - /*print_line("DDS width: "+itos(width)); + /* + print_line("DDS width: "+itos(width)); print_line("DDS height: "+itos(height)); - print_line("DDS mipmaps: "+itos(mipmaps));*/ + print_line("DDS mipmaps: "+itos(mipmaps)); - //printf("fourcc: %x fflags: %x, rgbbits: %x, fsize: %x\n",format_fourcc,format_flags,format_rgb_bits,format_size); - //printf("rmask: %x gmask: %x, bmask: %x, amask: %x\n",format_red_mask,format_green_mask,format_blue_mask,format_alpha_mask); + printf("fourcc: %x fflags: %x, rgbbits: %x, fsize: %x\n",format_fourcc,format_flags,format_rgb_bits,format_size); + printf("rmask: %x gmask: %x, bmask: %x, amask: %x\n",format_red_mask,format_green_mask,format_blue_mask,format_alpha_mask); + */ //must avoid this later while (f->get_pos() < 128) diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index c2f14f5466..2a3015c185 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -32,6 +32,10 @@ #include "gd_script.h" #include "global_config.h" #include "os/file_access.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_file_system.h" +#include "editor/editor_settings.h" +#endif void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { @@ -1406,6 +1410,17 @@ static void _make_function_hint(const GDParser::FunctionNode *p_func, int p_argi arghint += ")"; } +void get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) { + + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + get_directory_contents(p_dir->get_subdir(i), r_list); + } + + for (int i = 0; i < p_dir->get_file_count(); i++) { + r_list.insert("\"" + p_dir->get_file_path(i) + "\""); + } +} + static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, String &arghint) { //print_line("find type arguments?"); @@ -1754,6 +1769,10 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N const GDParser::BuiltInFunctionNode *fn = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]); MethodInfo mi = GDFunctions::get_info(fn->function); + if (mi.name == "load" && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { + get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), result); + } + arghint = _get_visual_datatype(mi.return_val, false) + " " + GDFunctions::get_func_name(fn->function) + String("("); for (int i = 0; i < mi.arguments.size(); i++) { if (i > 0) @@ -2375,6 +2394,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } } break; + case GDParser::COMPLETION_PRELOAD: { + + if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) + get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options); + } break; } for (Set<String>::Element *E = options.front(); E; E = E->next()) { diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index cd16fef6b3..b02d7f713b 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -387,6 +387,13 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool _set_error("Expected '(' after 'preload'"); return NULL; } + completion_cursor = StringName(); + completion_type = COMPLETION_PRELOAD; + completion_class = current_class; + completion_function = current_function; + completion_line = tokenizer->get_token_line(); + completion_block = current_block; + completion_found = true; tokenizer->advance(); String path; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 445ad7361c..4f3ca0dc5f 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -437,6 +437,7 @@ public: COMPLETION_PARENT_FUNCTION, COMPLETION_METHOD, COMPLETION_CALL_ARGUMENTS, + COMPLETION_PRELOAD, COMPLETION_INDEX, COMPLETION_VIRTUAL_FUNC, COMPLETION_YIELD, diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 2367f60740..fe20a842cf 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1696,9 +1696,9 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //same thing for placeholders #ifdef TOOLS_ENABLED - while (E->get()->placeholders.size()) { + for (Set<PlaceHolderScriptInstance *>::Element *P = E->get()->placeholders.front(); P; P = P->next()) { - Object *obj = E->get()->placeholders.front()->get()->get_owner(); + Object *obj = P->get()->get_owner(); //save instance info List<Pair<StringName, Variant> > state; if (obj->get_script_instance()) { diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index f92c11b9e0..00ae136790 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -384,6 +384,7 @@ public: virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; + virtual bool can_inherit_from_file() { return true; } virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint); diff --git a/modules/multiscript/SCsub b/modules/multiscript/SCsub new file mode 100644 index 0000000000..0882406761 --- /dev/null +++ b/modules/multiscript/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.modules_sources, "*.cpp") + +Export('env') diff --git a/modules/multiscript/config.py b/modules/multiscript/config.py new file mode 100644 index 0000000000..5698a37295 --- /dev/null +++ b/modules/multiscript/config.py @@ -0,0 +1,8 @@ + + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/multiscript/multiscript.cpp b/modules/multiscript/multiscript.cpp new file mode 100644 index 0000000000..b2633b7207 --- /dev/null +++ b/modules/multiscript/multiscript.cpp @@ -0,0 +1,750 @@ +/*************************************************************************/ +/* multiscript.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "multiscript.h" + +bool MultiScriptInstance::set(const StringName &p_name, const Variant &p_value) { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + bool found = sarr[i]->set(p_name, p_value); + if (found) + return true; + } + + if (String(p_name).begins_with("script_")) { + bool valid; + owner->set(p_name, p_value, &valid); + return valid; + } + return false; +} + +bool MultiScriptInstance::get(const StringName &p_name, Variant &r_ret) const { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + bool found = sarr[i]->get(p_name, r_ret); + if (found) + return true; + } + if (String(p_name).begins_with("script_")) { + bool valid; + r_ret = owner->get(p_name, &valid); + return valid; + } + return false; +} +void MultiScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + Set<String> existing; + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + List<PropertyInfo> pl; + sarr[i]->get_property_list(&pl); + + for (List<PropertyInfo>::Element *E = pl.front(); E; E = E->next()) { + + if (existing.has(E->get().name)) + continue; + + p_properties->push_back(E->get()); + existing.insert(E->get().name); + } + } + + p_properties->push_back(PropertyInfo(Variant::NIL, "Scripts", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); + + for (int i = 0; i < owner->scripts.size(); i++) { + + p_properties->push_back(PropertyInfo(Variant::OBJECT, "script_" + String::chr('a' + i), PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_EDITOR)); + } + + if (owner->scripts.size() < 25) { + + p_properties->push_back(PropertyInfo(Variant::OBJECT, "script_" + String::chr('a' + (owner->scripts.size())), PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_EDITOR)); + } +} + +void MultiScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + Set<StringName> existing; + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + List<MethodInfo> ml; + sarr[i]->get_method_list(&ml); + + for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) { + + if (existing.has(E->get().name)) + continue; + + p_list->push_back(E->get()); + existing.insert(E->get().name); + } + } +} +bool MultiScriptInstance::has_method(const StringName &p_method) const { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + if (sarr[i]->has_method(p_method)) + return true; + } + + return false; +} + +Variant MultiScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + Variant r = sarr[i]->call(p_method, p_args, p_argcount, r_error); + if (r_error.error == Variant::CallError::CALL_OK) + return r; + else if (r_error.error != Variant::CallError::CALL_ERROR_INVALID_METHOD) + return r; + } + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); +} + +void MultiScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + sarr[i]->call_multilevel(p_method, p_args, p_argcount); + } +} +void MultiScriptInstance::notification(int p_notification) { + + // ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + ScriptInstance *instance = instances[i]; + + if (!instance) + continue; + + instance->notification(p_notification); + } +} + +Ref<Script> MultiScriptInstance::get_script() const { + + return owner; +} + +ScriptLanguage *MultiScriptInstance::get_language() { + + return MultiScriptLanguage::get_singleton(); +} + +MultiScriptInstance::~MultiScriptInstance() { + + owner->remove_instance(object); +} + +Variant::Type MultiScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { + bool valid = false; + Variant::Type type; + + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + type = sarr[i]->get_property_type(p_name, &valid); + if (valid) { + *r_is_valid = valid; + return type; + } + } + *r_is_valid = false; + return Variant::NIL; +} + +ScriptInstance::RPCMode MultiScriptInstance::get_rpc_mode(const StringName &p_method) const { + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + if (sarr[i]->has_method(p_method)) + return sarr[i]->get_rpc_mode(p_method); + } + return RPC_MODE_DISABLED; +} + +ScriptInstance::RPCMode MultiScriptInstance::get_rset_mode(const StringName &p_variable) const { + ScriptInstance **sarr = instances.ptr(); + int sc = instances.size(); + + for (int i = 0; i < sc; i++) { + + if (!sarr[i]) + continue; + + List<PropertyInfo> properties; + sarr[i]->get_property_list(&properties); + + for (List<PropertyInfo>::Element *P = properties.front(); P; P = P->next()) { + if (P->get().name == p_variable) { + return sarr[i]->get_rset_mode(p_variable); + } + } + } + return RPC_MODE_DISABLED; +} + +/////////////////// + +bool MultiScript::is_tool() const { + + for (int i = 0; i < scripts.size(); i++) { + + if (scripts[i]->is_tool()) + return true; + } + + return false; +} + +bool MultiScript::_set(const StringName &p_name, const Variant &p_value) { + + _THREAD_SAFE_METHOD_ + + String s = String(p_name); + if (s.begins_with("script_")) { + + int idx = s[7]; + if (idx == 0) + return false; + idx -= 'a'; + + ERR_FAIL_COND_V(idx < 0, false); + + Ref<Script> s = p_value; + + if (idx < scripts.size()) { + + if (s.is_null()) + remove_script(idx); + else + set_script(idx, s); + } else if (idx == scripts.size()) { + if (s.is_null()) + return false; + add_script(s); + } else + return false; + + return true; + } + + return false; +} + +bool MultiScript::_get(const StringName &p_name, Variant &r_ret) const { + + _THREAD_SAFE_METHOD_ + + String s = String(p_name); + if (s.begins_with("script_")) { + + int idx = s[7]; + if (idx == 0) + return false; + idx -= 'a'; + + ERR_FAIL_COND_V(idx < 0, false); + + if (idx < scripts.size()) { + + r_ret = get_script(idx); + return true; + } else if (idx == scripts.size()) { + r_ret = Ref<Script>(); + return true; + } + } + + return false; +} +void MultiScript::_get_property_list(List<PropertyInfo> *p_list) const { + + _THREAD_SAFE_METHOD_ + + for (int i = 0; i < scripts.size(); i++) { + + p_list->push_back(PropertyInfo(Variant::OBJECT, "script_" + String::chr('a' + i), PROPERTY_HINT_RESOURCE_TYPE, "Script")); + } + + if (scripts.size() < 25) { + + p_list->push_back(PropertyInfo(Variant::OBJECT, "script_" + String::chr('a' + (scripts.size())), PROPERTY_HINT_RESOURCE_TYPE, "Script")); + } +} + +void MultiScript::set_script(int p_idx, const Ref<Script> &p_script) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_INDEX(p_idx, scripts.size()); + ERR_FAIL_COND(p_script.is_null()); + + scripts[p_idx] = p_script; + Ref<Script> s = p_script; + + for (Map<Object *, MultiScriptInstance *>::Element *E = instances.front(); E; E = E->next()) { + + MultiScriptInstance *msi = E->get(); + ScriptInstance *si = msi->instances[p_idx]; + if (si) { + msi->instances[p_idx] = NULL; + memdelete(si); + } + + if (p_script->can_instance()) + msi->instances[p_idx] = s->instance_create(msi->object); + } +} + +Ref<Script> MultiScript::get_script(int p_idx) const { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_INDEX_V(p_idx, scripts.size(), Ref<Script>()); + + return scripts[p_idx]; +} +void MultiScript::add_script(const Ref<Script> &p_script) { + + _THREAD_SAFE_METHOD_ + ERR_FAIL_COND(p_script.is_null()); + Multi *script_owner = memnew(Multi); + script_instances.push_back(script_owner); + scripts.push_back(p_script); + Ref<Script> s = p_script; + + for (Map<Object *, MultiScriptInstance *>::Element *E = instances.front(); E; E = E->next()) { + + MultiScriptInstance *msi = E->get(); + + if (p_script->can_instance()) { + script_owner->real_owner = msi->object; + msi->instances.push_back(s->instance_create(script_owner)); + } else { + msi->instances.push_back(NULL); + } + + msi->object->_change_notify(); + } + + _change_notify(); +} + +void MultiScript::remove_script(int p_idx) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_INDEX(p_idx, scripts.size()); + + scripts.remove(p_idx); + script_instances.remove(p_idx); + + for (Map<Object *, MultiScriptInstance *>::Element *E = instances.front(); E; E = E->next()) { + + MultiScriptInstance *msi = E->get(); + ScriptInstance *si = msi->instances[p_idx]; + msi->instances.remove(p_idx); + if (si) { + memdelete(si); + } + + msi->object->_change_notify(); + } +} + +void MultiScript::remove_instance(Object *p_object) { + + _THREAD_SAFE_METHOD_ + instances.erase(p_object); +} + +bool MultiScript::can_instance() const { + + return true; +} + +StringName MultiScript::get_instance_base_type() const { + + return StringName(); +} +ScriptInstance *MultiScript::instance_create(Object *p_this) { + + _THREAD_SAFE_METHOD_ + MultiScriptInstance *msi = memnew(MultiScriptInstance); + msi->object = p_this; + msi->owner = this; + + for (int i = 0; i < scripts.size(); i++) { + + ScriptInstance *si; + + if (scripts[i]->can_instance()) { + script_instances[i]->real_owner = p_this; + si = scripts[i]->instance_create(script_instances[i]); + } else { + si = NULL; + } + + msi->instances.push_back(si); + } + + instances[p_this] = msi; + p_this->_change_notify(); + return msi; +} +bool MultiScript::instance_has(const Object *p_this) const { + + _THREAD_SAFE_METHOD_ + return instances.has((Object *)p_this); +} + +bool MultiScript::has_source_code() const { + + return false; +} +String MultiScript::get_source_code() const { + + return ""; +} +void MultiScript::set_source_code(const String &p_code) { +} +Error MultiScript::reload(bool p_keep_state) { + + for (int i = 0; i < scripts.size(); i++) + scripts[i]->reload(p_keep_state); + + return OK; +} + +String MultiScript::get_node_type() const { + + return ""; +} + +void MultiScript::_bind_methods() { +} + +ScriptLanguage *MultiScript::get_language() const { + + return MultiScriptLanguage::get_singleton(); +} + +/////////////// + +MultiScript::MultiScript() { +} + +MultiScript::~MultiScript() { + for (int i = 0; i < script_instances.size(); i++) { + memdelete(script_instances[i]); + } + + script_instances.resize(0); +} + +Ref<Script> MultiScript::get_base_script() const { + Ref<MultiScript> base_script; + return base_script; +} + +bool MultiScript::has_method(const StringName &p_method) const { + for (int i = 0; i < scripts.size(); i++) { + if (scripts[i]->has_method(p_method)) { + return true; + } + } + return false; +} + +MethodInfo MultiScript::get_method_info(const StringName &p_method) const { + for (int i = 0; i < scripts.size(); i++) { + if (scripts[i]->has_method(p_method)) { + return scripts[i]->get_method_info(p_method); + } + } + return MethodInfo(); +} + +bool MultiScript::has_script_signal(const StringName &p_signal) const { + for (int i = 0; i < scripts.size(); i++) { + if (scripts[i]->has_script_signal(p_signal)) { + return true; + } + } + return false; +} + +void MultiScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + for (int i = 0; i < scripts.size(); i++) { + scripts[i]->get_script_signal_list(r_signals); + } +} + +bool MultiScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { + for (int i = 0; i < scripts.size(); i++) { + + if (scripts[i]->get_property_default_value(p_property, r_value)) { + return true; + } + } + return false; +} + +void MultiScript::get_script_method_list(List<MethodInfo> *p_list) const { + for (int i = 0; i < scripts.size(); i++) { + scripts[i]->get_script_method_list(p_list); + } +} + +void MultiScript::get_script_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < scripts.size(); i++) { + scripts[i]->get_script_property_list(p_list); + } +} + +void MultiScript::update_exports() { + for (int i = 0; i < scripts.size(); i++) { + scripts[i]->update_exports(); + } +} + +MultiScriptLanguage *MultiScriptLanguage::singleton = NULL; + +MultiScriptLanguage *MultiScriptLanguage::get_singleton() { + return singleton; +} + +String MultiScriptLanguage::get_name() const { + return "MultiScript"; +} + +void MultiScriptLanguage::init() {} + +String MultiScriptLanguage::get_type() const { + return "MultiScript"; +} + +String MultiScriptLanguage::get_extension() const { + return ""; +} + +Error MultiScriptLanguage::execute_file(const String &p_path) { + return OK; +} + +void MultiScriptLanguage::finish() {} + +void MultiScriptLanguage::get_reserved_words(List<String> *p_words) const {} + +void MultiScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {} + +void MultiScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {} + +Ref<Script> MultiScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { + MultiScript *s = memnew(MultiScript); + s->base_class_name = p_base_class_name; + return Ref<MultiScript>(s); +} + +bool MultiScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_fn) const { + return true; +} + +Script *MultiScriptLanguage::create_script() const { + return memnew(MultiScript); +} + +bool MultiScriptLanguage::has_named_classes() const { + return false; +} + +int MultiScriptLanguage::find_function(const String &p_function, const String &p_code) const { + return -1; +} + +String MultiScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { + return ""; +} + +String MultiScriptLanguage::debug_get_error() const { + return ""; +} + +int MultiScriptLanguage::debug_get_stack_level_count() const { + return 0; +} + +int MultiScriptLanguage::debug_get_stack_level_line(int p_level) const { + return 0; +} + +String MultiScriptLanguage::debug_get_stack_level_function(int p_level) const { + return ""; +} + +String MultiScriptLanguage::debug_get_stack_level_source(int p_level) const { + return ""; +} + +void MultiScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} + +void MultiScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} + +void MultiScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} + +String MultiScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { + return ""; +} + +void MultiScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {} + +void MultiScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {} + +MultiScriptLanguage::MultiScriptLanguage() { + singleton = this; +} + +MultiScriptLanguage::~MultiScriptLanguage() {} + +void MultiScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { +} + +void MultiScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { +} + +void MultiScriptLanguage::reload_all_scripts() { +} + +void MultiScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { +} + +void MultiScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { +} + +void MultiScriptLanguage::profiling_start() { +} + +void MultiScriptLanguage::profiling_stop() { +} + +int MultiScriptLanguage::profiling_get_accumulated_data(ScriptLanguage::ProfilingInfo *p_info_arr, int p_info_max) { + return 0; +} + +int MultiScriptLanguage::profiling_get_frame_data(ScriptLanguage::ProfilingInfo *p_info_arr, int p_info_max) { + return 0; +} + +void Multi::_bind_methods() { + // ClassDB::bind_method("call", &Multi::call); + // ClassDB::bind_method("call_multilevel", &Multi::call_multilevel); + // ClassDB::bind_method("call_multilevel_reversed", &Multi::call_multilevel_reversed); +} + +Variant Multi::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + if (real_owner) + return real_owner->call(p_method, p_args, p_argcount, r_error); + return Variant(); +} + +void Multi::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { + if (real_owner) + real_owner->call_multilevel(p_method, p_args, p_argcount); +} + +void Multi::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { + if (real_owner) + real_owner->call_multilevel_reversed(p_method, p_args, p_argcount); +} diff --git a/modules/multiscript/multiscript.h b/modules/multiscript/multiscript.h new file mode 100644 index 0000000000..7ec1d5402f --- /dev/null +++ b/modules/multiscript/multiscript.h @@ -0,0 +1,200 @@ +/*************************************************************************/ +/* multiscript.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef MULTISCRIPT_H +#define MULTISCRIPT_H + +#include "os/thread_safe.h" +#include "script_language.h" + +class MultiScript; + +class Multi : public Object { + GDCLASS(Multi, Object) + + friend class MultiScript; + + Object *real_owner; + +public: + static void _bind_methods(); + + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); + virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); + virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); +}; + +class MultiScriptInstance : public ScriptInstance { + friend class MultiScript; + mutable Vector<ScriptInstance *> instances; + Object *object; + mutable MultiScript *owner; + +public: + virtual bool set(const StringName &p_name, const Variant &p_value); + virtual bool get(const StringName &p_name, Variant &r_ret) const; + virtual void get_property_list(List<PropertyInfo> *p_properties) const; + + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName &p_method) const; + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); + virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); + virtual void notification(int p_notification); + + virtual Ref<Script> get_script() const; + + virtual ScriptLanguage *get_language(); + virtual ~MultiScriptInstance(); + + // ScriptInstance interface +public: + Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const; + RPCMode get_rpc_mode(const StringName &p_method) const; + RPCMode get_rset_mode(const StringName &p_variable) const; +}; + +class MultiScript : public Script { + + _THREAD_SAFE_CLASS_ + friend class MultiScriptInstance; + friend class MultiScriptLanguage; + GDCLASS(MultiScript, Script) + + StringName base_class_name; + + Vector<Ref<Script> > scripts; + Vector<Multi *> script_instances; + + Map<Object *, MultiScriptInstance *> instances; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + void remove_instance(Object *p_object); + virtual bool can_instance() const; + + virtual StringName get_instance_base_type() const; + virtual ScriptInstance *instance_create(Object *p_this); + virtual bool instance_has(const Object *p_this) const; + + virtual bool has_source_code() const; + virtual String get_source_code() const; + virtual void set_source_code(const String &p_code); + virtual Error reload(bool p_keep_state = false); + + virtual bool is_tool() const; + + virtual String get_node_type() const; + + void set_script(int p_idx, const Ref<Script> &p_script); + Ref<Script> get_script(int p_idx) const; + void remove_script(int p_idx); + void add_script(const Ref<Script> &p_script); + + virtual ScriptLanguage *get_language() const; + + MultiScript(); + ~MultiScript(); + + virtual Ref<Script> get_base_script() const; + virtual bool has_method(const StringName &p_method) const; + virtual MethodInfo get_method_info(const StringName &p_method) const; + virtual bool has_script_signal(const StringName &p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + virtual void get_script_method_list(List<MethodInfo> *p_list) const; + virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + virtual void update_exports(); +}; + +class MultiScriptLanguage : public ScriptLanguage { + + static MultiScriptLanguage *singleton; + +public: + static _FORCE_INLINE_ MultiScriptLanguage *get_singleton(); + virtual String get_name() const; + + /* LANGUAGE FUNCTIONS */ + virtual void init(); + virtual String get_type() const; + virtual String get_extension() const; + virtual Error execute_file(const String &p_path); + virtual void finish(); + + /* EDITOR FUNCTIONS */ + virtual void get_reserved_words(List<String> *p_words) const; + virtual void get_comment_delimiters(List<String> *p_delimiters) const; + virtual void get_string_delimiters(List<String> *p_delimiters) const; + virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_fn = NULL) const; + virtual Script *create_script() const; + virtual bool has_named_classes() const; + virtual int find_function(const String &p_function, const String &p_code) const; + virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; + + /* DEBUGGER FUNCTIONS */ + + virtual String debug_get_error() const; + virtual int debug_get_stack_level_count() const; + virtual int debug_get_stack_level_line(int p_level) const; + virtual String debug_get_stack_level_function(int p_level) const; + virtual String debug_get_stack_level_source(int p_level) const; + virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); + + /* LOADER FUNCTIONS */ + + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual void get_public_functions(List<MethodInfo> *p_functions) const; + + MultiScriptLanguage(); + virtual ~MultiScriptLanguage(); + + // ScriptLanguage interface +public: + void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; + void add_global_constant(const StringName &p_variable, const Variant &p_value); + void reload_all_scripts(); + void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); + void get_public_constants(List<Pair<String, Variant> > *p_constants) const; + void profiling_start(); + void profiling_stop(); + int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); + int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); +}; + +#endif // MULTISCRIPT_H diff --git a/modules/multiscript/register_types.cpp b/modules/multiscript/register_types.cpp new file mode 100644 index 0000000000..8170a2d9c1 --- /dev/null +++ b/modules/multiscript/register_types.cpp @@ -0,0 +1,51 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "multiscript.h" + +#include "core/script_language.h" + +static MultiScriptLanguage *script_multi_script = NULL; + +void register_multiscript_types() { + script_multi_script = memnew(MultiScriptLanguage); + ScriptServer::register_language(script_multi_script); + ClassDB::register_class<MultiScript>(); + + // ClassDB::register_class<Multi>(); +} + +void unregister_multiscript_types() { + if (script_multi_script) { + ScriptServer::unregister_language(script_multi_script); + memdelete(script_multi_script); + } +} diff --git a/modules/multiscript/register_types.h b/modules/multiscript/register_types.h new file mode 100644 index 0000000000..b18d1adff2 --- /dev/null +++ b/modules/multiscript/register_types.h @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_multiscript_types(); +void unregister_multiscript_types(); diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 39c8f812ac..889eac71a7 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -87,9 +87,11 @@ static Image _webp_lossy_unpack(const PoolVector<uint8_t> &p_buffer) { ERR_FAIL_V(Image()); } - //print_line("width: "+itos(features.width)); - //print_line("height: "+itos(features.height)); - //print_line("alpha: "+itos(features.has_alpha)); + /* + print_line("width: "+itos(features.width)); + print_line("height: "+itos(features.height)); + print_line("alpha: "+itos(features.has_alpha)); + */ PoolVector<uint8_t> dst_image; int datasize = features.width * features.height * (features.has_alpha ? 4 : 3); @@ -130,9 +132,11 @@ Error ImageLoaderWEBP::load_image(Image *p_image, FileAccess *f) { ERR_FAIL_V(ERR_FILE_CORRUPT); } + /* print_line("width: " + itos(features.width)); print_line("height: " + itos(features.height)); print_line("alpha: " + itos(features.has_alpha)); + */ src_w = PoolVector<uint8_t>::Write(); diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp index 432aecb72e..ddf17481b1 100644 --- a/platform/x11/context_gl_x11.cpp +++ b/platform/x11/context_gl_x11.cpp @@ -152,8 +152,6 @@ Error ContextGL_X11::initialize() { XSync(x11_display, False); XSetErrorHandler(oldHandler); - print_line("ALL IS GOOD"); - glXMakeCurrent(x11_display, x11_window, p->glx_context); /* diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index f752cbf6b6..626ea10515 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1199,7 +1199,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const revert_motion(); return Vector2(); } - } else if (get_collision_normal().dot(-p_floor_direction) <= Math::cos(p_floor_max_angle)) { //ceiling + } else if (get_collision_normal().dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling move_and_slide_on_ceiling = true; } else { move_and_slide_on_wall = true; diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 94f34d6fb3..98babedf0d 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "physics_body.h" +#include "method_bind_ext.inc" #include "scene/scene_string_names.h" void PhysicsBody::_notification(int p_what) { @@ -907,6 +908,19 @@ bool KinematicBody::_ignores_mode(PhysicsServer::BodyMode p_mode) const { return true; } +void KinematicBody::revert_motion() { + + Transform gt = get_global_transform(); + gt.origin -= travel; //I do hope this is correct. + travel = Vector3(); + set_global_transform(gt); +} + +Vector3 KinematicBody::get_travel() const { + + return travel; +} + Vector3 KinematicBody::move(const Vector3 &p_motion) { //give me back regular physics engine logic @@ -1097,10 +1111,111 @@ Vector3 KinematicBody::move(const Vector3 &p_motion) { Transform gt = get_global_transform(); gt.origin += motion; set_global_transform(gt); + travel = motion; return p_motion - motion; } +Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, const Vector3 &p_ceil_direction, float p_slope_stop_min_velocity, int p_max_bounces, float p_floor_max_angle, float p_ceil_max_angle) { + + /* + Things to note: + 1. This function is basically the KinematicBody2D function ported over. + 2. The 'travel' variable and stuff relating to it exists more or less for this function's sake. + 3. Someone is going to have to document this, so here's an example for them: + vel = move_and_slide(vel, Vector3(0, 1, 0), Vector3(0, -1, 0), 0.1); + Very useful for FPS controllers so long as you control horizontal motion properly - even for Quake-style AABB colliders. + The slope stop system is... rather weird, and it's correct operation depends on what scale your game is built on, + but as far as I can tell in theory it's suppposed to be a way of turning impassable slopes into invisible walls. + It can also be a pain, since there's a better-known way of defining such things: "let gravity do the work". + If you don't like it, set it to positive infinity. + 4. Might be a bug somewhere else in physics: When there are two CollisionShape nodes with a shared Shape, only one is considered, I think. + Test this further. + */ + + Vector3 motion = (move_and_slide_floor_velocity + p_linear_velocity) * get_fixed_process_delta_time(); + Vector3 lv = p_linear_velocity; + + move_and_slide_on_floor = false; + move_and_slide_on_ceiling = false; + move_and_slide_on_wall = false; + move_and_slide_colliders.clear(); + move_and_slide_floor_velocity = Vector3(); + + while (p_max_bounces) { + + motion = move(motion); + + if (is_colliding()) { + + bool hit_horizontal = false; //hit floor or ceiling + + if (p_floor_direction != Vector3()) { + if (get_collision_normal().dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor + + hit_horizontal = true; + move_and_slide_on_floor = true; + move_and_slide_floor_velocity = get_collider_velocity(); + + //Note: These two lines are the only lines that really changed between 3D/2D, see if it can't be reused somehow??? + Vector2 hz_velocity = Vector2(lv.x - move_and_slide_floor_velocity.x, lv.z - move_and_slide_floor_velocity.z); + if (get_travel().length() < 1 && hz_velocity.length() < p_slope_stop_min_velocity) { + revert_motion(); + return Vector3(); + } + } + } + + if (p_ceil_direction != Vector3()) { + if (get_collision_normal().dot(p_ceil_direction) >= Math::cos(p_ceil_max_angle)) { //ceiling + hit_horizontal = true; + move_and_slide_on_ceiling = true; + } + } + + //if it hit something but didn't hit a floor or ceiling, it is by default a wall + //(this imitates the pre-specifiable-ceiling logic more or less, except ceiling is optional) + if (!hit_horizontal) { + move_and_slide_on_wall = true; + } + + Vector3 n = get_collision_normal(); + motion = motion.slide(n); + lv = lv.slide(n); + Variant collider = _get_collider(); + if (collider.get_type() != Variant::NIL) { + move_and_slide_colliders.push_back(collider); + } + + } else { + break; + } + + p_max_bounces--; + if (motion == Vector3()) + break; + } + + return lv; +} + +bool KinematicBody::is_move_and_slide_on_floor() const { + + return move_and_slide_on_floor; +} +bool KinematicBody::is_move_and_slide_on_wall() const { + + return move_and_slide_on_wall; +} +bool KinematicBody::is_move_and_slide_on_ceiling() const { + + return move_and_slide_on_ceiling; +} +Array KinematicBody::get_move_and_slide_colliders() const { + + return move_and_slide_colliders; +} + Vector3 KinematicBody::move_to(const Vector3 &p_position) { return move(p_position - get_global_transform().origin); @@ -1223,6 +1338,7 @@ void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody::move); ClassDB::bind_method(D_METHOD("move_to", "position"), &KinematicBody::move_to); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "ceil_normal", "slope_stop_min_velocity", "max_bounces", "floor_max_angle", "ceil_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(Vector3(0, 0, 0)), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(Math::deg2rad((float)45))); ClassDB::bind_method(D_METHOD("can_teleport_to", "position"), &KinematicBody::can_teleport_to); @@ -1249,6 +1365,14 @@ void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_margin", "pixels"), &KinematicBody::set_collision_margin); ClassDB::bind_method(D_METHOD("get_collision_margin", "pixels"), &KinematicBody::get_collision_margin); + ClassDB::bind_method(D_METHOD("get_travel"), &KinematicBody::get_travel); + ClassDB::bind_method(D_METHOD("revert_motion"), &KinematicBody::revert_motion); + + ClassDB::bind_method(D_METHOD("get_move_and_slide_colliders"), &KinematicBody::get_move_and_slide_colliders); + ClassDB::bind_method(D_METHOD("is_move_and_slide_on_floor"), &KinematicBody::is_move_and_slide_on_floor); + ClassDB::bind_method(D_METHOD("is_move_and_slide_on_ceiling"), &KinematicBody::is_move_and_slide_on_ceiling); + ClassDB::bind_method(D_METHOD("is_move_and_slide_on_wall"), &KinematicBody::is_move_and_slide_on_wall); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with/static"), "set_collide_with_static_bodies", "can_collide_with_static_bodies"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with/kinematic"), "set_collide_with_kinematic_bodies", "can_collide_with_kinematic_bodies"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with/rigid"), "set_collide_with_rigid_bodies", "can_collide_with_rigid_bodies"); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index c62f6be13f..d13f84dc15 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -275,6 +275,13 @@ class KinematicBody : public PhysicsBody { Vector3 collider_vel; ObjectID collider; int collider_shape; + Vector3 travel; + + Vector3 move_and_slide_floor_velocity; + bool move_and_slide_on_floor; + bool move_and_slide_on_ceiling; + bool move_and_slide_on_wall; + Array move_and_slide_colliders; Variant _get_collider() const; @@ -295,6 +302,10 @@ public: bool can_teleport_to(const Vector3 &p_position); bool is_colliding() const; + + Vector3 get_travel() const; // Set by move and others. Consider unreliable except immediately after a move call. + void revert_motion(); + Vector3 get_collision_pos() const; Vector3 get_collision_normal() const; Vector3 get_collider_velocity() const; @@ -316,6 +327,12 @@ public: void set_collision_margin(float p_margin); float get_collision_margin() const; + Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), const Vector3 &p_ceil_direction = Vector3(0, 0, 0), float p_slope_stop_min_velocity = 5, int p_max_bounces = 4, float p_floor_max_angle = Math::deg2rad((float)45), float p_ceil_max_angle = Math::deg2rad((float)45)); + bool is_move_and_slide_on_floor() const; + bool is_move_and_slide_on_wall() const; + bool is_move_and_slide_on_ceiling() const; + Array get_move_and_slide_colliders() const; + KinematicBody(); ~KinematicBody(); }; diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index f984d8f06d..d3b4577c42 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -30,12 +30,15 @@ #include "ray_cast.h" #include "collision_object.h" +#include "mesh_instance.h" #include "servers/physics_server.h" void RayCast::set_cast_to(const Vector3 &p_point) { cast_to = p_point; if (is_inside_tree() && (get_tree()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) update_gizmo(); + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) + _update_debug_shape(); } Vector3 RayCast::get_cast_to() const { @@ -95,6 +98,13 @@ void RayCast::set_enabled(bool p_enabled) { set_fixed_process(p_enabled); if (!p_enabled) collided = false; + + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) { + if (p_enabled) + _update_debug_shape(); + else + _clear_debug_shape(); + } } bool RayCast::is_enabled() const { @@ -110,6 +120,9 @@ void RayCast::_notification(int p_what) { if (enabled && !get_tree()->is_editor_hint()) { set_fixed_process(true); + + if (get_tree()->is_debugging_collisions_hint()) + _update_debug_shape(); } else set_fixed_process(false); @@ -120,13 +133,23 @@ void RayCast::_notification(int p_what) { set_fixed_process(false); } + if (debug_shape) + _clear_debug_shape(); + } break; case NOTIFICATION_FIXED_PROCESS: { if (!enabled) break; + bool prev_collision_state = collided; _update_raycast_state(); + if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) { + if (debug_material.is_valid()) { + Ref<FixedSpatialMaterial> line_material = static_cast<Ref<FixedSpatialMaterial> >(debug_material); + line_material->set_albedo(collided ? Color(1.0, 0, 0) : Color(1.0, 0.8, 0.6)); + } + } } break; } @@ -232,6 +255,68 @@ void RayCast::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "type_mask", PROPERTY_HINT_FLAGS, "Static,Kinematic,Rigid,Character,Area"), "set_type_mask", "get_type_mask"); } +void RayCast::_create_debug_shape() { + + if (!debug_material.is_valid()) { + debug_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial)); + + Ref<FixedSpatialMaterial> line_material = static_cast<Ref<FixedSpatialMaterial> >(debug_material); + line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_albedo(Color(1.0, 0.8, 0.6)); + } + + Ref<Mesh> mesh = memnew(Mesh); + + MeshInstance *mi = memnew(MeshInstance); + mi->set_mesh(mesh); + + add_child(mi); + debug_shape = mi; +} + +void RayCast::_update_debug_shape() { + + if (!enabled) + return; + + if (!debug_shape) + _create_debug_shape(); + + MeshInstance *mi = static_cast<MeshInstance *>(debug_shape); + if (!mi->get_mesh().is_valid()) + return; + + Ref<Mesh> mesh = mi->get_mesh(); + if (mesh->get_surface_count() > 0) + mesh->surface_remove(0); + + Array a; + a.resize(Mesh::ARRAY_MAX); + + Vector<Vector3> verts; + verts.push_back(Vector3()); + verts.push_back(cast_to); + a[Mesh::ARRAY_VERTEX] = verts; + + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a); + mesh->surface_set_material(0, debug_material); +} + +void RayCast::_clear_debug_shape() { + + if (!debug_shape) + return; + + MeshInstance *mi = static_cast<MeshInstance *>(debug_shape); + if (mi->is_inside_tree()) + mi->queue_delete(); + else + memdelete(mi); + + debug_shape = NULL; +} + RayCast::RayCast() { enabled = false; @@ -241,4 +326,5 @@ RayCast::RayCast() { layer_mask = 1; type_mask = PhysicsDirectSpaceState::TYPE_MASK_COLLISION; cast_to = Vector3(0, -1, 0); + debug_shape = NULL; } diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 7ab7b57db3..63a53d724f 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -50,6 +50,13 @@ class RayCast : public Spatial { uint32_t layer_mask; uint32_t type_mask; + Node *debug_shape; + Ref<Material> debug_material; + + void _create_debug_shape(); + void _update_debug_shape(); + void _clear_debug_shape(); + protected: void _notification(int p_what); void _update_raycast_state(); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ee4f8736d7..839dcc3678 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -38,6 +38,8 @@ void BaseButton::_unpress_group() { if (!button_group.is_valid()) return; + status.pressed = true; + for (Set<BaseButton *>::Element *E = button_group->buttons.front(); E; E = E->next()) { if (E->get() == this) continue; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index cebec379e6..545c700354 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1761,8 +1761,8 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons Vector3 v02, v01; real_t a02, a01; - r02.get_axis_and_angle(v02, a02); - r01.get_axis_and_angle(v01, a01); + r02.get_axis_angle(v02, a02); + r01.get_axis_angle(v01, a01); if (Math::abs(a02) > p_max_optimizable_angle) return false; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 0889306bad..f0ac30a76e 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -459,25 +459,27 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla flags = f->get_32(); //texture flags! uint32_t df = f->get_32(); //data format + /* print_line("width: " + itos(tw)); print_line("height: " + itos(th)); print_line("flags: " + itos(flags)); print_line("df: " + itos(df)); + */ if (request_3d_callback && df & FORMAT_BIT_DETECT_3D) { - print_line("request detect 3D at " + p_path); + //print_line("request detect 3D at " + p_path); VS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this); } else { - print_line("not requesting detect 3D at " + p_path); + //print_line("not requesting detect 3D at " + p_path); VS::get_singleton()->texture_set_detect_3d_callback(texture, NULL, NULL); } if (request_srgb_callback && df & FORMAT_BIT_DETECT_SRGB) { - print_line("request detect srgb at " + p_path); + //print_line("request detect srgb at " + p_path); VS::get_singleton()->texture_set_detect_srgb_callback(texture, _requested_srgb, this); } else { + //print_line("not requesting detect srgb at " + p_path); VS::get_singleton()->texture_set_detect_srgb_callback(texture, NULL, NULL); - print_line("not requesting detect srgb at " + p_path); } if (!(df & FORMAT_BIT_STREAM)) { @@ -493,7 +495,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla uint32_t mipmaps = f->get_32(); uint32_t size = f->get_32(); - print_line("mipmaps: " + itos(mipmaps)); + //print_line("mipmaps: " + itos(mipmaps)); while (mipmaps > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) { @@ -539,7 +541,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla mipmap_images.push_back(img); } - print_line("mipmap read total: " + itos(mipmap_images.size())); + //print_line("mipmap read total: " + itos(mipmap_images.size())); memdelete(f); //no longer needed @@ -626,7 +628,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla { PoolVector<uint8_t>::Write w = img_data.write(); int bytes = f->get_buffer(w.ptr(), total_size - ofs); - print_line("requested read: " + itos(total_size - ofs) + " but got: " + itos(bytes)); + //print_line("requested read: " + itos(total_size - ofs) + " but got: " + itos(bytes)); memdelete(f); diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 9def425f28..715f93c1c1 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -495,7 +495,7 @@ void BodySW::integrate_forces(real_t p_step) { Vector3 axis; real_t angle; - rot.get_axis_and_angle(axis, angle); + rot.get_axis_angle(axis, angle); axis.normalize(); angular_velocity = axis.normalized() * (angle / p_step); @@ -638,7 +638,7 @@ void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) { Vector3 axis; real_t angle; - rot.get_axis_and_angle(axis,angle); + rot.get_axis_angle(axis,angle); axis.normalize(); angular_velocity=axis.normalized() * (angle/p_step); linear_velocity = (p_xform.origin - get_transform().origin)/p_step; |