Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions assets/models/branch.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
newmtl Material_Branch
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.400000 0.250000 0.150000
Ks 0.100000 0.100000 0.100000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
32 changes: 32 additions & 0 deletions assets/models/branch.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
mtllib branch.mtl
o Branch
v 0.0 0.0 0.0
v 0.1 0.0 0.0
v 0.1 0.0 0.1
v 0.0 0.0 0.1
v 0.05 1.0 0.05
v 0.0 0.5 0.0
v 0.1 0.5 0.0
v 0.1 0.5 0.1
v 0.0 0.5 0.1
vn 0.0 -1.0 0.0
vn 0.0 1.0 0.0
vn -1.0 0.0 0.0
vn 1.0 0.0 0.0
vn 0.0 0.0 -1.0
vn 0.0 0.0 1.0
usemtl Material_Branch
f 1//1 2//1 3//1
f 1//1 3//1 4//1
f 1//3 4//3 8//3
f 1//3 8//3 6//3
f 2//4 7//4 3//4
f 7//4 8//4 3//4
f 4//6 3//6 8//6
f 1//5 6//5 7//5
f 1//5 7//5 2//5
f 6//3 8//3 5//3
f 7//4 5//4 8//4
f 8//6 5//6 9//6
f 6//5 5//5 7//5
f 5//2 9//2 5//2
9 changes: 9 additions & 0 deletions assets/models/leaf.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
newmtl Material_Leaf
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.200000 0.600000 0.150000
Ks 0.100000 0.100000 0.100000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
16 changes: 16 additions & 0 deletions assets/models/leaf.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
mtllib leaf.mtl
o Leaf
v -0.1 0.0 0.0
v 0.1 0.0 0.0
v 0.05 0.5 0.0
v -0.05 0.5 0.0
v 0.0 0.8 0.0
vn 0.0 0.0 1.0
vn 0.0 0.0 -1.0
usemtl Material_Leaf
f 1//1 2//1 3//1
f 1//1 3//1 4//1
f 4//1 3//1 5//1
f 2//2 1//2 3//2
f 3//2 1//2 4//2
f 3//2 4//2 5//2
9 changes: 9 additions & 0 deletions assets/models/twig.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
newmtl Material_Twig
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.350000 0.200000 0.100000
Ks 0.100000 0.100000 0.100000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
29 changes: 29 additions & 0 deletions assets/models/twig.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
mtllib twig.mtl
o Twig
v -0.02 0.0 -0.02
v 0.02 0.0 -0.02
v 0.02 0.0 0.02
v -0.02 0.0 0.02
v -0.015 1.2 -0.015
v 0.015 1.2 -0.015
v 0.015 1.2 0.015
v -0.015 1.2 0.015
vn 0.0 -1.0 0.0
vn 0.0 1.0 0.0
vn -1.0 0.0 0.0
vn 1.0 0.0 0.0
vn 0.0 0.0 -1.0
vn 0.0 0.0 1.0
usemtl Material_Twig
f 1//1 4//1 3//1
f 1//1 3//1 2//1
f 5//2 6//2 7//2
f 5//2 7//2 8//2
f 1//3 5//3 8//3
f 1//3 8//3 4//3
f 2//4 3//4 7//4
f 2//4 7//4 6//4
f 4//6 8//6 7//6
f 4//6 7//6 3//6
f 1//5 2//5 6//5
f 1//5 6//5 5//5
76 changes: 54 additions & 22 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use winit::{
window::WindowId,
};

// TODO: this could probably be calculated based on time since last frame instead
const DELTA_TIME: f32 = 0.1;

