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