Skip to main content

fyrox_ui/
draw.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use crate::font::FontHeight;
22use crate::formatted_text::{DrawValueLayer, GlyphDrawValues};
23use crate::style::resource::StyleResource;
24use crate::{
25    brush::Brush,
26    core::{
27        algebra::{Matrix3, Point2, Vector2},
28        color::Color,
29        log::Log,
30        math::{self, Rect, TriangleDefinition},
31    },
32    font::FontResource,
33    formatted_text::FormattedText,
34    Thickness,
35};
36use bytemuck::{Pod, Zeroable};
37use fyrox_core::math::{round_to_step, OptionRect};
38use fyrox_material::MaterialResource;
39use fyrox_texture::TextureResource;
40use std::fmt::{Display, Formatter};
41use std::ops::Range;
42
43#[derive(Clone, Copy, Debug, Pod, Zeroable)]
44#[repr(C)]
45pub struct Vertex {
46    pub pos: Vector2<f32>,
47    pub tex_coord: Vector2<f32>,
48    pub color: Color,
49}
50
51impl Vertex {
52    fn new(pos: Vector2<f32>, tex_coord: Vector2<f32>) -> Vertex {
53        Vertex {
54            pos,
55            tex_coord,
56            color: Color::WHITE,
57        }
58    }
59}
60
61#[derive(Clone, Debug)]
62pub enum CommandTexture {
63    None,
64    Texture(TextureResource),
65    Font {
66        font: FontResource,
67        height: FontHeight,
68        page_index: usize,
69    },
70}
71
72/// A set of triangles that will be used for clipping.
73#[derive(Clone, Debug)]
74pub struct ClippingGeometry {
75    pub vertex_buffer: Vec<Vertex>,
76    pub triangle_buffer: Vec<TriangleDefinition>,
77    pub transform_stack: TransformStack,
78}
79
80impl Draw for ClippingGeometry {
81    #[inline(always)]
82    fn push_vertex_raw(&mut self, mut vertex: Vertex) {
83        vertex.pos = self
84            .transform_stack
85            .transform
86            .transform_point(&Point2::from(vertex.pos))
87            .coords;
88
89        self.vertex_buffer.push(vertex);
90    }
91
92    #[inline(always)]
93    fn push_triangle(&mut self, a: u32, b: u32, c: u32) {
94        self.triangle_buffer.push(TriangleDefinition([a, b, c]));
95    }
96
97    #[inline(always)]
98    fn last_vertex_index(&self) -> u32 {
99        self.vertex_buffer.len() as u32
100    }
101}
102
103impl ClippingGeometry {
104    #[inline]
105    pub fn is_contains_point(&self, pos: Vector2<f32>) -> bool {
106        for triangle in self.triangle_buffer.iter() {
107            if let Some((va, vb, vc)) = self.triangle_points(triangle) {
108                if math::is_point_inside_2d_triangle(pos, va.pos, vb.pos, vc.pos) {
109                    return true;
110                }
111            }
112        }
113
114        false
115    }
116
117    #[inline]
118    pub fn triangle_points(
119        &self,
120        triangle: &TriangleDefinition,
121    ) -> Option<(&Vertex, &Vertex, &Vertex)> {
122        let a = self.vertex_buffer.get(triangle[0] as usize)?;
123        let b = self.vertex_buffer.get(triangle[1] as usize)?;
124        let c = self.vertex_buffer.get(triangle[2] as usize)?;
125        Some((a, b, c))
126    }
127}
128
129#[derive(Clone, Debug)]
130pub struct Command {
131    /// Clipping bounds, should be used for scissor-test. Screen-space.
132    pub clip_bounds: Rect<f32>,
133    /// Total bounds of command's geometry. Screen-space.
134    pub bounds: Rect<f32>,
135    /// Brush defines the visual appearance of rendered geometry.
136    pub brush: Brush,
137    pub texture: CommandTexture,
138    pub triangles: Range<usize>,
139    pub material: MaterialResource,
140    pub opacity: f32,
141    /// A set of triangles that defines clipping region.
142    pub clipping_geometry: Option<ClippingGeometry>,
143}
144
145pub trait Draw {
146    #[inline]
147    fn push_vertex(&mut self, pos: Vector2<f32>, tex_coord: Vector2<f32>) {
148        self.push_vertex_raw(Vertex::new(pos, tex_coord))
149    }
150
151    fn push_vertex_raw(&mut self, vertex: Vertex);
152
153    fn push_triangle(&mut self, a: u32, b: u32, c: u32);
154
155    fn last_vertex_index(&self) -> u32;
156
157    #[inline]
158    fn push_triangle_multicolor(&mut self, vertices: [(Vector2<f32>, Color); 3]) {
159        let index = self.last_vertex_index();
160        for &(pos, color) in &vertices {
161            self.push_vertex_raw(Vertex {
162                pos,
163                tex_coord: Vector2::new(0.0, 0.0),
164                color,
165            });
166        }
167
168        self.push_triangle(index, index + 1, index + 2);
169    }
170
171    #[inline]
172    fn push_triangle_filled(&mut self, vertices: [Vector2<f32>; 3]) {
173        let index = self.last_vertex_index();
174
175        for &pos in &vertices {
176            self.push_vertex(pos, Default::default());
177        }
178
179        self.push_triangle(index, index + 1, index + 2);
180    }
181
182    #[inline]
183    fn push_line(&mut self, a: Vector2<f32>, b: Vector2<f32>, thickness: f32) {
184        let index = self.last_vertex_index();
185        let perp = get_line_thickness_vector(a, b, thickness);
186        self.push_vertex(a - perp, Vector2::new(0.0, 0.0));
187        self.push_vertex(b - perp, Vector2::new(1.0, 0.0));
188        self.push_vertex(a + perp, Vector2::new(1.0, 1.0));
189        self.push_vertex(b + perp, Vector2::new(0.0, 1.0));
190
191        self.push_triangle(index, index + 1, index + 2);
192        self.push_triangle(index + 2, index + 1, index + 3);
193    }
194
195    #[inline]
196    fn push_rect(&mut self, rect: &Rect<f32>, thickness: f32) {
197        let offset = thickness * 0.5;
198
199        let left_top = Vector2::new(rect.x() + offset, rect.y() + thickness);
200        let right_top = Vector2::new(rect.x() + rect.w() - offset, rect.y() + thickness);
201        let right_bottom = Vector2::new(
202            rect.x() + rect.w() - offset,
203            rect.y() + rect.h() - thickness,
204        );
205        let left_bottom = Vector2::new(rect.x() + offset, rect.y() + rect.h() - thickness);
206        let left_top_off = Vector2::new(rect.x(), rect.y() + offset);
207        let right_top_off = Vector2::new(rect.x() + rect.w(), rect.y() + offset);
208        let right_bottom_off = Vector2::new(rect.x() + rect.w(), rect.y() + rect.h() - offset);
209        let left_bottom_off = Vector2::new(rect.x(), rect.y() + rect.h() - offset);
210
211        // Horizontal lines
212        self.push_line(left_top_off, right_top_off, thickness);
213        self.push_line(right_bottom_off, left_bottom_off, thickness);
214
215        // Vertical line
216        self.push_line(right_top, right_bottom, thickness);
217        self.push_line(left_bottom, left_top, thickness);
218    }
219
220    #[inline]
221    fn push_rect_vary(&mut self, rect: &Rect<f32>, thickness: Thickness) {
222        let left_top = Vector2::new(rect.x() + thickness.left * 0.5, rect.y() + thickness.top);
223        let right_top = Vector2::new(
224            rect.x() + rect.w() - thickness.right * 0.5,
225            rect.y() + thickness.top,
226        );
227        let right_bottom = Vector2::new(
228            rect.x() + rect.w() - thickness.right * 0.5,
229            rect.y() + rect.h() - thickness.bottom,
230        );
231        let left_bottom = Vector2::new(
232            rect.x() + thickness.left * 0.5,
233            rect.y() + rect.h() - thickness.bottom,
234        );
235        let left_top_off = Vector2::new(rect.x(), rect.y() + thickness.top * 0.5);
236        let right_top_off = Vector2::new(rect.x() + rect.w(), rect.y() + thickness.top * 0.5);
237        let right_bottom_off = Vector2::new(
238            rect.x() + rect.w(),
239            rect.y() + rect.h() - thickness.bottom * 0.5,
240        );
241        let left_bottom_off = Vector2::new(rect.x(), rect.y() + rect.h() - thickness.bottom * 0.5);
242
243        // Horizontal lines
244        self.push_line(left_top_off, right_top_off, thickness.top);
245        self.push_line(right_bottom_off, left_bottom_off, thickness.bottom);
246
247        // Vertical lines
248        self.push_line(right_top, right_bottom, thickness.right);
249        self.push_line(left_bottom, left_top, thickness.left);
250    }
251
252    #[inline]
253    fn push_rect_filled(&mut self, rect: &Rect<f32>, tex_coords: Option<&[Vector2<f32>; 4]>) {
254        let index = self.last_vertex_index();
255        self.push_vertex(
256            Vector2::new(rect.x(), rect.y()),
257            tex_coords.map_or(Vector2::new(0.0, 0.0), |t| t[0]),
258        );
259        self.push_vertex(
260            Vector2::new(rect.x() + rect.w(), rect.y()),
261            tex_coords.map_or(Vector2::new(1.0, 0.0), |t| t[1]),
262        );
263        self.push_vertex(
264            Vector2::new(rect.x() + rect.w(), rect.y() + rect.h()),
265            tex_coords.map_or(Vector2::new(1.0, 1.0), |t| t[2]),
266        );
267        self.push_vertex(
268            Vector2::new(rect.x(), rect.y() + rect.h()),
269            tex_coords.map_or(Vector2::new(0.0, 1.0), |t| t[3]),
270        );
271
272        self.push_triangle(index, index + 1, index + 2);
273        self.push_triangle(index, index + 2, index + 3);
274    }
275
276    #[inline]
277    fn push_rect_multicolor(&mut self, rect: &Rect<f32>, colors: [Color; 4]) {
278        let index = self.last_vertex_index();
279        self.push_vertex_raw(Vertex {
280            pos: rect.left_top_corner(),
281            tex_coord: Vector2::new(0.0, 0.0),
282            color: colors[0],
283        });
284        self.push_vertex_raw(Vertex {
285            pos: rect.right_top_corner(),
286            tex_coord: Vector2::new(1.0, 0.0),
287            color: colors[1],
288        });
289        self.push_vertex_raw(Vertex {
290            pos: rect.right_bottom_corner(),
291            tex_coord: Vector2::new(1.0, 1.0),
292            color: colors[2],
293        });
294        self.push_vertex_raw(Vertex {
295            pos: rect.left_bottom_corner(),
296            tex_coord: Vector2::new(0.0, 1.0),
297            color: colors[3],
298        });
299
300        self.push_triangle(index, index + 1, index + 2);
301        self.push_triangle(index, index + 2, index + 3);
302    }
303
304    #[inline]
305    fn push_circle_filled(
306        &mut self,
307        origin: Vector2<f32>,
308        radius: f32,
309        segments: usize,
310        color: Color,
311    ) {
312        if segments >= 3 {
313            let center_index = self.last_vertex_index();
314
315            self.push_vertex_raw(Vertex {
316                pos: origin,
317                tex_coord: Vector2::default(),
318                color,
319            });
320
321            let two_pi = 2.0 * std::f32::consts::PI;
322            let delta_angle = two_pi / (segments as f32);
323            let mut angle: f32 = 0.0;
324            for _ in 0..segments {
325                let x = origin.x + radius * angle.cos();
326                let y = origin.y + radius * angle.sin();
327                self.push_vertex_raw(Vertex {
328                    pos: Vector2::new(x, y),
329                    tex_coord: Vector2::default(),
330                    color,
331                });
332                angle += delta_angle;
333            }
334
335            let first_vertex = center_index + 1;
336            for segment in 0..segments {
337                self.push_triangle(
338                    center_index,
339                    first_vertex + segment as u32,
340                    first_vertex + (segment as u32 + 1) % segments as u32,
341                );
342            }
343        }
344    }
345
346    #[inline]
347    fn push_circle(
348        &mut self,
349        center: Vector2<f32>,
350        radius: f32,
351        subdivisions: usize,
352        thickness: f32,
353    ) {
354        let start_vertex = self.last_vertex_index();
355        let d = std::f32::consts::TAU / subdivisions as f32;
356
357        let half_thickness = thickness * 0.5;
358
359        let mut angle = 0.0;
360        while angle < std::f32::consts::TAU {
361            let r = Vector2::new(angle.cos(), angle.sin());
362
363            let p0 = center + r.scale(radius - half_thickness);
364            self.push_vertex(p0, Default::default());
365
366            let p1 = center + r.scale(radius + half_thickness);
367            self.push_vertex(p1, Default::default());
368
369            angle += d;
370        }
371        let last_vertex_index = self.last_vertex_index();
372
373        self.connect_as_line(start_vertex, last_vertex_index, true)
374    }
375
376    #[inline]
377    fn connect_as_line(&mut self, from: u32, to: u32, closed: bool) {
378        if closed {
379            let count = to - from;
380            for i in (0..count).step_by(2) {
381                let i0 = from + i % count;
382                let i1 = from + (i + 1) % count;
383                let i2 = from + (i + 2) % count;
384                let i3 = from + (i + 3) % count;
385                self.push_triangle(i0, i1, i2);
386                self.push_triangle(i1, i3, i2);
387            }
388        } else {
389            for i in (from..to.saturating_sub(4)).step_by(2) {
390                let i0 = i;
391                let i1 = i + 1;
392                let i2 = i + 2;
393                let i3 = i + 3;
394                self.push_triangle(i0, i1, i2);
395                self.push_triangle(i1, i3, i2);
396            }
397        }
398    }
399
400    #[inline]
401    fn push_arc(
402        &mut self,
403        center: Vector2<f32>,
404        radius: f32,
405        angles: Range<f32>,
406        subdivisions: usize,
407        thickness: f32,
408    ) {
409        let start_vertex = self.last_vertex_index();
410        self.push_arc_path_with_thickness(center, radius, angles, subdivisions, thickness);
411        let last_vertex_index = self.last_vertex_index();
412
413        self.connect_as_line(start_vertex, last_vertex_index, false)
414    }
415
416    #[inline]
417    fn push_arc_path_with_thickness(
418        &mut self,
419        center: Vector2<f32>,
420        radius: f32,
421        angles: Range<f32>,
422        subdivisions: usize,
423        thickness: f32,
424    ) {
425        let mut start_angle = math::wrap_angle(angles.start);
426        let mut end_angle = math::wrap_angle(angles.end);
427
428        if start_angle > end_angle {
429            std::mem::swap(&mut start_angle, &mut end_angle);
430        }
431
432        let d = (end_angle - start_angle) / subdivisions as f32;
433
434        let half_thickness = thickness * 0.5;
435
436        let mut angle = start_angle;
437        while angle <= end_angle {
438            let r = Vector2::new(angle.cos(), angle.sin());
439
440            let p0 = center + r.scale(radius - half_thickness);
441            self.push_vertex(p0, Default::default());
442
443            let p1 = center + r.scale(radius + half_thickness);
444            self.push_vertex(p1, Default::default());
445
446            angle += d;
447        }
448    }
449
450    #[inline]
451    fn push_arc_path(
452        &mut self,
453        center: Vector2<f32>,
454        radius: f32,
455        angles: Range<f32>,
456        subdivisions: usize,
457    ) {
458        let mut start_angle = math::wrap_angle(angles.start);
459        let mut end_angle = math::wrap_angle(angles.end);
460
461        if start_angle > end_angle {
462            std::mem::swap(&mut start_angle, &mut end_angle);
463        }
464
465        let d = (end_angle - start_angle) / subdivisions as f32;
466
467        let mut angle = start_angle;
468        while angle <= end_angle {
469            let p0 = center + Vector2::new(angle.cos() * radius, angle.sin() * radius);
470
471            self.push_vertex(p0, Default::default());
472
473            angle += d;
474        }
475    }
476
477    #[inline]
478    fn push_line_path(&mut self, a: Vector2<f32>, b: Vector2<f32>) {
479        self.push_vertex(a, Default::default());
480        self.push_vertex(b, Default::default());
481    }
482
483    #[inline]
484    fn push_line_path_with_thickness(&mut self, a: Vector2<f32>, b: Vector2<f32>, thickness: f32) {
485        let perp = get_line_thickness_vector(a, b, thickness);
486        self.push_vertex(a - perp, Vector2::new(0.0, 0.0));
487        self.push_vertex(a + perp, Vector2::new(1.0, 1.0));
488        self.push_vertex(b - perp, Vector2::new(1.0, 0.0));
489        self.push_vertex(b + perp, Vector2::new(0.0, 1.0));
490    }
491
492    #[inline]
493    fn push_rounded_rect_filled(
494        &mut self,
495        rect: &Rect<f32>,
496        mut corner_radius: f32,
497        corner_subdivisions: usize,
498    ) {
499        // Restrict corner radius in available rectangle.
500        let min_axis = rect.w().min(rect.h());
501        corner_radius = corner_radius.min(min_axis * 0.5);
502
503        let center_index = self.last_vertex_index();
504        self.push_vertex(rect.center(), Default::default());
505
506        self.push_line_path(
507            Vector2::new(rect.x(), rect.y() + rect.h() - corner_radius),
508            Vector2::new(rect.x(), rect.y() + corner_radius),
509        );
510
511        self.push_arc_path(
512            rect.position + Vector2::repeat(corner_radius),
513            corner_radius,
514            180.0f32.to_radians()..270.0f32.to_radians(),
515            corner_subdivisions,
516        );
517
518        self.push_line_path(
519            Vector2::new(rect.x() + corner_radius, rect.y()),
520            Vector2::new(rect.x() + rect.w() - corner_radius, rect.y()),
521        );
522
523        self.push_arc_path(
524            Vector2::new(
525                rect.position.x + rect.w() - corner_radius,
526                rect.position.y + corner_radius,
527            ),
528            corner_radius,
529            270.0f32.to_radians()..359.9999f32.to_radians(),
530            corner_subdivisions,
531        );
532
533        self.push_line_path(
534            Vector2::new(rect.x() + rect.w(), rect.y() + corner_radius),
535            Vector2::new(rect.x() + rect.w(), rect.y() + rect.h() - corner_radius),
536        );
537
538        self.push_arc_path(
539            Vector2::new(
540                rect.position.x + rect.w() - corner_radius,
541                rect.position.y + rect.h() - corner_radius,
542            ),
543            corner_radius,
544            0.0f32.to_radians()..90.0f32.to_radians(),
545            corner_subdivisions,
546        );
547
548        self.push_line_path(
549            Vector2::new(rect.x() + rect.w() - corner_radius, rect.y() + rect.h()),
550            Vector2::new(rect.x() + corner_radius, rect.y() + rect.h()),
551        );
552
553        self.push_arc_path(
554            Vector2::new(
555                rect.position.x + corner_radius,
556                rect.position.y + rect.h() - corner_radius,
557            ),
558            corner_radius,
559            90.0f32.to_radians()..180.0f32.to_radians(),
560            corner_subdivisions,
561        );
562
563        // Connect all vertices.
564        let first_index = center_index + 1;
565        let last_vertex_index = self.last_vertex_index().saturating_sub(1);
566        for i in first_index..last_vertex_index {
567            let next = i + 1;
568            self.push_triangle(i, next, center_index)
569        }
570
571        self.push_triangle(last_vertex_index, first_index, center_index);
572    }
573
574    #[inline]
575    fn push_rounded_rect(
576        &mut self,
577        rect: &Rect<f32>,
578        thickness: f32,
579        mut corner_radius: f32,
580        corner_subdivisions: usize,
581    ) {
582        // Restrict corner radius in available rectangle.
583        let min_axis = rect.w().min(rect.h());
584        corner_radius = corner_radius.min(min_axis * 0.5);
585
586        let half_thickness = thickness * 0.5;
587
588        let start_index = self.last_vertex_index();
589
590        self.push_line_path_with_thickness(
591            Vector2::new(
592                rect.x() + half_thickness,
593                rect.y() + rect.h() - thickness - corner_radius,
594            ),
595            Vector2::new(
596                rect.x() + half_thickness,
597                rect.y() + thickness + corner_radius,
598            ),
599            thickness,
600        );
601
602        self.push_arc_path_with_thickness(
603            rect.position + Vector2::repeat(corner_radius + half_thickness),
604            corner_radius,
605            180.0f32.to_radians()..270.0f32.to_radians(),
606            corner_subdivisions,
607            thickness,
608        );
609
610        self.push_line_path_with_thickness(
611            Vector2::new(
612                rect.x() + corner_radius + half_thickness,
613                rect.y() + half_thickness,
614            ),
615            Vector2::new(
616                rect.x() + rect.w() - corner_radius - half_thickness,
617                rect.y() + half_thickness,
618            ),
619            thickness,
620        );
621
622        self.push_arc_path_with_thickness(
623            Vector2::new(
624                rect.position.x + rect.w() - corner_radius - half_thickness,
625                rect.position.y + corner_radius + half_thickness,
626            ),
627            corner_radius,
628            270.0f32.to_radians()..359.9999f32.to_radians(),
629            corner_subdivisions,
630            thickness,
631        );
632
633        self.push_line_path_with_thickness(
634            Vector2::new(
635                rect.x() + rect.w() - half_thickness,
636                rect.y() + thickness + corner_radius,
637            ),
638            Vector2::new(
639                rect.x() + rect.w() - half_thickness,
640                rect.y() + rect.h() - thickness - corner_radius,
641            ),
642            thickness,
643        );
644
645        self.push_arc_path_with_thickness(
646            Vector2::new(
647                rect.position.x + rect.w() - corner_radius - half_thickness,
648                rect.position.y + rect.h() - corner_radius - half_thickness,
649            ),
650            corner_radius,
651            0.0f32.to_radians()..90.0f32.to_radians(),
652            corner_subdivisions,
653            thickness,
654        );
655
656        self.push_line_path_with_thickness(
657            Vector2::new(
658                rect.x() + rect.w() - corner_radius - half_thickness,
659                rect.y() + rect.h() - half_thickness,
660            ),
661            Vector2::new(
662                rect.x() + corner_radius + half_thickness,
663                rect.y() + rect.h() - half_thickness,
664            ),
665            thickness,
666        );
667
668        self.push_arc_path_with_thickness(
669            Vector2::new(
670                rect.position.x + corner_radius + half_thickness,
671                rect.position.y + rect.h() - corner_radius - half_thickness,
672            ),
673            corner_radius,
674            90.0f32.to_radians()..180.0f32.to_radians(),
675            corner_subdivisions,
676            thickness,
677        );
678
679        let last_vertex_index = self.last_vertex_index();
680        self.connect_as_line(start_index, last_vertex_index, true);
681    }
682
683    #[inline]
684    fn push_bezier(
685        &mut self,
686        p0: Vector2<f32>,
687        p1: Vector2<f32>,
688        p2: Vector2<f32>,
689        p3: Vector2<f32>,
690        subdivisions: usize,
691        thickness: f32,
692    ) {
693        fn cubic_bezier(
694            p0: Vector2<f32>,
695            p1: Vector2<f32>,
696            p2: Vector2<f32>,
697            p3: Vector2<f32>,
698            t: f32,
699        ) -> Vector2<f32> {
700            p0.scale((1.0 - t).powi(3))
701                + p1.scale(3.0 * t * (1.0 - t).powi(2))
702                + p2.scale(3.0 * t.powi(2) * (1.0 - t))
703                + p3.scale(t.powi(3))
704        }
705
706        let mut prev = cubic_bezier(p0, p1, p2, p3, 0.0);
707        for i in 0..subdivisions {
708            let t = (i + 1) as f32 / subdivisions as f32;
709            let next = cubic_bezier(p0, p1, p2, p3, t);
710            // TODO: This could give gaps between segments on sharp turns, it should be either patched
711            // or be continuous line instead of separate segments.
712            self.push_line(prev, next, thickness);
713            prev = next;
714        }
715    }
716
717    #[inline]
718    fn push_grid(&mut self, zoom: f32, cell_size: Vector2<f32>, grid_bounds: Rect<f32>) {
719        let mut local_left_bottom = grid_bounds.left_top_corner();
720        local_left_bottom.x = round_to_step(local_left_bottom.x, cell_size.x);
721        local_left_bottom.y = round_to_step(local_left_bottom.y, cell_size.y);
722
723        let mut local_right_top = grid_bounds.right_bottom_corner();
724        local_right_top.x = round_to_step(local_right_top.x, cell_size.x);
725        local_right_top.y = round_to_step(local_right_top.y, cell_size.y);
726
727        let w = (local_right_top.x - local_left_bottom.x).abs();
728        let h = (local_right_top.y - local_left_bottom.y).abs();
729
730        let nw = ((w / cell_size.x).ceil()) as usize;
731        let nh = ((h / cell_size.y).ceil()) as usize;
732
733        for ny in 0..=nh {
734            let k = ny as f32 / (nh) as f32;
735            let y = local_left_bottom.y + k * h;
736            self.push_line(
737                Vector2::new(local_left_bottom.x - cell_size.x, y),
738                Vector2::new(local_right_top.x + cell_size.x, y),
739                1.0 / zoom,
740            );
741        }
742
743        for nx in 0..=nw {
744            let k = nx as f32 / (nw) as f32;
745            let x = local_left_bottom.x + k * w;
746            self.push_line(
747                Vector2::new(x, local_left_bottom.y - cell_size.y),
748                Vector2::new(x, local_right_top.y + cell_size.y),
749                1.0 / zoom,
750            );
751        }
752    }
753}
754
755#[derive(Clone, Debug)]
756pub struct TransformStack {
757    transform: Matrix3<f32>,
758    stack: Vec<Matrix3<f32>>,
759}
760
761impl Default for TransformStack {
762    fn default() -> Self {
763        Self {
764            transform: Matrix3::identity(),
765            stack: vec![],
766        }
767    }
768}
769
770impl TransformStack {
771    #[inline]
772    pub fn push(&mut self, matrix: Matrix3<f32>) {
773        self.stack
774            .push(std::mem::replace(&mut self.transform, matrix));
775    }
776
777    /// Returns the transformation matrix that will be used to transform vertices of drawing context.
778    #[inline]
779    pub fn transform(&self) -> &Matrix3<f32> {
780        &self.transform
781    }
782
783    #[inline]
784    pub fn len(&self) -> usize {
785        self.stack.len()
786    }
787
788    #[inline]
789    pub fn is_empty(&self) -> bool {
790        self.stack.is_empty()
791    }
792
793    #[inline]
794    pub fn content(&self) -> Vec<Matrix3<f32>> {
795        self.stack.clone()
796    }
797
798    #[inline]
799    pub fn pop(&mut self) {
800        if let Some(top) = self.stack.pop() {
801            self.transform = top;
802        } else {
803            Log::err("TransformStack pop failure.")
804        }
805    }
806}
807
808#[derive(Debug, Clone, Default)]
809pub struct RenderData {
810    pub vertex_buffer: Vec<Vertex>,
811    pub triangle_buffer: Vec<TriangleDefinition>,
812    pub command_buffer: Vec<Command>,
813}
814
815impl Display for RenderData {
816    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
817        f.debug_struct("RenderData")
818            .field("Vertices Count: ", &self.vertex_buffer.len())
819            .field("Triangles Count: ", &self.triangle_buffer.len())
820            .field("Commands Count: ", &self.command_buffer.len())
821            .finish()
822    }
823}
824
825impl RenderData {
826    pub fn clear(&mut self) {
827        self.vertex_buffer.clear();
828        self.triangle_buffer.clear();
829        self.command_buffer.clear();
830    }
831
832    pub fn append(&mut self, other: &Self) {
833        let vertex_index_offset = self.vertex_buffer.len();
834        let triangle_index_offset = self.triangle_buffer.len();
835        self.vertex_buffer.extend_from_slice(&other.vertex_buffer);
836        for cmd in other.command_buffer.iter() {
837            let mut cmd_copy = cmd.clone();
838            cmd_copy.triangles.start += triangle_index_offset;
839            cmd_copy.triangles.end += triangle_index_offset;
840            self.command_buffer.push(cmd_copy);
841        }
842        for triangle in other.triangle_buffer.iter() {
843            self.triangle_buffer
844                .push(triangle.add(vertex_index_offset as u32));
845        }
846    }
847
848    #[inline]
849    pub fn triangle_points(
850        &self,
851        triangle: &TriangleDefinition,
852    ) -> Option<(&Vertex, &Vertex, &Vertex)> {
853        let a = self.vertex_buffer.get(triangle[0] as usize)?;
854        let b = self.vertex_buffer.get(triangle[1] as usize)?;
855        let c = self.vertex_buffer.get(triangle[2] as usize)?;
856        Some((a, b, c))
857    }
858
859    #[inline]
860    pub fn is_command_contains_point(&self, command: &Command, pos: Vector2<f32>) -> bool {
861        for i in command.triangles.clone() {
862            if let Some(triangle) = self.triangle_buffer.get(i) {
863                if let Some((va, vb, vc)) = self.triangle_points(triangle) {
864                    if math::is_point_inside_2d_triangle(pos, va.pos, vb.pos, vc.pos) {
865                        return true;
866                    }
867                }
868            }
869        }
870
871        false
872    }
873}
874
875#[derive(Debug, Clone)]
876pub struct DrawingContext {
877    pub render_data: RenderData,
878    pub transform_stack: TransformStack,
879    opacity_stack: Vec<f32>,
880    triangles_to_commit: usize,
881    pub style: StyleResource,
882    /// Amount of time (in seconds) that passed from the creation of the engine. Keep in mind that
883    /// this value is **not** guaranteed to match real time. A user can change delta time with
884    /// which the engine "ticks" and this delta time affects elapsed time.
885    pub elapsed_time: f32,
886}
887
888fn get_line_thickness_vector(a: Vector2<f32>, b: Vector2<f32>, thickness: f32) -> Vector2<f32> {
889    if let Some(dir) = (b - a).try_normalize(f32::EPSILON) {
890        Vector2::new(dir.y, -dir.x).scale(thickness * 0.5)
891    } else {
892        Vector2::default()
893    }
894}
895
896impl Draw for DrawingContext {
897    #[inline(always)]
898    fn push_vertex_raw(&mut self, mut vertex: Vertex) {
899        vertex.pos = self
900            .transform_stack
901            .transform
902            .transform_point(&Point2::from(vertex.pos))
903            .coords;
904
905        self.render_data.vertex_buffer.push(vertex);
906    }
907
908    #[inline(always)]
909    fn push_triangle(&mut self, a: u32, b: u32, c: u32) {
910        self.render_data
911            .triangle_buffer
912            .push(TriangleDefinition([a, b, c]));
913        self.triangles_to_commit += 1;
914    }
915
916    #[inline(always)]
917    fn last_vertex_index(&self) -> u32 {
918        self.render_data.vertex_buffer.len() as u32
919    }
920}
921
922impl DrawingContext {
923    #[inline]
924    pub fn new(style: StyleResource) -> DrawingContext {
925        DrawingContext {
926            render_data: RenderData::default(),
927            triangles_to_commit: 0,
928            opacity_stack: vec![1.0],
929            transform_stack: Default::default(),
930            style,
931            elapsed_time: 0.0,
932        }
933    }
934
935    #[inline]
936    pub fn clear(&mut self) {
937        self.render_data.clear();
938        self.opacity_stack.clear();
939        self.opacity_stack.push(1.0);
940        self.triangles_to_commit = 0;
941    }
942
943    #[inline]
944    pub fn take_render_data(&mut self) -> RenderData {
945        let render_data = std::mem::take(&mut self.render_data);
946        self.triangles_to_commit = 0;
947        render_data
948    }
949
950    pub fn append(&mut self, render_data: &RenderData) {
951        self.render_data.append(render_data);
952    }
953
954    #[inline]
955    pub fn get_vertices(&self) -> &[Vertex] {
956        self.render_data.vertex_buffer.as_slice()
957    }
958
959    #[inline]
960    pub fn get_triangles(&self) -> &[TriangleDefinition] {
961        self.render_data.triangle_buffer.as_slice()
962    }
963
964    #[inline]
965    pub fn get_commands(&self) -> &Vec<Command> {
966        &self.render_data.command_buffer
967    }
968
969    #[inline]
970    pub fn push_opacity(&mut self, opacity: f32) {
971        self.opacity_stack.push(opacity);
972    }
973
974    #[inline]
975    pub fn pop_opacity(&mut self) {
976        self.opacity_stack.pop().unwrap();
977    }
978
979    #[inline]
980    pub fn triangle_points(
981        &self,
982        triangle: &TriangleDefinition,
983    ) -> Option<(&Vertex, &Vertex, &Vertex)> {
984        self.render_data.triangle_points(triangle)
985    }
986
987    #[inline]
988    pub fn is_command_contains_point(&self, command: &Command, pos: Vector2<f32>) -> bool {
989        self.render_data.is_command_contains_point(command, pos)
990    }
991
992    #[inline]
993    fn pending_range(&self) -> Range<usize> {
994        if self.render_data.triangle_buffer.is_empty() {
995            0..self.triangles_to_commit
996        } else {
997            (self.render_data.triangle_buffer.len() - self.triangles_to_commit)
998                ..self.render_data.triangle_buffer.len()
999        }
1000    }
1001
1002    #[inline]
1003    fn bounds_of(&self, range: Range<usize>) -> Rect<f32> {
1004        let mut bounds = OptionRect::default();
1005        for i in range {
1006            for &k in self.render_data.triangle_buffer[i].as_ref() {
1007                bounds.push(self.render_data.vertex_buffer[k as usize].pos);
1008            }
1009        }
1010        bounds.unwrap_or_default()
1011    }
1012
1013    #[inline]
1014    pub fn commit(
1015        &mut self,
1016        clip_bounds: Rect<f32>,
1017        brush: Brush,
1018        texture: CommandTexture,
1019        material: &MaterialResource,
1020        clipping_geometry: Option<ClippingGeometry>,
1021    ) {
1022        if self.triangles_to_commit > 0 {
1023            let triangles = self.pending_range();
1024            let bounds = self.bounds_of(triangles.clone());
1025
1026            let opacity = *self.opacity_stack.last().unwrap();
1027            self.render_data.command_buffer.push(Command {
1028                clip_bounds,
1029                bounds,
1030                brush,
1031                texture,
1032                triangles,
1033                material: material.clone(),
1034                opacity,
1035                clipping_geometry,
1036            });
1037            self.triangles_to_commit = 0;
1038        }
1039    }
1040
1041    #[inline]
1042    pub fn draw_text(
1043        &mut self,
1044        clip_bounds: Rect<f32>,
1045        position: Vector2<f32>,
1046        material: &MaterialResource,
1047        formatted_text: &FormattedText,
1048    ) {
1049        #[inline(always)]
1050        fn draw(
1051            formatted_text: &FormattedText,
1052            layer: DrawValueLayer,
1053            ctx: &mut DrawingContext,
1054            clip_bounds: Rect<f32>,
1055            position: Vector2<f32>,
1056            material: &MaterialResource,
1057        ) {
1058            let mut current_draw_values = None;
1059            for element in formatted_text.get_glyphs() {
1060                if let DrawValueLayer::Shadow = layer {
1061                    if !formatted_text.shadow_at(element.source_char_index) {
1062                        continue;
1063                    }
1064                }
1065                let draw_values = formatted_text.get_glyph_draw_values(layer, element);
1066                if current_draw_values.is_none() {
1067                    current_draw_values = Some(draw_values)
1068                } else if current_draw_values.as_ref() != Some(&draw_values) {
1069                    // If the drawing values have changed, commit the text and start a new batch.
1070                    let GlyphDrawValues {
1071                        atlas_page_index: page_index,
1072                        font,
1073                        brush,
1074                        height,
1075                    } = current_draw_values.unwrap();
1076                    let texture = CommandTexture::Font {
1077                        font,
1078                        page_index,
1079                        height,
1080                    };
1081                    ctx.commit(clip_bounds, brush, texture, material, None);
1082                    current_draw_values = Some(draw_values);
1083                }
1084
1085                let bounds = element.bounds;
1086                let dilation = match layer {
1087                    DrawValueLayer::Main => 0.0,
1088                    DrawValueLayer::Shadow => {
1089                        formatted_text.shadow_dilation_at(element.source_char_index)
1090                    }
1091                };
1092                let offset = match layer {
1093                    DrawValueLayer::Main => Vector2::default(),
1094                    DrawValueLayer::Shadow => {
1095                        formatted_text.shadow_offset_at(element.source_char_index)
1096                    }
1097                };
1098
1099                let final_bounds = Rect::new(
1100                    position.x + bounds.x() + offset.x,
1101                    position.y + bounds.y() + offset.y,
1102                    bounds.w(),
1103                    bounds.h(),
1104                )
1105                .inflate(dilation, dilation);
1106
1107                ctx.push_rect_filled(&final_bounds, Some(&element.tex_coords));
1108            }
1109
1110            if let Some(GlyphDrawValues {
1111                atlas_page_index: page_index,
1112                font,
1113                brush,
1114                height,
1115            }) = current_draw_values
1116            {
1117                let texture = CommandTexture::Font {
1118                    font,
1119                    page_index,
1120                    height,
1121                };
1122                // Commit the rest.
1123                ctx.commit(clip_bounds, brush, texture, material, None);
1124            }
1125        }
1126
1127        // Draw shadow, if any.
1128        if *formatted_text.shadow || !formatted_text.runs.is_empty() {
1129            draw(
1130                formatted_text,
1131                DrawValueLayer::Shadow,
1132                self,
1133                clip_bounds,
1134                position,
1135                material,
1136            );
1137        }
1138
1139        draw(
1140            formatted_text,
1141            DrawValueLayer::Main,
1142            self,
1143            clip_bounds,
1144            position,
1145            material,
1146        );
1147    }
1148}