summaryrefslogtreecommitdiffstats
path: root/scene/resources/curve.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/curve.cpp')
-rw-r--r--scene/resources/curve.cpp114
1 files changed, 90 insertions, 24 deletions
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 8926eb1d51..dc509a4669 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -1454,6 +1454,9 @@ void Curve3D::_remove_point(int p_index) {
void Curve3D::remove_point(int p_index) {
_remove_point(p_index);
+ if (closed && points.size() < 2) {
+ set_closed(false);
+ }
notify_property_list_changed();
}
@@ -1470,15 +1473,25 @@ Vector3 Curve3D::sample(int p_index, real_t p_offset) const {
ERR_FAIL_COND_V(pc == 0, Vector3());
if (p_index >= pc - 1) {
- return points[pc - 1].position;
+ if (!closed) {
+ return points[pc - 1].position;
+ } else {
+ p_index = pc - 1;
+ }
} else if (p_index < 0) {
return points[0].position;
}
Vector3 p0 = points[p_index].position;
Vector3 p1 = p0 + points[p_index].out;
- Vector3 p3 = points[p_index + 1].position;
- Vector3 p2 = p3 + points[p_index + 1].in;
+ Vector3 p3, p2;
+ if (!closed || p_index < pc - 1) {
+ p3 = points[p_index + 1].position;
+ p2 = p3 + points[p_index + 1].in;
+ } else {
+ p3 = points[0].position;
+ p2 = p3 + points[0].in;
+ }
return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
@@ -1596,13 +1609,16 @@ void Curve3D::_bake() const {
{
Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+
#ifdef TOOLS_ENABLED
- points_in_cache.resize(points.size());
+ points_in_cache.resize(closed ? (points.size() + 1) : points.size());
points_in_cache.set(0, 0);
#endif
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
pc++;
pc += midpoints[i].size();
#ifdef TOOLS_ENABLED
@@ -1625,18 +1641,29 @@ void Curve3D::_bake() const {
btw[0] = points[0].tilt;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
- bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
- btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ if (!closed || i < num_intervals - 1) {
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
+ btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ } else {
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[0].position + points[0].in, points[0].position, E.key);
+ btw[pidx] = Math::lerp(points[i].tilt, points[0].tilt, E.key);
+ }
}
pidx++;
- bpw[pidx] = points[i + 1].position;
- bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
- btw[pidx] = points[i + 1].tilt;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
+ btw[pidx] = points[i + 1].tilt;
+ } else {
+ bpw[pidx] = points[0].position;
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[0].position + points[0].in, points[0].position, 1.0);
+ btw[pidx] = points[0].tilt;
+ }
}
// Recalculate the baked distances.
@@ -2075,6 +2102,20 @@ real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
return nearest;
}
+void Curve3D::set_closed(bool p_closed) {
+ if (closed == p_closed) {
+ return;
+ }
+
+ closed = p_closed;
+ mark_dirty();
+ notify_property_list_changed();
+}
+
+bool Curve3D::is_closed() const {
+ return closed;
+}
+
void Curve3D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
mark_dirty();
@@ -2153,11 +2194,17 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
}
Vector<RBMap<real_t, Vector3>> midpoints;
- midpoints.resize(points.size() - 1);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ midpoints.resize(num_intervals);
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ for (int i = 0; i < num_intervals; i++) {
+ if (!closed || i < num_intervals - 1) {
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ } else {
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[0].position, points[0].in, 0, p_max_stages, p_tolerance);
+ }
pc++;
pc += midpoints[i].size();
}
@@ -2167,14 +2214,18 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
bpw[0] = points[0].position;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
}
pidx++;
- bpw[pidx] = points[i + 1].position;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ } else {
+ bpw[pidx] = points[0].position;
+ }
}
return tess;
@@ -2184,10 +2235,15 @@ Vector<RBMap<real_t, Vector3>> Curve3D::_tessellate_even_length(int p_max_stages
Vector<RBMap<real_t, Vector3>> midpoints;
ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point");
- midpoints.resize(points.size() - 1);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ midpoints.resize(num_intervals);
- for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ for (int i = 0; i < num_intervals; i++) {
+ if (!closed || i < num_intervals - 1) {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ } else {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[0].position, points[0].in, 0, p_max_stages, p_length);
+ }
}
return midpoints;
}
@@ -2200,8 +2256,10 @@ PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_le
return tess;
}
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
pc++;
pc += midpoints[i].size();
}
@@ -2211,14 +2269,18 @@ PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_le
bpw[0] = points[0].position;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
}
pidx++;
- bpw[pidx] = points[i + 1].position;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ } else {
+ bpw[pidx] = points[0].position;
+ }
}
return tess;
@@ -2274,13 +2336,13 @@ void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
- if (i != 0) {
+ if (closed || i != 0) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/in", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
- if (i != points.size() - 1) {
+ if (closed || i != points.size() - 1) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
@@ -2308,6 +2370,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points);
ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample);
ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef);
+ ClassDB::bind_method(D_METHOD("set_closed", "closed"), &Curve3D::set_closed);
+ ClassDB::bind_method(D_METHOD("is_closed"), &Curve3D::is_closed);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
@@ -2329,6 +2393,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "closed"), "set_closed", "is_closed");
+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");