Add feature requirement info to image loading docs (#13712)

# Objective

- Add "Available on crate feature <image format> only." for docs of
image format related types/functions
- Add warning "WARN bevy_render::texture::image: feature "<image
format>" is not enabled" on load attempt
- Fixes #13468 .

## Solution

- Added #[cfg(feature = "<image format>")] for types and warn!("feature
\"<image format>\" is not enabled"); for ImageFormat enum conversions

## Testing

ran reproducing example from issue #13468 and saw in logs
`WARN bevy_render::texture::image: feature "exr" is not enabled`

generated docs with command `RUSTDOCFLAGS="-Zunstable-options
--cfg=docsrs" cargo +nightly doc --workspace --all-features --no-deps
--document-private-items --open` and saw

![image](https://github.com/bevyengine/bevy/assets/17225606/820262bb-b4e6-4a5e-a306-bddbe9c40852)
that docs contain `Available on crate feature <image format> only.`
marks

![image](https://github.com/bevyengine/bevy/assets/17225606/57463440-a2ea-435f-a2c2-50d34f7f55a9)

## Migration Guide
Image format related entities are feature gated, if there are
compilation errors about unknown names there are some of features in
list (`exr`, `hdr`, `basis-universal`, `png`, `dds`, `tga`, `jpeg`,
`bmp`, `ktx2`, `webp` and `pnm`) should be added.
This commit is contained in:
Vitaliy Sapronenko 2024-08-17 02:43:20 +03:00 committed by GitHub
parent d7cb781977
commit bc445bb5c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 75 additions and 31 deletions

View File

@ -8,6 +8,7 @@ use wgpu::{
use super::{CompressedImageFormats, Image, TextureError}; use super::{CompressedImageFormats, Image, TextureError};
#[cfg(feature = "dds")]
pub fn dds_buffer_to_image( pub fn dds_buffer_to_image(
#[cfg(debug_assertions)] name: String, #[cfg(debug_assertions)] name: String,
buffer: &[u8], buffer: &[u8],
@ -82,6 +83,7 @@ pub fn dds_buffer_to_image(
Ok(image) Ok(image)
} }
#[cfg(feature = "dds")]
pub fn dds_format_to_texture_format( pub fn dds_format_to_texture_format(
dds: &Dds, dds: &Dds,
is_srgb: bool, is_srgb: bool,

View File

@ -10,9 +10,11 @@ use wgpu::{Extent3d, TextureDimension, TextureFormat};
/// Loads EXR textures as Texture assets /// Loads EXR textures as Texture assets
#[derive(Clone, Default)] #[derive(Clone, Default)]
#[cfg(feature = "exr")]
pub struct ExrTextureLoader; pub struct ExrTextureLoader;
#[derive(Serialize, Deserialize, Default, Debug)] #[derive(Serialize, Deserialize, Default, Debug)]
#[cfg(feature = "exr")]
pub struct ExrTextureLoaderSettings { pub struct ExrTextureLoaderSettings {
pub asset_usage: RenderAssetUsages, pub asset_usage: RenderAssetUsages,
} }
@ -20,6 +22,7 @@ pub struct ExrTextureLoaderSettings {
/// Possible errors that can be produced by [`ExrTextureLoader`] /// Possible errors that can be produced by [`ExrTextureLoader`]
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[cfg(feature = "exr")]
pub enum ExrTextureLoaderError { pub enum ExrTextureLoaderError {
#[error(transparent)] #[error(transparent)]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),

View File

@ -27,43 +27,66 @@ pub const SAMPLER_ASSET_INDEX: u64 = 1;
#[derive(Debug, Serialize, Deserialize, Copy, Clone)] #[derive(Debug, Serialize, Deserialize, Copy, Clone)]
pub enum ImageFormat { pub enum ImageFormat {
Avif, Avif,
#[cfg(feature = "basis-universal")]
Basis, Basis,
#[cfg(feature = "bmp")]
Bmp, Bmp,
#[cfg(feature = "dds")]
Dds, Dds,
Farbfeld, Farbfeld,
Gif, Gif,
#[cfg(feature = "exr")]
OpenExr, OpenExr,
#[cfg(feature = "hdr")]
Hdr, Hdr,
Ico, Ico,
#[cfg(feature = "jpeg")]
Jpeg, Jpeg,
#[cfg(feature = "ktx2")]
Ktx2, Ktx2,
#[cfg(feature = "png")]
Png, Png,
#[cfg(feature = "pnm")]
Pnm, Pnm,
#[cfg(feature = "tga")]
Tga, Tga,
Tiff, Tiff,
#[cfg(feature = "webp")]
WebP, WebP,
} }
macro_rules! feature_gate {
($feature: tt, $value: ident) => {{
#[cfg(not(feature = $feature))]
{
bevy_utils::tracing::warn!("feature \"{}\" is not enabled", $feature);
return None;
}
#[cfg(feature = $feature)]
ImageFormat::$value
}};
}
impl ImageFormat { impl ImageFormat {
pub fn from_mime_type(mime_type: &str) -> Option<Self> { pub fn from_mime_type(mime_type: &str) -> Option<Self> {
Some(match mime_type.to_ascii_lowercase().as_str() { Some(match mime_type.to_ascii_lowercase().as_str() {
"image/avif" => ImageFormat::Avif, "image/avif" => ImageFormat::Avif,
"image/bmp" | "image/x-bmp" => ImageFormat::Bmp, "image/bmp" | "image/x-bmp" => feature_gate!("bmp", Bmp),
"image/vnd-ms.dds" => ImageFormat::Dds, "image/vnd-ms.dds" => feature_gate!("dds", Dds),
"image/vnd.radiance" => ImageFormat::Hdr, "image/vnd.radiance" => feature_gate!("hdr", Hdr),
"image/gif" => ImageFormat::Gif, "image/gif" => ImageFormat::Gif,
"image/x-icon" => ImageFormat::Ico, "image/x-icon" => ImageFormat::Ico,
"image/jpeg" => ImageFormat::Jpeg, "image/jpeg" => feature_gate!("jpeg", Jpeg),
"image/ktx2" => ImageFormat::Ktx2, "image/ktx2" => feature_gate!("ktx2", Ktx2),
"image/png" => ImageFormat::Png, "image/png" => feature_gate!("png", Png),
"image/x-exr" => ImageFormat::OpenExr, "image/x-exr" => feature_gate!("exr", OpenExr),
"image/x-portable-bitmap" "image/x-portable-bitmap"
| "image/x-portable-graymap" | "image/x-portable-graymap"
| "image/x-portable-pixmap" | "image/x-portable-pixmap"
| "image/x-portable-anymap" => ImageFormat::Pnm, | "image/x-portable-anymap" => feature_gate!("pnm", Pnm),
"image/x-targa" | "image/x-tga" => ImageFormat::Tga, "image/x-targa" | "image/x-tga" => feature_gate!("tga", Tga),
"image/tiff" => ImageFormat::Tiff, "image/tiff" => ImageFormat::Tiff,
"image/webp" => ImageFormat::WebP, "image/webp" => feature_gate!("webp", WebP),
_ => return None, _ => return None,
}) })
} }
@ -71,21 +94,21 @@ impl ImageFormat {
pub fn from_extension(extension: &str) -> Option<Self> { pub fn from_extension(extension: &str) -> Option<Self> {
Some(match extension.to_ascii_lowercase().as_str() { Some(match extension.to_ascii_lowercase().as_str() {
"avif" => ImageFormat::Avif, "avif" => ImageFormat::Avif,
"basis" => ImageFormat::Basis, "basis" => feature_gate!("basis-universal", Basis),
"bmp" => ImageFormat::Bmp, "bmp" => feature_gate!("bmp", Bmp),
"dds" => ImageFormat::Dds, "dds" => feature_gate!("dds", Dds),
"ff" | "farbfeld" => ImageFormat::Farbfeld, "ff" | "farbfeld" => ImageFormat::Farbfeld,
"gif" => ImageFormat::Gif, "gif" => ImageFormat::Gif,
"exr" => ImageFormat::OpenExr, "exr" => feature_gate!("exr", OpenExr),
"hdr" => ImageFormat::Hdr, "hdr" => feature_gate!("hdr", Hdr),
"ico" => ImageFormat::Ico, "ico" => ImageFormat::Ico,
"jpg" | "jpeg" => ImageFormat::Jpeg, "jpg" | "jpeg" => feature_gate!("jpeg", Jpeg),
"ktx2" => ImageFormat::Ktx2, "ktx2" => feature_gate!("ktx2", Ktx2),
"pbm" | "pam" | "ppm" | "pgm" => ImageFormat::Pnm, "pbm" | "pam" | "ppm" | "pgm" => feature_gate!("pnm", Pnm),
"png" => ImageFormat::Png, "png" => feature_gate!("png", Png),
"tga" => ImageFormat::Tga, "tga" => feature_gate!("tga", Tga),
"tif" | "tiff" => ImageFormat::Tiff, "tif" | "tiff" => ImageFormat::Tiff,
"webp" => ImageFormat::WebP, "webp" => feature_gate!("webp", WebP),
_ => return None, _ => return None,
}) })
} }
@ -93,39 +116,51 @@ impl ImageFormat {
pub fn as_image_crate_format(&self) -> Option<image::ImageFormat> { pub fn as_image_crate_format(&self) -> Option<image::ImageFormat> {
Some(match self { Some(match self {
ImageFormat::Avif => image::ImageFormat::Avif, ImageFormat::Avif => image::ImageFormat::Avif,
#[cfg(feature = "bmp")]
ImageFormat::Bmp => image::ImageFormat::Bmp, ImageFormat::Bmp => image::ImageFormat::Bmp,
#[cfg(feature = "dds")]
ImageFormat::Dds => image::ImageFormat::Dds, ImageFormat::Dds => image::ImageFormat::Dds,
ImageFormat::Farbfeld => image::ImageFormat::Farbfeld, ImageFormat::Farbfeld => image::ImageFormat::Farbfeld,
ImageFormat::Gif => image::ImageFormat::Gif, ImageFormat::Gif => image::ImageFormat::Gif,
#[cfg(feature = "exr")]
ImageFormat::OpenExr => image::ImageFormat::OpenExr, ImageFormat::OpenExr => image::ImageFormat::OpenExr,
#[cfg(feature = "hdr")]
ImageFormat::Hdr => image::ImageFormat::Hdr, ImageFormat::Hdr => image::ImageFormat::Hdr,
ImageFormat::Ico => image::ImageFormat::Ico, ImageFormat::Ico => image::ImageFormat::Ico,
#[cfg(feature = "jpeg")]
ImageFormat::Jpeg => image::ImageFormat::Jpeg, ImageFormat::Jpeg => image::ImageFormat::Jpeg,
#[cfg(feature = "png")]
ImageFormat::Png => image::ImageFormat::Png, ImageFormat::Png => image::ImageFormat::Png,
#[cfg(feature = "pnm")]
ImageFormat::Pnm => image::ImageFormat::Pnm, ImageFormat::Pnm => image::ImageFormat::Pnm,
#[cfg(feature = "tga")]
ImageFormat::Tga => image::ImageFormat::Tga, ImageFormat::Tga => image::ImageFormat::Tga,
ImageFormat::Tiff => image::ImageFormat::Tiff, ImageFormat::Tiff => image::ImageFormat::Tiff,
#[cfg(feature = "webp")]
ImageFormat::WebP => image::ImageFormat::WebP, ImageFormat::WebP => image::ImageFormat::WebP,
ImageFormat::Basis | ImageFormat::Ktx2 => return None, #[cfg(feature = "basis-universal")]
ImageFormat::Basis => return None,
#[cfg(feature = "ktx2")]
ImageFormat::Ktx2 => return None,
}) })
} }
pub fn from_image_crate_format(format: image::ImageFormat) -> Option<ImageFormat> { pub fn from_image_crate_format(format: image::ImageFormat) -> Option<ImageFormat> {
Some(match format { Some(match format {
image::ImageFormat::Avif => ImageFormat::Avif, image::ImageFormat::Avif => ImageFormat::Avif,
image::ImageFormat::Bmp => ImageFormat::Bmp, image::ImageFormat::Bmp => feature_gate!("bmp", Bmp),
image::ImageFormat::Dds => ImageFormat::Dds, image::ImageFormat::Dds => feature_gate!("dds", Dds),
image::ImageFormat::Farbfeld => ImageFormat::Farbfeld, image::ImageFormat::Farbfeld => ImageFormat::Farbfeld,
image::ImageFormat::Gif => ImageFormat::Gif, image::ImageFormat::Gif => ImageFormat::Gif,
image::ImageFormat::OpenExr => ImageFormat::OpenExr, image::ImageFormat::OpenExr => feature_gate!("exr", OpenExr),
image::ImageFormat::Hdr => ImageFormat::Hdr, image::ImageFormat::Hdr => feature_gate!("hdr", Hdr),
image::ImageFormat::Ico => ImageFormat::Ico, image::ImageFormat::Ico => ImageFormat::Ico,
image::ImageFormat::Jpeg => ImageFormat::Jpeg, image::ImageFormat::Jpeg => feature_gate!("jpeg", Jpeg),
image::ImageFormat::Png => ImageFormat::Png, image::ImageFormat::Png => feature_gate!("png", Png),
image::ImageFormat::Pnm => ImageFormat::Pnm, image::ImageFormat::Pnm => feature_gate!("pnm", Pnm),
image::ImageFormat::Tga => ImageFormat::Tga, image::ImageFormat::Tga => feature_gate!("tga", Tga),
image::ImageFormat::Tiff => ImageFormat::Tiff, image::ImageFormat::Tiff => ImageFormat::Tiff,
image::ImageFormat::WebP => ImageFormat::WebP, image::ImageFormat::WebP => feature_gate!("webp", WebP),
_ => return None, _ => return None,
}) })
} }

View File

@ -20,6 +20,7 @@ use wgpu::{
use super::{CompressedImageFormats, DataFormat, Image, TextureError, TranscodeFormat}; use super::{CompressedImageFormats, DataFormat, Image, TextureError, TranscodeFormat};
#[cfg(feature = "ktx2")]
pub fn ktx2_buffer_to_image( pub fn ktx2_buffer_to_image(
buffer: &[u8], buffer: &[u8],
supported_compressed_formats: CompressedImageFormats, supported_compressed_formats: CompressedImageFormats,
@ -387,6 +388,7 @@ pub fn get_transcoded_formats(
} }
} }
#[cfg(feature = "ktx2")]
pub fn ktx2_get_texture_format<Data: AsRef<[u8]>>( pub fn ktx2_get_texture_format<Data: AsRef<[u8]>>(
ktx2: &ktx2::Reader<Data>, ktx2: &ktx2::Reader<Data>,
is_srgb: bool, is_srgb: bool,
@ -473,6 +475,7 @@ fn sample_information_to_data_type(
) )
} }
#[cfg(feature = "ktx2")]
pub fn ktx2_dfd_to_texture_format( pub fn ktx2_dfd_to_texture_format(
data_format_descriptor: &BasicDataFormatDescriptor, data_format_descriptor: &BasicDataFormatDescriptor,
sample_information: &[SampleInformation], sample_information: &[SampleInformation],
@ -1194,6 +1197,7 @@ pub fn ktx2_dfd_to_texture_format(
}) })
} }
#[cfg(feature = "ktx2")]
pub fn ktx2_format_to_texture_format( pub fn ktx2_format_to_texture_format(
ktx2_format: ktx2::Format, ktx2_format: ktx2::Format,
is_srgb: bool, is_srgb: bool,