shape editing works now!(also moved to using Transform)
This commit is contained in:
parent
01f7cfb6b7
commit
f52c7b9057
4 changed files with 323 additions and 65 deletions
192
src/create.rs
192
src/create.rs
|
@ -1,31 +1,62 @@
|
||||||
|
use bevy::math::Vec3Swizzles;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use bevy_prototype_lyon::prelude::*;
|
use bevy_prototype_lyon::prelude::*;
|
||||||
|
|
||||||
pub fn create_sys(
|
pub fn create_sys(
|
||||||
mut coms: Commands,
|
mut coms: Commands,
|
||||||
|
p_size: Res<PointSize>,
|
||||||
state: Res<UiState>,
|
state: Res<UiState>,
|
||||||
mouse: Res<Input<MouseButton>>,
|
mouse: Res<Input<MouseButton>>,
|
||||||
wnds: Res<Windows>,
|
wnds: Res<Windows>,
|
||||||
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
|
||||||
mut first_point: Local<Option<ShapeData>>,
|
mut first_point: Local<Option<ShapeData>>,
|
||||||
paths: Query<&mut Path>,
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
||||||
spoints: Query<&SPoint>,
|
mut paths: Query<&mut Path>,
|
||||||
|
mut transforms: Query<&mut Transform>,
|
||||||
) {
|
) {
|
||||||
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
||||||
|
|
||||||
if let Some(mouse_pos) = mouse_pos {
|
if let Some(mouse_pos) = mouse_pos {
|
||||||
|
|
||||||
if let Some(sd) = &mut *first_point {
|
if let Some(sd) = &mut *first_point {
|
||||||
update_main_shape_creation(paths, spoints, sd, mouse_pos);
|
update_main_shape_creation(&mut paths, &transforms, sd, mouse_pos);
|
||||||
|
|
||||||
if mouse.just_released(MouseButton::Left) {
|
if mouse.just_released(MouseButton::Left) {
|
||||||
let done = insert_edge_to_shape_creation(sd, mouse_pos, &mut coms);
|
let done = insert_edge_to_shape_creation(&mut coms, sd, mouse_pos, p_size.0);
|
||||||
|
|
||||||
if done {
|
if done {
|
||||||
|
let center = add_center_point(&mut coms, sd, &transforms, mouse_pos, p_size.0);
|
||||||
|
|
||||||
|
// Update each point to be relative to the new center!
|
||||||
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
||||||
|
t.translation = center.extend(0.0);
|
||||||
|
}
|
||||||
|
if let Ok(mut t) = transforms.get_mut(sd.center.unwrap()) {
|
||||||
|
t.translation = Vec3::new(0.0, 0.0, 1.0); // Just to make sure the center is centered
|
||||||
|
}
|
||||||
|
for edge in sd.edges.iter() {
|
||||||
|
if let Ok(mut t) = transforms.get_mut(*edge) {
|
||||||
|
t.translation -= center.extend(0.0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If we dont have a transform in the query for the relevant entity,
|
||||||
|
// then it should be the entity we just inserted, and we can just override its transform
|
||||||
|
coms.entity(*edge)
|
||||||
|
.insert(Transform::from_translation((mouse_pos - center).extend(1.0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize_shape_redraw(&mut paths, &transforms, sd, mouse_pos - center);
|
||||||
|
|
||||||
|
let mut ms = coms.entity(sd.main_shape);
|
||||||
|
ms.add_child(sd.center.unwrap());
|
||||||
|
for e in sd.edges.iter() {
|
||||||
|
ms.add_child(*e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
coms.spawn()
|
coms.spawn()
|
||||||
.insert(first_point.take().unwrap());
|
.insert(first_point.take().unwrap());
|
||||||
|
|
||||||
*first_point = None;
|
*first_point = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,29 +74,119 @@ pub fn create_sys(
|
||||||
else if mouse.just_released(MouseButton::Left) {
|
else if mouse.just_released(MouseButton::Left) {
|
||||||
// We can now spawn a shape in the current mouse position...
|
// We can now spawn a shape in the current mouse position...
|
||||||
// Spawn the first point
|
// Spawn the first point
|
||||||
*first_point = Some(create_new_shape(&mut coms, mouse_pos, state.create_shape));
|
*first_point = Some(create_new_shape(&mut coms, mouse_pos, state.create_shape, p_size.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a new edge/point to the currently created shape, return if the shape is complete
|
/// lpos - should be in local coordinates!
|
||||||
fn insert_edge_to_shape_creation(
|
fn finalize_shape_redraw(
|
||||||
sd: &mut ShapeData,
|
paths: &mut Query<&mut Path>,
|
||||||
mpos: Vec2,
|
transforms: &Query<&mut Transform>,
|
||||||
|
sd: &ShapeData,
|
||||||
|
lpos: Vec2, // Last position(1 we just inserted)
|
||||||
|
) {
|
||||||
|
let path = match sd.shape {
|
||||||
|
CreateShape::Triangle => {
|
||||||
|
assert!(sd.edges.len() == 3);
|
||||||
|
let fp = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let sp = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
let shape = shapes::Polygon {
|
||||||
|
points: Vec::from([fp, sp, lpos]),
|
||||||
|
closed: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
ShapePath::build_as(&shape)
|
||||||
|
},
|
||||||
|
CreateShape::Square => {
|
||||||
|
assert!(sd.edges.len() == 2);
|
||||||
|
let opposite_point = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let ext = (lpos - opposite_point).abs();
|
||||||
|
|
||||||
|
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::Center };
|
||||||
|
ShapePath::build_as(&shape)
|
||||||
|
},
|
||||||
|
CreateShape::Circle => {
|
||||||
|
assert!(sd.center.is_some());
|
||||||
|
let center= transforms.get(sd.center.unwrap()).unwrap().translation.xy();
|
||||||
|
|
||||||
|
let shape = shapes::Circle { radius: (lpos - center).length(), center: Vec2::ZERO };
|
||||||
|
ShapePath::build_as(&shape)
|
||||||
|
},
|
||||||
|
CreateShape::Capsule => {
|
||||||
|
panic!("Capsule creation not implemented yet!");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut p) = paths.get_mut(sd.main_shape) {
|
||||||
|
*p = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Adds a center point to the shape, returning the center location(due to commands not being run until end of frame)
|
||||||
|
fn add_center_point(
|
||||||
coms: &mut Commands,
|
coms: &mut Commands,
|
||||||
) -> bool {
|
sd: &mut ShapeData,
|
||||||
// Spawn the new point
|
transforms: &Query<&mut Transform>,
|
||||||
// Spawn the first point(where the user just clicked)
|
l_pos: Vec2, // We call this function before commands are executed, so we dont have the last entity YET!
|
||||||
|
p_size: f32,
|
||||||
|
) -> Vec2 {
|
||||||
|
if sd.center.is_some() {
|
||||||
|
return transforms.get(sd.center.unwrap()).unwrap().translation.xy();
|
||||||
|
}
|
||||||
|
|
||||||
|
let center = match sd.shape {
|
||||||
|
CreateShape::Triangle => {
|
||||||
|
assert!(sd.edges.len() == 3);
|
||||||
|
|
||||||
|
let fp = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let sp = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
(fp + sp + l_pos) / 3.0
|
||||||
|
},
|
||||||
|
CreateShape::Square => {
|
||||||
|
assert!(sd.edges.len() == 2);
|
||||||
|
|
||||||
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
(e1 + l_pos) * 0.5
|
||||||
|
},
|
||||||
|
_ => panic!("Should not be reachable, as circle has a center and capsule is disabled for now!"),
|
||||||
|
};
|
||||||
|
|
||||||
let shape = shapes::Circle {
|
let shape = shapes::Circle {
|
||||||
radius: 3.0,
|
radius: p_size,
|
||||||
center: mpos,
|
center: Vec2::ZERO,
|
||||||
};
|
};
|
||||||
let np = coms.spawn_bundle(GeometryBuilder::build_as(
|
let np = coms.spawn_bundle(GeometryBuilder::build_as(
|
||||||
&shape,
|
&shape,
|
||||||
DrawMode::Fill(FillMode::color(Color::RED)),
|
DrawMode::Fill(FillMode::color(Color::RED)),
|
||||||
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
||||||
))
|
))
|
||||||
.insert(SPoint(mpos))
|
.id();
|
||||||
|
sd.center = Some(np);
|
||||||
|
|
||||||
|
center
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts a new edge/point to the currently created shape, return if the shape is complete
|
||||||
|
fn insert_edge_to_shape_creation(
|
||||||
|
coms: &mut Commands,
|
||||||
|
sd: &mut ShapeData,
|
||||||
|
mpos: Vec2,
|
||||||
|
p_size: f32,
|
||||||
|
) -> bool {
|
||||||
|
// Spawn the new point
|
||||||
|
// Spawn the first point(where the user just clicked)
|
||||||
|
let shape = shapes::Circle {
|
||||||
|
radius: p_size,
|
||||||
|
center: Vec2::ZERO,
|
||||||
|
};
|
||||||
|
let np = coms.spawn_bundle(GeometryBuilder::build_as(
|
||||||
|
&shape,
|
||||||
|
DrawMode::Fill(FillMode::color(Color::RED)),
|
||||||
|
Transform::from_translation(mpos.extend(1.0))
|
||||||
|
))
|
||||||
.id();
|
.id();
|
||||||
|
|
||||||
match sd.shape {
|
match sd.shape {
|
||||||
|
@ -77,7 +198,7 @@ fn insert_edge_to_shape_creation(
|
||||||
sd.edges.push(np);
|
sd.edges.push(np);
|
||||||
sd.edges.len() == 2
|
sd.edges.len() == 2
|
||||||
},
|
},
|
||||||
CreateShape::SquareCenter | CreateShape::Circle => {
|
CreateShape::Circle => {
|
||||||
sd.edges.push(np);
|
sd.edges.push(np);
|
||||||
sd.edges.len() == 1
|
sd.edges.len() == 1
|
||||||
},
|
},
|
||||||
|
@ -98,22 +219,22 @@ fn insert_edge_to_shape_creation(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_main_shape_creation(
|
fn update_main_shape_creation(
|
||||||
mut paths: Query<&mut Path>,
|
paths: &mut Query<&mut Path>,
|
||||||
spoints: Query<&SPoint>,
|
transforms: &Query<&mut Transform>,
|
||||||
sd: &ShapeData,
|
sd: &ShapeData,
|
||||||
mpos: Vec2,
|
mpos: Vec2,
|
||||||
) {
|
) {
|
||||||
let path = match sd.shape {
|
let path = match sd.shape {
|
||||||
CreateShape::Triangle => {
|
CreateShape::Triangle => {
|
||||||
if sd.edges.len() == 1 {
|
if sd.edges.len() == 1 {
|
||||||
let first_point = spoints.get(sd.edges[0]).unwrap().0;
|
let first_point = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
|
||||||
let shape = shapes::Line(first_point, mpos);
|
let shape = shapes::Line(first_point, mpos);
|
||||||
ShapePath::build_as(&shape)
|
ShapePath::build_as(&shape)
|
||||||
}
|
}
|
||||||
else if sd.edges.len() == 2 {
|
else if sd.edges.len() == 2 {
|
||||||
let fp = spoints.get(sd.edges[0]).unwrap().0;
|
let fp = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
let sp = spoints.get(sd.edges[1]).unwrap().0;
|
let sp = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
|
||||||
let shape = shapes::Polygon {
|
let shape = shapes::Polygon {
|
||||||
points: Vec::from([fp, sp, mpos]),
|
points: Vec::from([fp, sp, mpos]),
|
||||||
|
@ -127,24 +248,16 @@ fn update_main_shape_creation(
|
||||||
},
|
},
|
||||||
CreateShape::Square => {
|
CreateShape::Square => {
|
||||||
assert!(sd.edges.len() == 1);
|
assert!(sd.edges.len() == 1);
|
||||||
let opposite_point = spoints.get(sd.edges[0]).unwrap().0;
|
let opposite_point = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
let ext = (mpos - opposite_point).abs();
|
let ext = (mpos - opposite_point).abs();
|
||||||
let center = mpos.min(opposite_point) + ext * 0.5;
|
let center = mpos.min(opposite_point) + ext * 0.5;
|
||||||
|
|
||||||
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::CustomCenter(center) };
|
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::CustomCenter(center) };
|
||||||
ShapePath::build_as(&shape)
|
ShapePath::build_as(&shape)
|
||||||
},
|
},
|
||||||
CreateShape::SquareCenter => {
|
|
||||||
assert!(sd.center.is_some());
|
|
||||||
let center = spoints.get(sd.center.unwrap()).unwrap().0;
|
|
||||||
let ext = (mpos - center).abs() * 2.0;
|
|
||||||
|
|
||||||
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::CustomCenter(center) };
|
|
||||||
ShapePath::build_as(&shape)
|
|
||||||
},
|
|
||||||
CreateShape::Circle => {
|
CreateShape::Circle => {
|
||||||
assert!(sd.center.is_some());
|
assert!(sd.center.is_some());
|
||||||
let center= spoints.get(sd.center.unwrap()).unwrap().0;
|
let center= transforms.get(sd.center.unwrap()).unwrap().translation.xy();
|
||||||
|
|
||||||
let shape = shapes::Circle { radius: (mpos - center).length(), center };
|
let shape = shapes::Circle { radius: (mpos - center).length(), center };
|
||||||
ShapePath::build_as(&shape)
|
ShapePath::build_as(&shape)
|
||||||
|
@ -159,7 +272,7 @@ fn update_main_shape_creation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape) -> ShapeData {
|
fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape, p_size: f32) -> ShapeData {
|
||||||
// Shape draw mode...
|
// Shape draw mode...
|
||||||
let draw_mode = DrawMode::Outlined {
|
let draw_mode = DrawMode::Outlined {
|
||||||
fill_mode: FillMode::color(Color::rgba(0.0, 0.5, 0.5, 0.4)),
|
fill_mode: FillMode::color(Color::rgba(0.0, 0.5, 0.5, 0.4)),
|
||||||
|
@ -168,15 +281,14 @@ fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape) -
|
||||||
|
|
||||||
// Spawn the first point(where the user just clicked)
|
// Spawn the first point(where the user just clicked)
|
||||||
let shape = shapes::Circle {
|
let shape = shapes::Circle {
|
||||||
radius: 3.0,
|
radius: p_size,
|
||||||
center: pos,
|
center: Vec2::ZERO,
|
||||||
};
|
};
|
||||||
let fp = coms.spawn_bundle(GeometryBuilder::build_as(
|
let fp = coms.spawn_bundle(GeometryBuilder::build_as(
|
||||||
&shape,
|
&shape,
|
||||||
DrawMode::Fill(FillMode::color(Color::RED)),
|
DrawMode::Fill(FillMode::color(Color::RED)),
|
||||||
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
Transform::from_translation(pos.extend(1.0))
|
||||||
))
|
))
|
||||||
.insert(SPoint(pos))
|
|
||||||
.id();
|
.id();
|
||||||
// Spawn main shape!
|
// Spawn main shape!
|
||||||
let main_shape = match create_shape {
|
let main_shape = match create_shape {
|
||||||
|
@ -188,7 +300,7 @@ fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape) -
|
||||||
Transform::from_translation(Vec3::ZERO)
|
Transform::from_translation(Vec3::ZERO)
|
||||||
)).id()
|
)).id()
|
||||||
},
|
},
|
||||||
CreateShape::Square | CreateShape::SquareCenter => {
|
CreateShape::Square => {
|
||||||
let shape = shapes::Rectangle { extents: Vec2::ZERO, origin: RectangleOrigin::CustomCenter(pos)};
|
let shape = shapes::Rectangle { extents: Vec2::ZERO, origin: RectangleOrigin::CustomCenter(pos)};
|
||||||
coms.spawn_bundle(GeometryBuilder::build_as(
|
coms.spawn_bundle(GeometryBuilder::build_as(
|
||||||
&shape,
|
&shape,
|
||||||
|
@ -207,7 +319,7 @@ fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape) -
|
||||||
};
|
};
|
||||||
// Get center point(if exists)
|
// Get center point(if exists)
|
||||||
let center = match create_shape {
|
let center = match create_shape {
|
||||||
CreateShape::SquareCenter | CreateShape::Circle => Some(fp),
|
CreateShape::Circle => Some(fp),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let edges = if center.is_none() { Vec::from([fp]) } else { Vec::new() };
|
let edges = if center.is_none() { Vec::from([fp]) } else { Vec::new() };
|
||||||
|
|
14
src/lib.rs
14
src/lib.rs
|
@ -1,13 +1,19 @@
|
||||||
|
#![feature(let_chains)]
|
||||||
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_egui::egui;
|
use bevy_egui::egui;
|
||||||
|
|
||||||
mod create;
|
mod create;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
mod modify;
|
||||||
|
pub use modify::modify_sys;
|
||||||
pub use create::create_sys;
|
pub use create::create_sys;
|
||||||
pub use helpers::*;
|
pub use helpers::*;
|
||||||
|
|
||||||
#[derive(Component, Debug, Clone, Copy)]
|
|
||||||
pub struct SPoint(pub Vec2);
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PointSize(pub f32);
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
pub struct ShapeData {
|
pub struct ShapeData {
|
||||||
|
@ -21,12 +27,12 @@ pub struct ShapeData {
|
||||||
pub struct MainCamera;
|
pub struct MainCamera;
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum CreateShape {
|
pub enum CreateShape {
|
||||||
Triangle, Square, SquareCenter, Circle, Capsule
|
Triangle, Square, Circle, Capsule
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Create, Modify, Delete
|
Create, Modify, Delete, Rotate
|
||||||
}
|
}
|
||||||
pub struct UiState {
|
pub struct UiState {
|
||||||
pub current_action: Action,
|
pub current_action: Action,
|
||||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -1,4 +1,5 @@
|
||||||
use bevy::ecs::schedule::ShouldRun;
|
use bevy::ecs::schedule::ShouldRun;
|
||||||
|
use bevy::math::Vec3Swizzles;
|
||||||
use bevy::{prelude::*, window::PresentMode, winit::WinitSettings};
|
use bevy::{prelude::*, window::PresentMode, winit::WinitSettings};
|
||||||
use bevy_egui::{egui, EguiContext, EguiPlugin};
|
use bevy_egui::{egui, EguiContext, EguiPlugin};
|
||||||
use bevy_prototype_lyon::prelude::*;
|
use bevy_prototype_lyon::prelude::*;
|
||||||
|
@ -20,6 +21,7 @@ fn main() {
|
||||||
})
|
})
|
||||||
.insert_resource(ButtonsColors::default())
|
.insert_resource(ButtonsColors::default())
|
||||||
.insert_resource(UiState::default())
|
.insert_resource(UiState::default())
|
||||||
|
.insert_resource(PointSize(5.0))
|
||||||
;
|
;
|
||||||
|
|
||||||
app
|
app
|
||||||
|
@ -72,6 +74,11 @@ fn action_bar_sys(
|
||||||
if m.clicked() {
|
if m.clicked() {
|
||||||
state.current_action = Action::Modify;
|
state.current_action = Action::Modify;
|
||||||
}
|
}
|
||||||
|
let r = hui.button(egui::RichText::new("R").color(state.current_action_color(&colors, Action::Rotate)))
|
||||||
|
.on_hover_text("Rotate");
|
||||||
|
if r.clicked() {
|
||||||
|
state.current_action = Action::Rotate;
|
||||||
|
}
|
||||||
let c = hui.button(egui::RichText::new("C").color(state.current_action_color(&colors, Action::Create)))
|
let c = hui.button(egui::RichText::new("C").color(state.current_action_color(&colors, Action::Create)))
|
||||||
.on_hover_text("Create");
|
.on_hover_text("Create");
|
||||||
if c.clicked() {
|
if c.clicked() {
|
||||||
|
@ -103,11 +110,6 @@ fn action_bar_sys(
|
||||||
if squ.clicked() {
|
if squ.clicked() {
|
||||||
state.create_shape = CreateShape::Square;
|
state.create_shape = CreateShape::Square;
|
||||||
}
|
}
|
||||||
let sce = hui.button(egui::RichText::new("SqC").color(state.create_shape_color(&colors, CreateShape::SquareCenter)))
|
|
||||||
.on_hover_text("Square - from center point and edge");
|
|
||||||
if sce.clicked() {
|
|
||||||
state.create_shape = CreateShape::SquareCenter;
|
|
||||||
}
|
|
||||||
let cir = hui.button(egui::RichText::new("Cir").color(state.create_shape_color(&colors, CreateShape::Circle)))
|
let cir = hui.button(egui::RichText::new("Cir").color(state.create_shape_color(&colors, CreateShape::Circle)))
|
||||||
.on_hover_text("Circle - center point and radius");
|
.on_hover_text("Circle - center point and radius");
|
||||||
if cir.clicked() {
|
if cir.clicked() {
|
||||||
|
@ -123,19 +125,3 @@ fn action_bar_sys(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn modify_sys(
|
|
||||||
mouse: Res<Input<MouseButton>>,
|
|
||||||
wnds: Res<Windows>,
|
|
||||||
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
|
||||||
mut paths: Query<&mut Path>,
|
|
||||||
mut transforms: Query<&mut Transform>,
|
|
||||||
shapes: Query<&ShapeData>,
|
|
||||||
) {
|
|
||||||
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
|
||||||
|
|
||||||
if let Some(mouse_pos) = mouse_pos {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
154
src/modify.rs
Normal file
154
src/modify.rs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
use bevy::math::Vec3Swizzles;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use crate::*;
|
||||||
|
use bevy_prototype_lyon::prelude::*;
|
||||||
|
|
||||||
|
pub fn modify_sys(
|
||||||
|
// Which entity the user currently drags, and which specific part of it(ShapeData entity, path entity)
|
||||||
|
mut holding: Local<Option<(Entity, Entity)>>,
|
||||||
|
mouse: Res<Input<MouseButton>>,
|
||||||
|
wnds: Res<Windows>,
|
||||||
|
p_size: Res<PointSize>,
|
||||||
|
paths: Query<&mut Path>,
|
||||||
|
mut transforms: Query<&mut Transform>,
|
||||||
|
gtransforms: Query<&GlobalTransform>,
|
||||||
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
||||||
|
shapes: Query<(Entity, &ShapeData)>,
|
||||||
|
) {
|
||||||
|
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
||||||
|
|
||||||
|
if let Some(mouse_pos) = mouse_pos {
|
||||||
|
if mouse.just_pressed(MouseButton::Left) && holding.is_none() {
|
||||||
|
// Grab attempt - search if we are holding a shape or something
|
||||||
|
for (e, sd) in shapes.iter() {
|
||||||
|
if let Ok(t) = gtransforms.get(sd.center.unwrap()) {
|
||||||
|
let t = t.translation.xy();
|
||||||
|
|
||||||
|
if (mouse_pos - t).length_squared() < p_size.0.powi(2) {
|
||||||
|
*holding = Some((e, sd.center.unwrap()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for edge in sd.edges.iter() {
|
||||||
|
if let Ok(t) = gtransforms.get(*edge) {
|
||||||
|
let t = t.translation.xy();
|
||||||
|
|
||||||
|
if (mouse_pos - t).length_squared() < p_size.0.powi(2) {
|
||||||
|
*holding = Some((e, *edge));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if mouse.just_released(MouseButton::Left) && holding.is_some() {
|
||||||
|
*holding = None; // We just released our sad little dot/shape
|
||||||
|
}
|
||||||
|
else if let Some((se, pe)) = *holding {
|
||||||
|
if let Ok(sd) = shapes.get_component::<ShapeData>(se) {
|
||||||
|
// Middle of a drag :D
|
||||||
|
if let Some(ce) = sd.center && ce == pe {
|
||||||
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
||||||
|
t.translation = mouse_pos.extend(t.translation.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if let Ok(mut t) = transforms.get_mut(pe) {
|
||||||
|
// Update the dot position
|
||||||
|
let delta = mouse_pos - gtransforms.get(pe).unwrap().translation.xy();
|
||||||
|
t.translation += delta.extend(0.0);
|
||||||
|
// We need to recalculate the center, and update the points to be the new relevant point from the center
|
||||||
|
let center_offset = calc_shape_center_offset(&transforms, sd).extend(0.0);
|
||||||
|
// Update each edge's offset, and then move the main shape's translation
|
||||||
|
for edge in sd.edges.iter() {
|
||||||
|
if let Ok(mut t) = transforms.get_mut(*edge) {
|
||||||
|
t.translation -= center_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
||||||
|
t.translation += center_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we need to update the shape itself
|
||||||
|
update_main_shape(paths, transforms, sd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_shape_center_offset(transforms: &Query<&mut Transform>, sd: &ShapeData) -> Vec2 {
|
||||||
|
match sd.shape {
|
||||||
|
CreateShape::Triangle => {
|
||||||
|
assert!(sd.edges.len() == 3);
|
||||||
|
|
||||||
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let e2 = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
let e3 = transforms.get(sd.edges[2]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
(e1 + e2 + e3) / 3.0
|
||||||
|
},
|
||||||
|
CreateShape::Square => {
|
||||||
|
assert!(sd.edges.len() == 2);
|
||||||
|
|
||||||
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let e2 = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
(e1 + e2) * 0.5
|
||||||
|
},
|
||||||
|
CreateShape::Circle => {
|
||||||
|
if let Ok(gt) = transforms.get(sd.center.unwrap()) {
|
||||||
|
gt.translation.xy()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Vec2::ZERO
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CreateShape::Capsule => unimplemented!("Capsule is disabled for now"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_main_shape(mut paths: Query<&mut Path>, transforms: Query<&mut Transform>, sd: &ShapeData) {
|
||||||
|
let path = match sd.shape {
|
||||||
|
CreateShape::Triangle => {
|
||||||
|
assert!(sd.edges.len() == 3);
|
||||||
|
assert!(sd.center.is_some());
|
||||||
|
|
||||||
|
let fp = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let sp = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
let tp = transforms.get(sd.edges[2]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
let shape = shapes::Polygon {
|
||||||
|
points: Vec::from([fp, sp, tp]),
|
||||||
|
closed: true,
|
||||||
|
};
|
||||||
|
ShapePath::build_as(&shape)
|
||||||
|
},
|
||||||
|
CreateShape::Square => {
|
||||||
|
assert!(sd.edges.len() == 2);
|
||||||
|
assert!(sd.center.is_some());
|
||||||
|
|
||||||
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
let e2 = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
||||||
|
let ext = (e2 - e1).abs();
|
||||||
|
|
||||||
|
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::Center };
|
||||||
|
ShapePath::build_as(&shape)
|
||||||
|
},
|
||||||
|
CreateShape::Circle => {
|
||||||
|
assert!(sd.center.is_some());
|
||||||
|
assert!(sd.edges.len() == 1);
|
||||||
|
|
||||||
|
let center= transforms.get(sd.center.unwrap()).unwrap().translation.xy();
|
||||||
|
let edge = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
||||||
|
|
||||||
|
let shape = shapes::Circle { radius: (edge - center).length(), center: Vec2::ZERO };
|
||||||
|
ShapePath::build_as(&shape)
|
||||||
|
},
|
||||||
|
CreateShape::Capsule => {
|
||||||
|
panic!("Capsule creation not implemented yet!");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if let Ok(mut p) = paths.get_mut(sd.main_shape) {
|
||||||
|
*p = path;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue