diff options
Diffstat (limited to 'core/math')
36 files changed, 442 insertions, 187 deletions
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index a0556ae839..e1388ad2ac 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -55,6 +55,7 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { pt->weight_scale = p_weight_scale; pt->prev_point = NULL; pt->last_pass = 0; + pt->enabled = true; points[p_id] = pt; } else { points[p_id]->pos = p_pos; @@ -97,11 +98,14 @@ void AStar::remove_point(int p_id) { Point *p = points[p_id]; - for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) { - - Segment s(p_id, E->get()->id); - segments.erase(s); - E->get()->neighbours.erase(p); + Map<int, Point *>::Element *PE = points.front(); + while (PE) { + for (Set<Point *>::Element *E = PE->get()->neighbours.front(); E; E = E->next()) { + Segment s(p_id, E->get()->id); + segments.erase(s); + E->get()->neighbours.erase(p); + } + PE = PE->next(); } memdelete(p); @@ -239,6 +243,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { pass++; + if (!end_point->enabled) + return false; + SelfList<Point>::List open_list; bool found_route = false; @@ -246,6 +253,10 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) { Point *n = E->get(); + + if (!n->enabled) + continue; + n->prev_point = begin_point; n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale; n->last_pass = pass; @@ -260,8 +271,8 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { } // Check open list - SelfList<Point> *least_cost_point = NULL; - real_t least_cost = 1e30; + SelfList<Point> *least_cost_point = open_list.first(); + real_t least_cost = Math_INF; // TODO: Cache previous results for (SelfList<Point> *E = open_list.first(); E; E = E->next()) { @@ -287,6 +298,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { Point *e = E->get(); + if (!e->enabled) + continue; + real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance; if (e->last_pass == pass) { @@ -371,14 +385,14 @@ PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) { { PoolVector<Vector3>::Write w = path.write(); - Point *p = end_point; + Point *p2 = end_point; int idx = pc - 1; - while (p != begin_point) { - w[idx--] = p->pos; - p = p->prev_point; + while (p2 != begin_point) { + w[idx--] = p2->pos; + p2 = p2->prev_point; } - w[0] = p->pos; // Assign first + w[0] = p2->pos; // Assign first } return path; @@ -435,6 +449,14 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) { return path; } +void AStar::set_point_disabled(int p_id, bool p_disabled) { + points[p_id]->enabled = !p_disabled; +} + +bool AStar::is_point_disabled(int p_id) const { + return !points[p_id]->enabled; +} + void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("get_available_point_id"), &AStar::get_available_point_id); @@ -447,6 +469,9 @@ void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point); ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points); + ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar::set_point_disabled, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar::is_point_disabled); + ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections); ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true)); diff --git a/core/math/a_star.h b/core/math/a_star.h index d094bc4863..c63e1aa4dc 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -54,6 +54,7 @@ class AStar : public Reference { Vector3 pos; real_t weight_scale; uint64_t last_pass; + bool enabled; Set<Point *> neighbours; @@ -114,6 +115,9 @@ public: PoolVector<int> get_point_connections(int p_id); Array get_points(); + void set_point_disabled(int p_id, bool p_disabled = true); + bool is_point_disabled(int p_id) const; + void connect_points(int p_id, int p_with_id, bool bidirectional = true); void disconnect_points(int p_id, int p_with_id); bool are_points_connected(int p_id, int p_with_id) const; diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h index f970c510e0..98e4e33021 100644 --- a/core/math/audio_frame.h +++ b/core/math/audio_frame.h @@ -31,6 +31,7 @@ #ifndef AUDIOFRAME_H #define AUDIOFRAME_H +#include "core/math/vector2.h" #include "core/typedefs.h" static inline float undenormalise(volatile float f) { @@ -122,6 +123,20 @@ struct AudioFrame { r = p_frame.r; } + _ALWAYS_INLINE_ AudioFrame operator=(const AudioFrame &p_frame) { + l = p_frame.l; + r = p_frame.r; + return *this; + } + + _ALWAYS_INLINE_ operator Vector2() const { + return Vector2(l, r); + } + + _ALWAYS_INLINE_ AudioFrame(const Vector2 &p_v2) { + l = p_v2.x; + r = p_v2.y; + } _ALWAYS_INLINE_ AudioFrame() {} }; diff --git a/core/math/matrix3.cpp b/core/math/basis.cpp index 0aa67078fb..9fcecd1ba6 100644 --- a/core/math/matrix3.cpp +++ b/core/math/basis.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* matrix3.cpp */ +/* basis.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "matrix3.h" +#include "basis.h" #include "core/math/math_funcs.h" #include "core/os/copymem.h" @@ -76,9 +76,11 @@ void Basis::invert() { } void Basis::orthonormalize() { + #ifdef MATH_CHECKS ERR_FAIL_COND(determinant() == 0); #endif + // Gram-Schmidt Process Vector3 x = get_axis(0); @@ -118,16 +120,16 @@ bool Basis::is_diagonal() const { } bool Basis::is_rotation() const { - return Math::is_equal_approx(determinant(), 1) && is_orthogonal(); + return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal(); } bool Basis::is_symmetric() const { - if (!Math::is_equal_approx(elements[0][1], elements[1][0])) + if (!Math::is_equal_approx_ratio(elements[0][1], elements[1][0], UNIT_EPSILON)) return false; - if (!Math::is_equal_approx(elements[0][2], elements[2][0])) + if (!Math::is_equal_approx_ratio(elements[0][2], elements[2][0], UNIT_EPSILON)) return false; - if (!Math::is_equal_approx(elements[1][2], elements[2][1])) + if (!Math::is_equal_approx_ratio(elements[1][2], elements[2][1], UNIT_EPSILON)) return false; return true; @@ -258,7 +260,7 @@ Vector3 Basis::get_scale_abs() const { } Vector3 Basis::get_scale_local() const { - real_t det_sign = determinant() > 0 ? 1 : -1; + real_t det_sign = SGN(determinant()); return det_sign * Vector3(elements[0].length(), elements[1].length(), elements[2].length()); } @@ -284,7 +286,7 @@ Vector3 Basis::get_scale() const { // matrix elements. // // The rotation part of this decomposition is returned by get_rotation* functions. - real_t det_sign = determinant() > 0 ? 1 : -1; + real_t det_sign = SGN(determinant()); return det_sign * Vector3( Vector3(elements[0][0], elements[1][0], elements[2][0]).length(), Vector3(elements[0][1], elements[1][1], elements[2][1]).length(), @@ -488,6 +490,11 @@ void Basis::set_euler_xyz(const Vector3 &p_euler) { // as the x, y, and z components of a Vector3 respectively. Vector3 Basis::get_euler_yxz() const { + /* checking this is a bad idea, because obtaining from scaled transform is a valid use case +#ifdef MATH_CHECKS + ERR_FAIL_COND(!is_rotation()); +#endif +*/ // Euler angles in YXZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -496,9 +503,7 @@ Vector3 Basis::get_euler_yxz() const { // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx Vector3 euler; -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), euler); -#endif + real_t m12 = elements[1][2]; if (m12 < 1) { @@ -552,11 +557,23 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) { *this = ymat * xmat * zmat; } -bool Basis::is_equal_approx(const Basis &a, const Basis &b) const { +bool Basis::is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j])) + if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j], p_epsilon)) + return false; + } + } + + return true; +} + +bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const { + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], p_epsilon)) return false; } } @@ -599,10 +616,16 @@ Basis::operator String() const { } Quat Basis::get_quat() const { + #ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), Quat()); + if (!is_rotation()) { + ERR_EXPLAIN("Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead."); + ERR_FAIL_V(Quat()); + } #endif - real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; + /* Allow getting a quaternion from an unnormalized transform */ + Basis m = *this; + real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2]; real_t temp[4]; if (trace > 0.0) { @@ -610,23 +633,23 @@ Quat Basis::get_quat() const { temp[3] = (s * 0.5); s = 0.5 / s; - temp[0] = ((elements[2][1] - elements[1][2]) * s); - temp[1] = ((elements[0][2] - elements[2][0]) * s); - temp[2] = ((elements[1][0] - elements[0][1]) * s); + temp[0] = ((m.elements[2][1] - m.elements[1][2]) * s); + temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s); + temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s); } else { - int i = elements[0][0] < elements[1][1] ? - (elements[1][1] < elements[2][2] ? 2 : 1) : - (elements[0][0] < elements[2][2] ? 2 : 0); + int i = m.elements[0][0] < m.elements[1][1] ? + (m.elements[1][1] < m.elements[2][2] ? 2 : 1) : + (m.elements[0][0] < m.elements[2][2] ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; - real_t s = Math::sqrt(elements[i][i] - elements[j][j] - elements[k][k] + 1.0); + real_t s = Math::sqrt(m.elements[i][i] - m.elements[j][j] - m.elements[k][k] + 1.0); temp[i] = s * 0.5; s = 0.5 / s; - temp[3] = (elements[k][j] - elements[j][k]) * s; - temp[j] = (elements[j][i] + elements[i][j]) * s; - temp[k] = (elements[k][i] + elements[i][k]) * s; + temp[3] = (m.elements[k][j] - m.elements[j][k]) * s; + temp[j] = (m.elements[j][i] + m.elements[i][j]) * s; + temp[k] = (m.elements[k][i] + m.elements[i][k]) * s; } return Quat(temp[0], temp[1], temp[2], temp[3]); @@ -696,9 +719,11 @@ void Basis::set_orthogonal_index(int p_index) { } void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { + /* checking this is a bad idea, because obtaining from scaled transform is a valid use case #ifdef MATH_CHECKS ERR_FAIL_COND(!is_rotation()); #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 @@ -835,14 +860,15 @@ void Basis::set_diagonal(const Vector3 p_diag) { } Basis Basis::slerp(const Basis &target, const real_t &t) const { -// TODO: implement this directly without using quaternions to make it more efficient -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), Basis()); - ERR_FAIL_COND_V(!target.is_rotation(), Basis()); -#endif + //consider scale Quat from(*this); Quat to(target); - return Basis(from.slerp(to, t)); + Basis b(from.slerp(to, t)); + b.elements[0] *= Math::lerp(elements[0].length(), target.elements[0].length(), t); + b.elements[1] *= Math::lerp(elements[1].length(), target.elements[1].length(), t); + b.elements[2] *= Math::lerp(elements[2].length(), target.elements[2].length(), t); + + return b; } diff --git a/core/math/matrix3.h b/core/math/basis.h index e7d6ab4522..75037c2c52 100644 --- a/core/math/matrix3.h +++ b/core/math/basis.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* matrix3.h */ +/* basis.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,8 +31,8 @@ // Circular dependency between Vector3 and Basis :/ #include "core/math/vector3.h" -#ifndef MATRIX3_H -#define MATRIX3_H +#ifndef BASIS_H +#define BASIS_H #include "core/math/quat.h" @@ -133,7 +133,8 @@ public: return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2]; } - bool is_equal_approx(const Basis &a, const Basis &b) const; + bool is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon = CMP_EPSILON) const; + bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon = UNIT_EPSILON) const; bool operator==(const Basis &p_matrix) const; bool operator!=(const Basis &p_matrix) const; @@ -341,4 +342,4 @@ real_t Basis::determinant() const { elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) + elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]); } -#endif +#endif // BASIS_H diff --git a/core/math/bsp_tree.h b/core/math/bsp_tree.h index 0af532a2d5..a7a3697990 100644 --- a/core/math/bsp_tree.h +++ b/core/math/bsp_tree.h @@ -31,11 +31,11 @@ #ifndef BSP_TREE_H #define BSP_TREE_H -#include "core/dvector.h" #include "core/math/aabb.h" #include "core/math/face3.h" #include "core/math/plane.h" #include "core/method_ptrcall.h" +#include "core/pool_vector.h" #include "core/variant.h" #include "core/vector.h" /** diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index caf08c7379..f615cc8c65 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -210,6 +210,14 @@ void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, r te[15] = 0; } +void CameraMatrix::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { + if (!p_flip_fov) { + p_size *= p_aspect; + } + + set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far); +} + real_t CameraMatrix::get_z_far() const { const real_t *matrix = (const real_t *)this->matrix; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 015588a8cb..3bcf48f5da 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -61,6 +61,7 @@ struct CameraMatrix { void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far); + void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); static real_t get_fovy(real_t p_fovx, real_t p_aspect) { diff --git a/core/math/delaunay.h b/core/math/delaunay.h index bd0cf97937..ed52c506db 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -80,11 +80,11 @@ public: } static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) { - if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON) { + if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) { return true; } - if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON) { + if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) { return true; } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 61e5154f44..079c9b524f 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -64,10 +64,12 @@ const char *Expression::func_name[Expression::FUNC_MAX] = { "is_inf", "ease", "decimals", + "step_decimals", "stepify", "lerp", "inverse_lerp", "range_lerp", + "smoothstep", "dectime", "randomize", "randi", @@ -148,6 +150,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) { case MATH_ISNAN: case MATH_ISINF: case MATH_DECIMALS: + case MATH_STEP_DECIMALS: case MATH_SEED: case MATH_RANDSEED: case MATH_DEG2RAD: @@ -164,10 +167,10 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) { case TEXT_PRINTRAW: case VAR_TO_STR: case STR_TO_VAR: - case VAR_TO_BYTES: - case BYTES_TO_VAR: case TYPE_EXISTS: return 1; + case VAR_TO_BYTES: + case BYTES_TO_VAR: case MATH_ATAN2: case MATH_FMOD: case MATH_FPOSMOD: @@ -185,6 +188,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) { return 2; case MATH_LERP: case MATH_INVERSE_LERP: + case MATH_SMOOTHSTEP: case MATH_DECTIME: case MATH_WRAP: case MATH_WRAPF: @@ -363,6 +367,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant VALIDATE_ARG_NUM(0); *r_return = Math::step_decimals((double)*p_inputs[0]); } break; + case MATH_STEP_DECIMALS: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::step_decimals((double)*p_inputs[0]); + } break; case MATH_STEPIFY: { VALIDATE_ARG_NUM(0); @@ -392,6 +401,12 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant VALIDATE_ARG_NUM(4); *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); } break; + case MATH_SMOOTHSTEP: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; case MATH_DECTIME: { VALIDATE_ARG_NUM(0); @@ -696,8 +711,9 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant case VAR_TO_BYTES: { PoolByteArray barr; + bool full_objects = *p_inputs[1]; int len; - Error err = encode_variant(*p_inputs[0], NULL, len); + Error err = encode_variant(*p_inputs[0], NULL, len, full_objects); if (err) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -709,7 +725,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant barr.resize(len); { PoolByteArray::Write w = barr.write(); - encode_variant(*p_inputs[0], w.ptr(), len); + encode_variant(*p_inputs[0], w.ptr(), len, full_objects); } *r_return = barr; } break; @@ -724,10 +740,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant } PoolByteArray varr = *p_inputs[0]; + bool allow_objects = *p_inputs[1]; Variant ret; { PoolByteArray::Read r = varr.read(); - Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects); if (err != OK) { r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -750,7 +767,8 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return = String(color); } break; - default: {} + default: { + } } } @@ -1264,10 +1282,10 @@ Expression::ENode *Expression::_parse_expression() { } str_ofs = cofs; //revert //parse an expression - ENode *expr = _parse_expression(); - if (!expr) + ENode *subexpr = _parse_expression(); + if (!subexpr) return NULL; - dn->dict.push_back(expr); + dn->dict.push_back(subexpr); _get_token(tk); if (tk.type != TK_COLON) { @@ -1275,11 +1293,11 @@ Expression::ENode *Expression::_parse_expression() { return NULL; } - expr = _parse_expression(); - if (!expr) + subexpr = _parse_expression(); + if (!subexpr) return NULL; - dn->dict.push_back(expr); + dn->dict.push_back(subexpr); cofs = str_ofs; _get_token(tk); @@ -1308,10 +1326,10 @@ Expression::ENode *Expression::_parse_expression() { } str_ofs = cofs; //revert //parse an expression - ENode *expr = _parse_expression(); - if (!expr) + ENode *subexpr = _parse_expression(); + if (!subexpr) return NULL; - an->array.push_back(expr); + an->array.push_back(subexpr); cofs = str_ofs; _get_token(tk); @@ -1355,25 +1373,25 @@ Expression::ENode *Expression::_parse_expression() { while (true) { - int cofs = str_ofs; + int cofs2 = str_ofs; _get_token(tk); if (tk.type == TK_PARENTHESIS_CLOSE) { break; } - str_ofs = cofs; //revert + str_ofs = cofs2; //revert //parse an expression - ENode *expr = _parse_expression(); - if (!expr) + ENode *subexpr = _parse_expression(); + if (!subexpr) return NULL; - func_call->arguments.push_back(expr); + func_call->arguments.push_back(subexpr); - cofs = str_ofs; + cofs2 = str_ofs; _get_token(tk); if (tk.type == TK_COMMA) { //all good } else if (tk.type == TK_PARENTHESIS_CLOSE) { - str_ofs = cofs; + str_ofs = cofs2; } else { _set_error("Expected ',' or ')'"); } @@ -1444,11 +1462,11 @@ Expression::ENode *Expression::_parse_expression() { } str_ofs = cofs; //revert //parse an expression - ENode *expr = _parse_expression(); - if (!expr) + ENode *subexpr = _parse_expression(); + if (!subexpr) return NULL; - constructor->arguments.push_back(expr); + constructor->arguments.push_back(subexpr); cofs = str_ofs; _get_token(tk); @@ -1485,11 +1503,11 @@ Expression::ENode *Expression::_parse_expression() { } str_ofs = cofs; //revert //parse an expression - ENode *expr = _parse_expression(); - if (!expr) + ENode *subexpr = _parse_expression(); + if (!subexpr) return NULL; - bifunc->arguments.push_back(expr); + bifunc->arguments.push_back(subexpr); cofs = str_ofs; _get_token(tk); @@ -1584,25 +1602,25 @@ Expression::ENode *Expression::_parse_expression() { while (true) { - int cofs = str_ofs; + int cofs3 = str_ofs; _get_token(tk); if (tk.type == TK_PARENTHESIS_CLOSE) { break; } - str_ofs = cofs; //revert + str_ofs = cofs3; //revert //parse an expression - ENode *expr = _parse_expression(); - if (!expr) + ENode *subexpr = _parse_expression(); + if (!subexpr) return NULL; - func_call->arguments.push_back(expr); + func_call->arguments.push_back(subexpr); - cofs = str_ofs; + cofs3 = str_ofs; _get_token(tk); if (tk.type == TK_COMMA) { //all good } else if (tk.type == TK_PARENTHESIS_CLOSE) { - str_ofs = cofs; + str_ofs = cofs3; } else { _set_error("Expected ',' or ')'"); } @@ -1669,7 +1687,8 @@ Expression::ENode *Expression::_parse_expression() { case TK_OP_BIT_OR: op = Variant::OP_BIT_OR; break; case TK_OP_BIT_XOR: op = Variant::OP_BIT_XOR; break; case TK_OP_BIT_INVERT: op = Variant::OP_BIT_NEGATE; break; - default: {}; + default: { + }; } if (op == Variant::OP_MAX) { //stop appending stuff @@ -1902,7 +1921,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: Variant b; if (op->nodes[1]) { - bool ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str); + ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str); if (ret) return true; } @@ -2070,7 +2089,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < call->arguments.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str); + ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str); if (ret) return true; diff --git a/core/math/expression.h b/core/math/expression.h index fa0878c93c..f20619f0b6 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -62,10 +62,12 @@ public: MATH_ISINF, MATH_EASE, MATH_DECIMALS, + MATH_STEP_DECIMALS, MATH_STEPIFY, MATH_LERP, MATH_INVERSE_LERP, MATH_RANGE_LERP, + MATH_SMOOTHSTEP, MATH_DECTIME, MATH_RANDOMIZE, MATH_RAND, diff --git a/core/math/face3.h b/core/math/face3.h index 1a00851eab..184e80ff77 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -241,13 +241,13 @@ bool Face3::intersects_aabb2(const AABB &p_aabb) const { real_t minT = 1e20, maxT = -1e20; for (int k = 0; k < 3; k++) { - real_t d = axis.dot(vertex[k]); + real_t vert_d = axis.dot(vertex[k]); - if (d > maxT) - maxT = d; + if (vert_d > maxT) + maxT = vert_d; - if (d < minT) - minT = d; + if (vert_d < minT) + minT = vert_d; } if (maxB < minT || maxT < minB) diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index 12c88f43b3..0ab8707d3a 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -31,6 +31,7 @@ #include "geometry.h" #include "core/print_string.h" +#include "thirdparty/misc/triangulator.h" /* this implementation is very inefficient, commenting unless bugs happen. See the other one. bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { @@ -514,7 +515,7 @@ static inline void _build_faces(uint8_t ***p_cell_status, int x, int y, int z, i Vector3(1,1,1), }; */ -#define vert(m_idx) Vector3((m_idx & 4) >> 2, (m_idx & 2) >> 1, m_idx & 1) +#define vert(m_idx) Vector3(((m_idx)&4) >> 2, ((m_idx)&2) >> 1, (m_idx)&1) static const uint8_t indices[6][4] = { { 7, 6, 4, 5 }, @@ -737,6 +738,40 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e return wrapped_faces; } +Vector<Vector<Vector2> > Geometry::decompose_polygon_in_convex(Vector<Point2> polygon) { + Vector<Vector<Vector2> > decomp; + List<TriangulatorPoly> in_poly, out_poly; + + TriangulatorPoly inp; + inp.Init(polygon.size()); + for (int i = 0; i < polygon.size(); i++) { + inp.GetPoint(i) = polygon[i]; + } + inp.SetOrientation(TRIANGULATOR_CCW); + in_poly.push_back(inp); + TriangulatorPartition tpart; + if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! + ERR_PRINT("Convex decomposing failed!"); + return decomp; + } + + decomp.resize(out_poly.size()); + int idx = 0; + for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) { + TriangulatorPoly &tp = I->get(); + + decomp.write[idx].resize(tp.GetNumPoints()); + + for (int i = 0; i < tp.GetNumPoints(); i++) { + decomp.write[idx].write[i] = tp.GetPoint(i); + } + + idx++; + } + + return decomp; +} + Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes) { MeshData mesh; @@ -801,7 +836,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes Vector3 rel = edge1_A - edge0_A; real_t den = clip.normal.dot(rel); - if (Math::abs(den) < CMP_EPSILON) + if (Math::is_zero_approx(den)) continue; // point too short real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den; diff --git a/core/math/geometry.h b/core/math/geometry.h index 29493516b8..f3a671aa9a 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -31,12 +31,12 @@ #ifndef GEOMETRY_H #define GEOMETRY_H -#include "core/dvector.h" #include "core/math/face3.h" #include "core/math/rect2.h" #include "core/math/triangulate.h" #include "core/math/vector3.h" #include "core/object.h" +#include "core/pool_vector.h" #include "core/print_string.h" #include "core/vector.h" @@ -181,8 +181,8 @@ public: } } // finally do the division to get sc and tc - sc = (Math::abs(sN) < CMP_EPSILON ? 0.0 : sN / sD); - tc = (Math::abs(tN) < CMP_EPSILON ? 0.0 : tN / tD); + sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD); + tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD); // get the difference of the two closest points Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) @@ -195,7 +195,7 @@ public: Vector3 e2 = p_v2 - p_v0; Vector3 h = p_dir.cross(e2); real_t a = e1.dot(h); - if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test + if (Math::is_zero_approx(a)) // parallel test return false; real_t f = 1.0 / a; @@ -233,7 +233,7 @@ public: Vector3 e2 = p_v2 - p_v0; Vector3 h = rel.cross(e2); real_t a = e1.dot(h); - if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test + if (Math::is_zero_approx(a)) // parallel test return false; real_t f = 1.0 / a; @@ -535,7 +535,7 @@ public: // see http://paulbourke.net/geometry/pointlineplane/ const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y; - if (Math::abs(denom) < CMP_EPSILON) { // parallel? + if (Math::is_zero_approx(denom)) { // parallel? return false; } @@ -702,9 +702,11 @@ public: /* if we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) then the following can be skipped and we can just return the equivalent of res1 */ sqrtterm = Math::sqrt(sqrtterm); real_t res1 = (-b - sqrtterm) / (2 * a); - //real_t res2 = ( -b + sqrtterm ) / (2 * a); + real_t res2 = (-b + sqrtterm) / (2 * a); - return (res1 >= 0 && res1 <= 1) ? res1 : -1; + if (res1 >= 0 && res1 <= 1) return res1; + if (res2 >= 0 && res2 <= 1) return res2; + return -1; } static inline Vector<Vector3> clip_polygon(const Vector<Vector3> &polygon, const Plane &p_plane) { @@ -950,6 +952,8 @@ public: return H; } + static Vector<Vector<Vector2> > decompose_polygon_in_convex(Vector<Point2> polygon); + static MeshData build_convex_mesh(const PoolVector<Plane> &p_planes); static PoolVector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis = Vector3::AXIS_Z); static PoolVector<Plane> build_box_planes(const Vector3 &p_extents); diff --git a/core/math/math_defs.h b/core/math/math_defs.h index 48533ba659..c54d3cc96f 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -33,6 +33,7 @@ #define CMP_EPSILON 0.00001 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON) + #define CMP_NORMALIZE_TOLERANCE 0.000001 #define CMP_POINT_IN_PLANE_EPSILON 0.00001 @@ -49,6 +50,14 @@ #define MATH_CHECKS #endif +//this epsilon is for values related to a unit size (scalar or vector len) +#ifdef PRECISE_MATH_CHECKS +#define UNIT_EPSILON 0.00001 +#else +//tolerate some more floating point error normally +#define UNIT_EPSILON 0.001 +#endif + #define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0) enum ClockDirection { diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index ea0bfd88cc..a75f2fb4ab 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -208,6 +208,17 @@ public: static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } + static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) { + if (is_equal_approx(p_from, p_to)) return p_from; + double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0); + return x * x * (3.0 - 2.0 * x); + } + static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) { + if (is_equal_approx(p_from, p_to)) return p_from; + float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f); + return x * x * (3.0f - 2.0f * x); + } + static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; } static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; } @@ -217,17 +228,17 @@ public: static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } - static _ALWAYS_INLINE_ int wrapi(int value, int min, int max) { - int rng = max - min; - return min + ((((value - min) % rng) + rng) % rng); + static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) { + int64_t rng = max - min; + return (rng != 0) ? min + ((((value - min) % rng) + rng) % rng) : min; } static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { double rng = max - min; - return value - (rng * Math::floor((value - min) / rng)); + return (!is_equal_approx(rng, 0.0)) ? value - (rng * Math::floor((value - min) / rng)) : min; } static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { float rng = max - min; - return value - (rng * Math::floor((value - min) / rng)); + return (!is_equal_approx(rng, 0.0f)) ? value - (rng * Math::floor((value - min) / rng)) : min; } // double only, as these functions are mainly used by the editor and not performance-critical, @@ -242,20 +253,39 @@ public: static void randomize(); static uint32_t rand_from_seed(uint64_t *seed); static uint32_t rand(); - static _ALWAYS_INLINE_ double randf() { return (double)rand() / (double)Math::RANDOM_MAX; } - static _ALWAYS_INLINE_ float randd() { return (float)rand() / (float)Math::RANDOM_MAX; } + static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_MAX; } + static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_MAX; } static double random(double from, double to); 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 is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON, real_t min_epsilon = CMP_EPSILON) { + // this is an approximate way to check that numbers are close, as a ratio of their average size + // helps compare approximate numbers that may be very big or very small + real_t diff = abs(a - b); + if (diff == 0.0 || diff < min_epsilon) { + return true; + } + real_t avg_size = (abs(a) + abs(b)) / 2.0; + diff /= avg_size; + return diff < epsilon; + } + 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. - // See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details. + real_t tolerance = CMP_EPSILON * abs(a); + if (tolerance < CMP_EPSILON) { + tolerance = CMP_EPSILON; + } + return abs(a - b) < tolerance; + } + + static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) { + return abs(a - b) < tolerance; + } - return abs(a - b) < CMP_EPSILON; + static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) { + return abs(s) < CMP_EPSILON; } static _ALWAYS_INLINE_ float absf(float g) { diff --git a/core/math/octree.h b/core/math/octree.h index 36a77663f4..d6fc9776bc 100644 --- a/core/math/octree.h +++ b/core/math/octree.h @@ -916,34 +916,34 @@ void Octree<T, use_pairs, AL>::move(OctreeElementID p_id, const AABB &p_aabb) { pass++; - for (typename List<typename Element::OctantOwner, AL>::Element *E = owners.front(); E;) { + for (typename List<typename Element::OctantOwner, AL>::Element *F = owners.front(); F;) { - Octant *o = E->get().octant; - typename List<typename Element::OctantOwner, AL>::Element *N = E->next(); + Octant *o = F->get().octant; + typename List<typename Element::OctantOwner, AL>::Element *N = F->next(); /* if (!use_pairs) - o->elements.erase( E->get().E ); + o->elements.erase( F->get().E ); */ if (use_pairs && e.pairable) - o->pairable_elements.erase(E->get().E); + o->pairable_elements.erase(F->get().E); else - o->elements.erase(E->get().E); + o->elements.erase(F->get().E); if (_remove_element_from_octant(&e, o, common_parent->parent)) { - owners.erase(E); + owners.erase(F); } - E = N; + F = N; } if (use_pairs) { //unpair child elements in anything that survived - for (typename List<typename Element::OctantOwner, AL>::Element *E = owners.front(); E; E = E->next()) { + for (typename List<typename Element::OctantOwner, AL>::Element *F = owners.front(); F; F = F->next()) { - Octant *o = E->get().octant; + Octant *o = F->get().octant; // erase children pairs, unref ONCE pass++; diff --git a/core/math/plane.cpp b/core/math/plane.cpp index cd3cbce300..b01853c4ac 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -110,7 +110,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 real_t den = normal.dot(segment); //printf("den is %i\n",den); - if (Math::abs(den) <= CMP_EPSILON) { + if (Math::is_zero_approx(den)) { return false; } @@ -135,7 +135,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec real_t den = normal.dot(segment); //printf("den is %i\n",den); - if (Math::abs(den) <= CMP_EPSILON) { + if (Math::is_zero_approx(den)) { return false; } diff --git a/core/math/plane.h b/core/math/plane.h index 1c6e4b816b..ec817edd2c 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_ bool Plane::operator==(const Plane &p_plane) const { - return normal == p_plane.normal && d == p_plane.d; + return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d); } bool Plane::operator!=(const Plane &p_plane) const { - return normal != p_plane.normal || d != p_plane.d; + return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d); } #endif // PLANE_H diff --git a/core/math/quat.cpp b/core/math/quat.cpp index c1e45f36f0..1a67be7384 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -30,7 +30,7 @@ #include "quat.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" #include "core/print_string.h" // set_euler_xyz expects a vector containing the Euler angles in the format @@ -135,7 +135,7 @@ Quat Quat::normalized() const { } bool Quat::is_normalized() const { - return Math::is_equal_approx(length_squared(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon } Quat Quat::inverse() const { diff --git a/core/math/quat.h b/core/math/quat.h index 7d71ec03e8..8ed2fa7cc2 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -131,6 +131,14 @@ public: w(q.w) { } + Quat operator=(const Quat &q) { + x = q.x; + y = q.y; + z = q.z; + w = q.w; + return *this; + } + Quat(const Vector3 &v0, const Vector3 &v1) // shortest arc { Vector3 c = v0.cross(v1); diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index 1aa345db1f..fc2eb1454d 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -36,8 +36,6 @@ uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF; Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_mesh) { - static const real_t over_tolerance = 0.0001; - /* CREATE AABB VOLUME */ AABB aabb; @@ -180,6 +178,8 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me faces.push_back(f); } + real_t over_tolerance = 3 * UNIT_EPSILON * (aabb.size.x + aabb.size.y + aabb.size.z); + /* COMPUTE AVAILABLE VERTICES */ for (int i = 0; i < p_points.size(); i++) { @@ -438,12 +438,12 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me } // remove all edge connections to this face - for (Map<Edge, RetFaceConnect>::Element *E = ret_edges.front(); E; E = E->next()) { - if (E->get().left == O) - E->get().left = NULL; + for (Map<Edge, RetFaceConnect>::Element *G = ret_edges.front(); G; G = G->next()) { + if (G->get().left == O) + G->get().left = NULL; - if (E->get().right == O) - E->get().right = NULL; + if (G->get().right == O) + G->get().right = NULL; } ret_edges.erase(F); //remove the edge diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h index 2e659cab6e..a445a47cbe 100644 --- a/core/math/quick_hull.h +++ b/core/math/quick_hull.h @@ -64,7 +64,7 @@ public: struct Face { Plane plane; - int vertices[3]; + uint32_t vertices[3]; Vector<int> points_over; bool operator<(const Face &p_face) const { diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp index fccc0f72fe..6add00c1d8 100644 --- a/core/math/random_number_generator.cpp +++ b/core/math/random_number_generator.cpp @@ -40,6 +40,7 @@ void RandomNumberGenerator::_bind_methods() { ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi); ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf); + ClassDB::bind_method(D_METHOD("randfn", "mean", "deviation"), &RandomNumberGenerator::randfn, DEFVAL(0.0), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range); ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range); ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize); diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h index 66c77b8ccf..6b6bcdd2cd 100644 --- a/core/math/random_number_generator.h +++ b/core/math/random_number_generator.h @@ -55,6 +55,8 @@ public: _FORCE_INLINE_ real_t randf_range(real_t from, real_t to) { return randbase.random(from, to); } + _FORCE_INLINE_ real_t randfn(real_t mean = 0.0, real_t deviation = 1.0) { return randbase.randfn(mean, deviation); } + _FORCE_INLINE_ int randi_range(int from, int to) { unsigned int ret = randbase.rand(); return ret % (to - from + 1) + from; diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp index 8bbcca88fe..8351bd138e 100644 --- a/core/math/random_pcg.cpp +++ b/core/math/random_pcg.cpp @@ -32,24 +32,24 @@ #include "core/os/os.h" -RandomPCG::RandomPCG(uint64_t seed, uint64_t inc) : - pcg() { - pcg.state = seed; - pcg.inc = inc; +RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) : + pcg(), + current_inc(p_inc) { + seed(p_seed); } void RandomPCG::randomize() { seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64); } -double RandomPCG::random(double from, double to) { +double RandomPCG::random(double p_from, double p_to) { unsigned int r = rand(); double ret = (double)r / (double)RANDOM_MAX; - return (ret) * (to - from) + from; + return (ret) * (p_to - p_from) + p_from; } -float RandomPCG::random(float from, float to) { +float RandomPCG::random(float p_from, float p_to) { unsigned int r = rand(); float ret = (float)r / (float)RANDOM_MAX; - return (ret) * (to - from) + from; + return (ret) * (p_to - p_from) + p_from; } diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h index ef69bf7120..0d1b311c0d 100644 --- a/core/math/random_pcg.h +++ b/core/math/random_pcg.h @@ -31,31 +31,48 @@ #ifndef RANDOM_PCG_H #define RANDOM_PCG_H +#include <math.h> + #include "core/math/math_defs.h" #include "thirdparty/misc/pcg.h" class RandomPCG { pcg32_random_t pcg; + uint64_t current_seed; // seed with this to get the same state + uint64_t current_inc; public: static const uint64_t DEFAULT_SEED = 12047754176567800795U; static const uint64_t DEFAULT_INC = PCG_DEFAULT_INC_64; static const uint64_t RANDOM_MAX = 0xFFFFFFFF; - RandomPCG(uint64_t seed = DEFAULT_SEED, uint64_t inc = PCG_DEFAULT_INC_64); + RandomPCG(uint64_t p_seed = DEFAULT_SEED, uint64_t p_inc = DEFAULT_INC); - _FORCE_INLINE_ void seed(uint64_t seed) { pcg.state = seed; } - _FORCE_INLINE_ uint64_t get_seed() { return pcg.state; } + _FORCE_INLINE_ void seed(uint64_t p_seed) { + current_seed = p_seed; + pcg32_srandom_r(&pcg, current_seed, current_inc); + } + _FORCE_INLINE_ uint64_t get_seed() { return current_seed; } void randomize(); - _FORCE_INLINE_ uint32_t rand() { return pcg32_random_r(&pcg); } + _FORCE_INLINE_ uint32_t rand() { + current_seed = pcg.state; + return pcg32_random_r(&pcg); + } _FORCE_INLINE_ double randd() { return (double)rand() / (double)RANDOM_MAX; } _FORCE_INLINE_ float randf() { return (float)rand() / (float)RANDOM_MAX; } - double random(double from, double to); - float random(float from, float to); - real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); } + _FORCE_INLINE_ double randfn(double p_mean, double p_deviation) { + return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(randd()))); // Box-Muller transform + } + _FORCE_INLINE_ float randfn(float p_mean, float p_deviation) { + return p_mean + p_deviation * (cos(Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform + } + + double random(double p_from, double p_to); + float random(float p_from, float p_to); + real_t random(int p_from, int p_to) { return (real_t)random((real_t)p_from, (real_t)p_to); } }; #endif // RANDOM_PCG_H diff --git a/core/math/rect2.h b/core/math/rect2.h index 901d372132..d636aa223f 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -67,7 +67,7 @@ struct Rect2 { if (p_point.x < position.x) { real_t d = position.x - p_point.x; - dist = inside ? d : MIN(dist, d); + dist = d; inside = false; } if (p_point.y < position.y) { @@ -103,7 +103,7 @@ struct Rect2 { ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); } - inline bool has_no_area() const { + _FORCE_INLINE_ bool has_no_area() const { return (size.x <= 0 || size.y <= 0); } @@ -154,8 +154,6 @@ struct Rect2 { return true; } - inline bool no_area() const { return (size.width <= 0 || size.height <= 0); } - bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } @@ -189,7 +187,7 @@ struct Rect2 { return g; } - inline Rect2 expand(const Vector2 &p_vector) const { + _FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const { Rect2 r = *this; r.expand_to(p_vector); @@ -215,7 +213,7 @@ struct Rect2 { size = end - begin; } - inline Rect2 abs() const { + _FORCE_INLINE_ Rect2 abs() const { return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); } @@ -265,7 +263,7 @@ struct Rect2i { ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); } - inline bool has_no_area() const { + _FORCE_INLINE_ bool has_no_area() const { return (size.x <= 0 || size.y <= 0); } @@ -316,8 +314,6 @@ struct Rect2i { return true; } - bool no_area() { return (size.width <= 0 || size.height <= 0); } - bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } @@ -331,6 +327,33 @@ struct Rect2i { return g; } + inline Rect2i grow_margin(Margin p_margin, int p_amount) const { + Rect2i g = *this; + g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, + (MARGIN_TOP == p_margin) ? p_amount : 0, + (MARGIN_RIGHT == p_margin) ? p_amount : 0, + (MARGIN_BOTTOM == p_margin) ? p_amount : 0); + return g; + } + + inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const { + + Rect2i g = *this; + g.position.x -= p_left; + g.position.y -= p_top; + g.size.width += p_left + p_right; + g.size.height += p_top + p_bottom; + + return g; + } + + _FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const { + + Rect2i r = *this; + r.expand_to(p_vector); + return r; + } + inline void expand_to(const Point2i &p_vector) { Point2i begin = position; diff --git a/core/math/transform.h b/core/math/transform.h index 9b323a6f0f..2f43f6b035 100644 --- a/core/math/transform.h +++ b/core/math/transform.h @@ -32,7 +32,7 @@ #define TRANSFORM_H #include "core/math/aabb.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" #include "core/math/plane.h" /** diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 295e60babb..1d0387bd45 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -80,13 +80,14 @@ real_t Transform2D::get_rotation() const { } void Transform2D::set_rotation(real_t p_rot) { - + Size2 scale = get_scale(); real_t cr = Math::cos(p_rot); real_t sr = Math::sin(p_rot); elements[0][0] = cr; elements[0][1] = sr; elements[1][0] = -sr; elements[1][1] = cr; + set_scale(scale); } Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) { @@ -101,10 +102,17 @@ Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) { } Size2 Transform2D::get_scale() const { - real_t det_sign = basis_determinant() > 0 ? 1 : -1; + real_t det_sign = SGN(basis_determinant()); return Size2(elements[0].length(), det_sign * elements[1].length()); } +void Transform2D::set_scale(const Size2 &p_scale) { + elements[0].normalize(); + elements[1].normalize(); + elements[0] *= p_scale.x; + elements[1] *= p_scale.y; +} + void Transform2D::scale(const Size2 &p_scale) { scale_basis(p_scale); elements[2] *= p_scale; diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 507e6a16eb..c44678674a 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -81,6 +81,7 @@ struct Transform2D { real_t basis_determinant() const; Size2 get_scale() const; + void set_scale(const Size2 &p_scale); _FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; } _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; } diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index cdf3d16b72..83784a1fa7 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -30,7 +30,7 @@ #include "triangle_mesh.h" -#include "core/sort.h" +#include "core/sort_array.h" int TriangleMesh::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, int p_depth, int &max_depth, int &max_alloc) { diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index e580057950..5c1ea5943d 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -65,7 +65,7 @@ Vector2 Vector2::normalized() const { bool Vector2::is_normalized() const { // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); } real_t Vector2::distance_to(const Vector2 &p_vector2) const { diff --git a/core/math/vector2.h b/core/math/vector2.h index a20326f667..a0c6024c9f 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -65,6 +65,7 @@ struct Vector2 { real_t distance_squared_to(const Vector2 &p_vector2) const; real_t angle_to(const Vector2 &p_vector2) const; real_t angle_to_point(const Vector2 &p_vector2) const; + _FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_b) const; real_t dot(const Vector2 &p_other) const; real_t cross(const Vector2 &p_other) const; @@ -98,14 +99,15 @@ struct Vector2 { Vector2 operator/(const real_t &rvalue) const; void operator/=(const real_t &rvalue); + void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; } Vector2 operator-() const; bool operator==(const Vector2 &p_vec2) const; bool operator!=(const Vector2 &p_vec2) const; - bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); } + bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); } real_t angle() const; @@ -211,11 +213,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const { _FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { - return x == p_vec2.x && y == p_vec2.y; + return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y); } _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { - return x != p_vec2.x || y != p_vec2.y; + return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y); } Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const { @@ -236,6 +238,12 @@ Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const { return rotated(theta * p_t); } +Vector2 Vector2::direction_to(const Vector2 &p_b) const { + Vector2 ret(p_b.x - x, p_b.y - y); + ret.normalize(); + return ret; +} + Vector2 Vector2::linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) { Vector2 res = p_a; diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index b2e89ac7b8..1c28934422 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -30,7 +30,7 @@ #include "vector3.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" void Vector3::rotate(const Vector3 &p_axis, real_t p_phi) { diff --git a/core/math/vector3.h b/core/math/vector3.h index b0eef35635..21fc09653f 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -112,6 +112,7 @@ struct Vector3 { _FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const; _FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const; + _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_b) const; _FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const; _FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const; @@ -151,7 +152,7 @@ struct Vector3 { }; // Should be included after class definition, otherwise we get circular refs -#include "core/math/matrix3.h" +#include "core/math/basis.h" Vector3 Vector3::cross(const Vector3 &p_b) const { @@ -244,6 +245,12 @@ real_t Vector3::angle_to(const Vector3 &p_b) const { return Math::atan2(cross(p_b).length(), dot(p_b)); } +Vector3 Vector3::direction_to(const Vector3 &p_b) const { + Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z); + ret.normalize(); + return ret; +} + /* Operators */ Vector3 &Vector3::operator+=(const Vector3 &p_v) { @@ -334,17 +341,17 @@ Vector3 Vector3::operator-() const { bool Vector3::operator==(const Vector3 &p_v) const { - return (x == p_v.x && y == p_v.y && z == p_v.z); + return (Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z)); } bool Vector3::operator!=(const Vector3 &p_v) const { - return (x != p_v.x || y != p_v.y || z != p_v.z); + return (!Math::is_equal_approx(x, p_v.x) || !Math::is_equal_approx(y, p_v.y) || !Math::is_equal_approx(z, p_v.z)); } bool Vector3::operator<(const Vector3 &p_v) const { - if (x == p_v.x) { - if (y == p_v.y) + if (Math::is_equal_approx(x, p_v.x)) { + if (Math::is_equal_approx(y, p_v.y)) return z < p_v.z; else return y < p_v.y; @@ -355,8 +362,8 @@ bool Vector3::operator<(const Vector3 &p_v) const { bool Vector3::operator<=(const Vector3 &p_v) const { - if (x == p_v.x) { - if (y == p_v.y) + if (Math::is_equal_approx(x, p_v.x)) { + if (Math::is_equal_approx(y, p_v.y)) return z <= p_v.z; else return y < p_v.y; @@ -395,13 +402,14 @@ real_t Vector3::length_squared() const { void Vector3::normalize() { - real_t l = length(); - if (l == 0) { + real_t lengthsq = length_squared(); + if (lengthsq == 0) { x = y = z = 0; } else { - x /= l; - y /= l; - z /= l; + real_t length = Math::sqrt(lengthsq); + x /= length; + y /= length; + z /= length; } } @@ -414,7 +422,7 @@ Vector3 Vector3::normalized() const { bool Vector3::is_normalized() const { // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); } Vector3 Vector3::inverse() const { |