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