diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2019-07-01 09:38:54 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-01 09:38:54 +0200 |
commit | e4a50999c04094f905ac7df46b14634d7f9552a7 (patch) | |
tree | f9cdb5fc6ab6736c10805d4fbd11a9c6005cd57f /scene/2d | |
parent | bbb725836d67c5bdae020db078afaca27a597d36 (diff) | |
parent | 14f8ed3317b0ece7fe2aac1595bb8ece63a81f7a (diff) |
Merge pull request #28565 from CedNaru/CurvedWidthLine2D
Added a Width Curve to Line2D + UVs fix
Diffstat (limited to 'scene/2d')
-rw-r--r-- | scene/2d/line_2d.cpp | 100 | ||||
-rw-r--r-- | scene/2d/line_2d.h | 5 | ||||
-rw-r--r-- | scene/2d/line_builder.cpp | 120 | ||||
-rw-r--r-- | scene/2d/line_builder.h | 1 |
4 files changed, 150 insertions, 76 deletions
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 1c8245d159..ad405fabbb 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -84,10 +84,10 @@ void Line2D::set_points(const PoolVector<Vector2> &p_points) { update(); } -void Line2D::set_width(float width) { - if (width < 0.0) - width = 0.0; - _width = width; +void Line2D::set_width(float p_width) { + if (p_width < 0.0) + p_width = 0.0; + _width = p_width; update(); } @@ -95,12 +95,32 @@ float Line2D::get_width() const { return _width; } +void Line2D::set_curve(const Ref<Curve> &p_curve) { + // Cleanup previous connection if any + if (_curve.is_valid()) { + _curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + } + + _curve = p_curve; + + // Connect to the curve so the line will update when it is changed + if (_curve.is_valid()) { + _curve->connect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + } + + update(); +} + +Ref<Curve> Line2D::get_curve() const { + return _curve; +} + PoolVector<Vector2> Line2D::get_points() const { return _points; } -void Line2D::set_point_position(int i, Vector2 pos) { - _points.set(i, pos); +void Line2D::set_point_position(int i, Vector2 p_pos) { + _points.set(i, p_pos); update(); } @@ -121,11 +141,11 @@ void Line2D::clear_points() { } } -void Line2D::add_point(Vector2 pos, int atpos) { - if (atpos < 0 || _points.size() < atpos) { - _points.append(pos); +void Line2D::add_point(Vector2 p_pos, int p_atpos) { + if (p_atpos < 0 || _points.size() < p_atpos) { + _points.append(p_pos); } else { - _points.insert(atpos, pos); + _points.insert(p_atpos, p_pos); } update(); } @@ -135,8 +155,8 @@ void Line2D::remove_point(int i) { update(); } -void Line2D::set_default_color(Color color) { - _default_color = color; +void Line2D::set_default_color(Color p_color) { + _default_color = p_color; update(); } @@ -144,18 +164,18 @@ Color Line2D::get_default_color() const { return _default_color; } -void Line2D::set_gradient(const Ref<Gradient> &gradient) { +void Line2D::set_gradient(const Ref<Gradient> &p_gradient) { // Cleanup previous connection if any if (_gradient.is_valid()) { - (**_gradient).disconnect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); + _gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); } - _gradient = gradient; + _gradient = p_gradient; // Connect to the gradient so the line will update when the ColorRamp is changed if (_gradient.is_valid()) { - (**_gradient).connect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); + _gradient->connect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); } update(); @@ -165,8 +185,8 @@ Ref<Gradient> Line2D::get_gradient() const { return _gradient; } -void Line2D::set_texture(const Ref<Texture> &texture) { - _texture = texture; +void Line2D::set_texture(const Ref<Texture> &p_texture) { + _texture = p_texture; update(); } @@ -174,8 +194,8 @@ Ref<Texture> Line2D::get_texture() const { return _texture; } -void Line2D::set_texture_mode(const LineTextureMode mode) { - _texture_mode = mode; +void Line2D::set_texture_mode(const LineTextureMode p_mode) { + _texture_mode = p_mode; update(); } @@ -183,8 +203,8 @@ Line2D::LineTextureMode Line2D::get_texture_mode() const { return _texture_mode; } -void Line2D::set_joint_mode(LineJointMode mode) { - _joint_mode = mode; +void Line2D::set_joint_mode(LineJointMode p_mode) { + _joint_mode = p_mode; update(); } @@ -192,8 +212,8 @@ Line2D::LineJointMode Line2D::get_joint_mode() const { return _joint_mode; } -void Line2D::set_begin_cap_mode(LineCapMode mode) { - _begin_cap_mode = mode; +void Line2D::set_begin_cap_mode(LineCapMode p_mode) { + _begin_cap_mode = p_mode; update(); } @@ -201,8 +221,8 @@ Line2D::LineCapMode Line2D::get_begin_cap_mode() const { return _begin_cap_mode; } -void Line2D::set_end_cap_mode(LineCapMode mode) { - _end_cap_mode = mode; +void Line2D::set_end_cap_mode(LineCapMode p_mode) { + _end_cap_mode = p_mode; update(); } @@ -218,10 +238,10 @@ void Line2D::_notification(int p_what) { } } -void Line2D::set_sharp_limit(float limit) { - if (limit < 0.f) - limit = 0.f; - _sharp_limit = limit; +void Line2D::set_sharp_limit(float p_limit) { + if (p_limit < 0.f) + p_limit = 0.f; + _sharp_limit = p_limit; update(); } @@ -229,10 +249,10 @@ float Line2D::get_sharp_limit() const { return _sharp_limit; } -void Line2D::set_round_precision(int precision) { - if (precision < 1) - precision = 1; - _round_precision = precision; +void Line2D::set_round_precision(int p_precision) { + if (p_precision < 1) + p_precision = 1; + _round_precision = p_precision; update(); } @@ -268,10 +288,11 @@ void Line2D::_draw() { lb.round_precision = _round_precision; lb.sharp_limit = _sharp_limit; lb.width = _width; + lb.curve = *_curve; RID texture_rid; if (_texture.is_valid()) { - texture_rid = (**_texture).get_rid(); + texture_rid = _texture->get_rid(); lb.tile_aspect = _texture->get_size().aspect(); } @@ -312,6 +333,10 @@ void Line2D::_gradient_changed() { update(); } +void Line2D::_curve_changed() { + update(); +} + // static void Line2D::_bind_methods() { @@ -331,6 +356,9 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width); ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width); + ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Line2D::set_curve); + ClassDB::bind_method(D_METHOD("get_curve"), &Line2D::get_curve); + ClassDB::bind_method(D_METHOD("set_default_color", "color"), &Line2D::set_default_color); ClassDB::bind_method(D_METHOD("get_default_color"), &Line2D::get_default_color); @@ -360,6 +388,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "width_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color"); ADD_GROUP("Fill", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); @@ -386,4 +415,5 @@ void Line2D::_bind_methods() { BIND_ENUM_CONSTANT(LINE_TEXTURE_STRETCH); ClassDB::bind_method(D_METHOD("_gradient_changed"), &Line2D::_gradient_changed); + ClassDB::bind_method(D_METHOD("_curve_changed"), &Line2D::_curve_changed); } diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 11be5055d4..14afa463ba 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -78,6 +78,9 @@ public: void set_width(float width); float get_width() const; + void set_curve(const Ref<Curve> &curve); + Ref<Curve> get_curve() const; + void set_default_color(Color color); Color get_default_color() const; @@ -113,6 +116,7 @@ protected: private: void _gradient_changed(); + void _curve_changed(); private: PoolVector<Vector2> _points; @@ -120,6 +124,7 @@ private: LineCapMode _begin_cap_mode; LineCapMode _end_cap_mode; float _width; + Ref<Curve> _curve; Color _default_color; Ref<Gradient> _gradient; Ref<Texture> _texture; diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index eb09d3c9d3..9fe5fb98b6 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -95,6 +95,7 @@ static inline Vector2 interpolate(const Rect2 &r, const Vector2 &v) { LineBuilder::LineBuilder() { joint_mode = Line2D::LINE_JOINT_SHARP; width = 10; + curve = NULL; default_color = Color(0.4, 0.5, 1); gradient = NULL; sharp_limit = 2.f; @@ -136,8 +137,8 @@ void LineBuilder::build() { Vector2 pos1 = points[1]; Vector2 f0 = (pos1 - pos0).normalized(); Vector2 u0 = rotate90(f0); - Vector2 pos_up0 = pos0 + u0 * hw; - Vector2 pos_down0 = pos0 - u0 * hw; + Vector2 pos_up0 = pos0; + Vector2 pos_down0 = pos0; Color color0; Color color1; @@ -145,12 +146,30 @@ void LineBuilder::build() { float current_distance0 = 0.f; float current_distance1 = 0.f; float total_distance = 0.f; + float width_factor = 1.f; _interpolate_color = gradient != NULL; + bool retrieve_curve = curve != NULL; bool distance_required = _interpolate_color || + retrieve_curve || texture_mode == Line2D::LINE_TEXTURE_TILE || texture_mode == Line2D::LINE_TEXTURE_STRETCH; - if (distance_required) + if (distance_required) { total_distance = calculate_total_distance(points); + //Ajust totalDistance. + // The line's outer length will be a little higher due to begin and end caps + if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) { + if (retrieve_curve) + total_distance += width * curve->interpolate_baked(0.f) * 0.5f; + else + total_distance += width * 0.5f; + } + if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) { + if (retrieve_curve) + total_distance += width * curve->interpolate_baked(1.f) * 0.5f; + else + total_distance += width * 0.5f; + } + } if (_interpolate_color) color0 = gradient->get_color(0); else @@ -159,22 +178,28 @@ void LineBuilder::build() { float uvx0 = 0.f; float uvx1 = 0.f; + if (retrieve_curve) + width_factor = curve->interpolate_baked(0.f); + + pos_up0 += u0 * hw * width_factor; + pos_down0 -= u0 * hw * width_factor; + // Begin cap if (begin_cap_mode == Line2D::LINE_CAP_BOX) { // Push back first vertices a little bit - pos_up0 -= f0 * hw; - pos_down0 -= f0 * hw; - // The line's outer length will be a little higher due to begin and end caps - total_distance += width; - current_distance0 += hw; + pos_up0 -= f0 * hw * width_factor; + pos_down0 -= f0 * hw * width_factor; + + current_distance0 += hw * width_factor; current_distance1 = current_distance0; } else if (begin_cap_mode == Line2D::LINE_CAP_ROUND) { if (texture_mode == Line2D::LINE_TEXTURE_TILE) { - uvx0 = 0.5f / tile_aspect; + uvx0 = width_factor * 0.5f / tile_aspect; + } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { + uvx0 = width * width_factor / total_distance; } - new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, fmin(uvx0 * 2, 1.f), 1.f)); - total_distance += width; - current_distance0 += hw; + new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, uvx0 * 2, 1.f)); + current_distance0 += hw * width_factor; current_distance1 = current_distance0; } @@ -206,13 +231,23 @@ void LineBuilder::build() { const float dp = u0.dot(f1); const Orientation orientation = (dp > 0.f ? UP : DOWN); + if (distance_required) { + current_distance1 += pos0.distance_to(pos1); + } + if (_interpolate_color) { + color1 = gradient->get_color_at_offset(current_distance1 / total_distance); + } + if (retrieve_curve) { + width_factor = curve->interpolate_baked(current_distance1 / total_distance); + } + Vector2 inner_normal0, inner_normal1; if (orientation == UP) { - inner_normal0 = u0 * hw; - inner_normal1 = u1 * hw; + inner_normal0 = u0 * hw * width_factor; + inner_normal1 = u1 * hw * width_factor; } else { - inner_normal0 = -u0 * hw; - inner_normal1 = -u1 * hw; + inner_normal0 = -u0 * hw * width_factor; + inner_normal1 = -u1 * hw * width_factor; } /* @@ -259,7 +294,8 @@ void LineBuilder::build() { Vector2 pos_up1, pos_down1; if (intersection_result == SEGMENT_INTERSECT) { // Fallback on bevel if sharp angle is too high (because it would produce very long miters) - if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / hw_sq > sharp_limit_sq) { + float width_factor_sq = width_factor * width_factor; + if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / (hw_sq * width_factor_sq) > sharp_limit_sq) { current_joint_mode = Line2D::LINE_JOINT_BEVEL; } if (current_joint_mode == Line2D::LINE_JOINT_SHARP) { @@ -271,9 +307,9 @@ void LineBuilder::build() { // Bevel or round if (orientation == UP) { pos_up1 = corner_pos_up; - pos_down1 = pos1 - u0 * hw; + pos_down1 = pos1 - u0 * hw * width_factor; } else { - pos_up1 = pos1 + u0 * hw; + pos_up1 = pos1 + u0 * hw * width_factor; pos_down1 = corner_pos_down; } } @@ -289,12 +325,6 @@ void LineBuilder::build() { // Add current line body quad // Triangles are clockwise - if (distance_required) { - current_distance1 += pos0.distance_to(pos1); - } - if (_interpolate_color) { - color1 = gradient->get_color_at_offset(current_distance1 / total_distance); - } if (texture_mode == Line2D::LINE_TEXTURE_TILE) { uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { @@ -315,15 +345,15 @@ void LineBuilder::build() { } else { if (orientation == UP) { pos_up0 = corner_pos_up; - pos_down0 = pos1 - u1 * hw; + pos_down0 = pos1 - u1 * hw * width_factor; } else { - pos_up0 = pos1 + u1 * hw; + pos_up0 = pos1 + u1 * hw * width_factor; pos_down0 = corner_pos_down; } } } else { - pos_up0 = pos1 + u1 * hw; - pos_down0 = pos1 - u1 * hw; + pos_up0 = pos1 + u1 * hw * width_factor; + pos_down0 = pos1 - u1 * hw * width_factor; } // From this point, bu0 and bd0 concern the next segment @@ -362,26 +392,28 @@ void LineBuilder::build() { strip_begin(pos_up0, pos_down0, color1, uvx1); } } - // Last (or only) segment - pos1 = points[points.size() - 1]; - Vector2 pos_up1 = pos1 + u0 * hw; - Vector2 pos_down1 = pos1 - u0 * hw; - - // End cap (box) - if (end_cap_mode == Line2D::LINE_CAP_BOX) { - pos_up1 += f0 * hw; - pos_down1 += f0 * hw; - } - if (distance_required) { current_distance1 += pos0.distance_to(pos1); } if (_interpolate_color) { color1 = gradient->get_color(gradient->get_points_count() - 1); } + if (retrieve_curve) { + width_factor = curve->interpolate_baked(1.f); + } + + Vector2 pos_up1 = pos1 + u0 * hw * width_factor; + Vector2 pos_down1 = pos1 - u0 * hw * width_factor; + + // End cap (box) + if (end_cap_mode == Line2D::LINE_CAP_BOX) { + pos_up1 += f0 * hw * width_factor; + pos_down1 += f0 * hw * width_factor; + } + if (texture_mode == Line2D::LINE_TEXTURE_TILE) { uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { @@ -394,7 +426,13 @@ void LineBuilder::build() { if (end_cap_mode == Line2D::LINE_CAP_ROUND) { // Note: color is not used in case we don't interpolate... Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0); - new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f / tile_aspect, 0.f, 1.0f / tile_aspect, 1.f)); + float dist = 0; + if (texture_mode == Line2D::LINE_TEXTURE_TILE) { + dist = width_factor / tile_aspect; + } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { + dist = width * width_factor / total_distance; + } + new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f * dist, 0.f, dist, 1.f)); } } diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index b961385e33..91b4518f9b 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -45,6 +45,7 @@ public: Line2D::LineCapMode begin_cap_mode; Line2D::LineCapMode end_cap_mode; float width; + Curve *curve; Color default_color; Gradient *gradient; Line2D::LineTextureMode texture_mode; |