use bevy_asset::{Asset, AssetId, Assets, Handle};
use bevy_image::Image;
use bevy_math::{URect, UVec2};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
#[cfg(feature = "serialize")]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
use bevy_utils::HashMap;
#[derive(Debug)]
pub struct TextureAtlasSources {
pub texture_ids: HashMap<AssetId<Image>, usize>,
}
impl TextureAtlasSources {
pub fn texture_index(&self, texture: impl Into<AssetId<Image>>) -> Option<usize> {
let id = texture.into();
self.texture_ids.get(&id).cloned()
}
pub fn handle(
&self,
layout: Handle<TextureAtlasLayout>,
texture: impl Into<AssetId<Image>>,
) -> Option<TextureAtlas> {
Some(TextureAtlas {
layout,
index: self.texture_index(texture)?,
})
}
pub fn texture_rect(
&self,
layout: &TextureAtlasLayout,
texture: impl Into<AssetId<Image>>,
) -> Option<URect> {
layout.textures.get(self.texture_index(texture)?).cloned()
}
}
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Asset, Reflect, PartialEq, Eq, Debug, Clone)]
#[reflect(Debug, PartialEq)]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
pub struct TextureAtlasLayout {
pub size: UVec2,
pub textures: Vec<URect>,
}
impl TextureAtlasLayout {
pub fn new_empty(dimensions: UVec2) -> Self {
Self {
size: dimensions,
textures: Vec::new(),
}
}
pub fn from_grid(
tile_size: UVec2,
columns: u32,
rows: u32,
padding: Option<UVec2>,
offset: Option<UVec2>,
) -> Self {
let padding = padding.unwrap_or_default();
let offset = offset.unwrap_or_default();
let mut sprites = Vec::new();
let mut current_padding = UVec2::ZERO;
for y in 0..rows {
if y > 0 {
current_padding.y = padding.y;
}
for x in 0..columns {
if x > 0 {
current_padding.x = padding.x;
}
let cell = UVec2::new(x, y);
let rect_min = (tile_size + current_padding) * cell + offset;
sprites.push(URect {
min: rect_min,
max: rect_min + tile_size,
});
}
}
let grid_size = UVec2::new(columns, rows);
Self {
size: ((tile_size + current_padding) * grid_size) - current_padding,
textures: sprites,
}
}
pub fn add_texture(&mut self, rect: URect) -> usize {
self.textures.push(rect);
self.textures.len() - 1
}
pub fn len(&self) -> usize {
self.textures.len()
}
pub fn is_empty(&self) -> bool {
self.textures.is_empty()
}
}
#[derive(Default, Debug, Clone, Reflect)]
#[reflect(Default, Debug)]
pub struct TextureAtlas {
pub layout: Handle<TextureAtlasLayout>,
pub index: usize,
}
impl TextureAtlas {
pub fn texture_rect(&self, texture_atlases: &Assets<TextureAtlasLayout>) -> Option<URect> {
let atlas = texture_atlases.get(&self.layout)?;
atlas.textures.get(self.index).copied()
}
}
impl From<Handle<TextureAtlasLayout>> for TextureAtlas {
fn from(texture_atlas: Handle<TextureAtlasLayout>) -> Self {
Self {
layout: texture_atlas,
index: 0,
}
}
}