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#[derive(Copy, Clone, Debug, Default)]
20pub struct Params {
21 pub scissor_mat: [f32; 12],
23 pub paint_mat: [f32; 12],
25 pub inner_col: [f32; 4],
27 pub outer_col: [f32; 4],
29 pub scissor_ext: [f32; 2],
31 pub scissor_scale: [f32; 2],
33 pub extent: [f32; 2],
35 pub radius: f32,
37 pub feather: f32,
39 pub stroke_mult: f32,
41 pub stroke_thr: f32,
43 pub tex_type: f32,
45 pub shader_type: f32,
47 pub glyph_texture_type: f32, pub image_blur_filter_direction: [f32; 2],
51 pub image_blur_filter_sigma: f32,
53 pub image_blur_filter_coeff: [f32; 3],
55}
56
57impl Params {
58 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 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}