Files
hcie-rust-v3.05/hcie-blend/examples/blend_tester.rs
2026-07-09 02:59:53 +03:00

215 lines
7.8 KiB
Rust

#![allow(deprecated)]
//! Visual test GUI for the decoupled `hcie-blend` library using `egui`.
//! Compiles only when running `cargo run --example blend_tester`.
use eframe::egui;
use hcie_blend::blend_buffers;
fn main() -> eframe::Result {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([600.0, 400.0])
.with_title("HCIE Blend Engine Visual Tester"),
..Default::default()
};
eframe::run_native(
"HCIE Blend Visual Tester",
options,
Box::new(|cc| Ok(Box::new(BlendTesterApp::new(cc)))),
)
}
struct BlendTesterApp {
background: Vec<u8>,
foreground: Vec<u8>,
blended: Vec<u8>,
width: u32,
height: u32,
opacity: f32,
blend_mode: i32,
texture: Option<egui::TextureHandle>,
}
impl BlendTesterApp {
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
let width = 256;
let height = 256;
let len = (width * height * 4) as usize;
// Generate background: Checkerboard (White / Light Gray)
let mut background = vec![0u8; len];
for y in 0..height {
for x in 0..width {
let i = ((y * width + x) * 4) as usize;
let is_gray = ((x / 16) + (y / 16)) % 2 == 0;
let c = if is_gray { 200 } else { 255 };
background[i] = c;
background[i + 1] = c;
background[i + 2] = c;
background[i + 3] = 255;
}
}
// Generate foreground: A soft-edged red circle in the center
let mut foreground = vec![0u8; len];
let cx = width as f32 / 2.0;
let cy = height as f32 / 2.0;
let r = 80.0;
for y in 0..height {
for x in 0..width {
let i = ((y * width + x) * 4) as usize;
let dx = x as f32 - cx;
let dy = y as f32 - cy;
let dist = (dx * dx + dy * dy).sqrt();
// Soft edge alpha transition
let alpha = if dist < r - 10.0 {
255
} else if dist < r + 10.0 {
(((r + 10.0 - dist) / 20.0) * 255.0) as u8
} else {
0
};
foreground[i] = 255; // Red
foreground[i + 1] = 50; // Orange-ish tint
foreground[i + 2] = 50;
foreground[i + 3] = alpha;
}
}
let blended = background.clone();
let mut app = Self {
background,
foreground,
blended,
width,
height,
opacity: 1.0,
blend_mode: 0, // Normal
texture: None,
};
app.update_blended();
app
}
fn update_blended(&mut self) {
// Reset blended buffer to background first
self.blended.copy_from_slice(&self.background);
// Run the blending function
let mode = match self.blend_mode {
0 => hcie_blend::BlendMode::Normal,
1 => hcie_blend::BlendMode::Dissolve,
2 => hcie_blend::BlendMode::Darken,
3 => hcie_blend::BlendMode::Multiply,
4 => hcie_blend::BlendMode::ColorBurn,
5 => hcie_blend::BlendMode::LinearBurn,
6 => hcie_blend::BlendMode::DarkerColor,
7 => hcie_blend::BlendMode::Lighten,
8 => hcie_blend::BlendMode::Screen,
9 => hcie_blend::BlendMode::ColorDodge,
10 => hcie_blend::BlendMode::LinearDodge,
11 => hcie_blend::BlendMode::LighterColor,
12 => hcie_blend::BlendMode::Overlay,
13 => hcie_blend::BlendMode::SoftLight,
14 => hcie_blend::BlendMode::HardLight,
15 => hcie_blend::BlendMode::VividLight,
16 => hcie_blend::BlendMode::LinearLight,
17 => hcie_blend::BlendMode::PinLight,
18 => hcie_blend::BlendMode::HardMix,
19 => hcie_blend::BlendMode::Difference,
20 => hcie_blend::BlendMode::Exclusion,
21 => hcie_blend::BlendMode::Subtract,
22 => hcie_blend::BlendMode::Divide,
23 => hcie_blend::BlendMode::Hue,
24 => hcie_blend::BlendMode::Saturation,
25 => hcie_blend::BlendMode::Color,
26 => hcie_blend::BlendMode::Luminosity,
_ => hcie_blend::BlendMode::Normal,
};
blend_buffers(
&mut self.blended,
&self.foreground,
mode,
self.opacity,
);
self.texture = None; // Invalidate texture to force reload
}
}
impl eframe::App for BlendTesterApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
let ctx = ui.ctx().clone();
let modes = [
(0, "Normal"), (1, "Dissolve"), (2, "Darken"), (3, "Multiply"),
(4, "Color Burn"), (5, "Linear Burn"), (6, "Darker Color"),
(7, "Lighten"), (8, "Screen"), (9, "Color Dodge"), (10, "Linear Dodge"),
(11, "Lighter Color"), (12, "Overlay"), (13, "Soft Light"), (14, "Hard Light"),
(15, "Vivid Light"), (16, "Linear Light"), (17, "Pin Light"), (18, "Hard Mix"),
(19, "Difference"), (20, "Exclusion"), (21, "Subtract"), (22, "Divide"),
(23, "Hue"), (24, "Saturation"), (25, "Color"), (26, "Luminosity"),
];
// Ensure texture is loaded
if self.texture.is_none() {
let color_image = egui::ColorImage::from_rgba_unmultiplied(
[self.width as usize, self.height as usize],
&self.blended,
);
self.texture = Some(ctx.load_texture("blended_preview", color_image, Default::default()));
}
let texture = self.texture.as_ref().unwrap().clone();
egui::CentralPanel::default().show(&ctx, |ui| {
ui.heading("HCIE Blend Engine Visual Tester");
ui.add_space(10.0);
ui.horizontal(|ui| {
// Left Column: Preview Canvas
ui.vertical(|ui| {
ui.image((texture.id(), texture.size_vec2()));
});
ui.add_space(20.0);
// Right Column: Controls
ui.vertical(|ui| {
let mut changed = false;
// Blend Mode Selection
ui.label("Blend Mode:");
let current_label = modes.iter().find(|m| m.0 == self.blend_mode).map(|m| m.1).unwrap_or("Normal");
egui::ComboBox::from_id_source("blend_mode_select")
.selected_text(current_label)
.show_ui(ui, |ui| {
for &(val, label) in &modes {
if ui.selectable_value(&mut self.blend_mode, val, label).clicked() {
changed = true;
}
}
});
ui.add_space(15.0);
// Opacity Slider
ui.label(format!("Opacity: {:.2}", self.opacity));
if ui.add(egui::Slider::new(&mut self.opacity, 0.0..=1.0)).changed() {
changed = true;
}
if changed {
self.update_blended();
}
ui.add_space(30.0);
ui.colored_label(egui::Color32::LIGHT_GREEN, "✓ Decoupled from hcie-protocol");
ui.colored_label(egui::Color32::LIGHT_GREEN, "✓ Compiles as a dynamic C FFI library");
ui.colored_label(egui::Color32::LIGHT_GREEN, "✓ Operating with parallel Rayon logic");
});
});
});
}
}