bevy_sprinkles_editor 0.2.0

GPU particle system editor for Bevy
use bevy::prelude::*;
use bevy::reflect::TypePath;
use bevy::render::render_resource::*;
use bevy::shader::ShaderRef;
use bevy_sprinkles::prelude::Curve;

const SHADER_CURVE_PATH: &str = "embedded://sprinkles/assets/shaders/curve_edit.wgsl";
pub const MAX_POINTS: usize = 8;
const BORDER_RADIUS: f32 = 4.0;

fn pack_f32(values: &[f32; MAX_POINTS]) -> [Vec4; 2] {
    [
        Vec4::new(values[0], values[1], values[2], values[3]),
        Vec4::new(values[4], values[5], values[6], values[7]),
    ]
}

fn pack_u32(values: &[u32; MAX_POINTS]) -> [UVec4; 2] {
    [
        UVec4::new(values[0], values[1], values[2], values[3]),
        UVec4::new(values[4], values[5], values[6], values[7]),
    ]
}

#[derive(AsBindGroup, Asset, TypePath, Debug, Clone, Default)]
pub struct CurveMaterial {
    #[uniform(0)]
    border_radius: f32,
    #[uniform(0)]
    point_count: u32,
    #[uniform(0)]
    range_min: f32,
    #[uniform(0)]
    range_max: f32,
    #[uniform(0)]
    curve_color: Vec4,
    #[uniform(0)]
    fill_color: Vec4,
    #[uniform(0)]
    positions_low: Vec4,
    #[uniform(0)]
    positions_high: Vec4,
    #[uniform(0)]
    values_low: Vec4,
    #[uniform(0)]
    values_high: Vec4,
    #[uniform(0)]
    modes_low: UVec4,
    #[uniform(0)]
    modes_high: UVec4,
    #[uniform(0)]
    tensions_low: Vec4,
    #[uniform(0)]
    tensions_high: Vec4,
    #[uniform(0)]
    easings_low: UVec4,
    #[uniform(0)]
    easings_high: UVec4,
}

impl CurveMaterial {
    pub fn from_channel(channel: &Curve, curve_color: Srgba, fill_color: Srgba) -> Self {
        let mut positions = [0.0f32; MAX_POINTS];
        let mut values = [0.0f32; MAX_POINTS];
        let mut modes = [0u32; MAX_POINTS];
        let mut tensions = [0.0f32; MAX_POINTS];
        let mut easings = [0u32; MAX_POINTS];

        for (i, point) in channel.points.iter().take(MAX_POINTS).enumerate() {
            positions[i] = point.position;
            values[i] = point.value as f32;
            modes[i] = point.mode as u32;
            tensions[i] = point.tension as f32;
            easings[i] = point.easing as u32;
        }

        let [positions_low, positions_high] = pack_f32(&positions);
        let [values_low, values_high] = pack_f32(&values);
        let [modes_low, modes_high] = pack_u32(&modes);
        let [tensions_low, tensions_high] = pack_f32(&tensions);
        let [easings_low, easings_high] = pack_u32(&easings);

        Self {
            border_radius: BORDER_RADIUS,
            point_count: channel.points.len().min(MAX_POINTS) as u32,
            range_min: channel.range.min,
            range_max: channel.range.max,
            curve_color: Vec4::new(
                curve_color.red,
                curve_color.green,
                curve_color.blue,
                curve_color.alpha,
            ),
            fill_color: Vec4::new(
                fill_color.red,
                fill_color.green,
                fill_color.blue,
                fill_color.alpha,
            ),
            positions_low,
            positions_high,
            values_low,
            values_high,
            modes_low,
            modes_high,
            tensions_low,
            tensions_high,
            easings_low,
            easings_high,
        }
    }
}

impl UiMaterial for CurveMaterial {
    fn fragment_shader() -> ShaderRef {
        SHADER_CURVE_PATH.into()
    }
}