proof_engine/fractal/
progressive.rs1use super::mandelbrot::{MandelbrotRenderer, MandelbrotParams, FractalPixel};
4
5pub struct ProgressiveRenderer {
7 pub target_width: u32,
8 pub target_height: u32,
9 pub current_level: u32,
10 pub max_level: u32,
11 pub pixels: Vec<FractalPixel>,
12 pub complete: bool,
13}
14
15impl ProgressiveRenderer {
16 pub fn new(width: u32, height: u32) -> Self {
17 let max_level = ((width.max(height) as f32).log2().ceil() as u32).max(2);
18 Self { target_width: width, target_height: height, current_level: 0, max_level, pixels: Vec::new(), complete: false }
19 }
20
21 pub fn step(&mut self, params: &MandelbrotParams) -> bool {
23 if self.complete { return true; }
24
25 let scale = 1u32 << (self.max_level - self.current_level);
26 let w = (self.target_width / scale).max(1);
27 let h = (self.target_height / scale).max(1);
28
29 let level_params = MandelbrotParams { width: w, height: h, ..params.clone() };
30 self.pixels = MandelbrotRenderer::render(&level_params);
31
32 self.current_level += 1;
33 self.complete = self.current_level >= self.max_level;
34 self.complete
35 }
36
37 pub fn current_resolution(&self) -> (u32, u32) {
39 let scale = 1u32 << (self.max_level - self.current_level.min(self.max_level));
40 ((self.target_width / scale).max(1), (self.target_height / scale).max(1))
41 }
42
43 pub fn progress(&self) -> f32 { self.current_level as f32 / self.max_level as f32 }
45
46 pub fn reset(&mut self) { self.current_level = 0; self.complete = false; self.pixels.clear(); }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 #[test]
54 fn progressive_refines() {
55 let mut pr = ProgressiveRenderer::new(64, 64);
56 let params = MandelbrotParams { width: 64, height: 64, max_iter: 50, ..Default::default() };
57 let (w1, h1) = pr.current_resolution();
58 pr.step(¶ms);
59 let (w2, h2) = pr.current_resolution();
60 assert!(w2 >= w1, "Resolution should increase: {w1} → {w2}");
61 }
62 #[test]
63 fn progressive_completes() {
64 let mut pr = ProgressiveRenderer::new(16, 16);
65 let params = MandelbrotParams { width: 16, height: 16, max_iter: 20, ..Default::default() };
66 for _ in 0..20 { if pr.step(¶ms) { break; } }
67 assert!(pr.complete);
68 }
69}