1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Added a Width Curve to Line2D + UVs fix

This commit is contained in:
Tristan Grespinet
2019-05-01 06:50:01 +02:00
parent dd2cd06165
commit 14f8ed3317
5 changed files with 153 additions and 76 deletions

View File

@@ -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));
}
}