aboutsummaryrefslogtreecommitdiff
path: root/src/tool
diff options
context:
space:
mode:
Diffstat (limited to 'src/tool')
-rw-r--r--src/tool/deletion_tool.rs75
-rw-r--r--src/tool/icon_tool.rs197
-rw-r--r--src/tool/mod.rs46
-rw-r--r--src/tool/polygon_room_tool.rs137
-rw-r--r--src/tool/rect_room_tool.rs78
-rw-r--r--src/tool/room_tool.rs103
-rw-r--r--src/tool/wall_tool.rs113
7 files changed, 230 insertions, 519 deletions
diff --git a/src/tool/deletion_tool.rs b/src/tool/deletion_tool.rs
index 74a8f92..ad3af1d 100644
--- a/src/tool/deletion_tool.rs
+++ b/src/tool/deletion_tool.rs
@@ -1,41 +1,25 @@
use super::Tool;
-use crate::button::Button;
-use crate::config::{DeletionToolKeybindings, ToolKeybindings};
-use crate::map_data::MapData;
+use crate::map::Map;
use crate::math::{Rect, Surface, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
use raylib::ffi::Color;
-use raylib::RaylibHandle;
pub struct DeletionTool {
- keybindings: DeletionToolKeybindings,
deletion_rect: Option<(Vec2<f64>, Vec2<f64>)>,
}
impl DeletionTool {
- pub fn new(keybindings: DeletionToolKeybindings) -> Self {
+ pub fn new() -> Self {
Self {
- keybindings,
deletion_rect: None,
}
}
+}
- /// Delete all map-data that is contained inside the provided rectangular space.
- pub fn delete_rect(map_data: &mut MapData, rect: Rect<f64>) {
- map_data
- .rooms_mut()
- .retain(|&room| !rect.contains_rect(&room));
- map_data
- .walls_mut()
- .retain(|&(pos1, pos2)| !rect.contains_point(&pos1) || !rect.contains_point(&pos2));
- map_data
- .icons_mut()
- .retain(|icon| !rect.contains_point(&icon.position));
- map_data
- .polygons_mut()
- .retain(|polygon| !rect.contains_polygon(&polygon));
- }
+fn delete_rect((pos1, pos2): (&Vec2<f64>, &Vec2<f64>), map: &mut Map) {
+ let bounds = Rect::bounding_rect(*pos1, *pos2);
+ map.retain(|e| !bounds.contains_rect(&e.bounding_rect()));
}
impl Tool for DeletionTool {
@@ -43,34 +27,13 @@ impl Tool for DeletionTool {
self.deletion_rect = None;
}
- fn active_update(
- &mut self,
- map_data: &mut MapData,
- rl: &RaylibHandle,
- transform: &Transform,
- mouse_blocked: bool,
- ) {
- let mouse_pos_m = transform.point_px_to_m(&rl.get_mouse_position().into());
+ fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) {
if let Some((_, ref mut pos2)) = &mut self.deletion_rect {
- *pos2 = mouse_pos_m;
- }
-
- if self.keybindings.do_delete.is_pressed(rl, mouse_blocked) && self.deletion_rect.is_some()
- {
- let (pos1, pos2) = self.deletion_rect.take().unwrap();
- Self::delete_rect(map_data, Rect::bounding_rect(pos1, pos2));
- } else if self
- .keybindings
- .start_selection
- .is_pressed(rl, mouse_blocked)
- {
- self.deletion_rect = Some((mouse_pos_m, mouse_pos_m))
- } else if self.keybindings.abort_deletion.is_pressed(rl, false) {
- self.deletion_rect = None;
+ *pos2 = *mouse_pos_m;
}
}
- fn draw(&self, _map_data: &MapData, rld: &mut RaylibDrawHandle, transform: &Transform) {
+ fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
if let Some((pos1, pos2)) = self.deletion_rect {
let rect_px = transform.rect_m_to_px(&Rect::bounding_rect(pos1, pos2));
rld.draw_rectangle_rec(
@@ -95,7 +58,23 @@ impl Tool for DeletionTool {
}
}
- fn activation_key(&self) -> Button {
- self.keybindings.activation_key()
+ fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) {
+ if let Some((pos1, pos2)) = self.deletion_rect {
+ delete_rect((&pos1, &pos2), map);
+ self.deletion_rect = None;
+ } else {
+ self.deletion_rect = Some((*mouse_pos_m, *mouse_pos_m));
+ }
+ }
+
+ fn finish(&mut self, map: &mut Map) {
+ if let Some((pos1, pos2)) = self.deletion_rect {
+ delete_rect((&pos1, &pos2), map);
+ self.deletion_rect = None;
+ }
+ }
+
+ fn abort(&mut self) {
+ self.deletion_rect = None;
}
}
diff --git a/src/tool/icon_tool.rs b/src/tool/icon_tool.rs
index e972c1c..09b0ac1 100644
--- a/src/tool/icon_tool.rs
+++ b/src/tool/icon_tool.rs
@@ -1,115 +1,33 @@
use crate::button::Button;
-use crate::config::{IconToolKeybindings, ToolKeybindings};
-use crate::grid::{snap_to_grid, SNAP_SIZE};
-use crate::map_data::MapData;
+use crate::config::IconToolKeys;
+use crate::map::icon_renderer::IconRenderer;
+use crate::map::{Icon, Map, Mappable};
use crate::math::Vec2;
use crate::tool::Tool;
use crate::transform::Transform;
-use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
-use raylib::core::texture::Texture2D;
-use raylib::ffi::Color;
-use raylib::{RaylibHandle, RaylibThread};
-use ron::de::from_reader;
-use serde::{Deserialize, Serialize};
-use std::fs::{self, File};
+use raylib::core::drawing::RaylibDrawHandle;
+use std::rc::Rc;
pub const ICON_DIR: &str = "assets/icons";
-#[derive(Deserialize)]
-struct IconFileInfo {
- /// The position the icon should be anchored in pixels. This is the Vector it will be moved by
- /// relative to the mouse pointer (to the left and up).
- anchor: Vec2<f64>,
- /// The scale of the icon as expressed in image pixels per real meter.
- pixels_per_m: f64,
-}
-
-#[derive(Clone, Serialize, Deserialize)]
-pub struct IconInfo {
- /// The id of the icon is the icons position in the currently loaded icon_data vector.
- pub icon_id: usize,
- /// The position of the icon on the map, given by the vector in meters.
- pub position: Vec2<f64>,
- /// Rotation of the icon texture in degrees.
- pub rotation: f64,
-}
-
pub struct IconTool {
// TODO: support svg
- keybindings: IconToolKeybindings,
- /// The icon data, containing the image texture and the info for that image texture like the
- /// scale the image actually has.
- icon_data: Vec<(Texture2D, IconFileInfo)>,
+ keybindings: IconToolKeys,
/// Saves whether the IconTool is the currently active tool or not.
active: bool,
/// The information of the icon that should be placed / is currently being placed, if it
/// exists.
- current_icon: IconInfo,
-}
-
-impl Default for IconInfo {
- fn default() -> Self {
- Self {
- icon_id: 0,
- position: Vec2::new(0., 0.),
- rotation: 0.,
- }
- }
+ current_icon: Icon,
+ renderer: Rc<IconRenderer>,
}
impl IconTool {
- pub fn new(
- rl: &mut RaylibHandle,
- rlt: &RaylibThread,
- keybindings: IconToolKeybindings,
- ) -> Self {
- /* Read all available icons from the icon directory. SVGs do not need any special scale
- * file, but pixel-based file formats require a RON-file declaring what the scale of the
- * picture is right beside them.
- */
- let mut image_files = Vec::new();
- for entry in fs::read_dir(ICON_DIR).expect("Could not open icon directory") {
- let entry = entry.expect("Failed to read file from icon directory");
-
- // Ignore the RON-files for now and put the image files into the vec
- if entry
- .path()
- .extension()
- .expect("Entry does not have a file extension")
- != "ron"
- {
- image_files.push(entry);
- }
- }
-
- // Read the RON-files where it is necessary.
- let mut icon_data = Vec::with_capacity(image_files.len());
- for file in image_files {
- // TODO: Handle svg
-
- let texture = rl
- .load_texture(
- rlt,
- file.path()
- .to_str()
- .expect("Unable to convert path to string."),
- )
- .expect("Could not read image file");
-
- let mut file = file.path();
- file.set_extension("ron");
- let ron = File::open(file).expect("Could not read ron file for icon information.");
- let icon_info: IconFileInfo =
- from_reader(ron).expect("Could not parse icon info from reader.");
-
- icon_data.push((texture, icon_info));
- }
-
+ pub fn new(keybindings: IconToolKeys, renderer: Rc<IconRenderer>) -> Self {
Self {
keybindings,
- icon_data,
active: false,
- current_icon: IconInfo::default(),
+ current_icon: Icon::new(0, Vec2::default(), 0., renderer.clone()),
+ renderer,
}
}
}
@@ -123,85 +41,30 @@ impl Tool for IconTool {
self.active = false;
}
- fn active_update(
- &mut self,
- map: &mut MapData,
- rl: &RaylibHandle,
- transform: &Transform,
- mouse_blocked: bool,
- ) {
- // Update the position of the icon that should be drawn to the current mouse position.
- let snapped_mouse_pos_m = snap_to_grid(
- transform.point_px_to_m(&rl.get_mouse_position().into()),
- SNAP_SIZE,
- );
- self.current_icon.position = snapped_mouse_pos_m;
-
- // Unwrap the current icon, since it is now definitely set, as we are in the active update.
- if self.keybindings.next.is_pressed(rl, mouse_blocked) {
- self.current_icon.icon_id = (self.current_icon.icon_id + 1) % self.icon_data.len();
- }
- if self
- .keybindings
- .rotate_clockwise
- .is_pressed(rl, mouse_blocked)
- {
- self.current_icon.rotation += 45.;
- }
-
- // Handle placing the icon on the map
- if self.keybindings.place.is_pressed(rl, mouse_blocked) {
- map.icons_mut().push(self.current_icon.clone());
- }
+ fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) {
+ self.current_icon.position = *mouse_pos_m;
}
- fn draw(&self, map: &MapData, rld: &mut RaylibDrawHandle, transform: &Transform) {
- // Draw all icons that have been placed on the map.
- for icon in map.icons() {
- let (texture, info) = &self.icon_data[icon.icon_id];
- // Round the position to whole pixels to fix rotation problems.
- let mut position_px =
- transform.point_m_to_px(&(icon.position - (info.anchor / info.pixels_per_m)));
- position_px.x = position_px.x.floor();
- position_px.y = position_px.y.floor();
- rld.draw_texture_ex(
- texture,
- position_px,
- icon.rotation as f32,
- (transform.pixels_per_m() / info.pixels_per_m) as f32,
- Color {
- r: 255,
- g: 255,
- b: 255,
- a: 255,
- },
- );
- }
-
- // Draw the icon that would be placed
+ fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
if self.active {
- let (texture, info) = &self.icon_data[self.current_icon.icon_id];
- // Round the position to whole pixels to fix rotation problems.
- let mut position_px = transform
- .point_m_to_px(&(self.current_icon.position - (info.anchor / info.pixels_per_m)));
- position_px.x = position_px.x.floor();
- position_px.y = position_px.y.floor();
- rld.draw_texture_ex(
- texture,
- position_px,
- self.current_icon.rotation as f32,
- (transform.pixels_per_m() / info.pixels_per_m) as f32,
- Color {
- r: 120,
- g: 200,
- b: 120,
- a: 255,
- },
- );
+ self.current_icon.draw(rld, transform);
}
}
- fn activation_key(&self) -> Button {
- self.keybindings.activation_key()
+ fn place_single(&mut self, map: &mut Map, _mouse_pos_m: &Vec2<f64>) {
+ map.push_icon(self.current_icon.clone());
+ }
+
+ fn on_button_pressed(&mut self, _map: &mut Map, button: Button) {
+ if button == self.keybindings.next {
+ self.current_icon.id = (self.current_icon.id + 1) % self.renderer.num_icons();
+ } else if button == self.keybindings.previous {
+ self.current_icon.id =
+ (self.current_icon.id + self.renderer.num_icons() - 1) % self.renderer.num_icons();
+ } else if button == self.keybindings.rotate_clockwise {
+ self.current_icon.rotation += 45.;
+ } else if button == self.keybindings.rotate_counterclockwise {
+ self.current_icon.rotation -= 45.;
+ }
}
}
diff --git a/src/tool/mod.rs b/src/tool/mod.rs
index f503d2b..532572a 100644
--- a/src/tool/mod.rs
+++ b/src/tool/mod.rs
@@ -1,25 +1,25 @@
pub mod deletion_tool;
pub mod icon_tool;
pub mod polygon_room_tool;
-pub mod room_tool;
+pub mod rect_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 rect_room_tool::RectRoomTool;
pub use wall_tool::WallTool;
use crate::button::Button;
-use crate::map_data::MapData;
+use crate::map::Map;
+use crate::math::Vec2;
use crate::transform::Transform;
use raylib::core::drawing::RaylibDrawHandle;
-use raylib::RaylibHandle;
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[repr(u8)]
pub enum ToolType {
- RoomTool,
+ RectRoomTool,
PolygonRoomTool,
WallTool,
IconTool,
@@ -28,19 +28,33 @@ pub enum ToolType {
}
pub trait Tool {
+ /// Code that needs to be called when this Tool is activated or reactivated goes here.
fn activate(&mut self) {}
+ /// Cleanup that needs to be done when the user switches from this tool to something else goes here.
fn deactivate(&mut self) {}
- fn update(&mut self, _map: &MapData, _rl: &RaylibHandle, _transform: &Transform) {}
- fn active_update(
- &mut self,
- map: &mut MapData,
- rl: &RaylibHandle,
- transform: &Transform,
- mouse_blocked: bool,
- );
+ /// Called on each frame when this tool is active.
+ fn update(&mut self, map: &Map, mouse_pos_m: &Vec2<f64>);
- fn draw(&self, _map: &MapData, _rld: &mut RaylibDrawHandle, _transform: &Transform) {}
+ /// Draw the contents of this tool.
+ // TODO: Maybe make this tool mappable? This might make it easier to make things resizable while
+ // it's still being drawn.
+ fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform);
- fn activation_key(&self) -> Button;
+ /// Generic keybinding.
+ /// Code to place a single node for this tool.
+ fn place_single(&mut self, _map: &mut Map, _mouse_pos_m: &Vec2<f64>) {}
+
+ /// Generic keybinding.
+ /// Code to finish whatever one is doing with this tool currently and trying to apply the
+ /// changes to the map data.
+ fn finish(&mut self, _map: &mut Map) {}
+
+ /// Generic keybinding.
+ /// Stop whatever one is doing with this tool and do not apply any changes to the map data.
+ fn abort(&mut self) {}
+
+ /// If there are any additional keybindings that need to be handled by this tool, these can be
+ /// handled here.
+ fn on_button_pressed(&mut self, _map: &mut Map, _button: Button) {}
}
diff --git a/src/tool/polygon_room_tool.rs b/src/tool/polygon_room_tool.rs
index 8cd2c25..4f8edce 100644
--- a/src/tool/polygon_room_tool.rs
+++ b/src/tool/polygon_room_tool.rs
@@ -1,14 +1,9 @@
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::map::Map;
use crate::math::{self, Polygon, PolygonError, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
use raylib::ffi::Color;
-use raylib::RaylibHandle;
struct UnfinishedPolygon {
pub corners: Vec<Vec2<f64>>,
@@ -16,9 +11,7 @@ struct UnfinishedPolygon {
}
pub struct PolygonRoomTool {
- keybindings: PolygonRoomToolKeybindings,
unfinished_polygon: Option<UnfinishedPolygon>,
- dimension_indicator: DimensionIndicator,
}
impl UnfinishedPolygon {
@@ -83,108 +76,26 @@ impl UnfinishedPolygon {
}
impl PolygonRoomTool {
- pub fn new(keybindings: PolygonRoomToolKeybindings) -> Self {
+ pub fn new() -> 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);
-
+ fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) {
// Update the position of the node that would be placed into the polygon next.
if let Some(ref mut polygon) = &mut self.unfinished_polygon {
- polygon.working_corner = snapped_mouse_pos_m;
-
- polygon.corners.push(polygon.working_corner);
- self.dimension_indicator.update_dimensions(&polygon.corners);
- polygon.working_corner = polygon.corners.pop().unwrap();
- }
-
- /* Check if the finishing keybinding has been pressed. If so, try to turn the part of the
- * polygon that is already completed into a proper polygon and push it into the map data.
- */
- if self.keybindings.finish.is_pressed(rl, mouse_blocked) {
- if let Some(ref mut polygon) = self.unfinished_polygon {
- if let Some(polygon) = polygon.try_into_completed() {
- self.dimension_indicator.clear_dimensions();
- map.polygons_mut().push(polygon);
- self.unfinished_polygon = None;
- }
- }
- }
-
- /* Handle placing a new corner of the polygon. If the corner is placed on the first node,
- * the polygon will be created.
- */
- if self.keybindings.place_node.is_pressed(rl, mouse_blocked) {
- if let Some(ref mut polygon) = &mut self.unfinished_polygon {
- if polygon.working_corner == polygon.corners[0] {
- /* The working corner will be ignored, since it would double the vertex at the
- * polygon starting position.
- */
- if let Some(polygon) = polygon.try_into_completed() {
- self.dimension_indicator.clear_dimensions();
- map.polygons_mut().push(polygon);
- self.unfinished_polygon = None;
- }
- } else {
- // Check if we can add the corner to the polygon without ruining it.
- if let Err(e) = polygon.try_push_working() {
- error!("Cannot add corner to polygon: {}", e);
- }
- }
- } else {
- // Start a new unfinished polygon
- self.unfinished_polygon = Some(UnfinishedPolygon {
- corners: vec![snapped_mouse_pos_m],
- working_corner: snapped_mouse_pos_m,
- });
- }
- }
-
- if self.keybindings.abort.is_pressed(rl, false) {
- self.unfinished_polygon = None;
+ polygon.working_corner = *mouse_pos_m;
}
}
- fn draw(&self, map: &MapData, rld: &mut RaylibDrawHandle, transform: &Transform) {
- // TODO: Buffer triangles so the polygons don't always have to be retriangulated.
- for polygon in map.polygons() {
- let triangles = math::triangulate(polygon.clone());
- for triangle in triangles {
- let triangle: [Vec2<f64>; 3] = triangle.into();
- rld.draw_triangle(
- transform.point_m_to_px(&triangle[0]),
- transform.point_m_to_px(&triangle[1]),
- transform.point_m_to_px(&triangle[2]),
- Color {
- r: 180,
- g: 180,
- b: 180,
- a: 255,
- },
- )
- }
- }
-
+ fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
if let Some(polygon) = &self.unfinished_polygon {
// The first corner is guaranteed to be set, so we can at least draw a line.
if polygon.corners.len() == 1 {
@@ -252,12 +163,44 @@ impl Tool for PolygonRoomTool {
}
}
}
+ }
+ }
+
+ fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) {
+ if let Some(ref mut polygon) = &mut self.unfinished_polygon {
+ if polygon.working_corner == polygon.corners[0] {
+ /* The working corner will be ignored, since it would double the vertex at the
+ * polygon starting position.
+ */
+ if let Some(polygon) = polygon.try_into_completed() {
+ map.push_polygon_room(polygon);
+ self.unfinished_polygon = None;
+ }
+ } else {
+ // Check if we can add the corner to the polygon without ruining it.
+ if let Err(e) = polygon.try_push_working() {
+ error!("Cannot add corner to polygon: {}", e);
+ }
+ }
+ } else {
+ // Start a new unfinished polygon
+ self.unfinished_polygon = Some(UnfinishedPolygon {
+ corners: vec![*mouse_pos_m],
+ working_corner: *mouse_pos_m,
+ });
+ }
+ }
- self.dimension_indicator.draw(rld, transform);
+ fn finish(&mut self, map: &mut Map) {
+ if let Some(ref mut polygon) = self.unfinished_polygon {
+ if let Some(polygon) = polygon.try_into_completed() {
+ map.push_polygon_room(polygon);
+ self.unfinished_polygon = None;
+ }
}
}
- fn activation_key(&self) -> Button {
- self.keybindings.activation_key()
+ fn abort(&mut self) {
+ self.unfinished_polygon = None;
}
}
diff --git a/src/tool/rect_room_tool.rs b/src/tool/rect_room_tool.rs
new file mode 100644
index 0000000..3eb40aa
--- /dev/null
+++ b/src/tool/rect_room_tool.rs
@@ -0,0 +1,78 @@
+use super::Tool;
+use crate::map::Map;
+use crate::math::{Rect, Vec2};
+use crate::transform::Transform;
+use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
+use raylib::ffi::Color;
+
+pub struct RectRoomTool {
+ /// The rectangle that is currently being drawn by the user. Once it is finished, it will be
+ /// pushed into the room_rects.
+ unfinished_rect: Option<(Vec2<f64>, Vec2<f64>)>,
+}
+
+impl RectRoomTool {
+ /// Create a new room tool where no rooms have been drawn yet.
+ pub fn new() -> Self {
+ Self {
+ unfinished_rect: None,
+ }
+ }
+}
+
+impl Tool for RectRoomTool {
+ fn deactivate(&mut self) {
+ self.unfinished_rect = None;
+ }
+
+ fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) {
+ if let Some((_, ref mut pos2)) = &mut self.unfinished_rect {
+ *pos2 = *mouse_pos_m;
+ }
+ }
+
+ fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
+ if let Some((pos1, pos2)) = self.unfinished_rect {
+ rld.draw_rectangle_rec(
+ transform.rect_m_to_px(&Rect::bounding_rect(pos1, pos2)),
+ Color {
+ r: 150,
+ g: 200,
+ b: 150,
+ a: 255,
+ },
+ );
+ }
+ }
+
+ fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) {
+ // Try to finish the rectangle if it has been started.
+ if let Some((pos1, pos2)) = self.unfinished_rect {
+ if pos1 == pos2 {
+ warn!("Cannot place rectangle with start and endpoint being the same");
+ return;
+ }
+
+ map.push_rect_room(Rect::bounding_rect(pos1, pos2));
+ self.unfinished_rect = None;
+ } else {
+ self.unfinished_rect = Some((*mouse_pos_m, *mouse_pos_m));
+ }
+ }
+
+ fn finish(&mut self, map: &mut Map) {
+ if let Some((pos1, pos2)) = self.unfinished_rect {
+ if pos1 == pos2 {
+ warn!("Cannot place rectangle with start and endpoint being the same");
+ return;
+ }
+
+ map.push_rect_room(Rect::bounding_rect(pos1, pos2));
+ self.unfinished_rect = None;
+ }
+ }
+
+ fn abort(&mut self) {
+ self.unfinished_rect = None;
+ }
+}
diff --git a/src/tool/room_tool.rs b/src/tool/room_tool.rs
deleted file mode 100644
index 6a283e3..0000000
--- a/src/tool/room_tool.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use super::Tool;
-use crate::button::Button;
-use crate::config::{RoomToolKeybindings, ToolKeybindings};
-use crate::dimension_indicator::DimensionIndicator;
-use crate::grid::{snap_to_grid, SNAP_SIZE};
-use crate::map_data::MapData;
-use crate::math::{Rect, Vec2};
-use crate::transform::Transform;
-use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
-use raylib::ffi::Color;
-use raylib::RaylibHandle;
-
-pub struct RoomTool {
- keybindings: RoomToolKeybindings,
- /// The rectangle that is currently being drawn by the user. Once it is finished, it will be
- /// pushed into the room_rects.
- unfinished_rect: Option<(Vec2<f64>, Vec2<f64>)>,
- dimension_indicator: DimensionIndicator,
-}
-
-impl RoomTool {
- /// Create a new room tool where no rooms have been drawn yet.
- pub fn new(keybindings: RoomToolKeybindings) -> Self {
- Self {
- keybindings,
- unfinished_rect: None,
- dimension_indicator: DimensionIndicator::new(),
- }
- }
-}
-
-impl Tool for RoomTool {
- fn deactivate(&mut self) {
- self.unfinished_rect = None;
- self.dimension_indicator.clear_dimensions();
- }
-
- fn active_update(
- &mut self,
- map_data: &mut MapData,
- rl: &RaylibHandle,
- transform: &Transform,
- mouse_blocked: bool,
- ) {
- let mouse_pos_m = transform.point_px_to_m(&rl.get_mouse_position().into());
- // Update the currently drawn rectangle, if it exists, and also its dimension indicator.
- if let Some((ref pos1, ref mut pos2)) = &mut self.unfinished_rect {
- *pos2 = snap_to_grid(mouse_pos_m, SNAP_SIZE);
-
- self.dimension_indicator.update_dimensions(&[*pos1, *pos2]);
- }
-
- // Start or finish drawing the currently unfinished rectangle
- if self.keybindings.finish_draw.is_pressed(rl, mouse_blocked)
- && self.unfinished_rect.is_some()
- {
- let (pos1, pos2) = self.unfinished_rect.take().unwrap();
- self.dimension_indicator.clear_dimensions();
- map_data.rooms_mut().push(Rect::bounding_rect(pos1, pos2));
- } else if self.keybindings.start_draw.is_pressed(rl, mouse_blocked) {
- let snapped_mouse_pos = snap_to_grid(mouse_pos_m, SNAP_SIZE);
- self.unfinished_rect = Some((snapped_mouse_pos, snapped_mouse_pos))
- }
-
- if self.keybindings.abort_draw.is_pressed(rl, false) {
- self.unfinished_rect = None;
- }
- }
-
- fn draw(&self, map_data: &MapData, rld: &mut RaylibDrawHandle, transform: &Transform) {
- // Draw all finished rectangles.
- for &rect in map_data.rooms() {
- rld.draw_rectangle_rec(
- transform.rect_m_to_px(&rect),
- Color {
- r: 180,
- g: 180,
- b: 180,
- a: 255,
- },
- );
- }
-
- // Do the same for the unfinished rectangle
- if let Some((pos1, pos2)) = self.unfinished_rect {
- rld.draw_rectangle_rec(
- transform.rect_m_to_px(&Rect::bounding_rect(pos1, pos2)),
- Color {
- r: 150,
- g: 200,
- b: 150,
- a: 255,
- },
- );
-
- self.dimension_indicator.draw(rld, transform);
- }
- }
-
- fn activation_key(&self) -> Button {
- self.keybindings.activation_key()
- }
-}
diff --git a/src/tool/wall_tool.rs b/src/tool/wall_tool.rs
index d86d0af..b958799 100644
--- a/src/tool/wall_tool.rs
+++ b/src/tool/wall_tool.rs
@@ -1,23 +1,17 @@
use super::Tool;
-use crate::button::Button;
-use crate::config::{ToolKeybindings, WallToolKeybindings};
-use crate::grid::{snap_to_grid, SNAP_SIZE};
-use crate::map_data::MapData;
-use crate::math::Vec2;
+use crate::map::Map;
+use crate::math::{LineSegment, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
use raylib::ffi::{Color, Vector2};
-use raylib::RaylibHandle;
pub struct WallTool {
- keybindings: WallToolKeybindings,
- unfinished_wall: Option<(Vec2<f64>, Vec2<f64>)>,
+ unfinished_wall: Option<LineSegment<f64>>,
}
impl WallTool {
- pub fn new(keybindings: WallToolKeybindings) -> Self {
+ pub fn new() -> Self {
Self {
- keybindings,
unfinished_wall: None,
}
}
@@ -28,86 +22,19 @@ impl Tool for WallTool {
self.unfinished_wall = None;
}
- fn active_update(
- &mut self,
- map_data: &mut MapData,
- rl: &RaylibHandle,
- transform: &Transform,
- mouse_blocked: bool,
- ) {
- let mouse_pos_m = transform.point_px_to_m(&rl.get_mouse_position().into());
- if let Some((_, ref mut pos2)) = &mut self.unfinished_wall {
- *pos2 = snap_to_grid(mouse_pos_m, SNAP_SIZE);
- }
-
- if self
- .keybindings
- .finish_segment
- .is_pressed(rl, mouse_blocked)
- && self.unfinished_wall.is_some()
- {
- let (pos1, pos2) = self.unfinished_wall.unwrap();
- map_data.walls_mut().push((pos1, pos2));
- self.unfinished_wall = Some((pos2, pos2));
- } else if self.keybindings.start_wall.is_pressed(rl, mouse_blocked) {
- let snapped_mouse_pos = snap_to_grid(mouse_pos_m, SNAP_SIZE);
- self.unfinished_wall = Some((snapped_mouse_pos, snapped_mouse_pos))
- }
-
- if self.keybindings.abort_segment.is_pressed(rl, false) {
- self.unfinished_wall = None;
+ fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) {
+ if let Some(ref mut wall) = &mut self.unfinished_wall {
+ wall.end = *mouse_pos_m;
}
}
- fn draw(&self, map_data: &MapData, rld: &mut RaylibDrawHandle, transform: &Transform) {
- for &(pos1, pos2) in map_data.walls() {
- let pos1_px = transform.point_m_to_px(&pos1);
- let pos2_px = transform.point_m_to_px(&pos2);
- rld.draw_line_ex(
- pos1_px,
- pos2_px,
- transform.length_m_to_px(0.1) as f32,
- Color {
- r: 200,
- g: 120,
- b: 120,
- a: 255,
- },
- );
-
- /* Find walls that end/start at the start or end of this wall and draw part of a circle
- * to join these two walls more nicely.
- */
- for &(other1, other2) in map_data.walls() {
- // Ignore the line segment if it's the same wall
- if pos1 == other1 && pos2 == other2 {
- continue;
- }
-
- // TODO: Only draw segments when introducing transparency.
- for pos in [pos1, pos2].iter() {
- if *pos == other1 || *pos == other2 {
- rld.draw_circle_v(
- transform.point_m_to_px(&pos),
- transform.length_m_to_px(0.05) as f32,
- Color {
- r: 200,
- g: 120,
- b: 120,
- a: 255,
- },
- );
- }
- }
- }
- }
-
- if let Some((pos1, pos2)) = self.unfinished_wall {
- let pos1: Vector2 = transform.point_m_to_px(&pos1).into();
- let pos2: Vector2 = transform.point_m_to_px(&pos2).into();
+ fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
+ if let Some(ref wall) = self.unfinished_wall {
+ let start: Vector2 = transform.point_m_to_px(&wall.start).into();
+ let end: Vector2 = transform.point_m_to_px(&wall.end).into();
rld.draw_line_ex(
- pos1,
- pos2,
+ start,
+ end,
transform.length_m_to_px(0.1) as f32,
Color {
r: 150,
@@ -119,7 +46,17 @@ impl Tool for WallTool {
}
}
- fn activation_key(&self) -> Button {
- self.keybindings.activation_key()
+ fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) {
+ if let Some(wall) = self.unfinished_wall.take() {
+ // Continue with the next wall straight away.
+ self.unfinished_wall = Some(LineSegment::new(wall.end, wall.end));
+ map.push_wall(wall);
+ } else {
+ self.unfinished_wall = Some(LineSegment::new(*mouse_pos_m, *mouse_pos_m));
+ }
+ }
+
+ fn abort(&mut self) {
+ self.unfinished_wall = None;
}
}