Skip to content

Commit

Permalink
Update creation of texture atlas layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
NiklasEi committed Feb 12, 2024
1 parent 29972f3 commit fc3f953
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 116 deletions.
4 changes: 1 addition & 3 deletions bevy_asset_loader/assets/full_dynamic_collection.assets.ron
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
"standard_material": StandardMaterial (
path: "images/tree.png",
),
"texture_atlas": TextureAtlas (
path: "images/female_adventurer_sheet.png",
sampler: Nearest,
"texture_atlas_layout": TextureAtlasLayout (
tile_size_x: 96.,
tile_size_y: 99.,
columns: 8,
Expand Down
3 changes: 2 additions & 1 deletion bevy_asset_loader/examples/atlas_from_grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn main() {
struct MyAssets {
// if the sheet would have padding, you could set that with `padding_x` and `padding_y`.
// if there would be space between the top left corner of the sheet and the first sprite, you could configure that with `offset_x` and `offset_y`
// A texture atlas layout does not have a path as no asset file will be loaded for the layout
#[asset(texture_atlas(tile_size_x = 96., tile_size_y = 99., columns = 8, rows = 1))]
female_adventurer_atlas: Handle<TextureAtlasLayout>,
// you can configure the sampler for the sprite sheet image
Expand Down Expand Up @@ -71,7 +72,7 @@ fn animate_sprite_system(
for (mut timer, mut sprite) in &mut sprites_to_animate {
timer.0.tick(time.delta());
if timer.0.finished() {
sprite.index = (sprite.index % 8) + 1;
sprite.index = (sprite.index + 1) % 8;
}
}
}
Expand Down
26 changes: 5 additions & 21 deletions bevy_asset_loader/examples/full_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ struct MyAssets {
standard_material: Handle<StandardMaterial>,
// Any image file that can be loaded and turned into a texture atlas
#[asset(texture_atlas(tile_size_x = 96., tile_size_y = 99., columns = 8, rows = 1))]
#[asset(image(sampler = nearest))]
#[asset(path = "images/female_adventurer_sheet.png")]
texture_atlas: Handle<TextureAtlas>,
texture_atlas_layout: Handle<TextureAtlasLayout>,
// Example field with type that implements `FromWorld`
// If no derive attributes are set, `from_world` will be used to set the value.
from_world: ColorStandardMaterial<{ u8::MAX }, 0, 0, { u8::MAX }>,
Expand Down Expand Up @@ -75,7 +73,7 @@ fn expectations(
assets: Res<MyAssets>,
asset_server: Res<AssetServer>,
standard_materials: Res<Assets<StandardMaterial>>,
texture_atlases: Res<Assets<TextureAtlasLayout>>,
texture_atlas_layouts: Res<Assets<TextureAtlasLayout>>,
images: Res<Assets<Image>>,
mut quit: EventWriter<AppExit>,
) {
Expand All @@ -97,23 +95,9 @@ fn expectations(
),
Some(RecursiveDependencyLoadState::Loaded)
);
let atlas = texture_atlases
.get(&assets.texture_atlas)
.expect("Texture atlas should be added to its assets resource.");
assert_eq!(
asset_server.get_recursive_dependency_load_state(atlas.texture.clone()),
Some(RecursiveDependencyLoadState::Loaded)
);
let image = images
.get(&atlas.texture)
.expect("Image for TextureAtlas should be added to its asset resource");
let ImageSampler::Descriptor(descriptor) = &image.sampler else {
panic!("Descriptor was not set to non default value nearest");
};
assert_eq!(
descriptor.as_wgpu(),
ImageSamplerDescriptor::nearest().as_wgpu()
);
texture_atlas_layouts
.get(&assets.texture_atlas_layout)
.expect("Texture atlas layout should be added to its assets resource.");

let material = standard_materials
.get(&assets.from_world.handle)
Expand Down
31 changes: 8 additions & 23 deletions bevy_asset_loader/examples/full_dynamic_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ struct MyAssets {
// Type in `assets/full_dynamic_collection.assets.ron`: `StandardMaterial`
#[asset(key = "standard_material")]
standard_material: Handle<StandardMaterial>,
// This image file will be converted to a texture atlas
// The configuration for that is part of the `.assets` file
// Type in `assets/full_dynamic_collection.assets.ron`: `TextureAtlas`
#[asset(key = "texture_atlas")]
texture_atlas: Handle<TextureAtlas>,
// Configuration of a texture atlas layout that is part of the `.assets` file
// Type in `assets/full_dynamic_collection.assets.ron`: `TextureAtlasLayout`
#[asset(key = "texture_atlas_layout")]
texture_atlas_layout: Handle<TextureAtlasLayout>,
// Optional asset
// The key `optional_file` is not defined in `assets/full_dynamic_collection.assets.ron`, so the value of this field
// will be `None`
Expand Down Expand Up @@ -109,7 +108,7 @@ fn expectations(
assets: Res<MyAssets>,
asset_server: Res<AssetServer>,
standard_materials: Res<Assets<StandardMaterial>>,
texture_atlases: Res<Assets<TextureAtlasLayout>>,
texture_atlas_layouts: Res<Assets<TextureAtlasLayout>>,
images: Res<Assets<Image>>,
mut quit: EventWriter<AppExit>,
) {
Expand All @@ -131,23 +130,9 @@ fn expectations(
),
Some(RecursiveDependencyLoadState::Loaded)
);
let atlas = texture_atlases
.get(&assets.texture_atlas)
.expect("Texture atlas should be added to its assets resource.");
assert_eq!(
asset_server.get_recursive_dependency_load_state(atlas.texture.clone()),
Some(RecursiveDependencyLoadState::Loaded)
);
let image = images
.get(&atlas.texture)
.expect("Image for TextureAtlas should be added to its asset resource");
let ImageSampler::Descriptor(descriptor) = &image.sampler else {
panic!("Descriptor was not set to non default value nearest");
};
assert_eq!(
descriptor.as_wgpu(),
ImageSamplerDescriptor::nearest().as_wgpu()
);
texture_atlas_layouts
.get(&assets.texture_atlas_layout)
.expect("Texture atlas layout should be added to its assets resource.");

assert_eq!(assets.optional_file, None);
let image = images
Expand Down
10 changes: 6 additions & 4 deletions bevy_asset_loader/src/standard_dynamic_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub enum StandardDynamicAsset {
},
/// A dynamic texture atlas asset loaded from a sprite sheet
#[cfg(feature = "2d")]
TextureAtlas {
TextureAtlasLayout {
/// The image width in pixels
tile_size_x: f32,
/// The image height in pixels
Expand Down Expand Up @@ -155,7 +155,7 @@ impl DynamicAsset for StandardDynamicAsset {
vec![asset_server.load::<Image>(path).untyped()]
}
#[cfg(feature = "2d")]
StandardDynamicAsset::TextureAtlas { .. } => {
StandardDynamicAsset::TextureAtlasLayout { .. } => {
vec![]
}
}
Expand Down Expand Up @@ -188,13 +188,15 @@ impl DynamicAsset for StandardDynamicAsset {
.get_resource_mut::<Assets<StandardMaterial>>()
.expect("Cannot get resource Assets<StandardMaterial>");
let handle = materials
.add(asset_server.get_handle::<Image>(path).unwrap().into())
.add(StandardMaterial::from(
asset_server.get_handle::<Image>(path).unwrap(),
))
.untyped();

Ok(DynamicAssetType::Single(handle))
}
#[cfg(feature = "2d")]
StandardDynamicAsset::TextureAtlas {
StandardDynamicAsset::TextureAtlasLayout {
tile_size_x,
tile_size_y,
columns,
Expand Down
89 changes: 25 additions & 64 deletions bevy_asset_loader_derive/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ use proc_macro2::{Ident, TokenStream};
use quote::quote;

#[derive(PartialEq, Debug)]
pub(crate) struct TextureAtlasAssetField {
pub(crate) struct TextureAtlasLayoutAssetField {
pub field_ident: Ident,
pub asset_path: String,
pub sampler: Option<SamplerType>,
pub tile_size_x: f32,
pub tile_size_y: f32,
pub columns: usize,
Expand Down Expand Up @@ -67,7 +65,7 @@ pub(crate) enum AssetField {
Basic(BasicAssetField),
Folder(BasicAssetField, Typed, Mapped),
Files(MultipleFilesField, Typed, Mapped),
TextureAtlas(TextureAtlasAssetField),
TextureAtlasLayout(TextureAtlasLayoutAssetField),
Image(ImageAssetField),
StandardMaterial(BasicAssetField),
Dynamic(DynamicAssetField),
Expand Down Expand Up @@ -232,14 +230,13 @@ impl AssetField {
let cell = world.cell();
let asset_server = cell.get_resource::<::bevy::asset::AssetServer>().expect("Cannot get AssetServer");
let mut materials = cell
.get_resource_mut::<::bevy::asset::Assets<StandardMaterial>>()
.get_resource_mut::<::bevy::asset::Assets<::bevy::pbr::StandardMaterial>>()
.expect("Cannot get resource Assets<StandardMaterial>");
materials.add(asset_server.load::<::bevy::render::texture::Image>(#asset_path).into())
materials.add(::bevy::pbr::StandardMaterial::from(asset_server.load::<::bevy::render::texture::Image>(#asset_path)))
},)
}
AssetField::TextureAtlas(texture_atlas) => {
AssetField::TextureAtlasLayout(texture_atlas) => {
let field_ident = texture_atlas.field_ident.clone();
let asset_path = texture_atlas.asset_path.clone();
let tile_size_x = texture_atlas.tile_size_x;
let tile_size_y = texture_atlas.tile_size_y;
let columns = texture_atlas.columns;
Expand All @@ -248,48 +245,13 @@ impl AssetField {
let padding_y = texture_atlas.padding_y;
let offset_x = texture_atlas.offset_x;
let offset_y = texture_atlas.offset_y;
let sampler_handling = texture_atlas.sampler.map(|sampler_type| {
let sampler = match sampler_type {
SamplerType::Linear => quote!(::bevy::render::texture::ImageSampler::linear()),
SamplerType::Nearest => quote!(::bevy::render::texture::ImageSampler::nearest()),
};
let descriptor = match sampler_type {
SamplerType::Linear => quote!(::bevy::render::texture::ImageSamplerDescriptor::linear()),
SamplerType::Nearest => quote!(::bevy::render::texture::ImageSamplerDescriptor::nearest()),
};

quote!(
let mut images = cell.get_resource_mut::<Assets<Image>>().expect("Cannot get resource Assets<Image>");
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 ::bevy::render::texture::ImageSampler::Descriptor(descriptor) = &image.sampler {
!descriptor.as_wgpu().eq(&#descriptor.as_wgpu())
} else {
false
};

if is_different_sampler {
let mut cloned_image = image.clone();
cloned_image.sampler = #sampler;
handle = images.add(cloned_image);
} else {
image.sampler = #sampler;
}
)
}).unwrap_or(quote!());
quote!(#token_stream #field_ident : {
let cell = world.cell();
let asset_server = cell
.get_resource::<::bevy::asset::AssetServer>()
.expect("Cannot get AssetServer");
let mut atlases = cell
.get_resource_mut::<::bevy::asset::Assets<TextureAtlasLayout>>()
.expect("Cannot get resource Assets<TextureAtlasLayout>");
let mut handle = asset_server.load(#asset_path);

#sampler_handling

atlases.add(TextureAtlas::from_grid(
handle,
atlases.add(TextureAtlasLayout::from_grid(
Vec2::new(#tile_size_x, #tile_size_y),
#columns,
#rows,
Expand Down Expand Up @@ -502,8 +464,10 @@ impl AssetField {
}
)
}
AssetField::TextureAtlasLayout(TextureAtlasLayoutAssetField { .. }) => {
quote!()
}
AssetField::StandardMaterial(BasicAssetField { asset_path, .. })
| AssetField::TextureAtlas(TextureAtlasAssetField { asset_path, .. })
| AssetField::Image(ImageAssetField { asset_path, .. }) => {
let asset_path = asset_path.clone();
quote!(#token_stream handles.push(asset_server.load::<::bevy::render::texture::Image>(#asset_path).untyped());)
Expand Down Expand Up @@ -569,6 +533,21 @@ impl AssetBuilder {
TextureAtlasAttribute::ROWS
));
}
if missing_fields.is_empty() {
return Ok(AssetField::TextureAtlasLayout(
TextureAtlasLayoutAssetField {
field_ident: self.field_ident.unwrap(),
tile_size_x: self.tile_size_x.unwrap(),
tile_size_y: self.tile_size_y.unwrap(),
columns: self.columns.unwrap(),
rows: self.rows.unwrap(),
padding_x: self.padding_x.unwrap_or_default(),
padding_y: self.padding_y.unwrap_or_default(),
offset_x: self.offset_x.unwrap_or_default(),
offset_y: self.offset_y.unwrap_or_default(),
},
));
}
if self.asset_path.is_none() && self.asset_paths.is_none() && self.key.is_none() {
return Err(vec![ParseFieldError::NoAttributes]);
}
Expand Down Expand Up @@ -660,21 +639,6 @@ impl AssetBuilder {
}
return Ok(AssetField::Basic(asset));
}
if missing_fields.is_empty() {
return Ok(AssetField::TextureAtlas(TextureAtlasAssetField {
field_ident: self.field_ident.unwrap(),
asset_path: self.asset_path.unwrap(),
sampler: self.sampler,
tile_size_x: self.tile_size_x.unwrap(),
tile_size_y: self.tile_size_y.unwrap(),
columns: self.columns.unwrap(),
rows: self.rows.unwrap(),
padding_x: self.padding_x.unwrap_or_default(),
padding_y: self.padding_y.unwrap_or_default(),
offset_x: self.offset_x.unwrap_or_default(),
offset_y: self.offset_y.unwrap_or_default(),
}));
}
Err(vec![ParseFieldError::MissingAttributes(missing_fields)])
}
}
Expand Down Expand Up @@ -890,7 +854,6 @@ mod test {
fn texture_atlas() {
let builder = AssetBuilder {
field_ident: Some(Ident::new("test", Span::call_site())),
asset_path: Some("some/folder".to_owned()),
tile_size_x: Some(100.),
tile_size_y: Some(50.),
columns: Some(10),
Expand All @@ -905,10 +868,8 @@ mod test {
.expect("This should be a valid TextureAtlasAsset");
assert_eq!(
asset,
AssetField::TextureAtlas(TextureAtlasAssetField {
AssetField::TextureAtlasLayout(TextureAtlasLayoutAssetField {
field_ident: Ident::new("test", Span::call_site()),
asset_path: "some/folder".to_owned(),
sampler: None,
tile_size_x: 100.0,
tile_size_y: 50.0,
columns: 10,
Expand Down

0 comments on commit fc3f953

Please sign in to comment.