diff --git a/creator/src/editor.rs b/creator/src/editor.rs index f8a2b3b7..5955086a 100644 --- a/creator/src/editor.rs +++ b/creator/src/editor.rs @@ -1309,13 +1309,17 @@ impl TheTrait for Editor { if id.name == "Undo" { manager.undo( self.server_ctx.curr_region, + &mut self.server_ctx, &mut self.project, + ui, ctx, ); } else { manager.redo( self.server_ctx.curr_region, + &mut self.server_ctx, &mut self.project, + ui, ctx, ); } @@ -1325,20 +1329,32 @@ impl TheTrait for Editor { self.server.update_region(region); RENDERER.lock().unwrap().set_region(region); } - } else if manager.context == UndoManagerContext::ModelFX { + } else if manager.context == UndoManagerContext::MaterialFX { if id.name == "Undo" { - manager.undo(Uuid::nil(), &mut self.project, ctx); + manager.undo( + Uuid::nil(), + &mut self.server_ctx, + &mut self.project, + ui, + ctx, + ); } else { - manager.redo(Uuid::nil(), &mut self.project, ctx); + manager.redo( + Uuid::nil(), + &mut self.server_ctx, + &mut self.project, + ui, + ctx, + ); } - let mut model_editor = MODELFXEDITOR.lock().unwrap(); - model_editor.modelfx.draw(ui, ctx, &self.project.palette); + //let mut model_editor = MODELFXEDITOR.lock().unwrap(); + //model_editor.modelfx.draw(ui, ctx, &self.project.palette); // model_editor.set_selected_node_ui( // ui, // ctx, // &self.project.palette, // ); - model_editor.render_preview(ui, &self.project.palette); + //model_editor.render_preview(ui, &self.project.palette); } } diff --git a/creator/src/main.rs b/creator/src/main.rs index 952b490c..e4e23e76 100644 --- a/creator/src/main.rs +++ b/creator/src/main.rs @@ -41,7 +41,7 @@ pub mod prelude { pub use crate::tilefxeditor::*; pub use crate::tilemapeditor::*; pub use crate::tilepicker::*; - pub use crate::undo::modelfx_undo::*; + pub use crate::undo::materialfx_undo::*; pub use crate::undo::region_undo::*; pub use crate::undo::*; } diff --git a/creator/src/modelfxeditor.rs b/creator/src/modelfxeditor.rs index 79859076..e2f0716e 100644 --- a/creator/src/modelfxeditor.rs +++ b/creator/src/modelfxeditor.rs @@ -1,4 +1,4 @@ -use crate::editor::{PRERENDERTHREAD, SIDEBARMODE, TILEDRAWER, UNDOMANAGER}; +use crate::editor::{PRERENDERTHREAD, TILEDRAWER, UNDOMANAGER}; use crate::prelude::*; #[derive(Debug, Clone, Copy, PartialEq)] @@ -20,7 +20,6 @@ pub struct ModelFXEditor { pub geos: FxHashMap<(i32, i32), GeoFXNode>, pub materials: FxHashMap<(i32, i32), Uuid>, - pub modelfx: ModelFX, pub editing_mode: EditingMode, pub current_material: Option, @@ -36,7 +35,6 @@ impl ModelFXEditor { geos: FxHashMap::default(), materials: FxHashMap::default(), - modelfx: ModelFX::default(), editing_mode: EditingMode::Geometry, current_material: None, @@ -277,6 +275,7 @@ impl ModelFXEditor { let node = MaterialFXNode::new(MaterialFXNodeRole::Geometry); material.nodes.push(node); material.selected_node = Some(material.nodes.len() - 1); + material.render_preview(&project.palette); PRERENDERTHREAD .lock() @@ -291,6 +290,10 @@ impl ModelFXEditor { // ); // } let material_id = material.id; + + let undo = MaterialFXUndoAtom::AddMaterial(material.clone()); + UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); + project.materials.insert(material.id, material); server_ctx.curr_material_object = Some(material_id); self.set_material_tiles(ui, ctx, project, Some(material_id)); @@ -300,19 +303,19 @@ impl ModelFXEditor { .unwrap() .set_materials(project.materials.clone()); } else if id.name == "ModelFX Clear" && state == &TheWidgetState::Clicked { - self.modelfx = ModelFX::default(); - self.modelfx.draw(ui, ctx, &project.palette); - self.render_preview(ui, &project.palette); + // self.modelfx = ModelFX::default(); + // self.modelfx.draw(ui, ctx, &project.palette); + // self.render_preview(ui, &project.palette); redraw = true; } else if id.name == "ModelFX Move" && state == &TheWidgetState::Clicked { - if !self.modelfx.nodes.is_empty() { - project.models.push(self.modelfx.clone()); - ctx.ui.send(TheEvent::Custom( - TheId::named("ModelFX Redraw Library"), - TheValue::Empty, - )); - self.redraw_modelfx_library(project, ui, ctx); - } + // if !self.modelfx.nodes.is_empty() { + // project.models.push(self.modelfx.clone()); + // ctx.ui.send(TheEvent::Custom( + // TheId::named("ModelFX Redraw Library"), + // TheValue::Empty, + // )); + // self.redraw_modelfx_library(project, ui, ctx); + // } redraw = true; } } @@ -321,23 +324,20 @@ impl ModelFXEditor { if self.editing_mode == EditingMode::MaterialNodes { if let Some(material_id) = server_ctx.curr_material_object { if let Some(material) = project.materials.get_mut(&material_id) { + let prev = material.to_json(); let material_id = material.id; let node = MaterialFXNode::new_from_name(item.name.clone()); material.nodes.push(node); material.selected_node = Some(material.nodes.len() - 1); + let undo = + MaterialFXUndoAtom::AddNode(material.id, prev, material.to_json()); + UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); let node_canvas = material.to_canvas(&project.palette); ui.set_node_canvas("MaterialFX NodeCanvas", node_canvas); self.set_material_tiles(ui, ctx, project, Some(material_id)); self.set_selected_material_node_ui(server_ctx, project, ui, ctx); } } - /* - self.modelfx.draw(ui, ctx, &project.palette); - self.update_node_canvas(&project.palette, ui); - self.set_selected_node_ui(server_ctx, project, ui, ctx); - self.render_preview(ui, &project.palette); - let undo = ModelFXUndoAtom::AddNode(prev, self.modelfx.to_json()); - UNDOMANAGER.lock().unwrap().add_modelfx_undo(undo, ctx);*/ redraw = true; } } @@ -349,90 +349,68 @@ impl ModelFXEditor { } else if id.name == "MaterialFX RGBA Layout View" { if let Some(material) = self.materials.get(&(coord.x, coord.y)) { server_ctx.curr_material_object = Some(*material); - - /* - let mut region_to_render: Option = None; - let mut tiles_to_render: Vec = vec![]; - - // Set the material to the current geometry node. - if let Some(curr_geo_node) = server_ctx.curr_geo_node { - if let Some(region) = project.get_region_mut(&server_ctx.curr_region) { - if let Some((geo_obj, _)) = region.find_geo_node(curr_geo_node) { - geo_obj.material_id = *material; - geo_obj.update_area(); - - tiles_to_render.clone_from(&geo_obj.area); - - server.update_region(region); - region_to_render = Some(region.clone()); - } - } - } - - // Render the region area covered by the object with the new material. - if let Some(region) = region_to_render { - PRERENDERTHREAD.lock().unwrap().render_region( - region, - project.palette.clone(), - tiles_to_render, - ); - }*/ } else { server_ctx.curr_material_object = None; + ui.set_node_canvas("MaterialFX NodeCanvas", TheNodeCanvas::default()); } self.set_material_node_ui(server_ctx, project, ui, ctx); + self.set_selected_material_node_ui(server_ctx, project, ui, ctx); redraw = true; } } - TheEvent::TileEditorClicked(id, coord) => { - if id.name == "GeoFX RGBA Layout View" && self.modelfx.clicked(*coord, ui, ctx) { + TheEvent::TileEditorClicked(id, _coord) => { + if id.name == "GeoFX RGBA Layout View" { + //&& self.modelfx.clicked(*coord, ui, ctx) { //self.modelfx.draw(ui, ctx, &project.palette); self.set_selected_material_node_ui(server_ctx, project, ui, ctx); - self.render_preview(ui, &project.palette); + //self.render_preview(ui, &project.palette); redraw = true; } } - TheEvent::TileEditorDragged(id, coord) => { - if id.name == "GeoFX RGBA Layout View" && self.modelfx.dragged(*coord, ui, ctx) { + TheEvent::TileEditorDragged(id, _coord) => { + if id.name == "GeoFX RGBA Layout View" { + //&& self.modelfx.dragged(*coord, ui, ctx) { //self.modelfx.draw(ui, ctx, &project.palette); redraw = true; } } TheEvent::TileEditorUp(id) => { //let prev = self.modelfx.to_json(); - if id.name == "GeoFX RGBA Layout View" && self.modelfx.released(ui, ctx) { + if id.name == "GeoFX RGBA Layout View" { + //&& self.modelfx.released(ui, ctx) { //self.modelfx.draw(ui, ctx, &project.palette); - self.render_preview(ui, &project.palette); + //self.render_preview(ui, &project.palette); //let undo = ModelFXUndoAtom::Edit(prev, self.modelfx.to_json()); //UNDOMANAGER.lock().unwrap().add_modelfx_undo(undo, ctx); redraw = true; } } - TheEvent::TileEditorHoverChanged(id, coord) => { - if id.name == "GeoFX RGBA Layout View" && self.modelfx.hovered(*coord, ui, ctx) { + TheEvent::TileEditorHoverChanged(id, _coord) => { + if id.name == "GeoFX RGBA Layout View" { + //&& self.modelfx.hovered(*coord, ui, ctx) { redraw = true; } } - TheEvent::TileEditorDelete(id, selected) => { - if id.name == "ModelFX Library RGBA Layout View" { - let prev = self.modelfx.to_json(); - for pos in selected { - let index = (pos.0 + pos.1 * 4) as usize; - project.models.remove(index); - } - self.redraw_modelfx_library(project, ui, ctx); - let undo = ModelFXUndoAtom::Edit(prev, self.modelfx.to_json()); - UNDOMANAGER.lock().unwrap().add_modelfx_undo(undo, ctx); - redraw = true; - } else if id.name == "GeoFX RGBA Layout View" { - let prev = self.modelfx.to_json(); - self.modelfx.delete(); - self.modelfx.draw(ui, ctx, &project.palette); - self.render_preview(ui, &project.palette); - let undo = ModelFXUndoAtom::Edit(prev, self.modelfx.to_json()); - UNDOMANAGER.lock().unwrap().add_modelfx_undo(undo, ctx); - redraw = true; - } + TheEvent::TileEditorDelete(_id, _selected) => { + // if id.name == "ModelFX Library RGBA Layout View" { + // let prev = self.modelfx.to_json(); + // for pos in selected { + // let index = (pos.0 + pos.1 * 4) as usize; + // project.models.remove(index); + // } + // self.redraw_modelfx_library(project, ui, ctx); + // let undo = MaterialFXUndoAtom::Edit(prev, self.modelfx.to_json()); + // UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); + // redraw = true; + // } else if id.name == "GeoFX RGBA Layout View" { + // let prev = self.modelfx.to_json(); + // self.modelfx.delete(); + // self.modelfx.draw(ui, ctx, &project.palette); + // self.render_preview(ui, &project.palette); + // let undo = MaterialFXUndoAtom::Edit(prev, self.modelfx.to_json()); + // UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); + // redraw = true; + // } } TheEvent::ColorButtonClicked(id) => { // When a color button is clicked, copy over the current palette index. @@ -450,10 +428,12 @@ impl ModelFXEditor { old_index = Some(index); } + let prev = material.to_json(); material.nodes[selected_index].set( name, TheValue::PaletteIndex(project.palette.current_index), ); + let next = material.to_json(); PRERENDERTHREAD .lock() @@ -494,13 +474,10 @@ impl ModelFXEditor { } } } - // self.modelfx.clear_previews(); - // self.modelfx.draw(ui, ctx, &project.palette); - // self.render_preview(ui, &project.palette); - // let undo = - // ModelFXUndoAtom::Edit(prev, self.modelfx.to_json()); - // UNDOMANAGER.lock().unwrap().add_modelfx_undo(undo, ctx); - // redraw = true; + + let undo = + MaterialFXUndoAtom::Edit(material_id, prev, next); + UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); } } } @@ -536,9 +513,9 @@ impl ModelFXEditor { } } } - self.modelfx.clear_previews(); - self.modelfx.draw(ui, ctx, &project.palette); - self.render_preview(ui, &project.palette); + // self.modelfx.clear_previews(); + // self.modelfx.draw(ui, ctx, &project.palette); + //self.render_preview(ui, &project.palette); } else if id.name.starts_with(":MODELFX:") { if let Some(name) = id.name.strip_prefix(":MODELFX: ") { let value = value.clone(); @@ -598,7 +575,9 @@ impl ModelFXEditor { if let Some(material_id) = server_ctx.curr_material_object { if let Some(material) = project.materials.get_mut(&material_id) { if let Some(selected_index) = material.selected_node { + let prev = material.to_json(); material.nodes[selected_index].set(name, value); + let next = material.to_json(); PRERENDERTHREAD .lock() @@ -616,6 +595,10 @@ impl ModelFXEditor { tiles_to_render = region.get_material_area(material_id); region_to_render = Some(region.clone()); } + + let undo = + MaterialFXUndoAtom::Edit(material_id, prev, next); + UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); } } } @@ -682,7 +665,10 @@ impl ModelFXEditor { } }*/ TheEvent::Custom(id, _) => { - if id.name == "Floor Selected" { + if id.name == "Update Materials" { + println!("Update Materials"); + self.set_material_tiles(ui, ctx, project, None); + } else if id.name == "Floor Selected" { if let Some(stack) = ui.get_stack_layout("ModelFX Stack Layout") { stack.set_index(0); redraw = true; @@ -748,7 +734,14 @@ impl ModelFXEditor { if id.name == "MaterialFX NodeCanvas" { if let Some(material_id) = server_ctx.curr_material_object { if let Some(material) = project.materials.get_mut(&material_id) { + let prev = material.to_json(); material.connections.clone_from(connections); + material.render_preview(&project.palette); + let undo = + MaterialFXUndoAtom::Edit(material.id, prev, material.to_json()); + UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); + self.set_material_tiles(ui, ctx, project, None); + redraw = true; } self.render_material_changes(material_id, server_ctx, project); } @@ -758,9 +751,15 @@ impl ModelFXEditor { if id.name == "MaterialFX NodeCanvas" { if let Some(material_id) = server_ctx.curr_material_object { if let Some(material) = project.materials.get_mut(&material_id) { + let prev = material.to_json(); material.nodes.remove(*deleted_node_index); material.node_previews.remove(*deleted_node_index); material.connections.clone_from(connections); + material.render_preview(&project.palette); + let undo = + MaterialFXUndoAtom::Edit(material.id, prev, material.to_json()); + UNDOMANAGER.lock().unwrap().add_materialfx_undo(undo, ctx); + self.set_material_tiles(ui, ctx, project, None); redraw = true; } self.render_material_changes(material_id, server_ctx, project); @@ -884,8 +883,7 @@ impl ModelFXEditor { let mut add_button = TheTraybarButton::new(TheId::named("MaterialFX Add")); add_button.set_text("Add Material".to_string()); - add_button - .set_status_text("Switches between an anim based preview and multi tiles preview."); + add_button.set_status_text("Add a new material"); text_layout.add_pair("".to_string(), Box::new(add_button)); @@ -980,6 +978,7 @@ impl ModelFXEditor { } } + /* pub fn render_preview(&mut self, ui: &mut TheUI, palette: &ThePalette) { self.modelfx.create_voxels(24, &Vec3f::zero(), palette); @@ -998,11 +997,11 @@ impl ModelFXEditor { let tile = TheRGBATile::buffer(buffer); icon_view.set_rgba_tile(tile); } - } + }*/ - pub fn get_model(&self) -> ModelFX { - self.modelfx.clone() - } + // pub fn get_model(&self) -> ModelFX { + // self.modelfx.clone() + // } /* pub fn set_model( @@ -1021,11 +1020,6 @@ impl ModelFXEditor { } */ - /// Update the node canvas - fn _update_node_canvas(&mut self, palette: &ThePalette, ui: &mut TheUI) { - ui.set_node_canvas("ModelFX NodeCanvas", self.modelfx.to_canvas(palette)); - } - /// Set the library models. pub fn redraw_modelfx_library( &mut self, @@ -1180,7 +1174,7 @@ impl ModelFXEditor { let mut buffer = TheRGBABuffer::new(TheDim::sized(width, max(lines * grid, height))); - let tile_buffer = TheRGBABuffer::new(TheDim::sized(tile_size, tile_size)); + // let tile_buffer = TheRGBABuffer::new(TheDim::sized(tile_size, tile_size)); for (i, (id, obj)) in project.materials.iter().enumerate() { let x = i as i32 % tiles_per_row; @@ -1208,7 +1202,7 @@ impl ModelFXEditor { }*/ //tile.preview(&mut tile_buffer); - buffer.copy_into(x * grid, y * grid, &tile_buffer); + buffer.copy_into(x * grid, y * grid, &obj.preview); self.materials.insert((x, y), *id); } @@ -1217,7 +1211,7 @@ impl ModelFXEditor { } } - fn render_material_changes( + pub fn render_material_changes( &mut self, material_id: Uuid, server_ctx: &mut ServerContext, diff --git a/creator/src/sidebar.rs b/creator/src/sidebar.rs index 20b2e98f..ebbbe3b3 100644 --- a/creator/src/sidebar.rs +++ b/creator/src/sidebar.rs @@ -2114,14 +2114,14 @@ impl Sidebar { SidebarMode::Model as usize, )); - MODELFXEDITOR - .lock() - .unwrap() - .render_preview(ui, &project.palette); - MODELFXEDITOR - .lock() - .unwrap() - .redraw_modelfx_library(project, ui, ctx); + // MODELFXEDITOR + // .lock() + // .unwrap() + // .render_preview(ui, &project.palette); + // MODELFXEDITOR + // .lock() + // .unwrap() + // .redraw_modelfx_library(project, ui, ctx); redraw = true; } else if id.name == "Debug Section" && *state == TheWidgetState::Selected { diff --git a/creator/src/tileeditor.rs b/creator/src/tileeditor.rs index 0b775dac..28b7753d 100644 --- a/creator/src/tileeditor.rs +++ b/creator/src/tileeditor.rs @@ -558,7 +558,7 @@ impl TileEditor { if id.name == "Region Editor View" || id.name == "RenderView" { UNDOMANAGER.lock().unwrap().context = UndoManagerContext::Region; } else if id.name == "ModelFX RGBA Layout View" { - UNDOMANAGER.lock().unwrap().context = UndoManagerContext::ModelFX; + UNDOMANAGER.lock().unwrap().context = UndoManagerContext::MaterialFX; } } TheEvent::StateChanged(id, _state) => { diff --git a/creator/src/undo/materialfx_undo.rs b/creator/src/undo/materialfx_undo.rs new file mode 100644 index 00000000..6806cbc4 --- /dev/null +++ b/creator/src/undo/materialfx_undo.rs @@ -0,0 +1,152 @@ +use crate::editor::MODELFXEDITOR; +use crate::prelude::*; +use theframework::prelude::*; + +#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] +pub enum MaterialFXUndoAtom { + AddMaterial(MaterialFXObject), + AddNode(Uuid, String, String), + Edit(Uuid, String, String), +} + +impl MaterialFXUndoAtom { + pub fn undo( + &self, + server_ctx: &mut ServerContext, + project: &mut Project, + ui: &mut TheUI, + ctx: &mut TheContext, + ) { + match self { + MaterialFXUndoAtom::AddMaterial(material) => { + project.materials.shift_remove(&material.id); + if server_ctx.curr_material_object == Some(material.id) { + server_ctx.curr_material_object = None; + } + + let mut editor = MODELFXEDITOR.lock().unwrap(); + editor.set_material_tiles(ui, ctx, project, None); + editor.set_material_node_ui(server_ctx, project, ui, ctx); + } + MaterialFXUndoAtom::AddNode(id, prev, _) | MaterialFXUndoAtom::Edit(id, prev, _) => { + if let Some(material) = project.materials.get_mut(id) { + *material = MaterialFXObject::from_json(prev); + material.render_preview(&project.palette); + + let node_canvas = material.to_canvas(&project.palette); + ui.set_node_canvas("MaterialFX NodeCanvas", node_canvas); + + let mut editor = MODELFXEDITOR.lock().unwrap(); + editor.set_material_tiles(ui, ctx, project, None); + editor.set_material_node_ui(server_ctx, project, ui, ctx); + editor.set_selected_material_node_ui(server_ctx, project, ui, ctx); + editor.render_material_changes(*id, server_ctx, project); + } + } + } + } + pub fn redo( + &self, + server_ctx: &mut ServerContext, + project: &mut Project, + ui: &mut TheUI, + ctx: &mut TheContext, + ) { + match self { + MaterialFXUndoAtom::AddMaterial(material) => { + project.materials.insert(material.id, material.clone()); + } + MaterialFXUndoAtom::AddNode(id, _, next) | MaterialFXUndoAtom::Edit(id, _, next) => { + if let Some(material) = project.materials.get_mut(id) { + *material = MaterialFXObject::from_json(next); + material.render_preview(&project.palette); + + let node_canvas = material.to_canvas(&project.palette); + ui.set_node_canvas("MaterialFX NodeCanvas", node_canvas); + + let mut editor = MODELFXEDITOR.lock().unwrap(); + editor.set_material_tiles(ui, ctx, project, None); + editor.set_material_node_ui(server_ctx, project, ui, ctx); + editor.set_selected_material_node_ui(server_ctx, project, ui, ctx); + editor.render_material_changes(*id, server_ctx, project); + } + } + } + } +} + +#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] +pub struct MaterialFXUndo { + pub stack: Vec, + pub index: isize, +} + +impl Default for MaterialFXUndo { + fn default() -> Self { + Self::new() + } +} + +impl MaterialFXUndo { + pub fn new() -> Self { + Self { + stack: vec![], + index: -1, + } + } + + pub fn is_empty(&self) -> bool { + self.stack.is_empty() + } + + pub fn clear(&mut self) { + self.stack = vec![]; + self.index = -1; + } + + pub fn has_undo(&self) -> bool { + self.index >= 0 + } + + pub fn has_redo(&self) -> bool { + if self.index >= -1 && self.index < self.stack.len() as isize - 1 { + return true; + } + false + } + + pub fn add(&mut self, atom: MaterialFXUndoAtom) { + let to_remove = self.stack.len() as isize - self.index - 1; + for _i in 0..to_remove { + self.stack.pop(); + } + self.stack.push(atom); + self.index += 1; + } + + pub fn undo( + &mut self, + server_ctx: &mut ServerContext, + project: &mut Project, + ui: &mut TheUI, + ctx: &mut TheContext, + ) { + if self.index >= 0 { + self.stack[self.index as usize].undo(server_ctx, project, ui, ctx); + self.index -= 1; + } + } + + pub fn redo( + &mut self, + server_ctx: &mut ServerContext, + project: &mut Project, + ui: &mut TheUI, + ctx: &mut TheContext, + ) { + if self.index < self.stack.len() as isize - 1 { + self.index += 1; + self.stack[self.index as usize].redo(server_ctx, project, ui, ctx); + } + } +} diff --git a/creator/src/undo/mod.rs b/creator/src/undo/mod.rs index 9fa6f4df..d138eb17 100644 --- a/creator/src/undo/mod.rs +++ b/creator/src/undo/mod.rs @@ -1,17 +1,17 @@ -pub mod modelfx_undo; +pub mod materialfx_undo; pub mod region_undo; use crate::prelude::*; -use crate::editor::MODELFXEDITOR; +//use crate::editor::MODELFXEDITOR; -use self::modelfx_undo::ModelFXUndo; +use self::materialfx_undo::MaterialFXUndo; #[derive(PartialEq, Clone, Debug)] pub enum UndoManagerContext { None, Region, - ModelFX, + MaterialFX, CodeGridFX, } @@ -20,7 +20,7 @@ pub struct UndoManager { pub context: UndoManagerContext, regions: FxHashMap, - modelfx: ModelFXUndo, + materialfx: MaterialFXUndo, } impl Default for UndoManager { @@ -35,7 +35,7 @@ impl UndoManager { context: UndoManagerContext::None, regions: FxHashMap::default(), - modelfx: ModelFXUndo::default(), + materialfx: MaterialFXUndo::default(), } } @@ -47,14 +47,21 @@ impl UndoManager { self.can_save(ctx); } - pub fn add_modelfx_undo(&mut self, atom: ModelFXUndoAtom, ctx: &mut TheContext) { - self.context = UndoManagerContext::ModelFX; - self.modelfx.add(atom); + pub fn add_materialfx_undo(&mut self, atom: MaterialFXUndoAtom, ctx: &mut TheContext) { + self.context = UndoManagerContext::MaterialFX; + self.materialfx.add(atom); ctx.ui.set_enabled("Undo"); self.can_save(ctx); } - pub fn undo(&mut self, context_id: Uuid, project: &mut Project, ctx: &mut TheContext) { + pub fn undo( + &mut self, + context_id: Uuid, + server_ctx: &mut ServerContext, + project: &mut Project, + ui: &mut TheUI, + ctx: &mut TheContext, + ) { match &self.context { UndoManagerContext::None => {} UndoManagerContext::Region => { @@ -79,17 +86,16 @@ impl UndoManager { } } } - UndoManagerContext::ModelFX => { - self.modelfx - .undo(&mut MODELFXEDITOR.lock().unwrap().modelfx); + UndoManagerContext::MaterialFX => { + self.materialfx.undo(server_ctx, project, ui, ctx); - if !self.modelfx.has_undo() { + if !self.materialfx.has_undo() { ctx.ui.set_disabled("Undo"); } else { ctx.ui.set_enabled("Undo"); } - if !self.modelfx.has_redo() { + if !self.materialfx.has_redo() { ctx.ui.set_disabled("Redo"); } else { ctx.ui.set_enabled("Redo"); @@ -100,7 +106,14 @@ impl UndoManager { self.can_save(ctx); } - pub fn redo(&mut self, context_id: Uuid, project: &mut Project, ctx: &mut TheContext) { + pub fn redo( + &mut self, + context_id: Uuid, + server_ctx: &mut ServerContext, + project: &mut Project, + ui: &mut TheUI, + ctx: &mut TheContext, + ) { match &self.context { UndoManagerContext::None => {} UndoManagerContext::Region => { @@ -125,17 +138,16 @@ impl UndoManager { } } } - UndoManagerContext::ModelFX => { - self.modelfx - .redo(&mut MODELFXEDITOR.lock().unwrap().modelfx); + UndoManagerContext::MaterialFX => { + self.materialfx.redo(server_ctx, project, ui, ctx); - if !self.modelfx.has_undo() { + if !self.materialfx.has_undo() { ctx.ui.set_disabled("Undo"); } else { ctx.ui.set_enabled("Undo"); } - if !self.modelfx.has_redo() { + if !self.materialfx.has_redo() { ctx.ui.set_disabled("Redo"); } else { ctx.ui.set_enabled("Redo"); @@ -168,7 +180,7 @@ impl UndoManager { } /// Clears the ModelFX undo. - pub fn clear_modelfx(&mut self) { - self.modelfx.clear(); + pub fn clear_materialfx(&mut self) { + self.materialfx.clear(); } } diff --git a/creator/src/undo/modelfx_undo.rs b/creator/src/undo/modelfx_undo.rs deleted file mode 100644 index 99040a46..00000000 --- a/creator/src/undo/modelfx_undo.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::prelude::*; -use theframework::prelude::*; - -#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] -pub enum ModelFXUndoAtom { - AddNode(String, String), - Edit(String, String), -} - -impl ModelFXUndoAtom { - pub fn undo(&self, model: &mut ModelFX) { - match self { - ModelFXUndoAtom::AddNode(prev, _) | ModelFXUndoAtom::Edit(prev, _) => { - *model = ModelFX::from_json(prev); - } - } - } - pub fn redo(&self, model: &mut ModelFX) { - match self { - ModelFXUndoAtom::AddNode(_, next) | ModelFXUndoAtom::Edit(_, next) => { - *model = ModelFX::from_json(next); - } - } - } -} - -#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] -pub struct ModelFXUndo { - pub stack: Vec, - pub index: isize, -} - -impl Default for ModelFXUndo { - fn default() -> Self { - Self::new() - } -} - -impl ModelFXUndo { - pub fn new() -> Self { - Self { - stack: vec![], - index: -1, - } - } - - pub fn is_empty(&self) -> bool { - self.stack.is_empty() - } - - pub fn clear(&mut self) { - self.stack = vec![]; - self.index = -1; - } - - pub fn has_undo(&self) -> bool { - self.index >= 0 - } - - pub fn has_redo(&self) -> bool { - if self.index >= -1 && self.index < self.stack.len() as isize - 1 { - return true; - } - false - } - - pub fn add(&mut self, atom: ModelFXUndoAtom) { - let to_remove = self.stack.len() as isize - self.index - 1; - for _i in 0..to_remove { - self.stack.pop(); - } - self.stack.push(atom); - self.index += 1; - } - - pub fn undo(&mut self, model: &mut ModelFX) { - if self.index >= 0 { - self.stack[self.index as usize].undo(model); - self.index -= 1; - } - } - - pub fn redo(&mut self, model: &mut ModelFX) { - if self.index < self.stack.len() as isize - 1 { - self.index += 1; - self.stack[self.index as usize].redo(model); - } - } -} diff --git a/shared/src/materialfxobject.rs b/shared/src/materialfxobject.rs index 7bfb6f01..0f3993a2 100644 --- a/shared/src/materialfxobject.rs +++ b/shared/src/materialfxobject.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use rayon::prelude::*; use theframework::prelude::*; /// A character instance. @@ -20,6 +21,8 @@ pub struct MaterialFXObject { pub zoom: f32, pub selected_node: Option, + pub preview: TheRGBABuffer, + #[serde(default = "Vec2i::zero")] pub scroll_offset: Vec2i, } @@ -44,6 +47,8 @@ impl MaterialFXObject { zoom: 1.0, selected_node: None, + preview: TheRGBABuffer::empty(), + scroll_offset: Vec2i::zero(), } } @@ -211,4 +216,122 @@ impl MaterialFXObject { canvas } + + pub fn render_preview(&mut self, palette: &ThePalette) { + let size: usize = 48; + let mut buffer = TheRGBABuffer::new(TheDim::sized(size as i32, size as i32)); + + fn distance(p: Vec3f) -> f32 { + length(p) - 1.8 + } + + pub fn normal(p: Vec3f) -> Vec3f { + let scale = 0.5773 * 0.0005; + let e = vec2f(1.0 * scale, -1.0 * scale); + + // IQs normal function + + let e1 = vec3f(e.x, e.y, e.y); + let e2 = vec3f(e.y, e.y, e.x); + let e3 = vec3f(e.y, e.x, e.y); + let e4 = vec3f(e.x, e.x, e.x); + + let n = e1 * distance(p + e1) + + e2 * distance(p + e2) + + e3 * distance(p + e3) + + e4 * distance(p + e4); + normalize(n) + } + + let ro = vec3f(2.0, 2.0, 2.0); + let rd = vec3f(0.0, 0.0, 0.0); + + let aa = 2; + let aa_f = aa as f32; + + let camera = Camera::new(ro, rd, 80.0); + let bgc = 74.0 / 255.0; + + buffer + .pixels_mut() + .par_rchunks_exact_mut(size * 4) + .enumerate() + .for_each(|(j, line)| { + let mut hit = Hit::default(); + + for (i, pixel) in line.chunks_exact_mut(4).enumerate() { + let i = j * size + i; + + let xx = (i % size) as f32; + let yy = (i / size) as f32; + + let mut total = Vec4f::zero(); + + for m in 0..aa { + for n in 0..aa { + let camera_offset = + vec2f(m as f32 / aa_f, n as f32 / aa_f) - vec2f(0.5, 0.5); + + let mut color = vec4f(bgc, bgc, bgc, 1.0); + + let ray = camera.create_ray( + vec2f(xx / size as f32, 1.0 - yy / size as f32), + vec2f(size as f32, size as f32), + camera_offset, + ); + + let mut t = 0.001; + + for _ in 0..20 { + let p = ray.at(t); + let d = distance(p); + if d.abs() < 0.001 { + hit.hit_point = p; + hit.normal = normal(p); + + for (i, node) in self.nodes.iter().enumerate() { + if node.role == MaterialFXNodeRole::Geometry { + self.follow_trail(i, 0, &mut hit, palette); + + color.x += hit.albedo.x; + color.y += hit.albedo.y; + color.z += hit.albedo.z; + break; + } + } + + break; + } + t += d; + } + total += color; + } + } + + let aa_aa = aa_f * aa_f; + total[0] /= aa_aa; + total[1] /= aa_aa; + total[2] /= aa_aa; + total[3] /= aa_aa; + + pixel.copy_from_slice(&TheColor::from_vec4f(total).to_u8_array()); + } + }); + self.preview = buffer; + } + + /// Load a model from a JSON string. + pub fn from_json(json: &str) -> Self { + let mut material: MaterialFXObject = serde_json::from_str(json).unwrap_or_default(); + let cnt = material.nodes.len(); + for _ in 0..cnt { + material.node_previews.push(None); + } + material + } + + /// Convert the model to a JSON string. + pub fn to_json(&self) -> String { + serde_json::to_string(&self).unwrap_or_default() + } }