diff --git a/editor/src/inspector/editors/mod.rs b/editor/src/inspector/editors/mod.rs index ca20f6150..2d1e71cfb 100644 --- a/editor/src/inspector/editors/mod.rs +++ b/editor/src/inspector/editors/mod.rs @@ -98,6 +98,7 @@ use crate::{ }, message::MessageSender, }; +use fyrox::scene::tilemap::brush::{TileMapBrush, TileMapBrushResource}; use std::{path::Path, sync::Arc}; pub mod animation; @@ -341,6 +342,22 @@ pub fn make_property_editors_container(sender: MessageSender) -> PropertyEditorD container.insert(InheritablePropertyEditorDefinition::>::new()); container.register_inheritable_vec_collection::>(); + container.insert(ResourceFieldPropertyEditorDefinition::::new( + Arc::new(Mutex::new( + |resource_manager: &ResourceManager, path: &Path| { + resource_manager + .try_request::(path) + .map(block_on) + }, + )), + sender.clone(), + )); + container.insert(InheritablePropertyEditorDefinition::< + Option, + >::new()); + container.register_inheritable_vec_collection::>(); + container.register_inheritable_inspectable::(); + container.register_inheritable_inspectable::(); container.register_inheritable_inspectable::(); diff --git a/editor/src/plugins/tilemap/mod.rs b/editor/src/plugins/tilemap/mod.rs index 4878a952f..b1039cfd3 100644 --- a/editor/src/plugins/tilemap/mod.rs +++ b/editor/src/plugins/tilemap/mod.rs @@ -1,4 +1,3 @@ -pub mod brush; pub mod palette; pub mod panel; pub mod tile_set_import; @@ -25,18 +24,13 @@ use crate::{ scene::{ debug::Line, node::Node, - tilemap::{Tile, TileMap, Tiles}, + tilemap::{brush::TileMapBrush, Tile, TileMap, Tiles}, }, }, interaction::{make_interaction_mode_button, InteractionMode}, message::MessageSender, plugin::EditorPlugin, - plugins::tilemap::{ - brush::{TileMapBrush, TileMapBrushLoader}, - palette::PaletteMessage, - panel::TileMapPanel, - tileset::TileSetEditor, - }, + plugins::tilemap::{palette::PaletteMessage, panel::TileMapPanel, tileset::TileSetEditor}, scene::{commands::GameSceneContext, controller::SceneController, GameScene, Selection}, settings::Settings, Editor, Message, @@ -256,17 +250,37 @@ pub struct TileMapEditorPlugin { } impl EditorPlugin for TileMapEditorPlugin { - fn on_start(&mut self, editor: &mut Editor) { - let mut resource_manager = editor.engine.resource_manager.state(); - resource_manager - .constructors_container - .add::(); - resource_manager.loaders.set(TileMapBrushLoader {}); - } - fn on_sync_to_model(&mut self, editor: &mut Editor) { + let ui = editor.engine.user_interfaces.first_mut(); + if let Some(tile_set_editor) = self.tile_set_editor.as_mut() { - tile_set_editor.sync_to_model(editor.engine.user_interfaces.first_mut()); + tile_set_editor.sync_to_model(ui); + } + + let Some(entry) = editor.scenes.current_scene_entry_mut() else { + return; + }; + + let Some(selection) = entry.selection.as_graph() else { + return; + }; + + let Some(game_scene) = entry.controller.downcast_mut::() else { + return; + }; + + let scene = &mut editor.engine.scenes[game_scene.scene]; + + for node_handle in selection.nodes().iter() { + if let Some(tile_map_node) = scene.graph.try_get(*node_handle) { + let Some(tile_map) = tile_map_node.component_ref::() else { + continue; + }; + + if let Some(panel) = self.panel.as_mut() { + panel.sync_to_model(ui, tile_map); + } + } } } @@ -283,7 +297,7 @@ impl EditorPlugin for TileMapEditorPlugin { } if let Some(panel) = self.panel.take() { - if let Some(PaletteMessage::Brush(brush)) = message.data() { + if let Some(PaletteMessage::ActiveBrush(brush)) = message.data() { if message.destination() == panel.palette { *self.brush.lock() = brush.clone(); } @@ -347,7 +361,8 @@ impl EditorPlugin for TileMapEditorPlugin { self.panel = Some(TileMapPanel::new( &mut ui.build_ctx(), editor.scene_viewer.frame(), - tile_map.tile_set().cloned(), + editor.engine.resource_manager.clone(), + tile_map, )); break; diff --git a/editor/src/plugins/tilemap/palette.rs b/editor/src/plugins/tilemap/palette.rs index 1a6f583ce..3d28662fa 100644 --- a/editor/src/plugins/tilemap/palette.rs +++ b/editor/src/plugins/tilemap/palette.rs @@ -1,10 +1,12 @@ use crate::{ absm::selectable::{Selectable, SelectableMessage}, + asset::item::AssetItem, fyrox::{ + asset::manager::ResourceManager, core::{ algebra::{Matrix3, Point2, Vector2}, color::Color, - math::Rect, + math::{OptionRect, Rect}, pool::Handle, reflect::prelude::*, type_traits::prelude::*, @@ -19,20 +21,27 @@ use crate::{ widget::{Widget, WidgetBuilder, WidgetMessage}, BuildContext, Control, UiNode, UserInterface, }, - scene::tilemap::tileset::TileSetResource, + scene::tilemap::{ + brush::{BrushTile, TileMapBrush, TileMapBrushResource}, + tileset::TileSetResource, + }, }, - plugins::tilemap::brush::{BrushTile, TileMapBrush}, }; -use fyrox::core::math::OptionRect; +use fyrox::core::log::Log; +use fyrox::scene::tilemap::tileset::TileSet; use std::ops::{Deref, DerefMut}; #[derive(Debug, PartialEq, Clone)] pub enum PaletteMessage { - Brush(TileMapBrush), + ActiveBrush(TileMapBrush), + BrushResource(Option), + TileSet(Option), } impl PaletteMessage { - define_constructor!(PaletteMessage:Brush => fn brush(TileMapBrush), layout: false); + define_constructor!(PaletteMessage:ActiveBrush => fn active_brush(TileMapBrush), layout: false); + define_constructor!(PaletteMessage:BrushResource => fn brush_resource(Option), layout: false); + define_constructor!(PaletteMessage:TileSet => fn tile_set(Option), layout: false); } #[derive(Debug, Clone, PartialEq, Visit, Reflect, Default)] @@ -70,6 +79,11 @@ pub struct PaletteWidget { tile_size: Vector2, selection: Vec>, mode: Mode, + tile_set: Option, + brush_resource: Option, + #[visit(skip)] + #[reflect(hidden)] + resource_manager: ResourceManager, } define_widget_deref!(PaletteWidget); @@ -160,7 +174,7 @@ impl PaletteWidget { self.selection = new_selection.to_vec(); - ui.send_message(PaletteMessage::brush( + ui.send_message(PaletteMessage::active_brush( self.handle(), MessageDirection::FromWidget, self.selected_tiles_to_brush(ui), @@ -179,6 +193,50 @@ impl PaletteWidget { (pos.y / self.tile_size.y) as i32, ) } + + fn recreate_tiles(&mut self, ui: &mut UserInterface) { + for &tile in self.children() { + ui.send_message(WidgetMessage::remove(tile, MessageDirection::ToWidget)); + } + + if let Some(tile_set) = self.tile_set.as_ref() { + if let Some(brush_resource) = self.brush_resource.as_ref() { + let brush = brush_resource.data_ref(); + self.tiles = generate_tiles(tile_set.clone(), &brush, &mut ui.build_ctx()); + + for &tile in &self.tiles { + ui.send_message(WidgetMessage::link( + tile, + MessageDirection::ToWidget, + self.handle, + )); + } + } + } + } + + fn save_brush(&self) { + if let Some(active_brush) = self.brush_resource.as_ref() { + Log::verify(active_brush.save_back()) + } + } +} + +fn generate_tiles( + tile_set_resource: TileSetResource, + tile_map_brush: &TileMapBrush, + ctx: &mut BuildContext, +) -> Vec> { + tile_map_brush + .tiles + .iter() + .map(|tile| { + TileViewBuilder::new(tile_set_resource.clone(), WidgetBuilder::new()) + .with_definition_index(tile.definition_index) + .with_position(tile.local_position) + .build(ctx) + }) + .collect::>() } impl Control for PaletteWidget { @@ -377,41 +435,120 @@ impl Control for PaletteWidget { { self.selection.remove(position); } + } else if let Some(WidgetMessage::Drop(dropped)) = message.data() { + if message.destination() == self.handle { + if let Some(item) = ui.node(*dropped).cast::() { + if let Some(brush) = item.resource::(&self.resource_manager) { + ui.send_message(PaletteMessage::brush_resource( + self.handle, + MessageDirection::ToWidget, + Some(brush), + )); + } else if let Some(tile_set) = item.resource::(&self.resource_manager) + { + if let Some(active_brush) = self.brush_resource.as_ref() { + let tile_set = tile_set.data_ref(); + let tiles = tile_set + .tiles + .iter() + .enumerate() + .map(|(index, _tile)| { + let side_size = 11; + + BrushTile { + definition_index: index, + local_position: Vector2::new( + index as i32 % side_size, + index as i32 / side_size, + ), + } + }) + .collect::>(); + active_brush.data_ref().tiles = tiles; + self.save_brush(); + self.recreate_tiles(ui); + } + } + } + } + } else if let Some(msg) = message.data::() { + if message.destination() == self.handle { + match msg { + PaletteMessage::BrushResource(brush_resource) => { + if &self.brush_resource != brush_resource { + self.brush_resource.clone_from(brush_resource); + self.recreate_tiles(ui); + } + } + PaletteMessage::ActiveBrush(_) => { + // Nothing to do. + } + PaletteMessage::TileSet(tile_set) => { + if &self.tile_set != tile_set { + self.tile_set.clone_from(tile_set); + self.recreate_tiles(ui); + } + } + } + } } } } pub struct PaletteWidgetBuilder { widget_builder: WidgetBuilder, - tiles: Vec>, + brush: Option, + tile_set: Option, } impl PaletteWidgetBuilder { pub fn new(widget_builder: WidgetBuilder) -> Self { Self { widget_builder, - tiles: Default::default(), + brush: None, + tile_set: None, } } - pub fn with_tiles(mut self, tiles: Vec>) -> Self { - self.tiles = tiles; + pub fn with_brush(mut self, brush: Option) -> Self { + self.brush = brush; self } - pub fn build(self, ctx: &mut BuildContext) -> Handle { + pub fn with_tile_set(mut self, tile_set_resource: Option) -> Self { + self.tile_set = tile_set_resource; + self + } + + pub fn build( + self, + resource_manager: ResourceManager, + ctx: &mut BuildContext, + ) -> Handle { + let mut tiles = Vec::default(); + if let Some(brush) = self.brush.as_ref() { + let brush = brush.data_ref(); + if let Some(tile_set_resource) = self.tile_set.as_ref() { + tiles = generate_tiles(tile_set_resource.clone(), &brush, ctx); + } + } + ctx.add_node(UiNode::new(PaletteWidget { widget: self .widget_builder + .with_allow_drop(true) .with_clip_to_bounds(false) - .with_children(self.tiles.iter().cloned()) + .with_children(tiles.iter().cloned()) .build(), - tiles: self.tiles, + tiles, view_position: Default::default(), zoom: 1.0, tile_size: Vector2::repeat(32.0), selection: Default::default(), mode: Mode::None, + tile_set: self.tile_set, + brush_resource: self.brush, + resource_manager, })) } } diff --git a/editor/src/plugins/tilemap/panel.rs b/editor/src/plugins/tilemap/panel.rs index dc5e144d5..74c3fdf0a 100644 --- a/editor/src/plugins/tilemap/panel.rs +++ b/editor/src/plugins/tilemap/panel.rs @@ -1,6 +1,7 @@ use crate::{ fyrox::{ - core::{algebra::Vector2, pool::Handle}, + asset::manager::ResourceManager, + core::pool::Handle, gui::{ grid::GridBuilder, message::{MessageDirection, UiMessage}, @@ -8,9 +9,9 @@ use crate::{ window::{WindowBuilder, WindowMessage, WindowTitle}, BuildContext, HorizontalAlignment, Thickness, UiNode, UserInterface, VerticalAlignment, }, - scene::tilemap::tileset::TileSetResource, + scene::tilemap::TileMap, }, - plugins::tilemap::palette::{PaletteWidgetBuilder, TileViewBuilder}, + plugins::{tilemap::palette::PaletteMessage, tilemap::palette::PaletteWidgetBuilder}, }; pub struct TileMapPanel { @@ -22,33 +23,13 @@ impl TileMapPanel { pub fn new( ctx: &mut BuildContext, scene_frame: Handle, - tile_set: Option, + resource_manager: ResourceManager, + tile_map: &TileMap, ) -> Self { - let tiles = tile_set - .map(|tile_set_resource| { - let tile_set = tile_set_resource.data_ref(); - tile_set - .tiles - .iter() - .enumerate() - .map(|(index, _tile)| { - let side_size = 11; - - TileViewBuilder::new(tile_set_resource.clone(), WidgetBuilder::new()) - .with_definition_index(index) - .with_position(Vector2::new( - index as i32 % side_size, - index as i32 / side_size, - )) - .build(ctx) - }) - .collect::>() - }) - .unwrap_or_default(); - let palette = PaletteWidgetBuilder::new(WidgetBuilder::new()) - .with_tiles(tiles) - .build(ctx); + .with_brush(tile_map.active_brush()) + .with_tile_set(tile_map.tile_set().cloned()) + .build(resource_manager, ctx); let content = GridBuilder::new(WidgetBuilder::new().with_child(palette)).build(ctx); @@ -91,4 +72,18 @@ impl TileMapPanel { Some(self) } + + pub fn sync_to_model(&self, ui: &UserInterface, tile_map: &TileMap) { + ui.send_message(PaletteMessage::brush_resource( + self.palette, + MessageDirection::ToWidget, + tile_map.active_brush(), + )); + + ui.send_message(PaletteMessage::tile_set( + self.palette, + MessageDirection::ToWidget, + tile_map.tile_set().cloned(), + )); + } } diff --git a/fyrox-impl/src/engine/mod.rs b/fyrox-impl/src/engine/mod.rs index e78225bca..9baf21c26 100644 --- a/fyrox-impl/src/engine/mod.rs +++ b/fyrox-impl/src/engine/mod.rs @@ -101,6 +101,7 @@ use crate::plugin::dynamic::DynamicPlugin; use crate::plugin::{DynamicPluginState, PluginContainer}; use crate::scene::mesh::surface; use crate::scene::mesh::surface::{SurfaceData, SurfaceDataLoader}; +use crate::scene::tilemap::brush::{TileMapBrush, TileMapBrushLoader}; use crate::scene::tilemap::tileset::{TileSet, TileSetLoader}; use fyrox_core::futures::future::join_all; use fyrox_core::notify; @@ -1229,6 +1230,7 @@ pub(crate) fn initialize_resource_manager_loaders( state.constructors_container.add::(); state.constructors_container.add::(); state.constructors_container.add::(); + state.constructors_container.add::(); let loaders = &mut state.loaders; loaders.set(model_loader); @@ -1252,6 +1254,7 @@ pub(crate) fn initialize_resource_manager_loaders( loaders.set(TileSetLoader { resource_manager: resource_manager.clone(), }); + state.loaders.set(TileMapBrushLoader {}); } fn try_copy_library(source_lib_path: &Path, lib_path: &Path) -> Result<(), String> { diff --git a/editor/src/plugins/tilemap/brush.rs b/fyrox-impl/src/scene/tilemap/brush.rs similarity index 99% rename from editor/src/plugins/tilemap/brush.rs rename to fyrox-impl/src/scene/tilemap/brush.rs index 03ebd0210..69f10fe64 100644 --- a/editor/src/plugins/tilemap/brush.rs +++ b/fyrox-impl/src/scene/tilemap/brush.rs @@ -1,4 +1,4 @@ -use crate::fyrox::{ +use crate::{ asset::{ io::ResourceIo, loader::{BoxedLoaderFuture, LoaderPayload, ResourceLoader}, diff --git a/fyrox-impl/src/scene/tilemap/mod.rs b/fyrox-impl/src/scene/tilemap/mod.rs index 73a903947..8785c7111 100644 --- a/fyrox-impl/src/scene/tilemap/mod.rs +++ b/fyrox-impl/src/scene/tilemap/mod.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] // TODO +pub mod brush; pub mod tileset; use crate::{ @@ -21,7 +22,7 @@ use crate::{ graph::Graph, mesh::{buffer::VertexTrait, RenderPath}, node::{Node, NodeTrait, RdcControlFlow}, - tilemap::tileset::TileSetResource, + tilemap::{brush::TileMapBrushResource, tileset::TileSetResource}, }, }; use fxhash::FxHashMap; @@ -44,6 +45,8 @@ pub struct TileMap { #[reflect(read_only)] tiles: InheritableVariable, tile_scale: InheritableVariable>, + brushes: InheritableVariable>>, + active_brush: InheritableVariable>, } impl TileMap { @@ -77,6 +80,22 @@ impl TileMap { .and_modify(|entry| *entry = tile.clone()) .or_insert(tile); } + + pub fn active_brush(&self) -> Option { + (*self.active_brush).clone() + } + + pub fn set_active_brush(&mut self, brush: Option) { + self.active_brush.set_value_and_mark_modified(brush); + } + + pub fn brushes(&self) -> &[Option] { + &self.brushes + } + + pub fn set_brushes(&mut self, brushes: Vec>) { + self.brushes.set_value_and_mark_modified(brushes); + } } impl Default for TileMap { @@ -86,6 +105,8 @@ impl Default for TileMap { tile_set: Default::default(), tiles: Default::default(), tile_scale: Vector2::repeat(1.0).into(), + brushes: Default::default(), + active_brush: Default::default(), } } } @@ -234,6 +255,7 @@ pub struct TileMapBuilder { tile_set: Option, tiles: Tiles, tile_scale: Vector2, + brushes: Vec>, } impl TileMapBuilder { @@ -243,6 +265,7 @@ impl TileMapBuilder { tile_set: None, tiles: Default::default(), tile_scale: Vector2::repeat(1.0), + brushes: Default::default(), } } @@ -261,12 +284,19 @@ impl TileMapBuilder { self } + pub fn with_brushes(mut self, brushes: Vec>) -> Self { + self.brushes = brushes; + self + } + pub fn build_node(self) -> Node { Node::new(TileMap { base: self.base_builder.build_base(), tile_set: self.tile_set.into(), tiles: self.tiles.into(), tile_scale: self.tile_scale.into(), + brushes: self.brushes.into(), + active_brush: Default::default(), }) }