vg/renderer/
params.rs

1use crate::{
2    paint::{
3        GlyphTexture,
4        GradientColors,
5    },
6    Color,
7    ImageFlags,
8    ImageStore,
9    Paint,
10    PaintFlavor,
11    PixelFormat,
12    Scissor,
13    Transform2D,
14};
15
16use super::ShaderType;
17
18/// Represents params
19#[derive(Copy, Clone, Debug, Default)]
20pub struct Params {
21    /// Scissor matxix
22    pub scissor_mat: [f32; 12],
23    /// Paint matxix
24    pub paint_mat: [f32; 12],
25    /// Inner column
26    pub inner_col: [f32; 4],
27    /// Outer column
28    pub outer_col: [f32; 4],
29    /// Scissor extent
30    pub scissor_ext: [f32; 2],
31    /// Scissor scale
32    pub scissor_scale: [f32; 2],
33    /// Extent
34    pub extent: [f32; 2],
35    /// Radius
36    pub radius: f32,
37    /// Feather
38    pub feather: f32,
39    /// Stroke multipier
40    pub stroke_mult: f32,
41    /// Stroke threshold
42    pub stroke_thr: f32,
43    /// Text type
44    pub tex_type: f32,
45    /// Shader type
46    pub shader_type: f32,
47    /// Glyph texture type
48    pub glyph_texture_type: f32, // 0 -> no glyph rendering, 1 -> alpha mask, 2 -> color texture
49    /// Image blud filter direction
50    pub image_blur_filter_direction: [f32; 2],
51    /// Image blur filter sigma
52    pub image_blur_filter_sigma: f32,
53    /// Image blur filter coefficient
54    pub image_blur_filter_coeff: [f32; 3],
55}
56
57impl Params {
58    /// Creates an Params struct
59    pub fn new<T>(
60        images: &ImageStore<T>,
61        paint: &Paint,
62        scissor: &Scissor,
63        stroke_width: f32,
64        fringe_width: f32,
65        stroke_thr: f32,
66    ) -> Self {
67        let mut params = Params::default();
68
69        // Scissor
70        let (scissor_ext, scissor_scale) = if let Some(ext) = scissor.extent {
71            if ext[0] < -0.5 || ext[1] < -0.5 {
72                ([1.0, 1.0], [1.0, 1.0])
73            } else {
74                params.scissor_mat = scissor.transform.inversed().to_mat3x4();
75
76                let scissor_scale = [
77                    (scissor.transform[0] * scissor.transform[0] + scissor.transform[2] * scissor.transform[2]).sqrt()
78                        / fringe_width,
79                    (scissor.transform[1] * scissor.transform[1] + scissor.transform[3] * scissor.transform[3]).sqrt()
80                        / fringe_width,
81                ];
82
83                (ext, scissor_scale)
84            }
85        } else {
86            ([1.0, 1.0], [1.0, 1.0])
87        };
88
89        params.scissor_ext = scissor_ext;
90        params.scissor_scale = scissor_scale;
91
92        params.stroke_mult = (stroke_width * 0.5 + fringe_width * 0.5) / fringe_width;
93        params.stroke_thr = stroke_thr;
94
95        params.glyph_texture_type = match paint.glyph_texture() {
96            GlyphTexture::None => 0.0,
97            GlyphTexture::AlphaMask(_) => 1.0,
98            GlyphTexture::ColorTexture(_) => 2.0,
99        };
100
101        let inv_transform;
102
103        match paint.flavor {
104            PaintFlavor::Color(color) => {
105                let color = color.premultiplied().to_array();
106                params.inner_col = color;
107                params.outer_col = color;
108                params.shader_type = ShaderType::FillGradient.to_f32();
109                inv_transform = paint.transform.inversed();
110            }
111            PaintFlavor::Image {
112                id,
113                cx,
114                cy,
115                width,
116                height,
117                angle,
118                alpha,
119            } => {
120                let image_info = match images.info(id) {
121                    Some(info) => info,
122                    None => return params,
123                };
124
125                params.extent[0] = width;
126                params.extent[1] = height;
127
128                let color = Color::rgbaf(1.0, 1.0, 1.0, alpha);
129
130                params.inner_col = color.premultiplied().to_array();
131                params.outer_col = color.premultiplied().to_array();
132
133                let mut transform = Transform2D::identity();
134                transform.rotate(angle);
135                transform.translate(cx, cy);
136                transform.multiply(&paint.transform);
137
138                if image_info.flags().contains(ImageFlags::FLIP_Y) {
139                    let mut m1 = Transform2D::identity();
140                    m1.translate(0.0, height * 0.5);
141                    m1.multiply(&transform);
142
143                    let mut m2 = Transform2D::identity();
144                    m2.scale(1.0, -1.0);
145                    m2.multiply(&m1);
146
147                    let mut m1 = Transform2D::identity();
148                    m1.translate(0.0, -height * 0.5);
149                    m1.multiply(&m2);
150
151                    inv_transform = m1.inversed();
152                } else {
153                    inv_transform = transform.inversed();
154                }
155
156                params.shader_type = ShaderType::FillImage.to_f32();
157
158                params.tex_type = match image_info.format() {
159                    PixelFormat::Rgba8 => {
160                        if image_info.flags().contains(ImageFlags::PREMULTIPLIED) {
161                            0.0
162                        } else {
163                            1.0
164                        }
165                    }
166                    PixelFormat::Gray8 => 2.0,
167                    _ => 0.0,
168                };
169            }
170            PaintFlavor::LinearGradient {
171                start_x,
172                start_y,
173                end_x,
174                end_y,
175                colors,
176            } => {
177                let large = 1e5f32;
178                let mut dx = end_x - start_x;
179                let mut dy = end_y - start_y;
180                let d = (dx * dx + dy * dy).sqrt();
181
182                if d > 0.0001 {
183                    dx /= d;
184                    dy /= d;
185                } else {
186                    dx = 0.0;
187                    dy = 1.0;
188                }
189
190                let mut transform = Transform2D([dy, -dx, dx, dy, start_x - dx * large, start_y - dy * large]);
191
192                transform.multiply(&paint.transform);
193
194                inv_transform = transform.inversed();
195
196                params.extent[0] = large;
197                params.extent[1] = large + d * 0.5;
198                params.feather = 1.0f32.max(d);
199
200                match colors {
201                    GradientColors::TwoStop { start_color, end_color } => {
202                        params.inner_col = start_color.premultiplied().to_array();
203                        params.outer_col = end_color.premultiplied().to_array();
204                        params.shader_type = ShaderType::FillGradient.to_f32();
205                    }
206                    GradientColors::MultiStop { .. } => {
207                        params.shader_type = ShaderType::FillImageGradient.to_f32();
208                    }
209                }
210            }
211            PaintFlavor::BoxGradient {
212                x,
213                y,
214                width,
215                height,
216                radius,
217                feather,
218                colors,
219            } => {
220                let mut transform = Transform2D::new_translation(x + width * 0.5, y + height * 0.5);
221                transform.multiply(&paint.transform);
222                inv_transform = transform.inversed();
223
224                params.extent[0] = width * 0.5;
225                params.extent[1] = height * 0.5;
226                params.radius = radius;
227                params.feather = feather;
228                match colors {
229                    GradientColors::TwoStop { start_color, end_color } => {
230                        params.inner_col = start_color.premultiplied().to_array();
231                        params.outer_col = end_color.premultiplied().to_array();
232                        params.shader_type = ShaderType::FillGradient.to_f32();
233                    }
234                    GradientColors::MultiStop { .. } => {
235                        params.shader_type = ShaderType::FillImageGradient.to_f32();
236                    }
237                }
238            }
239            PaintFlavor::RadialGradient {
240                cx,
241                cy,
242                in_radius,
243                out_radius,
244                colors,
245            } => {
246                let r = (in_radius + out_radius) * 0.5;
247                let f = out_radius - in_radius;
248
249                let mut transform = Transform2D::new_translation(cx, cy);
250                transform.multiply(&paint.transform);
251                inv_transform = transform.inversed();
252
253                params.extent[0] = r;
254                params.extent[1] = r;
255                params.radius = r;
256                params.feather = 1.0f32.max(f);
257                match colors {
258                    GradientColors::TwoStop { start_color, end_color } => {
259                        params.inner_col = start_color.premultiplied().to_array();
260                        params.outer_col = end_color.premultiplied().to_array();
261                        params.shader_type = ShaderType::FillGradient.to_f32();
262                    }
263                    GradientColors::MultiStop { .. } => {
264                        params.shader_type = ShaderType::FillImageGradient.to_f32();
265                    }
266                }
267            }
268        }
269
270        params.paint_mat = inv_transform.to_mat3x4();
271
272        params
273    }
274}