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