1use bevy::prelude::*;
2
3use crate::{
4 core::parameters::{SimulationSettings, Stick},
5 objects::{cloth::spawn_cloth, cube::spawn_cube, rope::spawn_rope, square::spawn_square},
6 plugins::{
7 info::plugin::ActiveInfoTarget,
8 modification::utils::{
9 cut_sticks, grab_point, lock_affected_points, perge_info_target, point_info,
10 purge_line, ray_coords_at, spawn_stick,
11 },
12 play_state::plugin::SimulationPlayState,
13 schedule::plugin::SimulationCycle,
14 },
15 prelude::{MaterialType, MeshType, Point},
16};
17
18pub struct ModificationPlugin;
19impl Plugin for ModificationPlugin {
20 fn build(&self, app: &mut App) {
21 app.init_state::<ModificationTarget>().add_systems(
22 Update,
23 (handle_target_change, handle_modification_event)
24 .chain()
25 .in_set(SimulationCycle::Preparation1),
26 );
27 }
28}
29
30#[derive(Event, Clone, PartialEq)]
31pub enum ModifyEventType {
32 Left(RelativeWindowPosition),
33 Right(RelativeWindowPosition),
34 Middle(RelativeWindowPosition),
35 Move(RelativeWindowPosition),
36 Release(RelativeWindowPosition),
37}
38#[derive(Clone, PartialEq)]
39pub struct RelativeWindowPosition {
40 pub event_x: f32,
41 pub event_y: f32,
42 pub container_h: f32,
43 pub container_w: f32,
44}
45impl RelativeWindowPosition {
46 pub fn create_ray(&self, camera: &Camera, camera_transform: &GlobalTransform) -> Ray3d {
49 if let Ok(cast_ray) =
50 camera.viewport_to_world(camera_transform, Vec2::new(self.event_x, self.event_y))
51 {
52 cast_ray
53 } else {
54 Ray3d::new(Vec3::new(0., 0., 0.), Dir3::NEG_Z)
55 }
56 }
57}
58
59#[derive(Event, Clone, PartialEq, States, Debug, Hash, Eq, Default)]
60pub enum ModificationTarget {
61 Point,
63 Line,
65 Lock,
67 Cut,
69 Cutting,
72 SpawnRope,
74 SpawnSquare,
76 SpawnCloth,
78 SpawnCube,
80 Delete,
82 PointInfo,
83 Grab,
84 #[default]
85 None,
86}
87
88#[derive(Component)]
89pub struct LineConnections {
90 pub p0: Option<Entity>,
91 pub p1: Option<Entity>,
92}
93
94pub fn handle_target_change(
95 mut next_state: ResMut<NextState<SimulationPlayState>>,
96 mut modification_target: ResMut<NextState<ModificationTarget>>,
97 mut event_reader: EventReader<ModificationTarget>,
98 mut commands: Commands,
99 line_query: Query<(Entity, &mut LineConnections)>,
100) {
101 for event in event_reader.read() {
102 if event != &ModificationTarget::None {
105 next_state.set(SimulationPlayState::Paused);
106 }
107 if event == &ModificationTarget::Line {
108 purge_line(&line_query, &mut commands);
109 }
110 modification_target.set(event.clone())
111 }
112}
113
114pub fn handle_modification_event(
115 mut commands: Commands,
116 mut event_reader: EventReader<ModifyEventType>,
117 current_target: Res<State<ModificationTarget>>,
118 mut meshes: ResMut<Assets<Mesh>>,
119 mut materials: ResMut<Assets<StandardMaterial>>,
120 mut stick_query: Query<(Entity, &mut Stick)>,
121 mut params: ParamSet<(
122 Query<&Point>,
123 Query<(&mut MeshMaterial3d<StandardMaterial>, &mut Point)>,
124 Query<(Entity, &Point)>,
125 Query<(Entity, &Point), With<ActiveInfoTarget>>,
126 Query<(Entity, &mut Point)>,
127 )>,
128 mut next_target: ResMut<NextState<ModificationTarget>>,
129 mut line_query: Query<(Entity, &mut LineConnections)>,
130 sim_settings: Res<SimulationSettings>,
131 camera: Query<(&Camera, &GlobalTransform), With<Camera3d>>,
132) {
133 let point_material = MaterialType::Color([1., 1., 1., 1.]);
134 let stick_material = MaterialType::Color([1., 1., 1., 0.5]);
135
136 for event in event_reader.read() {
137 match event {
138 ModifyEventType::Left(relative_pos) => {
139 let (camera, camera_transform) = match camera.single() {
140 Ok(queried_entity) => queried_entity,
141 Err(_) => continue,
142 };
143
144 let ray = relative_pos.create_ray(camera, camera_transform);
145
146 let view_plane_world_pos = match ray_coords_at(ray, 0.) {
147 Some(coordinates) => coordinates,
148 None => continue,
149 };
150
151 match current_target.get() {
152 ModificationTarget::Point => {
153 let point = Point::new(view_plane_world_pos, view_plane_world_pos, false);
154 point.spawn(
155 &mut commands,
156 &mut meshes,
157 &mut materials,
158 MeshType::Sphere,
159 MaterialType::Color([1., 1., 1., 1.]),
160 );
161 }
162 ModificationTarget::Line => spawn_stick(
163 ray,
164 &mut line_query,
165 ¶ms.p2(),
166 &mut commands,
167 &mut meshes,
168 &mut materials,
169 stick_material.clone(),
170 sim_settings.interaction_radius,
171 ),
172 ModificationTarget::Lock => {
173 lock_affected_points(
174 ray,
175 &mut params.p1(),
176 &mut materials,
177 sim_settings.interaction_radius,
178 );
179 }
180 ModificationTarget::Cut => next_target.set(ModificationTarget::Cutting),
181 ModificationTarget::SpawnSquare => {
182 spawn_square(
183 &mut commands,
184 &mut meshes,
185 &mut materials,
186 point_material.clone(),
187 stick_material.clone(),
188 view_plane_world_pos,
189 &sim_settings,
190 );
191 }
192 ModificationTarget::SpawnRope => {
193 spawn_rope(
194 &mut commands,
195 &mut meshes,
196 &mut materials,
197 point_material.clone(),
198 stick_material.clone(),
199 &sim_settings,
200 view_plane_world_pos,
201 );
202 }
203 ModificationTarget::SpawnCloth => spawn_cloth(
204 &mut commands,
205 &mut meshes,
206 point_material.clone(),
207 stick_material.clone(),
208 &mut materials,
209 &sim_settings,
210 ),
211 ModificationTarget::SpawnCube => spawn_cube(
212 &mut commands,
213 &mut meshes,
214 &mut materials,
215 point_material.clone(),
216 stick_material.clone(),
217 &view_plane_world_pos,
218 &sim_settings,
219 ),
220 ModificationTarget::PointInfo => {
221 perge_info_target(¶ms.p3(), &mut commands);
223 point_info(
224 ray,
225 ¶ms.p2(),
226 &mut commands,
227 sim_settings.interaction_radius,
228 )
229 }
230 ModificationTarget::None => {
231 next_target.set(ModificationTarget::Grab)
233 }
234 _ => (),
235 }
236 }
237 ModifyEventType::Right(_relative_pos) => {}
238 ModifyEventType::Middle(_relative_pos) => {}
239 ModifyEventType::Move(relative_pos) => {
240 let (camera, camera_transform) = match camera.single() {
241 Ok(queried_entity) => queried_entity,
242 Err(_) => continue,
243 };
244
245 let ray = relative_pos.create_ray(camera, camera_transform);
246
247 match current_target.get() {
248 ModificationTarget::Cutting => cut_sticks(
249 ray,
250 &mut stick_query,
251 ¶ms.p0(),
252 &mut commands,
253 sim_settings.interaction_radius,
254 ),
255 ModificationTarget::Grab => grab_point(params.p4(), ray),
256
257 _ => (),
258 }
259 }
260 ModifyEventType::Release(_) => {
261 match current_target.get() {
262 ModificationTarget::Cutting => {
263 next_target.set(ModificationTarget::Cut)
265 }
266 ModificationTarget::Grab => next_target.set(ModificationTarget::None),
267 _ => (),
268 }
269 }
270 }
271 }
272}