use super::Tool; use crate::colours::DEFAULT_COLOURS; use crate::map::Map; use crate::math::{self, Polygon, PolygonError, Vec2}; use crate::transform::Transform; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; struct UnfinishedPolygon { pub corners: Vec>, pub working_corner: Vec2, } pub struct PolygonRoomTool { unfinished_polygon: Option, } impl UnfinishedPolygon { // Check the validity of the already completed corners only pub fn check_validity_completed(&self) -> Result<(), PolygonError> { Polygon::check_validity(&self.corners) } // Check the validity of the already completed corners, but with the working corner wedged // between the last and first corner (making it the new last corner). pub fn check_validity_all(&self) -> Result<(), PolygonError> { // TODO: Is this possible without changing the mutability of self and without reallocation? let mut corners = self.corners.clone(); corners.push(self.working_corner); Polygon::check_validity(&corners) } pub fn try_into_completed(&mut self) -> Option> { match self.check_validity_completed() { Ok(()) => Some(Polygon::new_unchecked(self.corners.drain(..).collect())), Err(e) => { warn!("Cannot turn placed corners into a polygon: {}", e); None } } } pub fn try_into_all(&mut self) -> Option> { match self.check_validity_all() { Ok(()) => { self.corners.push(self.working_corner); Some(Polygon::new_unchecked(self.corners.drain(..).collect())) } Err(e) => { warn!( "Cannot turn corners with newest corner into a polygon: {}", e ); None } } } pub fn try_push_working(&mut self) -> Result<(), PolygonError> { assert!(!self.corners.is_empty()); if self.corners.len() == 1 { return if self.corners[0] != self.working_corner { self.corners.push(self.working_corner); Ok(()) } else { Err(PolygonError::VertexDoubling(self.corners[0], 0)) }; } self.check_validity_all()?; self.corners.push(self.working_corner); Ok(()) } } impl PolygonRoomTool { pub fn new() -> Self { Self { unfinished_polygon: None, } } } impl Tool for PolygonRoomTool { fn deactivate(&mut self) { self.unfinished_polygon = None; } fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2) { // 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 = *mouse_pos_m; } } 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 { rld.draw_line_ex( transform.point_m_to_px(&polygon.corners[0]), transform.point_m_to_px(&polygon.working_corner), transform.length_m_to_px(0.1) as f32, DEFAULT_COLOURS.room_selected, ); } else if polygon.corners.len() == 2 { // We have three valid corners, so we can draw a triangle. rld.draw_triangle( transform.point_m_to_px(&polygon.corners[0]), transform.point_m_to_px(&polygon.corners[1]), transform.point_m_to_px(&polygon.working_corner), DEFAULT_COLOURS.room_selected, ) } else { // A proper polygon can be drawn. if polygon.check_validity_all().is_ok() { let mut corners = polygon.corners.clone(); corners.push(polygon.working_corner); let polygon = Polygon::new_unchecked(corners); let triangles = math::triangulate(polygon); for triangle in triangles { let triangle: [Vec2; 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]), DEFAULT_COLOURS.room_selected, ) } } else if polygon.check_validity_completed().is_ok() { let polygon = Polygon::new_unchecked(polygon.corners.clone()); let triangles = math::triangulate(polygon); for triangle in triangles { let triangle: [Vec2; 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]), DEFAULT_COLOURS.room_selected, ) } } } } } fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2) { 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, }); } } 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 abort(&mut self) { self.unfinished_polygon = None; } }