gled-core 2.30.2

The engine of gled without a user interface: inputs, timing, rendering, Art-Net/DMX output and storage
Documentation
use crate::{
    action::UiAction,
    pipeline::extract_output::OutputConfig,
    svg::{universe_color_channels, universe_color_channels::UniverseColorChannels},
};
use gled_gpu::render_to_output::positions::Positions;
use gled_model::asset::group::Group;
use gled_svg::measurement_point::MeasurementPoints;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use std::sync::Arc;

/// Measurement points of the currently loaded SVG. Written by the engine when
/// an SVG is parsed, read by the render thread when positions are uploaded. The
/// lock only guards an `Arc` swap, so readers never wait on any real work.
static MEASUREMENT_POINTS: Lazy<Mutex<Arc<MeasurementPoints>>> =
    Lazy::new(|| Mutex::new(Arc::new(MeasurementPoints::new())));

/// Parses the SVG's lamp layout and makes it the current one for every
/// thread, with the output universes it uses. Returns `false` when the SVG
/// does not parse; the layout is then empty.
pub(crate) fn apply_svg_layout(contents: &str, output_config: &mut OutputConfig) -> bool {
    let svg = match gled_svg::ParsedSvg::parse(contents) {
        Ok(svg) => svg,
        Err(err) => {
            UiAction::Error(format!("Could not parse the SVG: {err:?}")).enqueue();
            reset_svg_layout();
            return false;
        }
    };
    for warning in &svg.warnings {
        UiAction::Error(warning.clone()).enqueue();
    }
    let measurement_points = MeasurementPoints::from(&svg);
    universe_color_channels::set(UniverseColorChannels::from(&svg));
    output_config.universes = Arc::new(measurement_points.universes());
    *MEASUREMENT_POINTS.lock() = Arc::new(measurement_points);
    true
}

/// Forgets the current lamp layout.
pub(crate) fn reset_svg_layout() {
    *MEASUREMENT_POINTS.lock() = Arc::new(MeasurementPoints::new());
}

/// The lamp layout of the SVG parsed last.
pub(crate) struct CurrentSvg;

impl CurrentSvg {
    fn measurement_points() -> Arc<MeasurementPoints> {
        MEASUREMENT_POINTS.lock().clone()
    }

    pub(crate) fn groups() -> Vec<Group> {
        Self::measurement_points().groups()
    }

    pub(crate) fn positions(group: &Group) -> Positions {
        Self::measurement_points().positions(group)
    }

    pub(crate) fn preview_positions() -> Positions {
        Self::measurement_points().preview_positions()
    }
}