terrain_forge/algorithms/
fractal.rs1use crate::{Algorithm, Grid, Rng, Tile};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
5pub enum FractalType {
7 #[default]
8 Mandelbrot,
10 Julia,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct FractalConfig {
17 pub fractal_type: FractalType,
19 pub max_iterations: usize,
21}
22
23impl Default for FractalConfig {
24 fn default() -> Self {
25 Self {
26 fractal_type: FractalType::default(),
27 max_iterations: 100,
28 }
29 }
30}
31
32#[derive(Debug, Clone)]
33pub struct Fractal {
35 config: FractalConfig,
36}
37
38impl Fractal {
39 pub fn new(config: FractalConfig) -> Self {
41 Self { config }
42 }
43}
44
45impl Default for Fractal {
46 fn default() -> Self {
47 Self::new(FractalConfig::default())
48 }
49}
50
51impl Algorithm<Tile> for Fractal {
52 fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
53 let mut rng = Rng::new(seed);
54 match self.config.fractal_type {
55 FractalType::Mandelbrot => generate_mandelbrot(grid, self.config.max_iterations),
56 FractalType::Julia => generate_julia(grid, &mut rng, self.config.max_iterations),
57 }
58 }
59
60 fn name(&self) -> &'static str {
61 "Fractal"
62 }
63}
64
65fn generate_mandelbrot(grid: &mut Grid<Tile>, max_iter: usize) {
66 let (w, h) = (grid.width(), grid.height());
67
68 for y in 0..h {
69 for x in 0..w {
70 let cx = (x as f64 / w as f64 - 0.5) * 4.0 - 0.5;
71 let cy = (y as f64 / h as f64 - 0.5) * 4.0;
72
73 let mut zx = 0.0;
74 let mut zy = 0.0;
75 let mut iter = 0;
76
77 while zx * zx + zy * zy < 4.0 && iter < max_iter {
78 let temp = zx * zx - zy * zy + cx;
79 zy = 2.0 * zx * zy + cy;
80 zx = temp;
81 iter += 1;
82 }
83
84 if iter < max_iter / 3 {
85 grid.set(x as i32, y as i32, Tile::Floor);
86 }
87 }
88 }
89}
90
91fn generate_julia(grid: &mut Grid<Tile>, rng: &mut Rng, max_iter: usize) {
92 let (w, h) = (grid.width(), grid.height());
93 let cx = rng.random() * 1.6 - 0.8;
95 let cy = rng.random() * 1.6 - 0.8;
96
97 for y in 0..h {
98 for x in 0..w {
99 let mut zx = (x as f64 / w as f64 - 0.5) * 3.0;
100 let mut zy = (y as f64 / h as f64 - 0.5) * 3.0;
101 let mut iter = 0;
102
103 while zx * zx + zy * zy < 4.0 && iter < max_iter {
104 let temp = zx * zx - zy * zy + cx;
105 zy = 2.0 * zx * zy + cy;
106 zx = temp;
107 iter += 1;
108 }
109
110 if iter < max_iter / 2 {
111 grid.set(x as i32, y as i32, Tile::Floor);
112 }
113 }
114 }
115}