diff options
Diffstat (limited to 'scene/resources/curve.cpp')
-rw-r--r-- | scene/resources/curve.cpp | 170 |
1 files changed, 146 insertions, 24 deletions
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 006e7de562..338311b87b 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -380,15 +380,16 @@ Curve2D::Curve2D() #endif +const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed"; + Curve::Curve() { _bake_resolution = 100; _baked_cache_dirty = false; -#ifdef TOOLS_ENABLED - _disable_set_data = false; -#endif + _min_value = 0; + _max_value = 1; } -int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) { +int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent, TangentMode left_mode, TangentMode right_mode) { // Add a point and preserve order // Curve bounds is in 0..1 @@ -400,7 +401,7 @@ int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) { int ret = -1; if (_points.size() == 0) { - _points.push_back(Point(p_pos, left_tangent, right_tangent)); + _points.push_back(Point(p_pos, left_tangent, right_tangent, left_mode, right_mode)); ret = 0; } else if (_points.size() == 1) { @@ -409,10 +410,10 @@ int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) { real_t diff = p_pos.x - _points[0].pos.x; if (diff > 0) { - _points.push_back(Point(p_pos, left_tangent, right_tangent)); + _points.push_back(Point(p_pos, left_tangent, right_tangent, left_mode, right_mode)); ret = 1; } else { - _points.insert(0, Point(p_pos, left_tangent, right_tangent)); + _points.insert(0, Point(p_pos, left_tangent, right_tangent, left_mode, right_mode)); ret = 0; } @@ -431,16 +432,18 @@ int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) { if (i == 0 && p_pos.x < _points[0].pos.x) { // Insert before anything else - _points.insert(0, Point(p_pos, left_tangent, right_tangent)); + _points.insert(0, Point(p_pos, left_tangent, right_tangent, left_mode, right_mode)); ret = 0; } else { // Insert between i and i+1 ++i; - _points.insert(i, Point(p_pos, left_tangent, right_tangent)); + _points.insert(i, Point(p_pos, left_tangent, right_tangent, left_mode, right_mode)); ret = i; } } + update_auto_tangents(ret); + mark_dirty(); return ret; @@ -496,12 +499,38 @@ void Curve::clean_dupes() { void Curve::set_point_left_tangent(int i, real_t tangent) { ERR_FAIL_INDEX(i, _points.size()); _points[i].left_tangent = tangent; + _points[i].left_mode = TANGENT_FREE; mark_dirty(); } void Curve::set_point_right_tangent(int i, real_t tangent) { ERR_FAIL_INDEX(i, _points.size()); _points[i].right_tangent = tangent; + _points[i].right_mode = TANGENT_FREE; + mark_dirty(); +} + +void Curve::set_point_left_mode(int i, TangentMode p_mode) { + ERR_FAIL_INDEX(i, _points.size()); + _points[i].left_mode = p_mode; + if (i > 0) { + if (p_mode == TANGENT_LINEAR) { + Vector2 v = (_points[i - 1].pos - _points[i].pos).normalized(); + _points[i].left_tangent = v.y / v.x; + } + } + mark_dirty(); +} + +void Curve::set_point_right_mode(int i, TangentMode p_mode) { + ERR_FAIL_INDEX(i, _points.size()); + _points[i].right_mode = p_mode; + if (i + 1 < _points.size()) { + if (p_mode == TANGENT_LINEAR) { + Vector2 v = (_points[i + 1].pos - _points[i].pos).normalized(); + _points[i].right_tangent = v.y / v.x; + } + } mark_dirty(); } @@ -515,6 +544,16 @@ real_t Curve::get_point_right_tangent(int i) const { return _points[i].right_tangent; } +Curve::TangentMode Curve::get_point_left_mode(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), TANGENT_FREE); + return _points[i].left_mode; +} + +Curve::TangentMode Curve::get_point_right_mode(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), TANGENT_FREE); + return _points[i].right_mode; +} + void Curve::remove_point(int p_index) { ERR_FAIL_INDEX(p_index, _points.size()); _points.remove(p_index); @@ -529,6 +568,7 @@ void Curve::clear_points() { void Curve::set_point_value(int p_index, real_t pos) { ERR_FAIL_INDEX(p_index, _points.size()); _points[p_index].pos.y = pos; + update_auto_tangents(p_index); mark_dirty(); } @@ -539,6 +579,11 @@ int Curve::set_point_offset(int p_index, float offset) { int i = add_point(Vector2(offset, p.pos.y)); _points[i].left_tangent = p.left_tangent; _points[i].right_tangent = p.right_tangent; + _points[i].left_mode = p.left_mode; + _points[i].right_mode = p.right_mode; + if (p_index != i) + update_auto_tangents(p_index); + update_auto_tangents(i); return i; } @@ -547,6 +592,58 @@ Vector2 Curve::get_point_pos(int p_index) const { return _points[p_index].pos; } +Curve::Point Curve::get_point(int p_index) const { + ERR_FAIL_INDEX_V(p_index, _points.size(), Point()); + return _points[p_index]; +} + +void Curve::update_auto_tangents(int i) { + + Point &p = _points[i]; + + if (i > 0) { + if (p.left_mode == TANGENT_LINEAR) { + Vector2 v = (_points[i - 1].pos - p.pos).normalized(); + p.left_tangent = v.y / v.x; + } + if (_points[i - 1].right_mode == TANGENT_LINEAR) { + Vector2 v = (_points[i - 1].pos - p.pos).normalized(); + _points[i - 1].right_tangent = v.y / v.x; + } + } + + if (i + 1 < _points.size()) { + if (p.right_mode == TANGENT_LINEAR && i + 1 < _points.size()) { + Vector2 v = (_points[i + 1].pos - p.pos).normalized(); + p.right_tangent = v.y / v.x; + } + if (_points[i + 1].left_mode == TANGENT_LINEAR) { + Vector2 v = (_points[i + 1].pos - p.pos).normalized(); + _points[i + 1].left_tangent = v.y / v.x; + } + } +} + +#define MIN_Y_RANGE 0.01 + +void Curve::set_min_value(float p_min) { + if (p_min > _max_value - MIN_Y_RANGE) + _min_value = _max_value - MIN_Y_RANGE; + else + _min_value = p_min; + // Note: min and max are indicative values, + // it's still possible that existing points are out of range at this point. + emit_signal(SIGNAL_RANGE_CHANGED); +} + +void Curve::set_max_value(float p_max) { + if (p_max < _min_value + MIN_Y_RANGE) + _max_value = _min_value + MIN_Y_RANGE; + else + _max_value = p_max; + emit_signal(SIGNAL_RANGE_CHANGED); +} + real_t Curve::interpolate(real_t offset) const { if (_points.size() == 0) return 0; @@ -606,48 +703,60 @@ void Curve::mark_dirty() { Array Curve::get_data() const { Array output; - output.resize(_points.size() * 3); + const unsigned int ELEMS = 5; + output.resize(_points.size() * ELEMS); for (int j = 0; j < _points.size(); ++j) { const Point p = _points[j]; - int i = j * 3; + int i = j * ELEMS; output[i] = p.pos; output[i + 1] = p.left_tangent; output[i + 2] = p.right_tangent; + output[i + 3] = p.left_mode; + output[i + 4] = p.right_mode; } return output; } void Curve::set_data(Array input) { - ERR_FAIL_COND(input.size() % 3 != 0); - -#ifdef TOOLS_ENABLED - if (_disable_set_data) - return; -#endif + const unsigned int ELEMS = 5; + ERR_FAIL_COND(input.size() % ELEMS != 0); _points.clear(); // Validate input - for (int i = 0; i < input.size(); i += 3) { + for (int i = 0; i < input.size(); i += ELEMS) { ERR_FAIL_COND(input[i].get_type() != Variant::VECTOR2); - ERR_FAIL_COND(input[i + 1].get_type() != Variant::REAL); + ERR_FAIL_COND(!input[i + 1].is_num()); ERR_FAIL_COND(input[i + 2].get_type() != Variant::REAL); + + ERR_FAIL_COND(input[i + 3].get_type() != Variant::INT); + int left_mode = input[i + 3]; + ERR_FAIL_COND(left_mode < 0 || left_mode >= TANGENT_MODE_COUNT); + + ERR_FAIL_COND(input[i + 4].get_type() != Variant::INT); + int right_mode = input[i + 4]; + ERR_FAIL_COND(right_mode < 0 || right_mode >= TANGENT_MODE_COUNT); } - _points.resize(input.size() / 3); + _points.resize(input.size() / ELEMS); for (int j = 0; j < _points.size(); ++j) { Point &p = _points[j]; - int i = j * 3; + int i = j * ELEMS; p.pos = input[i]; p.left_tangent = input[i + 1]; p.right_tangent = input[i + 2]; + // TODO For some reason the compiler won't convert from Variant to enum + int left_mode = input[i + 3]; + int right_mode = input[i + 4]; + p.left_mode = (TangentMode)left_mode; + p.right_mode = (TangentMode)right_mode; } mark_dirty(); @@ -716,18 +825,27 @@ real_t Curve::interpolate_baked(real_t offset) { void Curve::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_point", "pos", "left_tangent", "right_tangent"), &Curve::add_point, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_point", "pos", "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); ClassDB::bind_method(D_METHOD("get_point_pos", "index"), &Curve::get_point_pos); - ClassDB::bind_method(D_METHOD("set_point_value", "index, y"), &Curve::set_point_value); - ClassDB::bind_method(D_METHOD("set_point_offset", "index, offset"), &Curve::set_point_value); + ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value); + ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_value); ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate); ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked); ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent); ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_left_tangent); + ClassDB::bind_method(D_METHOD("get_point_left_mode", "index"), &Curve::get_point_left_mode); + ClassDB::bind_method(D_METHOD("get_point_right_mode", "index"), &Curve::get_point_left_mode); ClassDB::bind_method(D_METHOD("set_point_left_tangent", "index", "tangent"), &Curve::set_point_left_tangent); ClassDB::bind_method(D_METHOD("set_point_right_tangent", "index", "tangent"), &Curve::set_point_left_tangent); + ClassDB::bind_method(D_METHOD("set_point_left_mode", "index", "mode"), &Curve::set_point_left_mode); + ClassDB::bind_method(D_METHOD("set_point_right_mode", "index", "mode"), &Curve::set_point_left_mode); + ClassDB::bind_method(D_METHOD("get_min_value"), &Curve::get_min_value); + ClassDB::bind_method(D_METHOD("set_min_value", "min"), &Curve::set_min_value); + ClassDB::bind_method(D_METHOD("get_max_value"), &Curve::get_max_value); + ClassDB::bind_method(D_METHOD("set_max_value", "max"), &Curve::set_max_value); ClassDB::bind_method(D_METHOD("clean_dupes"), &Curve::clean_dupes); ClassDB::bind_method(D_METHOD("bake"), &Curve::bake); ClassDB::bind_method(D_METHOD("get_bake_resolution"), &Curve::get_bake_resolution); @@ -735,8 +853,12 @@ void Curve::_bind_methods() { ClassDB::bind_method(D_METHOD("_get_data"), &Curve::get_data); ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve::set_data); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_min_value", "get_min_value"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "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_NOEDITOR), "_set_data", "_get_data"); + + ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED)); } int Curve2D::get_point_count() const { |