Skip to content

Commit

Permalink
feat(projects): use archives for project files to be able to include …
Browse files Browse the repository at this point in the history
…media files etc
  • Loading branch information
maxjoehnk committed Jul 11, 2024
1 parent 201b912 commit 66dbb21
Show file tree
Hide file tree
Showing 40 changed files with 1,077 additions and 682 deletions.
222 changes: 192 additions & 30 deletions Cargo.lock

Large diffs are not rendered by default.

75 changes: 75 additions & 0 deletions crates/components/fixtures/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use serde::{Deserialize, Serialize};
use crate::fixture::FixtureConfiguration;
use crate::programmer::{Color, Position, Preset, Presets};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FixtureConfig {
pub id: u32,
pub name: String,
pub fixture: String,
pub channel: u16,
pub universe: Option<u16>,
#[serde(default)]
pub mode: Option<String>,
#[serde(default)]
pub configuration: FixtureConfiguration,
}

#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct PresetsStore {
#[serde(default)]
pub intensity: Vec<Preset<f64>>,
#[serde(default)]
pub shutter: Vec<Preset<f64>>,
#[serde(default)]
pub color: Vec<Preset<Color>>,
#[serde(default)]
pub position: Vec<Preset<Position>>,
}

impl PresetsStore {
pub fn load(&self, presets: &Presets) {
for preset in self.intensity.iter() {
presets.intensity.insert(preset.id, preset.clone());
}
for preset in self.shutter.iter() {
presets.shutter.insert(preset.id, preset.clone());
}
for preset in self.color.iter() {
presets.color.insert(preset.id, preset.clone());
}
for preset in self.position.iter() {
presets.position.insert(preset.id, preset.clone());
}
}

pub fn store(presets: &Presets) -> Self {
let intensity = presets
.intensity
.iter()
.map(|entry| entry.value().clone())
.collect();
let shutter = presets
.shutter
.iter()
.map(|entry| entry.value().clone())
.collect();
let color = presets
.color
.iter()
.map(|entry| entry.value().clone())
.collect();
let position = presets
.position
.iter()
.map(|entry| entry.value().clone())
.collect();

Self {
intensity,
shutter,
color,
position,
}
}
}
1 change: 1 addition & 0 deletions crates/components/fixtures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub use crate::module::*;
pub use crate::priority::*;
use crate::programmer::Color;

mod config;
mod contracts;
pub mod definition;
pub mod fixture;
Expand Down
87 changes: 87 additions & 0 deletions crates/components/fixtures/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::{Arc, Mutex, MutexGuard};

use dashmap::DashMap;
use itertools::Itertools;
use mizer_module::{LoadProjectContext, ProjectHandler, ProjectHandlerContext, SaveProjectContext};

use mizer_protocol_dmx::DmxConnectionManager;

Expand All @@ -15,6 +16,7 @@ use crate::programmer::{
GenericPreset, Group, Position, Preset, PresetId, PresetType, Presets, Programmer,
};
use crate::{FixtureId, FixturePriority, FixtureStates, GroupId};
use crate::config::{FixtureConfig, PresetsStore};

#[derive(Clone)]
pub struct FixtureManager {
Expand Down Expand Up @@ -405,6 +407,91 @@ impl FixtureManager {
fixture.set_to_default();
}
}

fn clear(&self) {
self.fixtures.clear();
self.groups.clear();
self.presets.clear();
self.states.clear();
}
}

impl ProjectHandler for FixtureManager {
fn get_name(&self) -> &'static str {
"fixtures"
}

fn new_project(&mut self, _context: &mut impl ProjectHandlerContext) -> anyhow::Result<()> {
self.clear();
self.presets.load_defaults();

Ok(())
}

fn load_project(&mut self, context: &mut impl LoadProjectContext) -> anyhow::Result<()> {
profiling::scope!("FixtureManager::load_project");
self.clear();
let fixtures = context.read_file::<Vec<FixtureConfig>>("patch")?;
for fixture in fixtures {
let def = self.get_definition(&fixture.fixture);
if let Some(def) = def {
self.add_fixture(
fixture.id,
fixture.name,
def,
fixture.mode,
fixture.channel,
fixture.universe,
fixture.configuration,
);
} else {
tracing::warn!(
"No fixture definition for fixture id {}. Missing fixture definition: {}",
fixture.id,
fixture.fixture
);
context.report_issue(format!(
"No fixture definition for fixture id {}. Missing fixture definition: {}",
fixture.id,
fixture.fixture
));
}
}
let groups = context.read_file::<Vec<Group>>("groups")?;
for group in groups {
self.groups.insert(group.id, group);
}
let presets = context.read_file::<PresetsStore>("presets")?;
presets.load(&self.presets);

Ok(())
}

