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