use bevy_asset::{Assets, Handle, HandleTemplate, RenderAssetUsages};
use bevy_camera::visibility::{self, ViewVisibility, Visibility, VisibilityClass};
use bevy_color::{Color, ColorToComponents, LinearRgba};
use bevy_ecs::prelude::*;
use bevy_ecs::template::{FromTemplate, OptionTemplate};
use bevy_image::Image;
use bevy_math::{Quat, UVec2, Vec3};
use bevy_reflect::prelude::*;
use bevy_transform::components::Transform;
use wgpu_types::{
Extent3d, TextureDimension, TextureFormat, TextureViewDescriptor, TextureViewDimension,
};
use crate::cluster::ClusterVisibilityClass;
#[derive(Component, Debug, Clone, Copy, Default, Reflect)]
#[reflect(Component, Default, Debug, Clone)]
#[require(Transform, ViewVisibility, Visibility, VisibilityClass)]
#[component(on_add = visibility::add_visibility_class::<ClusterVisibilityClass>)]
pub struct LightProbe {
pub falloff: Vec3,
}
impl LightProbe {
#[inline]
pub fn new() -> Self {
Self::default()
}
}
#[derive(Clone, Component, Reflect, FromTemplate)]
#[reflect(Component, Default, Clone)]
pub struct EnvironmentMapLight {
pub diffuse_map: Handle<Image>,
pub specular_map: Handle<Image>,
pub intensity: f32,
pub rotation: Quat,
pub affects_lightmapped_mesh_diffuse: bool,
}
impl EnvironmentMapLight {
pub fn solid_color(assets: &mut Assets<Image>, color: impl Into<Color>) -> Self {
let color = color.into();
Self::hemispherical_gradient(assets, color, color, color)
}
pub fn hemispherical_gradient(
assets: &mut Assets<Image>,
top_color: impl Into<Color>,
mid_color: impl Into<Color>,
bottom_color: impl Into<Color>,
) -> Self {
let handle = assets.add(Self::hemispherical_gradient_cubemap(
top_color.into(),
mid_color.into(),
bottom_color.into(),
));
Self {
diffuse_map: handle.clone(),
specular_map: handle,
intensity: 1.0,
..Default::default()
}
}
pub(crate) fn hemispherical_gradient_cubemap(
top_color: Color,
mid_color: Color,
bottom_color: Color,
) -> Image {
let top_color: LinearRgba = top_color.into();
let mid_color: LinearRgba = mid_color.into();
let bottom_color: LinearRgba = bottom_color.into();
Image {
texture_view_descriptor: Some(TextureViewDescriptor {
dimension: Some(TextureViewDimension::Cube),
..Default::default()
}),
..Image::new(
Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 6,
},
TextureDimension::D2,
[
mid_color,
mid_color,
top_color,
bottom_color,
mid_color,
mid_color,
]
.into_iter()
.flat_map(|c| c.to_f32_array().map(half::f16::from_f32))
.flat_map(half::f16::to_le_bytes)
.collect(),
TextureFormat::Rgba16Float,
RenderAssetUsages::RENDER_WORLD,
)
}
}
}
impl Default for EnvironmentMapLight {
fn default() -> Self {
EnvironmentMapLight {
diffuse_map: Handle::default(),
specular_map: Handle::default(),
intensity: 0.0,
rotation: Quat::IDENTITY,
affects_lightmapped_mesh_diffuse: true,
}
}
}
#[derive(Component, Clone, Reflect, FromTemplate)]
#[reflect(Component, Default, Clone)]
pub struct Skybox {
#[template(OptionTemplate<HandleTemplate<Image>>)]
pub image: Option<Handle<Image>>,
pub brightness: f32,
pub rotation: Quat,
}
impl Default for Skybox {
fn default() -> Self {
Skybox {
image: None,
brightness: 0.0,
rotation: Quat::IDENTITY,
}
}
}
#[derive(Clone, Component, Reflect, FromTemplate)]
#[reflect(Component, Default, Clone)]
pub struct GeneratedEnvironmentMapLight {
pub environment_map: Handle<Image>,
pub intensity: f32,
pub rotation: Quat,
pub affects_lightmapped_mesh_diffuse: bool,
}
impl Default for GeneratedEnvironmentMapLight {
fn default() -> Self {
GeneratedEnvironmentMapLight {
environment_map: Handle::default(),
intensity: 0.0,
rotation: Quat::IDENTITY,
affects_lightmapped_mesh_diffuse: true,
}
}
}
#[derive(Component, Clone)]
pub struct AtmosphereEnvironmentMapLight {
pub intensity: f32,
pub affects_lightmapped_mesh_diffuse: bool,
pub size: UVec2,
}
impl Default for AtmosphereEnvironmentMapLight {
fn default() -> Self {
Self {
intensity: 1.0,
affects_lightmapped_mesh_diffuse: true,
size: UVec2::new(512, 512),
}
}
}
#[derive(Clone, Reflect, Component, Debug, FromTemplate)]
#[reflect(Component, Default, Debug, Clone)]
#[require(LightProbe)]
pub struct IrradianceVolume {
pub voxels: Handle<Image>,
pub intensity: f32,
pub affects_lightmapped_meshes: bool,
}
impl Default for IrradianceVolume {
#[inline]
fn default() -> Self {
IrradianceVolume {
voxels: Handle::default(),
intensity: 0.0,
affects_lightmapped_meshes: true,
}
}
}
#[derive(Clone, Copy, Default, Component, Reflect)]
#[reflect(Clone, Default, Component)]
pub enum ParallaxCorrection {
None,
#[default]
Auto,
Custom(Vec3),
}
pub fn automatically_add_parallax_correction_components(
mut commands: Commands,
query: Query<
Entity,
(
With<EnvironmentMapLight>,
With<LightProbe>,
Without<ParallaxCorrection>,
),
>,
) {
for entity in &query {
commands
.entity(entity)
.insert(ParallaxCorrection::default());
}
}