2D Rendering / Mesh2d Repeated Texture

Back to examples View in GitHub
use bevy::{
    audio::AudioPlugin,
    image::{ImageAddressMode, ImageLoaderSettings, ImageSampler, ImageSamplerDescriptor},
    math::Affine2,
    prelude::*,
};

/// How much to move some rectangles away from the center
const RECTANGLE_OFFSET: f32 = 250.0;
/// Length of the sides of the rectangle
const RECTANGLE_SIDE: f32 = 200.;
/// How much to move the label away from the rectangle
const LABEL_OFFSET: f32 = (RECTANGLE_SIDE / 2.) + 25.;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.build().disable::<AudioPlugin>())
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    // #11111: We use a duplicated image so that it can be load with and without
    // settings
    let image_with_default_sampler =
        asset_server.load("textures/fantasy_ui_borders/panel-border-010.png");
    let image_with_repeated_sampler = asset_server.load_with_settings(
        "textures/fantasy_ui_borders/panel-border-010-repeated.png",
        |s: &mut _| {
            *s = ImageLoaderSettings {
                sampler: ImageSampler::Descriptor(ImageSamplerDescriptor {
                    // rewriting mode to repeat image,
                    address_mode_u: ImageAddressMode::Repeat,
                    address_mode_v: ImageAddressMode::Repeat,
                    ..default()
                }),
                ..default()
            }
        },
    );

    // central rectangle with not repeated texture
    commands.spawn((
        Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
        MeshMaterial2d(materials.add(ColorMaterial {
            texture: Some(image_with_default_sampler.clone()),
            ..default()
        })),
        Transform::from_translation(Vec3::ZERO),
        children![(
            Text2d::new("Control"),
            Transform::from_xyz(0., LABEL_OFFSET, 0.),
        )],
    ));

    // left rectangle with repeated texture
    commands.spawn((
        Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
        MeshMaterial2d(materials.add(ColorMaterial {
            texture: Some(image_with_repeated_sampler),
            // uv_transform used here for proportions only, but it is full Affine2
            // that's why you can use rotation and shift also
            uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
            ..default()
        })),
        Transform::from_xyz(-RECTANGLE_OFFSET, 0.0, 0.0),
        children![(
            Text2d::new("Repeat On"),
            Transform::from_xyz(0., LABEL_OFFSET, 0.),
        )],
    ));

    // right rectangle with scaled texture, but with default sampler.
    commands.spawn((
        Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
        MeshMaterial2d(materials.add(ColorMaterial {
            // there is no sampler set, that's why
            // by default you see only one small image in a row/column
            // and other space is filled by image edge
            texture: Some(image_with_default_sampler),

            // uv_transform used here for proportions only, but it is full Affine2
            // that's why you can use rotation and shift also
            uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
            ..default()
        })),
        Transform::from_xyz(RECTANGLE_OFFSET, 0.0, 0.0),
        children![(
            Text2d::new("Repeat Off"),
            Transform::from_xyz(0., LABEL_OFFSET, 0.),
        )],
    ));

    // camera
    commands.spawn((
        Camera2d,
        Transform::default().looking_at(Vec3::ZERO, Vec3::Y),
    ));
}