#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct CrtWarpEffectConfig {
pub k1: f32,
pub k2: f32,
pub corner_radius: f32,
pub vignette: f32,
pub curvature: f32,
pub enabled: bool,
}
impl Default for CrtWarpEffectConfig {
fn default() -> Self {
Self {
k1: 0.1,
k2: 0.02,
corner_radius: 0.05,
vignette: 0.4,
curvature: 0.3,
enabled: true,
}
}
}
#[allow(dead_code)]
pub fn new_crt_warp_effect_config() -> CrtWarpEffectConfig {
CrtWarpEffectConfig::default()
}
#[allow(dead_code)]
pub fn cw_set_k1(cfg: &mut CrtWarpEffectConfig, v: f32) {
cfg.k1 = v.clamp(-0.5, 0.5);
}
#[allow(dead_code)]
pub fn cw_set_k2(cfg: &mut CrtWarpEffectConfig, v: f32) {
cfg.k2 = v.clamp(-0.5, 0.5);
}
#[allow(dead_code)]
pub fn cw_set_vignette(cfg: &mut CrtWarpEffectConfig, v: f32) {
cfg.vignette = v.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn cw_set_curvature(cfg: &mut CrtWarpEffectConfig, v: f32) {
cfg.curvature = v.clamp(0.0, 1.0);
}
#[allow(dead_code)]
pub fn cw_distort_uv(uv: [f32; 2], cfg: &CrtWarpEffectConfig) -> [f32; 2] {
if !cfg.enabled {
return uv;
}
let r2 = uv[0] * uv[0] + uv[1] * uv[1];
let factor = 1.0 + cfg.k1 * r2 + cfg.k2 * r2 * r2;
[uv[0] * factor, uv[1] * factor]
}
#[allow(dead_code)]
pub fn cw_vignette_at(uv: [f32; 2], cfg: &CrtWarpEffectConfig) -> f32 {
let r = (uv[0] * uv[0] + uv[1] * uv[1]).sqrt();
let dark = r * r * cfg.vignette;
(1.0 - dark).clamp(0.0, 1.0)
}
#[allow(dead_code)]
pub fn cw_is_visible(distorted_uv: [f32; 2]) -> bool {
distorted_uv[0].abs() <= 0.5 && distorted_uv[1].abs() <= 0.5
}
#[allow(dead_code)]
pub fn cw_corner_distortion(cfg: &CrtWarpEffectConfig) -> f32 {
let uv = [0.5_f32, 0.5_f32];
let d = cw_distort_uv(uv, cfg);
let dx = d[0] - uv[0];
let dy = d[1] - uv[1];
(dx * dx + dy * dy).sqrt()
}
#[allow(dead_code)]
pub fn cw_to_json(cfg: &CrtWarpEffectConfig) -> String {
format!(
"{{\"k1\":{:.4},\"k2\":{:.4},\"vignette\":{:.3},\"curvature\":{:.3},\"enabled\":{}}}",
cfg.k1, cfg.k2, cfg.vignette, cfg.curvature, cfg.enabled
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn disabled_returns_identity() {
let mut cfg = new_crt_warp_effect_config();
cfg.enabled = false;
let uv = [0.3_f32, 0.2_f32];
let d = cw_distort_uv(uv, &cfg);
assert!((d[0] - uv[0]).abs() < 1e-6 && (d[1] - uv[1]).abs() < 1e-6);
}
#[test]
fn positive_k1_expands() {
let mut cfg = new_crt_warp_effect_config();
cfg.k1 = 0.2;
let d = cw_distort_uv([0.4, 0.0], &cfg);
assert!(d[0] > 0.4);
}
#[test]
fn negative_k1_contracts() {
let mut cfg = new_crt_warp_effect_config();
cfg.k1 = -0.2;
let d = cw_distort_uv([0.4, 0.0], &cfg);
assert!(d[0] < 0.4);
}
#[test]
fn vignette_at_center_one() {
let cfg = new_crt_warp_effect_config();
let v = cw_vignette_at([0.0, 0.0], &cfg);
assert!((v - 1.0).abs() < 1e-5);
}
#[test]
fn vignette_at_edge_less_than_center() {
let cfg = new_crt_warp_effect_config();
let center = cw_vignette_at([0.0, 0.0], &cfg);
let edge = cw_vignette_at([0.7, 0.7], &cfg);
assert!(edge <= center);
}
#[test]
fn k1_clamps() {
let mut cfg = new_crt_warp_effect_config();
cw_set_k1(&mut cfg, 5.0);
assert!((cfg.k1 - 0.5).abs() < 1e-6);
}
#[test]
fn vignette_clamps() {
let mut cfg = new_crt_warp_effect_config();
cw_set_vignette(&mut cfg, 5.0);
assert!((cfg.vignette - 1.0).abs() < 1e-6);
}
#[test]
fn corner_distortion_nonnegative() {
let cfg = new_crt_warp_effect_config();
assert!(cw_corner_distortion(&cfg) >= 0.0);
}
#[test]
fn center_uv_visible() {
assert!(cw_is_visible([0.0, 0.0]));
}
#[test]
fn json_has_keys() {
let j = cw_to_json(&new_crt_warp_effect_config());
assert!(j.contains("k1") && j.contains("enabled"));
}
}