use crate::common::ModelSelection;
use crate::gui::LSystemConfig;
use crate::lsystem::LSystem;
use crate::model_loader::{Model3D, load_cylinder, load_floor, load_monkey};
use crate::model_loader::{load_floor, load_model};
use crate::scene::Scene;
use crate::turtle::TurtleInterpreter;
use crate::{
Expand All @@ -36,7 +36,7 @@ pub struct App {
pressed_keys: HashSet<KeyCode>,
interaction_mode: AppInteractionMode,
lsystem_config: Option<LSystemConfig>,
base_models: Vec<Model3D>,
model_selection: Option<ModelSelection>,
scene: Option<Scene>,
}

Expand All @@ -51,10 +51,9 @@ impl ApplicationHandler for App {
glm::vec3(0.0, 1.0, 5.0),
self.renderer.as_ref().unwrap().get_aspect_ratio(),
));
self.base_models = vec![load_cylinder(), load_monkey()];
self.scene = Some(Scene::new(
load_floor(),
self.base_models[0].clone(),
load_model(ModelSelection::default()),
Vec::new(),
3.0,
[10.0, 10.0, 10.0],
Expand Down Expand Up @@ -94,12 +93,7 @@ impl ApplicationHandler for App {
return;
}

let new_lsystem_config = self.get_current_lsystem_config();
if new_lsystem_config != self.lsystem_config.as_ref().unwrap() {
log::info!("L-System config changed to {new_lsystem_config:?}");
self.lsystem_config = Some(new_lsystem_config.clone());
self.calculate_transformations();
}
self.update_fractal();

self.render_scene();
self.handle_movement();
Expand Down Expand Up @@ -197,17 +191,6 @@ impl App {

fn render_scene(&mut self) {
let renderer = self.renderer.as_mut().unwrap();

// TODO some reasonable base models for L-systems
let model = match renderer.get_gui_controller().get_model_selection() {
crate::gui::ModelSelection::Monkey => &self.base_models[1],
crate::gui::ModelSelection::Cylinder => &self.base_models[0],
};

if model.geometry.name != self.scene.as_ref().unwrap().fractal_base().geometry.name {
self.scene.as_mut().unwrap().set_fractal_base(model.clone());
}

let camera = self.camera.as_ref().unwrap();

renderer.render_scene(
Expand All @@ -217,6 +200,55 @@ impl App {
);
}

fn update_fractal(&mut self) {
let Some(renderer) = &self.renderer else {
return;
};

let gui = renderer.get_gui_controller();
let config = gui.get_lsystem_config();
let model_selection = gui.get_model_selection();

let config_changed = self.lsystem_config.as_ref() != Some(config);
let model_changed = self.model_selection.as_ref() != Some(model_selection);

if !config_changed && !model_changed {
return;
}

log::info!(
"Updating fractal - config_changed: {config_changed}, model_changed: {model_changed}"
);

if config_changed {
log::info!("L-System config changed to {config:?}");
self.lsystem_config = Some(config.clone());
}

if model_changed {
log::info!("Model selection changed to {model_selection:?}");
self.model_selection = Some(*model_selection);

let new_base = load_model(*model_selection);

if let Some(scene) = &mut self.scene {
scene.set_fractal_base(new_base);
}
}

let production_rules: HashMap<char, String> =
config.production_rules.iter().cloned().collect();
let lsystem = LSystem::new(&config.axiom, production_rules);
let generated = lsystem.generate(config.n_iterations);
let transformations = TurtleInterpreter::interpret(&generated, config.angle);

if let Some(scene) = &mut self.scene {
scene.update_transformations(transformations, config.fractal_height);
}

renderer.request_redraw();
}

fn calculate_transformations(&mut self) {
let lsystem_config = self.get_current_lsystem_config();
let target_height = lsystem_config.fractal_height;
Expand Down
9 changes: 9 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[derive(Debug, PartialEq, Clone, Copy, Default)]
pub enum ModelSelection {
#[default]
Cylinder,
Branch,
Leaf,
Twig,
Monkey,
}
14 changes: 6 additions & 8 deletions src/gui.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::common::ModelSelection;
use egui::Ui;
use egui_glium::EguiGlium;
use egui_glium::egui_winit::egui::ViewportId;
Expand Down Expand Up @@ -75,12 +76,6 @@ impl PresetSelection {
}
}

#[derive(Debug, PartialEq)]
pub enum ModelSelection {
Cylinder,
Monkey,
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ShadingMode {
Flat,
Expand Down Expand Up @@ -140,11 +135,14 @@ impl GuiController {
shading_mode: &mut ShadingMode,
ui: &mut Ui,
) {
egui::ComboBox::from_label("Selected Model")
egui::ComboBox::from_label("Base Model")
.selected_text(format!("{model_selection:?}"))
.show_ui(ui, |ui| {
ui.selectable_value(model_selection, ModelSelection::Monkey, "Monkey");
ui.selectable_value(model_selection, ModelSelection::Cylinder, "Cylinder");
ui.selectable_value(model_selection, ModelSelection::Branch, "Branch");
ui.selectable_value(model_selection, ModelSelection::Twig, "Twig");
ui.selectable_value(model_selection, ModelSelection::Leaf, "Leaf");
ui.selectable_value(model_selection, ModelSelection::Monkey, "Monkey");
});

ui.label("Shading Mode:");
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern crate nalgebra_glm as glm;

mod app;
mod camera;
mod common;
mod gui;
mod lsystem;
mod model_loader;
Expand Down
65 changes: 51 additions & 14 deletions src/model_loader.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::common::ModelSelection;
use tobj::{Material, Model};

#[derive(Clone, Debug)]
Expand All @@ -22,7 +23,7 @@ fn load_obj_file(path: &str) -> Model3D {
assert_eq!(
materials.len(),
1,
"Expected exactly one material in material file for {path}"
"Expected exactly one material in {path}"
);

let geometry = models.first().expect("Expected model").clone();
Expand All @@ -31,18 +32,40 @@ fn load_obj_file(path: &str) -> Model3D {
Model3D { geometry, material }
}

pub fn load_monkey() -> Model3D {
load_obj_file("assets/models/monkey.obj")
}

pub fn load_floor() -> Model3D {
load_obj_file("assets/models/floor.obj")
}

pub fn load_cylinder() -> Model3D {
fn load_monkey() -> Model3D {
load_obj_file("assets/models/monkey.obj")
}

fn load_cylinder() -> Model3D {
load_obj_file("assets/models/cylinder.obj")
}

fn load_branch() -> Model3D {
load_obj_file("assets/models/branch.obj")
}

fn load_leaf() -> Model3D {
load_obj_file("assets/models/leaf.obj")
}

fn load_twig() -> Model3D {
load_obj_file("assets/models/twig.obj")
}

pub fn load_model(selected_model: ModelSelection) -> Model3D {
match selected_model {
ModelSelection::Cylinder => load_cylinder(),
ModelSelection::Branch => load_branch(),
ModelSelection::Leaf => load_leaf(),
ModelSelection::Twig => load_twig(),
ModelSelection::Monkey => load_monkey(),
}
}

#[cfg(test)]
mod tests {
use crate::model_loader::*;
Expand Down Expand Up @@ -88,16 +111,30 @@ mod tests {
}

#[test]
fn floor_loads_correctly() {
let floor_model = load_floor();
display_model_info(&floor_model);
check_if_model_loaded_correctly(&floor_model);
fn cylinder_loads_correctly() {
let model = load_cylinder();
check_if_model_loaded_correctly(&model);
display_model_info(&model);
}

#[test]
fn cylinder_loads_correctly() {
let cylinder_model = load_cylinder();
display_model_info(&cylinder_model);
check_if_model_loaded_correctly(&cylinder_model);
fn branch_loads_correctly() {
let model = load_branch();
check_if_model_loaded_correctly(&model);
display_model_info(&model);
}

#[test]
fn leaf_loads_correctly() {
let model = load_leaf();
check_if_model_loaded_correctly(&model);
display_model_info(&model);
}

#[test]
fn twig_loads_correctly() {
let model = load_twig();
check_if_model_loaded_correctly(&model);
display_model_info(&model);
}
}
Loading