#![allow(dead_code, unused_imports, unused_variables, unused_macros, unreachable_patterns)] use std::io::Write; const SHADOW_RS: &str = "hcie-fx/src/emboss.rs"; const PSD_BASE: &str = "_images/_psd_stil_test/test_2"; const RESULTS_FILE: &str = "./emboss_results.txt"; fn main() { let original = std::fs::read_to_string(SHADOW_RS).expect("read shadow.rs"); let start_tag = " // BEGIN_TUNING_ZONE"; let end_tag = " // END_TUNING_ZONE"; let zone_start = original.find(start_tag).unwrap(); let zone_end = original.find(end_tag).unwrap(); let before = &original[..zone_start]; let after = &original[zone_end + end_tag.len()..]; let ref_img = image::open(&format!("{}/Emboss.png", PSD_BASE)) .expect("open Emboss.png") .to_rgba8(); let (w, h) = (ref_img.width(), ref_img.height()); let px = (w * h) as usize; let ref_pixels = ref_img.into_raw(); let layers = hcie_psd::import_psd(std::path::Path::new(&format!("{}/Emboss.psd", PSD_BASE))) .expect("import Emboss.psd"); let layer = &layers[0]; let alpha: Vec = layer.pixels.iter().skip(3).step_by(4).copied().collect(); let (depth, size, soften, angle, altitude, direction, technique, style) = { let mut d = 0.0f32; let mut sz = 0.0f32; let mut sof = 0.0f32; let mut ang = 0.0f32; let mut alt = 0.0f32; let mut dir = hcie_protocol::effects::Direction::Up; let mut tech = hcie_protocol::effects::Technique::Smooth; let mut sty = hcie_protocol::effects::BevelStyle::InnerBevel; for e in &layer.effects { if let hcie_protocol::effects::LayerEffect::BevelEmboss { enabled: true, depth, size, soften, angle, altitude, direction, technique, style, .. } = e { d = *depth; sz = *size; sof = *soften; ang = *angle; alt = *altitude; dir = direction.clone(); tech = technique.clone(); sty = style.clone(); } } (d, sz, sof, ang, alt, match dir { hcie_protocol::effects::Direction::Up => hcie_fx::types::Direction::Up, _ => hcie_fx::types::Direction::Down }, match tech { hcie_protocol::effects::Technique::Smooth => hcie_fx::types::Technique::Smooth, hcie_protocol::effects::Technique::ChiselHard => hcie_fx::types::Technique::ChiselHard, _ => hcie_fx::types::Technique::ChiselSoft }, match sty { hcie_protocol::effects::BevelStyle::InnerBevel => hcie_fx::types::BevelStyle::InnerBevel, hcie_protocol::effects::BevelStyle::OuterBevel => hcie_fx::types::BevelStyle::OuterBevel, hcie_protocol::effects::BevelStyle::Emboss => hcie_fx::types::BevelStyle::Emboss, hcie_protocol::effects::BevelStyle::PillowEmboss => hcie_fx::types::BevelStyle::PillowEmboss, _ => hcie_fx::types::BevelStyle::StrokeEmboss, }) }; println!("Emboss params: depth={}, size={}, soften={}, angle={}, altitude={}", depth, size, soften, angle, altitude); println!("Image: {}x{}", w, h); std::io::stdout().flush().ok(); let mut best_mae = f64::MAX; let mut best_code = String::new(); let mut best_params = (0i32, 0.0f32, 0.0f32); // Phase 1: coarse wide range let coarse_blur = &[4, 8, 12, 16, 20, 24, 30]; let coarse_hl = &[0.2, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0]; let coarse_sh = &[0.2, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0]; let total = coarse_blur.len() * coarse_hl.len() * coarse_sh.len(); println!("Phase 1: coarse grid ({} combos)", total); std::io::stdout().flush().ok(); search(original.as_str(), before, after, &alpha, w, h, px, &ref_pixels, &layer.pixels, depth, size, soften, angle, altitude, &direction, &technique, &style, coarse_blur, coarse_hl, coarse_sh, &mut best_mae, &mut best_code, &mut best_params); // Phase 2: fine grid around best let (bb, bhl, bsh) = best_params; let fine_blur: Vec = (bb - 4 ..= bb + 4).filter(|&v| v > 0).collect(); let fine_hl: Vec = ((bhl * 100.0 - 50.0) as i32 ..= (bhl * 100.0 + 50.0) as i32) .step_by(5).map(|v| v as f32 / 100.0).filter(|&v| v > 0.0).collect(); let fine_sh: Vec = ((bsh * 100.0 - 50.0) as i32 ..= (bsh * 100.0 + 50.0) as i32) .step_by(5).map(|v| v as f32 / 100.0).filter(|&v| v > 0.0).collect(); println!("\nPhase 2: fine grid around best ({} x {} x {} = {} combos)", fine_blur.len(), fine_hl.len(), fine_sh.len(), fine_blur.len() * fine_hl.len() * fine_sh.len()); std::io::stdout().flush().ok(); search(original.as_str(), before, after, &alpha, w, h, px, &ref_pixels, &layer.pixels, depth, size, soften, angle, altitude, &direction, &technique, &style, &fine_blur, &fine_hl, &fine_sh, &mut best_mae, &mut best_code, &mut best_params); if best_mae < f64::MAX { let (bb, bhl, bsh) = best_params; let zone_code = format!( " // BEGIN_TUNING_ZONE let lighting_blur = {}; lighting = box_blur_f32(&lighting, w, h, lighting_blur); for i in 0..px {{ let is_inner = alpha[i] > 0; let show = match style {{ crate::types::BevelStyle::InnerBevel => is_inner, crate::types::BevelStyle::OuterBevel => !is_inner, crate::types::BevelStyle::Emboss => true, _ => is_inner, }}; if !show {{ continue; }} let dist_abs = if is_inner {{ dist_inside_sq[i].sqrt() }} else {{ dist_outside_sq[i].sqrt() }}; if !is_inner && dist_abs > radius {{ continue; }} let technique_show = match technique {{ crate::types::Technique::Smooth => true, _ => dist_abs <= radius, }}; if !technique_show {{ continue; }} let ndl = lighting[i]; let is_flat = is_inner && dist_abs > radius; if is_flat {{ if style == crate::types::BevelStyle::Emboss && depth > 100.0 {{ shadow_buf[i * 4 + 3] = alpha[i]; }} continue; }} let hl_pred = (ndl * {:.4}).clamp(0.0, 1.0); let sh_pred = (-ndl * {:.4}).clamp(0.0, 1.0); let hl_a = (alpha[i] as f32 * hl_pred).round() as u8; let sh_a = (alpha[i] as f32 * sh_pred).round() as u8; if hl_a > 0 {{ highlight_buf[i * 4] = highlight_color[0]; highlight_buf[i * 4 + 1] = highlight_color[1]; highlight_buf[i * 4 + 2] = highlight_color[2]; highlight_buf[i * 4 + 3] = hl_a; }} if sh_a > 0 {{ shadow_buf[i * 4] = shadow_color[0]; shadow_buf[i * 4 + 1] = shadow_color[1]; shadow_buf[i * 4 + 2] = shadow_color[2]; shadow_buf[i * 4 + 3] = sh_a; }} }} // END_TUNING_ZONE", bb, bhl, bsh ); let mut patched = String::with_capacity(original.len()); patched.push_str(&original[..zone_start]); patched.push_str(&zone_code); patched.push_str(&original[zone_end + end_tag.len()..]); std::fs::write(SHADOW_RS, &patched).expect("write final best"); println!("\nCompleted. Best code saved with MAE = {:.3} (blur={}, hl_scale={:.2}, sh_scale={:.2})", best_mae, bb, bhl, bsh); if let Ok(mut file) = std::fs::OpenOptions::new().create(true).write(true).truncate(true).open(RESULTS_FILE) { let _ = writeln!(file, "=== Emboss Tuned ===\n Params: blur={}, hl_scale={:.2}, sh_scale={:.2}\n MAE: {:.3}", bb, bhl, bsh, best_mae); } } else { std::fs::write(SHADOW_RS, &original).expect("restore original"); } } fn search( _original: &str, _before: &str, _after: &str, alpha: &[u8], w: u32, h: u32, px: usize, ref_pixels: &[u8], src_pixels: &[u8], depth: f32, size: f32, soften: f32, angle: f32, altitude: f32, direction: &hcie_fx::types::Direction, technique: &hcie_fx::types::Technique, style: &hcie_fx::types::BevelStyle, blur_list: &[i32], hl_list: &[f32], sh_list: &[f32], best_mae: &mut f64, _best_code: &mut String, best_params: &mut (i32, f32, f32), ) { let total = blur_list.len() * hl_list.len() * sh_list.len(); let mut count = 0usize; for blur in blur_list { for hl_scale in hl_list { for sh_scale in sh_list { count += 1; if count % 100 == 0 { println!(" [{}/{}] best={:.3}", count, total, best_mae); std::io::stdout().flush().ok(); } let (hl_buf, sh_buf) = hcie_fx::tuned::generate_bevel_tuned( alpha, w, h, depth, size, soften, angle, altitude, direction, technique, style, *blur, *hl_scale, *sh_scale, 1.0, 0.05, ); let mut out = src_pixels.to_vec(); for i in 0..px { let dst = [out[i*4], out[i*4+1], out[i*4+2], out[i*4+3]]; let hl_src = [hl_buf[i*4], hl_buf[i*4+1], hl_buf[i*4+2], hl_buf[i*4+3]]; let sh_src = [sh_buf[i*4], sh_buf[i*4+1], sh_buf[i*4+2], sh_buf[i*4+3]]; let blended = hcie_blend::blend_pixels(dst, hl_src, hcie_blend::BlendMode::Screen, 0.75); let blended = hcie_blend::blend_pixels(blended, sh_src, hcie_blend::BlendMode::Multiply, 0.75); out[i*4..i*4+4].copy_from_slice(&blended); } let mut diff_sum = 0.0f64; for i in 0..px { let d = (0..4).map(|c| { (out[i * 4 + c] as i32 - ref_pixels[i * 4 + c] as i32).abs() as f64 }).sum::(); diff_sum += d; } let mae = diff_sum / px as f64 / 4.0; if mae < *best_mae { *best_mae = mae; *best_params = (*blur, *hl_scale, *sh_scale); println!("*** NEW BEST: {:.3} (blur={}, hl_scale={:.2}, sh_scale={:.2})", best_mae, blur, hl_scale, sh_scale); std::io::stdout().flush().ok(); } } } } }