summaryrefslogtreecommitdiff
path: root/core/math
diff options
context:
space:
mode:
Diffstat (limited to 'core/math')
-rw-r--r--core/math/audio_frame.h6
-rw-r--r--core/math/basis.cpp26
-rw-r--r--core/math/basis.h3
-rw-r--r--core/math/expression.cpp12
-rw-r--r--core/math/geometry.cpp37
-rw-r--r--core/math/geometry.h8
-rw-r--r--core/math/math_funcs.h4
-rw-r--r--core/math/quat.h8
-rw-r--r--core/math/random_number_generator.cpp1
-rw-r--r--core/math/random_number_generator.h2
-rw-r--r--core/math/random_pcg.cpp16
-rw-r--r--core/math/random_pcg.h32
12 files changed, 121 insertions, 34 deletions
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index f970c510e0..ebe0356c93 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -122,6 +122,12 @@ 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_ AudioFrame() {}
};
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 8816e3639a..82b2f7006d 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -557,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_ratio(a.elements[i][j], b.elements[i][j], UNIT_EPSILON))
+ 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;
}
}
@@ -605,12 +617,14 @@ Basis::operator String() const {
Quat Basis::get_quat() const {
+#ifdef MATH_CHECKS
+ 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
/* Allow getting a quaternion from an unnormalized transform */
Basis m = *this;
- m.elements[0].normalize();
- m.elements[1].normalize();
- m.elements[2].normalize();
-
real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2];
real_t temp[4];
diff --git a/core/math/basis.h b/core/math/basis.h
index 128e56b494..aa0ddb280f 100644
--- a/core/math/basis.h
+++ b/core/math/basis.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;
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 99251d80e3..708054e4ab 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -164,10 +164,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:
@@ -696,8 +696,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 +710,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 +725,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;
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index 12c88f43b3..a84b5a16c7 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;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index f927a63ed5..7347cb742a 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -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_funcs.h b/core/math/math_funcs.h
index 17112d8940..6ac6839827 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -249,11 +249,11 @@ 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 is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
+ 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) {
+ if (diff == 0.0 || diff < min_epsilon) {
return true;
}
real_t avg_size = (abs(a) + abs(b)) / 2.0;
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/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 2a69d43904..0d1b311c0d 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -31,34 +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;
- pcg32_random_r(&pcg); // Force changing internal state to avoid initial 0
+ _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 pcg.state; }
+ _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