use std::collections::HashMap;
use bevy::asset::{AssetId, Assets, Handle};
use bevy::color::{Color, ColorToComponents};
use bevy::ecs::prelude::*;
use bevy::math::Vec4;
use super::{FloraMaterial, FloraUniform, FloraWindBuffer, flora_material};
const MIN_PRUNE_AT: usize = 64;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct Look {
color: [u32; 4],
leaf: bool,
tree: [u32; 4],
response: [u32; 4],
leaf_look: [u32; 4],
tint: [u32; 4],
}
fn bits(v: Vec4) -> [u32; 4] {
v.to_array().map(f32::to_bits)
}
impl Look {
fn new(color: Color, uniform: &FloraUniform, leaf: bool) -> Self {
Self {
color: color.to_linear().to_f32_array().map(f32::to_bits),
leaf,
tree: bits(uniform.tree),
response: bits(uniform.response),
leaf_look: bits(uniform.leaf),
tint: bits(uniform.tint),
}
}
}
#[derive(Resource, Default)]
pub struct SharedFlora {
materials: HashMap<Look, AssetId<FloraMaterial>>,
prune_at: usize,
}
impl SharedFlora {
pub(crate) fn resolve(
&mut self,
assets: &mut Assets<FloraMaterial>,
color: Color,
uniform: FloraUniform,
leaf: bool,
wind: &FloraWindBuffer,
) -> Handle<FloraMaterial> {
let look = Look::new(color, &uniform, leaf);
if let Some(id) = self.materials.get(&look)
&& let Some(strong) = assets.get_strong_handle(*id)
{
return strong;
}
if self.materials.len() >= self.prune_at.max(MIN_PRUNE_AT) {
self.materials.retain(|_, id| assets.contains(*id));
self.prune_at = self.materials.len() * 2;
}
let strong = assets.add(flora_material(color, uniform, leaf, wind));
self.materials.insert(look, strong.id());
strong
}
}