Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_image/src/compressed_image_saver.rs
6595 views
1
use crate::{Image, ImageFormat, ImageFormatSetting, ImageLoader, ImageLoaderSettings};
2
3
use bevy_asset::saver::{AssetSaver, SavedAsset};
4
use futures_lite::AsyncWriteExt;
5
use thiserror::Error;
6
7
pub struct CompressedImageSaver;
8
9
#[non_exhaustive]
10
#[derive(Debug, Error)]
11
pub enum CompressedImageSaverError {
12
#[error(transparent)]
13
Io(#[from] std::io::Error),
14
#[error("Cannot compress an uninitialized image")]
15
UninitializedImage,
16
}
17
18
impl AssetSaver for CompressedImageSaver {
19
type Asset = Image;
20
21
type Settings = ();
22
type OutputLoader = ImageLoader;
23
type Error = CompressedImageSaverError;
24
25
async fn save(
26
&self,
27
writer: &mut bevy_asset::io::Writer,
28
image: SavedAsset<'_, Self::Asset>,
29
_settings: &Self::Settings,
30
) -> Result<ImageLoaderSettings, Self::Error> {
31
let is_srgb = image.texture_descriptor.format.is_srgb();
32
33
let compressed_basis_data = {
34
let mut compressor_params = basis_universal::CompressorParams::new();
35
compressor_params.set_basis_format(basis_universal::BasisTextureFormat::UASTC4x4);
36
compressor_params.set_generate_mipmaps(true);
37
let color_space = if is_srgb {
38
basis_universal::ColorSpace::Srgb
39
} else {
40
basis_universal::ColorSpace::Linear
41
};
42
compressor_params.set_color_space(color_space);
43
compressor_params.set_uastc_quality_level(basis_universal::UASTC_QUALITY_DEFAULT);
44
45
let mut source_image = compressor_params.source_image_mut(0);
46
let size = image.size();
47
let Some(ref data) = image.data else {
48
return Err(CompressedImageSaverError::UninitializedImage);
49
};
50
source_image.init(data, size.x, size.y, 4);
51
52
let mut compressor = basis_universal::Compressor::new(4);
53
#[expect(
54
unsafe_code,
55
reason = "The basis-universal compressor cannot be interacted with except through unsafe functions"
56
)]
57
// SAFETY: the CompressorParams are "valid" to the best of our knowledge. The basis-universal
58
// library bindings note that invalid params might produce undefined behavior.
59
unsafe {
60
compressor.init(&compressor_params);
61
compressor.process().unwrap();
62
}
63
compressor.basis_file().to_vec()
64
};
65
66
writer.write_all(&compressed_basis_data).await?;
67
Ok(ImageLoaderSettings {
68
format: ImageFormatSetting::Format(ImageFormat::Basis),
69
is_srgb,
70
sampler: image.sampler.clone(),
71
asset_usage: image.asset_usage,
72
texture_format: None,
73
})
74
}
75
}
76
77