bevy_render/texture/
mod.rs

1#[cfg(feature = "basis-universal")]
2mod basis;
3#[cfg(feature = "basis-universal")]
4mod compressed_image_saver;
5#[cfg(feature = "dds")]
6mod dds;
7#[cfg(feature = "exr")]
8mod exr_texture_loader;
9mod fallback_image;
10#[cfg(feature = "hdr")]
11mod hdr_texture_loader;
12#[allow(clippy::module_inception)]
13mod image;
14mod image_loader;
15#[cfg(feature = "ktx2")]
16mod ktx2;
17mod texture_attachment;
18mod texture_cache;
19
20pub(crate) mod image_texture_conversion;
21
22pub use self::image::*;
23#[cfg(feature = "ktx2")]
24pub use self::ktx2::*;
25#[cfg(feature = "dds")]
26pub use dds::*;
27#[cfg(feature = "exr")]
28pub use exr_texture_loader::*;
29#[cfg(feature = "hdr")]
30pub use hdr_texture_loader::*;
31
32#[cfg(feature = "basis-universal")]
33pub use compressed_image_saver::*;
34pub use fallback_image::*;
35pub use image_loader::*;
36pub use texture_attachment::*;
37pub use texture_cache::*;
38
39use crate::{
40    render_asset::RenderAssetPlugin, renderer::RenderDevice, Render, RenderApp, RenderSet,
41};
42use bevy_app::{App, Plugin};
43use bevy_asset::{AssetApp, Assets, Handle};
44use bevy_ecs::prelude::*;
45
46/// A handle to a 1 x 1 transparent white image.
47///
48/// Like [`Handle<Image>::default`], this is a handle to a fallback image asset.
49/// While that handle points to an opaque white 1 x 1 image, this handle points to a transparent 1 x 1 white image.
50// Number randomly selected by fair WolframAlpha query. Totally arbitrary.
51pub const TRANSPARENT_IMAGE_HANDLE: Handle<Image> =
52    Handle::weak_from_u128(154728948001857810431816125397303024160);
53
54// TODO: replace Texture names with Image names?
55/// Adds the [`Image`] as an asset and makes sure that they are extracted and prepared for the GPU.
56pub struct ImagePlugin {
57    /// The default image sampler to use when [`ImageSampler`] is set to `Default`.
58    pub default_sampler: ImageSamplerDescriptor,
59}
60
61impl Default for ImagePlugin {
62    fn default() -> Self {
63        ImagePlugin::default_linear()
64    }
65}
66
67impl ImagePlugin {
68    /// Creates image settings with linear sampling by default.
69    pub fn default_linear() -> ImagePlugin {
70        ImagePlugin {
71            default_sampler: ImageSamplerDescriptor::linear(),
72        }
73    }
74
75    /// Creates image settings with nearest sampling by default.
76    pub fn default_nearest() -> ImagePlugin {
77        ImagePlugin {
78            default_sampler: ImageSamplerDescriptor::nearest(),
79        }
80    }
81}
82
83impl Plugin for ImagePlugin {
84    fn build(&self, app: &mut App) {
85        #[cfg(feature = "exr")]
86        {
87            app.init_asset_loader::<ExrTextureLoader>();
88        }
89
90        #[cfg(feature = "hdr")]
91        {
92            app.init_asset_loader::<HdrTextureLoader>();
93        }
94
95        app.add_plugins(RenderAssetPlugin::<GpuImage>::default())
96            .register_type::<Image>()
97            .init_asset::<Image>()
98            .register_asset_reflect::<Image>();
99
100        let mut image_assets = app.world_mut().resource_mut::<Assets<Image>>();
101
102        image_assets.insert(&Handle::default(), Image::default());
103        image_assets.insert(&TRANSPARENT_IMAGE_HANDLE, Image::transparent());
104
105        #[cfg(feature = "basis-universal")]
106        if let Some(processor) = app
107            .world()
108            .get_resource::<bevy_asset::processor::AssetProcessor>()
109        {
110            processor.register_processor::<bevy_asset::processor::LoadAndSave<ImageLoader, CompressedImageSaver>>(
111                CompressedImageSaver.into(),
112            );
113            processor
114                .set_default_processor::<bevy_asset::processor::LoadAndSave<ImageLoader, CompressedImageSaver>>("png");
115        }
116
117        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
118            render_app.init_resource::<TextureCache>().add_systems(
119                Render,
120                update_texture_cache_system.in_set(RenderSet::Cleanup),
121            );
122        }
123
124        #[cfg(any(
125            feature = "png",
126            feature = "dds",
127            feature = "tga",
128            feature = "jpeg",
129            feature = "bmp",
130            feature = "basis-universal",
131            feature = "ktx2",
132            feature = "webp",
133            feature = "pnm"
134        ))]
135        app.preregister_asset_loader::<ImageLoader>(IMG_FILE_EXTENSIONS);
136    }
137
138    fn finish(&self, app: &mut App) {
139        #[cfg(any(
140            feature = "png",
141            feature = "dds",
142            feature = "tga",
143            feature = "jpeg",
144            feature = "bmp",
145            feature = "basis-universal",
146            feature = "ktx2",
147            feature = "webp",
148            feature = "pnm"
149        ))]
150        {
151            app.init_asset_loader::<ImageLoader>();
152        }
153
154        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
155            let default_sampler = {
156                let device = render_app.world().resource::<RenderDevice>();
157                device.create_sampler(&self.default_sampler.as_wgpu())
158            };
159            render_app
160                .insert_resource(DefaultImageSampler(default_sampler))
161                .init_resource::<FallbackImage>()
162                .init_resource::<FallbackImageZero>()
163                .init_resource::<FallbackImageCubemap>()
164                .init_resource::<FallbackImageFormatMsaaCache>();
165        }
166    }
167}
168
169pub trait BevyDefault {
170    fn bevy_default() -> Self;
171}
172
173impl BevyDefault for wgpu::TextureFormat {
174    fn bevy_default() -> Self {
175        wgpu::TextureFormat::Rgba8UnormSrgb
176    }
177}