Skip to main content

hello_hybrid/
hello_hybrid.rs

1//! The `hello` scene through the sparse-strips backend, for eyeballing the two
2//! against each other. Writes `examples/hello_hybrid.png` in the project root;
3//! `examples/hello.png` is the compute-shader backend's version of the same
4//! drawing.
5
6use hephaestus::backend::hybrid::HybridRenderer;
7use hephaestus::brush::Gradient;
8use hephaestus::color::{rgb, rgb8, rgba, Color};
9use hephaestus::stroke::{Cap, Join, Stroke};
10use hephaestus::{
11    Affine, BlendMode, Brush, Compose, FillRule, Mix, Path, PickId, Point, Rect, Renderer,
12    SceneBuilder,
13};
14use kurbo::Shape;
15
16fn main() {
17    let mut renderer = HybridRenderer::new().expect("hybrid renderer init");
18    let (w, h) = (512u32, 512u32);
19
20    {
21        let scene = renderer.scene();
22
23        // 1. Filled rectangle (solid brush)
24        let rect = Rect::new(40.0, 40.0, 240.0, 200.0).to_path(0.1);
25        let solid: Brush = rgb8(60, 120, 200).into();
26        scene.fill(
27            FillRule::NonZero,
28            Affine::IDENTITY,
29            &solid,
30            None,
31            &rect,
32            PickId::Skip,
33        );
34
35        // 2. Stroked open polyline with round caps/joins
36        let mut poly = Path::new();
37        poly.move_to(Point::new(60.0, 300.0));
38        poly.line_to(Point::new(140.0, 360.0));
39        poly.line_to(Point::new(200.0, 280.0));
40        poly.line_to(Point::new(260.0, 380.0));
41        let stroke = Stroke::new(8.0)
42            .with_caps(Cap::Round)
43            .with_join(Join::Round);
44        let line_brush: Brush = rgb8(220, 220, 220).into();
45        scene.stroke(
46            &stroke,
47            Affine::IDENTITY,
48            &line_brush,
49            None,
50            &poly,
51            PickId::Skip,
52        );
53
54        // 3. Gradient-filled circle
55        let circle = kurbo::Circle::new(Point::new(380.0, 150.0), 90.0).to_path(0.1);
56        let gradient = Gradient::new_linear(Point::new(290.0, 60.0), Point::new(470.0, 240.0))
57            .with_stops([rgb(0.95, 0.55, 0.15), rgb(0.15, 0.05, 0.45)].as_slice());
58        let grad_brush: Brush = gradient.into();
59        scene.fill(
60            FillRule::NonZero,
61            Affine::IDENTITY,
62            &grad_brush,
63            None,
64            &circle,
65            PickId::Skip,
66        );
67
68        // 4. Multiply layer with a translucent square overlapping the rect
69        let layer_clip = Rect::new(0.0, 0.0, w as f64, h as f64).to_path(0.1);
70        scene.push_layer(
71            BlendMode::new(Mix::Multiply, Compose::SrcOver),
72            1.0,
73            Affine::IDENTITY,
74            &layer_clip,
75        );
76        let overlap = Rect::new(160.0, 120.0, 360.0, 320.0).to_path(0.1);
77        let overlap_brush: Brush = rgba(1.0, 0.85, 0.2, 0.7).into();
78        scene.fill(
79            FillRule::NonZero,
80            Affine::IDENTITY,
81            &overlap_brush,
82            None,
83            &overlap,
84            PickId::Skip,
85        );
86        scene.pop_layer();
87    }
88
89    let mut pixels = vec![0u8; (w * h * 4) as usize];
90    let bg: Color = rgb8(20, 22, 28);
91    renderer
92        .render_to_buffer(w, h, bg, &mut pixels)
93        .expect("render");
94
95    let path = std::env::current_dir()
96        .unwrap()
97        .join("examples/hello_hybrid.png");
98    hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
99    println!("wrote {}", path.display());
100}