epaint/
tessellator.rs

1//! Converts graphics primitives into textured triangles.
2//!
3//! This module converts lines, circles, text and more represented by [`Shape`]
4//! into textured triangles represented by [`Mesh`].
5
6#![allow(clippy::identity_op)]
7
8use emath::{pos2, remap, vec2, GuiRounding as _, NumExt, Pos2, Rect, Rot2, Vec2};
9
10use crate::{
11    color::ColorMode, emath, stroke::PathStroke, texture_atlas::PreparedDisc, CircleShape,
12    ClippedPrimitive, ClippedShape, Color32, CornerRadiusF32, CubicBezierShape, EllipseShape, Mesh,
13    PathShape, Primitive, QuadraticBezierShape, RectShape, Shape, Stroke, StrokeKind, TextShape,
14    TextureId, Vertex, WHITE_UV,
15};
16
17// ----------------------------------------------------------------------------
18
19#[allow(clippy::approx_constant)]
20mod precomputed_vertices {
21    // fn main() {
22    //     let n = 64;
23    //     println!("pub const CIRCLE_{}: [Vec2; {}] = [", n, n+1);
24    //     for i in 0..=n {
25    //         let a = std::f64::consts::TAU * i as f64 / n as f64;
26    //         println!("    vec2({:.06}, {:.06}),", a.cos(), a.sin());
27    //     }
28    //     println!("];")
29    // }
30
31    use emath::{vec2, Vec2};
32
33    pub const CIRCLE_8: [Vec2; 9] = [
34        vec2(1.000000, 0.000000),
35        vec2(0.707107, 0.707107),
36        vec2(0.000000, 1.000000),
37        vec2(-0.707107, 0.707107),
38        vec2(-1.000000, 0.000000),
39        vec2(-0.707107, -0.707107),
40        vec2(0.000000, -1.000000),
41        vec2(0.707107, -0.707107),
42        vec2(1.000000, 0.000000),
43    ];
44
45    pub const CIRCLE_16: [Vec2; 17] = [
46        vec2(1.000000, 0.000000),
47        vec2(0.923880, 0.382683),
48        vec2(0.707107, 0.707107),
49        vec2(0.382683, 0.923880),
50        vec2(0.000000, 1.000000),
51        vec2(-0.382684, 0.923880),
52        vec2(-0.707107, 0.707107),
53        vec2(-0.923880, 0.382683),
54        vec2(-1.000000, 0.000000),
55        vec2(-0.923880, -0.382683),
56        vec2(-0.707107, -0.707107),
57        vec2(-0.382684, -0.923880),
58        vec2(0.000000, -1.000000),
59        vec2(0.382684, -0.923879),
60        vec2(0.707107, -0.707107),
61        vec2(0.923880, -0.382683),
62        vec2(1.000000, 0.000000),
63    ];
64
65    pub const CIRCLE_32: [Vec2; 33] = [
66        vec2(1.000000, 0.000000),
67        vec2(0.980785, 0.195090),
68        vec2(0.923880, 0.382683),
69        vec2(0.831470, 0.555570),
70        vec2(0.707107, 0.707107),
71        vec2(0.555570, 0.831470),
72        vec2(0.382683, 0.923880),
73        vec2(0.195090, 0.980785),
74        vec2(0.000000, 1.000000),
75        vec2(-0.195090, 0.980785),
76        vec2(-0.382683, 0.923880),
77        vec2(-0.555570, 0.831470),
78        vec2(-0.707107, 0.707107),
79        vec2(-0.831470, 0.555570),
80        vec2(-0.923880, 0.382683),
81        vec2(-0.980785, 0.195090),
82        vec2(-1.000000, 0.000000),
83        vec2(-0.980785, -0.195090),
84        vec2(-0.923880, -0.382683),
85        vec2(-0.831470, -0.555570),
86        vec2(-0.707107, -0.707107),
87        vec2(-0.555570, -0.831470),
88        vec2(-0.382683, -0.923880),
89        vec2(-0.195090, -0.980785),
90        vec2(-0.000000, -1.000000),
91        vec2(0.195090, -0.980785),
92        vec2(0.382683, -0.923880),
93        vec2(0.555570, -0.831470),
94        vec2(0.707107, -0.707107),
95        vec2(0.831470, -0.555570),
96        vec2(0.923880, -0.382683),
97        vec2(0.980785, -0.195090),
98        vec2(1.000000, -0.000000),
99    ];
100
101    pub const CIRCLE_64: [Vec2; 65] = [
102        vec2(1.000000, 0.000000),
103        vec2(0.995185, 0.098017),
104        vec2(0.980785, 0.195090),
105        vec2(0.956940, 0.290285),
106        vec2(0.923880, 0.382683),
107        vec2(0.881921, 0.471397),
108        vec2(0.831470, 0.555570),
109        vec2(0.773010, 0.634393),
110        vec2(0.707107, 0.707107),
111        vec2(0.634393, 0.773010),
112        vec2(0.555570, 0.831470),
113        vec2(0.471397, 0.881921),
114        vec2(0.382683, 0.923880),
115        vec2(0.290285, 0.956940),
116        vec2(0.195090, 0.980785),
117        vec2(0.098017, 0.995185),
118        vec2(0.000000, 1.000000),
119        vec2(-0.098017, 0.995185),
120        vec2(-0.195090, 0.980785),
121        vec2(-0.290285, 0.956940),
122        vec2(-0.382683, 0.923880),
123        vec2(-0.471397, 0.881921),
124        vec2(-0.555570, 0.831470),
125        vec2(-0.634393, 0.773010),
126        vec2(-0.707107, 0.707107),
127        vec2(-0.773010, 0.634393),
128        vec2(-0.831470, 0.555570),
129        vec2(-0.881921, 0.471397),
130        vec2(-0.923880, 0.382683),
131        vec2(-0.956940, 0.290285),
132        vec2(-0.980785, 0.195090),
133        vec2(-0.995185, 0.098017),
134        vec2(-1.000000, 0.000000),
135        vec2(-0.995185, -0.098017),
136        vec2(-0.980785, -0.195090),
137        vec2(-0.956940, -0.290285),
138        vec2(-0.923880, -0.382683),
139        vec2(-0.881921, -0.471397),
140        vec2(-0.831470, -0.555570),
141        vec2(-0.773010, -0.634393),
142        vec2(-0.707107, -0.707107),
143        vec2(-0.634393, -0.773010),
144        vec2(-0.555570, -0.831470),
145        vec2(-0.471397, -0.881921),
146        vec2(-0.382683, -0.923880),
147        vec2(-0.290285, -0.956940),
148        vec2(-0.195090, -0.980785),
149        vec2(-0.098017, -0.995185),
150        vec2(-0.000000, -1.000000),
151        vec2(0.098017, -0.995185),
152        vec2(0.195090, -0.980785),
153        vec2(0.290285, -0.956940),
154        vec2(0.382683, -0.923880),
155        vec2(0.471397, -0.881921),
156        vec2(0.555570, -0.831470),
157        vec2(0.634393, -0.773010),
158        vec2(0.707107, -0.707107),
159        vec2(0.773010, -0.634393),
160        vec2(0.831470, -0.555570),
161        vec2(0.881921, -0.471397),
162        vec2(0.923880, -0.382683),
163        vec2(0.956940, -0.290285),
164        vec2(0.980785, -0.195090),
165        vec2(0.995185, -0.098017),
166        vec2(1.000000, -0.000000),
167    ];
168
169    pub const CIRCLE_128: [Vec2; 129] = [
170        vec2(1.000000, 0.000000),
171        vec2(0.998795, 0.049068),
172        vec2(0.995185, 0.098017),
173        vec2(0.989177, 0.146730),
174        vec2(0.980785, 0.195090),
175        vec2(0.970031, 0.242980),
176        vec2(0.956940, 0.290285),
177        vec2(0.941544, 0.336890),
178        vec2(0.923880, 0.382683),
179        vec2(0.903989, 0.427555),
180        vec2(0.881921, 0.471397),
181        vec2(0.857729, 0.514103),
182        vec2(0.831470, 0.555570),
183        vec2(0.803208, 0.595699),
184        vec2(0.773010, 0.634393),
185        vec2(0.740951, 0.671559),
186        vec2(0.707107, 0.707107),
187        vec2(0.671559, 0.740951),
188        vec2(0.634393, 0.773010),
189        vec2(0.595699, 0.803208),
190        vec2(0.555570, 0.831470),
191        vec2(0.514103, 0.857729),
192        vec2(0.471397, 0.881921),
193        vec2(0.427555, 0.903989),
194        vec2(0.382683, 0.923880),
195        vec2(0.336890, 0.941544),
196        vec2(0.290285, 0.956940),
197        vec2(0.242980, 0.970031),
198        vec2(0.195090, 0.980785),
199        vec2(0.146730, 0.989177),
200        vec2(0.098017, 0.995185),
201        vec2(0.049068, 0.998795),
202        vec2(0.000000, 1.000000),
203        vec2(-0.049068, 0.998795),
204        vec2(-0.098017, 0.995185),
205        vec2(-0.146730, 0.989177),
206        vec2(-0.195090, 0.980785),
207        vec2(-0.242980, 0.970031),
208        vec2(-0.290285, 0.956940),
209        vec2(-0.336890, 0.941544),
210        vec2(-0.382683, 0.923880),
211        vec2(-0.427555, 0.903989),
212        vec2(-0.471397, 0.881921),
213        vec2(-0.514103, 0.857729),
214        vec2(-0.555570, 0.831470),
215        vec2(-0.595699, 0.803208),
216        vec2(-0.634393, 0.773010),
217        vec2(-0.671559, 0.740951),
218        vec2(-0.707107, 0.707107),
219        vec2(-0.740951, 0.671559),
220        vec2(-0.773010, 0.634393),
221        vec2(-0.803208, 0.595699),
222        vec2(-0.831470, 0.555570),
223        vec2(-0.857729, 0.514103),
224        vec2(-0.881921, 0.471397),
225        vec2(-0.903989, 0.427555),
226        vec2(-0.923880, 0.382683),
227        vec2(-0.941544, 0.336890),
228        vec2(-0.956940, 0.290285),
229        vec2(-0.970031, 0.242980),
230        vec2(-0.980785, 0.195090),
231        vec2(-0.989177, 0.146730),
232        vec2(-0.995185, 0.098017),
233        vec2(-0.998795, 0.049068),
234        vec2(-1.000000, 0.000000),
235        vec2(-0.998795, -0.049068),
236        vec2(-0.995185, -0.098017),
237        vec2(-0.989177, -0.146730),
238        vec2(-0.980785, -0.195090),
239        vec2(-0.970031, -0.242980),
240        vec2(-0.956940, -0.290285),
241        vec2(-0.941544, -0.336890),
242        vec2(-0.923880, -0.382683),
243        vec2(-0.903989, -0.427555),
244        vec2(-0.881921, -0.471397),
245        vec2(-0.857729, -0.514103),
246        vec2(-0.831470, -0.555570),
247        vec2(-0.803208, -0.595699),
248        vec2(-0.773010, -0.634393),
249        vec2(-0.740951, -0.671559),
250        vec2(-0.707107, -0.707107),
251        vec2(-0.671559, -0.740951),
252        vec2(-0.634393, -0.773010),
253        vec2(-0.595699, -0.803208),
254        vec2(-0.555570, -0.831470),
255        vec2(-0.514103, -0.857729),
256        vec2(-0.471397, -0.881921),
257        vec2(-0.427555, -0.903989),
258        vec2(-0.382683, -0.923880),
259        vec2(-0.336890, -0.941544),
260        vec2(-0.290285, -0.956940),
261        vec2(-0.242980, -0.970031),
262        vec2(-0.195090, -0.980785),
263        vec2(-0.146730, -0.989177),
264        vec2(-0.098017, -0.995185),
265        vec2(-0.049068, -0.998795),
266        vec2(-0.000000, -1.000000),
267        vec2(0.049068, -0.998795),
268        vec2(0.098017, -0.995185),
269        vec2(0.146730, -0.989177),
270        vec2(0.195090, -0.980785),
271        vec2(0.242980, -0.970031),
272        vec2(0.290285, -0.956940),
273        vec2(0.336890, -0.941544),
274        vec2(0.382683, -0.923880),
275        vec2(0.427555, -0.903989),
276        vec2(0.471397, -0.881921),
277        vec2(0.514103, -0.857729),
278        vec2(0.555570, -0.831470),
279        vec2(0.595699, -0.803208),
280        vec2(0.634393, -0.773010),
281        vec2(0.671559, -0.740951),
282        vec2(0.707107, -0.707107),
283        vec2(0.740951, -0.671559),
284        vec2(0.773010, -0.634393),
285        vec2(0.803208, -0.595699),
286        vec2(0.831470, -0.555570),
287        vec2(0.857729, -0.514103),
288        vec2(0.881921, -0.471397),
289        vec2(0.903989, -0.427555),
290        vec2(0.923880, -0.382683),
291        vec2(0.941544, -0.336890),
292        vec2(0.956940, -0.290285),
293        vec2(0.970031, -0.242980),
294        vec2(0.980785, -0.195090),
295        vec2(0.989177, -0.146730),
296        vec2(0.995185, -0.098017),
297        vec2(0.998795, -0.049068),
298        vec2(1.000000, -0.000000),
299    ];
300}
301
302// ----------------------------------------------------------------------------
303
304#[derive(Clone, Copy, Debug, Default, PartialEq)]
305struct PathPoint {
306    pos: Pos2,
307
308    /// For filled paths the normal is used for anti-aliasing (both strokes and filled areas).
309    ///
310    /// For strokes the normal is also used for giving thickness to the path
311    /// (i.e. in what direction to expand).
312    ///
313    /// The normal could be estimated by differences between successive points,
314    /// but that would be less accurate (and in some cases slower).
315    ///
316    /// Normals are normally unit-length.
317    normal: Vec2,
318}
319
320/// A connected line (without thickness or gaps) which can be tessellated
321/// to either to a stroke (with thickness) or a filled convex area.
322/// Used as a scratch-pad during tessellation.
323#[derive(Clone, Debug, Default)]
324pub struct Path(Vec<PathPoint>);
325
326impl Path {
327    #[inline(always)]
328    pub fn clear(&mut self) {
329        self.0.clear();
330    }
331
332    #[inline(always)]
333    pub fn reserve(&mut self, additional: usize) {
334        self.0.reserve(additional);
335    }
336
337    #[inline(always)]
338    pub fn add_point(&mut self, pos: Pos2, normal: Vec2) {
339        self.0.push(PathPoint { pos, normal });
340    }
341
342    pub fn add_circle(&mut self, center: Pos2, radius: f32) {
343        use precomputed_vertices::{CIRCLE_128, CIRCLE_16, CIRCLE_32, CIRCLE_64, CIRCLE_8};
344
345        // These cutoffs are based on a high-dpi display. TODO(emilk): use pixels_per_point here?
346        // same cutoffs as in add_circle_quadrant
347
348        if radius <= 2.0 {
349            self.0.extend(CIRCLE_8.iter().map(|&n| PathPoint {
350                pos: center + radius * n,
351                normal: n,
352            }));
353        } else if radius <= 5.0 {
354            self.0.extend(CIRCLE_16.iter().map(|&n| PathPoint {
355                pos: center + radius * n,
356                normal: n,
357            }));
358        } else if radius < 18.0 {
359            self.0.extend(CIRCLE_32.iter().map(|&n| PathPoint {
360                pos: center + radius * n,
361                normal: n,
362            }));
363        } else if radius < 50.0 {
364            self.0.extend(CIRCLE_64.iter().map(|&n| PathPoint {
365                pos: center + radius * n,
366                normal: n,
367            }));
368        } else {
369            self.0.extend(CIRCLE_128.iter().map(|&n| PathPoint {
370                pos: center + radius * n,
371                normal: n,
372            }));
373        }
374    }
375
376    pub fn add_line_segment(&mut self, points: [Pos2; 2]) {
377        self.reserve(2);
378        let normal = (points[1] - points[0]).normalized().rot90();
379        self.add_point(points[0], normal);
380        self.add_point(points[1], normal);
381    }
382
383    pub fn add_open_points(&mut self, points: &[Pos2]) {
384        let n = points.len();
385        assert!(n >= 2);
386
387        if n == 2 {
388            // Common case optimization:
389            self.add_line_segment([points[0], points[1]]);
390        } else {
391            self.reserve(n);
392            self.add_point(points[0], (points[1] - points[0]).normalized().rot90());
393            let mut n0 = (points[1] - points[0]).normalized().rot90();
394            for i in 1..n - 1 {
395                let mut n1 = (points[i + 1] - points[i]).normalized().rot90();
396
397                // Handle duplicated points (but not triplicated…):
398                if n0 == Vec2::ZERO {
399                    n0 = n1;
400                } else if n1 == Vec2::ZERO {
401                    n1 = n0;
402                }
403
404                let normal = (n0 + n1) / 2.0;
405                let length_sq = normal.length_sq();
406                let right_angle_length_sq = 0.5;
407                let sharper_than_a_right_angle = length_sq < right_angle_length_sq;
408                if sharper_than_a_right_angle {
409                    // cut off the sharp corner
410                    let center_normal = normal.normalized();
411                    let n0c = (n0 + center_normal) / 2.0;
412                    let n1c = (n1 + center_normal) / 2.0;
413                    self.add_point(points[i], n0c / n0c.length_sq());
414                    self.add_point(points[i], n1c / n1c.length_sq());
415                } else {
416                    // miter join
417                    self.add_point(points[i], normal / length_sq);
418                }
419
420                n0 = n1;
421            }
422            self.add_point(
423                points[n - 1],
424                (points[n - 1] - points[n - 2]).normalized().rot90(),
425            );
426        }
427    }
428
429    pub fn add_line_loop(&mut self, points: &[Pos2]) {
430        let n = points.len();
431        assert!(n >= 2);
432        self.reserve(n);
433
434        let mut n0 = (points[0] - points[n - 1]).normalized().rot90();
435
436        for i in 0..n {
437            let next_i = if i + 1 == n { 0 } else { i + 1 };
438            let mut n1 = (points[next_i] - points[i]).normalized().rot90();
439
440            // Handle duplicated points (but not triplicated…):
441            if n0 == Vec2::ZERO {
442                n0 = n1;
443            } else if n1 == Vec2::ZERO {
444                n1 = n0;
445            }
446
447            let normal = (n0 + n1) / 2.0;
448            let length_sq = normal.length_sq();
449
450            // We can't just cut off corners for filled shapes like this,
451            // because the feather will both expand and contract the corner along the provided normals
452            // to make sure it doesn't grow, and the shrinking will make the inner points cross each other.
453            //
454            // A better approach is to shrink the vertices in by half the feather-width here
455            // and then only expand during feathering.
456            //
457            // See https://github.com/emilk/egui/issues/1226
458            const CUT_OFF_SHARP_CORNERS: bool = false;
459
460            let right_angle_length_sq = 0.5;
461            let sharper_than_a_right_angle = length_sq < right_angle_length_sq;
462            if CUT_OFF_SHARP_CORNERS && sharper_than_a_right_angle {
463                // cut off the sharp corner
464                let center_normal = normal.normalized();
465                let n0c = (n0 + center_normal) / 2.0;
466                let n1c = (n1 + center_normal) / 2.0;
467                self.add_point(points[i], n0c / n0c.length_sq());
468                self.add_point(points[i], n1c / n1c.length_sq());
469            } else {
470                // miter join
471                self.add_point(points[i], normal / length_sq);
472            }
473
474            n0 = n1;
475        }
476    }
477
478    /// The path is taken to be closed (i.e. returning to the start again).
479    ///
480    /// Calling this may reverse the vertices in the path if they are wrong winding order.
481    /// The preferred winding order is clockwise.
482    pub fn fill_and_stroke(
483        &mut self,
484        feathering: f32,
485        fill: Color32,
486        stroke: &PathStroke,
487        out: &mut Mesh,
488    ) {
489        stroke_and_fill_path(feathering, &mut self.0, PathType::Closed, stroke, fill, out);
490    }
491
492    /// Open-ended.
493    pub fn stroke_open(&mut self, feathering: f32, stroke: &PathStroke, out: &mut Mesh) {
494        stroke_path(feathering, &mut self.0, PathType::Open, stroke, out);
495    }
496
497    /// A closed path (returning to the first point).
498    pub fn stroke_closed(&mut self, feathering: f32, stroke: &PathStroke, out: &mut Mesh) {
499        stroke_path(feathering, &mut self.0, PathType::Closed, stroke, out);
500    }
501
502    pub fn stroke(
503        &mut self,
504        feathering: f32,
505        path_type: PathType,
506        stroke: &PathStroke,
507        out: &mut Mesh,
508    ) {
509        stroke_path(feathering, &mut self.0, path_type, stroke, out);
510    }
511
512    /// The path is taken to be closed (i.e. returning to the start again).
513    ///
514    /// Calling this may reverse the vertices in the path if they are wrong winding order.
515    /// The preferred winding order is clockwise.
516    pub fn fill(&mut self, feathering: f32, color: Color32, out: &mut Mesh) {
517        fill_closed_path(feathering, &mut self.0, color, out);
518    }
519
520    /// Like [`Self::fill`] but with texturing.
521    ///
522    /// The `uv_from_pos` is called for each vertex position.
523    pub fn fill_with_uv(
524        &mut self,
525        feathering: f32,
526        color: Color32,
527        texture_id: TextureId,
528        uv_from_pos: impl Fn(Pos2) -> Pos2,
529        out: &mut Mesh,
530    ) {
531        fill_closed_path_with_uv(feathering, &mut self.0, color, texture_id, uv_from_pos, out);
532    }
533}
534
535pub mod path {
536    //! Helpers for constructing paths
537    use crate::CornerRadiusF32;
538    use emath::{pos2, Pos2, Rect};
539
540    /// overwrites existing points
541    pub fn rounded_rectangle(path: &mut Vec<Pos2>, rect: Rect, cr: CornerRadiusF32) {
542        path.clear();
543
544        let min = rect.min;
545        let max = rect.max;
546
547        let cr = clamp_corner_radius(cr, rect);
548
549        if cr == CornerRadiusF32::ZERO {
550            path.reserve(4);
551            path.push(pos2(min.x, min.y)); // left top
552            path.push(pos2(max.x, min.y)); // right top
553            path.push(pos2(max.x, max.y)); // right bottom
554            path.push(pos2(min.x, max.y)); // left bottom
555        } else {
556            // We need to avoid duplicated vertices, because that leads to visual artifacts later.
557            // Duplicated vertices can happen when one side is all rounding, with no straight edge between.
558            let eps = f32::EPSILON * rect.size().max_elem();
559
560            add_circle_quadrant(path, pos2(max.x - cr.se, max.y - cr.se), cr.se, 0.0); // south east
561
562            if rect.width() <= cr.se + cr.sw + eps {
563                path.pop(); // avoid duplicated vertex
564            }
565
566            add_circle_quadrant(path, pos2(min.x + cr.sw, max.y - cr.sw), cr.sw, 1.0); // south west
567
568            if rect.height() <= cr.sw + cr.nw + eps {
569                path.pop(); // avoid duplicated vertex
570            }
571
572            add_circle_quadrant(path, pos2(min.x + cr.nw, min.y + cr.nw), cr.nw, 2.0); // north west
573
574            if rect.width() <= cr.nw + cr.ne + eps {
575                path.pop(); // avoid duplicated vertex
576            }
577
578            add_circle_quadrant(path, pos2(max.x - cr.ne, min.y + cr.ne), cr.ne, 3.0); // north east
579
580            if rect.height() <= cr.ne + cr.se + eps {
581                path.pop(); // avoid duplicated vertex
582            }
583        }
584    }
585
586    /// Add one quadrant of a circle
587    ///
588    /// * quadrant 0: right bottom
589    /// * quadrant 1: left bottom
590    /// * quadrant 2: left top
591    /// * quadrant 3: right top
592    //
593    // Derivation:
594    //
595    // * angle 0 * TAU / 4 = right
596    //   - quadrant 0: right bottom
597    // * angle 1 * TAU / 4 = bottom
598    //   - quadrant 1: left bottom
599    // * angle 2 * TAU / 4 = left
600    //   - quadrant 2: left top
601    // * angle 3 * TAU / 4 = top
602    //   - quadrant 3: right top
603    // * angle 4 * TAU / 4 = right
604    pub fn add_circle_quadrant(path: &mut Vec<Pos2>, center: Pos2, radius: f32, quadrant: f32) {
605        use super::precomputed_vertices::{CIRCLE_128, CIRCLE_16, CIRCLE_32, CIRCLE_64, CIRCLE_8};
606
607        // These cutoffs are based on a high-dpi display. TODO(emilk): use pixels_per_point here?
608        // same cutoffs as in add_circle
609
610        if radius <= 0.0 {
611            path.push(center);
612        } else if radius <= 2.0 {
613            let offset = quadrant as usize * 2;
614            let quadrant_vertices = &CIRCLE_8[offset..=offset + 2];
615            path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
616        } else if radius <= 5.0 {
617            let offset = quadrant as usize * 4;
618            let quadrant_vertices = &CIRCLE_16[offset..=offset + 4];
619            path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
620        } else if radius < 18.0 {
621            let offset = quadrant as usize * 8;
622            let quadrant_vertices = &CIRCLE_32[offset..=offset + 8];
623            path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
624        } else if radius < 50.0 {
625            let offset = quadrant as usize * 16;
626            let quadrant_vertices = &CIRCLE_64[offset..=offset + 16];
627            path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
628        } else {
629            let offset = quadrant as usize * 32;
630            let quadrant_vertices = &CIRCLE_128[offset..=offset + 32];
631            path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
632        }
633    }
634
635    // Ensures the radius of each corner is within a valid range
636    fn clamp_corner_radius(cr: CornerRadiusF32, rect: Rect) -> CornerRadiusF32 {
637        let half_width = rect.width() * 0.5;
638        let half_height = rect.height() * 0.5;
639        let max_cr = half_width.min(half_height);
640        cr.at_most(max_cr).at_least(0.0)
641    }
642}
643
644// ----------------------------------------------------------------------------
645
646#[derive(Clone, Copy, PartialEq, Eq)]
647pub enum PathType {
648    Open,
649    Closed,
650}
651
652/// Tessellation quality options
653#[derive(Clone, Copy, Debug, PartialEq)]
654#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
655#[cfg_attr(feature = "serde", serde(default))]
656pub struct TessellationOptions {
657    /// Use "feathering" to smooth out the edges of shapes as a form of anti-aliasing.
658    ///
659    /// Feathering works by making each edge into a thin gradient into transparency.
660    /// The size of this edge is controlled by [`Self::feathering_size_in_pixels`].
661    ///
662    /// This makes shapes appear smoother, but requires more triangles and is therefore slower.
663    ///
664    /// This setting does not affect text.
665    ///
666    /// Default: `true`.
667    pub feathering: bool,
668
669    /// The size of the feathering, in physical pixels.
670    ///
671    /// The default, and suggested, value for this is `1.0`.
672    /// If you use a larger value, edges will appear blurry.
673    pub feathering_size_in_pixels: f32,
674
675    /// If `true` (default) cull certain primitives before tessellating them.
676    /// This likely makes
677    pub coarse_tessellation_culling: bool,
678
679    /// If `true`, small filled circled will be optimized by using pre-rasterized circled
680    /// from the font atlas.
681    pub prerasterized_discs: bool,
682
683    /// If `true` (default) align text to the physical pixel grid.
684    /// This makes the text sharper on most platforms.
685    pub round_text_to_pixels: bool,
686
687    /// If `true` (default), align right-angled line segments to the physical pixel grid.
688    ///
689    /// This makes the line segments appear crisp on any display.
690    pub round_line_segments_to_pixels: bool,
691
692    /// If `true` (default), align rectangles to the physical pixel grid.
693    ///
694    /// This makes the rectangle strokes more crisp,
695    /// and makes filled rectangles tile perfectly (without feathering).
696    ///
697    /// You can override this with [`crate::RectShape::round_to_pixels`].
698    pub round_rects_to_pixels: bool,
699
700    /// Output the clip rectangles to be painted.
701    pub debug_paint_clip_rects: bool,
702
703    /// Output the text-containing rectangles.
704    pub debug_paint_text_rects: bool,
705
706    /// If true, no clipping will be done.
707    pub debug_ignore_clip_rects: bool,
708
709    /// The maximum distance between the original curve and the flattened curve.
710    pub bezier_tolerance: f32,
711
712    /// The default value will be 1.0e-5, it will be used during float compare.
713    pub epsilon: f32,
714
715    /// If `rayon` feature is activated, should we parallelize tessellation?
716    pub parallel_tessellation: bool,
717
718    /// If `true`, invalid meshes will be silently ignored.
719    /// If `false`, invalid meshes will cause a panic.
720    ///
721    /// The default is `false` to save performance.
722    pub validate_meshes: bool,
723}
724
725impl Default for TessellationOptions {
726    fn default() -> Self {
727        Self {
728            feathering: true,
729            feathering_size_in_pixels: 1.0,
730            coarse_tessellation_culling: true,
731            prerasterized_discs: true,
732            round_text_to_pixels: true,
733            round_line_segments_to_pixels: true,
734            round_rects_to_pixels: true,
735            debug_paint_text_rects: false,
736            debug_paint_clip_rects: false,
737            debug_ignore_clip_rects: false,
738            bezier_tolerance: 0.1,
739            epsilon: 1.0e-5,
740            parallel_tessellation: true,
741            validate_meshes: false,
742        }
743    }
744}
745
746fn cw_signed_area(path: &[PathPoint]) -> f64 {
747    if let Some(last) = path.last() {
748        let mut previous = last.pos;
749        let mut area = 0.0;
750        for p in path {
751            area += (previous.x * p.pos.y - p.pos.x * previous.y) as f64;
752            previous = p.pos;
753        }
754        area
755    } else {
756        0.0
757    }
758}
759
760/// Tessellate the given convex area into a polygon.
761///
762/// Calling this may reverse the vertices in the path if they are wrong winding order.
763///
764/// The preferred winding order is clockwise.
765fn fill_closed_path(feathering: f32, path: &mut [PathPoint], fill_color: Color32, out: &mut Mesh) {
766    if fill_color == Color32::TRANSPARENT {
767        return;
768    }
769
770    let n = path.len() as u32;
771    if n < 3 {
772        return;
773    }
774
775    if 0.0 < feathering {
776        if cw_signed_area(path) < 0.0 {
777            // Wrong winding order - fix:
778            path.reverse();
779            for point in &mut *path {
780                point.normal = -point.normal;
781            }
782        }
783
784        out.reserve_triangles(3 * n as usize);
785        out.reserve_vertices(2 * n as usize);
786        let idx_inner = out.vertices.len() as u32;
787        let idx_outer = idx_inner + 1;
788
789        // The fill:
790        for i in 2..n {
791            out.add_triangle(idx_inner + 2 * (i - 1), idx_inner, idx_inner + 2 * i);
792        }
793
794        // The feathering:
795        let mut i0 = n - 1;
796        for i1 in 0..n {
797            let p1 = &path[i1 as usize];
798            let dm = 0.5 * feathering * p1.normal;
799
800            let pos_inner = p1.pos - dm;
801            let pos_outer = p1.pos + dm;
802
803            out.colored_vertex(pos_inner, fill_color);
804            out.colored_vertex(pos_outer, Color32::TRANSPARENT);
805            out.add_triangle(idx_inner + i1 * 2, idx_inner + i0 * 2, idx_outer + 2 * i0);
806            out.add_triangle(idx_outer + i0 * 2, idx_outer + i1 * 2, idx_inner + 2 * i1);
807            i0 = i1;
808        }
809    } else {
810        out.reserve_triangles(n as usize);
811        let idx = out.vertices.len() as u32;
812        out.vertices.extend(path.iter().map(|p| Vertex {
813            pos: p.pos,
814            uv: WHITE_UV,
815            color: fill_color,
816        }));
817        for i in 2..n {
818            out.add_triangle(idx, idx + i - 1, idx + i);
819        }
820    }
821}
822
823/// Like [`fill_closed_path`] but with texturing.
824///
825/// The `uv_from_pos` is called for each vertex position.
826fn fill_closed_path_with_uv(
827    feathering: f32,
828    path: &mut [PathPoint],
829    color: Color32,
830    texture_id: TextureId,
831    uv_from_pos: impl Fn(Pos2) -> Pos2,
832    out: &mut Mesh,
833) {
834    if color == Color32::TRANSPARENT {
835        return;
836    }
837
838    if out.is_empty() {
839        out.texture_id = texture_id;
840    } else {
841        assert_eq!(
842            out.texture_id, texture_id,
843            "Mixing different `texture_id` in the same "
844        );
845    }
846
847    let n = path.len() as u32;
848    if 0.0 < feathering {
849        if cw_signed_area(path) < 0.0 {
850            // Wrong winding order - fix:
851            path.reverse();
852            for point in &mut *path {
853                point.normal = -point.normal;
854            }
855        }
856
857        out.reserve_triangles(3 * n as usize);
858        out.reserve_vertices(2 * n as usize);
859        let color_outer = Color32::TRANSPARENT;
860        let idx_inner = out.vertices.len() as u32;
861        let idx_outer = idx_inner + 1;
862
863        // The fill:
864        for i in 2..n {
865            out.add_triangle(idx_inner + 2 * (i - 1), idx_inner, idx_inner + 2 * i);
866        }
867
868        // The feathering:
869        let mut i0 = n - 1;
870        for i1 in 0..n {
871            let p1 = &path[i1 as usize];
872            let dm = 0.5 * feathering * p1.normal;
873
874            let pos = p1.pos - dm;
875            out.vertices.push(Vertex {
876                pos,
877                uv: uv_from_pos(pos),
878                color,
879            });
880
881            let pos = p1.pos + dm;
882            out.vertices.push(Vertex {
883                pos,
884                uv: uv_from_pos(pos),
885                color: color_outer,
886            });
887
888            out.add_triangle(idx_inner + i1 * 2, idx_inner + i0 * 2, idx_outer + 2 * i0);
889            out.add_triangle(idx_outer + i0 * 2, idx_outer + i1 * 2, idx_inner + 2 * i1);
890            i0 = i1;
891        }
892    } else {
893        out.reserve_triangles(n as usize);
894        let idx = out.vertices.len() as u32;
895        out.vertices.extend(path.iter().map(|p| Vertex {
896            pos: p.pos,
897            uv: uv_from_pos(p.pos),
898            color,
899        }));
900        for i in 2..n {
901            out.add_triangle(idx, idx + i - 1, idx + i);
902        }
903    }
904}
905
906/// Tessellate the given path as a stroke with thickness.
907fn stroke_path(
908    feathering: f32,
909    path: &mut [PathPoint],
910    path_type: PathType,
911    stroke: &PathStroke,
912    out: &mut Mesh,
913) {
914    let fill = Color32::TRANSPARENT;
915    stroke_and_fill_path(feathering, path, path_type, stroke, fill, out);
916}
917
918/// Tessellate the given path as a stroke with thickness, with optional fill color.
919///
920/// Calling this may reverse the vertices in the path if they are wrong winding order.
921///
922/// The preferred winding order is clockwise.
923fn stroke_and_fill_path(
924    feathering: f32,
925    path: &mut [PathPoint],
926    path_type: PathType,
927    stroke: &PathStroke,
928    color_fill: Color32,
929    out: &mut Mesh,
930) {
931    let n = path.len() as u32;
932
933    if n < 2 {
934        return;
935    }
936
937    if stroke.width == 0.0 {
938        // Skip the stroke, just fill.
939        return fill_closed_path(feathering, path, color_fill, out);
940    }
941
942    if color_fill != Color32::TRANSPARENT && cw_signed_area(path) < 0.0 {
943        // Wrong winding order - fix:
944        path.reverse();
945        for point in &mut *path {
946            point.normal = -point.normal;
947        }
948    }
949
950    if stroke.color == ColorMode::TRANSPARENT {
951        // Skip the stroke, just fill. But subtract the width from the path:
952        match stroke.kind {
953            StrokeKind::Inside => {
954                for point in &mut *path {
955                    point.pos -= stroke.width * point.normal;
956                }
957            }
958            StrokeKind::Middle => {
959                for point in &mut *path {
960                    point.pos -= 0.5 * stroke.width * point.normal;
961                }
962            }
963            StrokeKind::Outside => {}
964        }
965
966        // Skip the stroke, just fill.
967        return fill_closed_path(feathering, path, color_fill, out);
968    }
969
970    let idx = out.vertices.len() as u32;
971
972    // Move the points so that the stroke is on middle of the path.
973    match stroke.kind {
974        StrokeKind::Inside => {
975            for point in &mut *path {
976                point.pos -= 0.5 * stroke.width * point.normal;
977            }
978        }
979        StrokeKind::Middle => {
980            // correct
981        }
982        StrokeKind::Outside => {
983            for point in &mut *path {
984                point.pos += 0.5 * stroke.width * point.normal;
985            }
986        }
987    }
988
989    // Expand the bounding box to include the thickness of the path
990    let uv_bbox = if matches!(stroke.color, ColorMode::UV(_)) {
991        Rect::from_points(&path.iter().map(|p| p.pos).collect::<Vec<Pos2>>())
992            .expand((stroke.width / 2.0) + feathering)
993    } else {
994        Rect::NAN
995    };
996    let get_color = |col: &ColorMode, pos: Pos2| match col {
997        ColorMode::Solid(col) => *col,
998        ColorMode::UV(fun) => fun(uv_bbox, pos),
999    };
1000
1001    if 0.0 < feathering {
1002        let color_outer = Color32::TRANSPARENT;
1003        let color_middle = &stroke.color;
1004
1005        // We add a bit of an epsilon here, because when we round to pixels,
1006        // we can get rounding errors (unless pixels_per_point is an integer).
1007        // And it's better to err on the side of the nicer rendering with line caps
1008        // (the thin-line optimization has no line caps).
1009        let thin_line = stroke.width <= 0.9 * feathering;
1010        if thin_line {
1011            // If the stroke is painted smaller than the pixel width (=feathering width),
1012            // then we risk severe aliasing.
1013            // Instead, we paint the stroke as a triangular ridge, two feather-widths wide,
1014            // and lessen the opacity of the middle part instead of making it thinner.
1015            if color_fill != Color32::TRANSPARENT && stroke.width < feathering {
1016                // If this is filled shape, then we need to also compensate so that the
1017                // filled area remains the same as it would have been without the
1018                // artificially wide line.
1019                for point in &mut *path {
1020                    point.pos += 0.5 * (feathering - stroke.width) * point.normal;
1021                }
1022            }
1023
1024            // TODO(emilk): add line caps (if this is an open line).
1025
1026            let opacity = stroke.width / feathering;
1027
1028            /*
1029            We paint the line using three edges: outer, middle, fill.
1030
1031            .       o   m   i      outer, middle, fill
1032            .       |---|          feathering (pixel width)
1033            */
1034
1035            out.reserve_triangles(4 * n as usize);
1036            out.reserve_vertices(3 * n as usize);
1037
1038            let mut i0 = n - 1;
1039            for i1 in 0..n {
1040                let connect_with_previous = path_type == PathType::Closed || i1 > 0;
1041                let p1 = path[i1 as usize];
1042                let p = p1.pos;
1043                let n = p1.normal;
1044                out.colored_vertex(p + n * feathering, color_outer);
1045                out.colored_vertex(p, mul_color(get_color(color_middle, p), opacity));
1046                out.colored_vertex(p - n * feathering, color_fill);
1047
1048                if connect_with_previous {
1049                    out.add_triangle(idx + 3 * i0 + 0, idx + 3 * i0 + 1, idx + 3 * i1 + 0);
1050                    out.add_triangle(idx + 3 * i0 + 1, idx + 3 * i1 + 0, idx + 3 * i1 + 1);
1051
1052                    out.add_triangle(idx + 3 * i0 + 1, idx + 3 * i0 + 2, idx + 3 * i1 + 1);
1053                    out.add_triangle(idx + 3 * i0 + 2, idx + 3 * i1 + 1, idx + 3 * i1 + 2);
1054                }
1055
1056                i0 = i1;
1057            }
1058
1059            if color_fill != Color32::TRANSPARENT {
1060                out.reserve_triangles(n as usize - 2);
1061                let idx_fill = idx + 2;
1062                for i in 2..n {
1063                    out.add_triangle(idx_fill + 3 * (i - 1), idx_fill, idx_fill + 3 * i);
1064                }
1065            }
1066        } else {
1067            // thick anti-aliased line
1068
1069            /*
1070            We paint the line using four edges: outer, middle, middle, fill
1071
1072            .       o   m     p    m   f   outer, middle, point, middle, fill
1073            .       |---|                  feathering (pixel width)
1074            .         |--------------|     width
1075            .       |---------|            outer_rad
1076            .           |-----|            inner_rad
1077            */
1078
1079            let inner_rad = 0.5 * (stroke.width - feathering);
1080            let outer_rad = 0.5 * (stroke.width + feathering);
1081
1082            match path_type {
1083                PathType::Closed => {
1084                    out.reserve_triangles(6 * n as usize);
1085                    out.reserve_vertices(4 * n as usize);
1086
1087                    let mut i0 = n - 1;
1088                    for i1 in 0..n {
1089                        let p1 = path[i1 as usize];
1090                        let p = p1.pos;
1091                        let n = p1.normal;
1092                        out.colored_vertex(p + n * outer_rad, color_outer);
1093                        out.colored_vertex(
1094                            p + n * inner_rad,
1095                            get_color(color_middle, p + n * inner_rad),
1096                        );
1097                        out.colored_vertex(
1098                            p - n * inner_rad,
1099                            get_color(color_middle, p - n * inner_rad),
1100                        );
1101                        out.colored_vertex(p - n * outer_rad, color_fill);
1102
1103                        out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0);
1104                        out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1);
1105
1106                        out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1);
1107                        out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
1108
1109                        out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2);
1110                        out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
1111
1112                        i0 = i1;
1113                    }
1114
1115                    if color_fill != Color32::TRANSPARENT {
1116                        out.reserve_triangles(n as usize - 2);
1117                        let idx_fill = idx + 3;
1118                        for i in 2..n {
1119                            out.add_triangle(idx_fill + 4 * (i - 1), idx_fill, idx_fill + 4 * i);
1120                        }
1121                    }
1122                }
1123                PathType::Open => {
1124                    // Anti-alias the ends by extruding the outer edge and adding
1125                    // two more triangles to each end:
1126
1127                    //   | aa |       | aa |
1128                    //    _________________   ___
1129                    //   | \    added    / |  feathering
1130                    //   |   \ ___p___ /   |  ___
1131                    //   |    |       |    |
1132                    //   |    |  opa  |    |
1133                    //   |    |  que  |    |
1134                    //   |    |       |    |
1135
1136                    // (in the future it would be great with an option to add a circular end instead)
1137
1138                    // TODO(emilk): we should probably shrink before adding the line caps,
1139                    // so that we don't add to the area of the line.
1140                    // TODO(emilk): make line caps optional.
1141
1142                    out.reserve_triangles(6 * n as usize + 4);
1143                    out.reserve_vertices(4 * n as usize);
1144
1145                    {
1146                        let end = path[0];
1147                        let p = end.pos;
1148                        let n = end.normal;
1149                        let back_extrude = n.rot90() * feathering;
1150                        out.colored_vertex(p + n * outer_rad + back_extrude, color_outer);
1151                        out.colored_vertex(
1152                            p + n * inner_rad,
1153                            get_color(color_middle, p + n * inner_rad),
1154                        );
1155                        out.colored_vertex(
1156                            p - n * inner_rad,
1157                            get_color(color_middle, p - n * inner_rad),
1158                        );
1159                        out.colored_vertex(p - n * outer_rad + back_extrude, color_outer);
1160
1161                        out.add_triangle(idx + 0, idx + 1, idx + 2);
1162                        out.add_triangle(idx + 0, idx + 2, idx + 3);
1163                    }
1164
1165                    let mut i0 = 0;
1166                    for i1 in 1..n - 1 {
1167                        let point = path[i1 as usize];
1168                        let p = point.pos;
1169                        let n = point.normal;
1170                        out.colored_vertex(p + n * outer_rad, color_outer);
1171                        out.colored_vertex(
1172                            p + n * inner_rad,
1173                            get_color(color_middle, p + n * inner_rad),
1174                        );
1175                        out.colored_vertex(
1176                            p - n * inner_rad,
1177                            get_color(color_middle, p - n * inner_rad),
1178                        );
1179                        out.colored_vertex(p - n * outer_rad, color_outer);
1180
1181                        out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0);
1182                        out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1);
1183
1184                        out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1);
1185                        out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
1186
1187                        out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2);
1188                        out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
1189
1190                        i0 = i1;
1191                    }
1192
1193                    {
1194                        let i1 = n - 1;
1195                        let end = path[i1 as usize];
1196                        let p = end.pos;
1197                        let n = end.normal;
1198                        let back_extrude = -n.rot90() * feathering;
1199                        out.colored_vertex(p + n * outer_rad + back_extrude, color_outer);
1200                        out.colored_vertex(
1201                            p + n * inner_rad,
1202                            get_color(color_middle, p + n * inner_rad),
1203                        );
1204                        out.colored_vertex(
1205                            p - n * inner_rad,
1206                            get_color(color_middle, p - n * inner_rad),
1207                        );
1208                        out.colored_vertex(p - n * outer_rad + back_extrude, color_outer);
1209
1210                        out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0);
1211                        out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1);
1212
1213                        out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1);
1214                        out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
1215
1216                        out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2);
1217                        out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
1218
1219                        // The extension:
1220                        out.add_triangle(idx + 4 * i1 + 0, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
1221                        out.add_triangle(idx + 4 * i1 + 0, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
1222                    }
1223                }
1224            }
1225        }
1226    } else {
1227        // not anti-aliased:
1228        out.reserve_triangles(2 * n as usize);
1229        out.reserve_vertices(2 * n as usize);
1230
1231        let last_index = if path_type == PathType::Closed {
1232            n
1233        } else {
1234            n - 1
1235        };
1236        for i in 0..last_index {
1237            out.add_triangle(
1238                idx + (2 * i + 0) % (2 * n),
1239                idx + (2 * i + 1) % (2 * n),
1240                idx + (2 * i + 2) % (2 * n),
1241            );
1242            out.add_triangle(
1243                idx + (2 * i + 2) % (2 * n),
1244                idx + (2 * i + 1) % (2 * n),
1245                idx + (2 * i + 3) % (2 * n),
1246            );
1247        }
1248
1249        let thin_line = stroke.width <= feathering;
1250        if thin_line {
1251            // Fade out thin lines rather than making them thinner
1252            let opacity = stroke.width / feathering;
1253            let radius = feathering / 2.0;
1254            for p in path.iter_mut() {
1255                out.colored_vertex(
1256                    p.pos + radius * p.normal,
1257                    mul_color(get_color(&stroke.color, p.pos + radius * p.normal), opacity),
1258                );
1259                out.colored_vertex(
1260                    p.pos - radius * p.normal,
1261                    mul_color(get_color(&stroke.color, p.pos - radius * p.normal), opacity),
1262                );
1263            }
1264        } else {
1265            let radius = stroke.width / 2.0;
1266            for p in path.iter_mut() {
1267                out.colored_vertex(
1268                    p.pos + radius * p.normal,
1269                    get_color(&stroke.color, p.pos + radius * p.normal),
1270                );
1271                out.colored_vertex(
1272                    p.pos - radius * p.normal,
1273                    get_color(&stroke.color, p.pos - radius * p.normal),
1274                );
1275            }
1276        }
1277
1278        if color_fill != Color32::TRANSPARENT {
1279            // We Need to create new vertices, because the ones we used for the stroke
1280            // has the wrong color.
1281
1282            // Shrink to ignore the stroke…
1283            for point in &mut *path {
1284                point.pos -= 0.5 * stroke.width * point.normal;
1285            }
1286            // …then fill:
1287            fill_closed_path(feathering, path, color_fill, out);
1288        }
1289    }
1290}
1291
1292fn mul_color(color: Color32, factor: f32) -> Color32 {
1293    // The fast gamma-space multiply also happens to be perceptually better.
1294    // Win-win!
1295    color.gamma_multiply(factor)
1296}
1297
1298// ----------------------------------------------------------------------------
1299
1300/// Converts [`Shape`]s into triangles ([`Mesh`]).
1301///
1302/// For performance reasons it is smart to reuse the same [`Tessellator`].
1303///
1304/// See also [`tessellate_shapes`], a convenient wrapper around [`Tessellator`].
1305#[derive(Clone)]
1306pub struct Tessellator {
1307    pixels_per_point: f32,
1308    options: TessellationOptions,
1309    font_tex_size: [usize; 2],
1310
1311    /// See [`crate::TextureAtlas::prepared_discs`].
1312    prepared_discs: Vec<PreparedDisc>,
1313
1314    /// size of feathering in points. normally the size of a physical pixel. 0.0 if disabled
1315    feathering: f32,
1316
1317    /// Only used for culling
1318    clip_rect: Rect,
1319
1320    scratchpad_points: Vec<Pos2>,
1321    scratchpad_path: Path,
1322}
1323
1324impl Tessellator {
1325    /// Create a new [`Tessellator`].
1326    ///
1327    /// * `pixels_per_point`: number of physical pixels to each logical point
1328    /// * `options`: tessellation quality
1329    /// * `shapes`: what to tessellate
1330    /// * `font_tex_size`: size of the font texture. Required to normalize glyph uv rectangles when tessellating text.
1331    /// * `prepared_discs`: What [`crate::TextureAtlas::prepared_discs`] returns. Can safely be set to an empty vec.
1332    pub fn new(
1333        pixels_per_point: f32,
1334        options: TessellationOptions,
1335        font_tex_size: [usize; 2],
1336        prepared_discs: Vec<PreparedDisc>,
1337    ) -> Self {
1338        let feathering = if options.feathering {
1339            let pixel_size = 1.0 / pixels_per_point;
1340            options.feathering_size_in_pixels * pixel_size
1341        } else {
1342            0.0
1343        };
1344        Self {
1345            pixels_per_point,
1346            options,
1347            font_tex_size,
1348            prepared_discs,
1349            feathering,
1350            clip_rect: Rect::EVERYTHING,
1351            scratchpad_points: Default::default(),
1352            scratchpad_path: Default::default(),
1353        }
1354    }
1355
1356    /// Set the [`Rect`] to use for culling.
1357    pub fn set_clip_rect(&mut self, clip_rect: Rect) {
1358        self.clip_rect = clip_rect;
1359    }
1360
1361    /// Tessellate a clipped shape into a list of primitives.
1362    pub fn tessellate_clipped_shape(
1363        &mut self,
1364        clipped_shape: ClippedShape,
1365        out_primitives: &mut Vec<ClippedPrimitive>,
1366    ) {
1367        let ClippedShape { clip_rect, shape } = clipped_shape;
1368
1369        if !clip_rect.is_positive() {
1370            return; // skip empty clip rectangles
1371        }
1372
1373        if let Shape::Vec(shapes) = shape {
1374            for shape in shapes {
1375                self.tessellate_clipped_shape(ClippedShape { clip_rect, shape }, out_primitives);
1376            }
1377            return;
1378        }
1379
1380        if let Shape::Callback(callback) = shape {
1381            out_primitives.push(ClippedPrimitive {
1382                clip_rect,
1383                primitive: Primitive::Callback(callback),
1384            });
1385            return;
1386        }
1387
1388        let start_new_mesh = match out_primitives.last() {
1389            None => true,
1390            Some(output_clipped_primitive) => {
1391                output_clipped_primitive.clip_rect != clip_rect
1392                    || match &output_clipped_primitive.primitive {
1393                        Primitive::Mesh(output_mesh) => {
1394                            output_mesh.texture_id != shape.texture_id()
1395                        }
1396                        Primitive::Callback(_) => true,
1397                    }
1398            }
1399        };
1400
1401        if start_new_mesh {
1402            out_primitives.push(ClippedPrimitive {
1403                clip_rect,
1404                primitive: Primitive::Mesh(Mesh::default()),
1405            });
1406        }
1407
1408        let out = out_primitives.last_mut().unwrap();
1409
1410        if let Primitive::Mesh(out_mesh) = &mut out.primitive {
1411            self.clip_rect = clip_rect;
1412            self.tessellate_shape(shape, out_mesh);
1413        } else {
1414            unreachable!();
1415        }
1416    }
1417
1418    /// Tessellate a single [`Shape`] into a [`Mesh`].
1419    ///
1420    /// This call can panic the given shape is of [`Shape::Vec`] or [`Shape::Callback`].
1421    /// For that, use [`Self::tessellate_clipped_shape`] instead.
1422    /// * `shape`: the shape to tessellate.
1423    /// * `out`: triangles are appended to this.
1424    pub fn tessellate_shape(&mut self, shape: Shape, out: &mut Mesh) {
1425        match shape {
1426            Shape::Noop => {}
1427            Shape::Vec(vec) => {
1428                for shape in vec {
1429                    self.tessellate_shape(shape, out);
1430                }
1431            }
1432            Shape::Circle(circle) => {
1433                self.tessellate_circle(circle, out);
1434            }
1435            Shape::Ellipse(ellipse) => {
1436                self.tessellate_ellipse(ellipse, out);
1437            }
1438            Shape::Mesh(mesh) => {
1439                profiling::scope!("mesh");
1440
1441                if self.options.validate_meshes && !mesh.is_valid() {
1442                    debug_assert!(false, "Invalid Mesh in Shape::Mesh");
1443                    return;
1444                }
1445                // note: `append` still checks if the mesh is valid if extra asserts are enabled.
1446
1447                if self.options.coarse_tessellation_culling
1448                    && !self.clip_rect.intersects(mesh.calc_bounds())
1449                {
1450                    return;
1451                }
1452
1453                out.append_ref(&mesh);
1454            }
1455            Shape::LineSegment { points, stroke } => {
1456                self.tessellate_line_segment(points, stroke, out);
1457            }
1458            Shape::Path(path_shape) => {
1459                self.tessellate_path(&path_shape, out);
1460            }
1461            Shape::Rect(rect_shape) => {
1462                self.tessellate_rect(&rect_shape, out);
1463            }
1464            Shape::Text(text_shape) => {
1465                if self.options.debug_paint_text_rects {
1466                    let rect = text_shape.galley.rect.translate(text_shape.pos.to_vec2());
1467                    self.tessellate_rect(
1468                        &RectShape::stroke(rect, 2.0, (0.5, Color32::GREEN), StrokeKind::Outside),
1469                        out,
1470                    );
1471                }
1472                self.tessellate_text(&text_shape, out);
1473            }
1474            Shape::QuadraticBezier(quadratic_shape) => {
1475                self.tessellate_quadratic_bezier(&quadratic_shape, out);
1476            }
1477            Shape::CubicBezier(cubic_shape) => self.tessellate_cubic_bezier(&cubic_shape, out),
1478            Shape::Callback(_) => {
1479                panic!("Shape::Callback passed to Tessellator");
1480            }
1481        }
1482    }
1483
1484    /// Tessellate a single [`CircleShape`] into a [`Mesh`].
1485    ///
1486    /// * `shape`: the circle to tessellate.
1487    /// * `out`: triangles are appended to this.
1488    pub fn tessellate_circle(&mut self, shape: CircleShape, out: &mut Mesh) {
1489        let CircleShape {
1490            center,
1491            radius,
1492            mut fill,
1493            stroke,
1494        } = shape;
1495
1496        if radius <= 0.0 {
1497            return;
1498        }
1499
1500        if self.options.coarse_tessellation_culling
1501            && !self
1502                .clip_rect
1503                .expand(radius + stroke.width)
1504                .contains(center)
1505        {
1506            return;
1507        }
1508
1509        if self.options.prerasterized_discs && fill != Color32::TRANSPARENT {
1510            let radius_px = radius * self.pixels_per_point;
1511            // strike the right balance between some circles becoming too blurry, and some too sharp.
1512            let cutoff_radius = radius_px * 2.0_f32.powf(0.25);
1513
1514            // Find the right disc radius for a crisp edge:
1515            // TODO(emilk): perhaps we can do something faster than this linear search.
1516            for disc in &self.prepared_discs {
1517                if cutoff_radius <= disc.r {
1518                    let side = radius_px * disc.w / (self.pixels_per_point * disc.r);
1519                    let rect = Rect::from_center_size(center, Vec2::splat(side));
1520                    out.add_rect_with_uv(rect, disc.uv, fill);
1521
1522                    if stroke.is_empty() {
1523                        return; // we are done
1524                    } else {
1525                        // we still need to do the stroke
1526                        fill = Color32::TRANSPARENT; // don't fill again below
1527                        break;
1528                    }
1529                }
1530            }
1531        }
1532
1533        let path_stroke = PathStroke::from(stroke).outside();
1534        self.scratchpad_path.clear();
1535        self.scratchpad_path.add_circle(center, radius);
1536        self.scratchpad_path
1537            .fill_and_stroke(self.feathering, fill, &path_stroke, out);
1538    }
1539
1540    /// Tessellate a single [`EllipseShape`] into a [`Mesh`].
1541    ///
1542    /// * `shape`: the ellipse to tessellate.
1543    /// * `out`: triangles are appended to this.
1544    pub fn tessellate_ellipse(&mut self, shape: EllipseShape, out: &mut Mesh) {
1545        let EllipseShape {
1546            center,
1547            radius,
1548            fill,
1549            stroke,
1550        } = shape;
1551
1552        if radius.x <= 0.0 || radius.y <= 0.0 {
1553            return;
1554        }
1555
1556        if self.options.coarse_tessellation_culling
1557            && !self
1558                .clip_rect
1559                .expand2(radius + Vec2::splat(stroke.width))
1560                .contains(center)
1561        {
1562            return;
1563        }
1564
1565        // Get the max pixel radius
1566        let max_radius = (radius.max_elem() * self.pixels_per_point) as u32;
1567
1568        // Ensure there is at least 8 points in each quarter of the ellipse
1569        let num_points = u32::max(8, max_radius / 16);
1570
1571        // Create an ease ratio based the ellipses a and b
1572        let ratio = ((radius.y / radius.x) / 2.0).clamp(0.0, 1.0);
1573
1574        // Generate points between the 0 to pi/2
1575        let quarter: Vec<Vec2> = (1..num_points)
1576            .map(|i| {
1577                let percent = i as f32 / num_points as f32;
1578
1579                // Ease the percent value, concentrating points around tight bends
1580                let eased = 2.0 * (percent - percent.powf(2.0)) * ratio + percent.powf(2.0);
1581
1582                // Scale the ease to the quarter
1583                let t = eased * std::f32::consts::FRAC_PI_2;
1584                Vec2::new(radius.x * f32::cos(t), radius.y * f32::sin(t))
1585            })
1586            .collect();
1587
1588        // Build the ellipse from the 4 known vertices filling arcs between
1589        // them by mirroring the points between 0 and pi/2
1590        let mut points = Vec::new();
1591        points.push(center + Vec2::new(radius.x, 0.0));
1592        points.extend(quarter.iter().map(|p| center + *p));
1593        points.push(center + Vec2::new(0.0, radius.y));
1594        points.extend(quarter.iter().rev().map(|p| center + Vec2::new(-p.x, p.y)));
1595        points.push(center + Vec2::new(-radius.x, 0.0));
1596        points.extend(quarter.iter().map(|p| center - *p));
1597        points.push(center + Vec2::new(0.0, -radius.y));
1598        points.extend(quarter.iter().rev().map(|p| center + Vec2::new(p.x, -p.y)));
1599
1600        let path_stroke = PathStroke::from(stroke).outside();
1601        self.scratchpad_path.clear();
1602        self.scratchpad_path.add_line_loop(&points);
1603        self.scratchpad_path
1604            .fill_and_stroke(self.feathering, fill, &path_stroke, out);
1605    }
1606
1607    /// Tessellate a single [`Mesh`] into a [`Mesh`].
1608    ///
1609    /// * `mesh`: the mesh to tessellate.
1610    /// * `out`: triangles are appended to this.
1611    pub fn tessellate_mesh(&self, mesh: &Mesh, out: &mut Mesh) {
1612        if !mesh.is_valid() {
1613            debug_assert!(false, "Invalid Mesh in Shape::Mesh");
1614            return;
1615        }
1616
1617        if self.options.coarse_tessellation_culling
1618            && !self.clip_rect.intersects(mesh.calc_bounds())
1619        {
1620            return;
1621        }
1622
1623        out.append_ref(mesh);
1624    }
1625
1626    /// Tessellate a line segment between the two points with the given stroke into a [`Mesh`].
1627    ///
1628    /// * `shape`: the mesh to tessellate.
1629    /// * `out`: triangles are appended to this.
1630    pub fn tessellate_line_segment(
1631        &mut self,
1632        mut points: [Pos2; 2],
1633        stroke: impl Into<Stroke>,
1634        out: &mut Mesh,
1635    ) {
1636        let stroke = stroke.into();
1637        if stroke.is_empty() {
1638            return;
1639        }
1640
1641        if self.options.coarse_tessellation_culling
1642            && !self
1643                .clip_rect
1644                .intersects(Rect::from_two_pos(points[0], points[1]).expand(stroke.width))
1645        {
1646            return;
1647        }
1648
1649        if self.options.round_line_segments_to_pixels {
1650            let feathering = self.feathering;
1651            let pixels_per_point = self.pixels_per_point;
1652
1653            let quarter_pixel = 0.25 * feathering; // Used to avoid fence post problem.
1654
1655            let [a, b] = &mut points;
1656            if a.x == b.x {
1657                // Vertical line
1658                let mut x = a.x;
1659                round_line_segment(&mut x, &stroke, self.pixels_per_point);
1660                a.x = x;
1661                b.x = x;
1662
1663                // Often the ends of the line are exactly on a pixel boundary,
1664                // but we extend line segments with a cap that is a pixel wide…
1665                // Solution: first shrink the line segment (on each end),
1666                // then round to pixel center!
1667                // We shrink by half-a-pixel n total (a quarter on each end),
1668                // so that on average we avoid the fence-post-problem after rounding.
1669                if a.y < b.y {
1670                    a.y = (a.y + quarter_pixel).round_to_pixel_center(pixels_per_point);
1671                    b.y = (b.y - quarter_pixel).round_to_pixel_center(pixels_per_point);
1672                } else {
1673                    a.y = (a.y - quarter_pixel).round_to_pixel_center(pixels_per_point);
1674                    b.y = (b.y + quarter_pixel).round_to_pixel_center(pixels_per_point);
1675                }
1676            }
1677            if a.y == b.y {
1678                // Horizontal line
1679                let mut y = a.y;
1680                round_line_segment(&mut y, &stroke, self.pixels_per_point);
1681                a.y = y;
1682                b.y = y;
1683
1684                // See earlier comment for vertical lines
1685                if a.x < b.x {
1686                    a.x = (a.x + quarter_pixel).round_to_pixel_center(pixels_per_point);
1687                    b.x = (b.x - quarter_pixel).round_to_pixel_center(pixels_per_point);
1688                } else {
1689                    a.x = (a.x - quarter_pixel).round_to_pixel_center(pixels_per_point);
1690                    b.x = (b.x + quarter_pixel).round_to_pixel_center(pixels_per_point);
1691                }
1692            }
1693        }
1694
1695        self.scratchpad_path.clear();
1696        self.scratchpad_path.add_line_segment(points);
1697        self.scratchpad_path
1698            .stroke_open(self.feathering, &stroke.into(), out);
1699    }
1700
1701    #[deprecated = "Use `tessellate_line_segment` instead"]
1702    pub fn tessellate_line(
1703        &mut self,
1704        points: [Pos2; 2],
1705        stroke: impl Into<Stroke>,
1706        out: &mut Mesh,
1707    ) {
1708        self.tessellate_line_segment(points, stroke, out);
1709    }
1710
1711    /// Tessellate a single [`PathShape`] into a [`Mesh`].
1712    ///
1713    /// * `path_shape`: the path to tessellate.
1714    /// * `out`: triangles are appended to this.
1715    pub fn tessellate_path(&mut self, path_shape: &PathShape, out: &mut Mesh) {
1716        if path_shape.points.len() < 2 {
1717            return;
1718        }
1719
1720        if self.options.coarse_tessellation_culling
1721            && !path_shape.visual_bounding_rect().intersects(self.clip_rect)
1722        {
1723            return;
1724        }
1725
1726        profiling::function_scope!();
1727
1728        let PathShape {
1729            points,
1730            closed,
1731            fill,
1732            stroke,
1733        } = path_shape;
1734
1735        self.scratchpad_path.clear();
1736
1737        if *closed {
1738            self.scratchpad_path.add_line_loop(points);
1739
1740            self.scratchpad_path
1741                .fill_and_stroke(self.feathering, *fill, stroke, out);
1742        } else {
1743            debug_assert_eq!(
1744                *fill,
1745                Color32::TRANSPARENT,
1746                "You asked to fill a path that is not closed. That makes no sense."
1747            );
1748
1749            self.scratchpad_path.add_open_points(points);
1750
1751            self.scratchpad_path
1752                .stroke(self.feathering, PathType::Open, stroke, out);
1753        }
1754    }
1755
1756    /// Tessellate a single [`Rect`] into a [`Mesh`].
1757    ///
1758    /// * `rect`: the rectangle to tessellate.
1759    /// * `out`: triangles are appended to this.
1760    pub fn tessellate_rect(&mut self, rect_shape: &RectShape, out: &mut Mesh) {
1761        if self.options.coarse_tessellation_culling
1762            && !rect_shape.visual_bounding_rect().intersects(self.clip_rect)
1763        {
1764            return;
1765        }
1766
1767        let brush = rect_shape.brush.as_ref();
1768        let RectShape {
1769            mut rect,
1770            corner_radius,
1771            mut fill,
1772            mut stroke,
1773            mut stroke_kind,
1774            round_to_pixels,
1775            mut blur_width,
1776            brush: _, // brush is extracted on its own, because it is not Copy
1777        } = *rect_shape;
1778
1779        let mut corner_radius = CornerRadiusF32::from(corner_radius);
1780        let round_to_pixels = round_to_pixels.unwrap_or(self.options.round_rects_to_pixels);
1781        let pixel_size = 1.0 / self.pixels_per_point;
1782
1783        if stroke.width == 0.0 {
1784            stroke.color = Color32::TRANSPARENT;
1785        }
1786
1787        // It is common to (sometimes accidentally) create an infinitely sized rectangle.
1788        // Make sure we can handle that:
1789        rect.min = rect.min.at_least(pos2(-1e7, -1e7));
1790        rect.max = rect.max.at_most(pos2(1e7, 1e7));
1791
1792        if !stroke.is_empty() {
1793            // Check if the stroke covers the whole rectangle
1794            let rect_with_stroke = match stroke_kind {
1795                StrokeKind::Inside => rect,
1796                StrokeKind::Middle => rect.expand(stroke.width / 2.0),
1797                StrokeKind::Outside => rect.expand(stroke.width),
1798            };
1799
1800            if rect_with_stroke.size().min_elem() <= 2.0 * stroke.width + 0.5 * self.feathering {
1801                // The stroke covers the fill.
1802                // Change this to be a fill-only shape, using the stroke color as the new fill color.
1803                rect = rect_with_stroke;
1804
1805                // We blend so that if the stroke is semi-transparent,
1806                // the fill still shines through.
1807                fill = stroke.color;
1808
1809                stroke = Stroke::NONE;
1810            }
1811        }
1812
1813        if stroke.is_empty() {
1814            // Approximate thin rectangles with line segments.
1815            // This is important so that thin rectangles look good.
1816            if rect.width() <= 2.0 * self.feathering {
1817                return self.tessellate_line_segment(
1818                    [rect.center_top(), rect.center_bottom()],
1819                    (rect.width(), fill),
1820                    out,
1821                );
1822            }
1823            if rect.height() <= 2.0 * self.feathering {
1824                return self.tessellate_line_segment(
1825                    [rect.left_center(), rect.right_center()],
1826                    (rect.height(), fill),
1827                    out,
1828                );
1829            }
1830        }
1831
1832        // Important: round to pixels BEFORE modifying/applying stroke_kind
1833        if round_to_pixels {
1834            // The rounding is aware of the stroke kind.
1835            // It is designed to be clever in trying to divine the intentions of the user.
1836            match stroke_kind {
1837                StrokeKind::Inside => {
1838                    // The stroke is inside the rect, so the rect defines the _outside_ of the stroke.
1839                    // We round the outside of the stroke on a pixel boundary.
1840                    // This will make the outside of the stroke crisp.
1841                    //
1842                    // Will make each stroke asymmetric if not an even multiple of physical pixels,
1843                    // but the left stroke will always be the mirror image of the right stroke,
1844                    // and the top stroke will always be the mirror image of the bottom stroke.
1845                    //
1846                    // This is so that a user can tile rectangles with `StrokeKind::Inside`,
1847                    // and get no pixel overlap between them.
1848                    rect = rect.round_to_pixels(self.pixels_per_point);
1849                }
1850                StrokeKind::Middle => {
1851                    // On this path we optimize for crisp and symmetric strokes.
1852                    // We put odd-width strokes in the center of pixels.
1853                    // To understand why, see `fn round_line_segment`.
1854                    if stroke.width <= 0.0 {
1855                        rect = rect.round_to_pixels(self.pixels_per_point);
1856                    } else if stroke.width <= pixel_size
1857                        || is_nearest_integer_odd(self.pixels_per_point * stroke.width)
1858                    {
1859                        rect = rect.round_to_pixel_center(self.pixels_per_point);
1860                    } else {
1861                        rect = rect.round_to_pixels(self.pixels_per_point);
1862                    }
1863                }
1864                StrokeKind::Outside => {
1865                    // Put the inside of the stroke on a pixel boundary.
1866                    // Makes the inside of the stroke and the filled rect crisp,
1867                    // but the outside of the stroke may become feathered (blurry).
1868                    //
1869                    // Will make each stroke asymmetric if not an even multiple of physical pixels,
1870                    // but the left stroke will always be the mirror image of the right stroke,
1871                    // and the top stroke will always be the mirror image of the bottom stroke.
1872                    rect = rect.round_to_pixels(self.pixels_per_point);
1873                }
1874            }
1875        }
1876
1877        let old_feathering = self.feathering;
1878
1879        if self.feathering < blur_width {
1880            // We accomplish the blur by using a larger-than-normal feathering.
1881            // Feathering is usually used to make the edges of a shape softer for anti-aliasing.
1882
1883            // The tessellator can't handle blurring/feathering larger than the smallest side of the rect.
1884            let eps = 0.1; // avoid numerical problems
1885            blur_width = blur_width
1886                .at_most(rect.size().min_elem() - eps - 2.0 * stroke.width)
1887                .at_least(0.0);
1888
1889            corner_radius += 0.5 * blur_width;
1890
1891            self.feathering = self.feathering.max(blur_width);
1892        }
1893
1894        {
1895            // Modify `rect` so that it represents the OUTER border
1896            // We do this because `path::rounded_rectangle` uses the
1897            // corner radius to pick the fidelity/resolution of the corner.
1898
1899            let original_cr = corner_radius;
1900
1901            match stroke_kind {
1902                StrokeKind::Inside => {}
1903                StrokeKind::Middle => {
1904                    rect = rect.expand(stroke.width / 2.0);
1905                    corner_radius += stroke.width / 2.0;
1906                }
1907                StrokeKind::Outside => {
1908                    rect = rect.expand(stroke.width);
1909                    corner_radius += stroke.width;
1910                }
1911            }
1912
1913            stroke_kind = StrokeKind::Inside;
1914
1915            // A small corner_radius is incompatible with a wide stroke,
1916            // because the small bend will be extruded inwards and cross itself.
1917            // There are two ways to solve this (wile maintaining constant stroke width):
1918            // either we increase the corner_radius, or we set it to zero.
1919            // We choose the former: if the user asks for _any_ corner_radius, they should get it.
1920
1921            let min_inside_cr = 0.1; // Large enough to avoid numerical issues
1922            let min_outside_cr = stroke.width + min_inside_cr;
1923
1924            let extra_cr_tweak = 0.4; // Otherwise is doesn't _feels_  enough.
1925
1926            if original_cr.nw == 0.0 {
1927                corner_radius.nw = 0.0;
1928            } else {
1929                corner_radius.nw += extra_cr_tweak;
1930                corner_radius.nw = corner_radius.nw.at_least(min_outside_cr);
1931            }
1932            if original_cr.ne == 0.0 {
1933                corner_radius.ne = 0.0;
1934            } else {
1935                corner_radius.ne += extra_cr_tweak;
1936                corner_radius.ne = corner_radius.ne.at_least(min_outside_cr);
1937            }
1938            if original_cr.sw == 0.0 {
1939                corner_radius.sw = 0.0;
1940            } else {
1941                corner_radius.sw += extra_cr_tweak;
1942                corner_radius.sw = corner_radius.sw.at_least(min_outside_cr);
1943            }
1944            if original_cr.se == 0.0 {
1945                corner_radius.se = 0.0;
1946            } else {
1947                corner_radius.se += extra_cr_tweak;
1948                corner_radius.se = corner_radius.se.at_least(min_outside_cr);
1949            }
1950        }
1951
1952        let path = &mut self.scratchpad_path;
1953        path.clear();
1954        path::rounded_rectangle(&mut self.scratchpad_points, rect, corner_radius);
1955        path.add_line_loop(&self.scratchpad_points);
1956
1957        let path_stroke = PathStroke::from(stroke).with_kind(stroke_kind);
1958
1959        if let Some(brush) = brush {
1960            // Textured fill
1961
1962            let fill_rect = match stroke_kind {
1963                StrokeKind::Inside => rect.shrink(stroke.width),
1964                StrokeKind::Middle => rect.shrink(stroke.width / 2.0),
1965                StrokeKind::Outside => rect,
1966            };
1967
1968            if fill_rect.is_positive() {
1969                let crate::Brush {
1970                    fill_texture_id,
1971                    uv,
1972                } = **brush;
1973                let uv_from_pos = |p: Pos2| {
1974                    pos2(
1975                        remap(p.x, rect.x_range(), uv.x_range()),
1976                        remap(p.y, rect.y_range(), uv.y_range()),
1977                    )
1978                };
1979                path.fill_with_uv(self.feathering, fill, fill_texture_id, uv_from_pos, out);
1980            }
1981
1982            if !stroke.is_empty() {
1983                path.stroke_closed(self.feathering, &path_stroke, out);
1984            }
1985        } else {
1986            // Stroke and maybe fill
1987            path.fill_and_stroke(self.feathering, fill, &path_stroke, out);
1988        }
1989
1990        self.feathering = old_feathering; // restore
1991    }
1992
1993    /// Tessellate a single [`TextShape`] into a [`Mesh`].
1994    /// * `text_shape`: the text to tessellate.
1995    /// * `out`: triangles are appended to this.
1996    pub fn tessellate_text(&mut self, text_shape: &TextShape, out: &mut Mesh) {
1997        let TextShape {
1998            pos: galley_pos,
1999            galley,
2000            underline,
2001            override_text_color,
2002            fallback_color,
2003            opacity_factor,
2004            angle,
2005        } = text_shape;
2006
2007        if galley.is_empty() {
2008            return;
2009        }
2010
2011        if *opacity_factor <= 0.0 {
2012            return;
2013        }
2014
2015        if galley.pixels_per_point != self.pixels_per_point {
2016            let warn = "epaint: WARNING: pixels_per_point (dpi scale) have changed between text layout and tessellation. \
2017                       You must recreate your text shapes if pixels_per_point changes.";
2018            #[cfg(feature = "log")]
2019            log::warn!("{warn}");
2020            #[cfg(not(feature = "log"))]
2021            println!("{warn}");
2022        }
2023
2024        out.vertices.reserve(galley.num_vertices);
2025        out.indices.reserve(galley.num_indices);
2026
2027        // The contents of the galley are already snapped to pixel coordinates,
2028        // but we need to make sure the galley ends up on the start of a physical pixel:
2029        let galley_pos = if self.options.round_text_to_pixels {
2030            galley_pos.round_to_pixels(self.pixels_per_point)
2031        } else {
2032            *galley_pos
2033        };
2034
2035        let uv_normalizer = vec2(
2036            1.0 / self.font_tex_size[0] as f32,
2037            1.0 / self.font_tex_size[1] as f32,
2038        );
2039
2040        let rotator = Rot2::from_angle(*angle);
2041
2042        for row in &galley.rows {
2043            if row.visuals.mesh.is_empty() {
2044                continue;
2045            }
2046
2047            let mut row_rect = row.visuals.mesh_bounds;
2048            if *angle != 0.0 {
2049                row_rect = row_rect.rotate_bb(rotator);
2050            }
2051            row_rect = row_rect.translate(galley_pos.to_vec2());
2052
2053            if self.options.coarse_tessellation_culling && !self.clip_rect.intersects(row_rect) {
2054                // culling individual lines of text is important, since a single `Shape::Text`
2055                // can span hundreds of lines.
2056                continue;
2057            }
2058
2059            let index_offset = out.vertices.len() as u32;
2060
2061            out.indices.extend(
2062                row.visuals
2063                    .mesh
2064                    .indices
2065                    .iter()
2066                    .map(|index| index + index_offset),
2067            );
2068
2069            out.vertices.extend(
2070                row.visuals
2071                    .mesh
2072                    .vertices
2073                    .iter()
2074                    .enumerate()
2075                    .map(|(i, vertex)| {
2076                        let Vertex { pos, uv, mut color } = *vertex;
2077
2078                        if let Some(override_text_color) = override_text_color {
2079                            // Only override the glyph color (not background color, strike-through color, etc)
2080                            if row.visuals.glyph_vertex_range.contains(&i) {
2081                                color = *override_text_color;
2082                            }
2083                        } else if color == Color32::PLACEHOLDER {
2084                            color = *fallback_color;
2085                        }
2086
2087                        if *opacity_factor < 1.0 {
2088                            color = color.gamma_multiply(*opacity_factor);
2089                        }
2090
2091                        debug_assert!(color != Color32::PLACEHOLDER, "A placeholder color made it to the tessellator. You forgot to set a fallback color.");
2092
2093                        let offset = if *angle == 0.0 {
2094                            pos.to_vec2()
2095                        } else {
2096                            rotator * pos.to_vec2()
2097                        };
2098
2099                        Vertex {
2100                            pos: galley_pos + offset,
2101                            uv: (uv.to_vec2() * uv_normalizer).to_pos2(),
2102                            color,
2103                        }
2104                    }),
2105            );
2106
2107            if *underline != Stroke::NONE {
2108                self.tessellate_line_segment(
2109                    [row_rect.left_bottom(), row_rect.right_bottom()],
2110                    *underline,
2111                    out,
2112                );
2113            }
2114        }
2115    }
2116
2117    /// Tessellate a single [`QuadraticBezierShape`] into a [`Mesh`].
2118    ///
2119    /// * `quadratic_shape`: the shape to tessellate.
2120    /// * `out`: triangles are appended to this.
2121    pub fn tessellate_quadratic_bezier(
2122        &mut self,
2123        quadratic_shape: &QuadraticBezierShape,
2124        out: &mut Mesh,
2125    ) {
2126        let options = &self.options;
2127        let clip_rect = self.clip_rect;
2128
2129        if options.coarse_tessellation_culling
2130            && !quadratic_shape.visual_bounding_rect().intersects(clip_rect)
2131        {
2132            return;
2133        }
2134
2135        let points = quadratic_shape.flatten(Some(options.bezier_tolerance));
2136
2137        self.tessellate_bezier_complete(
2138            &points,
2139            quadratic_shape.fill,
2140            quadratic_shape.closed,
2141            &quadratic_shape.stroke,
2142            out,
2143        );
2144    }
2145
2146    /// Tessellate a single [`CubicBezierShape`] into a [`Mesh`].
2147    ///
2148    /// * `cubic_shape`: the shape to tessellate.
2149    /// * `out`: triangles are appended to this.
2150    pub fn tessellate_cubic_bezier(&mut self, cubic_shape: &CubicBezierShape, out: &mut Mesh) {
2151        let options = &self.options;
2152        let clip_rect = self.clip_rect;
2153        if options.coarse_tessellation_culling
2154            && !cubic_shape.visual_bounding_rect().intersects(clip_rect)
2155        {
2156            return;
2157        }
2158
2159        let points_vec =
2160            cubic_shape.flatten_closed(Some(options.bezier_tolerance), Some(options.epsilon));
2161
2162        for points in points_vec {
2163            self.tessellate_bezier_complete(
2164                &points,
2165                cubic_shape.fill,
2166                cubic_shape.closed,
2167                &cubic_shape.stroke,
2168                out,
2169            );
2170        }
2171    }
2172
2173    fn tessellate_bezier_complete(
2174        &mut self,
2175        points: &[Pos2],
2176        fill: Color32,
2177        closed: bool,
2178        stroke: &PathStroke,
2179        out: &mut Mesh,
2180    ) {
2181        if points.len() < 2 {
2182            return;
2183        }
2184
2185        self.scratchpad_path.clear();
2186        if closed {
2187            self.scratchpad_path.add_line_loop(points);
2188
2189            self.scratchpad_path
2190                .fill_and_stroke(self.feathering, fill, stroke, out);
2191        } else {
2192            debug_assert_eq!(
2193                fill,
2194                Color32::TRANSPARENT,
2195                "You asked to fill a bezier path that is not closed. That makes no sense."
2196            );
2197
2198            self.scratchpad_path.add_open_points(points);
2199
2200            self.scratchpad_path
2201                .stroke(self.feathering, PathType::Open, stroke, out);
2202        }
2203    }
2204}
2205
2206fn round_line_segment(coord: &mut f32, stroke: &Stroke, pixels_per_point: f32) {
2207    // If the stroke is an odd number of pixels wide,
2208    // we want to round the center of it to the center of a pixel.
2209    //
2210    // If however it is an even number of pixels wide,
2211    // we want to round the center to be between two pixels.
2212    //
2213    // We also want to treat strokes that are _almost_ odd as it it was odd,
2214    // to make it symmetric. Same for strokes that are _almost_ even.
2215    //
2216    // For strokes less than a pixel wide we also round to the center,
2217    // because it will rendered as a single row of pixels by the tessellator.
2218
2219    let pixel_size = 1.0 / pixels_per_point;
2220
2221    if stroke.width <= pixel_size || is_nearest_integer_odd(pixels_per_point * stroke.width) {
2222        *coord = coord.round_to_pixel_center(pixels_per_point);
2223    } else {
2224        *coord = coord.round_to_pixels(pixels_per_point);
2225    }
2226}
2227
2228fn is_nearest_integer_odd(width: f32) -> bool {
2229    (width * 0.5 + 0.25).fract() > 0.5
2230}
2231
2232#[test]
2233fn test_is_nearest_integer_odd() {
2234    assert!(is_nearest_integer_odd(0.6));
2235    assert!(is_nearest_integer_odd(1.0));
2236    assert!(is_nearest_integer_odd(1.4));
2237    assert!(!is_nearest_integer_odd(1.6));
2238    assert!(!is_nearest_integer_odd(2.0));
2239    assert!(!is_nearest_integer_odd(2.4));
2240    assert!(is_nearest_integer_odd(2.6));
2241    assert!(is_nearest_integer_odd(3.0));
2242    assert!(is_nearest_integer_odd(3.4));
2243}
2244
2245#[deprecated = "Use `Tessellator::new(…).tessellate_shapes(…)` instead"]
2246pub fn tessellate_shapes(
2247    pixels_per_point: f32,
2248    options: TessellationOptions,
2249    font_tex_size: [usize; 2],
2250    prepared_discs: Vec<PreparedDisc>,
2251    shapes: Vec<ClippedShape>,
2252) -> Vec<ClippedPrimitive> {
2253    Tessellator::new(pixels_per_point, options, font_tex_size, prepared_discs)
2254        .tessellate_shapes(shapes)
2255}
2256
2257impl Tessellator {
2258    /// Turns [`Shape`]:s into sets of triangles.
2259    ///
2260    /// The given shapes will tessellated in the same order as they are given.
2261    /// They will be batched together by clip rectangle.
2262    ///
2263    /// * `pixels_per_point`: number of physical pixels to each logical point
2264    /// * `options`: tessellation quality
2265    /// * `shapes`: what to tessellate
2266    /// * `font_tex_size`: size of the font texture. Required to normalize glyph uv rectangles when tessellating text.
2267    /// * `prepared_discs`: What [`crate::TextureAtlas::prepared_discs`] returns. Can safely be set to an empty vec.
2268    ///
2269    /// The implementation uses a [`Tessellator`].
2270    ///
2271    /// ## Returns
2272    /// A list of clip rectangles with matching [`Mesh`].
2273    #[allow(unused_mut)]
2274    pub fn tessellate_shapes(&mut self, mut shapes: Vec<ClippedShape>) -> Vec<ClippedPrimitive> {
2275        profiling::function_scope!();
2276
2277        #[cfg(feature = "rayon")]
2278        if self.options.parallel_tessellation {
2279            self.parallel_tessellation_of_large_shapes(&mut shapes);
2280        }
2281
2282        let mut clipped_primitives: Vec<ClippedPrimitive> = Vec::default();
2283
2284        {
2285            profiling::scope!("tessellate");
2286            for clipped_shape in shapes {
2287                self.tessellate_clipped_shape(clipped_shape, &mut clipped_primitives);
2288            }
2289        }
2290
2291        if self.options.debug_paint_clip_rects {
2292            clipped_primitives = self.add_clip_rects(clipped_primitives);
2293        }
2294
2295        if self.options.debug_ignore_clip_rects {
2296            for clipped_primitive in &mut clipped_primitives {
2297                clipped_primitive.clip_rect = Rect::EVERYTHING;
2298            }
2299        }
2300
2301        clipped_primitives.retain(|p| {
2302            p.clip_rect.is_positive()
2303                && match &p.primitive {
2304                    Primitive::Mesh(mesh) => !mesh.is_empty(),
2305                    Primitive::Callback(_) => true,
2306                }
2307        });
2308
2309        for clipped_primitive in &clipped_primitives {
2310            if let Primitive::Mesh(mesh) = &clipped_primitive.primitive {
2311                debug_assert!(mesh.is_valid(), "Tessellator generated invalid Mesh");
2312            }
2313        }
2314
2315        clipped_primitives
2316    }
2317
2318    /// Find large shapes and throw them on the rayon thread pool,
2319    /// then replace the original shape with their tessellated meshes.
2320    #[cfg(feature = "rayon")]
2321    fn parallel_tessellation_of_large_shapes(&self, shapes: &mut [ClippedShape]) {
2322        profiling::function_scope!();
2323
2324        use rayon::prelude::*;
2325
2326        // We only parallelize large/slow stuff, because each tessellation job
2327        // will allocate a new Mesh, and so it creates a lot of extra memory fragmentation
2328        // and allocations that is only worth it for large shapes.
2329        fn should_parallelize(shape: &Shape) -> bool {
2330            match shape {
2331                Shape::Vec(shapes) => 4 < shapes.len() || shapes.iter().any(should_parallelize),
2332
2333                Shape::Path(path_shape) => 32 < path_shape.points.len(),
2334
2335                Shape::QuadraticBezier(_) | Shape::CubicBezier(_) | Shape::Ellipse(_) => true,
2336
2337                Shape::Noop
2338                | Shape::Text(_)
2339                | Shape::Circle(_)
2340                | Shape::Mesh(_)
2341                | Shape::LineSegment { .. }
2342                | Shape::Rect(_)
2343                | Shape::Callback(_) => false,
2344            }
2345        }
2346
2347        let tessellated: Vec<(usize, Mesh)> = shapes
2348            .par_iter()
2349            .enumerate()
2350            .filter(|(_, clipped_shape)| should_parallelize(&clipped_shape.shape))
2351            .map(|(index, clipped_shape)| {
2352                profiling::scope!("tessellate_big_shape");
2353                // TODO(emilk): reuse tessellator in a thread local
2354                let mut tessellator = (*self).clone();
2355                let mut mesh = Mesh::default();
2356                tessellator.tessellate_shape(clipped_shape.shape.clone(), &mut mesh);
2357                (index, mesh)
2358            })
2359            .collect();
2360
2361        profiling::scope!("distribute results", tessellated.len().to_string());
2362        for (index, mesh) in tessellated {
2363            shapes[index].shape = Shape::Mesh(mesh.into());
2364        }
2365    }
2366
2367    fn add_clip_rects(
2368        &mut self,
2369        clipped_primitives: Vec<ClippedPrimitive>,
2370    ) -> Vec<ClippedPrimitive> {
2371        self.clip_rect = Rect::EVERYTHING;
2372        let stroke = Stroke::new(2.0, Color32::from_rgb(150, 255, 150));
2373
2374        clipped_primitives
2375            .into_iter()
2376            .flat_map(|clipped_primitive| {
2377                let mut clip_rect_mesh = Mesh::default();
2378                self.tessellate_shape(
2379                    Shape::rect_stroke(
2380                        clipped_primitive.clip_rect,
2381                        0.0,
2382                        stroke,
2383                        StrokeKind::Outside,
2384                    ),
2385                    &mut clip_rect_mesh,
2386                );
2387
2388                [
2389                    clipped_primitive,
2390                    ClippedPrimitive {
2391                        clip_rect: Rect::EVERYTHING, // whatever
2392                        primitive: Primitive::Mesh(clip_rect_mesh),
2393                    },
2394                ]
2395            })
2396            .collect()
2397    }
2398}
2399
2400#[test]
2401fn test_tessellator() {
2402    use crate::*;
2403
2404    let mut shapes = Vec::with_capacity(2);
2405
2406    let rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0));
2407    let uv = Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0));
2408
2409    let mut mesh = Mesh::with_texture(TextureId::Managed(1));
2410    mesh.add_rect_with_uv(rect, uv, Color32::WHITE);
2411    shapes.push(Shape::mesh(mesh));
2412
2413    let mut mesh = Mesh::with_texture(TextureId::Managed(2));
2414    mesh.add_rect_with_uv(rect, uv, Color32::WHITE);
2415    shapes.push(Shape::mesh(mesh));
2416
2417    let shape = Shape::Vec(shapes);
2418    let clipped_shapes = vec![ClippedShape {
2419        clip_rect: rect,
2420        shape,
2421    }];
2422
2423    let font_tex_size = [1024, 1024]; // unused
2424    let prepared_discs = vec![]; // unused
2425
2426    let primitives = Tessellator::new(1.0, Default::default(), font_tex_size, prepared_discs)
2427        .tessellate_shapes(clipped_shapes);
2428
2429    assert_eq!(primitives.len(), 2);
2430}
2431
2432#[test]
2433fn path_bounding_box() {
2434    use crate::*;
2435
2436    for i in 1..=100 {
2437        let width = i as f32;
2438
2439        let rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(10.0, 10.0));
2440        let expected_rect = rect.expand((width / 2.0) + 1.5);
2441
2442        let mut mesh = Mesh::default();
2443
2444        let mut path = Path::default();
2445        path.add_open_points(&[
2446            pos2(0.0, 0.0),
2447            pos2(2.0, 0.0),
2448            pos2(5.0, 5.0),
2449            pos2(0.0, 5.0),
2450            pos2(0.0, 7.0),
2451            pos2(10.0, 10.0),
2452        ]);
2453
2454        path.stroke(
2455            1.5,
2456            PathType::Closed,
2457            &PathStroke::new_uv(width, move |r, p| {
2458                assert_eq!(r, expected_rect);
2459                // see https://github.com/emilk/egui/pull/4353#discussion_r1573879940 for why .contains() isn't used here.
2460                // TL;DR rounding errors.
2461                assert!(
2462                    r.distance_to_pos(p) <= 0.55,
2463                    "passed rect {r:?} didn't contain point {p:?} (distance: {})",
2464                    r.distance_to_pos(p)
2465                );
2466                assert!(
2467                    expected_rect.distance_to_pos(p) <= 0.55,
2468                    "expected rect {expected_rect:?} didn't contain point {p:?}"
2469                );
2470                Color32::WHITE
2471            }),
2472            &mut mesh,
2473        );
2474    }
2475}