diff options
Diffstat (limited to 'scene/2d/line_builder.cpp')
-rw-r--r-- | scene/2d/line_builder.cpp | 120 |
1 files changed, 79 insertions, 41 deletions
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)); } } |