1use hephaestus::backend::vello::VelloRenderer;
12use hephaestus::color::{rgb8, Color};
13use hephaestus::stroke::{Cap, Join, Stroke};
14use hephaestus::{
15 annular_wedge, clip_polyline, offset_polygon, polygon, round_corners, round_path_corners,
16 wedge, Affine, Brush, CornerRounding, EndClip, FillRule, Path, PickId, Point, PolygonOptions,
17 Rect, Renderer, SceneBuilder,
18};
19use kurbo::Shape;
20use std::f64::consts::PI;
21
22fn main() {
23 let mut renderer = VelloRenderer::new().expect("vello renderer init");
24 let (w, h) = (640u32, 800u32);
25
26 {
27 let scene = renderer.scene();
28 let reference_brush: Brush = rgb8(80, 80, 80).into();
29 let dotted = Stroke::new(1.0).with_dashes(0.0, vec![3.0, 4.0]);
30
31 let node_a_center = Point::new(120.0, 140.0);
34 let node_a_radius = 40.0;
35 let node_b = Rect::new(440.0, 100.0, 580.0, 180.0);
36
37 let node_brush: Brush = rgb8(60, 90, 140).into();
38 scene.fill(
39 FillRule::NonZero,
40 Affine::IDENTITY,
41 &node_brush,
42 None,
43 &kurbo::Circle::new(node_a_center, node_a_radius).to_path(0.1),
44 PickId::Skip,
45 );
46 scene.fill(
47 FillRule::NonZero,
48 Affine::IDENTITY,
49 &node_brush,
50 None,
51 &node_b.to_path(0.1),
52 PickId::Skip,
53 );
54
55 let raw = [
56 node_a_center,
57 Point::new(220.0, 60.0),
58 Point::new(340.0, 220.0),
59 Point::new(420.0, 80.0),
60 Point::new(node_b.center().x, node_b.center().y),
61 ];
62 let clipped = clip_polyline(
63 &raw,
64 Some(EndClip::Circle {
65 center: node_a_center,
66 radius: node_a_radius,
67 }),
68 Some(EndClip::Rect(node_b)),
69 );
70 let connector = round_corners(
71 &clipped,
72 false,
73 CornerRounding {
74 max_cut: 30.0,
75 ..Default::default()
76 },
77 );
78 let line_stroke = Stroke::new(4.0)
79 .with_caps(Cap::Round)
80 .with_join(Join::Round);
81 let line_brush: Brush = rgb8(230, 200, 120).into();
82 scene.stroke(
83 &line_stroke,
84 Affine::IDENTITY,
85 &line_brush,
86 None,
87 &connector,
88 PickId::Skip,
89 );
90 scene.stroke(
91 &dotted,
92 Affine::IDENTITY,
93 &reference_brush,
94 None,
95 &mk_polyline(&raw),
96 PickId::Skip,
97 );
98
99 let outer = [
102 Point::new(120.0, 320.0),
103 Point::new(520.0, 320.0),
104 Point::new(520.0, 500.0),
105 Point::new(120.0, 500.0),
106 ];
107 let hole = [
108 Point::new(240.0, 370.0),
109 Point::new(400.0, 370.0),
110 Point::new(400.0, 450.0),
111 Point::new(240.0, 450.0),
112 ];
113 let rings: [&[Point]; 2] = [&outer, &hole];
114
115 let plain = polygon(&rings, PolygonOptions::default());
116 scene.stroke(
117 &dotted,
118 Affine::IDENTITY,
119 &reference_brush,
120 None,
121 &plain,
122 PickId::Skip,
123 );
124
125 let inflated_rings = offset_polygon(&rings, 15.0, 4.0);
126 let mut inflated = Path::new();
127 for r in &inflated_rings {
128 let sub = round_corners(r, true, CornerRounding::default());
129 for el in sub.iter() {
130 inflated.push(el);
131 }
132 }
133 let fill_brush: Brush = rgb8(180, 70, 90).into();
134 scene.fill(
135 FillRule::NonZero,
136 Affine::IDENTITY,
137 &fill_brush,
138 None,
139 &inflated,
140 PickId::Skip,
141 );
142
143 let w_center = Point::new(170.0, 680.0);
147 let w_radius = 90.0;
148 let plain_wedge = wedge(w_center, w_radius, -PI / 2.0 - PI / 5.0, PI * 2.0 / 5.0);
149 scene.stroke(
150 &dotted,
151 Affine::IDENTITY,
152 &reference_brush,
153 None,
154 &plain_wedge,
155 PickId::Skip,
156 );
157 let rounded_wedge = round_path_corners(
158 &plain_wedge,
159 CornerRounding {
160 max_cut: 18.0,
161 ..Default::default()
162 },
163 );
164 let wedge_brush: Brush = rgb8(110, 160, 90).into();
165 scene.fill(
166 FillRule::NonZero,
167 Affine::IDENTITY,
168 &wedge_brush,
169 None,
170 &rounded_wedge,
171 PickId::Skip,
172 );
173
174 let a_center = Point::new(450.0, 680.0);
176 let plain_aw = annular_wedge(a_center, 35.0, 100.0, -PI / 2.0 - PI / 4.0, PI / 2.0);
177 scene.stroke(
178 &dotted,
179 Affine::IDENTITY,
180 &reference_brush,
181 None,
182 &plain_aw,
183 PickId::Skip,
184 );
185 let rounded_aw = round_path_corners(
186 &plain_aw,
187 CornerRounding {
188 max_cut: 14.0,
189 ..Default::default()
190 },
191 );
192 let aw_brush: Brush = rgb8(180, 130, 90).into();
193 scene.fill(
194 FillRule::NonZero,
195 Affine::IDENTITY,
196 &aw_brush,
197 None,
198 &rounded_aw,
199 PickId::Skip,
200 );
201 }
202
203 let mut pixels = vec![0u8; (w * h * 4) as usize];
204 let bg: Color = rgb8(20, 22, 28);
205 renderer
206 .render_to_buffer(w, h, bg, &mut pixels)
207 .expect("render");
208
209 let path = std::env::current_dir()
210 .unwrap()
211 .join("examples/primitives_demo.png");
212 hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
213 println!("wrote {}", path.display());
214}
215
216fn mk_polyline(pts: &[Point]) -> Path {
217 let mut p = Path::new();
218 p.move_to(pts[0]);
219 for v in &pts[1..] {
220 p.line_to(*v);
221 }
222 p
223}