2026-07-09 02:59:53 +03:00
|
|
|
//! Automated visual check for the Meadow brush.
|
|
|
|
|
//!
|
|
|
|
|
//! Purpose: Renders several Meadow strokes onto a transparent canvas using the
|
|
|
|
|
//! public engine API and saves the result as a PNG. This bypasses the GUI so
|
|
|
|
|
//! brush behaviour can be inspected directly, and doubles as a regression
|
|
|
|
|
//! guard for color-variant and blade geometry.
|
|
|
|
|
//!
|
|
|
|
|
//! Logic & Workflow:
|
|
|
|
|
//! 1. Create a 512x512 white/opaque canvas.
|
|
|
|
|
//! 2. Configure a Meadow brush with color_variant enabled and a green base color.
|
|
|
|
|
//! 3. Draw multiple short strokes at different positions.
|
|
|
|
|
//! 4. Save the composited pixels to `target/meadow_check.png`.
|
|
|
|
|
|
2026-07-16 22:10:22 +03:00
|
|
|
use hcie_engine_api::{BrushStyle, BrushTip, Engine};
|
2026-07-09 02:59:53 +03:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "manual visual check: run with --ignored --test meadow_check and inspect target/meadow_check.png"]
|
|
|
|
|
fn meadow_brush_visual_check() {
|
|
|
|
|
let mut engine = Engine::new_with_options("MeadowCheck", 512, 512, false);
|
|
|
|
|
let layer_id = engine.active_layer_id();
|
|
|
|
|
|
|
|
|
|
let mut tip = BrushTip::default();
|
|
|
|
|
tip.style = BrushStyle::Meadow;
|
|
|
|
|
tip.size = 80.0;
|
|
|
|
|
tip.opacity = 0.95;
|
|
|
|
|
tip.hardness = 0.85;
|
|
|
|
|
tip.spacing = 0.40;
|
|
|
|
|
tip.color_variant = true;
|
|
|
|
|
tip.variant_amount = 0.6;
|
|
|
|
|
engine.set_brush_tip(tip);
|
|
|
|
|
engine.set_color([50, 200, 80, 255]);
|
|
|
|
|
|
|
|
|
|
// Stroke 1: a short wavy tuft.
|
|
|
|
|
engine.begin_stroke(layer_id, 150.0, 400.0);
|
|
|
|
|
for i in 0..=30 {
|
|
|
|
|
let t = i as f32 / 30.0;
|
|
|
|
|
let x = 100.0 + t * 120.0;
|
|
|
|
|
let y = 400.0 - (t * 60.0).sin() * 25.0 - t * 40.0;
|
|
|
|
|
engine.stroke_to(layer_id, x, y, 0.6 + 0.4 * (1.0 - t));
|
|
|
|
|
}
|
|
|
|
|
engine.end_stroke(layer_id);
|
|
|
|
|
|
|
|
|
|
// Stroke 2: vertical grass clump.
|
|
|
|
|
engine.begin_stroke(layer_id, 300.0, 420.0);
|
|
|
|
|
for i in 0..=25 {
|
|
|
|
|
let t = i as f32 / 25.0;
|
|
|
|
|
let x = 300.0 + t * 10.0;
|
|
|
|
|
let y = 420.0 - t * 90.0;
|
|
|
|
|
engine.stroke_to(layer_id, x, y, 1.0);
|
|
|
|
|
}
|
|
|
|
|
engine.end_stroke(layer_id);
|
|
|
|
|
|
|
|
|
|
// Stroke 3: a few scattered dabs.
|
|
|
|
|
engine.begin_stroke(layer_id, 420.0, 410.0);
|
|
|
|
|
engine.stroke_to(layer_id, 430.0, 360.0, 1.0);
|
|
|
|
|
engine.stroke_to(layer_id, 440.0, 320.0, 0.8);
|
|
|
|
|
engine.stroke_to(layer_id, 450.0, 300.0, 0.6);
|
|
|
|
|
engine.end_stroke(layer_id);
|
|
|
|
|
|
|
|
|
|
let pixels = engine.get_composite_pixels();
|
|
|
|
|
let mut output_layer = hcie_protocol::Layer::new_transparent("", 512, 512);
|
|
|
|
|
output_layer.pixels = pixels.clone();
|
2026-07-16 22:10:22 +03:00
|
|
|
let out_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
|
|
|
.parent()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.join("target");
|
2026-07-09 02:59:53 +03:00
|
|
|
std::fs::create_dir_all(&out_dir).unwrap();
|
|
|
|
|
let path = out_dir.join("meadow_check.png");
|
|
|
|
|
hcie_engine_api::dynamic_loader::save_image(&output_layer, &path, "png").expect("save png");
|
|
|
|
|
|
|
|
|
|
// Basic sanity: output should contain non-white, non-transparent pixels.
|
2026-07-16 22:10:22 +03:00
|
|
|
let has_color = pixels
|
|
|
|
|
.chunks_exact(4)
|
|
|
|
|
.any(|p| p[3] > 0 && (p[0] != 255 || p[1] != 255 || p[2] != 255));
|
2026-07-09 02:59:53 +03:00
|
|
|
assert!(has_color, "Meadow check produced no colored pixels");
|
|
|
|
|
}
|