use bevy::{
asset::load_internal_asset,
pbr::{NotShadowCaster, NotShadowReceiver},
prelude::*,
render::{
camera::{CameraProjection, Projection},
view::RenderLayers,
},
};
use crate::{
pipeline::*,
skybox::{AtmosphereSkyBoxMaterial, SkyBoxMaterial, ATMOSPHERE_SKYBOX_SHADER_HANDLE},
};
pub const ATMOSPHERE_INIT: &str = "ATMOSPHERE_INIT";
#[derive(Debug, Clone, Copy)]
pub struct AtmospherePlugin;
impl Plugin for AtmospherePlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(
app,
ATMOSPHERE_SKYBOX_SHADER_HANDLE,
"shaders/skybox.wgsl",
Shader::from_wgsl
);
app.add_plugin(MaterialPlugin::<SkyBoxMaterial>::default());
app.add_plugin(AtmospherePipelinePlugin);
{
let image_handle = {
let image = app.world.resource::<AtmosphereImage>();
image.handle.clone()
};
let mut material_assets = app.world.resource_mut::<Assets<SkyBoxMaterial>>();
let material = material_assets.add(SkyBoxMaterial {
sky_texture: image_handle,
});
app.insert_resource(AtmosphereSkyBoxMaterial(material));
}
#[cfg(feature = "init")]
app.add_startup_system_to_stage(
StartupStage::PostStartup,
atmosphere_init.label(ATMOSPHERE_INIT),
);
app.add_system(atmosphere_cancel_rotation);
}
}
#[derive(Component, Debug, Clone, Copy)]
pub struct AtmosphereCamera(pub Option<u8>);
#[derive(Component, Debug, Clone, Copy)]
pub struct AtmosphereSkyBox;
#[cfg(feature = "init")]
fn atmosphere_init(
mut commands: Commands,
mut mesh_assets: ResMut<Assets<Mesh>>,
material: Res<AtmosphereSkyBoxMaterial>,
atmosphere_cameras: Query<(Entity, &Projection, &AtmosphereCamera)>,
) {
info!(
"Found '{}' `AtmosphereCamera`s",
atmosphere_cameras.iter().len()
);
for (camera, projection, atmosphere_camera) in &atmosphere_cameras {
#[cfg(feature = "trace")]
trace!("Adding skybox to camera entity (ID:{:?})", camera);
commands
.entity(camera)
.insert_bundle(VisibilityBundle {
visibility: Visibility { is_visible: true },
..default()
})
.with_children(|c| {
let mut child = c.spawn_bundle(MaterialMeshBundle {
mesh: mesh_assets.add(crate::skybox::mesh(projection.far())),
material: material.0.clone(),
..default()
});
child
.insert(AtmosphereSkyBox)
.insert(NotShadowCaster)
.insert(NotShadowReceiver);
if let AtmosphereCamera(Some(render_layer)) = atmosphere_camera {
child.insert(RenderLayers::layer(*render_layer));
}
});
}
}
fn atmosphere_cancel_rotation(
mut atmosphere_sky_boxes: Query<(&mut Transform, &Parent), With<AtmosphereSkyBox>>,
atmosphere_cameras: Query<&GlobalTransform, With<AtmosphereCamera>>,
) {
for (mut transform, parent) in &mut atmosphere_sky_boxes {
if let Ok(parent_transform) = atmosphere_cameras.get(parent.get()) {
let (_, parent_rotation, _) = parent_transform.to_scale_rotation_translation();
transform.rotation = parent_rotation.inverse();
} else {
debug!("Did not get transform of skybox parent");
}
}
}