gled 2.14.0

gled is an application for creating animations and effects on artnet or dmx installations
pub mod effect;
pub mod effect_state;
pub mod instance;

use super::{Asset, AssetTrait, animation::Animation, palette::Palette};
use crate::{
    pipeline::group::{GroupIndices, Groups},
    storage::AssetId,
    ui::pills::show_pills,
};
use effect::Effect;
use effect_state::EffectState;
use egui::{Color32, Vec2};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use wgpu::{CommandEncoder, Queue};

#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
pub struct Scene {
    effects: Vec<Effect>,
}

impl Scene {
    pub fn group_indices(&self) -> GroupIndices {
        self.effects
            .iter()
            .map(|effect| effect.group_index)
            .collect()
    }

    pub fn set_output_mix_buffers(&self, effect_states: &mut [EffectState]) {
        for (effect, effect_state) in self.effects.iter().zip(effect_states.iter_mut()) {
            effect.set_output_mix_buffers(effect_state);
        }
    }

    pub fn effect(&mut self, index: usize) -> Option<&mut Effect> {
        self.effects.get_mut(index)
    }

    pub fn effects(&self) -> &[Effect] {
        &self.effects
    }

    pub fn add_effect(&mut self, effect_states: &mut Vec<EffectState>, effect: Effect) -> usize {
        effect_states.push(EffectState::new(&effect));
        self.effects.push(effect);

        self.effects.len() - 1
    }

    pub fn remove_effect(
        &mut self,
        effect_states: &mut Vec<EffectState>,
        index: usize,
    ) -> Option<Effect> {
        let mut effect = None;

        if self.effects.len() > index {
            effect = Some(self.effects.remove(index));
            effect_states.remove(index);
        }

        effect
    }

    pub fn init_states(&self, effect_states: &mut Vec<EffectState>) {
        if effect_states.len() != self.effects.len() {
            if effect_states.len() > self.effects.len() {
                effect_states.truncate(self.effects.len());
            } else {
                let previous_len = effect_states.len();
                effect_states.extend(self.effects.iter().skip(previous_len).map(EffectState::new));
                for (effect, state) in self
                    .effects
                    .iter()
                    .zip(effect_states.iter_mut())
                    .skip(previous_len)
                {
                    state.update(effect);
                }
            }
        }
    }

    pub fn reload_shader_code(
        &self,
        effect_states: &mut [EffectState],
        animation: AssetId<Animation>,
    ) {
        for (effect, state) in self.effects.iter().zip(effect_states.iter_mut()) {
            if effect.animation == Some(animation) {
                state.update(effect);
            }
        }
    }

    pub fn prepare(
        &self,
        effect_states: &mut [EffectState],
        queue: &Queue,
        palette: Option<Arc<Asset<Palette>>>,
        groups: &Groups,
        main_opacity: f32,
    ) {
        debug_assert_eq!(effect_states.len(), self.effects.len());

        for (effect, state) in self.effects.iter().zip(effect_states.iter_mut()) {
            effect.prepare(state, queue, palette.clone(), groups, main_opacity);
        }
    }

    pub fn render(
        &self,
        effect_states: &mut [EffectState],
        encoder: &mut CommandEncoder,
        send_output: bool,
    ) {
        debug_assert_eq!(effect_states.len(), self.effects.len());

        for (effect, state) in self.effects.iter().zip(effect_states.iter_mut()) {
            effect.render(state, encoder, send_output);
        }
    }
}

impl AssetTrait for Scene {
    const DIR_NAME: &'static str = "scenes";
    const NAME: &'static str = "Scene";
    const SHOW_NAME_IF_SELECTED: bool = true;

    fn show(&self, ui: &mut egui::Ui, rect: egui::Rect) {
        show_pills(
            ui,
            rect.right_top() + Vec2::new(0.0, 1.0),
            self.group_indices()
                .into_iter()
                .map(|index| (index.to_string(), Color32::GOLD))
                .collect(),
        );
    }
}