mesh2d_repeated_texture/
mesh2d_repeated_texture.rs

1//! By default Bevy loads images to textures that clamps the image to the edges
2//! This example shows how to configure it to repeat the image instead.
3
4use bevy::{
5    audio::AudioPlugin,
6    image::{ImageAddressMode, ImageLoaderSettings, ImageSampler, ImageSamplerDescriptor},
7    math::Affine2,
8    prelude::*,
9};
10
11/// How much to move some rectangles away from the center
12const RECTANGLE_OFFSET: f32 = 250.0;
13/// Length of the sides of the rectangle
14const RECTANGLE_SIDE: f32 = 200.;
15/// How much to move the label away from the rectangle
16const LABEL_OFFSET: f32 = (RECTANGLE_SIDE / 2.) + 25.;
17
18fn main() {
19    App::new()
20        .add_plugins(DefaultPlugins.build().disable::<AudioPlugin>())
21        .add_systems(Startup, setup)
22        .run();
23}
24
25fn setup(
26    mut commands: Commands,
27    asset_server: Res<AssetServer>,
28    mut meshes: ResMut<Assets<Mesh>>,
29    mut materials: ResMut<Assets<ColorMaterial>>,
30) {
31    // #11111: We use a duplicated image so that it can be load with and without
32    // settings
33    let image_with_default_sampler =
34        asset_server.load("textures/fantasy_ui_borders/panel-border-010.png");
35    let image_with_repeated_sampler = asset_server.load_with_settings(
36        "textures/fantasy_ui_borders/panel-border-010-repeated.png",
37        |s: &mut _| {
38            *s = ImageLoaderSettings {
39                sampler: ImageSampler::Descriptor(ImageSamplerDescriptor {
40                    // rewriting mode to repeat image,
41                    address_mode_u: ImageAddressMode::Repeat,
42                    address_mode_v: ImageAddressMode::Repeat,
43                    ..default()
44                }),
45                ..default()
46            }
47        },
48    );
49
50    // central rectangle with not repeated texture
51    commands.spawn((
52        Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
53        MeshMaterial2d(materials.add(ColorMaterial {
54            texture: Some(image_with_default_sampler.clone()),
55            ..default()
56        })),
57        Transform::from_translation(Vec3::ZERO),
58        children![(
59            Text2d::new("Control"),
60            Transform::from_xyz(0., LABEL_OFFSET, 0.),
61        )],
62    ));
63
64    // left rectangle with repeated texture
65    commands.spawn((
66        Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
67        MeshMaterial2d(materials.add(ColorMaterial {
68            texture: Some(image_with_repeated_sampler),
69            // uv_transform used here for proportions only, but it is full Affine2
70            // that's why you can use rotation and shift also
71            uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
72            ..default()
73        })),
74        Transform::from_xyz(-RECTANGLE_OFFSET, 0.0, 0.0),
75        children![(
76            Text2d::new("Repeat On"),
77            Transform::from_xyz(0., LABEL_OFFSET, 0.),
78        )],
79    ));
80
81    // right rectangle with scaled texture, but with default sampler.
82    commands.spawn((
83        Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
84        MeshMaterial2d(materials.add(ColorMaterial {
85            // there is no sampler set, that's why
86            // by default you see only one small image in a row/column
87            // and other space is filled by image edge
88            texture: Some(image_with_default_sampler),
89
90            // uv_transform used here for proportions only, but it is full Affine2
91            // that's why you can use rotation and shift also
92            uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
93            ..default()
94        })),
95        Transform::from_xyz(RECTANGLE_OFFSET, 0.0, 0.0),
96        children![(
97            Text2d::new("Repeat Off"),
98            Transform::from_xyz(0., LABEL_OFFSET, 0.),
99        )],
100    ));
101
102    // camera
103    commands.spawn((
104        Camera2d,
105        Transform::default().looking_at(Vec3::ZERO, Vec3::Y),
106    ));
107}