1use interpolation::lerp;
3
4use crate::{
5 math::{multiply, orient, translate, Matrix2d, Scalar, Vec2d},
6 radians::Radians,
7 types::{Line, Polygon, Polygons, Radius, Rectangle, Resolution, SourceRectangle},
8 ImageSize, BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE,
9};
10
11#[inline(always)]
13pub fn tx(m: Matrix2d, x: Scalar, y: Scalar) -> f32 {
14 (m[0][0] * x + m[0][1] * y + m[0][2]) as f32
15}
16
17#[inline(always)]
19pub fn ty(m: Matrix2d, x: Scalar, y: Scalar) -> f32 {
20 (m[1][0] * x + m[1][1] * y + m[1][2]) as f32
21}
22
23#[inline(always)]
25pub fn with_lerp_polygons_tri_list<F>(
26 m: Matrix2d,
27 polygons: Polygons<'_>,
28 tween_factor: Scalar,
29 f: F,
30) where
31 F: FnMut(&[[f32; 2]]),
32{
33 let poly_len = polygons.len() as Scalar;
34 let tw = tween_factor % 1.0;
36 let tw = if tw < 0.0 { tw + 1.0 } else { tw };
38 let tw = tw * poly_len;
40 let frame = tw as usize;
42 let next_frame = (frame + 1) % polygons.len();
44 let p0 = polygons[frame];
45 let p1 = polygons[next_frame];
46 let tw = tw - frame as Scalar;
48 let n = polygons[0].len();
49 stream_polygon_tri_list(m, (0..n).map(|j| lerp(&p0[j], &p1[j], &tw)), f);
50}
51
52#[inline(always)]
54pub fn with_ellipse_tri_list<F>(resolution: Resolution, m: Matrix2d, rect: Rectangle, f: F)
55where
56 F: FnMut(&[[f32; 2]]),
57{
58 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
59 let (cw, ch) = (0.5 * w, 0.5 * h);
60 let (cx, cy) = (x + cw, y + ch);
61 let n = resolution;
62 stream_polygon_tri_list(
63 m,
64 (0..n).map(|i| {
65 let angle = i as Scalar / n as Scalar * <Scalar as Radians>::_360();
66 [cx + angle.cos() * cw, cy + angle.sin() * ch]
67 }),
68 f,
69 );
70}
71
72#[inline(always)]
74pub fn with_round_border_line_tri_list<F>(
75 resolution_cap: Resolution,
76 m: Matrix2d,
77 line: Line,
78 round_border_radius: Radius,
79 f: F,
80) where
81 F: FnMut(&[[f32; 2]]),
82{
83 let radius = round_border_radius;
84 let (x1, y1, x2, y2) = (line[0], line[1], line[2], line[3]);
85 let (dx, dy) = (x2 - x1, y2 - y1);
86 let w = (dx * dx + dy * dy).sqrt();
87 let m = multiply(m, translate([x1, y1]));
88 let m = multiply(m, orient(dx, dy));
89 let n = resolution_cap * 2;
90 stream_polygon_tri_list(
91 m,
92 (0..n).map(|j| {
93 match j {
98 j if j >= resolution_cap => {
99 let angle = (j - resolution_cap) as Scalar / (resolution_cap - 1) as Scalar
104 * <Scalar as Radians>::_180()
105 + <Scalar as Radians>::_180();
106 let angle = angle + <Scalar as Radians>::_90();
108 [w + angle.cos() * radius, angle.sin() * radius]
109 }
110 j => {
111 let angle =
114 j as Scalar / (resolution_cap - 1) as Scalar * <Scalar as Radians>::_180();
115 let angle = angle + <Scalar as Radians>::_90();
117 [angle.cos() * radius, angle.sin() * radius]
118 }
119 }
120 }),
121 f,
122 );
123}
124
125#[allow(clippy::identity_op)] #[inline(always)]
128pub fn with_round_rectangle_tri_list<F>(
129 resolution_corner: Resolution,
130 m: Matrix2d,
131 rect: Rectangle,
132 round_radius: Radius,
133 f: F,
134) where
135 F: FnMut(&[[f32; 2]]),
136{
137 use vecmath::traits::FromPrimitive;
138
139 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
140 let radius = round_radius;
141 let n = resolution_corner * 4;
142 stream_polygon_tri_list(
143 m,
144 (0..n).map(|j| {
145 match j {
150 j if j >= resolution_corner * 3 => {
151 let angle: Scalar = (j - resolution_corner * 3) as Scalar
156 / (resolution_corner - 1) as Scalar
157 * <Scalar as Radians>::_90()
158 + <Scalar as FromPrimitive>::from_f64(3.0) * <Scalar as Radians>::_90();
159 let (cx, cy) = (x + w - radius, y + radius);
161 [cx + angle.cos() * radius, cy + angle.sin() * radius]
162 }
163 j if j >= resolution_corner * 2 => {
164 let angle = (j - resolution_corner * 2) as Scalar
169 / (resolution_corner - 1) as Scalar
170 * <Scalar as Radians>::_90()
171 + <Scalar as Radians>::_180();
172 let (cx, cy) = (x + radius, y + radius);
174 [cx + angle.cos() * radius, cy + angle.sin() * radius]
175 }
176 j if j >= resolution_corner * 1 => {
177 let angle = (j - resolution_corner) as Scalar
182 / (resolution_corner - 1) as Scalar
183 * <Scalar as Radians>::_90()
184 + <Scalar as Radians>::_90();
185 let (cx, cy) = (x + radius, y + h - radius);
187 [cx + angle.cos() * radius, cy + angle.sin() * radius]
188 }
189 j => {
190 let angle = j as Scalar / (resolution_corner - 1) as Scalar
193 * <Scalar as Radians>::_90();
194 let (cx, cy) = (x + w - radius, y + h - radius);
196 [cx + angle.cos() * radius, cy + angle.sin() * radius]
197 }
198 }
199 }),
200 f,
201 );
202}
203
204pub fn stream_polygon_tri_list<E, F>(m: Matrix2d, mut polygon: E, mut f: F)
226where
227 E: Iterator<Item = Vec2d>,
228 F: FnMut(&[[f32; 2]]),
229{
230 let mut vertices: [[f32; 2]; BUFFER_SIZE] = [[0.0; 2]; BUFFER_SIZE];
231 let fp = match polygon.next() {
233 None => return,
234 Some(val) => val,
235 };
236 let f1 = [tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1])];
237 let gp = match polygon.next() {
238 None => return,
239 Some(val) => val,
240 };
241 let mut g1 = [tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1])];
242 let mut i = 0;
243 let vertices_per_triangle = 3;
244 let align_vertices = vertices_per_triangle;
245 'read_vertices: loop {
246 let ind_out = i * align_vertices;
247 vertices[ind_out] = f1;
248
249 let p = match polygon.next() {
251 None => break 'read_vertices,
252 Some(val) => val,
253 };
254 let pos = [tx(m, p[0], p[1]), ty(m, p[0], p[1])];
255
256 vertices[ind_out + 1] = g1;
257 vertices[ind_out + 2] = pos;
258 g1 = pos;
259
260 i += 1;
261 if (i + 1) * align_vertices > BUFFER_SIZE {
263 f(&vertices[0..i * align_vertices]);
265 i = 0;
266 }
267 }
268
269 if i > 0 {
270 f(&vertices[0..i * align_vertices]);
271 }
272}
273
274#[inline(always)]
276pub fn with_ellipse_border_tri_list<F>(
277 resolution: Resolution,
278 m: Matrix2d,
279 rect: Rectangle,
280 border_radius: Radius,
281 f: F,
282) where
283 F: FnMut(&[[f32; 2]]),
284{
285 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
286 let (cw, ch) = (0.5 * w, 0.5 * h);
287 let (cw1, ch1) = (cw + border_radius, ch + border_radius);
288 let (cw2, ch2) = (cw - border_radius, ch - border_radius);
289 let (cx, cy) = (x + cw, y + ch);
290 let n = resolution;
291 let mut i = 0;
292 stream_quad_tri_list(
293 m,
294 || {
295 if i > n {
296 return None;
297 }
298
299 let angle = i as Scalar / n as Scalar * <Scalar as Radians>::_360();
300 let cos = angle.cos();
301 let sin = angle.sin();
302 i += 1;
303 Some((
304 [cx + cos * cw1, cy + sin * ch1],
305 [cx + cos * cw2, cy + sin * ch2],
306 ))
307 },
308 f,
309 );
310}
311
312#[inline(always)]
314pub fn with_arc_tri_list<F>(
315 start_radians: Scalar,
316 end_radians: Scalar,
317 resolution: Resolution,
318 m: Matrix2d,
319 rect: Rectangle,
320 border_radius: Radius,
321 f: F,
322) where
323 F: FnMut(&[[f32; 2]]),
324{
325 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
326 let (cw, ch) = (0.5 * w, 0.5 * h);
327 let (cw1, ch1) = (cw + border_radius, ch + border_radius);
328 let (cw2, ch2) = (cw - border_radius, ch - border_radius);
329 let (cx, cy) = (x + cw, y + ch);
330 let mut i = 0;
331
332 let twopi = <Scalar as Radians>::_360();
333 let max_seg_size = twopi / resolution as Scalar;
334
335 let (start_radians, delta) = if (end_radians - start_radians).abs() >= twopi {
336 (0.0, twopi)
338 } else {
339 (
341 start_radians,
342 (((end_radians - start_radians) % twopi) + twopi) % twopi,
343 )
344 };
345
346 let n_quads = (delta / max_seg_size).ceil() as u64;
349
350 let seg_size = delta / n_quads as Scalar;
352 stream_quad_tri_list(
353 m,
354 || {
355 if i > n_quads {
356 return None;
357 }
358
359 let angle = start_radians + (i as Scalar * seg_size);
360
361 let cos = angle.cos();
362 let sin = angle.sin();
363 i += 1;
364 Some((
365 [cx + cos * cw1, cy + sin * ch1],
366 [cx + cos * cw2, cy + sin * ch2],
367 ))
368 },
369 f,
370 );
371}
372
373#[allow(clippy::identity_op)] #[inline(always)]
376pub fn with_round_rectangle_border_tri_list<F>(
377 resolution_corner: Resolution,
378 m: Matrix2d,
379 rect: Rectangle,
380 round_radius: Radius,
381 border_radius: Radius,
382 f: F,
383) where
384 F: FnMut(&[[f32; 2]]),
385{
386 use vecmath::traits::FromPrimitive;
387
388 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
389 let radius = round_radius;
390 let radius1 = round_radius + border_radius;
391 let radius2 = round_radius - border_radius;
392 let n = resolution_corner * 4;
393 let mut i = 0;
394 stream_quad_tri_list(
395 m,
396 || {
397 if i > n {
398 return None;
399 }
400
401 let j = i;
402 i += 1;
403 match j {
408 j if j == n => {
409 let (cx, cy) = (x + w - radius, y + h - radius);
410 Some(([cx + radius1, cy], [cx + radius2, cy]))
411 }
412 j if j >= resolution_corner * 3 => {
413 let angle: Scalar = (j - resolution_corner * 3) as Scalar
418 / (resolution_corner - 1) as Scalar
419 * <Scalar as Radians>::_90()
420 + <Scalar as FromPrimitive>::from_f64(3.0) * <Scalar as Radians>::_90();
421 let (cx, cy) = (x + w - radius, y + radius);
423 let cos = angle.cos();
424 let sin = angle.sin();
425 Some((
426 [cx + cos * radius1, cy + sin * radius1],
427 [cx + cos * radius2, cy + sin * radius2],
428 ))
429 }
430 j if j >= resolution_corner * 2 => {
431 let angle = (j - resolution_corner * 2) as Scalar
436 / (resolution_corner - 1) as Scalar
437 * <Scalar as Radians>::_90()
438 + <Scalar as Radians>::_180();
439 let (cx, cy) = (x + radius, y + radius);
441 let cos = angle.cos();
442 let sin = angle.sin();
443 Some((
444 [cx + cos * radius1, cy + sin * radius1],
445 [cx + cos * radius2, cy + sin * radius2],
446 ))
447 }
448 j if j >= resolution_corner * 1 => {
449 let angle = (j - resolution_corner) as Scalar
454 / (resolution_corner - 1) as Scalar
455 * <Scalar as Radians>::_90()
456 + <Scalar as Radians>::_90();
457 let (cx, cy) = (x + radius, y + h - radius);
459 let cos = angle.cos();
460 let sin = angle.sin();
461 Some((
462 [cx + cos * radius1, cy + sin * radius1],
463 [cx + cos * radius2, cy + sin * radius2],
464 ))
465 }
466 j => {
467 let angle = j as Scalar / (resolution_corner - 1) as Scalar
470 * <Scalar as Radians>::_90();
471 let (cx, cy) = (x + w - radius, y + h - radius);
473 let cos = angle.cos();
474 let sin = angle.sin();
475 Some((
476 [cx + cos * radius1, cy + sin * radius1],
477 [cx + cos * radius2, cy + sin * radius2],
478 ))
479 }
480 }
481 },
482 f,
483 );
484}
485
486#[allow(clippy::identity_op)] pub fn stream_quad_tri_list<E, F>(m: Matrix2d, mut quad_edge: E, mut f: F)
516where
517 E: FnMut() -> Option<(Vec2d, Vec2d)>,
518 F: FnMut(&[[f32; 2]]),
519{
520 let mut vertices: [[f32; 2]; BUFFER_SIZE] = [[0.0; 2]; BUFFER_SIZE];
521 let (fp1, fp2) = match quad_edge() {
523 None => return,
524 Some((val1, val2)) => (val1, val2),
525 };
526 let mut f1 = [tx(m, fp1[0], fp1[1]), ty(m, fp1[0], fp1[1])];
528 let mut f2 = [tx(m, fp2[0], fp2[1]), ty(m, fp2[0], fp2[1])];
529 let mut i = 0;
531 let triangles_per_quad = 2;
532 let vertices_per_triangle = 3;
533 let align_vertices = triangles_per_quad * vertices_per_triangle;
534 loop {
535 let (gp1, gp2) = match quad_edge() {
537 None => break,
538 Some((val1, val2)) => (val1, val2),
539 };
540 let g1 = [tx(m, gp1[0], gp1[1]), ty(m, gp1[0], gp1[1])];
542 let g2 = [tx(m, gp2[0], gp2[1]), ty(m, gp2[0], gp2[1])];
543 let ind_out = i * align_vertices;
544
545 vertices[ind_out + 0] = f1;
547 vertices[ind_out + 1] = f2;
548 vertices[ind_out + 2] = g1;
549
550 vertices[ind_out + 3] = f2;
552 vertices[ind_out + 4] = g1;
553 vertices[ind_out + 5] = g2;
554
555 i += 1;
557
558 f1 = g1;
560 f2 = g2;
561
562 if (i + 1) * align_vertices > BUFFER_SIZE {
564 f(&vertices[0..i * align_vertices]);
566 i = 0;
567 }
568 }
569
570 if i > 0 {
571 f(&vertices[0..i * align_vertices]);
572 }
573}
574
575pub fn with_polygon_tri_list<F>(m: Matrix2d, polygon: Polygon<'_>, f: F)
580where
581 F: FnMut(&[[f32; 2]]),
582{
583 stream_polygon_tri_list(m, (0..polygon.len()).map(|i| polygon[i]), f);
584}
585
586#[inline(always)]
588pub fn rect_tri_list_xy(m: Matrix2d, rect: Rectangle) -> [[f32; 2]; 6] {
589 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
590 let (x2, y2) = (x + w, y + h);
591 [
592 [tx(m, x, y), ty(m, x, y)],
593 [tx(m, x2, y), ty(m, x2, y)],
594 [tx(m, x, y2), ty(m, x, y2)],
595 [tx(m, x2, y), ty(m, x2, y)],
596 [tx(m, x2, y2), ty(m, x2, y2)],
597 [tx(m, x, y2), ty(m, x, y2)],
598 ]
599}
600
601#[inline(always)]
603pub fn rect_border_tri_list_xy(
604 m: Matrix2d,
605 rect: Rectangle,
606 border_radius: Radius,
607) -> [[f32; 2]; 24] {
608 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
609 let (w1, h1) = (w + border_radius, h + border_radius);
610 let (w2, h2) = (w - border_radius, h - border_radius);
611 let (x11, y11) = (x - border_radius, y - border_radius);
612 let (x21, y21) = (x + border_radius, y + border_radius);
613 let (x12, y12) = (x + w1, y + h1);
614 let (x22, y22) = (x + w2, y + h2);
615 [
616 [tx(m, x11, y11), ty(m, x11, y11)],
617 [tx(m, x12, y11), ty(m, x12, y11)],
618 [tx(m, x21, y21), ty(m, x21, y21)],
619 [tx(m, x21, y21), ty(m, x21, y21)],
620 [tx(m, x12, y11), ty(m, x12, y11)],
621 [tx(m, x22, y21), ty(m, x22, y21)],
622 [tx(m, x22, y21), ty(m, x22, y21)],
623 [tx(m, x12, y11), ty(m, x12, y11)],
624 [tx(m, x12, y12), ty(m, x12, y12)],
625 [tx(m, x22, y21), ty(m, x22, y21)],
626 [tx(m, x12, y12), ty(m, x12, y12)],
627 [tx(m, x22, y22), ty(m, x22, y22)],
628 [tx(m, x12, y12), ty(m, x12, y12)],
629 [tx(m, x22, y22), ty(m, x22, y22)],
630 [tx(m, x11, y12), ty(m, x11, y12)],
631 [tx(m, x22, y22), ty(m, x22, y22)],
632 [tx(m, x11, y12), ty(m, x11, y12)],
633 [tx(m, x21, y22), ty(m, x21, y22)],
634 [tx(m, x11, y12), ty(m, x11, y12)],
635 [tx(m, x21, y21), ty(m, x21, y21)],
636 [tx(m, x21, y22), ty(m, x21, y22)],
637 [tx(m, x11, y12), ty(m, x11, y12)],
638 [tx(m, x11, y11), ty(m, x11, y11)],
639 [tx(m, x21, y21), ty(m, x21, y21)],
640 ]
641}
642
643#[inline(always)]
645pub fn rect_tri_list_uv<I: ImageSize>(image: &I, source_rect: SourceRectangle) -> [[f32; 2]; 6] {
646 let (w, h) = image.get_size();
647 let (src_x, src_y, src_w, src_h) = (
648 source_rect[0],
649 source_rect[1],
650 source_rect[2],
651 source_rect[3],
652 );
653
654 let x1 = src_x as f32 / w as f32;
655 let y1 = src_y as f32 / h as f32;
656 let x2 = (src_w + src_x) as f32 / w as f32;
657 let y2 = (src_h + src_y) as f32 / h as f32;
658 [[x1, y1], [x2, y1], [x1, y2], [x2, y1], [x2, y2], [x1, y2]]
659}