use crate::prelude::*;
use crate::scatter::utils::*;
use bevy_asset::{Assets, Handle};
use bevy_camera::prelude::Visibility;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::prelude::*;
use bevy_image::Image;
use bevy_math::{Quat, Vec3};
use bevy_pbr::StandardMaterial;
use bevy_reflect::Reflect;
use bevy_tasks::Task;
use bevy_transform::prelude::Transform;
use rand::Rng;
use bevy_ecs::lifecycle::HookContext;
use bevy_ecs::world::DeferredWorld;
use derive_more::From;
use std::fmt::Debug;
use std::marker::PhantomData;
#[derive(Component, Reflect, Debug, Clone, Copy)]
#[reflect(Component, Debug, Clone)]
pub struct ScatterRequest<T = StandardMaterial>
where
T: ScatterMaterial,
{
pub target_entity: Entity,
pub layer_entity: Entity,
pub chunk_entity: Option<Entity>,
#[reflect(ignore)]
_marker: PhantomData<T>,
}
impl<T> ScatterRequest<T>
where
T: ScatterMaterial,
{
pub fn new(target_entity: Entity, layer_entity: Entity, chunk_entity: Option<Entity>) -> Self {
Self {
target_entity,
layer_entity,
chunk_entity,
_marker: Default::default(),
}
}
}
#[derive(Clone)]
pub struct ScatterTaskData {
pub container: Container,
pub map_height: Option<MapHeight>,
pub scale: Option<InstanceScaleRange>,
pub rotation: Option<InstanceRotationYawRange>,
pub jitter: Option<InstanceJitterStrength>,
pub avoidance: Option<Avoidance>,
pub height_map_image: Option<Image>,
pub height_map_config: Option<HeightMapConfig>,
pub density_map_image: Option<Image>,
pub external_avoidance_data: ScatterOccupancyMap,
pub density: Option<LodDensity>,
}
#[derive(Component, Debug)]
pub struct CpuScatterTask<T>(pub Task<T>);
#[derive(Component, Debug)]
pub struct CpuScatterResult<T>(pub T);
#[derive(Component, Reflect, Debug, Clone)]
#[reflect(Component, Debug, Clone)]
pub struct ScatterItem;
#[derive(Component, Reflect, Debug, Clone)]
#[reflect(Component, Debug, Clone)]
pub struct ScatterRootProcessed;
#[derive(Component, Reflect, Debug, Clone, Default)]
#[reflect(Component, Debug, Clone)]
pub struct ScatterChunked;
#[cfg(feature = "avian")]
#[derive(Component, Debug, Clone, Reflect, Default)]
pub struct ScatterPhysicsBody;
#[derive(Component, Reflect, Debug, Clone, Deref, Default)]
#[reflect(Component, Debug, Clone)]
pub struct ScatterItemAsset<T>(pub Handle<ScatterAsset<T>>)
where
T: ScatterMaterialAsset;
#[derive(Component, Debug, Clone, Reflect, Deref)]
#[reflect(Component, Debug, Clone)]
#[relationship(relationship_target = ScatterLayer)]
pub struct ScatterItemOf(pub Entity);
#[derive(Component, Reflect, Default)]
#[require(Transform, Visibility)]
#[relationship_target(relationship = ScatterItemOf)]
#[reflect(Component)]
pub struct ScatterLayer(Vec<Entity>);
#[derive(Component, Reflect, Debug)]
#[reflect(Component, Debug)]
pub struct ChunkInitScatter<T = StandardMaterial>
where
T: ScatterMaterial,
{
#[reflect(ignore)]
_marker: PhantomData<T>,
}
impl<T> Default for ChunkInitScatter<T>
where
T: ScatterMaterial,
{
fn default() -> Self {
Self {
_marker: Default::default(),
}
}
}
#[derive(Component, Reflect, Debug)]
#[reflect(Component, Debug)]
#[require(ScatterLayer)]
pub struct ScatterLayerType<T = StandardMaterial>
where
T: ScatterMaterial,
{
#[reflect(ignore)]
_marker: PhantomData<T>,
}
impl<T> Default for ScatterLayerType<T>
where
T: ScatterMaterial,
{
fn default() -> Self {
Self {
_marker: Default::default(),
}
}
}
#[derive(Component)]
pub struct ScatterLayerProcessed;
#[derive(Component)]
pub struct ScatterLayerChildProcessed;
#[derive(Component)]
pub struct ScatterObserver;
#[derive(Component, Debug, Clone, Reflect, Deref)]
#[reflect(Component, Debug)]
#[relationship(relationship_target = ScatterRoot)]
pub struct ScatterLayerOf(pub Entity);
#[derive(Component, Debug, Clone, Reflect, Deref, Default)]
#[reflect(Component, Debug)]
#[require(Transform, Visibility, LodConfig, ScatterOccupancyMap)]
#[relationship_target(relationship = ScatterLayerOf)]
pub struct ScatterRoot(Vec<Entity>);
#[derive(Component, Reflect, Debug, From, Clone, Default)]
#[reflect(Component, Debug)]
pub struct ScatterLayerDisabled;
#[derive(Component, Reflect, Deref, DerefMut, Debug)]
#[reflect(Component, Debug)]
pub struct DistributionDensity(pub f32);
impl From<f32> for DistributionDensity {
fn from(value: f32) -> Self {
Self(value)
}
}
impl From<i32> for DistributionDensity {
fn from(value: i32) -> Self {
Self(value as f32)
}
}
impl From<usize> for DistributionDensity {
fn from(value: usize) -> Self {
Self(value as f32)
}
}
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component, Debug)]
pub struct ScaleDensity;
#[derive(Component, Reflect, Deref, DerefMut, Debug)]
#[reflect(Component, Debug)]
pub struct ScatteredInstance(pub Entity);
#[derive(Component, Reflect, Deref, DerefMut, Debug)]
#[reflect(Component, Debug)]
pub struct ScatteredAsset<T>(pub Handle<ScatterAsset<T>>)
where
T: ScatterMaterialAsset;
#[derive(Component, Reflect, Deref, DerefMut, Debug)]
#[reflect(Component, Debug)]
#[component(on_add = Self::on_add)]
pub struct ScatteredPart<T>(pub (Handle<ScatterAsset<T>>, usize))
where
T: ScatterMaterialAsset;
impl<T: ScatterMaterialAsset> ScatteredPart<T> {
fn on_add(mut world: DeferredWorld, ctx: HookContext) {
let scatter_assets = world.get_resource::<Assets<ScatterAsset<T>>>().unwrap();
let ScatteredPart((handle, index)) = world.get::<Self>(ctx.entity).unwrap();
let asset = scatter_assets.get(handle).unwrap();
let part = asset.parts.get(*index).cloned().unwrap();
let mut cmd = world.commands();
if part.properties.wind_affected {
cmd.entity(ctx.entity).insert(WindAffected);
}
if let Some(render_layers) = part.properties.options.render_layers {
cmd.entity(ctx.entity).insert(render_layers);
}
#[cfg(feature = "avian")]
if let Some(collider) = part.o_collider.clone() {
cmd.entity(ctx.entity).insert(collider);
}
}
}
#[derive(Component, Reflect, Deref, DerefMut, Debug)]
#[reflect(Component, Debug)]
pub struct DistributionPattern(pub Handle<Image>);
#[derive(Component, Reflect, Clone, Debug, Default)]
#[reflect(Component, Debug, Clone)]
#[require(InstanceRotationYawRange)]
pub struct InstanceRotationYaw;
#[derive(Component, Reflect, Clone, Copy, Debug)]
#[reflect(Component, Debug)]
pub struct InstanceRotationYawRange {
pub min: f32,
pub max: f32,
}
impl InstanceRotationYawRange {
#[inline]
pub fn is_fixed(&self) -> bool {
self.min == self.max
}
pub fn into_quad(self, rng: &mut impl Rng) -> Quat {
Quat::from_rotation_y(if self.is_fixed() {
self.min
} else {
rng.random_range(self.min..self.max)
})
}
}
impl Default for InstanceRotationYawRange {
fn default() -> Self {
Self {
min: 0.0,
max: std::f32::consts::TAU,
}
}
}
#[derive(Component, Reflect, Clone, Debug, Default)]
#[reflect(Component, Debug, Clone)]
#[require(InstanceScaleRange)]
pub struct InstanceScale;
#[derive(Component, Reflect, Clone, Debug)]
#[reflect(Component, Debug, Clone)]
pub struct InstanceScaleRange {
pub min: f32,
pub max: f32,
}
impl InstanceScaleRange {
#[inline]
pub fn is_fixed(&self) -> bool {
self.min == self.max
}
pub fn into_f32(self, rng: &mut impl Rng) -> f32 {
if self.is_fixed() {
self.min
} else {
rng.random_range(self.min..self.max)
}
}
pub fn into_vec3(self, rng: &mut impl Rng) -> Vec3 {
Vec3::splat(self.into_f32(rng))
}
}
impl Default for InstanceScaleRange {
fn default() -> Self {
Self { min: 1., max: 2. }
}
}
#[derive(Component, Reflect, Clone, Debug, Default)]
#[reflect(Component, Debug, Clone)]
#[require(InstanceJitterStrength)]
pub struct InstanceJitter;
#[derive(Component, Reflect, Deref, DerefMut, Clone, Debug)]
#[reflect(Component, Debug, Clone)]
pub struct InstanceJitterStrength(pub f32);
impl Default for InstanceJitterStrength {
fn default() -> Self {
Self(1.)
}
}
#[derive(Component, Reflect, Deref, DerefMut, Clone, Debug)]
#[reflect(Component, Debug)]
pub struct InstanceDensity(pub f32);
#[derive(Component, Reflect, Clone, Debug, Default)]
#[reflect(Component, Debug, Clone)]
#[require(Avoidance)]
pub struct Avoid;
#[derive(Component, Clone, Debug, Deref, DerefMut, Reflect)]
#[reflect(Component, Debug)]
pub struct Avoidance(pub f32);
impl Default for Avoidance {
fn default() -> Self {
Self(1.)
}
}
#[derive(Component, Debug, Reflect, Default)]
#[reflect(Component, Debug)]
pub struct HierarchicalScatterState<T = StandardMaterial>
where
T: ScatterMaterial,
{
pub ordered_layers: Vec<Entity>,
pub current_layer_index: usize,
pub pending_tasks: usize,
#[reflect(ignore)]
pub _marker: PhantomData<T>,
}