use super::primitives::{default_directional_light, default_point_light, default_spot_light};
use crate::editor::undo::{UndoHistory, UndoableOperation, capture_hierarchy};
use crate::prelude::*;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum NodeType {
Empty,
Camera,
DirectionalLight,
PointLight,
SpotLight,
Mesh,
ParticleEmitter,
Decal,
WaterPlane,
GrassRegion,
#[cfg(feature = "physics")]
CharacterController,
}
pub struct AddNodeModalResult {
pub close_modal: bool,
pub node_to_create: Option<NodeType>,
}
pub fn add_node_modal_ui(
ui_context: &egui::Context,
modal_open: &mut bool,
search: &mut String,
) -> AddNodeModalResult {
if !*modal_open {
return AddNodeModalResult {
close_modal: false,
node_to_create: None,
};
}
let mut close_modal = false;
let mut node_to_create: Option<NodeType> = None;
egui::Window::new("Add Node")
.open(modal_open)
.collapsible(false)
.resizable(false)
.default_width(250.0)
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
.show(ui_context, |ui| {
ui.horizontal(|ui| {
ui.label("Search:");
ui.text_edit_singleline(search);
});
ui.separator();
let node_types: Vec<(&str, NodeType)> = vec![
("Empty Node", NodeType::Empty),
("Camera", NodeType::Camera),
("Directional Light", NodeType::DirectionalLight),
("Point Light", NodeType::PointLight),
("Spot Light", NodeType::SpotLight),
("Mesh", NodeType::Mesh),
("Particle Emitter", NodeType::ParticleEmitter),
("Decal", NodeType::Decal),
("Water Plane", NodeType::WaterPlane),
("Grass Region", NodeType::GrassRegion),
#[cfg(feature = "physics")]
("Character Controller", NodeType::CharacterController),
];
let search_lower = search.to_lowercase();
egui::ScrollArea::vertical()
.max_height(300.0)
.show(ui, |ui| {
for (name, node_type) in &node_types {
if !search_lower.is_empty() && !name.to_lowercase().contains(&search_lower)
{
continue;
}
if ui.selectable_label(false, *name).clicked() {
node_to_create = Some(*node_type);
close_modal = true;
}
}
});
});
if !*modal_open {
close_modal = true;
}
AddNodeModalResult {
close_modal,
node_to_create,
}
}
pub fn create_node(
world: &mut World,
undo_history: &mut UndoHistory,
node_type: NodeType,
parent: Option<Entity>,
) -> Entity {
let name = match node_type {
NodeType::Empty => "Node",
NodeType::Camera => "Camera",
NodeType::DirectionalLight => "Directional Light",
NodeType::PointLight => "Point Light",
NodeType::SpotLight => "Spot Light",
NodeType::Mesh => "Mesh",
NodeType::ParticleEmitter => "Particle Emitter",
NodeType::Decal => "Decal",
NodeType::WaterPlane => "Water Plane",
NodeType::GrassRegion => "Grass Region",
#[cfg(feature = "physics")]
NodeType::CharacterController => "Character Controller",
};
let new_entity = EntityBuilder::new()
.with_local_transform(LocalTransform::default())
.with_global_transform(GlobalTransform::default())
.spawn(world, 1)[0];
if let Some(parent_entity) = parent {
world.set_parent(new_entity, Parent(Some(parent_entity)));
}
match node_type {
NodeType::Empty => {}
NodeType::Camera => {
world.set_camera(new_entity, Camera::default());
}
NodeType::DirectionalLight => {
world.set_light(new_entity, default_directional_light());
}
NodeType::PointLight => {
world.set_light(new_entity, default_point_light());
}
NodeType::SpotLight => {
world.set_light(new_entity, default_spot_light());
}
NodeType::Mesh => {
world.set_render_mesh(new_entity, RenderMesh::new("Cube"));
}
NodeType::ParticleEmitter => {
use crate::ecs::particles::components::ParticleEmitter;
world.add_components(new_entity, crate::ecs::world::PARTICLE_EMITTER);
world.set_particle_emitter(
new_entity,
ParticleEmitter::fire(nalgebra_glm::Vec3::zeros()),
);
}
NodeType::Decal => {
use crate::ecs::decal::Decal;
world.set_decal(new_entity, Decal::default());
}
NodeType::WaterPlane => {
use crate::ecs::water::Water;
world.set_water(new_entity, Water::default());
world.set_render_mesh(new_entity, RenderMesh::new("Plane"));
}
NodeType::GrassRegion => {
use crate::ecs::grass::GrassRegion;
world.add_components(new_entity, crate::ecs::world::GRASS_REGION);
world.set_grass_region(new_entity, GrassRegion::default());
}
#[cfg(feature = "physics")]
NodeType::CharacterController => {
use crate::ecs::physics::components::CharacterControllerComponent;
world.add_components(new_entity, crate::ecs::world::CHARACTER_CONTROLLER);
world.set_character_controller(new_entity, CharacterControllerComponent::default());
}
}
world.set_name(new_entity, Name(format!("{} {}", name, new_entity.id)));
let hierarchy = Box::new(capture_hierarchy(world, new_entity));
undo_history.push(
UndoableOperation::EntityCreated {
hierarchy,
current_entity: new_entity,
},
format!("Create {}", name),
);
new_entity
}