Point2 TextureProgress::unit_val_to_uv(float val) { if (progress.is_null()) return Point2(); if (val < 0) val += 1; if (val > 1) val -= 1; Point2 p = get_relative_center(); if (val < 0.125) return Point2(p.x + (1 - p.x) * val * 8, 0); if (val < 0.25) return Point2(1, p.y * (val - 0.125) * 8); if (val < 0.375) return Point2(1, p.y + (1 - p.y) * (val - 0.25) * 8); if (val < 0.5) return Point2(1 - (1 - p.x) * (val - 0.375) * 8, 1); if (val < 0.625) return Point2(p.x * (1 - (val - 0.5) * 8), 1); if (val < 0.75) return Point2(0, 1 - ((1 - p.y) * (val - 0.625) * 8)); if (val < 0.875) return Point2(0, p.y - p.y * (val - 0.75) * 8); else return Point2(p.x * (val - 0.875) * 8, 0); }
Point2 TextureProgress::unit_val_to_uv(float val) { if (progress.is_null()) return Point2(); if (val < 0) val += 1; if (val > 1) val -= 1; Point2 p = get_relative_center(); // Minimal version of Liang-Barsky clipping algorithm float angle = (val * Math_TAU) - Math_PI * 0.5; Point2 dir = Vector2(Math::cos(angle), Math::sin(angle)); float t1 = 1.0; float cp; float cq; float cr; float edgeLeft = 0.0; float edgeRight = 1.0; float edgeBottom = 0.0; float edgeTop = 1.0; for (int edge = 0; edge < 4; edge++) { if (edge == 0) { if (dir.x > 0) continue; cp = -dir.x; cq = -(edgeLeft - p.x); } else if (edge == 1) { if (dir.x < 0) continue; cp = dir.x; cq = (edgeRight - p.x); } else if (edge == 2) { if (dir.y > 0) continue; cp = -dir.y; cq = -(edgeBottom - p.y); } else if (edge == 3) { if (dir.y < 0) continue; cp = dir.y; cq = (edgeTop - p.y); } cr = cq / cp; if (cr >= 0 && cr < t1) t1 = cr; } return (p + t1 * dir); }
void TextureProgress::_notification(int p_what) { const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 }; switch (p_what) { case NOTIFICATION_DRAW: { if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP)) { if (under.is_valid()) { draw_nine_patch_stretched(under, FILL_LEFT_TO_RIGHT, 1.0, tint_under); } if (progress.is_valid()) { draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress); } if (over.is_valid()) { draw_nine_patch_stretched(over, FILL_LEFT_TO_RIGHT, 1.0, tint_over); } } else { if (under.is_valid()) draw_texture(under, Point2(), tint_under); if (progress.is_valid()) { Size2 s = progress->get_size(); switch (mode) { case FILL_LEFT_TO_RIGHT: { Rect2 region = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_RIGHT_TO_LEFT: { Rect2 region = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_TOP_TO_BOTTOM: { Rect2 region = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_BOTTOM_TO_TOP: { Rect2 region = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { Rect2 region = Rect2(Point2(), s); draw_texture_rect_region(progress, region, region, tint_progress); } else if (val != 0) { Array pts; float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1; float start; if (mode == FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE) { start = rad_init_angle / 360 - val / 2; } else { start = rad_init_angle / 360; } float end = start + direction * val; pts.append(start); pts.append(end); float from = MIN(start, end); float to = MAX(start, end); for (int i = 0; i < 12; i++) if (corners[i] > from && corners[i] < to) pts.append(corners[i]); pts.sort(); Vector<Point2> uvs; Vector<Point2> points; uvs.push_back(get_relative_center()); points.push_back(Point2(s.x * get_relative_center().x, s.y * get_relative_center().y)); for (int i = 0; i < pts.size(); i++) { Point2 uv = unit_val_to_uv(pts[i]); if (uvs.find(uv) >= 0) continue; uvs.push_back(uv); points.push_back(Point2(uv.x * s.x, uv.y * s.y)); } Vector<Color> colors; colors.push_back(tint_progress); draw_polygon(points, colors, uvs, progress); } if (Engine::get_singleton()->is_editor_hint()) { Point2 p = progress->get_size(); p.x *= get_relative_center().x; p.y *= get_relative_center().y; p = p.floor(); draw_line(p - Point2(8, 0), p + Point2(8, 0), Color(0.9, 0.5, 0.5), 2); draw_line(p - Point2(0, 8), p + Point2(0, 8), Color(0.9, 0.5, 0.5), 2); } } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; default: draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); } } if (over.is_valid()) draw_texture(over, Point2(), tint_over); } } break; } }