blob: 099b4fef915d679c22cd810fa7617ef6e4190a5d [file]
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Clip example showing deeply nested clipping.
#![expect(
clippy::cast_possible_truncation,
reason = "We temporarily ignore those because the casts\
only break in edge cases, and some of them are also only related to conversions from f64 to f32."
)]
use crate::{ExampleScene, RenderingContext};
use vello_common::color::palette::css::{
BLACK, BLUE, DARK_BLUE, DARK_GREEN, GREEN, REBECCA_PURPLE, RED,
};
use vello_common::kurbo::{Affine, BezPath, Circle, Point, Rect, Shape, Stroke};
use vello_common::peniko::Color;
/// Clip scene state
#[derive(Debug)]
pub struct ClipScene {}
impl ExampleScene for ClipScene {
fn render(&mut self, ctx: &mut impl RenderingContext, root_transform: Affine) {
render(ctx, root_transform);
}
}
impl ClipScene {
/// Create a new `ClipScene`
pub fn new() -> Self {
Self {}
}
}
impl Default for ClipScene {
fn default() -> Self {
Self::new()
}
}
fn draw_clipping_outline(ctx: &mut impl RenderingContext, path: &BezPath) {
let stroke = Stroke::new(1.0);
ctx.set_paint(DARK_BLUE);
ctx.set_stroke(stroke);
ctx.stroke_path(path);
}
/// Draws a deeply nested clip of circles.
pub fn render(ctx: &mut impl RenderingContext, root_transform: Affine) {
const INITIAL_RADIUS: f64 = 48.0;
const RADIUS_DECREMENT: f64 = 2.5;
const INNER_COUNT: usize = 10;
// `.ceil()` is not constant-evaluatable, so we have to do this at runtime.
let outer_count: usize =
(INITIAL_RADIUS / RADIUS_DECREMENT / INNER_COUNT as f64).ceil() as usize;
const COLORS: [Color; INNER_COUNT] = [
RED,
DARK_BLUE,
DARK_GREEN,
REBECCA_PURPLE,
BLACK,
BLUE,
GREEN,
RED,
DARK_BLUE,
DARK_GREEN,
];
const COVER_RECT: Rect = Rect::new(0.0, 0.0, 100.0, 100.0);
const CENTER: Point = Point::new(50.0, 50.0);
let mut radius = INITIAL_RADIUS;
ctx.set_transform(root_transform);
for _ in 0..outer_count {
for color in COLORS.iter() {
let clip_circle = Circle::new(CENTER, radius).to_path(0.1);
draw_clipping_outline(ctx, &clip_circle);
ctx.push_clip_layer(&clip_circle);
ctx.set_paint(*color);
ctx.fill_rect(&COVER_RECT);
radius -= RADIUS_DECREMENT;
}
}
for _ in 0..outer_count {
for _ in COLORS.iter() {
ctx.pop_layer();
}
}
}