Skip to content
Snippets Groups Projects
loader.rs 2.42 KiB
Newer Older
Louis's avatar
Louis committed
use std::marker::PhantomData;

use bevy::asset::LoadState;
use bevy::ecs::system::SystemParam;
use bevy::prelude::*;
use bevy::reflect::TypeUuid;
Louis's avatar
Louis committed
use micro_musicbox::prelude::AudioSource;
Louis's avatar
Louis committed

use crate::assets::{AssetHandles, FixedAssetNameMapping, SpriteSheetConfig};

#[derive(SystemParam)]
pub struct AssetTypeLoader<'w, 's> {
	pub handles: ResMut<'w, AssetHandles>,
	pub asset_server: Res<'w, AssetServer>,
	pub atlas: ResMut<'w, Assets<TextureAtlas>>,
	#[system_param(ignore)]
	marker: PhantomData<&'s usize>,
}

macro_rules! load_basic_type {
	($name: tt, $type: ty => $key: ident) => {
		pub fn $name(&mut self, assets: &[FixedAssetNameMapping]) -> Vec<Handle<$type>> {
			self.load_list(assets, |loader, path, key| {
				let handle: Handle<$type> = loader.asset_server.load(&path);
				loader.handles.$key.insert(key, handle.clone());
				handle
			})
		}
	};
}

macro_rules! load_state {
	($container: expr => $key: ident) => {
		$container
			.asset_server
			.get_group_load_state($container.handles.$key.values().map(|f| f.id))
	};
}

impl<'w, 's> AssetTypeLoader<'w, 's> {
	fn load_list<
		T: Sync + Send + TypeUuid + 'static,
		Loader: Fn(&mut AssetTypeLoader, String, String) -> Handle<T>,
	>(
		&mut self,
		files: &[FixedAssetNameMapping],
		load: Loader,
	) -> Vec<Handle<T>> {
		files
			.iter()
			.map(|(path, key)| load(self, path.to_string(), key.to_string()))
			.collect()
	}

	load_basic_type!(load_images, Image => images);
	load_basic_type!(load_audio, AudioSource => sounds);
	load_basic_type!(load_font, Font => fonts);

	pub fn load_spritesheet(
		&mut self,
		config: &SpriteSheetConfig,
		assets: &[FixedAssetNameMapping],
	) -> Vec<Handle<Image>> {
		self.load_list(assets, |loader, path, key| {
			let handle: Handle<Image> = loader.asset_server.load(&path);

			loader
				.handles
				.images
				.insert(key.to_string(), handle.clone());

			let atlas = TextureAtlas::from_grid(
				handle.clone(),
				Vec2::new(config.tile_width as f32, config.tile_height as f32),
				config.columns,
				config.rows,
			);

			let atlas_handle = loader.atlas.add(atlas);
			loader.handles.atlas.insert(key, atlas_handle);

			handle
		})
	}

	pub fn get_all_load_state(&self) -> Vec<LoadState> {
		let image_state = self
			.asset_server
			.get_group_load_state(self.handles.images.values().map(|f| f.id));
		let atlas_state = self
			.asset_server
			.get_group_load_state(self.handles.images.values().map(|f| f.id));

		vec![image_state, atlas_state]
	}
}