vyre_libs/visual/cell_grid/
mod.rs1use vyre_foundation::ir::model::expr::GeneratorRef;
15use vyre_foundation::ir::{BufferAccess, BufferDecl, DataType, Expr, Node, Program};
16
17const OP_ID: &str = "vyre-libs::visual::cell_grid";
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct GridShape {
25 pub cols: u32,
27 pub rows: u32,
29 pub cell_width: u32,
31 pub cell_height: u32,
33}
34
35impl GridShape {
36 #[must_use]
38 pub const fn width(&self) -> u32 {
39 self.cols * self.cell_width
40 }
41
42 #[must_use]
44 pub const fn height(&self) -> u32 {
45 self.rows * self.cell_height
46 }
47
48 #[must_use]
50 pub const fn cell_count(&self) -> u32 {
51 self.cols * self.rows
52 }
53
54 #[must_use]
56 pub const fn pixel_count(&self) -> u32 {
57 self.width() * self.height()
58 }
59
60 pub(super) fn validated(self) -> Self {
61 assert!(
62 self.cols > 0 && self.rows > 0,
63 "Fix: a cell grid needs at least one row and one column, got {}x{}",
64 self.cols,
65 self.rows
66 );
67 assert!(
68 self.cell_width > 0 && self.cell_height > 0,
69 "Fix: a cell needs a non-zero size, got {}x{} pixels",
70 self.cell_width,
71 self.cell_height
72 );
73 let width = self
77 .cols
78 .checked_mul(self.cell_width)
79 .expect("Fix: cols * cell_width overflows u32");
80 let height = self
81 .rows
82 .checked_mul(self.cell_height)
83 .expect("Fix: rows * cell_height overflows u32");
84 width
85 .checked_mul(height)
86 .expect("Fix: the surface pixel count overflows u32");
87 self.cols
88 .checked_mul(self.rows)
89 .expect("Fix: cols * rows overflows u32");
90 self
91 }
92}
93
94pub(super) fn cell_lookup_nodes(shape: GridShape) -> Vec<Node> {
102 let width = shape.width();
103 vec![
104 Node::let_bind("y", Expr::div(Expr::var("idx"), Expr::u32(width))),
105 Node::let_bind(
109 "x",
110 Expr::sub(
111 Expr::var("idx"),
112 Expr::mul(Expr::var("y"), Expr::u32(width)),
113 ),
114 ),
115 Node::let_bind(
116 "col",
117 Expr::div(Expr::var("x"), Expr::u32(shape.cell_width)),
118 ),
119 Node::let_bind(
120 "row",
121 Expr::div(Expr::var("y"), Expr::u32(shape.cell_height)),
122 ),
123 Node::let_bind(
124 "cell",
125 Expr::add(
126 Expr::mul(Expr::var("row"), Expr::u32(shape.cols)),
127 Expr::var("col"),
128 ),
129 ),
130 ]
131}
132
133#[must_use]
139pub fn cell_grid_fill(cells: &str, output: &str, shape: GridShape) -> Program {
140 let shape = shape.validated();
141 let pixels = shape.pixel_count();
142 let width = shape.width();
143
144 Program::wrapped(
145 vec![
146 BufferDecl::storage(cells, 0, BufferAccess::ReadOnly, DataType::U32)
147 .with_count(shape.cell_count()),
148 BufferDecl::storage(output, 1, BufferAccess::ReadWrite, DataType::U32)
149 .with_count(pixels),
150 ],
151 super::PIXEL_WORKGROUP_SIZE,
152 vec![crate::region::wrap_anonymous(
153 OP_ID,
154 vec![crate::region::wrap_child(
155 vyre_primitives::visual::packed_rgba_map::OP_ID,
156 GeneratorRef {
157 name: OP_ID.to_string(),
158 },
159 vec![
160 Node::let_bind("idx", Expr::gid_x()),
161 Node::if_then(
162 Expr::lt(Expr::var("idx"), Expr::u32(pixels)),
163 {
164 let mut body = cell_lookup_nodes(shape);
165 body.push(Node::let_bind(
166 "colour",
167 Expr::load(cells, Expr::var("cell")),
168 ));
169 body.push(Node::store(output, Expr::var("idx"), Expr::var("colour")));
170 body
171 },
172 ),
173 ],
174 )],
175 )],
176 )
177}
178
179inventory::submit! {
180 vyre_foundation::operation::OperationRegistration {
181 semantic_version: 1,
182 signature: None,
183 tier: vyre_foundation::operation::OperationTier::Library,
184 laws: &[],
185 tolerance: vyre_foundation::operation::TolerancePolicy::EXACT,
186 id: OP_ID,
187 build: Some(|| {
188 cell_grid_fill(
189 "cells",
190 "out",
191 GridShape { cols: 2, rows: 2, cell_width: 2, cell_height: 2 },
192 )
193 }),
194 test_inputs: Some(|| {
195 let cells = [0xFF00_00FFu32, 0xFF00_FF00, 0xFFFF_0000, 0xFFFF_FFFF];
199 vec![vec![
200 crate::visual::byte_helpers::u32_words_to_le_bytes(&cells),
201 vec![0u8; 16 * 4],
202 ]]
203 }),
204 expected_output: Some(|| {
205 const R: u32 = 0xFF00_00FF;
208 const G: u32 = 0xFF00_FF00;
209 const B: u32 = 0xFFFF_0000;
210 const W: u32 = 0xFFFF_FFFF;
211 let expected = [
212 R, R, G, G,
213 R, R, G, G,
214 B, B, W, W,
215 B, B, W, W,
216 ];
217 vec![vec![crate::visual::byte_helpers::u32_words_to_le_bytes(&expected)]]
218 }),
219 category: Some("visual"),
220 }
221}