use crate::{ app::App, diff::Differ, export::Exporter, paint::{PaintUniforms, Painter}, }; use log::{debug, info}; use rand::Rng; use std::sync::Arc; use wgpu::{Extent3d, Texture, TextureUsages}; #[allow(unused)] pub struct Approximator { app: Arc, size: Extent3d, differ: Differ, painter: Painter, exporter: Exporter, tex_approx: Texture, tex_savestate: Texture, tex_target: Texture, } impl Approximator { pub fn new(app: &Arc, tex_target: Texture, size: Extent3d) -> Self { let App { device, .. } = app.as_ref(); let tex_approx = device.create_texture(&wgpu::TextureDescriptor { size, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8Unorm, usage: TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING | TextureUsages::STORAGE_BINDING | TextureUsages::COPY_SRC, label: None, }); let tex_savestate = device.create_texture(&wgpu::TextureDescriptor { size, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8Unorm, usage: TextureUsages::COPY_DST | TextureUsages::COPY_SRC, label: None, }); // let initial_init = (0..) // write_texture(queue, &tex_approx, initial_init, size); let differ = Differ::new(&app, size, &tex_approx, &tex_target); let painter = Painter::new(&app, size, &tex_approx); let exporter = Exporter::new(&app, size); Approximator { app: app.clone(), size, differ, tex_savestate, tex_approx, tex_target, painter, exporter, } } pub fn save(&self) { self.app .copy_texture(&self.tex_approx, &self.tex_savestate, self.size); } pub fn restore(&self) { self.app .copy_texture(&self.tex_savestate, &self.tex_approx, self.size); } pub async fn run(&mut self, iters: usize) { let rscale = self.size.width as f32 * 0.1; for i in 0..iters { let mut p = PaintUniforms { x: rand::thread_rng().gen_range(0.0..self.size.width as f32), y: rand::thread_rng().gen_range(0.0..self.size.height as f32), rx: rscale, ry: rscale, r: rand::thread_rng().gen_range(0.0..1.0), g: rand::thread_rng().gen_range(0.0..1.0), b: rand::thread_rng().gen_range(0.0..1.0), }; // Find initial diff self.save(); self.painter.run(p); let initial_diff = pollster::block_on(self.differ.run()); debug!("initial diff={initial_diff}"); self.restore(); let mut cd = initial_diff; self.save(); loop { let mut q = 0; let mut k = |k: usize| { q += k; q == 0 }; if k(self.optimize_param(&mut cd, &mut p, "more red", |p| p.r += 0.1)) { k(self.optimize_param(&mut cd, &mut p, "less red", |p| p.r -= 0.1)); } if k(self.optimize_param(&mut cd, &mut p, "more green", |p| p.g += 0.1)) { k(self.optimize_param(&mut cd, &mut p, "less green", |p| p.g -= 0.1)); } if k(self.optimize_param(&mut cd, &mut p, "more blue", |p| p.b += 0.1)) { k(self.optimize_param(&mut cd, &mut p, "less blue", |p| p.b -= 0.1)); } if k(self.optimize_param(&mut cd, &mut p, "increase rx", |p| p.rx *= 1.5)) { k(self.optimize_param(&mut cd, &mut p, "decrease rx", |p| p.rx /= 1.5)); } if k(self.optimize_param(&mut cd, &mut p, "increase ry", |p| p.ry *= 1.5)) { k(self.optimize_param(&mut cd, &mut p, "decrease ry", |p| p.ry /= 1.5)); } if k(self.optimize_param(&mut cd, &mut p, "move right", |p| p.x += 5.0)) { k(self.optimize_param(&mut cd, &mut p, "move left", |p| p.x -= 5.0)); } if k(self.optimize_param(&mut cd, &mut p, "move down", |p| p.y += 5.0)) { k(self.optimize_param(&mut cd, &mut p, "move up", |p| p.y -= 5.0)); } if q == 0 { break; } } self.painter.run(p); info!("{i} (improvement={})", initial_diff - cd); } self.exporter.run(&self.tex_approx, "a/approx.png").await; } pub fn optimize_param( &self, current_diff: &mut u32, params: &mut PaintUniforms, label: &'static str, f: F, ) -> usize where F: Fn(&mut PaintUniforms) -> (), { let mut p = params.clone(); let mut i = 0; loop { f(&mut p); self.painter.run(p); let diff = pollster::block_on(self.differ.run()); // pollster::block_on(self.exporter.run(&self.tex_approx, &format!("a/snap.png"))); debug!("try {label:?} ({})", diff as i64 - *current_diff as i64); self.restore(); if diff >= *current_diff { break i; } debug!("applied {label:?}"); i += 1; *current_diff = diff; *params = p } } }