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::{self, Polygon, Vec2}; use crate::transform::Transform; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; use raylib::ffi::Color; 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, 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) { // 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; 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, }, ) } } // Draw the current polygon if let Some(corners) = &self.unfinished_polygon { let mut corners = corners.clone(); corners.dedup(); match corners.len() { 0 | 1 => {} 2 => rld.draw_line_ex( transform.point_m_to_px(corners[0]), transform.point_m_to_px(corners[1]), transform.length_m_to_px(0.1), Color { r: 150, g: 200, b: 150, a: 255, }, ), _ => { let polygon = Polygon::new(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]), Color { r: 150, g: 200, b: 150, a: 255, }, ) } } } self.dimension_indicator.draw(rld, transform); } } fn activation_key(&self) -> Button { self.keybindings.activation_key() } }