1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
//! Tool to create rooms in the shape of generic polygons.
use super::Tool;
use crate::client::colours::DEFAULT_COLOURS;
use crate::client::map::Map;
use crate::client::transform::Transform;
use crate::client::FLOAT_MARGIN;
use crate::math::{self, PolygonGraph, Vec2};
use crate::net::{Cargo, Connection};
use crate::world::Room;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
/// The tool itself.
pub struct PolygonRoomTool {
unfinished_room: Option<(PolygonGraph<f64>, Vec2<f64>)>,
last_mouse_pos_m: Vec2<f64>,
}
impl PolygonRoomTool {
/// Create a new polygon room tool. There should be only one instance and it should be created
/// in the editor.
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
unfinished_room: None,
last_mouse_pos_m: Vec2::new(0., 0.),
}
}
/* Helper function to try and finish the currently drawn polygon. If successful, it will add it
* to the map, clear the currently drawn polygon and return bool. Otherwise it will leave the
* unfinished polygon as is and return false without pushing anything.
*/
fn try_push(&mut self, server: &Connection<Cargo>) -> bool {
if self.unfinished_room.is_none() {
return false;
}
match self
.unfinished_room
.as_ref()
.unwrap()
.0
.clone()
.bounding_polygon(FLOAT_MARGIN)
{
Some(polygon) => {
server.send(Cargo::AddRoom(Room::new(polygon)));
self.unfinished_room = None;
true
}
None => false,
}
}
}
impl Tool for PolygonRoomTool {
fn deactivate(&mut self) {
self.unfinished_room = None;
}
fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) {
// Update the last mouse position that was seen for later use.
self.last_mouse_pos_m = *mouse_pos_m;
}
fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
if let Some((graph, last_node)) = &self.unfinished_room {
/* To turn the graph into a polygon, we need a copy, might as well do
* it now, so we can add the working corner to it.
*/
let mut graph = graph.clone();
// Add the current mouse position as the next position if possible.
graph.add_edge(&last_node, &self.last_mouse_pos_m);
if graph.num_nodes() <= 1 {
// Only able to draw a point
rld.draw_circle_v(
transform.point_m_to_px(&self.last_mouse_pos_m),
transform.length_m_to_px(0.1) as f32,
DEFAULT_COLOURS.room_selected,
);
} else if let Some(polygon) = graph.clone().bounding_polygon(FLOAT_MARGIN) {
let triangles = math::triangulate(polygon, FLOAT_MARGIN);
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]),
DEFAULT_COLOURS.room_selected,
)
}
} else {
// For some reason the polygon creation failed. Draw lines for the edges instead.
for edge in graph.edge_iter() {
rld.draw_line_ex(
transform.point_m_to_px(&edge.start),
transform.point_m_to_px(&edge.end),
transform.length_m_to_px(0.1) as f32,
DEFAULT_COLOURS.room_selected,
);
}
}
}
}
fn place_single(
&mut self,
_map: &mut Map,
server: &Connection<Cargo>,
mouse_pos_m: &Vec2<f64>,
) {
if let Some((ref mut graph, ref mut last_placed)) = &mut self.unfinished_room {
// If the corner already exists in the polygon, try to finish and push it after adding the
// next edge.
let try_finish = graph.has_node(&mouse_pos_m);
// Add an edge from the last corner to the currently active position if possible.
if graph.add_edge(last_placed, &mouse_pos_m) {
*last_placed = *mouse_pos_m;
}
if try_finish {
self.try_push(server);
}
} else {
// Start a new unfinished polygon
self.unfinished_room = Some((PolygonGraph::new(), *mouse_pos_m));
}
}
fn finish(&mut self, _map: &mut Map, server: &Connection<Cargo>) {
self.try_push(server);
}
fn abort(&mut self) {
self.unfinished_room = None;
}
}
|