pathfinder_renderer/
options.rs

1// pathfinder/renderer/src/options.rs
2//
3// Copyright © 2019 The Pathfinder Project Developers.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Options that control how rendering is to be performed.
12
13use crate::gpu_data::RenderCommand;
14use pathfinder_geometry::rect::RectF;
15use pathfinder_geometry::transform2d::Transform2F;
16use pathfinder_geometry::transform3d::Perspective;
17use pathfinder_geometry::vector::{Vector2F, Vector4F};
18use pathfinder_content::clip::PolygonClipper3D;
19
20pub trait RenderCommandListener: Send + Sync {
21    fn send(&self, command: RenderCommand);
22}
23
24impl<F> RenderCommandListener for F
25where
26    F: Fn(RenderCommand) + Send + Sync,
27{
28    #[inline]
29    fn send(&self, command: RenderCommand) {
30        (*self)(command)
31    }
32}
33
34/// Options that influence scene building.
35#[derive(Clone, Default)]
36pub struct BuildOptions {
37    pub transform: RenderTransform,
38    pub dilation: Vector2F,
39    pub subpixel_aa_enabled: bool,
40}
41
42impl BuildOptions {
43    pub(crate) fn prepare(self, bounds: RectF) -> PreparedBuildOptions {
44        PreparedBuildOptions {
45            transform: self.transform.prepare(bounds),
46            dilation: self.dilation,
47            subpixel_aa_enabled: self.subpixel_aa_enabled,
48        }
49    }
50}
51
52#[derive(Clone)]
53pub enum RenderTransform {
54    Transform2D(Transform2F),
55    Perspective(Perspective),
56}
57
58impl Default for RenderTransform {
59    #[inline]
60    fn default() -> RenderTransform {
61        RenderTransform::Transform2D(Transform2F::default())
62    }
63}
64
65impl RenderTransform {
66    fn prepare(&self, bounds: RectF) -> PreparedRenderTransform {
67        let perspective = match self {
68            RenderTransform::Transform2D(ref transform) => {
69                if transform.is_identity() {
70                    return PreparedRenderTransform::None;
71                }
72                return PreparedRenderTransform::Transform2D(*transform);
73            }
74            RenderTransform::Perspective(ref perspective) => *perspective,
75        };
76
77        let mut points = vec![
78            bounds.origin().to_4d(),
79            bounds.upper_right().to_4d(),
80            bounds.lower_right().to_4d(),
81            bounds.lower_left().to_4d(),
82        ];
83        debug!("-----");
84        debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
85        for point in &mut points {
86            *point = perspective.transform * *point;
87        }
88        debug!("... PERSPECTIVE quad={:?}", points);
89
90        // Compute depth.
91        let quad = [
92            points[0].to_3d().to_4d(),
93            points[1].to_3d().to_4d(),
94            points[2].to_3d().to_4d(),
95            points[3].to_3d().to_4d(),
96        ];
97        debug!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
98
99        points = PolygonClipper3D::new(points).clip();
100        debug!("... CLIPPED quad={:?}", points);
101        for point in &mut points {
102            *point = point.to_3d().to_4d()
103        }
104
105        let inverse_transform = perspective.transform.inverse();
106        let clip_polygon = points.into_iter()
107                                 .map(|point| (inverse_transform * point).to_2d())
108                                 .collect();
109        return PreparedRenderTransform::Perspective {
110            perspective,
111            clip_polygon,
112            quad,
113        };
114    }
115}
116
117pub(crate) struct PreparedBuildOptions {
118    pub(crate) transform: PreparedRenderTransform,
119    pub(crate) dilation: Vector2F,
120    pub(crate) subpixel_aa_enabled: bool,
121}
122
123impl PreparedBuildOptions {
124    #[inline]
125    pub(crate) fn bounding_quad(&self) -> BoundingQuad {
126        match self.transform {
127            PreparedRenderTransform::Perspective { quad, .. } => quad,
128            _ => [Vector4F::default(); 4],
129        }
130    }
131}
132
133pub(crate) type BoundingQuad = [Vector4F; 4];
134
135pub(crate) enum PreparedRenderTransform {
136    None,
137    Transform2D(Transform2F),
138    Perspective {
139        perspective: Perspective,
140        clip_polygon: Vec<Vector2F>,
141        quad: [Vector4F; 4],
142    },
143}
144
145impl PreparedRenderTransform {
146    #[inline]
147    pub(crate) fn is_2d(&self) -> bool {
148        match *self {
149            PreparedRenderTransform::Transform2D(_) => true,
150            _ => false,
151        }
152    }
153}