Skip to content

Commit

Permalink
Merge pull request #159 from NiklasEi/add_image_sampler_to_readme_and…
Browse files Browse the repository at this point in the history
…_example

Add image sampler to readme and example
  • Loading branch information
NiklasEi authored Nov 1, 2023
2 parents b4bb174 + b2baf59 commit 3ebdd8b
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 35 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Image>,

#[asset(path = "images/pixel_tree.png")]
#[asset(image(sampler = nearest))]
tree_nearest: Handle<Image>,
}
```

### 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).
Expand Down
File renamed without changes
37 changes: 20 additions & 17 deletions bevy_asset_loader/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>`.

| 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

Expand All @@ -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)
24 changes: 20 additions & 4 deletions bevy_asset_loader/examples/full_collection.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<Image>,

// Load collections of assets

// A folder (not supported on the web)
Expand Down Expand Up @@ -70,6 +76,7 @@ fn expectations(
asset_server: Res<AssetServer>,
standard_materials: Res<Assets<StandardMaterial>>,
texture_atlases: Res<Assets<TextureAtlas>>,
images: Res<Assets<Image>>,
mut quit: EventWriter<AppExit>,
) {
info!("Done loading the collection. Checking expectations...");
Expand Down Expand Up @@ -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()),
Expand All @@ -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()),
Expand Down
4 changes: 2 additions & 2 deletions bevy_asset_loader/examples/image_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Image>,

#[asset(path = "images/tree_2.png")]
#[asset(path = "images/pixel_tree.png")]
#[asset(image(sampler = nearest))]
tree_nearest: Handle<Image>,
}
Expand Down
19 changes: 7 additions & 12 deletions bevy_asset_loader_derive/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<TokenStream>().unwrap();
let descriptor_token_stream = descriptor.parse::<TokenStream>().unwrap();

quote!(#token_stream #field_ident : {
use bevy::render::texture::ImageSampler;
let cell = world.cell();
Expand All @@ -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
Expand Down

0 comments on commit 3ebdd8b

Please sign in to comment.