1 //! Methods for converting shapes into triangles.
2 
3 use ImageSize;
4 use BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
5 use interpolation::lerp;
6 use types::{Line, SourceRectangle, Polygon, Polygons, Radius, Rectangle, Resolution};
7 use math::{multiply, orient, translate, Matrix2d, Scalar, Vec2d};
8 use radians::Radians;
9 
10 /// Transformed x coordinate as f32.
11 #[inline(always)]
tx(m: Matrix2d, x: Scalar, y: Scalar) -> f3212 pub fn tx(m: Matrix2d, x: Scalar, y: Scalar) -> f32 {
13     (m[0][0] * x + m[0][1] * y + m[0][2]) as f32
14 }
15 
16 /// Transformed y coordinate as f32.
17 #[inline(always)]
ty(m: Matrix2d, x: Scalar, y: Scalar) -> f3218 pub fn ty(m: Matrix2d, x: Scalar, y: Scalar) -> f32 {
19     (m[1][0] * x + m[1][1] * y + m[1][2]) as f32
20 }
21 
22 /// Streams tweened polygons using linear interpolation.
23 #[inline(always)]
with_lerp_polygons_tri_list<F>(m: Matrix2d, polygons: Polygons, tween_factor: Scalar, f: F) where F: FnMut(&[[f32; 2]])24 pub fn with_lerp_polygons_tri_list<F>(m: Matrix2d, polygons: Polygons, tween_factor: Scalar, f: F)
25     where F: FnMut(&[[f32; 2]])
26 {
27 
28     let poly_len = polygons.len() as Scalar;
29     // Map to interval between 0 and 1.
30     let tw = tween_factor % 1.0;
31     // Map negative values to positive.
32     let tw = if tw < 0.0 { tw + 1.0 } else { tw };
33     // Map to frame.
34     let tw = tw * poly_len;
35     // Get the current frame.
36     let frame = tw as usize;
37     // Get the next frame.
38     let next_frame = (frame + 1) % polygons.len();
39     let p0 = polygons[frame];
40     let p1 = polygons[next_frame];
41     // Get factor between frames.
42     let tw = tw - frame as Scalar;
43     let n = polygons[0].len();
44     stream_polygon_tri_list(m, (0..n).map(|j| lerp(&p0[j], &p1[j], &tw)), f);
45 }
46 
47 /// Streams an ellipse specified by a resolution.
48 #[inline(always)]
with_ellipse_tri_list<F>(resolution: Resolution, m: Matrix2d, rect: Rectangle, f: F) where F: FnMut(&[[f32; 2]])49 pub fn with_ellipse_tri_list<F>(resolution: Resolution, m: Matrix2d, rect: Rectangle, f: F)
50     where F: FnMut(&[[f32; 2]])
51 {
52     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
53     let (cw, ch) = (0.5 * w, 0.5 * h);
54     let (cx, cy) = (x + cw, y + ch);
55     let n = resolution;
56     stream_polygon_tri_list(m,
57         (0..n).map(|i| {
58             let angle = i as Scalar / n as Scalar * <Scalar as Radians>::_360();
59             [cx + angle.cos() * cw, cy + angle.sin() * ch]
60         }), f);
61 }
62 
63 /// Streams a round border line.
64 #[inline(always)]
with_round_border_line_tri_list<F>(resolution_cap: Resolution, m: Matrix2d, line: Line, round_border_radius: Radius, f: F) where F: FnMut(&[[f32; 2]])65 pub fn with_round_border_line_tri_list<F>(resolution_cap: Resolution,
66                                           m: Matrix2d,
67                                           line: Line,
68                                           round_border_radius: Radius,
69                                           f: F)
70     where F: FnMut(&[[f32; 2]])
71 {
72 
73     let radius = round_border_radius;
74     let (x1, y1, x2, y2) = (line[0], line[1], line[2], line[3]);
75     let (dx, dy) = (x2 - x1, y2 - y1);
76     let w = (dx * dx + dy * dy).sqrt();
77     let m = multiply(m, translate([x1, y1]));
78     let m = multiply(m, orient(dx, dy));
79     let n = resolution_cap * 2;
80     stream_polygon_tri_list(m,
81         (0..n).map(|j| {
82             // Detect the half circle from index.
83             // There is one half circle at each end of the line.
84             // Together they form a full circle if
85             // the length of the line is zero.
86             match j {
87                 j if j >= resolution_cap => {
88                     // Compute the angle to match start and end
89                     // point of half circle.
90                     // This requires an angle offset since
91                     // the other end of line is the first half circle.
92                     let angle = (j - resolution_cap) as Scalar / (resolution_cap - 1) as Scalar *
93                                 <Scalar as Radians>::_180() +
94                                 <Scalar as Radians>::_180();
95                     // Rotate 90 degrees since the line is horizontal.
96                     let angle = angle + <Scalar as Radians>::_90();
97                     [w + angle.cos() * radius, angle.sin() * radius]
98                 }
99                 j => {
100                     // Compute the angle to match start and end
101                     // point of half circle.
102                     let angle = j as Scalar / (resolution_cap - 1) as Scalar *
103                                 <Scalar as Radians>::_180();
104                     // Rotate 90 degrees since the line is horizontal.
105                     let angle = angle + <Scalar as Radians>::_90();
106                     [angle.cos() * radius, angle.sin() * radius]
107                 }
108             }
109         }), f);
110 }
111 
112 /// Streams a round rectangle.
113 #[inline(always)]
with_round_rectangle_tri_list<F>(resolution_corner: Resolution, m: Matrix2d, rect: Rectangle, round_radius: Radius, f: F) where F: FnMut(&[[f32; 2]])114 pub fn with_round_rectangle_tri_list<F>(resolution_corner: Resolution,
115                                         m: Matrix2d,
116                                         rect: Rectangle,
117                                         round_radius: Radius,
118                                         f: F)
119     where F: FnMut(&[[f32; 2]])
120 {
121     use vecmath::traits::FromPrimitive;
122 
123     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
124     let radius = round_radius;
125     let n = resolution_corner * 4;
126     stream_polygon_tri_list(m,
127         (0..n).map(|j| {
128             // Detect quarter circle from index.
129             // There is one quarter circle at each corner.
130             // Together they form a full circle if
131             // each side of rectangle is 2 times the radius.
132             match j {
133                 j if j >= resolution_corner * 3 => {
134                     // Compute the angle to match start and end
135                     // point of quarter circle.
136                     // This requires an angle offset since this
137                     // is the last quarter.
138                     let angle: Scalar =
139                         (j - resolution_corner * 3) as Scalar / (resolution_corner - 1) as Scalar *
140                         <Scalar as Radians>::_90() +
141                         <Scalar as FromPrimitive>::from_f64(3.0) * <Scalar as Radians>::_90();
142                     // Set center of the circle to the last corner.
143                     let (cx, cy) = (x + w - radius, y + radius);
144                     [cx + angle.cos() * radius, cy + angle.sin() * radius]
145                 }
146                 j if j >= resolution_corner * 2 => {
147                     // Compute the angle to match start and end
148                     // point of quarter circle.
149                     // This requires an angle offset since
150                     // this is the second last quarter.
151                     let angle =
152                         (j - resolution_corner * 2) as Scalar / (resolution_corner - 1) as Scalar *
153                         <Scalar as Radians>::_90() + <Scalar as Radians>::_180();
154                     // Set center of the circle to the second last corner.
155                     let (cx, cy) = (x + radius, y + radius);
156                     [cx + angle.cos() * radius, cy + angle.sin() * radius]
157                 }
158                 j if j >= resolution_corner * 1 => {
159                     // Compute the angle to match start and end
160                     // point of quarter circle.
161                     // This requires an angle offset since
162                     // this is the second quarter.
163                     let angle = (j - resolution_corner) as Scalar / (resolution_corner - 1) as Scalar *
164                                 <Scalar as Radians>::_90() +
165                                 <Scalar as Radians>::_90();
166                     // Set center of the circle to the second corner.
167                     let (cx, cy) = (x + radius, y + h - radius);
168                     [cx + angle.cos() * radius, cy + angle.sin() * radius]
169                 }
170                 j => {
171                     // Compute the angle to match start and end
172                     // point of quarter circle.
173                     let angle = j as Scalar / (resolution_corner - 1) as Scalar *
174                                 <Scalar as Radians>::_90();
175                     // Set center of the circle to the first corner.
176                     let (cx, cy) = (x + w - radius, y + h - radius);
177                     [cx + angle.cos() * radius, cy + angle.sin() * radius]
178                 }
179             }
180         }), f);
181 }
182 
183 /// Streams a polygon into tri list.
184 /// Uses buffers that fit inside L1 cache.
185 ///
186 /// `polygon` is a function that provides the vertices that comprise the polygon. Each
187 /// call to E will return a new vertex until there are none left.
188 ///
189 /// `f` is a function that consumes the tri list constructed by the output of `polygon`,
190 /// one chunk (buffer) at a time.
191 ///
192 /// Each chunk (buffer) is a fixed size array) of the format:
193 ///
194 /// ```
195 /// //     [[x0, y0], [x1, y1], [x2, y2], [x3, y3], ... [y4, y5], ...]
196 /// //      ^--------------------------^  ^--------------------^
197 /// //        3 Points of triangle   3 points of second triangle,
198 /// ```
199 ///
200 /// Together all the chunks comprise the full tri list. Each time the buffer size is
201 /// reached, that chunk is fed to `f`, then this function proceeds using a new buffer
202 /// until a call to `polygon` returns `None`, indicating there are no points left in
203 /// the polygon. (in which case the last partially filled buffer is sent to `f`)
stream_polygon_tri_list<E, F>(m: Matrix2d, mut polygon: E, mut f: F) where E: Iterator<Item = Vec2d>, F: FnMut(&[[f32; 2]])204 pub fn stream_polygon_tri_list<E, F>(m: Matrix2d, mut polygon: E, mut f: F)
205     where E: Iterator<Item = Vec2d>,
206           F: FnMut(&[[f32; 2]])
207 {
208 
209     let mut vertices: [[f32; 2]; BUFFER_SIZE] = [[0.0; 2]; BUFFER_SIZE];
210     // Get the first point which will be used a lot.
211     let fp = match polygon.next() {
212         None => return,
213         Some(val) => val,
214     };
215     let f1 = [tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1])];
216     let gp = match polygon.next() {
217         None => return,
218         Some(val) => val,
219     };
220     let mut g1 = [tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1])];
221     let mut i = 0;
222     let vertices_per_triangle = 3;
223     let align_vertices = vertices_per_triangle;
224     'read_vertices: loop {
225         let ind_out = i * align_vertices;
226         vertices[ind_out] = f1;
227 
228         // Copy vertex.
229         let p = match polygon.next() {
230             None => break 'read_vertices,
231             Some(val) => val,
232         };
233         let pos = [tx(m, p[0], p[1]), ty(m, p[0], p[1])];
234 
235         vertices[ind_out + 1] = g1;
236         vertices[ind_out + 2] = pos;
237         g1 = pos;
238 
239         i += 1;
240         // Buffer is full.
241         if i * align_vertices + 1 >= vertices.len() {
242             // Send chunk and start over.
243             f(&vertices[0..i * align_vertices]);
244             i = 0;
245         }
246     }
247 
248     if i > 0 {
249         f(&vertices[0..i * align_vertices]);
250     }
251 }
252 
253 /// Streams an ellipse border specified by a resolution.
254 #[inline(always)]
with_ellipse_border_tri_list<F>(resolution: Resolution, m: Matrix2d, rect: Rectangle, border_radius: Radius, f: F) where F: FnMut(&[[f32; 2]])255 pub fn with_ellipse_border_tri_list<F>(resolution: Resolution,
256                                        m: Matrix2d,
257                                        rect: Rectangle,
258                                        border_radius: Radius,
259                                        f: F)
260     where F: FnMut(&[[f32; 2]])
261 {
262 
263     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
264     let (cw, ch) = (0.5 * w, 0.5 * h);
265     let (cw1, ch1) = (cw + border_radius, ch + border_radius);
266     let (cw2, ch2) = (cw - border_radius, ch - border_radius);
267     let (cx, cy) = (x + cw, y + ch);
268     let n = resolution;
269     let mut i = 0;
270     stream_quad_tri_list(m,
271                          || {
272         if i > n {
273             return None;
274         }
275 
276         let angle = i as Scalar / n as Scalar * <Scalar as Radians>::_360();
277         let cos = angle.cos();
278         let sin = angle.sin();
279         i += 1;
280         Some(([cx + cos * cw1, cy + sin * ch1], [cx + cos * cw2, cy + sin * ch2]))
281     },
282                          f);
283 }
284 
285 /// Streams an arc between the two radian boundaries.
286 #[inline(always)]
with_arc_tri_list<F>(start_radians: Scalar, end_radians: Scalar, resolution: Resolution, m: Matrix2d, rect: Rectangle, border_radius: Radius, f: F) where F: FnMut(&[[f32; 2]])287 pub fn with_arc_tri_list<F>(start_radians: Scalar,
288                             end_radians: Scalar,
289                             resolution: Resolution,
290                             m: Matrix2d,
291                             rect: Rectangle,
292                             border_radius: Radius,
293                             f: F)
294     where F: FnMut(&[[f32; 2]])
295 {
296 
297     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
298     let (cw, ch) = (0.5 * w, 0.5 * h);
299     let (cw1, ch1) = (cw + border_radius, ch + border_radius);
300     let (cw2, ch2) = (cw - border_radius, ch - border_radius);
301     let (cx, cy) = (x + cw, y + ch);
302     let mut i = 0;
303 
304     let twopi = <Scalar as Radians>::_360();
305     let max_seg_size = twopi / resolution as Scalar;
306 
307     // Take true modulus by 2pi.
308     let delta = (((end_radians - start_radians) % twopi) + twopi) % twopi;
309 
310     // Taking ceiling here implies that the resolution parameter provides a
311     // lower bound on the drawn resolution.
312     let n_quads = (delta / max_seg_size).ceil() as u64;
313 
314     // n_quads * seg_size exactly spans the included angle.
315     let seg_size = delta / n_quads as Scalar;
316     stream_quad_tri_list(m,
317                          || {
318         if i > n_quads {
319             return None;
320         }
321 
322         let angle = start_radians + (i as Scalar * seg_size);
323 
324         let cos = angle.cos();
325         let sin = angle.sin();
326         i += 1;
327         Some(([cx + cos * cw1, cy + sin * ch1], [cx + cos * cw2, cy + sin * ch2]))
328     },
329                          f);
330 }
331 
332 /// Streams a round rectangle border.
333 #[inline(always)]
with_round_rectangle_border_tri_list<F>(resolution_corner: Resolution, m: Matrix2d, rect: Rectangle, round_radius: Radius, border_radius: Radius, f: F) where F: FnMut(&[[f32; 2]])334 pub fn with_round_rectangle_border_tri_list<F>(resolution_corner: Resolution,
335                                                m: Matrix2d,
336                                                rect: Rectangle,
337                                                round_radius: Radius,
338                                                border_radius: Radius,
339                                                f: F)
340     where F: FnMut(&[[f32; 2]])
341 {
342     use vecmath::traits::FromPrimitive;
343 
344     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
345     let radius = round_radius;
346     let radius1 = round_radius + border_radius;
347     let radius2 = round_radius - border_radius;
348     let n = resolution_corner * 4;
349     let mut i = 0;
350     stream_quad_tri_list(m,
351                          || {
352         if i > n {
353             return None;
354         }
355 
356         let j = i;
357         i += 1;
358         // Detect quarter circle from index.
359         // There is one quarter circle at each corner.
360         // Together they form a full circle if
361         // each side of rectangle is 2 times the radius.
362         match j {
363             j if j == n => {
364                 let (cx, cy) = (x + w - radius, y + h - radius);
365                 Some(([cx + radius1, cy], [cx + radius2, cy]))
366             }
367             j if j >= resolution_corner * 3 => {
368                 // Compute the angle to match start and end
369                 // point of quarter circle.
370                 // This requires an angle offset since this
371                 // is the last quarter.
372                 let angle: Scalar =
373                     (j - resolution_corner * 3) as Scalar / (resolution_corner - 1) as Scalar *
374                     <Scalar as Radians>::_90() +
375                     <Scalar as FromPrimitive>::from_f64(3.0) * <Scalar as Radians>::_90();
376                 // Set center of the circle to the last corner.
377                 let (cx, cy) = (x + w - radius, y + radius);
378                 let cos = angle.cos();
379                 let sin = angle.sin();
380                 Some(([cx + cos * radius1, cy + sin * radius1],
381                       [cx + cos * radius2, cy + sin * radius2]))
382             }
383             j if j >= resolution_corner * 2 => {
384                 // Compute the angle to match start and end
385                 // point of quarter circle.
386                 // This requires an angle offset since
387                 // this is the second last quarter.
388                 let angle =
389                     (j - resolution_corner * 2) as Scalar / (resolution_corner - 1) as Scalar *
390                     <Scalar as Radians>::_90() + <Scalar as Radians>::_180();
391                 // Set center of the circle to the second last corner.
392                 let (cx, cy) = (x + radius, y + radius);
393                 let cos = angle.cos();
394                 let sin = angle.sin();
395                 Some(([cx + cos * radius1, cy + sin * radius1],
396                       [cx + cos * radius2, cy + sin * radius2]))
397             }
398             j if j >= resolution_corner * 1 => {
399                 // Compute the angle to match start and end
400                 // point of quarter circle.
401                 // This requires an angle offset since
402                 // this is the second quarter.
403                 let angle = (j - resolution_corner) as Scalar / (resolution_corner - 1) as Scalar *
404                             <Scalar as Radians>::_90() +
405                             <Scalar as Radians>::_90();
406                 // Set center of the circle to the second corner.
407                 let (cx, cy) = (x + radius, y + h - radius);
408                 let cos = angle.cos();
409                 let sin = angle.sin();
410                 Some(([cx + cos * radius1, cy + sin * radius1],
411                       [cx + cos * radius2, cy + sin * radius2]))
412             }
413             j => {
414                 // Compute the angle to match start and end
415                 // point of quarter circle.
416                 let angle = j as Scalar / (resolution_corner - 1) as Scalar *
417                             <Scalar as Radians>::_90();
418                 // Set center of the circle to the first corner.
419                 let (cx, cy) = (x + w - radius, y + h - radius);
420                 let cos = angle.cos();
421                 let sin = angle.sin();
422                 Some(([cx + cos * radius1, cy + sin * radius1],
423                       [cx + cos * radius2, cy + sin * radius2]))
424             }
425         }
426     },
427                          f);
428 }
429 
430 /// Streams a quad into tri list.
431 ///
432 /// Uses buffers that fit inside L1 cache.
433 /// The 'quad_edge' stream returns two points
434 /// defining the next edge.
435 ///
436 /// `quad_edge` is a function that returns two vertices, which together comprise
437 /// one edge of a quad
438 ///
439 ///
440 /// `f` is a function that consumes the tri list constructed by the output of
441 /// `quad_edge`, one chunk (buffer) at a time
442 ///
443 /// The tri list is series of buffers (fixed size array) of the format:
444 ///
445 /// ```
446 /// //     [[x0, y0], [x1, y1], [x2, y2], [x3, y3], ... [y4, y5], ...]
447 /// //      ^--------------------------^  ^--------------------^
448 /// //        3 Points of triangle   3 points of second triangle,
449 /// //      ^------------------------------------^          __
450 /// //         Two triangles together form a single quad |\\ 2|
451 /// //                                                   |1\\ |
452 /// //                                                   |__\\|
453 /// ```
454 /// Together all the chunks comprise the full tri list. Each time the buffer size is
455 /// reached, that chunk is fed to `f`, then this function proceeds using a new buffer
456 /// until a call to `quad_edge` returns `None`, indicating there are no more edges left.
457 /// (in which case the last partially filled buffer is sent to `f`)
stream_quad_tri_list<E, F>(m: Matrix2d, mut quad_edge: E, mut f: F) where E: FnMut() -> Option<(Vec2d, Vec2d)>, F: FnMut(&[[f32; 2]])458 pub fn stream_quad_tri_list<E, F>(m: Matrix2d, mut quad_edge: E, mut f: F)
459     where E: FnMut() -> Option<(Vec2d, Vec2d)>,
460           F: FnMut(&[[f32; 2]])
461 {
462     let mut vertices: [[f32; 2]; BUFFER_SIZE] = [[0.0; 2]; BUFFER_SIZE];
463     // Get the two points .
464     let (fp1, fp2) = match quad_edge() {
465         None => return,
466         Some((val1, val2)) => (val1, val2),
467     };
468     // Transform the points using the matrix.
469     let mut f1 = [tx(m, fp1[0], fp1[1]), ty(m, fp1[0], fp1[1])];
470     let mut f2 = [tx(m, fp2[0], fp2[1]), ty(m, fp2[0], fp2[1])];
471     // Counts the quads.
472     let mut i = 0;
473     let triangles_per_quad = 2;
474     let vertices_per_triangle = 3;
475     let align_vertices = triangles_per_quad * vertices_per_triangle;
476     loop {
477         // Read two more points.
478         let (gp1, gp2) = match quad_edge() {
479             None => break,
480             Some((val1, val2)) => (val1, val2),
481         };
482         // Transform the points using the matrix.
483         let g1 = [tx(m, gp1[0], gp1[1]), ty(m, gp1[0], gp1[1])];
484         let g2 = [tx(m, gp2[0], gp2[1]), ty(m, gp2[0], gp2[1])];
485         let ind_out = i * align_vertices;
486 
487         // First triangle.
488         vertices[ind_out + 0] = f1;
489         vertices[ind_out + 1] = f2;
490         vertices[ind_out + 2] = g1;
491 
492         // Second triangle.
493         vertices[ind_out + 3] = f2;
494         vertices[ind_out + 4] = g1;
495         vertices[ind_out + 5] = g2;
496 
497         // Next quad.
498         i += 1;
499 
500         // Set next current edge.
501         f1 = g1;
502         f2 = g2;
503 
504         // Buffer is full.
505         if i * align_vertices >= vertices.len() {
506             // Send chunk and start over.
507             f(&vertices[0..i * align_vertices]);
508             i = 0;
509         }
510     }
511 
512     if i > 0 {
513         f(&vertices[0..i * align_vertices]);
514     }
515 }
516 
517 /// Splits polygon into convex segments.
518 /// Create a buffer that fits into L1 cache with 1KB overhead.
519 ///
520 /// See stream_polygon_tri_list docs for detailed explanation.
with_polygon_tri_list<F>(m: Matrix2d, polygon: Polygon, f: F) where F: FnMut(&[[f32; 2]])521 pub fn with_polygon_tri_list<F>(m: Matrix2d, polygon: Polygon, f: F)
522     where F: FnMut(&[[f32; 2]])
523 {
524     stream_polygon_tri_list(m, (0..polygon.len()).map(|i| polygon[i]), f);
525 }
526 
527 /// Creates triangle list vertices from rectangle.
528 #[inline(always)]
rect_tri_list_xy(m: Matrix2d, rect: Rectangle) -> [[f32; 2]; 6]529 pub fn rect_tri_list_xy(m: Matrix2d, rect: Rectangle) -> [[f32; 2]; 6] {
530     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
531     let (x2, y2) = (x + w, y + h);
532     [[tx(m, x, y), ty(m, x, y)],
533      [tx(m, x2, y), ty(m, x2, y)],
534      [tx(m, x, y2), ty(m, x, y2)],
535      [tx(m, x2, y), ty(m, x2, y)],
536      [tx(m, x2, y2), ty(m, x2, y2)],
537      [tx(m, x, y2), ty(m, x, y2)]]
538 }
539 
540 /// Creates triangle list vertices from rectangle.
541 #[inline(always)]
rect_border_tri_list_xy(m: Matrix2d, rect: Rectangle, border_radius: Radius) -> [[f32; 2]; 24]542 pub fn rect_border_tri_list_xy(m: Matrix2d,
543                                rect: Rectangle,
544                                border_radius: Radius)
545                                -> [[f32; 2]; 24] {
546     let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
547     let (w1, h1) = (w + border_radius, h + border_radius);
548     let (w2, h2) = (w - border_radius, h - border_radius);
549     let (x11, y11) = (x - border_radius, y - border_radius);
550     let (x21, y21) = (x + border_radius, y + border_radius);
551     let (x12, y12) = (x + w1, y + h1);
552     let (x22, y22) = (x + w2, y + h2);
553     [[tx(m, x11, y11), ty(m, x11, y11)],
554      [tx(m, x12, y11), ty(m, x12, y11)],
555      [tx(m, x21, y21), ty(m, x21, y21)],
556 
557      [tx(m, x21, y21), ty(m, x21, y21)],
558      [tx(m, x12, y11), ty(m, x12, y11)],
559      [tx(m, x22, y21), ty(m, x22, y21)],
560 
561      [tx(m, x22, y21), ty(m, x22, y21)],
562      [tx(m, x12, y11), ty(m, x12, y11)],
563      [tx(m, x12, y12), ty(m, x12, y12)],
564 
565      [tx(m, x22, y21), ty(m, x22, y21)],
566      [tx(m, x12, y12), ty(m, x12, y12)],
567      [tx(m, x22, y22), ty(m, x22, y22)],
568 
569      [tx(m, x12, y12), ty(m, x12, y12)],
570      [tx(m, x22, y22), ty(m, x22, y22)],
571      [tx(m, x11, y12), ty(m, x11, y12)],
572 
573      [tx(m, x22, y22), ty(m, x22, y22)],
574      [tx(m, x11, y12), ty(m, x11, y12)],
575      [tx(m, x21, y22), ty(m, x21, y22)],
576 
577      [tx(m, x11, y12), ty(m, x11, y12)],
578      [tx(m, x21, y21), ty(m, x21, y21)],
579      [tx(m, x21, y22), ty(m, x21, y22)],
580 
581      [tx(m, x11, y12), ty(m, x11, y12)],
582      [tx(m, x11, y11), ty(m, x11, y11)],
583      [tx(m, x21, y21), ty(m, x21, y21)]]
584 }
585 
586 /// Creates triangle list texture coords from image.
587 #[inline(always)]
rect_tri_list_uv<I: ImageSize>(image: &I, source_rect: SourceRectangle) -> [[f32; 2]; 6]588 pub fn rect_tri_list_uv<I: ImageSize>(image: &I, source_rect: SourceRectangle) -> [[f32; 2]; 6] {
589     let (w, h) = image.get_size();
590     let (src_x, src_y, src_w, src_h) =
591         (source_rect[0], source_rect[1], source_rect[2], source_rect[3]);
592 
593     let x1 = src_x as f32 / w as f32;
594     let y1 = src_y as f32 / h as f32;
595     let x2 = (src_w + src_x) as f32 / w as f32;
596     let y2 = (src_h + src_y) as f32 / h as f32;
597     [[x1, y1], [x2, y1], [x1, y2], [x2, y1], [x2, y2], [x1, y2]]
598 }
599