use legion::Entity; use crate::model; use std::ops::{Deref, DerefMut}; pub struct World { pub world: legion::World, pub resources: legion::Resources, pub root_objects: Vec, } impl Deref for World { type Target = legion::World; fn deref(&self) -> &legion::World { &self.world } } impl DerefMut for World { fn deref_mut(&mut self) -> &mut legion::World { &mut self.world } } impl World { pub fn new() -> Self { Self { world: Default::default(), resources: Default::default(), root_objects: vec![], } } pub fn execute(&mut self, schedule: &mut legion::Schedule) { schedule.execute(&mut self.world, &mut self.resources); } pub fn get_component_mut(&mut self, entity: Entity) -> &mut T { self.entry(entity).unwrap().into_component_mut().unwrap() } pub fn spawn_model(&mut self, model: &model::LoadedModel, transform: &glam::Mat4) -> Entity { let mut children = Vec::new(); for object in model.objects.iter() { children.push(self.spawn_object(object, transform)); } let root = self.world.push((Object { name: model.name.to_owned(), transform: model::Transform::default(), entities: Default::default(), children, dirty: false, children_dirty: false, },)); self.root_objects.push(root); root } pub fn spawn_object( &mut self, object: &model::LoadedObject, root_transform: &glam::Mat4, ) -> Entity { let transform = cyborg::scene::Transform { transform: *root_transform * object.transform.to_mat4(), }; let mut entities = Vec::new(); for mesh in object.meshes.iter() { let mesh = cyborg::scene::Mesh { mesh: *mesh }; let entity = self.world.push((mesh, transform.clone())); entities.push(entity); } let mut children = Vec::new(); for child in object.children.iter() { children.push(self.spawn_object(child, root_transform)); } self.world.push((Object { name: object.name.clone(), transform: object.transform.clone(), entities, children, dirty: false, children_dirty: false, },)) } pub fn flush_dirty_objects(&mut self) { let mut stack = self.root_objects.to_owned(); while let Some(parent) = stack.pop() { let parent: &mut Object = self.get_component_mut(parent); if parent.children_dirty { parent.children_dirty = false; stack.extend_from_slice(&parent.children); } if parent.dirty { parent.dirty = false; let mat4 = parent.transform.to_mat4(); for entity in parent.entities.to_owned().into_iter() { let transform: &mut cyborg::scene::Transform = self.get_component_mut(entity); transform.transform = mat4; } } } } } pub struct Object { pub name: Option, pub transform: model::Transform, pub entities: Vec, pub children: Vec, pub dirty: bool, pub children_dirty: bool, } impl Object { pub fn ui(&mut self, ui: &mut egui::Ui) { egui::Grid::new("root_object") .num_columns(4) .striped(true) .show(ui, |ui| { ui.label("Position: "); self.ui_position(ui); ui.end_row(); ui.label("Rotation: "); self.ui_rotation(ui); ui.end_row(); ui.label("Scale: "); self.ui_scale(ui); ui.end_row(); }); } pub fn ui_position(&mut self, ui: &mut egui::Ui) { let speed = 0.1 * self.transform.scale.min_element(); if Self::ui_vec3(ui, speed, &mut self.transform.position) { self.dirty = true; } } pub fn ui_rotation(&mut self, ui: &mut egui::Ui) { let axes = &mut self.transform.rotation; if ui.drag_angle(&mut axes.x).changed() { self.dirty = true; } if ui.drag_angle(&mut axes.y).changed() { self.dirty = true; } if ui.drag_angle(&mut axes.z).changed() { self.dirty = true; } } pub fn ui_vec3(ui: &mut egui::Ui, speed: f32, vec3: &mut glam::Vec3) -> bool { let x_drag = egui::DragValue::new(&mut vec3.x).speed(speed); let dirty = ui.add(x_drag).changed(); let dirty = dirty || { // For some reason, Rust complains if this isn't in a block let y_drag = egui::DragValue::new(&mut vec3.y).speed(speed); ui.add(y_drag).changed() }; let z_drag = egui::DragValue::new(&mut vec3.z).speed(speed); let dirty = dirty || ui.add(z_drag).changed(); dirty } pub fn ui_scale(&mut self, ui: &mut egui::Ui) { let speed = self.transform.scale.min_element() * 0.01; if Self::ui_vec3(ui, speed, &mut self.transform.scale) { self.dirty = true; } } }