From 54de1a7db478e307f5b3d87822e8efc09c3b51c0 Mon Sep 17 00:00:00 2001 From: Niklas Eicker Date: Tue, 31 Oct 2023 20:38:09 +0100 Subject: [PATCH] Add the new image sampler attribute to the readme, full collection example and changelog --- CHANGELOG.md | 2 + README.md | 20 ++++++++++ .../images/{tree_2.png => pixel_tree.png} | Bin bevy_asset_loader/examples/README.md | 37 ++++++++++-------- bevy_asset_loader/examples/full_collection.rs | 24 ++++++++++-- bevy_asset_loader/examples/image_asset.rs | 4 +- bevy_asset_loader_derive/src/assets.rs | 19 ++++----- 7 files changed, 71 insertions(+), 35 deletions(-) rename bevy_asset_loader/assets/images/{tree_2.png => pixel_tree.png} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1069c81..a3206e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog - Make `loading_state::LoadingStateSet` public for explicit system ordering +- Support configuring an image sampler through a derive attribute ([#156](https://github.com/NiklasEi/bevy_asset_loader/pull/156)) + - See [the new example](bevy_asset_loader/examples/image_asset.rs) ## v0.17.0 - update to Bevy 0.11 diff --git a/README.md b/README.md index 1ee45d5..abf386f 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,26 @@ struct MyAssets { } ``` +### Images + +Asset collections support one of the most common operations for image asset: changing their sampler. You can configure either a linear or a nearest sampler like so: + +```rust +use bevy::prelude::*; +use bevy_asset_loader::asset_collection::AssetCollection; + +#[derive(AssetCollection, Resource)] +struct ImageAssets { + #[asset(path = "images/pixel_tree.png")] + #[asset(image(sampler = linear))] + tree_linear: Handle, + + #[asset(path = "images/pixel_tree.png")] + #[asset(image(sampler = nearest))] + tree_nearest: Handle, +} +``` + ### Standard materials You can directly load standard materials if you enable the feature `3d`. For a complete example please take a look at [standard_material.rs](bevy_asset_loader/examples/standard_material.rs). diff --git a/bevy_asset_loader/assets/images/tree_2.png b/bevy_asset_loader/assets/images/pixel_tree.png similarity index 100% rename from bevy_asset_loader/assets/images/tree_2.png rename to bevy_asset_loader/assets/images/pixel_tree.png diff --git a/bevy_asset_loader/examples/README.md b/bevy_asset_loader/examples/README.md index 7ac2836..75b0598 100644 --- a/bevy_asset_loader/examples/README.md +++ b/bevy_asset_loader/examples/README.md @@ -3,23 +3,23 @@ These examples are simple Bevy Apps illustrating the capabilities of `bevy_asset_loader`. Run the examples with `cargo run --example `. -| Example | Description | -|------------------------------------------------------------|--------------------------------------------------------------------------| -| Example | Description | -|------------------------------------------------------------|--------------------------------------------------------------------------| -| [`atlas_from_grid.rs`](atlas_from_grid.rs) | Loading a texture atlas from a sprite sheet | -| [`custom_dynamic_assets.rs`](custom_dynamic_assets.rs) | Define and use your own dynamic assets | -| [`dynamic_asset.rs`](dynamic_asset.rs) | Load dynamic assets from a `.ron` file | -| [`failure_state.rs`](failure_state.rs) | Sets up a failure state | -| [`full_collection.rs`](full_collection.rs) | A complete asset collection with all supported non-dynamic field types | -| [`full_dynamic_collection.rs`](full_dynamic_collection.rs) | A complete asset collection with all supported dynamic asset field types | -| [`init_resource.rs`](init_resource.rs) | Inserting a `FromWorld` resource when all asset collections are loaded | -| [`manual_dynamic_asset.rs`](manual_dynamic_asset.rs) | Load an image asset from a path resolved at run time | -| [`no_loading_state.rs`](no_loading_state.rs) | How to use asset collections without a loading state | -| [`progress_tracking.rs`](progress_tracking.rs) | How to set up progress tracking using `iyes_progress` | -| [`standard_material.rs`](standard_material.rs) | Loading a standard material from a png file | -| [`two_collections.rs`](two_collections.rs) | Load multiple asset collections | -| [`image_asset.rs`](image_asset.rs) | How to set a different sampler for an image asset | +| Example | Description | +|--------------------------------------------------------------|----------------------------------------------------------------------------| +| Example | Description | +| ------------------------------------------------------------ | -------------------------------------------------------------------------- | +| [`atlas_from_grid.rs`](atlas_from_grid.rs) | Loading a texture atlas from a sprite sheet | +| [`custom_dynamic_assets.rs`](custom_dynamic_assets.rs) | Define and use your own dynamic assets | +| [`dynamic_asset.rs`](dynamic_asset.rs) | Load dynamic assets from a `.ron` file | +| [`failure_state.rs`](failure_state.rs) | Sets up a failure state | +| [`full_collection.rs`](full_collection.rs) | A complete asset collection with all supported non-dynamic field types | +| [`full_dynamic_collection.rs`](full_dynamic_collection.rs) | A complete asset collection with all supported dynamic asset field types | +| [`init_resource.rs`](init_resource.rs) | Inserting a `FromWorld` resource when all asset collections are loaded | +| [`manual_dynamic_asset.rs`](manual_dynamic_asset.rs) | Load an image asset from a path resolved at run time | +| [`no_loading_state.rs`](no_loading_state.rs) | How to use asset collections without a loading state | +| [`progress_tracking.rs`](progress_tracking.rs) | How to set up progress tracking using `iyes_progress` | +| [`standard_material.rs`](standard_material.rs) | Loading a standard material from a png file | +| [`two_collections.rs`](two_collections.rs) | Load multiple asset collections | +| [`image_asset.rs`](image_asset.rs) | How to set different samplers for image assets | ## Credits @@ -30,3 +30,6 @@ by [Jay_You](https://freesound.org/people/Jay_You/sounds/460432/) Toon character sheets [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/) by [Kenny](https://kenney.nl/assets/toon-characters-1) + +Pixelart tree [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/) +by [Kenny](https://www.kenney.nl/assets/tiny-town) diff --git a/bevy_asset_loader/examples/full_collection.rs b/bevy_asset_loader/examples/full_collection.rs index 0ab372e..4ec569b 100644 --- a/bevy_asset_loader/examples/full_collection.rs +++ b/bevy_asset_loader/examples/full_collection.rs @@ -1,6 +1,7 @@ use bevy::app::AppExit; use bevy::asset::LoadState; use bevy::prelude::*; +use bevy::render::texture::ImageSampler; use bevy::utils::HashMap; use bevy_asset_loader::prelude::*; use path_slash::PathExt; @@ -34,6 +35,11 @@ struct MyAssets { // If no derive attributes are set, `from_world` will be used to set the value. from_world: ColorStandardMaterial<{ u8::MAX }, 0, 0, { u8::MAX }>, + // Image asset with sampler nearest (good for crisp pixel art) + #[asset(path = "images/pixel_tree.png")] + #[asset(image(sampler = nearest))] + image_tree_nearest: Handle, + // Load collections of assets // A folder (not supported on the web) @@ -70,6 +76,7 @@ fn expectations( asset_server: Res, standard_materials: Res>, texture_atlases: Res>, + images: Res>, mut quit: EventWriter, ) { info!("Done loading the collection. Checking expectations..."); @@ -101,21 +108,30 @@ fn expectations( .get(&assets.from_world.handle) .expect("Standard material should be added to its assets resource."); assert_eq!(material.base_color, Color::RED); - assert_eq!(assets.folder_untyped.len(), 6); + + let image = images + .get(&assets.image_tree_nearest) + .expect("Image should be added to its asset resource"); + let ImageSampler::Descriptor(descriptor) = &image.sampler_descriptor else { + panic!("Descriptor was not set to non default value nearest"); + }; + assert_eq!(descriptor, &ImageSampler::nearest_descriptor()); + + assert_eq!(assets.folder_untyped.len(), 7); for handle in assets.folder_untyped.iter() { assert_eq!( asset_server.get_load_state(handle.clone()), LoadState::Loaded ); } - assert_eq!(assets.folder_typed.len(), 6); + assert_eq!(assets.folder_typed.len(), 7); for handle in assets.folder_typed.iter() { assert_eq!( asset_server.get_load_state(handle.clone()), LoadState::Loaded ); } - assert_eq!(assets.mapped_folder_untyped.len(), 6); + assert_eq!(assets.mapped_folder_untyped.len(), 7); for (name, handle) in assets.mapped_folder_untyped.iter() { assert_eq!( asset_server.get_load_state(handle.clone()), @@ -132,7 +148,7 @@ fn expectations( name ); } - assert_eq!(assets.mapped_folder_typed.len(), 6); + assert_eq!(assets.mapped_folder_typed.len(), 7); for (name, handle) in assets.mapped_folder_typed.iter() { assert_eq!( asset_server.get_load_state(handle.clone()), diff --git a/bevy_asset_loader/examples/image_asset.rs b/bevy_asset_loader/examples/image_asset.rs index 7dcb620..98d39a5 100644 --- a/bevy_asset_loader/examples/image_asset.rs +++ b/bevy_asset_loader/examples/image_asset.rs @@ -17,11 +17,11 @@ fn main() { #[derive(AssetCollection, Resource)] struct ImageAssets { - #[asset(path = "images/tree_2.png")] + #[asset(path = "images/pixel_tree.png")] #[asset(image(sampler = linear))] tree_linear: Handle, - #[asset(path = "images/tree_2.png")] + #[asset(path = "images/pixel_tree.png")] #[asset(image(sampler = nearest))] tree_nearest: Handle, } diff --git a/bevy_asset_loader_derive/src/assets.rs b/bevy_asset_loader_derive/src/assets.rs index 6d90b62..0975045 100644 --- a/bevy_asset_loader_derive/src/assets.rs +++ b/bevy_asset_loader_derive/src/assets.rs @@ -122,20 +122,15 @@ impl AssetField { AssetField::Image(image) => { let field_ident = image.field_ident.clone(); let asset_path = image.asset_path.clone(); - let sampler = match image.sampler { - SamplerType::Linear => "ImageSampler::linear()", - SamplerType::Nearest => "ImageSampler::nearest()", + SamplerType::Linear => quote!(ImageSampler::linear()), + SamplerType::Nearest => quote!(ImageSampler::nearest()), }; - let descriptor = match image.sampler { - SamplerType::Linear => "ImageSampler::linear_descriptor()", - SamplerType::Nearest => "ImageSampler::nearest_descriptor()", + SamplerType::Linear => quote!(ImageSampler::linear_descriptor()), + SamplerType::Nearest => quote!(ImageSampler::nearest_descriptor()), }; - let sampler_token_stream = sampler.parse::().unwrap(); - let descriptor_token_stream = descriptor.parse::().unwrap(); - quote!(#token_stream #field_ident : { use bevy::render::texture::ImageSampler; let cell = world.cell(); @@ -146,17 +141,17 @@ impl AssetField { let mut image = images.get_mut(&handle).expect("Only asset collection fields holding an `Image` handle can be annotated with `image`"); let is_different_sampler = if let ImageSampler::Descriptor(descriptor) = &image.sampler_descriptor { - !descriptor.eq(&#descriptor_token_stream) + !descriptor.eq(&#descriptor) } else { false }; if is_different_sampler { let mut cloned_image = image.clone(); - cloned_image.sampler_descriptor = #sampler_token_stream; + cloned_image.sampler_descriptor = #sampler; handle = images.add(cloned_image); } else { - image.sampler_descriptor = #sampler_token_stream; + image.sampler_descriptor = #sampler; } handle