bevy_react/filters/builtin/
pixelize.rs1use std::sync::Arc;
8
9use bevy::asset::load_embedded_asset;
10use bevy::prelude::*;
11use bevy::shader::Shader;
12use serde::Deserialize;
13
14use crate::animations::ValueKind;
15use crate::filters::params::{ParamSlot, static_layout};
16use crate::filters::registry::{ReactFilter, ReactMorphFilter};
17
18fn default_squares_min() -> [f32; 2] {
19 [20.0, 20.0]
20}
21
22fn default_steps() -> f32 {
23 50.0
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Deserialize, ts_rs::TS)]
34#[serde(deny_unknown_fields)]
35pub struct PixelizeParams {
36 #[serde(default = "default_squares_min", rename = "squaresMin")]
38 pub squares_min: [f32; 2],
39 #[serde(default = "default_steps")]
41 pub steps: f32,
42}
43
44impl Default for PixelizeParams {
45 fn default() -> Self {
46 Self {
47 squares_min: default_squares_min(),
48 steps: default_steps(),
49 }
50 }
51}
52
53fn pixelize_layout() -> Arc<[ParamSlot]> {
54 static_layout![
55 ParamSlot {
56 name: "squaresMin",
57 kind: ValueKind::Scalar,
58 vec: 0,
59 comp: 0,
60 len: 2,
61 },
62 ParamSlot {
63 name: "steps",
64 kind: ValueKind::Scalar,
65 vec: 0,
66 comp: 2,
67 len: 1,
68 },
69 ]
70}
71
72impl ReactFilter for PixelizeParams {
73 const NAME: &'static str = "pixelize";
74 const IS_MORPH: bool = true;
75
76 fn shader(assets: &AssetServer) -> Handle<Shader> {
77 load_embedded_asset!(assets, "pixelize.wgsl")
78 }
79
80 fn outset(&self) -> Result<f32, String> {
82 Ok(0.0)
83 }
84
85 fn pack(&self) -> (Vec<Vec4>, Arc<[ParamSlot]>) {
86 (
87 vec![Vec4::new(
88 self.squares_min[0],
89 self.squares_min[1],
90 self.steps,
91 0.0,
92 )],
93 pixelize_layout(),
94 )
95 }
96}
97
98impl ReactMorphFilter for PixelizeParams {}
99
100#[cfg(test)]
101mod tests {
102 use serde_json::json;
103
104 use super::*;
105 use crate::filters::test_util::{asset_app, params};
106
107 #[test]
110 fn pixelize_resolves_to_single_zero_outset_pass() {
111 let app = asset_app();
112 let assets = app.world().resource::<AssetServer>();
113
114 let passes = params::<PixelizeParams>(json!({}))
115 .resolve(assets)
116 .expect("pixelize resolves");
117 assert_eq!(passes.len(), 1);
118 assert_eq!(passes[0].params[0], Vec4::new(20.0, 20.0, 50.0, 0.0));
119 assert!(passes[0].params.len() <= crate::filters::MORPH_MAX_USER_PARAM_VECS);
120 assert_eq!(params::<PixelizeParams>(json!({})).outset(), Ok(0.0));
121
122 let p = params::<PixelizeParams>(json!({ "squaresMin": [8, 4], "steps": 0 }));
123 assert_eq!(p.pack().0[0], Vec4::new(8.0, 4.0, 0.0, 0.0));
124 assert_eq!(p.pack().1[0].name, "squaresMin");
125 assert_eq!(p.pack().1[1].name, "steps");
126 }
127
128 #[test]
131 fn unknown_pixelize_params_reject() {
132 assert!(
133 serde_json::from_value::<PixelizeParams>(json!({ "squares_min": [4, 4] })).is_err()
134 );
135 assert!(serde_json::from_value::<PixelizeParams>(json!({ "blocks": 3 })).is_err());
136 }
137}