bevy_sprite/texture_slice/
mod.rs

1mod border_rect;
2mod slicer;
3
4use bevy_math::{Rect, Vec2};
5pub use border_rect::BorderRect;
6pub use slicer::{SliceScaleMode, TextureSlicer};
7
8/// Single texture slice, representing a texture rect to draw in a given area
9#[derive(Debug, Clone, PartialEq)]
10pub struct TextureSlice {
11    /// texture area to draw
12    pub texture_rect: Rect,
13    /// slice draw size
14    pub draw_size: Vec2,
15    /// offset of the slice
16    pub offset: Vec2,
17}
18
19impl TextureSlice {
20    /// Transforms the given slice in a collection of tiled subdivisions.
21    ///
22    /// # Arguments
23    ///
24    /// * `stretch_value` - The slice will repeat when the ratio between the *drawing dimensions* of texture and the
25    ///   *original texture size* (rect) are above `stretch_value`.
26    /// * `tile_x` - should the slice be tiled horizontally
27    /// * `tile_y` - should the slice be tiled vertically
28    #[must_use]
29    pub fn tiled(self, stretch_value: f32, (tile_x, tile_y): (bool, bool)) -> Vec<Self> {
30        if !tile_x && !tile_y {
31            return vec![self];
32        }
33        let stretch_value = stretch_value.max(0.001);
34        let rect_size = self.texture_rect.size();
35        // Each tile expected size
36        let expected_size = Vec2::new(
37            if tile_x {
38                // No slice should be less than 1 pixel wide
39                (rect_size.x * stretch_value).max(1.0)
40            } else {
41                self.draw_size.x
42            },
43            if tile_y {
44                // No slice should be less than 1 pixel high
45                (rect_size.y * stretch_value).max(1.0)
46            } else {
47                self.draw_size.y
48            },
49        )
50        .min(self.draw_size);
51        let mut slices = Vec::new();
52        let base_offset = Vec2::new(
53            -self.draw_size.x / 2.0,
54            self.draw_size.y / 2.0, // Start from top
55        );
56        let mut offset = base_offset;
57
58        let mut remaining_columns = self.draw_size.y;
59        while remaining_columns > 0.0 {
60            let size_y = expected_size.y.min(remaining_columns);
61            offset.x = base_offset.x;
62            offset.y -= size_y / 2.0;
63            let mut remaining_rows = self.draw_size.x;
64            while remaining_rows > 0.0 {
65                let size_x = expected_size.x.min(remaining_rows);
66                offset.x += size_x / 2.0;
67                let draw_size = Vec2::new(size_x, size_y);
68                let delta = draw_size / expected_size;
69                slices.push(Self {
70                    texture_rect: Rect {
71                        min: self.texture_rect.min,
72                        max: self.texture_rect.min + self.texture_rect.size() * delta,
73                    },
74                    draw_size,
75                    offset: self.offset + offset,
76                });
77                offset.x += size_x / 2.0;
78                remaining_rows -= size_x;
79            }
80            offset.y -= size_y / 2.0;
81            remaining_columns -= size_y;
82        }
83        if slices.len() > 1_000 {
84            tracing::warn!("One of your tiled textures has generated {} slices. You might want to use higher stretch values to avoid a great performance cost", slices.len());
85        }
86        slices
87    }
88}