use crate::camera; use bevy::prelude::*; use bevy::core_pipeline::Skybox; use bevy::asset::LoadState; use bevy::render::{ render_resource::{TextureViewDescriptor, TextureViewDimension}, renderer::RenderDevice, texture::CompressedImageFormats, }; #[derive(Resource)] pub struct Cubemap { is_loaded: bool, index: usize, image_handle: Handle, } const CUBEMAPS: &[(&str, CompressedImageFormats)] = &[ ( "textures/stars_cubemap.png", CompressedImageFormats::NONE, ), ]; pub fn setup( mut commands: Commands, asset_server: Res, ) { let skybox_handle = asset_server.load(CUBEMAPS[0].0); commands.spawn(( Camera3dBundle { transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, camera::CameraController::default(), Skybox { image: asset_server.load(CUBEMAPS[0].0).clone(), brightness: 150.0, }, )); commands.spawn(( Skybox { image: skybox_handle.clone(), brightness: 150.0, }, )); commands.insert_resource(Cubemap { is_loaded: false, index: 0, image_handle: skybox_handle, }); } pub fn load_cubemap_asset( mut cubemap: ResMut, asset_server: Res, render_device: Res, ) { let supported_compressed_formats = CompressedImageFormats::from_features(render_device.features()); let mut new_index = cubemap.index; for _ in 0..CUBEMAPS.len() { new_index = (new_index + 1) % CUBEMAPS.len(); if supported_compressed_formats.contains(CUBEMAPS[new_index].1) { break; } info!("Skipping unsupported format: {:?}", CUBEMAPS[new_index]); } // Skip swapping to the same texture. Useful for when ktx2, zstd, or compressed texture support // is missing if new_index == cubemap.index { return; } cubemap.index = new_index; cubemap.image_handle = asset_server.load(CUBEMAPS[cubemap.index].0); cubemap.is_loaded = false; } pub fn asset_loaded( asset_server: Res, mut images: ResMut>, mut cubemap: ResMut, mut skyboxes: Query<&mut Skybox>, ) { if !cubemap.is_loaded && asset_server.load_state(&cubemap.image_handle) == LoadState::Loaded { info!("Swapping to {}...", CUBEMAPS[cubemap.index].0); let image = images.get_mut(&cubemap.image_handle).unwrap(); // NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture, // so they appear as one texture. The following code reconfigures the texture as necessary. if image.texture_descriptor.array_layer_count() == 1 { image.reinterpret_stacked_2d_as_array(image.height() / image.width()); image.texture_view_descriptor = Some(TextureViewDescriptor { dimension: Some(TextureViewDimension::Cube), ..default() }); } for mut skybox in &mut skyboxes { skybox.image = cubemap.image_handle.clone(); } cubemap.is_loaded = true; } }