Live object editing!
This commit is contained in:
parent
e6cdb5ebe8
commit
afb3dca4ce
|
@ -7,6 +7,7 @@ use egui_winit::winit::{
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
use legion::EntityStore;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod render;
|
mod render;
|
||||||
|
@ -26,6 +27,7 @@ struct Application {
|
||||||
viewport: ui::ViewportWidget,
|
viewport: ui::ViewportWidget,
|
||||||
render_state: render::RenderState,
|
render_state: render::RenderState,
|
||||||
file_receiver: crossbeam_channel::Receiver<ui::FileEvent>,
|
file_receiver: crossbeam_channel::Receiver<ui::FileEvent>,
|
||||||
|
objects: Vec<ui::ObjectWidget>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
|
@ -92,6 +94,7 @@ impl Application {
|
||||||
viewport: ui::ViewportWidget::new(viewport_texture),
|
viewport: ui::ViewportWidget::new(viewport_texture),
|
||||||
render_state,
|
render_state,
|
||||||
file_receiver,
|
file_receiver,
|
||||||
|
objects: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,9 +116,36 @@ impl Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for object in self.objects.iter_mut() {
|
||||||
|
object.flush_dirty(|object| {
|
||||||
|
let translation = glam::Vec3::from_slice(&object.position);
|
||||||
|
let rotation = glam::Quat::from_euler(
|
||||||
|
glam::EulerRot::XYZ,
|
||||||
|
object.rotation[0],
|
||||||
|
object.rotation[1],
|
||||||
|
object.rotation[2],
|
||||||
|
);
|
||||||
|
let scale = glam::Vec3::splat(object.scale);
|
||||||
|
let transform =
|
||||||
|
glam::Mat4::from_scale_rotation_translation(scale, rotation, translation);
|
||||||
|
self.render_state
|
||||||
|
.world
|
||||||
|
.entry_mut(object.entity)
|
||||||
|
.unwrap()
|
||||||
|
.get_component_mut::<cyborg::scene::Transform>()
|
||||||
|
.unwrap()
|
||||||
|
.transform = transform;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_stl(&mut self, path: std::path::PathBuf) {
|
pub fn load_stl(&mut self, path: std::path::PathBuf) {
|
||||||
|
let root_name = path
|
||||||
|
.file_name()
|
||||||
|
.map(|v| v.to_string_lossy().to_string())
|
||||||
|
.unwrap_or("<unnamed>".to_string());
|
||||||
|
|
||||||
use cyborg::pass::{
|
use cyborg::pass::{
|
||||||
mesh::{Index, MeshPass, Vertex},
|
mesh::{Index, MeshPass, Vertex},
|
||||||
RenderPassBox,
|
RenderPassBox,
|
||||||
|
@ -172,14 +202,25 @@ impl Application {
|
||||||
mesh.attributes.push(vertices);
|
mesh.attributes.push(vertices);
|
||||||
mesh.attributes.push(indices);
|
mesh.attributes.push(indices);
|
||||||
|
|
||||||
self.render_state.world.push((
|
let entity = self.render_state.world.push((
|
||||||
cyborg::scene::Mesh {
|
cyborg::scene::Mesh {
|
||||||
mesh: mesh_pass.get_mesh_pool().load(mesh).unwrap(),
|
mesh: mesh_pass.get_mesh_pool().load(mesh).unwrap(),
|
||||||
},
|
},
|
||||||
cyborg::scene::Transform {
|
cyborg::scene::Transform {
|
||||||
transform: glam::Mat4::from_translation(glam::Vec3::new(0.0, -10.0, 0.0)),
|
transform: Default::default(),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let object = ui::ObjectWidget {
|
||||||
|
name: root_name,
|
||||||
|
position: [0.0; 3],
|
||||||
|
rotation: [0.0; 3],
|
||||||
|
scale: 1.0,
|
||||||
|
entity,
|
||||||
|
dirty: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.objects.push(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_resize(&mut self, new_size: PhysicalSize<u32>) {
|
pub fn on_resize(&mut self, new_size: PhysicalSize<u32>) {
|
||||||
|
@ -201,8 +242,9 @@ impl Application {
|
||||||
let output = {
|
let output = {
|
||||||
puffin::profile_scope!("Draw egui");
|
puffin::profile_scope!("Draw egui");
|
||||||
let raw_input = self.egui_state.take_egui_input(&self.window);
|
let raw_input = self.egui_state.take_egui_input(&self.window);
|
||||||
self.egui_ctx
|
self.egui_ctx.run(raw_input, |ctx| {
|
||||||
.run(raw_input, |ctx| self.ui.run(ctx, &mut self.viewport))
|
self.ui.run(ctx, &mut self.viewport, &mut self.objects)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,6 @@ pub struct UserInterface {
|
||||||
quit: bool,
|
quit: bool,
|
||||||
show_about: bool,
|
show_about: bool,
|
||||||
log_contents: String,
|
log_contents: String,
|
||||||
object: ObjectWidget,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserInterface {
|
impl UserInterface {
|
||||||
|
@ -34,7 +33,6 @@ impl UserInterface {
|
||||||
quit: false,
|
quit: false,
|
||||||
show_about: false,
|
show_about: false,
|
||||||
log_contents: "Hello logging!\n".to_string(),
|
log_contents: "Hello logging!\n".to_string(),
|
||||||
object: ObjectWidget::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +40,12 @@ impl UserInterface {
|
||||||
self.quit
|
self.quit
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, ctx: &egui::Context, viewport: &mut ViewportWidget) {
|
pub fn run(
|
||||||
|
&mut self,
|
||||||
|
ctx: &egui::Context,
|
||||||
|
viewport: &mut ViewportWidget,
|
||||||
|
objects: &mut [ObjectWidget],
|
||||||
|
) {
|
||||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||||
egui::menu::bar(ui, |ui| {
|
egui::menu::bar(ui, |ui| {
|
||||||
ui.menu_button("File", |ui| {
|
ui.menu_button("File", |ui| {
|
||||||
|
@ -148,7 +151,9 @@ impl UserInterface {
|
||||||
egui::SidePanel::left("objects_panel")
|
egui::SidePanel::left("objects_panel")
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
self.object.ui(ui);
|
for object in objects.iter_mut() {
|
||||||
|
object.ui(ui);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
egui::TopBottomPanel::bottom("info_panel")
|
egui::TopBottomPanel::bottom("info_panel")
|
||||||
|
@ -260,20 +265,11 @@ pub struct ObjectWidget {
|
||||||
pub position: [f32; 3],
|
pub position: [f32; 3],
|
||||||
pub rotation: [f32; 3],
|
pub rotation: [f32; 3],
|
||||||
pub scale: f32,
|
pub scale: f32,
|
||||||
|
pub entity: legion::Entity,
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectWidget {
|
impl ObjectWidget {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
name: "Example Object".to_string(),
|
|
||||||
position: [0.0; 3],
|
|
||||||
rotation: [0.0; 3],
|
|
||||||
scale: 1.0,
|
|
||||||
dirty: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui) {
|
pub fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
egui::CollapsingHeader::new(&self.name)
|
egui::CollapsingHeader::new(&self.name)
|
||||||
.default_open(true)
|
.default_open(true)
|
||||||
|
|
Loading…
Reference in New Issue