b09795ccff
- Add `persistence.rs` for stable serialization of dock layouts without runtime identifiers. - Introduce `preview.rs` for geometry handling of dock drop previews. - Create `sizing.rs` to manage content-aware sizing policies and constraint solving for dock panels. - Implement `welcome.rs` to provide a welcome surface when no documents are open, featuring New and Open actions.
367 lines
12 KiB
Rust
367 lines
12 KiB
Rust
#![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<u8> = 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<i32> = (bb - 4..=bb + 4).filter(|&v| v > 0).collect();
|
|
let fine_hl: Vec<f32> = ((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<f32> = ((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::<f64>();
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|