use bevy_egui::egui;
use crate::ashlar::AshlarConfig;
use crate::asphalt::AsphaltConfig;
use crate::bark::BarkConfig;
use crate::brick::BrickConfig;
use crate::cobblestone::CobblestoneConfig;
use crate::concrete::ConcreteConfig;
use crate::corrugated::CorrugatedConfig;
use crate::encaustic::{EncausticConfig, EncausticPattern};
use crate::ground::GroundConfig;
use crate::iron_grille::IronGrilleConfig;
use crate::leaf::LeafConfig;
use crate::marble::MarbleConfig;
use crate::metal::{MetalConfig, MetalStyle};
use crate::pavers::{PaversConfig, PaversLayout};
use crate::plank::PlankConfig;
use crate::rock::RockConfig;
use crate::shingle::ShingleConfig;
use crate::stained_glass::StainedGlassConfig;
use crate::stucco::StuccoConfig;
use crate::thatch::ThatchConfig;
use crate::twig::TwigConfig;
use crate::wainscoting::WainscotingConfig;
use crate::window::WindowConfig;
macro_rules! impl_config_editor {
(
$(#[doc = $doc:expr])*
fn $fn_name:ident, $Config:ty, $header:literal =>
{ $( $wname:ident $wargs:tt ),+ $(,)? }
) => {
$(#[doc = $doc])*
pub fn $fn_name(ui: &mut egui::Ui, cfg: &mut $Config, id: egui::Id) -> (bool, bool) {
let mut wb = false;
let mut regen = false;
egui::CollapsingHeader::new($header)
.id_salt(id)
.show(ui, |ui| {
$( impl_config_editor!(@widget ui, cfg, id, wb, regen, $wname $wargs); )+
});
(wb, regen)
}
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
slider ($label:expr, $field:ident, $range:expr)) => {
slider_debounced(
$ui,
egui::Slider::new(&mut $cfg.$field, $range).text($label),
&mut $wb,
&mut $regen,
);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
slider_step ($label:expr, $field:ident, $range:expr, $step:expr)) => {
slider_debounced(
$ui,
egui::Slider::new(&mut $cfg.$field, $range).step_by($step).text($label),
&mut $wb,
&mut $regen,
);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
usize ($label:expr, $field:ident, $range:expr)) => {
usize_instant($ui, &mut $cfg.$field, $range, $label, &mut $wb, &mut $regen);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
u32 ($label:expr, $field:ident)) => {
u32_instant($ui, &mut $cfg.$field, $label, &mut $wb, &mut $regen);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
color ($label:expr, $field:ident)) => {
color_instant($ui, $label, &mut $cfg.$field, &mut $wb, &mut $regen);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
bool ($label:expr, $field:ident)) => {
bool_instant($ui, &mut $cfg.$field, $label, &mut $wb, &mut $regen);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
separator ()) => {
$ui.separator();
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
label ($text:expr)) => {
$ui.label($text);
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
enum_select ($label:expr, $field:ident, [ $(($btn_label:expr, $variant:expr)),+ ])) => {
$ui.horizontal(|ui| {
ui.label($label);
$(
let selected = $cfg.$field == $variant;
if ui.selectable_label(selected, $btn_label).clicked() && !selected {
$cfg.$field = $variant;
$wb = true;
$regen = true;
}
)+
});
};
(@widget $ui:ident, $cfg:ident, $id:ident, $wb:ident, $regen:ident,
nested ($editor_fn:ident, $field:ident, $salt:expr)) => {
let (sub_wb, sub_regen) = $editor_fn($ui, &mut $cfg.$field, $id.with($salt));
$wb |= sub_wb;
$regen |= sub_regen;
};
}
impl_config_editor!(
fn leaf_config_editor, LeafConfig, "Leaf Config" => {
color("Base Color", color_base),
color("Edge Color", color_edge),
slider("Serration", serration_strength, 0.0..=0.5),
slider("Vein Angle", vein_angle, 1.0..=5.0),
slider("Vein Count", vein_count, 2.0..=12.0),
slider("Lobe Count", lobe_count, 0.0..=6.0),
slider("Lobe Depth", lobe_depth, 0.0..=1.0),
slider("Micro Detail", micro_detail, 0.0..=1.0),
slider("Normal Strength", normal_strength, 0.0..=8.0),
slider("Petiole", petiole_length, 0.0..=0.3),
}
);
impl_config_editor!(
fn twig_config_editor, TwigConfig, "Twig Config" => {
color("Stem Color", stem_color),
slider("Stem Width", stem_half_width, 0.005..=0.05),
usize("Leaf Pairs", leaf_pairs, 1..=8),
slider("Leaf Angle", leaf_angle, 0.0..=std::f64::consts::PI),
slider("Leaf Scale", leaf_scale, 0.1..=0.6),
slider("Stem Curve", stem_curve, 0.0..=0.15),
bool("Sympodial", sympodial),
nested(leaf_config_editor, leaf, "twig_leaf"),
}
);
impl_config_editor!(
fn bark_config_editor, BarkConfig, "Bark Config" => {
color("Light Color", color_light),
color("Dark Color", color_dark),
slider("Scale", scale, 1.0..=12.0),
slider("Warp H", warp_u, 0.0..=0.5),
slider("Warp V", warp_v, 0.0..=1.5),
slider("Normal Strength", normal_strength, 0.0..=8.0),
usize("Octaves", octaves, 1..=8),
separator(),
label("Rhytidome Plates:"),
slider("Furrow Blend", furrow_multiplier, 0.0..=1.0),
slider("Plate Width", furrow_scale_u, 0.5..=6.0),
slider("Plate Length", furrow_scale_v, 0.05..=1.0),
slider("Plate Shape", furrow_shape, 0.1..=2.0),
}
);
impl_config_editor!(
fn window_config_editor, WindowConfig, "Window Config" => {
u32("Seed", seed),
slider("Frame Width", frame_width, 0.0..=0.4),
usize("Panes X", panes_x, 1..=6),
usize("Panes Y", panes_y, 1..=6),
slider("Mullion Thickness", mullion_thickness, 0.0..=0.2),
slider("Corner Radius", corner_radius, 0.0..=0.4),
slider("Glass Opacity", glass_opacity, 0.0..=1.0),
slider("Grime", grime_level, 0.0..=1.0),
color("Frame Color", color_frame),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn ground_config_editor, GroundConfig, "Ground Config" => {
u32("Seed", seed),
slider("Macro Scale", macro_scale, 0.5..=8.0),
usize("Macro Octaves", macro_octaves, 1..=8),
slider("Micro Scale", micro_scale, 2.0..=20.0),
usize("Micro Octaves", micro_octaves, 1..=6),
slider("Micro Weight", micro_weight, 0.0..=1.0),
color("Color Dry", color_dry),
color("Color Moist", color_moist),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn rock_config_editor, RockConfig, "Rock Config" => {
u32("Seed", seed),
slider("Scale", scale, 0.5..=12.0),
usize("Octaves", octaves, 1..=12),
slider("Attenuation", attenuation, 0.5..=6.0),
color("Color Gaps", color_light),
color("Color Stone", color_dark),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn brick_config_editor, BrickConfig, "Brick Config" => {
u32("Seed", seed),
slider_step("Scale (Rows)", scale, 1.0..=16.0, 1.0),
slider("Row Offset", row_offset, 0.0..=1.0),
slider("Aspect Ratio", aspect_ratio, 1.0..=4.0),
slider("Mortar Size", mortar_size, 0.0..=0.4),
slider("Bevel", bevel, 0.0..=1.0),
slider("Color Variance", cell_variance, 0.0..=1.0),
slider("Surface Roughness", roughness, 0.0..=1.0),
color("Brick Color", color_brick),
color("Mortar Color", color_mortar),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn plank_config_editor, PlankConfig, "Plank Config" => {
u32("Seed", seed),
slider_step("Plank Count", plank_count, 1.0..=16.0, 1.0),
slider("Grain Scale", grain_scale, 2.0..=32.0),
slider("Joint Width", joint_width, 0.0..=0.3),
slider("Stagger", stagger, 0.0..=1.0),
slider("Knot Density", knot_density, 0.0..=1.0),
slider("Grain Warp", grain_warp, 0.0..=1.0),
color("Wood Light", color_wood_light),
color("Wood Dark", color_wood_dark),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn shingle_config_editor, ShingleConfig, "Shingle Config" => {
u32("Seed", seed),
slider_step("Scale (Rows)", scale, 2.0..=16.0, 1.0),
slider("Shape (Square→Scallop)", shape_profile, 0.0..=1.0),
slider("Overlap", overlap, 0.0..=0.8),
slider("Stagger", stagger, 0.0..=1.0),
slider("Moss", moss_level, 0.0..=1.0),
color("Tile Color", color_tile),
color("Grout Color", color_grout),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn stucco_config_editor, StuccoConfig, "Stucco Config" => {
u32("Seed", seed),
slider("Scale", scale, 1.0..=20.0),
usize("Octaves", octaves, 1..=10),
slider("Roughness", roughness, 0.0..=1.0),
color("Base Color", color_base),
color("Shadow Color", color_shadow),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
impl_config_editor!(
fn concrete_config_editor, ConcreteConfig, "Concrete Config" => {
u32("Seed", seed),
slider("Scale", scale, 1.0..=16.0),
usize("Octaves", octaves, 1..=10),
slider("Roughness", roughness, 0.0..=1.0),
slider_step("Formwork Lines", formwork_lines, 0.0..=12.0, 1.0),
slider("Formwork Depth", formwork_depth, 0.0..=0.5),
slider("Pit Density", pit_density, 0.0..=0.45),
color("Base Color", color_base),
color("Pit Color", color_pit),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
impl_config_editor!(
fn metal_config_editor, MetalConfig, "Metal Config" => {
u32("Seed", seed),
enum_select("Style:", style, [
("Brushed", MetalStyle::Brushed),
("Standing Seam", MetalStyle::StandingSeam)
]),
slider("Scale", scale, 1.0..=16.0),
slider_step("Seam Count", seam_count, 1.0..=16.0, 1.0),
slider("Seam Sharpness", seam_sharpness, 0.5..=6.0),
slider("Brush Stretch", brush_stretch, 1.0..=20.0),
slider("Roughness", roughness, 0.0..=1.0),
slider("Metallic", metallic, 0.0..=1.0),
slider("Rust", rust_level, 0.0..=1.0),
color("Metal Color", color_metal),
color("Rust Color", color_rust),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
impl_config_editor!(
fn pavers_config_editor, PaversConfig, "Pavers Config" => {
u32("Seed", seed),
enum_select("Layout:", layout, [
("Square", PaversLayout::Square),
("Hexagonal", PaversLayout::Hexagonal)
]),
slider_step("Scale", scale, 1.0..=16.0, 1.0),
slider("Aspect Ratio", aspect_ratio, 0.5..=3.0),
slider("Grout Width", grout_width, 0.0..=0.35),
slider("Bevel", bevel, 0.0..=1.0),
slider("Color Variance", cell_variance, 0.0..=0.8),
slider("Surface Roughness", roughness, 0.0..=1.0),
color("Stone Color", color_stone),
color("Grout Color", color_grout),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn ashlar_config_editor, AshlarConfig, "Ashlar Config" => {
u32("Seed", seed),
usize("Rows", rows, 2..=8),
usize("Cols", cols, 2..=6),
slider("Mortar Size", mortar_size, 0.005..=0.15),
slider("Bevel", bevel, 0.0..=1.0),
slider("Color Variance", cell_variance, 0.0..=1.0),
slider("Chisel Depth", chisel_depth, 0.0..=1.0),
slider("Roughness", roughness, 0.0..=1.0),
color("Stone Color", color_stone),
color("Mortar Color", color_mortar),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn cobblestone_config_editor, CobblestoneConfig, "Cobblestone Config" => {
u32("Seed", seed),
slider("Scale", scale, 2.0..=14.0),
slider("Gap Width", gap_width, 0.01..=0.3),
slider("Color Variance", cell_variance, 0.0..=1.0),
slider("Roundness", roundness, 0.3..=2.5),
color("Stone Color", color_stone),
color("Mud Color", color_mud),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn thatch_config_editor, ThatchConfig, "Thatch Config" => {
u32("Seed", seed),
slider("Fibre Density", density, 3.0..=24.0),
slider("Anisotropy", anisotropy, 2.0..=20.0),
slider("Warp", warp_strength, 0.0..=0.6),
slider("Layer Count", layer_count, 2.0..=20.0),
slider("Layer Shadow", layer_shadow, 0.0..=1.0),
color("Straw Color", color_straw),
color("Shadow Color", color_shadow),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
impl_config_editor!(
fn marble_config_editor, MarbleConfig, "Marble Config" => {
u32("Seed", seed),
slider("Scale", scale, 0.5..=10.0),
usize("Octaves", octaves, 2..=10),
slider("Warp Strength", warp_strength, 0.0..=2.0),
slider("Vein Frequency", vein_frequency, 0.5..=10.0),
slider("Vein Sharpness", vein_sharpness, 0.3..=8.0),
slider("Roughness", roughness, 0.0..=0.4),
color("Base Color", color_base),
color("Vein Color", color_vein),
slider("Normal Strength", normal_strength, 0.0..=4.0),
}
);
impl_config_editor!(
fn corrugated_config_editor, CorrugatedConfig, "Corrugated Metal Config" => {
u32("Seed", seed),
slider_step("Ridges", ridges, 2.0..=20.0, 1.0),
slider("Ridge Depth", ridge_depth, 0.3..=2.5),
slider("Roughness", roughness, 0.0..=1.0),
slider("Rust", rust_level, 0.0..=1.0),
slider("Metallic", metallic, 0.0..=1.0),
color("Metal Color", color_metal),
color("Rust Color", color_rust),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
impl_config_editor!(
fn asphalt_config_editor, AsphaltConfig, "Asphalt Config" => {
u32("Seed", seed),
slider("Scale", scale, 1.0..=14.0),
slider("Aggregate Density", aggregate_density, 0.02..=0.5),
slider("Aggregate Scale", aggregate_scale, 4.0..=40.0),
slider("Roughness", roughness, 0.5..=1.0),
slider("Stain Level", stain_level, 0.0..=1.0),
color("Base Color", color_base),
color("Aggregate Color", color_aggregate),
slider("Normal Strength", normal_strength, 0.0..=4.0),
}
);
impl_config_editor!(
fn wainscoting_config_editor, WainscotingConfig, "Wainscoting Config" => {
u32("Seed", seed),
usize("Panels X", panels_x, 1..=4),
usize("Panels Y", panels_y, 1..=4),
slider("Frame Width", frame_width, 0.05..=0.4),
slider("Panel Inset", panel_inset, 0.0..=0.2),
slider("Grain Scale", grain_scale, 4.0..=28.0),
slider("Grain Warp", grain_warp, 0.0..=1.0),
color("Wood Light", color_wood_light),
color("Wood Dark", color_wood_dark),
slider("Normal Strength", normal_strength, 0.0..=8.0),
}
);
impl_config_editor!(
fn stained_glass_config_editor, StainedGlassConfig, "Stained Glass Config" => {
u32("Seed", seed),
usize("Cell Count", cell_count, 3..=30),
slider("Lead Width", lead_width, 0.01..=0.15),
slider("Saturation", saturation, 0.3..=1.0),
slider("Glass Roughness", glass_roughness, 0.0..=0.2),
slider("Grime", grime_level, 0.0..=0.6),
slider("Normal Strength", normal_strength, 0.0..=4.0),
}
);
impl_config_editor!(
fn iron_grille_config_editor, IronGrilleConfig, "Iron Grille Config" => {
u32("Seed", seed),
usize("Bars X", bars_x, 1..=12),
usize("Bars Y", bars_y, 1..=12),
slider("Bar Width", bar_width, 0.01..=0.25),
bool("Round Bars", round_bars),
slider("Rust", rust_level, 0.0..=1.0),
color("Iron Color", color_iron),
color("Rust Color", color_rust),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
impl_config_editor!(
fn encaustic_config_editor, EncausticConfig, "Encaustic Tile Config" => {
u32("Seed", seed),
slider_step("Scale", scale, 1.0..=12.0, 1.0),
enum_select("Pattern:", pattern, [
("Checker", EncausticPattern::Checkerboard),
("Octagon", EncausticPattern::Octagon),
("Diamond", EncausticPattern::Diamond)
]),
slider("Grout Width", grout_width, 0.01..=0.2),
slider("Glaze Roughness", glaze_roughness, 0.0..=0.15),
color("Color A", color_a),
color("Color B", color_b),
color("Grout Color", color_grout),
slider("Normal Strength", normal_strength, 0.0..=6.0),
}
);
pub fn slider_debounced(
ui: &mut egui::Ui,
slider: impl egui::Widget,
writeback: &mut bool,
regen: &mut bool,
) {
let r = ui.add(slider);
*writeback |= r.changed();
*regen |= r.drag_stopped() || (r.changed() && !r.dragged());
}
pub fn f32_slider(
ui: &mut egui::Ui,
val: &mut f32,
label: &str,
range: std::ops::RangeInclusive<f32>,
) -> bool {
ui.horizontal(|ui| {
ui.label(label);
ui.add(egui::Slider::new(val, range)).changed()
})
.inner
}
pub fn f64_slider(
ui: &mut egui::Ui,
val: &mut f64,
label: &str,
range: std::ops::RangeInclusive<f64>,
) -> bool {
ui.horizontal(|ui| {
ui.label(label);
ui.add(egui::Slider::new(val, range)).changed()
})
.inner
}
pub fn usize_slider(
ui: &mut egui::Ui,
val: &mut usize,
label: &str,
range: std::ops::RangeInclusive<usize>,
) -> bool {
ui.horizontal(|ui| {
ui.label(label);
ui.add(egui::Slider::new(val, range)).changed()
})
.inner
}
pub fn u32_drag(ui: &mut egui::Ui, val: &mut u32, label: &str) -> bool {
ui.horizontal(|ui| {
ui.label(label);
ui.add(egui::DragValue::new(val).speed(1.0)).changed()
})
.inner
}
fn color_instant(
ui: &mut egui::Ui,
label: &str,
color: &mut [f32; 3],
wb: &mut bool,
regen: &mut bool,
) {
ui.horizontal(|ui| {
ui.label(label);
let r = ui.color_edit_button_rgb(color);
*wb |= r.changed();
*regen |= r.changed();
});
}
fn bool_instant(ui: &mut egui::Ui, val: &mut bool, label: &str, wb: &mut bool, regen: &mut bool) {
let r = ui.checkbox(val, label);
*wb |= r.changed();
*regen |= r.changed();
}
fn usize_instant(
ui: &mut egui::Ui,
val: &mut usize,
range: std::ops::RangeInclusive<usize>,
label: &str,
wb: &mut bool,
regen: &mut bool,
) {
let r = ui.add(egui::Slider::new(val, range).text(label));
*wb |= r.changed();
*regen |= r.changed();
}
fn u32_instant(ui: &mut egui::Ui, val: &mut u32, label: &str, wb: &mut bool, regen: &mut bool) {
ui.horizontal(|ui| {
ui.label(label);
let r = ui.add(egui::DragValue::new(val).speed(1.0));
*wb |= r.changed();
*regen |= r.changed();
});
}