Files

219 lines
9.1 KiB
Rust
Raw Permalink Normal View History

2026-07-09 02:59:53 +03:00
/// Generate an expanded Bevel & Emboss PSD set for ground-truth MAE tuning.
///
/// Includes more shapes and OuterBevel in addition to InnerBevel/Emboss.
/// Technique is kept as Smooth for the main set; ChiselHard/ChiselSoft can be
/// generated separately if needed.
///
/// Shapes: rect, circle, triangle, star, L, T
/// Styles: InnerBevel, Emboss, OuterBevel
/// Output: `_tmp/bevel_emboss_psd_set/`
use hcie_protocol::{Layer, LayerType, LayerData, BlendMode, effects::{LayerEffect, BevelStyle, Technique, Direction}};
use std::sync::atomic::{AtomicBool};
use std::sync::Mutex;
fn make_shape(shape: &str, canvas: u32) -> Vec<u8> {
let mut pixels = vec![0u8; (canvas * canvas * 4) as usize];
let cx = canvas / 2;
let cy = canvas / 2;
for y in 0..canvas {
for x in 0..canvas {
let i = (y * canvas + x) as usize * 4;
let inside = match shape {
"rect" => {
x >= 64 && x < canvas - 64 && y >= 64 && y < canvas - 64
}
"tall" => {
x >= 96 && x < canvas - 96 && y >= 32 && y < canvas - 32
}
"wide" => {
x >= 32 && x < canvas - 32 && y >= 96 && y < canvas - 96
}
"circle" => {
let dx = x as f32 - cx as f32;
let dy = y as f32 - cy as f32;
let r = (canvas / 2 - 64) as f32;
(dx * dx + dy * dy).sqrt() <= r
}
"triangle" => {
let dx = (x as i32 - cx as i32).abs();
let top = 64i32;
let bottom = (canvas - 64) as i32;
if (y as i32) < top || (y as i32) > bottom { false } else {
let y_span = ((y as i32) - top) as f32 / (bottom - top) as f32;
let half_width_at_y = (canvas - 128) as f32 / 2.0 * (1.0 - y_span);
(dx as f32) <= half_width_at_y
}
}
"star" => {
let dx = x as f32 - cx as f32;
let dy = y as f32 - cy as f32;
let r = (dx * dx + dy * dy).sqrt();
if r > 96.0 || r < 20.0 { false } else {
let angle = dy.atan2(dx);
let points = 5.0f32;
let sector = (angle * points).cos();
let limit = 64.0 + sector * 32.0;
r <= limit
}
}
"L" => {
(x >= 64 && x < 96 && y >= 64 && y < canvas - 64)
|| (x >= 64 && x < canvas - 64 && y >= canvas - 96 && y < canvas - 64)
}
"T" => {
(y >= 64 && y < 96 && x >= 64 && x < canvas - 64)
|| (x >= 112 && x < 144 && y >= 64 && y < canvas - 64)
}
"cross" => {
(x >= 112 && x < 144 && y >= 48 && y < canvas - 48)
|| (y >= 112 && y < 144 && x >= 48 && x < canvas - 48)
}
_ => false,
};
if inside {
pixels[i] = 0;
pixels[i + 1] = 0;
pixels[i + 2] = 0;
pixels[i + 3] = 255;
}
}
}
pixels
}
fn main() {
let out_dir = std::path::Path::new("_tmp/bevel_emboss_psd_set");
std::fs::create_dir_all(out_dir).expect("create output dir");
let canvas: u32 = 256;
let shapes: &[(&str, &str)] = &[
("rect", "rect"),
("circle", "circle"),
("triangle", "triangle"),
("star", "star"),
("L", "L"),
("T", "T"),
];
let styles: &[(BevelStyle, &str)] = &[
(BevelStyle::InnerBevel, "inner"),
(BevelStyle::Emboss, "emboss"),
(BevelStyle::OuterBevel, "outer"),
];
let techniques: &[(Technique, &str)] = &[
(Technique::Smooth, "smooth"),
];
let depths: &[f32] = &[50.0, 100.0, 200.0];
let sizes: &[f32] = &[10.0, 25.0];
let softens: &[f32] = &[0.0, 5.0];
let directions: &[(Direction, &str)] = &[
(Direction::Up, "up"),
(Direction::Down, "down"),
];
let altitudes: &[f32] = &[30.0, 60.0];
let total = shapes.len() * styles.len() * techniques.len() * depths.len()
* sizes.len() * softens.len() * directions.len() * altitudes.len();
println!("Generating {} bevel & emboss PSDs...", total);
let mut count = 0usize;
let mut errors = 0usize;
for &(shape_name, shape_tag) in shapes {
for &(style, style_tag) in styles {
for &(technique, tech_tag) in techniques {
for &depth in depths {
for &size in sizes {
for &soften in softens {
for &(direction, dir_tag) in directions {
for &altitude in altitudes {
count += 1;
let filename = format!(
"be_{}_{}_d{}_sz{}_sf{}_{}_alt{}_{}.psd",
shape_tag, style_tag,
depth as u32, size as u32,
soften as u32, dir_tag,
altitude as u32,
tech_tag
);
let path = out_dir.join(&filename);
if path.exists() {
continue;
}
let pixels = make_shape(shape_name, canvas);
let effect = LayerEffect::BevelEmboss {
enabled: true,
style,
technique,
depth,
direction,
size,
soften,
angle: 120.0,
altitude,
highlight_blend: "screen".to_string(),
highlight_color: [255, 255, 255, 255],
highlight_opacity: 1.0,
shadow_blend: "multiply".to_string(),
shadow_color: [0, 0, 0, 255],
shadow_opacity: 1.0,
contour: None,
};
let layer = Layer {
name: "shape".to_string(),
layer_type: LayerType::Raster,
data: LayerData::Raster,
pixels: pixels.clone(),
width: canvas,
height: canvas,
visible: true,
opacity: 1.0,
blend_mode: BlendMode::Normal,
locked: false,
dirty: false,
id: 1,
parent_id: None,
styles: vec![],
clipping_mask: false,
collapsed: false,
adjustment: None,
mask_pixels: None,
mask_bounds: None,
mask_default_color: 0,
curve_points: vec![],
fill_opacity: 1.0,
effects: vec![effect],
effects_dirty: AtomicBool::new(false),
effects_cache: Mutex::new(None),
adjustment_raw: None,
is_section_divider: false,
image_resources_raw: None,
};
match hcie_psd::save_psd(&[layer], canvas, canvas, &pixels, &path) {
Ok(()) => {}
Err(e) => {
eprintln!(" ERROR {}: {}", filename, e);
errors += 1;
}
}
if count % 20 == 0 {
println!(" [{}/{}] errors={}", count, total, errors);
}
}
}
}
}
}
}
}
}
println!("Done. {} PSDs generated, {} errors.", count - errors, errors);
}