1use alloc::vec;
13use alloc::vec::Vec;
14
15use gfx::blendmode::{bm_row, BM_NORMAL, BM_OPAC_SHIFT};
16use rt::fx::cvtd;
17
18use crate::conv::*;
19use crate::*;
20
21struct Shadow<'d, 'e, 's> {
22 dst: &'d mut Dst<'e>,
23 a: &'s FxArgs<'s>,
24 ox: i32,
25 oy: i32,
26 rgb: u32,
27 k: u32,
28 only: bool,
29 tmp: Vec<u8>,
30}
31
32impl SepIo for Shadow<'_, '_, '_> {
33 fn load(&mut self, sep: &Sep, w16: &mut [i16], y: i32, x0: i32, x1: i32) {
35 load_row(w16, sep.src, y - self.oy, x0 - self.ox, x1 - self.ox, FXL_ZERO);
36 }
37
38 fn emit(&mut self, sep: &Sep, y: i32, row: &[i16]) {
40 let n = (sep.x1 - sep.x0) as usize;
41 for i in 0..n {
42 let s = (row[i * 4 + 3] as i32).clamp(0, 16320) as u32;
43 let al = (s.wrapping_mul(self.k).wrapping_add(816000)) / 1632000;
44 put(&mut self.tmp, i, al << 24 | self.rgb);
45 }
46 let d = dst_px(self.dst, y, sep.x0, n as i32);
47 if self.only {
48 d.copy_from_slice(&self.tmp[..n * 4]);
49 } else {
50 let s = &self.a.src_row(y)[sep.x0 as usize * 4..sep.x1 as usize * 4];
51 bm_row(d, &self.tmp[..n * 4], s, BM_NORMAL | 255 << BM_OPAC_SHIFT);
52 }
53 }
54}
55
56fn shadow_render(a: &FxArgs, dst: &mut Dst) -> i32 {
57 let col = a.params.0[0] as u32;
58 let k = pint(a, 4, 0, 100) as u32 * (col >> 24);
59 let only = pint(a, 5, 0, 1) != 0;
60 let (s, c) = gfx::xform::sincos(pdbl(a, 1) * 0.017453292519943295);
61 let d = pint(a, 2, 0, 100) as f64;
62 let ox = cvtd(c * d);
63 let oy = cvtd(s * d);
64 let kern = Kern::gauss(var12(pint(a, 3, 0, 100)));
65 let Some(mut sep) = Sep::new(a, &kern) else {
66 return 0;
67 };
68 sep.custom_load = true;
69 let n = (sep.x1 - sep.x0) as usize;
70 let mut io = Shadow { dst, a, ox, oy, rgb: col & 0x00FF_FFFF, k, only, tmp: vec![0u8; n * 4 + 64] };
71 sep_run(&sep, &mut io)
72}
73
74static P_SHADOW: [FxProp; 6] = [
75 FxProp::color(0, "color", 0xFF00_0000),
76 FxProp::new(FP_ANGLE, 2, 1, 0, "angle", -180.0, 180.0, 45.0),
77 FxProp::new(FP_INT, 0, 2, 0, "distance", 0.0, 100.0, 10.0),
78 FxProp::new(FP_INT, 0, 3, 0, "blur_radius", 0.0, 100.0, 10.0),
79 FxProp::new(FP_INT, 0, 4, 0, "opacity", 0.0, 100.0, 50.0),
80 FxProp::new(FP_BOOL, 0, 5, 0, "shadow_only", 0.0, 1.0, 0.0),
81];
82
83pub static FXTAB: [FxDesc; 1] = [FxDesc {
85 id: FX_DROP_SHADOW,
86 flags: 0,
87 name: "drop_shadow",
88 prepare: None,
89 render: shadow_render,
90 props: &P_SHADOW,
91 category: FXC_OBJECT,
92 user: 0,
93}];