Skip to content

Commit 1efbcbc

Browse files
committed
chore: merge 22
2 parents 8798a3e + 325f371 commit 1efbcbc

7 files changed

Lines changed: 251 additions & 155 deletions

File tree

src/app.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl ApplicationHandler for App {
5959
load_floor(),
6060
self.base_models[0].clone(),
6161
Vec::new(),
62+
3.0,
6263
[10.0, 10.0, 10.0],
6364
));
6465

@@ -250,7 +251,7 @@ impl App {
250251

251252
fn calculate_transformations(&mut self) {
252253
let lsystem_config = self.get_current_lsystem_config();
253-
254+
let target_height = lsystem_config.fractal_height;
254255
let production_rules: HashMap<char, String> =
255256
lsystem_config.production_rules.iter().cloned().collect();
256257
let lsystem = LSystem::new(&lsystem_config.axiom, production_rules);
@@ -272,7 +273,7 @@ impl App {
272273
self.scene
273274
.as_mut()
274275
.unwrap()
275-
.update_transformations(final_transformations);
276+
.update_transformations(final_transformations, target_height);
276277
self.renderer
277278
.as_mut()
278279
.unwrap()

src/gui.rs

Lines changed: 92 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use egui::Context;
1+
use egui::Ui;
22
use egui_glium::EguiGlium;
33
use egui_glium::egui_winit::egui::ViewportId;
44
use glium::glutin::surface::WindowSurface;
@@ -24,15 +24,17 @@ pub struct LSystemConfig {
2424
pub production_rules: Vec<(char, String)>,
2525
pub n_iterations: u32,
2626
pub angle: f32,
27+
pub fractal_height: f32, // TODO move elsewhere, now leaving here for convenience with App update logic
2728
}
2829

2930
impl Default for LSystemConfig {
3031
fn default() -> Self {
3132
Self {
3233
axiom: "F".to_string(),
33-
production_rules: vec![('F', "F[+F]F[-F]F".to_string())],
34+
production_rules: vec![('F', "F[+F][&F][\\F]F[-F][^F][/F]F".to_string())],
3435
n_iterations: 3,
3536
angle: 25.0,
37+
fractal_height: 3.0,
3638
}
3739
}
3840
}
@@ -148,101 +150,97 @@ impl GuiController {
148150
fn ui_control_panel(
149151
model_selection: &mut ModelSelection,
150152
shading_mode: &mut ShadingMode,
151-
ctx: &Context,
153+
ui: &mut Ui,
152154
) {
153-
egui::Window::new("Control panel").show(ctx, |ui| {
154-
egui::ComboBox::from_label("Selected Model")
155-
.selected_text(format!("{model_selection:?}"))
156-
.show_ui(ui, |ui| {
157-
ui.selectable_value(model_selection, ModelSelection::Monkey, "Monkey");
158-
ui.selectable_value(model_selection, ModelSelection::Cylinder, "Cylinder");
159-
});
155+
egui::ComboBox::from_label("Selected Model")
156+
.selected_text(format!("{model_selection:?}"))
157+
.show_ui(ui, |ui| {
158+
ui.selectable_value(model_selection, ModelSelection::Monkey, "Monkey");
159+
ui.selectable_value(model_selection, ModelSelection::Cylinder, "Cylinder");
160+
});
160161

161-
ui.separator();
162-
ui.label("Shading Mode:");
163-
ui.radio_value(shading_mode, ShadingMode::Flat, "Flat");
164-
ui.radio_value(shading_mode, ShadingMode::Gouraud, "Gouraud");
165-
ui.radio_value(shading_mode, ShadingMode::Phong, "Phong");
166-
ui.separator();
167-
});
162+
ui.label("Shading Mode:");
163+
ui.radio_value(shading_mode, ShadingMode::Flat, "Flat");
164+
ui.radio_value(shading_mode, ShadingMode::Gouraud, "Gouraud");
165+
ui.radio_value(shading_mode, ShadingMode::Phong, "Phong");
166+
}
167+
168+
fn ui_fractal_height(fractal_height: &mut f32, ui: &mut Ui) {
169+
ui.label("Fractal Height:");
170+
ui.add(egui::Slider::new(fractal_height, 0.1..=5.0).text("Fractal Height"));
168171
}
169172

170173
fn ui_tree_generation_config(
171174
tree_generation_config: &mut TreeGenerationConfig,
172175
requires_redraw: &mut bool,
173-
ctx: &Context,
176+
ui: &mut Ui,
174177
) {
175-
egui::Window::new("Tree Generation").show(ctx, |ui| {
176-
ui.label("Number of trees");
177-
ui.add(egui::Slider::new(
178-
&mut tree_generation_config.num_trees,
179-
1..=128,
180-
));
181-
ui.label("X Bounds:");
182-
ui.add(
183-
egui::Slider::new(
184-
&mut tree_generation_config.xmin,
185-
-50..=tree_generation_config.xmax - 1,
186-
)
187-
.text("X Min"),
188-
);
189-
ui.add(
190-
egui::Slider::new(
191-
&mut tree_generation_config.xmax,
192-
(tree_generation_config.xmin + 1)..=50,
193-
)
194-
.text("X Max"),
195-
);
196-
ui.label("Z Bounds:");
197-
ui.add(
198-
egui::Slider::new(
199-
&mut tree_generation_config.zmin,
200-
-50..=tree_generation_config.zmax - 1,
201-
)
202-
.text("Z Min"),
203-
);
204-
ui.add(
205-
egui::Slider::new(
206-
&mut tree_generation_config.zmax,
207-
(tree_generation_config.zmin + 1)..=50,
208-
)
209-
.text("Z Max"),
210-
);
211-
if ui.add(egui::Button::new("Regenerate trees")).clicked() {
212-
*requires_redraw = true;
213-
}
214-
});
178+
ui.label("Number of trees");
179+
ui.add(egui::Slider::new(
180+
&mut tree_generation_config.num_trees,
181+
1..=128,
182+
));
183+
ui.label("X Bounds:");
184+
ui.add(
185+
egui::Slider::new(
186+
&mut tree_generation_config.xmin,
187+
-50..=tree_generation_config.xmax - 1,
188+
)
189+
.text("X Min"),
190+
);
191+
ui.add(
192+
egui::Slider::new(
193+
&mut tree_generation_config.xmax,
194+
(tree_generation_config.xmin + 1)..=50,
195+
)
196+
.text("X Max"),
197+
);
198+
ui.label("Z Bounds:");
199+
ui.add(
200+
egui::Slider::new(
201+
&mut tree_generation_config.zmin,
202+
-50..=tree_generation_config.zmax - 1,
203+
)
204+
.text("Z Min"),
205+
);
206+
ui.add(
207+
egui::Slider::new(
208+
&mut tree_generation_config.zmax,
209+
(tree_generation_config.zmin + 1)..=50,
210+
)
211+
.text("Z Max"),
212+
);
213+
if ui.add(egui::Button::new("Regenerate trees")).clicked() {
214+
*requires_redraw = true;
215+
}
215216
}
216217

217218
// TODO make editable
218-
fn ui_lsystem_config(lsystem_config: &mut LSystemConfig, ctx: &Context) {
219-
egui::Window::new("LSystem Configuration").show(ctx, |ui| {
220-
ui.add(
221-
egui::Slider::new(&mut lsystem_config.n_iterations, 0..=6)
222-
.text("Number of Iterations"),
223-
);
224-
ui.add(egui::Slider::new(&mut lsystem_config.angle, 0.0..=45.0).text("Angle"));
225-
ui.label(format!("{:?}", lsystem_config.axiom));
226-
ui.label("Production Rules:");
227-
for (i, (symbol, replacement)) in lsystem_config.production_rules.iter().enumerate() {
228-
ui.horizontal(|ui| {
229-
ui.label(format!("{i}: {symbol} -> {replacement}"));
230-
});
231-
}
232-
});
219+
fn ui_lsystem_config(lsystem_config: &mut LSystemConfig, ui: &mut Ui) {
220+
ui.label("LSystem Config:");
221+
ui.add(
222+
egui::Slider::new(&mut lsystem_config.n_iterations, 0..=6).text("Number of Iterations"),
223+
);
224+
ui.add(egui::Slider::new(&mut lsystem_config.angle, 0.0..=45.0).text("Angle"));
225+
ui.label(format!("{:?}", lsystem_config.axiom));
226+
ui.label("Production Rules:");
227+
for (i, (symbol, replacement)) in lsystem_config.production_rules.iter().enumerate() {
228+
ui.horizontal(|ui| {
229+
ui.label(format!("{i}: {symbol} -> {replacement}"));
230+
});
231+
}
233232
}
234233

235234
fn ui_color_panel(
236235
interpolation_color_low: &mut [f32; 3],
237236
interpolation_color_high: &mut [f32; 3],
238-
ctx: &Context,
237+
ui: &mut Ui,
239238
) {
240-
egui::Window::new("Color Configuration").show(ctx, |ui| {
241-
ui.label("Color - low");
242-
ui.color_edit_button_rgb(interpolation_color_low);
243-
ui.label("Color - high");
244-
ui.color_edit_button_rgb(interpolation_color_high);
245-
});
239+
ui.label("Color Interpolation:");
240+
ui.label("Color - low");
241+
ui.color_edit_button_rgb(interpolation_color_low);
242+
ui.label("Color - high");
243+
ui.color_edit_button_rgb(interpolation_color_high);
246244
}
247245

248246
pub fn draw(&mut self, window: &Window, display: &Display<WindowSurface>, frame: &mut Frame) {
@@ -253,14 +251,20 @@ impl GuiController {
253251
let color_high = &mut self.interpolation_color_high;
254252

255253
self.egui_glium.run(window, |ctx| {
256-
GuiController::ui_control_panel(model_selection, shading_mode, ctx);
257-
GuiController::ui_lsystem_config(lsystem_config, ctx);
258-
GuiController::ui_color_panel(color_low, color_high, ctx);
259-
GuiController::ui_tree_generation_config(
260-
&mut self.tree_generation_config,
261-
&mut self.requires_tree_regeneration,
262-
ctx,
263-
);
254+
egui::Window::new("Control panel").show(ctx, |ui| {
255+
GuiController::ui_control_panel(model_selection, shading_mode, ui);
256+
GuiController::ui_fractal_height(&mut lsystem_config.fractal_height, ui);
257+
ui.separator();
258+
GuiController::ui_lsystem_config(lsystem_config, ui);
259+
ui.separator();
260+
GuiController::ui_color_panel(color_low, color_high, ui);
261+
ui.separator();
262+
GuiController::ui_tree_generation_config(
263+
&mut self.tree_generation_config,
264+
&mut self.requires_tree_regeneration,
265+
ui,
266+
);
267+
});
264268
});
265269
self.egui_glium.paint(display, frame);
266270
}

src/lsystem.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ pub struct LSystem {
66
}
77

88
impl LSystem {
9-
// TODO: restrict input to a predefined alphabet?
109
pub fn new(axiom: &str, production_rules: HashMap<char, String>) -> Self {
1110
Self {
1211
axiom: axiom.to_string(),

src/model_loader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ fn load_obj_file(path: &str) -> Model3D {
2525
"Expected exactly one material in material file for {path}"
2626
);
2727

28-
let model = models.first().expect("Expected model").clone();
28+
let geometry = models.first().expect("Expected model").clone();
2929
let material = materials.first().expect("Expected material").clone();
3030

31-
Model3D { geometry: model, material }
31+
Model3D { geometry, material }
3232
}
3333

3434
pub fn load_monkey() -> Model3D {

src/renderer.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ impl Renderer {
9191
let (interpolation_color_low, interpolation_color_high) =
9292
self.gui.get_interpolation_colors();
9393

94-
let fractal_total_height = scene.fractal_total_height();
95-
9694
if !scene.transformations().is_empty() {
9795
let instance_data: Vec<InstanceData> = scene
9896
.transformations()
@@ -111,7 +109,7 @@ impl Renderer {
111109
view_parameters,
112110
*scene.light_position(),
113111
shading_mode,
114-
fractal_total_height,
112+
scene.target_height(),
115113
interpolation_color_low,
116114
interpolation_color_high,
117115
ColorMode::Interpolated,

src/scene.rs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub struct Scene {
66
floor: Model3D,
77
fractal_base: Model3D,
88
transformations: Vec<Vec<Mat4>>,
9+
target_height: f32,
910
light_position: [f32; 3],
1011
}
1112

@@ -14,12 +15,14 @@ impl Scene {
1415
floor: Model3D,
1516
fractal_base: Model3D,
1617
transformations: Vec<Vec<Mat4>>,
18+
target_height: f32,
1719
light_position: [f32; 3],
1820
) -> Self {
1921
Self {
2022
floor,
2123
fractal_base,
2224
transformations,
25+
target_height,
2326
light_position,
2427
}
2528
}
@@ -36,12 +39,22 @@ impl Scene {
3639
&self.transformations
3740
}
3841

42+
pub fn target_height(&self) -> f32 {
43+
self.target_height
44+
}
45+
3946
pub fn light_position(&self) -> &[f32; 3] {
4047
&self.light_position
4148
}
4249

43-
pub fn update_transformations(&mut self, transformations: Vec<Vec<Mat4>>) {
44-
self.transformations = transformations;
50+
pub fn update_transformations(&mut self, transformations: Vec<Vec<Mat4>>, target_height: f32) {
51+
let scaled_transformations = Self::scale_transformations_to_height(
52+
transformations,
53+
target_height,
54+
&self.fractal_base.geometry,
55+
);
56+
self.transformations = scaled_transformations;
57+
self.target_height = target_height;
4558
}
4659

4760
pub fn set_fractal_base(&mut self, model: Model3D) {
@@ -58,19 +71,38 @@ impl Scene {
5871
.fold(f32::NEG_INFINITY, f32::max)
5972
}
6073

61-
pub fn fractal_total_height(&self) -> f32 {
62-
if self.transformations.is_empty() {
74+
fn fractal_total_height(base: &Model, transformations: &[Vec<Mat4>]) -> f32 {
75+
if transformations.is_empty() {
6376
return 0.0;
6477
}
6578

66-
let model_height = Self::model_max_local_y(&self.fractal_base.geometry);
79+
let model_height = Self::model_max_local_y(base);
6780
let up_vector = Vec4::new(0.0, model_height, 0.0, 1.0);
6881

69-
self.transformations
70-
.first()
71-
.expect("Empty case was handled above")
82+
transformations
7283
.iter()
73-
.map(|mat| (mat * up_vector)[1])
84+
.flat_map(|mat_list| mat_list.iter().map(|mat| (mat * up_vector)[1]))
7485
.fold(f32::NEG_INFINITY, f32::max)
7586
}
87+
88+
fn scale_transformations_to_height(
89+
transformations: Vec<Vec<Mat4>>,
90+
target_height: f32,
91+
base_model: &Model,
92+
) -> Vec<Vec<Mat4>> {
93+
let current_height = Self::fractal_total_height(base_model, &transformations);
94+
if current_height == 0.0 {
95+
return transformations;
96+
}
97+
let scale_factor = target_height / current_height;
98+
let scale_matrix = glm::scale(
99+
&Mat4::identity(),
100+
&glm::vec3(scale_factor, scale_factor, scale_factor),
101+
);
102+
103+
transformations
104+
.into_iter()
105+
.map(|mat_list| mat_list.into_iter().map(|mat| scale_matrix * mat).collect())
106+
.collect()
107+
}
76108
}

0 commit comments

Comments
 (0)