pub struct AssetServer { /* private fields */ }
Expand description
Loads and tracks the state of Asset
values from a configured AssetReader
.
This can be used to kick off new asset loads and retrieve their current load states.
The general process to load an asset is:
- Initialize a new
Asset
type with theAssetServer
viaAssetApp::init_asset
, which will internally callAssetServer::register_asset
and set up related ECSAssets
storage and systems. - Register one or more
AssetLoader
s for that asset withAssetApp::init_asset_loader
- Add the asset to your asset folder (defaults to
assets
). - Call
AssetServer::load
with a path to your asset.
AssetServer
can be cloned. It is backed by an Arc
so clones will share state. Clones can be freely used in parallel.
Implementations§
Source§impl AssetServer
impl AssetServer
Sourcepub fn new(
sources: AssetSources,
mode: AssetServerMode,
watching_for_changes: bool,
unapproved_path_mode: UnapprovedPathMode,
) -> AssetServer
pub fn new( sources: AssetSources, mode: AssetServerMode, watching_for_changes: bool, unapproved_path_mode: UnapprovedPathMode, ) -> AssetServer
Create a new instance of AssetServer
. If watch_for_changes
is true, the AssetReader
storage will watch for changes to
asset sources and hot-reload them.
Sourcepub fn new_with_meta_check(
sources: AssetSources,
mode: AssetServerMode,
meta_check: AssetMetaCheck,
watching_for_changes: bool,
unapproved_path_mode: UnapprovedPathMode,
) -> AssetServer
pub fn new_with_meta_check( sources: AssetSources, mode: AssetServerMode, meta_check: AssetMetaCheck, watching_for_changes: bool, unapproved_path_mode: UnapprovedPathMode, ) -> AssetServer
Create a new instance of AssetServer
. If watch_for_changes
is true, the AssetReader
storage will watch for changes to
asset sources and hot-reload them.
Sourcepub fn get_source<'a>(
&self,
source: impl Into<AssetSourceId<'a>>,
) -> Result<&AssetSource, MissingAssetSourceError>
pub fn get_source<'a>( &self, source: impl Into<AssetSourceId<'a>>, ) -> Result<&AssetSource, MissingAssetSourceError>
Retrieves the AssetSource
for the given source
.
Sourcepub fn watching_for_changes(&self) -> bool
pub fn watching_for_changes(&self) -> bool
Returns true if the AssetServer
watches for changes.
Sourcepub fn register_loader<L>(&self, loader: L)where
L: AssetLoader,
pub fn register_loader<L>(&self, loader: L)where
L: AssetLoader,
Registers a new AssetLoader
. AssetLoader
s must be registered before they can be used.
Sourcepub fn register_asset<A>(&self, assets: &Assets<A>)where
A: Asset,
pub fn register_asset<A>(&self, assets: &Assets<A>)where
A: Asset,
Sourcepub async fn get_asset_loader_with_extension(
&self,
extension: &str,
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
pub async fn get_asset_loader_with_extension( &self, extension: &str, ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
Returns the registered AssetLoader
associated with the given extension, if it exists.
Sourcepub async fn get_asset_loader_with_type_name(
&self,
type_name: &str,
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeNameError>
pub async fn get_asset_loader_with_type_name( &self, type_name: &str, ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeNameError>
Returns the registered AssetLoader
associated with the given core::any::type_name
, if it exists.
Sourcepub async fn get_path_asset_loader<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
pub async fn get_path_asset_loader<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
Retrieves the default AssetLoader
for the given path, if one can be found.
Sourcepub async fn get_asset_loader_with_asset_type_id(
&self,
type_id: TypeId,
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>
pub async fn get_asset_loader_with_asset_type_id( &self, type_id: TypeId, ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>
Retrieves the default AssetLoader
for the given Asset
TypeId
, if one can be found.
Sourcepub async fn get_asset_loader_with_asset_type<A>(
&self,
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>where
A: Asset,
pub async fn get_asset_loader_with_asset_type<A>(
&self,
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>where
A: Asset,
Retrieves the default AssetLoader
for the given Asset
type, if one can be found.
Sourcepub fn load<'a, A>(&self, path: impl Into<AssetPath<'a>>) -> Handle<A>where
A: Asset,
pub fn load<'a, A>(&self, path: impl Into<AssetPath<'a>>) -> Handle<A>where
A: Asset,
Begins loading an Asset
of type A
stored at path
. This will not block on the asset load. Instead,
it returns a “strong” Handle
. When the Asset
is loaded (and enters LoadState::Loaded
), it will be added to the
associated Assets
resource.
Note that if the asset at this path is already loaded, this function will return the existing handle, and will not waste work spawning a new load task.
In case the file path contains a hashtag (#
), the path
must be specified using Path
or AssetPath
because otherwise the hashtag would be interpreted as separator between
the file path and the label. For example:
// `#path` is a label.
asset_server.load("some/file#path");
// `#path` is part of the file name.
asset_server.load(Path::new("some/file#path"));
Furthermore, if you need to load a file with a hashtag in its name and a label, you can
manually construct an AssetPath
.
asset_server.load(AssetPath::from_path(Path::new("some/file#path")).with_label("subasset"));
You can check the asset’s load state by reading AssetEvent
events, calling AssetServer::load_state
, or checking
the Assets
storage to see if the Asset
exists yet.
The asset load will fail and an error will be printed to the logs if the asset stored at path
is not of type A
.
Examples found in repository?
More examples
- examples/window/transparent_window.rs
- examples/3d/reflection_probes.rs
- examples/2d/sprite.rs
- examples/3d/specular_tint.rs
- examples/shader/custom_render_phase.rs
- examples/state/computed_states.rs
- examples/shader/shader_material_wesl.rs
- examples/asset/asset_decompression.rs
- examples/ecs/removal_detection.rs
- examples/2d/move_sprite.rs
- examples/shader/custom_phase_item.rs
- examples/shader/specialized_mesh_pipeline.rs
- examples/testbed/ui.rs
- examples/3d/clearcoat.rs
- examples/2d/sprite_flipping.rs
- examples/movement/physics_in_fixed_timestep.rs
- examples/animation/gltf_skinned_mesh.rs
- examples/asset/custom_asset.rs
- examples/asset/processing/asset_processing.rs
- examples/3d/query_gltf_primitives.rs
- examples/2d/sprite_tile.rs
- examples/3d/lightmaps.rs
- examples/shader/shader_material_2d.rs
- examples/audio/audio_control.rs
- examples/ui/overflow_debug.rs
- examples/shader/array_texture.rs
- examples/ecs/fallible_params.rs
- examples/3d/color_grading.rs
- examples/window/window_settings.rs
- examples/3d/ssr.rs
- examples/audio/soundtrack.rs
- examples/2d/custom_gltf_vertex_attribute.rs
- examples/3d/occlusion_culling.rs
- examples/2d/pixel_grid_snap.rs
- examples/shader/shader_material.rs
- examples/shader/shader_material_glsl.rs
- examples/3d/clustered_decals.rs
- examples/3d/mixed_lighting.rs
- examples/asset/extra_source.rs
- examples/shader/texture_binding_array.rs
- examples/2d/sprite_slice.rs
- examples/ui/window_fallthrough.rs
- examples/asset/hot_asset_reloading.rs
- examples/ecs/parallel_query.rs
- examples/2d/transparency_2d.rs
- examples/3d/load_gltf_extras.rs
- examples/animation/morph_targets.rs
- examples/3d/post_processing.rs
- examples/games/game_menu.rs
- examples/asset/embedded_asset.rs
- examples/3d/rotate_environment_map.rs
- examples/2d/sprite_sheet.rs
- examples/games/loading_screen.rs
- examples/shader/shader_material_screenspace_texture.rs
- examples/3d/pcss.rs
- examples/testbed/3d.rs
- examples/3d/tonemapping.rs
- examples/3d/edit_material_on_gltf.rs
- examples/shader/shader_material_bindless.rs
- examples/3d/anisotropy.rs
- examples/ui/font_atlas_debug.rs
- examples/animation/animation_masks.rs
- examples/3d/animated_material.rs
- examples/3d/depth_of_field.rs
- examples/3d/skybox.rs
- examples/3d/load_gltf.rs
- examples/ui/tab_navigation.rs
- examples/input/text_input.rs
- examples/ui/button.rs
- examples/animation/animated_mesh.rs
- examples/shader/extended_material_bindless.rs
- examples/stress_tests/text_pipeline.rs
- examples/3d/update_gltf_scene.rs
- examples/3d/atmospheric_fog.rs
- examples/window/custom_cursor_image.rs
- examples/2d/mesh2d_vertex_color_texture.rs
- examples/ecs/hierarchy.rs
- examples/3d/fog_volumes.rs
- examples/3d/generate_custom_mesh.rs
- examples/stress_tests/many_sprites.rs
- examples/audio/spatial_audio_2d.rs
- examples/ui/relative_cursor_position.rs
- examples/ui/ui_material.rs
- examples/games/contributors.rs
- examples/testbed/2d.rs
- examples/ui/ui_scaling.rs
- examples/window/multiple_windows.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/ui/ui_texture_atlas.rs
- examples/2d/bloom_2d.rs
- examples/animation/animation_graph.rs
- examples/animation/animated_mesh_events.rs
- examples/ui/ghost_nodes.rs
- examples/asset/alter_sprite.rs
- examples/stress_tests/many_buttons.rs
- examples/shader/automatic_instancing.rs
- examples/audio/spatial_audio_3d.rs
- examples/camera/projection_zoom.rs
- examples/2d/rotation.rs
- examples/ui/ui_texture_slice.rs
- examples/3d/visibility_range.rs
- examples/2d/sprite_animation.rs
- examples/animation/animated_mesh_control.rs
- examples/3d/volumetric_fog.rs
- examples/3d/atmosphere.rs
- examples/3d/texture.rs
- examples/animation/animated_ui.rs
- examples/time/virtual_time.rs
- examples/3d/motion_blur.rs
- examples/ui/size_constraints.rs
- examples/games/stepping.rs
- examples/3d/anti_aliasing.rs
- examples/ui/transparency_ui.rs
- examples/transforms/align.rs
- examples/3d/decal.rs
- examples/ui/ui_texture_atlas_slice.rs
- examples/picking/sprite_picking.rs
- examples/2d/mesh2d_alpha_mode.rs
- examples/2d/mesh2d_arcs.rs
- examples/asset/repeated_texture.rs
- examples/ui/text_wrap_debug.rs
- examples/games/alien_cake_addict.rs
- examples/asset/alter_mesh.rs
- examples/asset/asset_settings.rs
- examples/ui/text.rs
- examples/2d/mesh2d_repeated_texture.rs
- examples/3d/meshlet.rs
- examples/3d/pbr.rs
- examples/asset/asset_loading.rs
- examples/3d/auto_exposure.rs
- examples/ui/overflow.rs
- examples/ui/flex_layout.rs
- examples/ui/overflow_clip_margin.rs
- examples/stress_tests/bevymark.rs
- examples/shader/shader_prepass.rs
- examples/ui/display_and_visibility.rs
- examples/games/breakout.rs
- examples/stress_tests/many_foxes.rs
- examples/3d/split_screen.rs
- examples/games/desk_toy.rs
- examples/2d/text2d.rs
- examples/2d/texture_atlas.rs
- examples/2d/sprite_scale.rs
- examples/3d/parallax_mapping.rs
- examples/3d/deferred_rendering.rs
- examples/animation/custom_skinned_mesh.rs
- examples/3d/blend_modes.rs
- examples/3d/lighting.rs
- examples/ui/text_debug.rs
- examples/ui/grid.rs
- examples/3d/transmission.rs
- examples/ui/scroll.rs
- examples/testbed/full_ui.rs
Sourcepub fn load_override<'a, A>(&self, path: impl Into<AssetPath<'a>>) -> Handle<A>where
A: Asset,
pub fn load_override<'a, A>(&self, path: impl Into<AssetPath<'a>>) -> Handle<A>where
A: Asset,
Same as load
, but you can load assets from unaproved paths
if AssetPlugin::unapproved_path_mode
is Deny
.
Sourcepub fn load_acquire<'a, A, G>(
&self,
path: impl Into<AssetPath<'a>>,
guard: G,
) -> Handle<A>
pub fn load_acquire<'a, A, G>( &self, path: impl Into<AssetPath<'a>>, guard: G, ) -> Handle<A>
Begins loading an Asset
of type A
stored at path
while holding a guard item.
The guard item is dropped when either the asset is loaded or loading has failed.
This function returns a “strong” Handle
. When the Asset
is loaded (and enters LoadState::Loaded
), it will be added to the
associated Assets
resource.
The guard item should notify the caller in its Drop
implementation. See example multi_asset_sync
.
Synchronously this can be a Arc<AtomicU32>
that decrements its counter, asynchronously this can be a Barrier
.
This function only guarantees the asset referenced by the Handle
is loaded. If your asset is separated into
multiple files, sub-assets referenced by the main asset might still be loading, depend on the implementation of the AssetLoader
.
Additionally, you can check the asset’s load state by reading AssetEvent
events, calling AssetServer::load_state
, or checking
the Assets
storage to see if the Asset
exists yet.
The asset load will fail and an error will be printed to the logs if the asset stored at path
is not of type A
.
Examples found in repository?
144fn setup_assets(mut commands: Commands, asset_server: Res<AssetServer>) {
145 let (barrier, guard) = AssetBarrier::new();
146 commands.insert_resource(OneHundredThings(std::array::from_fn(|i| match i % 5 {
147 0 => asset_server.load_acquire("models/GolfBall/GolfBall.glb", guard.clone()),
148 1 => asset_server.load_acquire("models/AlienCake/alien.glb", guard.clone()),
149 2 => asset_server.load_acquire("models/AlienCake/cakeBirthday.glb", guard.clone()),
150 3 => asset_server.load_acquire("models/FlightHelmet/FlightHelmet.gltf", guard.clone()),
151 4 => asset_server.load_acquire("models/torus/torus.gltf", guard.clone()),
152 _ => unreachable!(),
153 })));
154 let future = barrier.wait_async();
155 commands.insert_resource(barrier);
156
157 let loading_state = Arc::new(AtomicBool::new(false));
158 commands.insert_resource(AsyncLoadingState(loading_state.clone()));
159
160 // await the `AssetBarrierFuture`.
161 AsyncComputeTaskPool::get()
162 .spawn(async move {
163 future.await;
164 // Notify via `AsyncLoadingState`
165 loading_state.store(true, Ordering::Release);
166 })
167 .detach();
168}
Sourcepub fn load_acquire_override<'a, A, G>(
&self,
path: impl Into<AssetPath<'a>>,
guard: G,
) -> Handle<A>
pub fn load_acquire_override<'a, A, G>( &self, path: impl Into<AssetPath<'a>>, guard: G, ) -> Handle<A>
Same as load
, but you can load assets from unaproved paths
if AssetPlugin::unapproved_path_mode
is Deny
.
Sourcepub fn load_with_settings<'a, A, S>(
&self,
path: impl Into<AssetPath<'a>>,
settings: impl Fn(&mut S) + Send + Sync + 'static,
) -> Handle<A>
pub fn load_with_settings<'a, A, S>( &self, path: impl Into<AssetPath<'a>>, settings: impl Fn(&mut S) + Send + Sync + 'static, ) -> Handle<A>
Begins loading an Asset
of type A
stored at path
. The given settings
function will override the asset’s
AssetLoader
settings. The type S
must match the configured AssetLoader::Settings
or settings
changes
will be ignored and an error will be printed to the log.
Examples found in repository?
60fn spawn_sphere(
61 commands: &mut Commands,
62 materials: &mut Assets<StandardMaterial>,
63 asset_server: &AssetServer,
64 sphere_mesh: &Handle<Mesh>,
65) {
66 commands.spawn((
67 Mesh3d(sphere_mesh.clone()),
68 MeshMaterial3d(materials.add(StandardMaterial {
69 clearcoat: 1.0,
70 clearcoat_perceptual_roughness: 0.3,
71 clearcoat_normal_texture: Some(asset_server.load_with_settings(
72 "textures/ScratchedGold-Normal.png",
73 |settings: &mut ImageLoaderSettings| settings.is_srgb = false,
74 )),
75 metallic: 0.9,
76 perceptual_roughness: 0.1,
77 base_color: GOLD.into(),
78 ..default()
79 })),
80 Transform::from_xyz(0.0, 0.0, 0.0).with_scale(Vec3::splat(1.25)),
81 ));
82}
More examples
92fn spawn_car_paint_sphere(
93 commands: &mut Commands,
94 materials: &mut Assets<StandardMaterial>,
95 asset_server: &AssetServer,
96 sphere: &Handle<Mesh>,
97) {
98 commands
99 .spawn((
100 Mesh3d(sphere.clone()),
101 MeshMaterial3d(materials.add(StandardMaterial {
102 clearcoat: 1.0,
103 clearcoat_perceptual_roughness: 0.1,
104 normal_map_texture: Some(asset_server.load_with_settings(
105 "textures/BlueNoise-Normal.png",
106 |settings: &mut ImageLoaderSettings| settings.is_srgb = false,
107 )),
108 metallic: 0.9,
109 perceptual_roughness: 0.5,
110 base_color: BLUE.into(),
111 ..default()
112 })),
113 Transform::from_xyz(-1.0, 1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
114 ))
115 .insert(ExampleSphere);
116}
117
118/// Spawn a semitransparent object with a clearcoat layer.
119fn spawn_coated_glass_bubble_sphere(
120 commands: &mut Commands,
121 materials: &mut Assets<StandardMaterial>,
122 sphere: &Handle<Mesh>,
123) {
124 commands
125 .spawn((
126 Mesh3d(sphere.clone()),
127 MeshMaterial3d(materials.add(StandardMaterial {
128 clearcoat: 1.0,
129 clearcoat_perceptual_roughness: 0.1,
130 metallic: 0.5,
131 perceptual_roughness: 0.1,
132 base_color: Color::srgba(0.9, 0.9, 0.9, 0.3),
133 alpha_mode: AlphaMode::Blend,
134 ..default()
135 })),
136 Transform::from_xyz(-1.0, -1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
137 ))
138 .insert(ExampleSphere);
139}
140
141/// Spawns an object with both a clearcoat normal map (a scratched varnish) and
142/// a main layer normal map (the golf ball pattern).
143///
144/// This object is in glTF format, using the `KHR_materials_clearcoat`
145/// extension.
146fn spawn_golf_ball(commands: &mut Commands, asset_server: &AssetServer) {
147 commands.spawn((
148 SceneRoot(
149 asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/GolfBall/GolfBall.glb")),
150 ),
151 Transform::from_xyz(1.0, 1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
152 ExampleSphere,
153 ));
154}
155
156/// Spawns an object with only a clearcoat normal map (a scratch pattern) and no
157/// main layer normal map.
158fn spawn_scratched_gold_ball(
159 commands: &mut Commands,
160 materials: &mut Assets<StandardMaterial>,
161 asset_server: &AssetServer,
162 sphere: &Handle<Mesh>,
163) {
164 commands
165 .spawn((
166 Mesh3d(sphere.clone()),
167 MeshMaterial3d(materials.add(StandardMaterial {
168 clearcoat: 1.0,
169 clearcoat_perceptual_roughness: 0.3,
170 clearcoat_normal_texture: Some(asset_server.load_with_settings(
171 "textures/ScratchedGold-Normal.png",
172 |settings: &mut ImageLoaderSettings| settings.is_srgb = false,
173 )),
174 metallic: 0.9,
175 perceptual_roughness: 0.1,
176 base_color: GOLD.into(),
177 ..default()
178 })),
179 Transform::from_xyz(1.0, -1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
180 ))
181 .insert(ExampleSphere);
182}
218fn setup_parallax(
219 mut commands: Commands,
220 mut materials: ResMut<Assets<StandardMaterial>>,
221 mut meshes: ResMut<Assets<Mesh>>,
222 asset_server: Res<AssetServer>,
223) {
224 // The normal map. Note that to generate it in the GIMP image editor, you should
225 // open the depth map, and do Filters → Generic → Normal Map
226 // You should enable the "flip X" checkbox.
227 let normal_handle = asset_server.load_with_settings(
228 "textures/parallax_example/cube_normal.png",
229 // The normal map texture is in linear color space. Lighting won't look correct
230 // if `is_srgb` is `true`, which is the default.
231 |settings: &mut ImageLoaderSettings| settings.is_srgb = false,
232 );
233
234 let mut cube = Mesh::from(Cuboid::new(0.15, 0.15, 0.15));
235
236 // NOTE: for normal maps and depth maps to work, the mesh
237 // needs tangents generated.
238 cube.generate_tangents().unwrap();
239
240 let parallax_material = materials.add(StandardMaterial {
241 perceptual_roughness: 0.4,
242 base_color_texture: Some(asset_server.load("textures/parallax_example/cube_color.png")),
243 normal_map_texture: Some(normal_handle),
244 // The depth map is a grayscale texture where black is the highest level and
245 // white the lowest.
246 depth_map: Some(asset_server.load("textures/parallax_example/cube_depth.png")),
247 parallax_depth_scale: 0.09,
248 parallax_mapping_method: ParallaxMappingMethod::Relief { max_steps: 4 },
249 max_parallax_layer_count: ops::exp2(5.0f32),
250 ..default()
251 });
252 commands.spawn((
253 Mesh3d(meshes.add(cube)),
254 MeshMaterial3d(parallax_material),
255 Transform::from_xyz(0.4, 0.2, -0.8),
256 Spin { speed: 0.3 },
257 ));
258}
175fn spawn_water(
176 commands: &mut Commands,
177 asset_server: &AssetServer,
178 meshes: &mut Assets<Mesh>,
179 water_materials: &mut Assets<ExtendedMaterial<StandardMaterial, Water>>,
180) {
181 commands.spawn((
182 Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(1.0)))),
183 MeshMaterial3d(water_materials.add(ExtendedMaterial {
184 base: StandardMaterial {
185 base_color: BLACK.into(),
186 perceptual_roughness: 0.0,
187 ..default()
188 },
189 extension: Water {
190 normals: asset_server.load_with_settings::<Image, ImageLoaderSettings>(
191 "textures/water_normals.png",
192 |settings| {
193 settings.is_srgb = false;
194 settings.sampler = ImageSampler::Descriptor(ImageSamplerDescriptor {
195 address_mode_u: ImageAddressMode::Repeat,
196 address_mode_v: ImageAddressMode::Repeat,
197 mag_filter: ImageFilterMode::Linear,
198 min_filter: ImageFilterMode::Linear,
199 ..default()
200 });
201 },
202 ),
203 // These water settings are just random values to create some
204 // variety.
205 settings: WaterSettings {
206 octave_vectors: [
207 vec4(0.080, 0.059, 0.073, -0.062),
208 vec4(0.153, 0.138, -0.149, -0.195),
209 ],
210 octave_scales: vec4(1.0, 2.1, 7.9, 14.9) * 5.0,
211 octave_strengths: vec4(0.16, 0.18, 0.093, 0.044),
212 },
213 },
214 })),
215 Transform::from_scale(Vec3::splat(100.0)),
216 ));
217}
48fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
49 let bird_left = Bird::Normal;
50 let bird_right = Bird::Normal;
51 commands.spawn(Camera2d);
52
53 let texture_left = asset_server.load_with_settings(
54 bird_left.get_texture_path(),
55 // `RenderAssetUsages::all()` is already the default, so the line below could be omitted.
56 // It's helpful to know it exists, however.
57 //
58 // `RenderAssetUsages` tell Bevy whether to keep the data around:
59 // - for the GPU (`RenderAssetUsages::RENDER_WORLD`),
60 // - for the CPU (`RenderAssetUsages::MAIN_WORLD`),
61 // - or both.
62 // `RENDER_WORLD` is necessary to render the image, `MAIN_WORLD` is necessary to inspect
63 // and modify the image (via `ResMut<Assets<Image>>`).
64 //
65 // Since most games will not need to modify textures at runtime, many developers opt to pass
66 // only `RENDER_WORLD`. This is more memory efficient, as we don't need to keep the image in
67 // RAM. For this example however, this would not work, as we need to inspect and modify the
68 // image at runtime.
69 |settings: &mut ImageLoaderSettings| settings.asset_usage = RenderAssetUsages::all(),
70 );
71
72 commands.spawn((
73 Name::new("Bird Left"),
74 // This marker component ensures we can easily find either of the Birds by using With and
75 // Without query filters.
76 Left,
77 Sprite::from_image(texture_left),
78 Transform::from_xyz(-200.0, 0.0, 0.0),
79 bird_left,
80 ));
81
82 commands.spawn((
83 Name::new("Bird Right"),
84 // In contrast to the above, here we rely on the default `RenderAssetUsages` loader setting
85 Sprite::from_image(asset_server.load(bird_right.get_texture_path())),
86 Transform::from_xyz(200.0, 0.0, 0.0),
87 bird_right,
88 ));
89}
20fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
21 let image = asset_server.load_with_settings(
22 "textures/fantasy_ui_borders/numbered_slices.png",
23 |settings: &mut ImageLoaderSettings| {
24 // Need to use nearest filtering to avoid bleeding between the slices with tiling
25 settings.sampler = ImageSampler::nearest();
26 },
27 );
28
29 let slicer = TextureSlicer {
30 // `numbered_slices.png` is 48 pixels square. `BorderRect::square(16.)` insets the slicing line from each edge by 16 pixels, resulting in nine slices that are each 16 pixels square.
31 border: BorderRect::all(16.),
32 // With `SliceScaleMode::Tile` the side and center slices are tiled to fill the side and center sections of the target.
33 // And with a `stretch_value` of `1.` the tiles will have the same size as the corresponding slices in the source image.
34 center_scale_mode: SliceScaleMode::Tile { stretch_value: 1. },
35 sides_scale_mode: SliceScaleMode::Tile { stretch_value: 1. },
36 ..default()
37 };
38
39 // ui camera
40 commands.spawn(Camera2d);
41
42 commands
43 .spawn(Node {
44 width: Val::Percent(100.),
45 height: Val::Percent(100.),
46 justify_content: JustifyContent::Center,
47 align_content: AlignContent::Center,
48 flex_wrap: FlexWrap::Wrap,
49 column_gap: Val::Px(10.),
50 row_gap: Val::Px(10.),
51 ..default()
52 })
53 .with_children(|parent| {
54 for [columns, rows] in [[3., 3.], [4., 4.], [5., 4.], [4., 5.], [5., 5.]] {
55 for (flip_x, flip_y) in [(false, false), (false, true), (true, false), (true, true)]
56 {
57 parent.spawn((
58 ImageNode {
59 image: image.clone(),
60 flip_x,
61 flip_y,
62 image_mode: NodeImageMode::Sliced(slicer.clone()),
63 ..default()
64 },
65 Node {
66 width: Val::Px(16. * columns),
67 height: Val::Px(16. * rows),
68 ..default()
69 },
70 ));
71 }
72 }
73 });
74}
Sourcepub fn load_with_settings_override<'a, A, S>(
&self,
path: impl Into<AssetPath<'a>>,
settings: impl Fn(&mut S) + Send + Sync + 'static,
) -> Handle<A>
pub fn load_with_settings_override<'a, A, S>( &self, path: impl Into<AssetPath<'a>>, settings: impl Fn(&mut S) + Send + Sync + 'static, ) -> Handle<A>
Same as load
, but you can load assets from unaproved paths
if AssetPlugin::unapproved_path_mode
is Deny
.
Sourcepub fn load_acquire_with_settings<'a, A, S, G>(
&self,
path: impl Into<AssetPath<'a>>,
settings: impl Fn(&mut S) + Send + Sync + 'static,
guard: G,
) -> Handle<A>
pub fn load_acquire_with_settings<'a, A, S, G>( &self, path: impl Into<AssetPath<'a>>, settings: impl Fn(&mut S) + Send + Sync + 'static, guard: G, ) -> Handle<A>
Begins loading an Asset
of type A
stored at path
while holding a guard item.
The guard item is dropped when either the asset is loaded or loading has failed.
This function only guarantees the asset referenced by the Handle
is loaded. If your asset is separated into
multiple files, sub-assets referenced by the main asset might still be loading, depend on the implementation of the AssetLoader
.
The given settings
function will override the asset’s
AssetLoader
settings. The type S
must match the configured AssetLoader::Settings
or settings
changes
will be ignored and an error will be printed to the log.
Sourcepub fn load_acquire_with_settings_override<'a, A, S, G>(
&self,
path: impl Into<AssetPath<'a>>,
settings: impl Fn(&mut S) + Send + Sync + 'static,
guard: G,
) -> Handle<A>
pub fn load_acquire_with_settings_override<'a, A, S, G>( &self, path: impl Into<AssetPath<'a>>, settings: impl Fn(&mut S) + Send + Sync + 'static, guard: G, ) -> Handle<A>
Same as load
, but you can load assets from unaproved paths
if AssetPlugin::unapproved_path_mode
is Deny
.
Sourcepub async fn load_untyped_async<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Result<UntypedHandle, AssetLoadError>
pub async fn load_untyped_async<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Result<UntypedHandle, AssetLoadError>
Asynchronously load an asset that you do not know the type of statically. If you do know the type of the asset,
you should use AssetServer::load
. If you don’t know the type of the asset, but you can’t use an async method,
consider using AssetServer::load_untyped
.
Sourcepub fn load_untyped<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Handle<LoadedUntypedAsset>
pub fn load_untyped<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Handle<LoadedUntypedAsset>
Load an asset without knowing its type. The method returns a handle to a LoadedUntypedAsset
.
Once the LoadedUntypedAsset
is loaded, an untyped handle for the requested path can be
retrieved from it.
use bevy_asset::{Assets, Handle, LoadedUntypedAsset};
use bevy_ecs::system::Res;
use bevy_ecs::resource::Resource;
#[derive(Resource)]
struct LoadingUntypedHandle(Handle<LoadedUntypedAsset>);
fn resolve_loaded_untyped_handle(loading_handle: Res<LoadingUntypedHandle>, loaded_untyped_assets: Res<Assets<LoadedUntypedAsset>>) {
if let Some(loaded_untyped_asset) = loaded_untyped_assets.get(&loading_handle.0) {
let handle = loaded_untyped_asset.handle.clone();
// continue working with `handle` which points to the asset at the originally requested path
}
}
This indirection enables a non blocking load of an untyped asset, since I/O is required to figure out the asset type before a handle can be created.
Sourcepub fn reload<'a>(&self, path: impl Into<AssetPath<'a>>)
pub fn reload<'a>(&self, path: impl Into<AssetPath<'a>>)
Kicks off a reload of the asset stored at the given path. This will only reload the asset if it currently loaded.
Sourcepub fn add<A>(&self, asset: A) -> Handle<A>where
A: Asset,
pub fn add<A>(&self, asset: A) -> Handle<A>where
A: Asset,
Queues a new asset to be tracked by the AssetServer
and returns a Handle
to it. This can be used to track
dependencies of assets created at runtime.
After the asset has been fully loaded by the AssetServer
, it will show up in the relevant Assets
storage.
Examples found in repository?
115fn decompress<T: Component + From<Handle<A>>, A: Asset>(
116 mut commands: Commands,
117 asset_server: Res<AssetServer>,
118 mut compressed_assets: ResMut<Assets<GzAsset>>,
119 query: Query<(Entity, &Compressed<A>)>,
120) {
121 for (entity, Compressed { compressed, .. }) in query.iter() {
122 let Some(GzAsset { uncompressed }) = compressed_assets.remove(compressed) else {
123 continue;
124 };
125
126 let uncompressed = uncompressed.take::<A>().unwrap();
127
128 commands
129 .entity(entity)
130 .remove::<Compressed<A>>()
131 .insert(T::from(asset_server.add(uncompressed)));
132 }
133}
More examples
100fn setup(mut commands: Commands, asset_server: Res<AssetServer>, app_status: Res<AppStatus>) {
101 commands.spawn((
102 Camera3d::default(),
103 Transform::from_translation(CAMERA_INITIAL_POSITION).looking_at(Vec3::ZERO, Vec3::Y),
104 ));
105
106 spawn_directional_light(&mut commands);
107
108 commands.spawn((
109 SceneRoot(asset_server.load("models/AnisotropyBarnLamp/AnisotropyBarnLamp.gltf#Scene0")),
110 Transform::from_xyz(0.0, 0.07, -0.13),
111 Scene::BarnLamp,
112 ));
113
114 commands.spawn((
115 Mesh3d(
116 asset_server.add(
117 Mesh::from(Sphere::new(0.1))
118 .with_generated_tangents()
119 .unwrap(),
120 ),
121 ),
122 MeshMaterial3d(asset_server.add(StandardMaterial {
123 base_color: palettes::tailwind::GRAY_300.into(),
124 anisotropy_rotation: 0.5,
125 anisotropy_strength: 1.,
126 ..default()
127 })),
128 Scene::Sphere,
129 Visibility::Hidden,
130 ));
131
132 spawn_text(&mut commands, &app_status);
133}
Sourcepub fn add_async<A, E>(
&self,
future: impl Future<Output = Result<A, E>> + Send + 'static,
) -> Handle<A>
pub fn add_async<A, E>( &self, future: impl Future<Output = Result<A, E>> + Send + 'static, ) -> Handle<A>
Queues a new asset to be tracked by the AssetServer
and returns a Handle
to it. This can be used to track
dependencies of assets created at runtime.
After the asset has been fully loaded, it will show up in the relevant Assets
storage.
Sourcepub fn load_folder<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Handle<LoadedFolder>
pub fn load_folder<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Handle<LoadedFolder>
Loads all assets from the specified folder recursively. The LoadedFolder
asset (when it loads) will
contain handles to all assets in the folder. You can wait for all assets to load by checking the LoadedFolder
’s
RecursiveDependencyLoadState
.
Loading the same folder multiple times will return the same handle. If the file_watcher
feature is enabled, LoadedFolder
handles will reload when a file in the folder is
removed, added or moved. This includes files in subdirectories and moving, adding,
or removing complete subdirectories.
Examples found in repository?
More examples
12fn setup(
13 mut commands: Commands,
14 asset_server: Res<AssetServer>,
15 meshes: Res<Assets<Mesh>>,
16 mut materials: ResMut<Assets<StandardMaterial>>,
17) {
18 // By default AssetServer will load assets from inside the "assets" folder.
19 // For example, the next line will load GltfAssetLabel::Primitive{mesh:0,primitive:0}.from_asset("ROOT/assets/models/cube/cube.gltf"),
20 // where "ROOT" is the directory of the Application.
21 //
22 // This can be overridden by setting [`AssetPlugin.file_path`].
23 let cube_handle = asset_server.load(
24 GltfAssetLabel::Primitive {
25 mesh: 0,
26 primitive: 0,
27 }
28 .from_asset("models/cube/cube.gltf"),
29 );
30 let sphere_handle = asset_server.load(
31 GltfAssetLabel::Primitive {
32 mesh: 0,
33 primitive: 0,
34 }
35 .from_asset("models/sphere/sphere.gltf"),
36 );
37
38 // All assets end up in their Assets<T> collection once they are done loading:
39 if let Some(sphere) = meshes.get(&sphere_handle) {
40 // You might notice that this doesn't run! This is because assets load in parallel without
41 // blocking. When an asset has loaded, it will appear in relevant Assets<T>
42 // collection.
43 info!("{:?}", sphere.primitive_topology());
44 } else {
45 info!("sphere hasn't loaded yet");
46 }
47
48 // You can load all assets in a folder like this. They will be loaded in parallel without
49 // blocking. The LoadedFolder asset holds handles to each asset in the folder. These are all
50 // dependencies of the LoadedFolder asset, meaning you can wait for the LoadedFolder asset to
51 // fire AssetEvent::LoadedWithDependencies if you want to wait for all assets in the folder
52 // to load.
53 // If you want to keep the assets in the folder alive, make sure you store the returned handle
54 // somewhere.
55 let _loaded_folder: Handle<LoadedFolder> = asset_server.load_folder("models/torus");
56
57 // If you want a handle to a specific asset in a loaded folder, the easiest way to get one is to call load.
58 // It will _not_ be loaded a second time.
59 // The LoadedFolder asset will ultimately also hold handles to the assets, but waiting for it to load
60 // and finding the right handle is more work!
61 let torus_handle = asset_server.load(
62 GltfAssetLabel::Primitive {
63 mesh: 0,
64 primitive: 0,
65 }
66 .from_asset("models/torus/torus.gltf"),
67 );
68
69 // You can also add assets directly to their Assets<T> storage:
70 let material_handle = materials.add(StandardMaterial {
71 base_color: Color::srgb(0.8, 0.7, 0.6),
72 ..default()
73 });
74
75 // torus
76 commands.spawn((
77 Mesh3d(torus_handle),
78 MeshMaterial3d(material_handle.clone()),
79 Transform::from_xyz(-3.0, 0.0, 0.0),
80 ));
81 // cube
82 commands.spawn((
83 Mesh3d(cube_handle),
84 MeshMaterial3d(material_handle.clone()),
85 Transform::from_xyz(0.0, 0.0, 0.0),
86 ));
87 // sphere
88 commands.spawn((
89 Mesh3d(sphere_handle),
90 MeshMaterial3d(material_handle),
91 Transform::from_xyz(3.0, 0.0, 0.0),
92 ));
93 // light
94 commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 5.0, 4.0)));
95 // camera
96 commands.spawn((
97 Camera3d::default(),
98 Transform::from_xyz(0.0, 3.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
99 ));
100}
Sourcepub fn get_load_states(
&self,
id: impl Into<UntypedAssetId>,
) -> Option<(LoadState, DependencyLoadState, RecursiveDependencyLoadState)>
pub fn get_load_states( &self, id: impl Into<UntypedAssetId>, ) -> Option<(LoadState, DependencyLoadState, RecursiveDependencyLoadState)>
Retrieves all loads states for the given asset id.
Sourcepub fn get_load_state(&self, id: impl Into<UntypedAssetId>) -> Option<LoadState>
pub fn get_load_state(&self, id: impl Into<UntypedAssetId>) -> Option<LoadState>
Retrieves the main LoadState
of a given asset id
.
Note that this is “just” the root asset load state. To get the load state of
its dependencies or recursive dependencies, see AssetServer::get_dependency_load_state
and AssetServer::get_recursive_dependency_load_state
respectively.
Sourcepub fn get_dependency_load_state(
&self,
id: impl Into<UntypedAssetId>,
) -> Option<DependencyLoadState>
pub fn get_dependency_load_state( &self, id: impl Into<UntypedAssetId>, ) -> Option<DependencyLoadState>
Retrieves the DependencyLoadState
of a given asset id
’s dependencies.
Note that this is only the load state of direct dependencies of the root asset. To get
the load state of the root asset itself or its recursive dependencies, see
AssetServer::get_load_state
and AssetServer::get_recursive_dependency_load_state
respectively.
Sourcepub fn get_recursive_dependency_load_state(
&self,
id: impl Into<UntypedAssetId>,
) -> Option<RecursiveDependencyLoadState>
pub fn get_recursive_dependency_load_state( &self, id: impl Into<UntypedAssetId>, ) -> Option<RecursiveDependencyLoadState>
Retrieves the main RecursiveDependencyLoadState
of a given asset id
’s recursive dependencies.
Note that this is only the load state of recursive dependencies of the root asset. To get
the load state of the root asset itself or its direct dependencies only, see
AssetServer::get_load_state
and AssetServer::get_dependency_load_state
respectively.
Examples found in repository?
196fn update_loading_data(
197 mut loading_data: ResMut<LoadingData>,
198 mut loading_state: ResMut<LoadingState>,
199 asset_server: Res<AssetServer>,
200 pipelines_ready: Res<PipelinesReady>,
201) {
202 if !loading_data.loading_assets.is_empty() || !pipelines_ready.0 {
203 // If we are still loading assets / pipelines are not fully compiled,
204 // we reset the confirmation frame count.
205 loading_data.confirmation_frames_count = 0;
206
207 loading_data.loading_assets.retain(|asset| {
208 asset_server
209 .get_recursive_dependency_load_state(asset)
210 .is_none_or(|state| !state.is_loaded())
211 });
212
213 // If there are no more assets being monitored, and pipelines
214 // are compiled, then start counting confirmation frames.
215 // Once enough confirmations have passed, everything will be
216 // considered to be fully loaded.
217 } else {
218 loading_data.confirmation_frames_count += 1;
219 if loading_data.confirmation_frames_count == loading_data.confirmation_frames_target {
220 *loading_state = LoadingState::LevelReady;
221 }
222 }
223}
Sourcepub fn load_state(&self, id: impl Into<UntypedAssetId>) -> LoadState
pub fn load_state(&self, id: impl Into<UntypedAssetId>) -> LoadState
Retrieves the main LoadState
of a given asset id
.
This is the same as AssetServer::get_load_state
except the result is unwrapped. If
the result is None, LoadState::NotLoaded
is returned.
Examples found in repository?
127fn environment_map_load_finish(
128 mut commands: Commands,
129 asset_server: Res<AssetServer>,
130 environment_map: Single<&EnvironmentMapLight>,
131 label_entity: Option<Single<Entity, With<EnvironmentMapLabel>>>,
132) {
133 if asset_server
134 .load_state(&environment_map.diffuse_map)
135 .is_loaded()
136 && asset_server
137 .load_state(&environment_map.specular_map)
138 .is_loaded()
139 {
140 // Do not attempt to remove `label_entity` if it has already been removed.
141 if let Some(label_entity) = label_entity {
142 commands.entity(*label_entity).despawn();
143 }
144 }
145}
More examples
143fn asset_loaded(
144 asset_server: Res<AssetServer>,
145 mut images: ResMut<Assets<Image>>,
146 mut cubemap: ResMut<Cubemap>,
147 mut skyboxes: Query<&mut Skybox>,
148) {
149 if !cubemap.is_loaded && asset_server.load_state(&cubemap.image_handle).is_loaded() {
150 info!("Swapping to {}...", CUBEMAPS[cubemap.index].0);
151 let image = images.get_mut(&cubemap.image_handle).unwrap();
152 // NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture,
153 // so they appear as one texture. The following code reconfigures the texture as necessary.
154 if image.texture_descriptor.array_layer_count() == 1 {
155 image.reinterpret_stacked_2d_as_array(image.height() / image.width());
156 image.texture_view_descriptor = Some(TextureViewDescriptor {
157 dimension: Some(TextureViewDimension::Cube),
158 ..default()
159 });
160 }
161
162 for mut skybox in &mut skyboxes {
163 skybox.image = cubemap.image_handle.clone();
164 }
165
166 cubemap.is_loaded = true;
167 }
168}
50fn create_array_texture(
51 mut commands: Commands,
52 asset_server: Res<AssetServer>,
53 mut loading_texture: ResMut<LoadingTexture>,
54 mut images: ResMut<Assets<Image>>,
55 mut meshes: ResMut<Assets<Mesh>>,
56 mut materials: ResMut<Assets<ArrayTextureMaterial>>,
57) {
58 if loading_texture.is_loaded
59 || !asset_server
60 .load_state(loading_texture.handle.id())
61 .is_loaded()
62 {
63 return;
64 }
65 loading_texture.is_loaded = true;
66 let image = images.get_mut(&loading_texture.handle).unwrap();
67
68 // Create a new array texture asset from the loaded texture.
69 let array_layers = 4;
70 image.reinterpret_stacked_2d_as_array(array_layers);
71
72 // Spawn some cubes using the array texture
73 let mesh_handle = meshes.add(Cuboid::default());
74 let material_handle = materials.add(ArrayTextureMaterial {
75 array_texture: loading_texture.handle.clone(),
76 });
77 for x in -5..=5 {
78 commands.spawn((
79 Mesh3d(mesh_handle.clone()),
80 MeshMaterial3d(material_handle.clone()),
81 Transform::from_xyz(x as f32 + 0.5, 0.0, 0.0),
82 ));
83 }
84}
Sourcepub fn dependency_load_state(
&self,
id: impl Into<UntypedAssetId>,
) -> DependencyLoadState
pub fn dependency_load_state( &self, id: impl Into<UntypedAssetId>, ) -> DependencyLoadState
Retrieves the DependencyLoadState
of a given asset id
.
This is the same as AssetServer::get_dependency_load_state
except the result is unwrapped. If
the result is None, DependencyLoadState::NotLoaded
is returned.
Sourcepub fn recursive_dependency_load_state(
&self,
id: impl Into<UntypedAssetId>,
) -> RecursiveDependencyLoadState
pub fn recursive_dependency_load_state( &self, id: impl Into<UntypedAssetId>, ) -> RecursiveDependencyLoadState
Retrieves the RecursiveDependencyLoadState
of a given asset id
.
This is the same as AssetServer::get_recursive_dependency_load_state
except the result is unwrapped. If
the result is None, RecursiveDependencyLoadState::NotLoaded
is returned.
Sourcepub fn is_loaded(&self, id: impl Into<UntypedAssetId>) -> bool
pub fn is_loaded(&self, id: impl Into<UntypedAssetId>) -> bool
Convenience method that returns true if the asset has been loaded.
Sourcepub fn is_loaded_with_direct_dependencies(
&self,
id: impl Into<UntypedAssetId>,
) -> bool
pub fn is_loaded_with_direct_dependencies( &self, id: impl Into<UntypedAssetId>, ) -> bool
Convenience method that returns true if the asset and all of its direct dependencies have been loaded.
Sourcepub fn is_loaded_with_dependencies(&self, id: impl Into<UntypedAssetId>) -> bool
pub fn is_loaded_with_dependencies(&self, id: impl Into<UntypedAssetId>) -> bool
Convenience method that returns true if the asset, all of its dependencies, and all of its recursive dependencies have been loaded.
Sourcepub fn get_handle<'a, A>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Option<Handle<A>>where
A: Asset,
pub fn get_handle<'a, A>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Option<Handle<A>>where
A: Asset,
Returns an active handle for the given path, if the asset at the given path has already started loading, or is still “alive”.
Examples found in repository?
50fn setup(
51 mut commands: Commands,
52 rpg_sprite_handles: Res<RpgSpriteFolder>,
53 asset_server: Res<AssetServer>,
54 mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
55 loaded_folders: Res<Assets<LoadedFolder>>,
56 mut textures: ResMut<Assets<Image>>,
57) {
58 let loaded_folder = loaded_folders.get(&rpg_sprite_handles.0).unwrap();
59
60 // Create texture atlases with different padding and sampling
61
62 let (texture_atlas_linear, linear_sources, linear_texture) = create_texture_atlas(
63 loaded_folder,
64 None,
65 Some(ImageSampler::linear()),
66 &mut textures,
67 );
68 let atlas_linear_handle = texture_atlases.add(texture_atlas_linear);
69
70 let (texture_atlas_nearest, nearest_sources, nearest_texture) = create_texture_atlas(
71 loaded_folder,
72 None,
73 Some(ImageSampler::nearest()),
74 &mut textures,
75 );
76 let atlas_nearest_handle = texture_atlases.add(texture_atlas_nearest);
77
78 let (texture_atlas_linear_padded, linear_padded_sources, linear_padded_texture) =
79 create_texture_atlas(
80 loaded_folder,
81 Some(UVec2::new(6, 6)),
82 Some(ImageSampler::linear()),
83 &mut textures,
84 );
85 let atlas_linear_padded_handle = texture_atlases.add(texture_atlas_linear_padded.clone());
86
87 let (texture_atlas_nearest_padded, nearest_padded_sources, nearest_padded_texture) =
88 create_texture_atlas(
89 loaded_folder,
90 Some(UVec2::new(6, 6)),
91 Some(ImageSampler::nearest()),
92 &mut textures,
93 );
94 let atlas_nearest_padded_handle = texture_atlases.add(texture_atlas_nearest_padded);
95
96 commands.spawn(Camera2d);
97
98 // Padded textures are to the right, unpadded to the left
99
100 // Draw unpadded texture atlas
101 commands.spawn((
102 Sprite::from_image(linear_texture.clone()),
103 Transform {
104 translation: Vec3::new(-250.0, -160.0, 0.0),
105 scale: Vec3::splat(0.5),
106 ..default()
107 },
108 ));
109
110 // Draw padded texture atlas
111 commands.spawn((
112 Sprite::from_image(linear_padded_texture.clone()),
113 Transform {
114 translation: Vec3::new(250.0, -160.0, 0.0),
115 scale: Vec3::splat(0.5),
116 ..default()
117 },
118 ));
119
120 let font = asset_server.load("fonts/FiraSans-Bold.ttf");
121
122 // Padding label text style
123 let text_style: TextFont = TextFont {
124 font: font.clone(),
125 font_size: 42.0,
126 ..default()
127 };
128
129 // Labels to indicate padding
130
131 // No padding
132 create_label(
133 &mut commands,
134 (-250.0, 250.0, 0.0),
135 "No padding",
136 text_style.clone(),
137 );
138
139 // Padding
140 create_label(&mut commands, (250.0, 250.0, 0.0), "Padding", text_style);
141
142 // Get handle to a sprite to render
143 let vendor_handle: Handle<Image> = asset_server
144 .get_handle("textures/rpg/chars/vendor/generic-rpg-vendor.png")
145 .unwrap();
146
147 // Configuration array to render sprites through iteration
148 let configurations: [(
149 &str,
150 Handle<TextureAtlasLayout>,
151 TextureAtlasSources,
152 Handle<Image>,
153 f32,
154 ); 4] = [
155 (
156 "Linear",
157 atlas_linear_handle,
158 linear_sources,
159 linear_texture,
160 -350.0,
161 ),
162 (
163 "Nearest",
164 atlas_nearest_handle,
165 nearest_sources,
166 nearest_texture,
167 -150.0,
168 ),
169 (
170 "Linear",
171 atlas_linear_padded_handle,
172 linear_padded_sources,
173 linear_padded_texture,
174 150.0,
175 ),
176 (
177 "Nearest",
178 atlas_nearest_padded_handle,
179 nearest_padded_sources,
180 nearest_padded_texture,
181 350.0,
182 ),
183 ];
184
185 // Label text style
186 let sampling_label_style = TextFont {
187 font,
188 font_size: 25.0,
189 ..default()
190 };
191
192 let base_y = 80.0; // y position of the sprites
193
194 for (sampling, atlas_handle, atlas_sources, atlas_texture, x) in configurations {
195 // Render a sprite from the texture_atlas
196 create_sprite_from_atlas(
197 &mut commands,
198 (x, base_y, 0.0),
199 atlas_texture,
200 atlas_sources,
201 atlas_handle,
202 &vendor_handle,
203 );
204
205 // Render a label to indicate the sampling setting
206 create_label(
207 &mut commands,
208 (x, base_y + 110.0, 0.0), // Offset to y position of the sprite
209 sampling,
210 sampling_label_style.clone(),
211 );
212 }
213}
Sourcepub fn get_id_handle<A>(&self, id: AssetId<A>) -> Option<Handle<A>>where
A: Asset,
pub fn get_id_handle<A>(&self, id: AssetId<A>) -> Option<Handle<A>>where
A: Asset,
Get a Handle
from an AssetId
.
This only returns Some
if id
is derived from a Handle
that was
loaded through an AssetServer
, otherwise it returns None
.
Consider using Assets::get_strong_handle
in the case the Handle
comes from Assets::add
.
Sourcepub fn get_id_handle_untyped(&self, id: UntypedAssetId) -> Option<UntypedHandle>
pub fn get_id_handle_untyped(&self, id: UntypedAssetId) -> Option<UntypedHandle>
Get an UntypedHandle
from an UntypedAssetId
.
See AssetServer::get_id_handle
for details.
Sourcepub fn is_managed(&self, id: impl Into<UntypedAssetId>) -> bool
pub fn is_managed(&self, id: impl Into<UntypedAssetId>) -> bool
Returns true
if the given id
corresponds to an asset that is managed by this AssetServer
.
Otherwise, returns false
.
Sourcepub fn get_path_id<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Option<UntypedAssetId>
pub fn get_path_id<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Option<UntypedAssetId>
Returns an active untyped asset id for the given path, if the asset at the given path has already started loading, or is still “alive”. Returns the first ID in the event of multiple assets being registered against a single path.
§See also
get_path_ids
for all handles.
Sourcepub fn get_path_ids<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Vec<UntypedAssetId>
pub fn get_path_ids<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Vec<UntypedAssetId>
Returns all active untyped asset IDs for the given path, if the assets at the given path have already started loading,
or are still “alive”.
Multiple IDs will be returned in the event that a single path is used by multiple AssetLoader
’s.
Sourcepub fn get_handle_untyped<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Option<UntypedHandle>
pub fn get_handle_untyped<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Option<UntypedHandle>
Returns an active untyped handle for the given path, if the asset at the given path has already started loading, or is still “alive”. Returns the first handle in the event of multiple assets being registered against a single path.
§See also
get_handles_untyped
for all handles.
Sourcepub fn get_handles_untyped<'a>(
&self,
path: impl Into<AssetPath<'a>>,
) -> Vec<UntypedHandle>
pub fn get_handles_untyped<'a>( &self, path: impl Into<AssetPath<'a>>, ) -> Vec<UntypedHandle>
Returns all active untyped handles for the given path, if the assets at the given path have already started loading,
or are still “alive”.
Multiple handles will be returned in the event that a single path is used by multiple AssetLoader
’s.
Sourcepub fn get_path_and_type_id_handle(
&self,
path: &AssetPath<'_>,
type_id: TypeId,
) -> Option<UntypedHandle>
pub fn get_path_and_type_id_handle( &self, path: &AssetPath<'_>, type_id: TypeId, ) -> Option<UntypedHandle>
Returns an active untyped handle for the given path and TypeId
, if the asset at the given path has already started loading,
or is still “alive”.
Sourcepub fn get_path(&self, id: impl Into<UntypedAssetId>) -> Option<AssetPath<'_>>
pub fn get_path(&self, id: impl Into<UntypedAssetId>) -> Option<AssetPath<'_>>
Returns the path for the given id
, if it has one.
Sourcepub fn mode(&self) -> AssetServerMode
pub fn mode(&self) -> AssetServerMode
Returns the AssetServerMode
this server is currently in.
Sourcepub fn preregister_loader<L>(&self, extensions: &[&str])where
L: AssetLoader,
pub fn preregister_loader<L>(&self, extensions: &[&str])where
L: AssetLoader,
Pre-register a loader that will later be added.
Assets loaded with matching extensions will be blocked until the real loader is added.
Sourcepub async fn wait_for_asset<A>(
&self,
handle: &Handle<A>,
) -> Result<(), WaitForAssetError>where
A: Asset,
pub async fn wait_for_asset<A>(
&self,
handle: &Handle<A>,
) -> Result<(), WaitForAssetError>where
A: Asset,
Returns a future that will suspend until the specified asset and its dependencies finish loading.
§Errors
This will return an error if the asset or any of its dependencies fail to load, or if the asset has not been queued up to be loaded.
Sourcepub async fn wait_for_asset_untyped(
&self,
handle: &UntypedHandle,
) -> Result<(), WaitForAssetError>
pub async fn wait_for_asset_untyped( &self, handle: &UntypedHandle, ) -> Result<(), WaitForAssetError>
Returns a future that will suspend until the specified asset and its dependencies finish loading.
§Errors
This will return an error if the asset or any of its dependencies fail to load, or if the asset has not been queued up to be loaded.
Sourcepub async fn wait_for_asset_id(
&self,
id: impl Into<UntypedAssetId>,
) -> Result<(), WaitForAssetError>
pub async fn wait_for_asset_id( &self, id: impl Into<UntypedAssetId>, ) -> Result<(), WaitForAssetError>
Returns a future that will suspend until the specified asset and its dependencies finish loading.
Note that since an asset ID does not count as a reference to the asset, the future returned from this method will not keep the asset alive. This may lead to the asset unexpectedly being dropped while you are waiting for it to finish loading.
When calling this method, make sure a strong handle is stored elsewhere to prevent the
asset from being dropped.
If you have access to an asset’s strong Handle
, you should prefer to call
AssetServer::wait_for_asset
or wait_for_asset_untyped
to ensure the asset finishes
loading.
§Errors
This will return an error if the asset or any of its dependencies fail to load, or if the asset has not been queued up to be loaded.
Sourcepub async fn write_default_loader_meta_file_for_path(
&self,
path: impl Into<AssetPath<'_>>,
) -> Result<(), WriteDefaultMetaError>
pub async fn write_default_loader_meta_file_for_path( &self, path: impl Into<AssetPath<'_>>, ) -> Result<(), WriteDefaultMetaError>
Writes the default loader meta file for the provided path
.
This function only generates meta files that simply load the path directly. To generate a
meta file that will use the default asset processor for the path, see
AssetProcessor::write_default_meta_file_for_path
.
Note if there is already a meta file for path
, this function returns
Err(WriteDefaultMetaError::MetaAlreadyExists)
.
Trait Implementations§
Source§impl Clone for AssetServer
impl Clone for AssetServer
Source§fn clone(&self) -> AssetServer
fn clone(&self) -> AssetServer
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl Debug for AssetServer
impl Debug for AssetServer
impl Resource for AssetServer
Auto Trait Implementations§
impl Freeze for AssetServer
impl !RefUnwindSafe for AssetServer
impl Send for AssetServer
impl Sync for AssetServer
impl Unpin for AssetServer
impl !UnwindSafe for AssetServer
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
, which can then be
downcast
into Box<dyn ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
, which can then be further
downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.