fn save_project(&self, context: &mut impl SaveProjectContext) -> anyhow::Result<()> {
profiling::scope!("FixtureManager::save_project");
let mut fixtures = Vec::with_capacity(self.fixtures.len());
for fixture in self.get_fixtures() {
fixtures.push(FixtureConfig {
id: fixture.id,
name: fixture.name.clone(),
universe: fixture.universe.into(),
channel: fixture.channel,
fixture: fixture.definition.id.clone(),
mode: fixture.current_mode.name.clone().into(),
configuration: fixture.configuration.clone(),
});
}
context.write_file("patch", &fixtures)?;
let mut groups = Vec::with_capacity(self.groups.len());
for group in self.get_groups() {
groups.push(group.deref().clone());
}
context.write_file("groups", &groups)?;
let presets = PresetsStore::store(&self.presets);
context.write_file("presets", &presets)?;

Ok(())
}
}

struct MutexLogWrapper<'a, T>(MutexGuard<'a, T>);
Expand Down
1 change: 1 addition & 0 deletions crates/components/fixtures/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl<TLibraryLoader: FixtureLibraryLoader + Default + 'static> Module
context.provide_api(library.clone());
context.provide(library);
context.provide_api(manager.clone());
context.add_project_handler(manager.clone());
context.provide(manager);
context.add_processor(FixtureProcessor);
context.add_debug_ui_pane(FixturesDebugUiPane);
Expand Down
1 change: 1 addition & 0 deletions crates/components/sequencer/src/effects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod engine;
mod instance;
mod module;
mod processor;
mod project_loading;
mod spline;

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions crates/components/sequencer/src/effects/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl Module for EffectsModule {
fn register(self, context: &mut impl ModuleContext) -> anyhow::Result<()> {
let engine = EffectEngine::new();
context.provide_api(engine.clone());
context.add_project_handler(engine.clone());
context.provide(engine);
context.add_processor(EffectsProcessor);
context.add_debug_ui_pane(EffectsDebugUiPane);
Expand Down
40 changes: 40 additions & 0 deletions crates/components/sequencer/src/effects/project_loading.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use mizer_module::*;
use crate::{Effect, EffectEngine};

impl ProjectHandler for EffectEngine {
fn get_name(&self) -> &'static str {
"effects"
}

fn new_project(&mut self, _context: &mut impl ProjectHandlerContext) -> anyhow::Result<()> {
self.clear();
self.load_defaults();

Ok(())
}

fn load_project(&mut self, context: &mut impl LoadProjectContext) -> anyhow::Result<()> {
self.clear();
let effects = context.read_file::<Vec<Effect>>("effects")?;
profiling::scope!("EffectEngine::load_project");
tracing::debug!("load effect engine");
for effect in &effects {
self.effects.insert(effect.id, effect.clone());
}

Ok(())
}

fn save_project(&self, context: &mut impl SaveProjectContext) -> anyhow::Result<()> {
profiling::scope!("EffectEngine::save_project");
tracing::debug!("save effect engine");
let mut effects = Vec::with_capacity(self.effects.len());
for effect in self.effects.iter() {
effects.push(effect.value().clone());
}

context.write_file("effects", &effects)?;

Ok(())
}
}
1 change: 1 addition & 0 deletions crates/components/sequencer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod sequencer;
mod state;
mod value;
mod cue_preset;
mod project_loading;

#[cfg(test)]
mod tests {
Expand Down
1 change: 1 addition & 0 deletions crates/components/sequencer/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl Module for SequencerModule {
fn register(self, context: &mut impl ModuleContext) -> anyhow::Result<()> {
let sequencer = Sequencer::new();
context.provide_api(sequencer.clone());
context.add_project_handler(sequencer.clone());
context.provide(sequencer);
context.add_processor(SequenceProcessor);

Expand Down
27 changes: 27 additions & 0 deletions crates/components/sequencer/src/project_loading.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use mizer_module::*;
use crate::{Sequence, Sequencer};

impl ProjectHandler for Sequencer {
fn get_name(&self) -> &'static str {
"sequencer"
}

fn new_project(&mut self, context: &mut impl ProjectHandlerContext) -> anyhow::Result<()> {

Check warning on line 9 in crates/components/sequencer/src/project_loading.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `context`

warning: unused variable: `context` --> crates/components/sequencer/src/project_loading.rs:9:31 | 9 | fn new_project(&mut self, context: &mut impl ProjectHandlerContext) -> anyhow::Result<()> { | ^^^^^^^ help: if this is intentional, prefix it with an underscore: `_context` | = note: `#[warn(unused_variables)]` on by default
self.clear();

Ok(())
}

fn load_project(&mut self, context: &mut impl LoadProjectContext) -> anyhow::Result<()> {
let sequences = context.read_file::<Vec<Sequence>>("sequences")?;
self.load_sequences(sequences);

Ok(())
}

fn save_project(&self, context: &mut impl SaveProjectContext) -> anyhow::Result<()> {
context.write_file("sequences", self.sequences())?;

Ok(())
}
}
1 change: 1 addition & 0 deletions crates/components/surfaces/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub mod commands;
mod models;
mod module;
mod registry;
mod project_loading;
5 changes: 3 additions & 2 deletions crates/components/surfaces/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use mizer_message_bus::MessageBus;
use mizer_module::*;

use crate::project_loading::SurfaceProjectHandler;
use crate::registry::SurfaceRegistry;
use crate::Surface;

Expand All @@ -21,7 +21,8 @@ impl Module for SurfaceModule {
let api = SurfaceRegistryApi {
bus: registry.bus.clone(),
};
context.provide(registry);
context.provide(SurfaceProjectHandler);

context.provide_api(api);

Ok(())
Expand Down
45 changes: 45 additions & 0 deletions crates/components/surfaces/src/project_loading.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use mizer_module::{LoadProjectContext, ProjectHandler, ProjectHandlerContext, SaveProjectContext};
use crate::{Surface, SurfaceRegistry};

pub struct SurfaceProjectHandler;

impl ProjectHandler for SurfaceProjectHandler {
fn get_name(&self) -> &'static str {
"surfaces"
}

fn new_project(&mut self, context: &mut impl ProjectHandlerContext) -> anyhow::Result<()> {
let Some(registry) = context.try_get_mut::<SurfaceRegistry>() else {
context.report_issue("Unable to load surfaces");

return Ok(());
};
registry.clear_surfaces();

Ok(())
}

fn load_project(&mut self, context: &mut impl LoadProjectContext) -> anyhow::Result<()> {
let surfaces = context.read_file::<Vec<Surface>>("surfaces")?;
let Some(registry) = context.try_get_mut::<SurfaceRegistry>() else {
context.report_issue("Unable to load surfaces");

return Ok(());
};
registry.clear_surfaces();
registry.add_surfaces(surfaces);

Ok(())
}

fn save_project(&self, context: &mut impl SaveProjectContext) -> anyhow::Result<()> {
let Some(registry) = context.try_get_mut::<SurfaceRegistry>() else {
context.report_issue("Unable to load surfaces");

return Ok(());
};
context.write_file("surfaces", registry.list_surfaces())?;

Check failure on line 41 in crates/components/surfaces/src/project_loading.rs

View workflow job for this annotation

GitHub Actions / clippy

cannot borrow `*context` as mutable more than once at a time

error[E0499]: cannot borrow `*context` as mutable more than once at a time --> crates/components/surfaces/src/project_loading.rs:41:9 | 36 | let Some(registry) = context.try_get_mut::<SurfaceRegistry>() else { | ------- first mutable borrow occurs here ... 41 | context.write_file("surfaces", registry.list_surfaces())?; | ^^^^^^^ -------- first borrow later used here | | | second mutable borrow occurs here

Ok(())
}
}
4 changes: 2 additions & 2 deletions crates/mizer/src/api/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ impl ApiHandler {
}
ApiCommand::NewProject(sender) => {
profiling::scope!("ApiCommand::NewProject");
mizer.new_project();
let result = mizer.new_project();
sender
.send(Ok(()))
.send(result)
.expect("api command sender disconnected");
}
ApiCommand::LoadProject(path, sender) => {
Expand Down
1 change: 1 addition & 0 deletions crates/mizer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ mod flags;
mod mizer;
mod module_context;
mod runtime_builder;
mod project_handler;
Loading

0 comments on commit 66dbb21

Please sign in to comment.