Expose Curve points in the inspector

Exposes the Curve, Curve2D and Curve3D points as an array property.
This commit is contained in:
Raul Santos 2022-02-12 19:12:22 +01:00
parent 0ba0d51c9e
commit a9a41df0c8
No known key found for this signature in database
GPG key ID: B532473AE3A803E4
5 changed files with 280 additions and 19 deletions

View file

@ -38,12 +38,6 @@
Removes all points from the curve.
</description>
</method>
<method name="get_point_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of points describing the curve.
</description>
</method>
<method name="get_point_left_mode" qualifiers="const">
<return type="int" enum="Curve.TangentMode" />
<argument index="0" name="index" type="int" />
@ -159,6 +153,9 @@
<member name="min_value" type="float" setter="set_min_value" getter="get_min_value" default="0.0">
The minimum value the curve can reach.
</member>
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>
</members>
<signals>
<signal name="range_changed">

View file

@ -55,12 +55,6 @@
[code]to_point[/code] must be in this curve's local space.
</description>
</method>
<method name="get_point_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of points describing the curve.
</description>
</method>
<method name="get_point_in" qualifiers="const">
<return type="Vector2" />
<argument index="0" name="idx" type="int" />
@ -155,5 +149,8 @@
<member name="bake_interval" type="float" setter="set_bake_interval" getter="get_bake_interval" default="5.0">
The distance in pixels between two adjacent cached points. Changing it forces the cache to be recomputed the next time the [method get_baked_points] or [method get_baked_length] function is called. The smaller the distance, the more points in the cache and the more memory it will consume, so use with care.
</member>
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>
</members>
</class>

View file

@ -68,12 +68,6 @@
[code]to_point[/code] must be in this curve's local space.
</description>
</method>
<method name="get_point_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of points describing the curve.
</description>
</method>
<method name="get_point_in" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="idx" type="int" />
@ -194,6 +188,9 @@
<member name="bake_interval" type="float" setter="set_bake_interval" getter="get_bake_interval" default="0.2">
The distance in meters between two adjacent cached points. Changing it forces the cache to be recomputed the next time the [method get_baked_points] or [method get_baked_length] function is called. The smaller the distance, the more points in the cache and the more memory it will consume, so use with care.
</member>
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>
<member name="up_vector_enabled" type="bool" setter="set_up_vector_enabled" getter="is_up_vector_enabled" default="true">
If [code]true[/code], the curve will bake up vectors used for orientation. This is used when [member PathFollow3D.rotation_mode] is set to [constant PathFollow3D.ROTATION_ORIENTED]. Changing it forces the cache to be recomputed.
</member>

View file

