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