diff --git a/Cargo.toml b/Cargo.toml index 6784941..785f875 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ rand = "0.9.1" regex = "1.11.1" ron = "0.8" serde = "1.0.219" +rfd = "0.15.4" diff --git a/src/complex.rs b/src/complex.rs index 1cb5599..e6470fb 100644 --- a/src/complex.rs +++ b/src/complex.rs @@ -5,7 +5,7 @@ use std::fs::File; use std::io; use std::io::Read; -use crate::controller::ExportedProject; +use omagari::controller::ExportedProject; struct PreparedEffect { name: String, diff --git a/src/controller.rs b/src/controller.rs index 58e7f43..d8e5cfa 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -1,33 +1,15 @@ use bevy::{platform::collections::HashMap, prelude::*}; use bevy_hanabi::prelude::*; -use ron::{de::from_str, ser::PrettyConfig}; -use serde::{Deserialize, Serialize}; +use ron::de::from_str; use std::{ cell::RefCell, fs::File, - io::{self, Read, Write}, + io::{self, Read}, rc::Rc, }; -use crate::{effect::*, AppContext}; - -#[derive(Resource, Serialize, Deserialize, Default)] -pub struct OmagariProject { - pub effects: Vec, -} - -#[derive(Resource, Serialize, Deserialize, Default)] -pub struct ExportedEffect { - pub name: String, - pub parent: Option, - pub texture_index: Option, - pub effect_asset: EffectAsset, -} - -#[derive(Resource, Serialize, Deserialize, Default)] -pub struct ExportedProject { - pub effects: Vec, -} +use crate::OmagariProject; +use crate::editor_prelude::AppContext; #[derive(Resource)] pub struct EffectResource { @@ -72,50 +54,6 @@ pub fn spawn_particle_effects( } } -pub fn export_effects_to_files(filename: &str, clone: Rc>) { - let base = filename.split('.').next().unwrap(); - let other_filename = format!("{}.hanabi.ron", base); - let mut to_export = ExportedProject::default(); - for effect in clone.borrow().effects.iter() { - to_export.effects.push(ExportedEffect { - name: effect.name().to_string(), - parent: effect.parent().clone(), - texture_index: effect.texture_index(), - effect_asset: effect.produce(), - }); - } - let ron_string = - ron::ser::to_string_pretty(&to_export, PrettyConfig::new().new_line("\n".to_string())) - .unwrap(); - let mut file = File::create(&other_filename).unwrap(); - file.write_all(ron_string.as_bytes()).unwrap(); -} - -pub fn projects_list() -> Vec { - let mut files = Vec::new(); - let entries = std::fs::read_dir(".").unwrap(); - for entry in entries { - let entry = entry.unwrap(); - let filename = entry.file_name(); - if filename.to_string_lossy().ends_with(".omagari.ron") { - files.push(filename.to_string_lossy().into_owned()); - } - } - files -} - -pub fn load_project(filename: &str) -> Result { - let mut file = File::open(filename)?; - let mut ron_string = String::new(); - file.read_to_string(&mut ron_string)?; - let graph: OmagariProject = - from_str(&ron_string).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - Ok(graph) -} - -pub fn validate_project_filename(filename: &str) -> bool { - regex::Regex::new(r".*\.omagari\.ron") - .unwrap() - .captures(&filename) - .is_some() +pub fn validate_project_filename>(p: P) -> bool { + p.as_ref().ends_with("omagari.ron") } diff --git a/src/effect.rs b/src/effect.rs index 4cbb48d..2928df5 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -5,11 +5,11 @@ use bevy_hanabi::prelude::*; use serde::Deserialize; use serde::Serialize; +use crate::editor_prelude::AppContext; use crate::helpers::*; use crate::modifiers::ModifierProducer; use crate::modifiers::RenderModifierProducer; use crate::modifiers::*; -use crate::AppContext; fn ui_for_modifiers_list( app: &mut AppContext, diff --git a/src/expr.rs b/src/expr.rs index f23555b..377b4b0 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -5,8 +5,8 @@ use bevy_hanabi::prelude::*; use serde::Deserialize; use serde::Serialize; +use crate::editor_prelude::AppContext; use crate::helpers::*; -use crate::AppContext; pub const ALL_ATTRS: [(Attribute, &str); 39] = [ (Attribute::ID, "ID"), diff --git a/src/helpers.rs b/src/helpers.rs index d721c8e..e43506f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_egui::*; -use crate::AppContext; +use crate::editor_prelude::AppContext; pub trait UiProvider { fn draw_ui(&mut self, app: &mut AppContext, ui: &mut egui::Ui, index: u64); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e310f44 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,79 @@ +use bevy::prelude::*; +use bevy_hanabi::prelude::*; +use serde::{Deserialize, Serialize}; + +pub mod controller; +pub mod effect; +pub mod expr; +pub mod helpers; +pub mod modifiers; + +use effect::EffectEditor; +use std::io::{self, Read}; + +#[derive(Resource, Serialize, Deserialize, Default)] +pub struct OmagariProject { + pub effects: Vec, +} + +impl OmagariProject { + pub fn load>(p: P) -> Result { + let mut file = std::fs::File::open(p)?; + let mut ron_string = String::new(); + file.read_to_string(&mut ron_string)?; + let graph: OmagariProject = ron::de::from_str(&ron_string) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + Ok(graph) + } +} + +impl From for OmagariBundle { + fn from(project: OmagariProject) -> Self { + Self { + effects: project + .effects + .iter() + .map(|e| OmagariEffect { + texture_asset: "effects/cloud2.png".to_string(), + effect: e.produce(), + }) + .collect(), + } + } +} + +pub struct OmagariEffect { + pub texture_asset: String, + pub effect: EffectAsset, + // For setting parenting for hanabi + // is_child: bool, +} + +pub struct OmagariBundle { + pub effects: Vec, +} + +pub mod prelude { + pub use super::OmagariProject; +} + +pub mod editor_prelude { + use std::path::PathBuf; + + pub use super::controller::*; + pub use super::effect::*; + pub use super::expr::*; + pub use super::helpers::*; + pub use super::modifiers::*; + + pub use super::OmagariProject; + + use super::expr::ExprWriterEditor; + + #[derive(Default)] + pub struct AppContext { + pub expr_clipboard: Option, + pub visible_effects: Vec, + pub filename: Option, + } +} diff --git a/src/main.rs b/src/main.rs index 021a6f1..c15b2fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,25 +8,16 @@ use bevy::{ use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin}; use bevy_egui::{ - egui::{self, scroll_area::ScrollBarVisibility, Layout}, EguiContext, EguiContexts, EguiGlobalSettings, EguiPlugin, EguiPrimaryContextPass, PrimaryEguiContext, + egui::{self, Layout, scroll_area::ScrollBarVisibility}, }; use bevy_hanabi::prelude::*; use ron::ser::PrettyConfig; use std::fs::File; use std::io::Write; -mod controller; -mod effect; -mod expr; -mod helpers; -mod modifiers; - -use crate::controller::*; -use crate::effect::*; -use crate::expr::*; -use crate::helpers::*; +use omagari::editor_prelude::*; fn main() { App::new() @@ -78,13 +69,6 @@ fn setup( }); } -#[derive(Default)] -struct AppContext { - expr_clipboard: Option, - visible_effects: Vec, - filename: Option, -} - fn app_ui( mut commands: Commands, mut contexts: EguiContexts, @@ -108,9 +92,9 @@ fn app_ui( let mut filename = res .context .filename - .as_ref() - .unwrap_or(&"".to_string()) - .clone(); + .clone() + .map(|x| x.display().to_string()) + .unwrap_or(String::new()); egui::TopBottomPanel::top("Toolbar") .resizable(false) @@ -128,10 +112,6 @@ fn app_ui( ); } - if ui.button("🖭 EXPORT").clicked() { - export_effects_to_files(&filename, project.clone()); - } - ui.add_space(10.0); ui.separator(); ui.add_space(10.0); @@ -148,7 +128,7 @@ fn app_ui( } filename_textedit.show(ui); - res.context.filename = Some(filename.clone()); + res.context.filename = Some(std::path::PathBuf::from(&filename)); if ui.button("🌌 NEW").clicked() { res.context.filename = None; @@ -156,13 +136,16 @@ fn app_ui( } ui.menu_button("⮉ LOAD", |ui| { - for f in projects_list() { - if ui.button(f.clone()).clicked() { - if let Ok(project) = load_project(&f) { - commands.insert_resource(project); - res.context.filename = Some(f.clone()); - ui.close_menu(); - } + let files = rfd::FileDialog::new() + .add_filter("omagari", &["omagari.ron"]) + .set_directory(".") + .pick_file(); + + if let Some(path) = files { + if let Ok(project) = OmagariProject::load(&path) { + commands.insert_resource(project); + res.context.filename = Some(path.clone()); + ui.close_menu(); } } }); @@ -176,7 +159,7 @@ fn app_ui( ) .unwrap(); - if let Ok(mut file) = File::create(filename) { + if let Ok(mut file) = File::create(&filename) { file.write_all(ron_string.as_bytes()).unwrap(); } } diff --git a/src/modifiers.rs b/src/modifiers.rs index 8002575..f9216d8 100644 --- a/src/modifiers.rs +++ b/src/modifiers.rs @@ -4,9 +4,9 @@ use bevy_hanabi::prelude::*; use serde::Deserialize; use serde::Serialize; +use crate::editor_prelude::AppContext; use crate::expr::*; use crate::helpers::*; -use crate::AppContext; pub trait ModifierProducer where