photonic_effects/nodes/
alert.rs1use std::ops::Neg;
2
3use anyhow::Result;
4use palette::Hsv;
5
6use photonic::{math, Attr, BoundAttrDecl, Buffer, FreeAttrDecl, Node, NodeBuilder, NodeDecl, RenderContext};
7
8pub struct Alert<Hue, Block, Speed> {
9 pub hue: Hue,
10 pub block: Block,
11 pub speed: Speed,
12}
13
14pub struct AlertNode<Hue, Block, Speed> {
15 hue: Hue,
16 block: Block,
17 speed: Speed,
18
19 time: f32,
20}
21
22impl<Hue, Block, Speed> NodeDecl for Alert<Hue, Block, Speed>
23where
24 Hue: BoundAttrDecl<f32>,
25 Block: BoundAttrDecl<i64>,
26 Speed: FreeAttrDecl<f32>, {
28 const KIND: &'static str = "alert";
29
30 type Node = AlertNode<Hue::Attr, Block::Attr, Speed::Attr>;
31
32 async fn materialize(self, builder: &mut NodeBuilder<'_>) -> Result<Self::Node> {
33 return Ok(Self::Node {
34 hue: builder.bound_attr("hue", self.hue, (0.0, 360.0))?,
35 block: builder.bound_attr("block", self.block, (0, builder.size as i64))?,
36 speed: builder.unbound_attr("speed", self.speed)?,
37
38 time: 0.0,
39 });
40 }
41}
42
43impl<Hue, Block, Speed> Node for AlertNode<Hue, Block, Speed>
44where
45 Hue: Attr<f32>,
46 Block: Attr<i64>,
47 Speed: Attr<f32>,
48{
49 type Element = Hsv;
50
51 fn update(&mut self, ctx: &RenderContext, out: &mut Buffer<Self::Element>) -> Result<()> {
52 let hue = self.hue.update(ctx);
53 let block = self.block.update(ctx);
54 let speed = self.speed.update(ctx);
55
56 self.time += ctx.duration.as_secs_f32() / speed;
57 self.time %= 2.0;
58
59 let value = math::clamp(f32::sin(self.time * std::f32::consts::PI), (-1.0, 1.0));
60
61 out.update(|i, _| {
62 let x = (i / block as usize) % 2 == 0;
63
64 return Hsv::new(hue, 1.0, if x { value } else { value.neg() }.max(0.0));
65 });
66
67 return Ok(());
68 }
69}
70
71#[cfg(feature = "dynamic")]
72pub mod dynamic {
73 use palette::rgb::Rgb;
74 use serde::Deserialize;
75
76 use photonic::boxed::{BoxedBoundAttrDecl, BoxedFreeAttrDecl, DynNodeDecl};
77 use photonic_dynamic::factory::Producible;
78 use photonic_dynamic::registry::Registry;
79 use photonic_dynamic::{builder, config};
80
81 use super::*;
82
83 #[derive(Deserialize, Debug)]
84 pub struct Config {
85 pub hue: config::Attr<f32>,
86 pub block: config::Attr<i64>,
87 pub speed: config::Attr<f32>,
88 }
89
90 impl Producible<dyn DynNodeDecl<Rgb>> for Config {
91 type Product = Alert<BoxedBoundAttrDecl<f32>, BoxedBoundAttrDecl<i64>, BoxedFreeAttrDecl<f32>>;
92
93 fn produce<Reg: Registry>(config: Self, mut builder: builder::NodeBuilder<'_, Reg>) -> Result<Self::Product> {
94 return Ok(Alert {
95 hue: builder.bound_attr("hue", config.hue)?,
96 block: builder.bound_attr("block", config.block)?,
97 speed: builder.free_attr("speed", config.speed)?,
98 });
99 }
100 }
101}