use bevy::prelude::*;
use crate::{
core::parameters::{SimulationSettings, Stick},
objects::{cloth::spawn_cloth, cube::spawn_cube, rope::spawn_rope, square::spawn_square},
plugins::{
info::plugin::ActiveInfoTarget,
modification::utils::{
cut_sticks, grab_point, lock_affected_points, perge_info_target, point_info,
purge_line, ray_coords_at, spawn_stick,
},
play_state::plugin::SimulationPlayState,
schedule::plugin::SimulationCycle,
},
prelude::{MaterialType, MeshType, Point},
};
pub struct ModificationPlugin;
impl Plugin for ModificationPlugin {
fn build(&self, app: &mut App) {
app.init_state::<ModificationTarget>().add_systems(
Update,
(handle_target_change, handle_modification_event)
.chain()
.in_set(SimulationCycle::Preparation1),
);
}
}
#[derive(Event, Clone, PartialEq)]
pub enum ModifyEventType {
Left(RelativeWindowPosition),
Right(RelativeWindowPosition),
Middle(RelativeWindowPosition),
Move(RelativeWindowPosition),
Release(RelativeWindowPosition),
}
#[derive(Clone, PartialEq)]
pub struct RelativeWindowPosition {
pub event_x: f32,
pub event_y: f32,
pub container_h: f32,
pub container_w: f32,
}
impl RelativeWindowPosition {
pub fn create_ray(&self, camera: &Camera, camera_transform: &GlobalTransform) -> Ray3d {
if let Ok(cast_ray) =
camera.viewport_to_world(camera_transform, Vec2::new(self.event_x, self.event_y))
{
cast_ray
} else {
Ray3d::new(Vec3::new(0., 0., 0.), Dir3::NEG_Z)
}
}
}
#[derive(Event, Clone, PartialEq, States, Debug, Hash, Eq, Default)]
pub enum ModificationTarget {
Point,
Line,
Lock,
Cut,
Cutting,
SpawnRope,
SpawnSquare,
SpawnCloth,
SpawnCube,
Delete,
PointInfo,
Grab,
#[default]
None,
}
#[derive(Component)]
pub struct LineConnections {
pub p0: Option<Entity>,
pub p1: Option<Entity>,
}
pub fn handle_target_change(
mut next_state: ResMut<NextState<SimulationPlayState>>,
mut modification_target: ResMut<NextState<ModificationTarget>>,
mut event_reader: EventReader<ModificationTarget>,
mut commands: Commands,
line_query: Query<(Entity, &mut LineConnections)>,
) {
for event in event_reader.read() {
if event != &ModificationTarget::None {
next_state.set(SimulationPlayState::Paused);
}
if event == &ModificationTarget::Line {
purge_line(&line_query, &mut commands);
}
modification_target.set(event.clone())
}
}
pub fn handle_modification_event(
mut commands: Commands,
mut event_reader: EventReader<ModifyEventType>,
current_target: Res<State<ModificationTarget>>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut stick_query: Query<(Entity, &mut Stick)>,
mut params: ParamSet<(
Query<&Point>,
Query<(&mut MeshMaterial3d<StandardMaterial>, &mut Point)>,
Query<(Entity, &Point)>,
Query<(Entity, &Point), With<ActiveInfoTarget>>,
Query<(Entity, &mut Point)>,
)>,
mut next_target: ResMut<NextState<ModificationTarget>>,
mut line_query: Query<(Entity, &mut LineConnections)>,
sim_settings: Res<SimulationSettings>,
camera: Query<(&Camera, &GlobalTransform), With<Camera3d>>,
) {
let point_material = MaterialType::Color([1., 1., 1., 1.]);
let stick_material = MaterialType::Color([1., 1., 1., 0.5]);
for event in event_reader.read() {
match event {
ModifyEventType::Left(relative_pos) => {
let (camera, camera_transform) = match camera.single() {
Ok(queried_entity) => queried_entity,
Err(_) => continue,
};
let ray = relative_pos.create_ray(camera, camera_transform);
let view_plane_world_pos = match ray_coords_at(ray, 0.) {
Some(coordinates) => coordinates,
None => continue,
};
match current_target.get() {
ModificationTarget::Point => {
let point = Point::new(view_plane_world_pos, view_plane_world_pos, false);
point.spawn(
&mut commands,
&mut meshes,
&mut materials,
MeshType::Sphere,
MaterialType::Color([1., 1., 1., 1.]),
);
}
ModificationTarget::Line => spawn_stick(
ray,
&mut line_query,
¶ms.p2(),
&mut commands,
&mut meshes,
&mut materials,
stick_material.clone(),
sim_settings.interaction_radius,
),
ModificationTarget::Lock => {
lock_affected_points(
ray,
&mut params.p1(),
&mut materials,
sim_settings.interaction_radius,
);
}
ModificationTarget::Cut => next_target.set(ModificationTarget::Cutting),
ModificationTarget::SpawnSquare => {
spawn_square(
&mut commands,
&mut meshes,
&mut materials,
point_material.clone(),
stick_material.clone(),
view_plane_world_pos,
&sim_settings,
);
}
ModificationTarget::SpawnRope => {
spawn_rope(
&mut commands,
&mut meshes,
&mut materials,
point_material.clone(),
stick_material.clone(),
&sim_settings,
view_plane_world_pos,
);
}
ModificationTarget::SpawnCloth => spawn_cloth(
&mut commands,
&mut meshes,
point_material.clone(),
stick_material.clone(),
&mut materials,
&sim_settings,
),
ModificationTarget::SpawnCube => spawn_cube(
&mut commands,
&mut meshes,
&mut materials,
point_material.clone(),
stick_material.clone(),
&view_plane_world_pos,
&sim_settings,
),
ModificationTarget::PointInfo => {
perge_info_target(¶ms.p3(), &mut commands);
point_info(
ray,
¶ms.p2(),
&mut commands,
sim_settings.interaction_radius,
)
}
ModificationTarget::None => {
next_target.set(ModificationTarget::Grab)
}
_ => (),
}
}
ModifyEventType::Right(_relative_pos) => {}
ModifyEventType::Middle(_relative_pos) => {}
ModifyEventType::Move(relative_pos) => {
let (camera, camera_transform) = match camera.single() {
Ok(queried_entity) => queried_entity,
Err(_) => continue,
};
let ray = relative_pos.create_ray(camera, camera_transform);
match current_target.get() {
ModificationTarget::Cutting => cut_sticks(
ray,
&mut stick_query,
¶ms.p0(),
&mut commands,
sim_settings.interaction_radius,
),
ModificationTarget::Grab => grab_point(params.p4(), ray),
_ => (),
}
}
ModifyEventType::Release(_) => {
match current_target.get() {
ModificationTarget::Cutting => {
next_target.set(ModificationTarget::Cut)
}
ModificationTarget::Grab => next_target.set(ModificationTarget::None),
_ => (),
}
}
}
}
}