@ -49,6 +49,18 @@ const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
Curve::Curve() {
}
void Curve::set_point_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
if (_points.size() >= p_count) {
_points.resize(p_count);
mark_dirty();
} else {
for (int i = p_count - _points.size(); i > 0; i--) {
add_point(Vector2());
}
}
}
int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
// Add a point and preserve order
@ -358,6 +370,7 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
void Curve::mark_dirty() {
_baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
notify_property_list_changed();
}
Array Curve::get_data() const {
@ -409,7 +422,6 @@ void Curve::set_data(const Array p_input) {
p.position = p_input[i];
p.left_tangent = p_input[i + 1];
p.right_tangent = p_input[i + 2];
// TODO For some reason the compiler won't convert from Variant to enum
int left_mode = p_input[i + 3];
int right_mode = p_input[i + 4];
p.left_mode = (TangentMode)left_mode;
@ -490,8 +502,91 @@ void Curve::ensure_default_setup(real_t p_min, real_t p_max) {
}
}
bool Curve::_set(const StringName &p_name, const Variant &p_value) {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
int point_index = components[0].trim_prefix("point_").to_int();
String property = components[1];
if (property == "position") {
Vector2 position = p_value.operator Vector2();
set_point_offset(point_index, position.x);
set_point_value(point_index, position.y);
return true;
} else if (property == "left_tangent") {
set_point_left_tangent(point_index, p_value);
return true;
} else if (property == "left_mode") {
int mode = p_value;
set_point_left_mode(point_index, (TangentMode)mode);
return true;
} else if (property == "right_tangent") {
set_point_right_tangent(point_index, p_value);
return true;
} else if (property == "right_mode") {
int mode = p_value;
set_point_right_mode(point_index, (TangentMode)mode);
return true;
}
}
return false;
}
bool Curve::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
int point_index = components[0].trim_prefix("point_").to_int();
String property = components[1];
if (property == "position") {
r_ret = get_point_position(point_index);
return true;
} else if (property == "left_tangent") {
r_ret = get_point_left_tangent(point_index);
return true;
} else if (property == "left_mode") {
r_ret = get_point_left_mode(point_index);
return true;
} else if (property == "right_tangent") {
r_ret = get_point_right_tangent(point_index);
return true;
} else if (property == "right_mode") {
r_ret = get_point_right_mode(point_index);
return true;
}
}
return false;
}
void Curve::_get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < _points.size(); i++) {
PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
if (i != 0) {
pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/left_tangent", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
pi = PropertyInfo(Variant::INT, vformat("point_%d/left_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
if (i != _points.size() - 1) {
pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/right_tangent", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
pi = PropertyInfo(Variant::INT, vformat("point_%d/right_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
}
}
void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "left_tangent", "right_tangent", "left_mode", "right_mode"), &Curve::add_point, DEFVAL(0), DEFVAL(0), DEFVAL(TANGENT_FREE), DEFVAL(TANGENT_FREE));
ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points);
@ -523,6 +618,7 @@ void Curve::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_max_value", "get_max_value");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution");
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_");
ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED));
@ -535,6 +631,20 @@ int Curve2D::get_point_count() const {
return points.size();
}
void Curve2D::set_point_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
if (points.size() >= p_count) {
points.resize(p_count);
mark_dirty();
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
} else {
for (int i = p_count - points.size(); i > 0; i--) {
add_point(Vector2());
}
}
}
void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
Point n;
n.position = p_position;
@ -629,6 +739,7 @@ Vector2 Curve2D::interpolatef(real_t p_findex) const {
void Curve2D::mark_dirty() {
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
notify_property_list_changed();
}
void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
@ -983,8 +1094,67 @@ PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
bool Curve2D::_set(const StringName &p_name, const Variant &p_value) {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
int point_index = components[0].trim_prefix("point_").to_int();
String property = components[1];
if (property == "position") {
set_point_position(point_index, p_value);
return true;
} else if (property == "in") {
set_point_in(point_index, p_value);
return true;
} else if (property == "out") {
set_point_out(point_index, p_value);
return true;
}
}
return false;
}
bool Curve2D::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
int point_index = components[0].trim_prefix("point_").to_int();
String property = components[1];
if (property == "position") {
r_ret = get_point_position(point_index);
return true;
} else if (property == "in") {
r_ret = get_point_in(point_index);
return true;
} else if (property == "out") {
r_ret = get_point_out(point_index);
return true;
}
}
return false;
}
void Curve2D::_get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < points.size(); i++) {
PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
if (i != 0) {
pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/in", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
if (i != points.size() - 1) {
pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/out", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
}
}
void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve2D::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position);
@ -1012,6 +1182,7 @@ void Curve2D::_bind_methods() {
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_");
}
Curve2D::Curve2D() {}
@ -1027,6 +1198,18 @@ int Curve3D::get_point_count() const {
return points.size();
}
void Curve3D::set_point_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
if (points.size() >= p_count) {
points.resize(p_count);
mark_dirty();
} else {
for (int i = p_count - points.size(); i > 0; i--) {
add_point(Vector3());
}
}
}
void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
Point n;
n.position = p_position;
@ -1133,6 +1316,7 @@ Vector3 Curve3D::interpolatef(real_t p_findex) const {
void Curve3D::mark_dirty() {
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
notify_property_list_changed();
}
void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
@ -1693,8 +1877,77 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
bool Curve3D::_set(const StringName &p_name, const Variant &p_value) {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
int point_index = components[0].trim_prefix("point_").to_int();
String property = components[1];
if (property == "position") {
set_point_position(point_index, p_value);
return true;
} else if (property == "in") {
set_point_in(point_index, p_value);
return true;
} else if (property == "out") {
set_point_out(point_index, p_value);
return true;
} else if (property == "tilt") {
set_point_tilt(point_index, p_value);
return true;
}
}
return false;
}
bool Curve3D::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
int point_index = components[0].trim_prefix("point_").to_int();
String property = components[1];
if (property == "position") {
r_ret = get_point_position(point_index);
return true;
} else if (property == "in") {
r_ret = get_point_in(point_index);
return true;
} else if (property == "out") {
r_ret = get_point_out(point_index);
return true;
} else if (property == "tilt") {
r_ret = get_point_tilt(point_index);
return true;
}
}
return false;
}
void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < points.size(); i++) {
PropertyInfo pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/position", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
if (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) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/tilt", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
}
void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve3D::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position);
@ -1729,6 +1982,7 @@ void Curve3D::_bind_methods() {
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_");
ADD_GROUP("Up Vector", "up_vector_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled");

View file

@ -76,6 +76,8 @@ public:
int get_point_count() const { return _points.size(); }
void set_point_count(int p_count);
int add_point(Vector2 p_position,
real_t left_tangent = 0,
real_t right_tangent = 0,
@ -126,6 +128,10 @@ public:
void ensure_default_setup(real_t p_min, real_t p_max);
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;
protected:
static void _bind_methods();
@ -174,11 +180,16 @@ class Curve2D : public Resource {
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
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;
protected:
static void _bind_methods();
public:
int get_point_count() const;
void set_point_count(int p_count);
void add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
void set_point_position(int p_index, const Vector2 &p_position);
Vector2 get_point_position(int p_index) const;
@ -241,11 +252,16 @@ class Curve3D : public Resource {
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
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;
protected:
static void _bind_methods();
public:
int get_point_count() const;
void set_point_count(int p_count);
void add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
void set_point_position(int p_index, const Vector3 &p_position);
Vector3 get_point_position(int p_index) const;