mirror of
https://github.com/bevyengine/bevy.git
synced 2026-07-04 01:33:14 -04:00
61127f6d01
# Objective
- In 0.18, we had 10 different functions that load assets (I'm not even
counting `load_folder`).
- In 0.19, we've even added `load_erased` - but it unfortunately doesn't
support all the features that the other variants support.
- We apparently needed `load_acquire_with_settings_override` which 1)
loads the asset, 2) uses the settings provided, 3) allows reading
unapproved asset paths, and 4) drops a guard once the load completes.
- That's fine if that's necessary. But we needed to create an explicit
variant for that.
- We need fewer load paths!
## Solution
- Create a builder.
- Store all these options dynamically instead of statically handling
each case.
- Have the caller choose a particular "kind" of load when they are
ready: `load`, `load_erased`, `load_untyped`, or `load_untyped_async`.
- I intentionally didn't provide a `load_async` or `load_erased_async`,
since those can be replicated using `load`/`load_erased` +
`AssetServer::wait_for_asset_id` to get the exact same effect.
I am also intentionally leaving `NestedLoader` untouched in this PR, but
a followup will duplicate this API for `NestedLoader`, which should make
it easier to understand.
Unlike the `NestedLoader` API, we aren't doing any type-state craziness,
so the docs are much more clear: users don't need to understand how
type-state stuff works, they just call the handful of methods on the
type. The "cost" here is we now need to be careful about including the
cross product of loads between static asset type, runtime asset type, or
dynamic asset type, crossed with deferred or async. In theory, if we
added more kinds on either side, we would need to expand this cross
product a lot. In practice though, it seems unlikely there will be any
more variants there. (maybe there could be a blocking variant? I don't
think this is a popular opinion though).
A big con here is some somewhat common calls are now more verbose.
Specifically, `asset_server.load_with_settings()` has become
`asset_server.load_builder().with_settings().load()`. I am not really
concerned about this though, since it really isn't that painful.
## Testing
- Tests all pass!
---
## Showcase
Now instead of:
```rust
asset_server.load_acquire_with_settings_override("some_path", |settings: &mut GltfLoaderSettings| { ... }, my_lock_guard);
```
You can instead do:
```rust
asset_server.load_builder()
.with_guard(my_lock_guard)
.with_settings(|settings: &mut GltfLoaderSettings| { ... })
.override_unapproved()
.load("some_path");
```
We also now cover more variants! For example, you can now load an asset
untyped with a guard, or with override_unapproved, etc.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
108 lines
3.8 KiB
Rust
108 lines
3.8 KiB
Rust
//! By default Bevy loads images to textures that clamps the image to the edges
|
|
//! This example shows how to configure it to repeat the image instead.
|
|
|
|
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_builder()
|
|
.with_settings(|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()
|
|
}
|
|
})
|
|
.load("textures/fantasy_ui_borders/panel-border-010-repeated.png");
|
|
|
|
// 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),
|
|
));
|
|
}
|