-
Notifications
You must be signed in to change notification settings - Fork 3
/
lib.rs
128 lines (113 loc) · 4.03 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use bevy::asset::{AssetLoader, AssetPath, BoxedFuture, LoadContext, LoadedAsset};
use bevy::math::vec2;
use bevy::prelude::*;
use bevy::sprite::TextureAtlas;
use bevy::utils::HashMap;
use lazy_static::*;
use serde::Deserialize;
use std::path::Path;
use std::sync::Mutex;
lazy_static! {
static ref UNSIZED_ATLAS_LIST: Mutex<Vec<Handle<TextureAtlas>>> = Mutex::new(vec![]);
}
#[derive(Debug, Deserialize)]
struct Sprite {
#[serde(default)]
name: String,
x: u32,
y: u32,
w: u32,
h: u32,
}
#[derive(Debug, Deserialize)]
struct Manifest {
path: String,
sprites: Vec<crate::Sprite>,
}
impl From<Sprite> for (String, bevy::math::Rect) {
fn from(sprite_rect: Sprite) -> Self {
let Sprite { name, x, y, w, h } = sprite_rect;
(
name,
bevy::math::Rect {
min: vec2(x as f32, y as f32),
max: vec2((x + w - 1) as f32, (y + h - 1) as f32),
},
)
}
}
#[derive(Default)]
struct TextureAtlasLoader;
impl AssetLoader for TextureAtlasLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), anyhow::Error>> {
Box::pin(async move {
// load manifest data
let manifest: Manifest = ron::de::from_bytes(bytes)?;
// get the image handle
let image_asset_path = AssetPath::new_ref(Path::new(&manifest.path), None);
let image_handle: Handle<Image> = load_context.get_handle(image_asset_path.clone());
// create the texture atlas
// image not loaded yet, set the atlas size to one pixel temporarily.
let mut texture_atlas = TextureAtlas::new_empty(image_handle, Vec2::splat(1.));
for (name, sprite_rect) in manifest.sprites.into_iter().map(|sprite| sprite.into()) {
let index = texture_atlas.add_texture(sprite_rect);
if !name.is_empty() {
let handles = texture_atlas
.texture_handles
.get_or_insert(HashMap::default());
if let Some(_rect) = handles.insert(Handle::weak(name.clone().into()), index) {
warn!(
"Sprite name {name} in manifest for texture atlas {} not unique",
manifest.path
);
}
}
}
let asset_path = AssetPath::new(load_context.path().into(), None);
let texture_atlas_handle: Handle<TextureAtlas> = load_context.get_handle(asset_path);
// create and return the asset
let atlas_asset = LoadedAsset::new(texture_atlas).with_dependency(image_asset_path);
UNSIZED_ATLAS_LIST
.lock()
.unwrap()
.push(texture_atlas_handle.clone_weak());
load_context.set_default_asset(atlas_asset);
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["ron"]
}
}
fn set_texture_atlas_size(
images: Res<Assets<Image>>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
) {
let mut loading = UNSIZED_ATLAS_LIST.lock().unwrap();
loading.retain(|texture_atlas_handle| {
if let Some(texture_atlas) = texture_atlases.get_mut(texture_atlas_handle) {
if let Some(texture) = images.get(&texture_atlas.texture) {
texture_atlas.size = texture.size();
// texture atlas size set, remove it from the list
false
} else {
// no texture yet for this atlas, check again next frame
true
}
} else {
// texture atlas assets doesn't have an atlas for this handle, so forget it.
false
}
});
}
pub struct TextureAtlasLoaderPlugin;
impl Plugin for TextureAtlasLoaderPlugin {
fn build(&self, app: &mut App) {
app.init_asset_loader::<TextureAtlasLoader>()
.add_system(set_texture_atlas_size);
}
}