From bff1955c38480f2dffd0a10c16ef46dc11320752 Mon Sep 17 00:00:00 2001 From: Arne Dußin Date: Fri, 20 Nov 2020 23:41:46 +0100 Subject: Add unfinished polygon room tool When adding the polygon room tool, a problem with drawing polygons arised. Drawing a simple, but nonregular polygon is not something that is supported by raylib, so further additions to the math library are needed. --- src/config.rs | 20 ++++++++++ src/map_data.rs | 12 +++++- src/math/polygon.rs | 3 +- src/tool/mod.rs | 3 ++ src/tool/polygon_room_tool.rs | 91 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/tool/polygon_room_tool.rs diff --git a/src/config.rs b/src/config.rs index 4e90b21..b4703a2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,6 +10,7 @@ use std::path::Path; pub struct Config { pub deletion_keybindings: DeletionToolKeybindings, pub icon_keybindings: IconToolKeybindings, + pub polygon_keybindings: PolygonRoomToolKeybindings, pub room_keybindings: RoomToolKeybindings, pub wall_keybindings: WallToolKeybindings, } @@ -37,6 +38,14 @@ pub struct IconToolKeybindings { pub place: Button, } +#[derive(Serialize, Deserialize)] +pub struct PolygonRoomToolKeybindings { + pub activation: Button, + pub place_node: Button, + pub finish: Button, + pub abort: Button, +} + #[derive(Serialize, Deserialize)] pub struct RoomToolKeybindings { pub activation: Button, @@ -98,6 +107,12 @@ impl Default for Config { rotate_counterclockwise: Button::Keyboard(KeyboardKey::Minus), place: Button::Mouse(MouseButton::Left), }, + polygon_keybindings: PolygonRoomToolKeybindings { + activation: Button::Keyboard(KeyboardKey::P), + place_node: Button::Mouse(MouseButton::Left), + finish: Button::Keyboard(KeyboardKey::Enter), + abort: Button::Mouse(MouseButton::Right), + }, room_keybindings: RoomToolKeybindings { activation: Button::Keyboard(KeyboardKey::R), start_draw: Button::Mouse(MouseButton::Left), @@ -124,6 +139,11 @@ impl ToolKeybindings for IconToolKeybindings { self.activation } } +impl ToolKeybindings for PolygonRoomToolKeybindings { + fn activation_key(&self) -> Button { + self.activation + } +} impl ToolKeybindings for RoomToolKeybindings { fn activation_key(&self) -> Button { self.activation diff --git a/src/map_data.rs b/src/map_data.rs index e1a9c0b..b17d779 100644 --- a/src/map_data.rs +++ b/src/map_data.rs @@ -1,4 +1,4 @@ -use crate::math::{Rect, Vec2}; +use crate::math::{Polygon, Rect, Vec2}; use crate::tool::icon_tool::IconInfo; use ron::de::from_reader; use ron::ser::{to_string_pretty, PrettyConfig}; @@ -13,6 +13,7 @@ use std::path::Path; #[derive(Serialize, Deserialize)] pub struct MapData { rooms: Vec>, + polygons: Vec>, walls: Vec<(Vec2, Vec2)>, icons: Vec, } @@ -22,6 +23,7 @@ impl MapData { pub fn new() -> Self { Self { rooms: Vec::new(), + polygons: Vec::new(), walls: Vec::new(), icons: Vec::new(), } @@ -40,6 +42,7 @@ impl MapData { * future) */ self.rooms.append(&mut data.rooms); + self.polygons.append(&mut data.polygons); self.walls.append(&mut data.walls); self.icons.append(&mut data.icons); @@ -71,6 +74,13 @@ impl MapData { &mut self.rooms } + pub fn polygons(&self) -> &Vec> { + &self.polygons + } + pub fn polygons_mut(&mut self) -> &mut Vec> { + &mut self.polygons + } + pub fn walls(&self) -> &Vec<(Vec2, Vec2)> { &self.walls } diff --git a/src/math/polygon.rs b/src/math/polygon.rs index 5711049..5cf8104 100644 --- a/src/math/polygon.rs +++ b/src/math/polygon.rs @@ -1,9 +1,10 @@ use super::{PolygonGraph, Vec2}; use nalgebra::{ClosedDiv, ClosedMul, ClosedSub, RealField, Scalar}; use num_traits::Zero; +use serde::{Deserialize, Serialize}; use std::ops::Neg; -#[derive(Debug)] +#[derive(Debug, Deserialize, Serialize, PartialEq)] // TODO: Support polygons with holes pub struct Polygon { pub corners: Vec>, diff --git a/src/tool/mod.rs b/src/tool/mod.rs index e528b8f..f503d2b 100644 --- a/src/tool/mod.rs +++ b/src/tool/mod.rs @@ -1,10 +1,12 @@ pub mod deletion_tool; pub mod icon_tool; +pub mod polygon_room_tool; pub mod room_tool; pub mod wall_tool; pub use deletion_tool::DeletionTool; pub use icon_tool::IconTool; +pub use polygon_room_tool::PolygonRoomTool; pub use room_tool::RoomTool; pub use wall_tool::WallTool; @@ -18,6 +20,7 @@ use raylib::RaylibHandle; #[repr(u8)] pub enum ToolType { RoomTool, + PolygonRoomTool, WallTool, IconTool, DeletionTool, diff --git a/src/tool/polygon_room_tool.rs b/src/tool/polygon_room_tool.rs new file mode 100644 index 0000000..4aab7f7 --- /dev/null +++ b/src/tool/polygon_room_tool.rs @@ -0,0 +1,91 @@ +use super::Tool; +use crate::button::Button; +use crate::config::{PolygonRoomToolKeybindings, ToolKeybindings}; +use crate::dimension_indicator::DimensionIndicator; +use crate::grid::{snap_to_grid, SNAP_SIZE}; +use crate::map_data::MapData; +use crate::math::{Polygon, Vec2}; +use crate::transform::Transform; +use raylib::core::drawing::RaylibDrawHandle; +use raylib::RaylibHandle; + +pub struct PolygonRoomTool { + keybindings: PolygonRoomToolKeybindings, + unfinished_polygon: Option>>, + dimension_indicator: DimensionIndicator, +} + +impl PolygonRoomTool { + pub fn new(keybindings: PolygonRoomToolKeybindings) -> Self { + Self { + keybindings, + unfinished_polygon: None, + dimension_indicator: DimensionIndicator::new(), + } + } +} + +impl Tool for PolygonRoomTool { + fn activate(&mut self) {} + + fn deactivate(&mut self) { + self.unfinished_polygon = None; + } + + fn active_update( + &mut self, + map: &mut MapData, + rl: &RaylibHandle, + transform: &Transform, + mouse_blocked: bool, + ) { + let mouse_pos_m = transform.point_px_to_m(rl.get_mouse_position().into()); + let snapped_mouse_pos_m = snap_to_grid(mouse_pos_m, SNAP_SIZE); + // Update the position of the node that would be placed into the polygon next. + if let Some(ref mut corners) = &mut self.unfinished_polygon { + let last_element = corners.len() - 1; + corners[last_element] = snapped_mouse_pos_m; + self.dimension_indicator.update_dimensions(&corners); + } + + if self.keybindings.finish.is_pressed(rl, mouse_blocked) + && self.unfinished_polygon.is_some() + { + // Make sure the polygon is at least a triangle, so it can be drawn. + if self.unfinished_polygon.as_ref().unwrap().len() >= 3 { + let polygon = Polygon::new(self.unfinished_polygon.take().unwrap()); + self.dimension_indicator.clear_dimensions(); + map.polygons_mut().push(polygon); + } + } + + if self.keybindings.place_node.is_pressed(rl, mouse_blocked) { + if let Some(ref mut corners) = self.unfinished_polygon.as_mut() { + if snapped_mouse_pos_m == corners[0] { + // Make sure the polygon is at least a triangle, so it can be drawn. + if corners.len() >= 3 { + // The last corner is redundant. + corners.pop(); + let polygon = Polygon::new(self.unfinished_polygon.take().unwrap()); + self.dimension_indicator.clear_dimensions(); + map.polygons_mut().push(polygon); + } + } else { + corners.push(snapped_mouse_pos_m); + } + } else { + self.unfinished_polygon = Some(vec![snapped_mouse_pos_m]); + } + } + + if self.keybindings.abort.is_pressed(rl, false) { + self.unfinished_polygon = None; + } + } + + fn draw(&self, _map: &MapData, _rld: &mut RaylibDrawHandle, _transform: &Transform) {} + + fn activation_key(&self) -> Button { + self.keybindings.activation_key() + } +} -- cgit v1.2.3-70-g09d2