From 8adc9e9d6ea5d73d992830c2fc3f779f51c45488 Mon Sep 17 00:00:00 2001 From: Clar Fon <15850505+clarfonthey@users.noreply.github.com> Date: Mon, 7 Oct 2024 12:37:45 -0400 Subject: [PATCH] Feature-gate all image formats (#15586) # Objective Bevy supports feature gates for each format it supports, but several formats that it loads via the `image` crate do not have feature gates. Additionally, the QOI format is supported by the `image` crate and wasn't available at all. This fixes that. ## Solution The following feature gates are added: * `avif` * `ff` (Farbfeld) * `gif` * `ico` * `qoi` * `tiff` None of these formats are enabled by default, despite the fact that all these formats appeared to be enabled by default before. Since `default-features` was disabled for the `image` crate, it's likely that using any of these formats would have errored by default before this change, although this probably needs additional testing. ## Testing The changes seemed minimal enough that a compile test would be sufficient. ## Migration guide Image formats that previously weren't feature-gated are now feature-gated, meaning they will have to be enabled if you use them: * `avif` * `ff` (Farbfeld) * `gif` * `ico` * `tiff` Additionally, the `qoi` feature has been added to support loading QOI format images. Previously, these formats appeared in the enum by default, but weren't actually enabled via the `image` crate, potentially resulting in weird bugs. Now, you should be able to add these features to your projects to support them properly. --- Cargo.toml | 87 +++--- crates/bevy_core_pipeline/Cargo.toml | 7 +- crates/bevy_gltf/Cargo.toml | 3 +- crates/bevy_image/Cargo.toml | 19 +- crates/bevy_image/src/image.rs | 286 +++++++++++++++++- crates/bevy_internal/Cargo.toml | 43 ++- crates/bevy_render/Cargo.toml | 23 +- .../bevy_render/src/texture/image_loader.rs | 31 +- crates/bevy_render/src/texture/mod.rs | 28 +- docs/cargo_features.md | 6 + 10 files changed, 389 insertions(+), 144 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 15bc3e8b7c0de..aa38f582c1067 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,39 +100,40 @@ unused_qualifications = "warn" [features] default = [ + "android-game-activity", + "android-game-activity", + "android_shared_stdcxx", "animation", "bevy_asset", - "bevy_state", "bevy_audio", "bevy_color", - "bevy_gilrs", - "bevy_scene", - "bevy_winit", "bevy_core_pipeline", + "bevy_gilrs", + "bevy_gizmos", + "bevy_gltf", "bevy_pbr", "bevy_picking", - "bevy_sprite_picking_backend", - "bevy_ui_picking_backend", - "bevy_gltf", + "bevy_remote", "bevy_render", + "bevy_scene", "bevy_sprite", + "bevy_sprite_picking_backend", + "bevy_state", "bevy_text", "bevy_ui", - "bevy_remote", + "bevy_ui_picking_backend", + "bevy_winit", + "custom_cursor", + "default_font", + "hdr", "multi_threaded", "png", - "hdr", - "vorbis", - "x11", - "bevy_gizmos", - "android_shared_stdcxx", - "tonemapping_luts", "smaa_luts", - "default_font", - "webgl2", "sysinfo_plugin", - "android-game-activity", - "custom_cursor", + "tonemapping_luts", + "vorbis", + "webgl2", + "x11", ] # Provides an implementation for picking sprites @@ -242,38 +243,56 @@ trace_tracy_memory = [ # Tracing support trace = ["bevy_internal/trace"] +# AVIF image format support +avif = ["bevy_internal/avif"] + +# Basis Universal compressed texture support +basis-universal = ["bevy_internal/basis-universal"] + +# BMP image format support +bmp = ["bevy_internal/bmp"] + +# DDS compressed texture support +dds = ["bevy_internal/dds"] + # EXR image format support exr = ["bevy_internal/exr"] +# Farbfeld image format support +ff = ["bevy_internal/ff"] + +# GIF image format support +gif = ["bevy_internal/gif"] + # HDR image format support hdr = ["bevy_internal/hdr"] -# PNG image format support -png = ["bevy_internal/png"] +# KTX2 compressed texture support +ktx2 = ["bevy_internal/ktx2"] -# TGA image format support -tga = ["bevy_internal/tga"] +# ICO image format support +ico = ["bevy_internal/ico"] # JPEG image format support jpeg = ["bevy_internal/jpeg"] -# BMP image format support -bmp = ["bevy_internal/bmp"] +# PNG image format support +png = ["bevy_internal/png"] -# WebP image format support -webp = ["bevy_internal/webp"] +# PNM image format support, includes pam, pbm, pgm and ppm +pnm = ["bevy_internal/pnm"] -# Basis Universal compressed texture support -basis-universal = ["bevy_internal/basis-universal"] +# QOI image format support +qoi = ["bevy_internal/qoi"] -# DDS compressed texture support -dds = ["bevy_internal/dds"] +# TGA image format support +tga = ["bevy_internal/tga"] -# KTX2 compressed texture support -ktx2 = ["bevy_internal/ktx2"] +# TIFF image format support +tiff = ["bevy_internal/tiff"] -# PNM image format support, includes pam, pbm, pgm and ppm -pnm = ["bevy_internal/pnm"] +# WebP image format support +webp = ["bevy_internal/webp"] # For KTX2 supercompression zlib = ["bevy_internal/zlib"] diff --git a/crates/bevy_core_pipeline/Cargo.toml b/crates/bevy_core_pipeline/Cargo.toml index 9db01932f402f..fbf070f4cbb61 100644 --- a/crates/bevy_core_pipeline/Cargo.toml +++ b/crates/bevy_core_pipeline/Cargo.toml @@ -13,12 +13,12 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -dds = ["bevy_render/dds"] +dds = ["bevy_render/dds", "bevy_image/dds"] trace = [] webgl = [] webgpu = [] -tonemapping_luts = ["bevy_render/ktx2", "bevy_render/zstd"] -smaa_luts = ["bevy_render/ktx2", "bevy_render/zstd"] +tonemapping_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"] +smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"] [dependencies] # bevy @@ -28,6 +28,7 @@ bevy_core = { path = "../bevy_core", version = "0.15.0-dev" } bevy_color = { path = "../bevy_color", version = "0.15.0-dev" } bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" } +bevy_image = { path = "../bevy_image", version = "0.15.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" } bevy_render = { path = "../bevy_render", version = "0.15.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" } diff --git a/crates/bevy_gltf/Cargo.toml b/crates/bevy_gltf/Cargo.toml index 6bc73daa1688c..9b0ef61cbb809 100644 --- a/crates/bevy_gltf/Cargo.toml +++ b/crates/bevy_gltf/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -dds = ["bevy_render/dds", "bevy_core_pipeline/dds"] +dds = ["bevy_render/dds", "bevy_image/dds", "bevy_core_pipeline/dds"] pbr_transmission_textures = ["bevy_pbr/pbr_transmission_textures"] pbr_multi_layer_material_textures = [ "bevy_pbr/pbr_multi_layer_material_textures", @@ -26,6 +26,7 @@ bevy_core = { path = "../bevy_core", version = "0.15.0-dev" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" } bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" } +bevy_image = { path = "../bevy_image", version = "0.15.0-dev" } bevy_math = { path = "../bevy_math", version = "0.15.0-dev" } bevy_pbr = { path = "../bevy_pbr", version = "0.15.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [ diff --git a/crates/bevy_image/Cargo.toml b/crates/bevy_image/Cargo.toml index bc3e187ff893e..a9b6c6fdc3269 100644 --- a/crates/bevy_image/Cargo.toml +++ b/crates/bevy_image/Cargo.toml @@ -9,15 +9,24 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -png = ["image/png"] +# Image formats +avif = ["image/avif"] +basis-universal = ["dep:basis-universal"] +bmp = ["image/bmp"] +dds = ["ddsfile"] exr = ["image/exr"] +ff = ["image/ff"] +gif = ["image/gif"] hdr = ["image/hdr"] -tga = ["image/tga"] +ktx2 = ["dep:ktx2"] +ico = ["image/ico"] jpeg = ["image/jpeg"] -bmp = ["image/bmp"] -webp = ["image/webp"] -dds = ["ddsfile"] +png = ["image/png"] pnm = ["image/pnm"] +qoi = ["image/qoi"] +tga = ["image/tga"] +tiff = ["image/tiff"] +webp = ["image/webp"] # For ktx2 supercompression zlib = ["flate2"] diff --git a/crates/bevy_image/src/image.rs b/crates/bevy_image/src/image.rs index 6965f55ddec53..61b271cb273da 100644 --- a/crates/bevy_image/src/image.rs +++ b/crates/bevy_image/src/image.rs @@ -29,6 +29,7 @@ pub const SAMPLER_ASSET_INDEX: u64 = 1; #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub enum ImageFormat { + #[cfg(feature = "avif")] Avif, #[cfg(feature = "basis-universal")] Basis, @@ -36,12 +37,15 @@ pub enum ImageFormat { Bmp, #[cfg(feature = "dds")] Dds, + #[cfg(feature = "ff")] Farbfeld, + #[cfg(feature = "gif")] Gif, #[cfg(feature = "exr")] OpenExr, #[cfg(feature = "hdr")] Hdr, + #[cfg(feature = "ico")] Ico, #[cfg(feature = "jpeg")] Jpeg, @@ -51,8 +55,11 @@ pub enum ImageFormat { Png, #[cfg(feature = "pnm")] Pnm, + #[cfg(feature = "qoi")] + Qoi, #[cfg(feature = "tga")] Tga, + #[cfg(feature = "tiff")] Tiff, #[cfg(feature = "webp")] WebP, @@ -71,24 +78,261 @@ macro_rules! feature_gate { } impl ImageFormat { + /// Number of image formats, used for computing other constants. + const COUNT: usize = { + let mut count = 0; + #[cfg(feature = "avif")] + { + count += 1; + } + #[cfg(feature = "basis-universal")] + { + count += 1; + } + #[cfg(feature = "bmp")] + { + count += 1; + } + #[cfg(feature = "dds")] + { + count += 1; + } + #[cfg(feature = "ff")] + { + count += 1; + } + #[cfg(feature = "gif")] + { + count += 1; + } + #[cfg(feature = "exr")] + { + count += 1; + } + #[cfg(feature = "hdr")] + { + count += 1; + } + #[cfg(feature = "ico")] + { + count += 1; + } + #[cfg(feature = "jpeg")] + { + count += 1; + } + #[cfg(feature = "ktx2")] + { + count += 1; + } + #[cfg(feature = "pnm")] + { + count += 1; + } + #[cfg(feature = "png")] + { + count += 1; + } + #[cfg(feature = "qoi")] + { + count += 1; + } + #[cfg(feature = "tga")] + { + count += 1; + } + #[cfg(feature = "tiff")] + { + count += 1; + } + #[cfg(feature = "webp")] + { + count += 1; + } + count + }; + + /// Full list of supported formats. + pub const SUPPORTED: &'static [ImageFormat] = &[ + #[cfg(feature = "avif")] + ImageFormat::Avif, + #[cfg(feature = "basis-universal")] + ImageFormat::Basis, + #[cfg(feature = "bmp")] + ImageFormat::Bmp, + #[cfg(feature = "dds")] + ImageFormat::Dds, + #[cfg(feature = "ff")] + ImageFormat::Farbfeld, + #[cfg(feature = "gif")] + ImageFormat::Gif, + #[cfg(feature = "exr")] + ImageFormat::OpenExr, + #[cfg(feature = "hdr")] + ImageFormat::Hdr, + #[cfg(feature = "ico")] + ImageFormat::Ico, + #[cfg(feature = "jpeg")] + ImageFormat::Jpeg, + #[cfg(feature = "ktx2")] + ImageFormat::Ktx2, + #[cfg(feature = "png")] + ImageFormat::Png, + #[cfg(feature = "pnm")] + ImageFormat::Pnm, + #[cfg(feature = "qoi")] + ImageFormat::Qoi, + #[cfg(feature = "tga")] + ImageFormat::Tga, + #[cfg(feature = "tiff")] + ImageFormat::Tiff, + #[cfg(feature = "webp")] + ImageFormat::WebP, + ]; + + /// Total count of file extensions, for computing supported file extensions list. + const COUNT_FILE_EXTENSIONS: usize = { + let mut count = 0; + let mut idx = 0; + while idx < ImageFormat::COUNT { + count += ImageFormat::SUPPORTED[idx].to_file_extensions().len(); + idx += 1; + } + count + }; + + /// Gets the list of file extensions for all formats. + pub const SUPPORTED_FILE_EXTENSIONS: &'static [&'static str] = &{ + let mut exts = [""; ImageFormat::COUNT_FILE_EXTENSIONS]; + let mut ext_idx = 0; + let mut fmt_idx = 0; + while fmt_idx < ImageFormat::COUNT { + let mut off = 0; + let fmt_exts = ImageFormat::SUPPORTED[fmt_idx].to_file_extensions(); + while off < fmt_exts.len() { + exts[ext_idx] = fmt_exts[off]; + off += 1; + ext_idx += 1; + } + fmt_idx += 1; + } + exts + }; + + /// Gets the file extensions for a given format. + pub const fn to_file_extensions(&self) -> &'static [&'static str] { + match self { + #[cfg(feature = "avif")] + ImageFormat::Avif => &["avif"], + #[cfg(feature = "basis-universal")] + ImageFormat::Basis => &["basis"], + #[cfg(feature = "bmp")] + ImageFormat::Bmp => &["bmp"], + #[cfg(feature = "dds")] + ImageFormat::Dds => &["dds"], + #[cfg(feature = "ff")] + ImageFormat::Farbfeld => &["ff", "farbfeld"], + #[cfg(feature = "gif")] + ImageFormat::Gif => &["gif"], + #[cfg(feature = "exr")] + ImageFormat::OpenExr => &["exr"], + #[cfg(feature = "hdr")] + ImageFormat::Hdr => &["hdr"], + #[cfg(feature = "ico")] + ImageFormat::Ico => &["ico"], + #[cfg(feature = "jpeg")] + ImageFormat::Jpeg => &["jpg", "jpeg"], + #[cfg(feature = "ktx2")] + ImageFormat::Ktx2 => &["ktx2"], + #[cfg(feature = "pnm")] + ImageFormat::Pnm => &["pam", "pbm", "pgm", "ppm"], + #[cfg(feature = "png")] + ImageFormat::Png => &["png"], + #[cfg(feature = "qoi")] + ImageFormat::Qoi => &["qoi"], + #[cfg(feature = "tga")] + ImageFormat::Tga => &["tga"], + #[cfg(feature = "tiff")] + ImageFormat::Tiff => &["tif", "tiff"], + #[cfg(feature = "webp")] + ImageFormat::WebP => &["webp"], + // FIXME: https://github.com/rust-lang/rust/issues/129031 + #[allow(unreachable_patterns)] + _ => &[], + } + } + + /// Gets the MIME types for a given format. + /// + /// If a format doesn't have any dedicated MIME types, this list will be empty. + pub const fn to_mime_types(&self) -> &'static [&'static str] { + match self { + #[cfg(feature = "avif")] + ImageFormat::Avif => &["image/avif"], + #[cfg(feature = "basis-universal")] + ImageFormat::Basis => &["image/basis", "image/x-basis"], + #[cfg(feature = "bmp")] + ImageFormat::Bmp => &["image/bmp", "image/x-bmp"], + #[cfg(feature = "dds")] + ImageFormat::Dds => &["image/vnd-ms.dds"], + #[cfg(feature = "hdr")] + ImageFormat::Hdr => &["image/vnd.radiance"], + #[cfg(feature = "gif")] + ImageFormat::Gif => &["image/gif"], + #[cfg(feature = "ff")] + ImageFormat::Farbfeld => &[], + #[cfg(feature = "ico")] + ImageFormat::Ico => &["image/x-icon"], + #[cfg(feature = "jpeg")] + ImageFormat::Jpeg => &["image/jpeg"], + #[cfg(feature = "ktx2")] + ImageFormat::Ktx2 => &["image/ktx2"], + #[cfg(feature = "png")] + ImageFormat::Png => &["image/png"], + #[cfg(feature = "qoi")] + ImageFormat::Qoi => &["image/qoi", "image/x-qoi"], + #[cfg(feature = "exr")] + ImageFormat::OpenExr => &["image/x-exr"], + #[cfg(feature = "pnm")] + ImageFormat::Pnm => &[ + "image/x-portable-bitmap", + "image/x-portable-graymap", + "image/x-portable-pixmap", + "image/x-portable-anymap", + ], + #[cfg(feature = "tga")] + ImageFormat::Tga => &["image/x-targa", "image/x-tga"], + #[cfg(feature = "tiff")] + ImageFormat::Tiff => &["image/tiff"], + #[cfg(feature = "webp")] + ImageFormat::WebP => &["image/webp"], + // FIXME: https://github.com/rust-lang/rust/issues/129031 + #[allow(unreachable_patterns)] + _ => &[], + } + } + pub fn from_mime_type(mime_type: &str) -> Option { Some(match mime_type.to_ascii_lowercase().as_str() { - "image/avif" => ImageFormat::Avif, + // note: farbfeld does not have a MIME type + "image/avif" => feature_gate!("avif", Avif), + "image/basis" | "image/x-basis" => feature_gate!("basis-universal", Basis), "image/bmp" | "image/x-bmp" => feature_gate!("bmp", Bmp), "image/vnd-ms.dds" => feature_gate!("dds", Dds), "image/vnd.radiance" => feature_gate!("hdr", Hdr), - "image/gif" => ImageFormat::Gif, - "image/x-icon" => ImageFormat::Ico, + "image/gif" => feature_gate!("gif", Gif), + "image/x-icon" => feature_gate!("ico", Ico), "image/jpeg" => feature_gate!("jpeg", Jpeg), "image/ktx2" => feature_gate!("ktx2", Ktx2), "image/png" => feature_gate!("png", Png), + "image/qoi" | "image/x-qoi" => feature_gate!("qoi", Qoi), "image/x-exr" => feature_gate!("exr", OpenExr), "image/x-portable-bitmap" | "image/x-portable-graymap" | "image/x-portable-pixmap" | "image/x-portable-anymap" => feature_gate!("pnm", Pnm), "image/x-targa" | "image/x-tga" => feature_gate!("tga", Tga), - "image/tiff" => ImageFormat::Tiff, + "image/tiff" => feature_gate!("tiff", Tiff), "image/webp" => feature_gate!("webp", WebP), _ => return None, }) @@ -96,21 +340,22 @@ impl ImageFormat { pub fn from_extension(extension: &str) -> Option { Some(match extension.to_ascii_lowercase().as_str() { - "avif" => ImageFormat::Avif, + "avif" => feature_gate!("avif", Avif), "basis" => feature_gate!("basis-universal", Basis), "bmp" => feature_gate!("bmp", Bmp), "dds" => feature_gate!("dds", Dds), - "ff" | "farbfeld" => ImageFormat::Farbfeld, - "gif" => ImageFormat::Gif, + "ff" | "farbfeld" => feature_gate!("ff", Farbfeld), + "gif" => feature_gate!("gif", Gif), "exr" => feature_gate!("exr", OpenExr), "hdr" => feature_gate!("hdr", Hdr), - "ico" => ImageFormat::Ico, + "ico" => feature_gate!("ico", Ico), "jpg" | "jpeg" => feature_gate!("jpeg", Jpeg), "ktx2" => feature_gate!("ktx2", Ktx2), - "pbm" | "pam" | "ppm" | "pgm" => feature_gate!("pnm", Pnm), + "pam" | "pbm" | "pgm" | "ppm" => feature_gate!("pnm", Pnm), "png" => feature_gate!("png", Png), + "qoi" => feature_gate!("qoi", Qoi), "tga" => feature_gate!("tga", Tga), - "tif" | "tiff" => ImageFormat::Tiff, + "tif" | "tiff" => feature_gate!("tiff", Tiff), "webp" => feature_gate!("webp", WebP), _ => return None, }) @@ -118,17 +363,21 @@ impl ImageFormat { pub fn as_image_crate_format(&self) -> Option { Some(match self { + #[cfg(feature = "avif")] ImageFormat::Avif => image::ImageFormat::Avif, #[cfg(feature = "bmp")] ImageFormat::Bmp => image::ImageFormat::Bmp, #[cfg(feature = "dds")] ImageFormat::Dds => image::ImageFormat::Dds, + #[cfg(feature = "ff")] ImageFormat::Farbfeld => image::ImageFormat::Farbfeld, + #[cfg(feature = "gif")] ImageFormat::Gif => image::ImageFormat::Gif, #[cfg(feature = "exr")] ImageFormat::OpenExr => image::ImageFormat::OpenExr, #[cfg(feature = "hdr")] ImageFormat::Hdr => image::ImageFormat::Hdr, + #[cfg(feature = "ico")] ImageFormat::Ico => image::ImageFormat::Ico, #[cfg(feature = "jpeg")] ImageFormat::Jpeg => image::ImageFormat::Jpeg, @@ -136,8 +385,11 @@ impl ImageFormat { ImageFormat::Png => image::ImageFormat::Png, #[cfg(feature = "pnm")] ImageFormat::Pnm => image::ImageFormat::Pnm, + #[cfg(feature = "qoi")] + ImageFormat::Qoi => image::ImageFormat::Qoi, #[cfg(feature = "tga")] ImageFormat::Tga => image::ImageFormat::Tga, + #[cfg(feature = "tiff")] ImageFormat::Tiff => image::ImageFormat::Tiff, #[cfg(feature = "webp")] ImageFormat::WebP => image::ImageFormat::WebP, @@ -145,24 +397,28 @@ impl ImageFormat { ImageFormat::Basis => return None, #[cfg(feature = "ktx2")] ImageFormat::Ktx2 => return None, + // FIXME: https://github.com/rust-lang/rust/issues/129031 + #[allow(unreachable_patterns)] + _ => return None, }) } pub fn from_image_crate_format(format: image::ImageFormat) -> Option { Some(match format { - image::ImageFormat::Avif => ImageFormat::Avif, + image::ImageFormat::Avif => feature_gate!("avif", Avif), image::ImageFormat::Bmp => feature_gate!("bmp", Bmp), image::ImageFormat::Dds => feature_gate!("dds", Dds), - image::ImageFormat::Farbfeld => ImageFormat::Farbfeld, - image::ImageFormat::Gif => ImageFormat::Gif, + image::ImageFormat::Farbfeld => feature_gate!("ff", Farbfeld), + image::ImageFormat::Gif => feature_gate!("gif", Gif), image::ImageFormat::OpenExr => feature_gate!("exr", OpenExr), image::ImageFormat::Hdr => feature_gate!("hdr", Hdr), - image::ImageFormat::Ico => ImageFormat::Ico, + image::ImageFormat::Ico => feature_gate!("ico", Ico), image::ImageFormat::Jpeg => feature_gate!("jpeg", Jpeg), image::ImageFormat::Png => feature_gate!("png", Png), image::ImageFormat::Pnm => feature_gate!("pnm", Pnm), + image::ImageFormat::Qoi => feature_gate!("qoi", Qoi), image::ImageFormat::Tga => feature_gate!("tga", Tga), - image::ImageFormat::Tiff => ImageFormat::Tiff, + image::ImageFormat::Tiff => feature_gate!("tiff", Tiff), image::ImageFormat::WebP => feature_gate!("webp", WebP), _ => return None, }) diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index b8de4caf57d59..2ea147a826a52 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -28,21 +28,35 @@ detailed_trace = ["bevy_utils/detailed_trace"] sysinfo_plugin = ["bevy_diagnostic/sysinfo_plugin"] -# Image format support for texture loading (PNG and HDR are enabled by default) -exr = ["bevy_render/exr"] -hdr = ["bevy_render/hdr"] -png = ["bevy_render/png"] -tga = ["bevy_render/tga"] -jpeg = ["bevy_render/jpeg"] -bmp = ["bevy_render/bmp"] -webp = ["bevy_render/webp"] -basis-universal = ["bevy_render/basis-universal"] -dds = ["bevy_render/dds", "bevy_core_pipeline/dds", "bevy_gltf/dds"] -pnm = ["bevy_render/pnm"] -ktx2 = ["bevy_render/ktx2"] +# Texture formats that have specific rendering support (HDR enabled by default) +basis-universal = ["bevy_image/basis-universal", "bevy_render/basis-universal"] +dds = [ + "bevy_image/dds", + "bevy_render/dds", + "bevy_core_pipeline/dds", + "bevy_gltf/dds", +] +exr = ["bevy_image/exr", "bevy_render/exr"] +hdr = ["bevy_image/hdr", "bevy_render/hdr"] +ktx2 = ["bevy_image/ktx2", "bevy_render/ktx2"] + # For ktx2 supercompression -zlib = ["bevy_render/zlib"] -zstd = ["bevy_render/zstd"] +zlib = ["bevy_image/zlib"] +zstd = ["bevy_image/zstd"] + +# Image format support (PNG enabled by default) +avif = ["bevy_image/avif"] +bmp = ["bevy_image/bmp"] +ff = ["bevy_image/ff"] +gif = ["bevy_image/gif"] +ico = ["bevy_image/ico"] +jpeg = ["bevy_image/jpeg"] +png = ["bevy_image/png"] +pnm = ["bevy_image/pnm"] +qoi = ["bevy_image/qoi"] +tga = ["bevy_image/tga"] +tiff = ["bevy_image/tiff"] +webp = ["bevy_image/webp"] # Enable SPIR-V passthrough spirv_shader_passthrough = ["bevy_render/spirv_shader_passthrough"] @@ -258,6 +272,7 @@ bevy_dev_tools = { path = "../bevy_dev_tools", optional = true, version = "0.15. bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.15.0-dev" } bevy_gizmos = { path = "../bevy_gizmos", optional = true, version = "0.15.0-dev", default-features = false } bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.15.0-dev" } +bevy_image = { path = "../bevy_image", optional = true, version = "0.15.0-dev" } bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.15.0-dev" } bevy_picking = { path = "../bevy_picking", optional = true, version = "0.15.0-dev" } bevy_remote = { path = "../bevy_remote", optional = true, version = "0.15.0-dev" } diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 46018bde2b07b..ab3603e0f53a1 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -9,31 +9,18 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -png = ["image/png", "bevy_image/png"] -exr = ["image/exr", "bevy_image/exr"] -hdr = ["image/hdr", "bevy_image/hdr"] -tga = ["image/tga", "bevy_image/tga"] -jpeg = ["image/jpeg", "bevy_image/jpeg"] -bmp = ["image/bmp", "bevy_image/bmp"] -webp = ["image/webp", "bevy_image/webp"] -dds = ["ddsfile", "bevy_image/dds"] -pnm = ["image/pnm", "bevy_image/pnm"] - -ddsfile = ["bevy_image/ddsfile"] -ktx2 = ["dep:ktx2", "bevy_image/ktx2"] -flate2 = ["bevy_image/flate2"] -ruzstd = ["bevy_image/ruzstd"] +# Texture formats (require more than just image support) basis-universal = ["dep:basis-universal", "bevy_image/basis-universal"] +dds = ["bevy_image/dds"] +exr = ["bevy_image/exr"] +hdr = ["bevy_image/hdr"] +ktx2 = ["dep:ktx2", "bevy_image/ktx2"] multi_threaded = ["bevy_tasks/multi_threaded"] shader_format_glsl = ["naga/glsl-in", "naga/wgsl-out", "naga_oil/glsl"] shader_format_spirv = ["wgpu/spirv", "naga/spv-in", "naga/spv-out"] -# For ktx2 supercompression -zlib = ["flate2", "bevy_image/zlib"] -zstd = ["ruzstd", "bevy_image/zstd"] - # Enable SPIR-V shader passthrough spirv_shader_passthrough = [] diff --git a/crates/bevy_render/src/texture/image_loader.rs b/crates/bevy_render/src/texture/image_loader.rs index c82c64807b812..9f3c55502eddc 100644 --- a/crates/bevy_render/src/texture/image_loader.rs +++ b/crates/bevy_render/src/texture/image_loader.rs @@ -17,35 +17,6 @@ pub struct ImageLoader { supported_compressed_formats: CompressedImageFormats, } -pub(crate) const IMG_FILE_EXTENSIONS: &[&str] = &[ - #[cfg(feature = "basis-universal")] - "basis", - #[cfg(feature = "bmp")] - "bmp", - #[cfg(feature = "png")] - "png", - #[cfg(feature = "dds")] - "dds", - #[cfg(feature = "tga")] - "tga", - #[cfg(feature = "jpeg")] - "jpg", - #[cfg(feature = "jpeg")] - "jpeg", - #[cfg(feature = "ktx2")] - "ktx2", - #[cfg(feature = "webp")] - "webp", - #[cfg(feature = "pnm")] - "pam", - #[cfg(feature = "pnm")] - "pbm", - #[cfg(feature = "pnm")] - "pgm", - #[cfg(feature = "pnm")] - "ppm", -]; - #[derive(Serialize, Deserialize, Default, Debug)] pub enum ImageFormatSetting { #[default] @@ -131,7 +102,7 @@ impl AssetLoader for ImageLoader { } fn extensions(&self) -> &[&str] { - IMG_FILE_EXTENSIONS + ImageFormat::SUPPORTED_FILE_EXTENSIONS } } diff --git a/crates/bevy_render/src/texture/mod.rs b/crates/bevy_render/src/texture/mod.rs index 1c64dde93f57b..49b74d4c6cf0e 100644 --- a/crates/bevy_render/src/texture/mod.rs +++ b/crates/bevy_render/src/texture/mod.rs @@ -114,33 +114,13 @@ impl Plugin for ImagePlugin { ); } - #[cfg(any( - feature = "png", - feature = "dds", - feature = "tga", - feature = "jpeg", - feature = "bmp", - feature = "basis-universal", - feature = "ktx2", - feature = "webp", - feature = "pnm" - ))] - app.preregister_asset_loader::(IMG_FILE_EXTENSIONS); + if !ImageFormat::SUPPORTED_FILE_EXTENSIONS.is_empty() { + app.preregister_asset_loader::(ImageFormat::SUPPORTED_FILE_EXTENSIONS); + } } fn finish(&self, app: &mut App) { - #[cfg(any( - feature = "png", - feature = "dds", - feature = "tga", - feature = "jpeg", - feature = "bmp", - feature = "basis-universal", - feature = "ktx2", - feature = "webp", - feature = "pnm" - ))] - { + if !ImageFormat::SUPPORTED.is_empty() { app.init_asset_loader::(); } diff --git a/docs/cargo_features.md b/docs/cargo_features.md index 273ee171ffaec..e45c379955740 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -56,6 +56,7 @@ The default feature set enables most of the expected features of a game engine, |android-native-activity|Android NativeActivity support. Legacy, should be avoided for most new Android games.| |asset_processor|Enables the built-in asset processor for processed assets.| |async-io|Use async-io's implementation of block_on instead of futures-lite's implementation. This is preferred if your application uses async-io.| +|avif|AVIF image format support| |basis-universal|Basis Universal compressed texture support| |bevy_ci_testing|Enable systems that allow for automated testing on CI| |bevy_debug_stepping|Enable stepping-based debugging of Bevy systems| @@ -67,9 +68,12 @@ The default feature set enables most of the expected features of a game engine, |dynamic_linking|Force dynamic linking, which improves iterative compile times| |embedded_watcher|Enables watching in memory asset providers for Bevy Asset hot-reloading| |exr|EXR image format support| +|ff|Farbfeld image format support| |file_watcher|Enables watching the filesystem for Bevy Asset hot-reloading| |flac|FLAC audio format support| +|gif|GIF image format support| |glam_assert|Enable assertions to check the validity of parameters passed to glam| +|ico|ICO image format support| |ios_simulator|Enable support for the ios_simulator by downgrading some rendering capabilities| |jpeg|JPEG image format support| |meshlet|Enables the meshlet renderer for dense high-poly scenes (experimental)| @@ -80,6 +84,7 @@ The default feature set enables most of the expected features of a game engine, |pbr_multi_layer_material_textures|Enable support for multi-layer material textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs| |pbr_transmission_textures|Enable support for transmission-related textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs| |pnm|PNM image format support, includes pam, pbm, pgm and ppm| +|qoi|QOI image format support| |reflect_functions|Enable function reflection| |serialize|Enable serialization support through serde| |shader_format_glsl|Enable support for shaders in GLSL| @@ -92,6 +97,7 @@ The default feature set enables most of the expected features of a game engine, |symphonia-vorbis|OGG/VORBIS audio format support (through symphonia)| |symphonia-wav|WAV audio format support (through symphonia)| |tga|TGA image format support| +|tiff|TIFF image format support| |trace|Tracing support| |trace_chrome|Tracing support, saving a file in Chrome Tracing format| |trace_tracy|Tracing support, exposing a port for Tracy|