127 lines
5.1 KiB
Rust
127 lines
5.1 KiB
Rust
|
|
#![allow(unreachable_patterns, unused_assignments, unused_must_use)]
|
||
|
|
#![allow(dead_code, unused_imports, unused_variables, unused_macros)]
|
||
|
|
use std::io::Write;
|
||
|
|
|
||
|
|
const SHADOW_RS: &str = "hcie-fx/src/shadow.rs";
|
||
|
|
|
||
|
|
fn main() {
|
||
|
|
let original = std::fs::read_to_string(SHADOW_RS).expect("read shadow.rs");
|
||
|
|
|
||
|
|
let mut best_mae = f64::MAX;
|
||
|
|
let mut best_code = String::new();
|
||
|
|
let mut best_params = (0, 0.0, 0.0);
|
||
|
|
|
||
|
|
// Grid search in Rust
|
||
|
|
for blur in vec![2, 4, 6, 8, 10, 12] {
|
||
|
|
for hl_scale in vec![0.5, 1.0, 1.5, 2.0, 2.5, 3.0] {
|
||
|
|
for sh_scale in vec![1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0] {
|
||
|
|
// Generate patched code
|
||
|
|
let code_patch = format!(
|
||
|
|
r#" // 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);
|
||
|
|
|
||
|
|
highlight_buf[i * 4 + 3] = (alpha[i] as f32 * hl_pred).round() as u8;
|
||
|
|
shadow_buf[i * 4 + 3] = (alpha[i] as f32 * sh_pred).round() as u8;
|
||
|
|
}}
|
||
|
|
// END_TUNING_ZONE"#,
|
||
|
|
blur, hl_scale, sh_scale
|
||
|
|
);
|
||
|
|
|
||
|
|
// Replace tuning zone
|
||
|
|
let start_tag = " // BEGIN_TUNING_ZONE";
|
||
|
|
let end_tag = " // END_TUNING_ZONE";
|
||
|
|
if let (Some(start_idx), Some(end_idx)) = (original.find(start_tag), original.find(end_tag)) {
|
||
|
|
let mut new_content = String::new();
|
||
|
|
new_content.push_str(&original[..start_idx]);
|
||
|
|
new_content.push_str(&code_patch);
|
||
|
|
new_content.push_str(&original[end_idx + end_tag.len()..]);
|
||
|
|
|
||
|
|
std::fs::write(SHADOW_RS, &new_content).expect("write shadow.rs");
|
||
|
|
|
||
|
|
let mae = measure_layer2_mae();
|
||
|
|
println!("blur={}, hl_scale={:.1}, sh_scale={:.1} => MAE={:.4}", blur, hl_scale, sh_scale, mae);
|
||
|
|
|
||
|
|
if mae < best_mae {
|
||
|
|
best_mae = mae;
|
||
|
|
best_code = new_content.clone();
|
||
|
|
best_params = (blur, hl_scale, sh_scale);
|
||
|
|
println!("*** NEW BEST: {:.4} (params: {:?})", best_mae, best_params);
|
||
|
|
// Save immediately so intermediate progress is preserved
|
||
|
|
std::fs::write(SHADOW_RS, &best_code).expect("write best");
|
||
|
|
|
||
|
|
// Update sultan_results.txt to show the best results of all layers
|
||
|
|
let _ = std::fs::copy("sultan_results_temp.txt", "sultan_results.txt");
|
||
|
|
if let Ok(mut file) = std::fs::OpenOptions::new().append(true).open("sultan_results.txt") {
|
||
|
|
let _ = writeln!(file, "\n=== Best Bevel/Emboss Tuned (So Far) ===\n Params: blur={}, hl_scale={:.1}, sh_scale={:.1}\n MAE: {:.4}", blur, hl_scale, sh_scale, mae);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if best_mae < f64::MAX {
|
||
|
|
println!("Completed. Best code saved with MAE = {:.4} (params: {:?})", best_mae, best_params);
|
||
|
|
let _ = std::fs::remove_file("sultan_results_temp.txt");
|
||
|
|
} else {
|
||
|
|
std::fs::write(SHADOW_RS, &original).expect("restore original");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn measure_layer2_mae() -> f64 {
|
||
|
|
let output = std::process::Command::new("cargo")
|
||
|
|
.args(["run", "-p", "hcie-io", "--example", "test_sultan", "-q"])
|
||
|
|
.env("SULTAN_RESULTS_FILE", "sultan_results_temp.txt")
|
||
|
|
.output()
|
||
|
|
.expect("run test_sultan");
|
||
|
|
|
||
|
|
if !output.status.success() {
|
||
|
|
return f64::MAX;
|
||
|
|
}
|
||
|
|
|
||
|
|
let results = std::fs::read_to_string("sultan_results_temp.txt").expect("read results");
|
||
|
|
let lines: Vec<&str> = results.lines().collect();
|
||
|
|
for i in 0..lines.len() {
|
||
|
|
if lines[i].contains("Layer 2.psd") {
|
||
|
|
for j in i+1..lines.len() {
|
||
|
|
if lines[j].starts_with(" Avg diff per channel:") {
|
||
|
|
let value = lines[j].trim_start_matches(" Avg diff per channel:").trim();
|
||
|
|
return value.parse::<f64>().unwrap_or(f64::MAX) / 4.0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
f64::MAX
|
||
|
|
}
|