nightshade 0.8.0

A cross-platform data-oriented game engine.
Documentation
use super::{ComponentInspector, InspectorContext, impl_simple_inspector};
use crate::ecs::grass::components::{GrassInteractor, GrassRegion, GrassSpecies};
use crate::prelude::*;

fn add_grass_region(world: &mut World, entity: Entity) {
    world.add_components(entity, crate::ecs::world::GRASS_REGION);
    world.set_grass_region(entity, GrassRegion::default());
}

fn grass_region_ui(
    world: &mut World,
    entity: Entity,
    ui: &mut egui::Ui,
    _context: &mut InspectorContext,
) {
    if let Some(region) = world.get_grass_region_mut(entity) {
        ui.horizontal(|ui| {
            ui.label("Enabled:");
            ui.checkbox(&mut region.enabled, "");
        });

        ui.separator();
        ui.label(egui::RichText::new("Config").strong());

        ui.horizontal(|ui| {
            ui.label("Blades Per Patch:");
            ui.add(egui::DragValue::new(&mut region.config.blades_per_patch).range(1..=1024));
        });

        ui.horizontal(|ui| {
            ui.label("Patch Size:");
            ui.add(
                egui::DragValue::new(&mut region.config.patch_size)
                    .speed(0.5)
                    .range(1.0..=64.0),
            );
        });

        ui.horizontal(|ui| {
            ui.label("Stream Radius:");
            ui.add(
                egui::DragValue::new(&mut region.config.stream_radius)
                    .speed(1.0)
                    .range(10.0..=1000.0),
            );
        });

        ui.separator();
        ui.label(egui::RichText::new("Wind").strong());

        ui.horizontal(|ui| {
            ui.label("Strength:");
            ui.add(egui::Slider::new(
                &mut region.config.wind_strength,
                0.0..=5.0,
            ));
        });

        ui.horizontal(|ui| {
            ui.label("Frequency:");
            ui.add(egui::Slider::new(
                &mut region.config.wind_frequency,
                0.0..=5.0,
            ));
        });

        ui.horizontal(|ui| {
            ui.label("Direction:");
            ui.add(
                egui::DragValue::new(&mut region.config.wind_direction[0])
                    .speed(0.1)
                    .prefix("X: "),
            );
            ui.add(
                egui::DragValue::new(&mut region.config.wind_direction[1])
                    .speed(0.1)
                    .prefix("Z: "),
            );
        });

        ui.separator();
        ui.label(egui::RichText::new("Shadows").strong());

        ui.horizontal(|ui| {
            ui.label("Cast:");
            ui.checkbox(&mut region.config.cast_shadows, "");
            ui.label("Receive:");
            ui.checkbox(&mut region.config.receive_shadows, "");
        });

        ui.separator();
        ui.label(egui::RichText::new("Bounds").strong());

        ui.horizontal(|ui| {
            ui.label("Min:");
            ui.add(
                egui::DragValue::new(&mut region.bounds_min.x)
                    .speed(1.0)
                    .prefix("X: "),
            );
            ui.add(
                egui::DragValue::new(&mut region.bounds_min.y)
                    .speed(1.0)
                    .prefix("Y: "),
            );
            ui.add(
                egui::DragValue::new(&mut region.bounds_min.z)
                    .speed(1.0)
                    .prefix("Z: "),
            );
        });

        ui.horizontal(|ui| {
            ui.label("Max:");
            ui.add(
                egui::DragValue::new(&mut region.bounds_max.x)
                    .speed(1.0)
                    .prefix("X: "),
            );
            ui.add(
                egui::DragValue::new(&mut region.bounds_max.y)
                    .speed(1.0)
                    .prefix("Y: "),
            );
            ui.add(
                egui::DragValue::new(&mut region.bounds_max.z)
                    .speed(1.0)
                    .prefix("Z: "),
            );
        });

        ui.separator();
        ui.label(egui::RichText::new("Species").strong());

        let mut delete_index = None;
        for index in 0..region.species.len() {
            ui.group(|ui| {
                ui.horizontal(|ui| {
                    ui.label(format!("Species {}", index));
                    if ui.small_button("X").clicked() {
                        delete_index = Some(index);
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("Name:");
                    ui.text_edit_singleline(&mut region.species[index].name);
                });

                ui.horizontal(|ui| {
                    ui.label("Blade Width:");
                    ui.add(
                        egui::DragValue::new(&mut region.species[index].blade_width)
                            .speed(0.01)
                            .range(0.001..=1.0),
                    );
                });

                ui.horizontal(|ui| {
                    ui.label("Height Min:");
                    ui.add(
                        egui::DragValue::new(&mut region.species[index].blade_height_min)
                            .speed(0.01)
                            .range(0.01..=5.0),
                    );
                    ui.label("Max:");
                    ui.add(
                        egui::DragValue::new(&mut region.species[index].blade_height_max)
                            .speed(0.01)
                            .range(0.01..=5.0),
                    );
                });

                ui.horizontal(|ui| {
                    ui.label("Curvature:");
                    ui.add(egui::Slider::new(
                        &mut region.species[index].blade_curvature,
                        0.0..=1.0,
                    ));
                });

                ui.horizontal(|ui| {
                    ui.label("Base Color:");
                    ui.color_edit_button_rgba_unmultiplied(&mut region.species[index].base_color);
                });

                ui.horizontal(|ui| {
                    ui.label("Tip Color:");
                    ui.color_edit_button_rgba_unmultiplied(&mut region.species[index].tip_color);
                });

                ui.horizontal(|ui| {
                    ui.label("Density Scale:");
                    ui.add(egui::Slider::new(
                        &mut region.species[index].density_scale,
                        0.0..=3.0,
                    ));
                });

                if index < region.species_weights.len() {
                    ui.horizontal(|ui| {
                        ui.label("Weight:");
                        ui.add(egui::Slider::new(
                            &mut region.species_weights[index],
                            0.0..=10.0,
                        ));
                    });
                }
            });
        }

        if let Some(index) = delete_index
            && region.species.len() > 1
        {
            region.species.remove(index);
            if index < region.species_weights.len() {
                region.species_weights.remove(index);
            }
        }

        if ui.button("Add Species").clicked() {
            region.species.push(GrassSpecies::default());
            region.species_weights.push(1.0);
        }
    }
}

impl_simple_inspector!(
    GrassRegionInspector,
    "Grass Region",
    entity_has_grass_region,
    remove_grass_region,
    grass_region_ui,
    custom_add => add_grass_region
);

fn add_grass_interactor(world: &mut World, entity: Entity) {
    world.add_components(entity, crate::ecs::world::GRASS_INTERACTOR);
    world.set_grass_interactor(entity, GrassInteractor::default());
}

fn grass_interactor_ui(
    world: &mut World,
    entity: Entity,
    ui: &mut egui::Ui,
    _context: &mut InspectorContext,
) {
    if let Some(interactor) = world.get_grass_interactor_mut(entity) {
        ui.horizontal(|ui| {
            ui.label("Radius:");
            ui.add(
                egui::DragValue::new(&mut interactor.radius)
                    .speed(0.1)
                    .range(0.0..=10.0),
            );
        });

        ui.horizontal(|ui| {
            ui.label("Strength:");
            ui.add(
                egui::DragValue::new(&mut interactor.strength)
                    .speed(0.1)
                    .range(0.0..=5.0),
            );
        });
    }
}

impl_simple_inspector!(
    GrassInteractorInspector,
    "Grass Interactor",
    entity_has_grass_interactor,
    remove_grass_interactor,
    grass_interactor_ui,
    custom_add => add_grass_interactor
);