Live object editing!
This commit is contained in:
parent
e6cdb5ebe8
commit
afb3dca4ce
|
@ -7,6 +7,7 @@ use egui_winit::winit::{
|
|||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
};
|
||||
use legion::EntityStore;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod render;
|
||||
|
@ -26,6 +27,7 @@ struct Application {
|
|||
viewport: ui::ViewportWidget,
|
||||
render_state: render::RenderState,
|
||||
file_receiver: crossbeam_channel::Receiver<ui::FileEvent>,
|
||||
objects: Vec<ui::ObjectWidget>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
|
@ -92,6 +94,7 @@ impl Application {
|
|||
viewport: ui::ViewportWidget::new(viewport_texture),
|
||||
render_state,
|
||||
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) {
|
||||
let root_name = path
|
||||
.file_name()
|
||||
.map(|v| v.to_string_lossy().to_string())
|
||||
.unwrap_or("<unnamed>".to_string());
|
||||
|
||||
use cyborg::pass::{
|
||||
mesh::{Index, MeshPass, Vertex},
|
||||
RenderPassBox,
|
||||
|
@ -172,14 +202,25 @@ impl Application {
|
|||
mesh.attributes.push(vertices);
|
||||
mesh.attributes.push(indices);
|
||||
|
||||
self.render_state.world.push((
|
||||
let entity = self.render_state.world.push((
|
||||
cyborg::scene::Mesh {
|
||||
mesh: mesh_pass.get_mesh_pool().load(mesh).unwrap(),
|
||||
},
|
||||
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>) {
|
||||
|
@ -201,8 +242,9 @@ impl Application {
|
|||
let output = {
|
||||
puffin::profile_scope!("Draw egui");
|
||||
let raw_input = self.egui_state.take_egui_input(&self.window);
|
||||
self.egui_ctx
|
||||
.run(raw_input, |ctx| self.ui.run(ctx, &mut self.viewport))
|
||||
self.egui_ctx.run(raw_input, |ctx| {
|
||||
self.ui.run(ctx, &mut self.viewport, &mut self.objects)
|
||||
})
|
||||
};
|
||||
|
||||
{
|
||||
|
|
|
@ -22,7 +22,6 @@ pub struct UserInterface {
|
|||
quit: bool,
|
||||
show_about: bool,
|
||||
log_contents: String,
|
||||
object: ObjectWidget,
|
||||
}
|
||||
|
||||
impl UserInterface {
|
||||
|
@ -34,7 +33,6 @@ impl UserInterface {
|
|||
quit: false,
|
||||
show_about: false,
|
||||
log_contents: "Hello logging!\n".to_string(),
|
||||
object: ObjectWidget::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +40,12 @@ impl UserInterface {
|
|||
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::menu::bar(ui, |ui| {
|
||||
ui.menu_button("File", |ui| {
|
||||
|
@ -148,7 +151,9 @@ impl UserInterface {
|
|||
egui::SidePanel::left("objects_panel")
|
||||
.resizable(true)
|
||||
.show(ctx, |ui| {
|
||||
self.object.ui(ui);
|
||||
for object in objects.iter_mut() {
|
||||
object.ui(ui);
|
||||
}
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::bottom("info_panel")
|
||||
|
@ -260,20 +265,11 @@ pub struct ObjectWidget {
|
|||
pub position: [f32; 3],
|
||||
pub rotation: [f32; 3],
|
||||
pub scale: f32,
|
||||
pub entity: legion::Entity,
|
||||
pub dirty: bool,
|
||||
}
|
||||
|
||||
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) {
|
||||
egui::CollapsingHeader::new(&self.name)
|
||||
.default_open(true)
|
||||
|
|
Loading…
Reference in New Issue