1use bevy::prelude::*;
7
8pub trait Field<T: Copy + Default> {
20 const SIZE: UVec3;
22
23 const VOLUME: usize = (Self::SIZE.x * Self::SIZE.y * Self::SIZE.z) as usize;
25
26 const DEFAULT: T;
28
29 fn data(&self) -> &[T];
31
32 fn data_mut(&mut self) -> &mut [T];
34
35 #[inline]
39 fn index(x: u32, y: u32, z: u32) -> usize {
40 (x + y * Self::SIZE.x + z * Self::SIZE.x * Self::SIZE.y) as usize
41 }
42
43 #[inline]
45 fn coords(index: usize) -> UVec3 {
46 let index = index as u32;
47 let z = index / (Self::SIZE.x * Self::SIZE.y);
48 let rem = index % (Self::SIZE.x * Self::SIZE.y);
49 let y = rem / Self::SIZE.x;
50 let x = rem % Self::SIZE.x;
51 uvec3(x, y, z)
52 }
53
54 #[inline]
56 fn in_bounds_unsigned(x: u32, y: u32, z: u32) -> bool {
57 x < Self::SIZE.x && y < Self::SIZE.y && z < Self::SIZE.z
58 }
59
60 #[inline]
64 fn in_bounds(x: i32, y: i32, z: i32) -> bool {
65 x >= 0
66 && y >= 0
67 && z >= 0
68 && (x as u32) < Self::SIZE.x
69 && (y as u32) < Self::SIZE.y
70 && (z as u32) < Self::SIZE.z
71 }
72
73 #[inline]
77 fn get(&self, x: u32, y: u32, z: u32) -> T {
78 if Self::in_bounds_unsigned(x, y, z) {
79 self.data()[Self::index(x, y, z)]
80 } else {
81 Self::DEFAULT
82 }
83 }
84
85 #[inline]
87 fn get_uvec3(&self, pos: UVec3) -> T {
88 self.get(pos.x, pos.y, pos.z)
89 }
90
91 #[inline]
95 fn get_signed(&self, x: i32, y: i32, z: i32) -> Option<T> {
96 if Self::in_bounds(x, y, z) {
97 Some(self.data()[Self::index(x as u32, y as u32, z as u32)])
98 } else {
99 None
100 }
101 }
102
103 #[inline]
107 fn get_ivec3(&self, pos: IVec3) -> Option<T> {
108 self.get_signed(pos.x, pos.y, pos.z)
109 }
110
111 #[inline]
115 fn set(&mut self, x: u32, y: u32, z: u32, value: T) {
116 if Self::in_bounds_unsigned(x, y, z) {
117 self.data_mut()[Self::index(x, y, z)] = value;
118 }
119 }
120
121 #[inline]
123 fn set_uvec3(&mut self, pos: UVec3, value: T) {
124 self.set(pos.x, pos.y, pos.z, value);
125 }
126
127 #[inline]
131 fn set_signed(&mut self, x: i32, y: i32, z: i32, value: T) -> bool {
132 if Self::in_bounds(x, y, z) {
133 self.data_mut()[Self::index(x as u32, y as u32, z as u32)] = value;
134 true
135 } else {
136 false
137 }
138 }
139
140 #[inline]
144 fn set_ivec3(&mut self, pos: IVec3, value: T) -> bool {
145 self.set_signed(pos.x, pos.y, pos.z, value)
146 }
147
148 #[inline]
150 fn fill(&mut self, value: T) {
151 self.data_mut().fill(value);
152 }
153
154 fn iter(&self) -> FieldIter<'_, T, Self>
156 where
157 Self: Sized,
158 {
159 FieldIter {
160 field: self,
161 index: 0,
162 _marker: std::marker::PhantomData,
163 }
164 }
165
166 fn positions() -> FieldPositionIter {
168 FieldPositionIter {
169 size: Self::SIZE,
170 index: 0,
171 }
172 }
173}
174
175pub struct FieldIter<'a, T: Copy + Default, F: Field<T>> {
177 field: &'a F,
178 index: usize,
179 _marker: std::marker::PhantomData<T>,
180}
181
182impl<'a, T: Copy + Default, F: Field<T>> Iterator for FieldIter<'a, T, F> {
183 type Item = (UVec3, T);
184
185 fn next(&mut self) -> Option<Self::Item> {
186 if self.index < F::VOLUME {
187 let pos = F::coords(self.index);
188 let value = self.field.data()[self.index];
189 self.index += 1;
190 Some((pos, value))
191 } else {
192 None
193 }
194 }
195
196 fn size_hint(&self) -> (usize, Option<usize>) {
197 let remaining = F::VOLUME - self.index;
198 (remaining, Some(remaining))
199 }
200}
201
202impl<'a, T: Copy + Default, F: Field<T>> ExactSizeIterator for FieldIter<'a, T, F> {}
203
204pub struct FieldPositionIter {
206 size: UVec3,
207 index: u32,
208}
209
210impl Iterator for FieldPositionIter {
211 type Item = UVec3;
212
213 fn next(&mut self) -> Option<Self::Item> {
214 let volume = self.size.x * self.size.y * self.size.z;
215 if self.index < volume {
216 let z = self.index / (self.size.x * self.size.y);
217 let rem = self.index % (self.size.x * self.size.y);
218 let y = rem / self.size.x;
219 let x = rem % self.size.x;
220 self.index += 1;
221 Some(uvec3(x, y, z))
222 } else {
223 None
224 }
225 }
226
227 fn size_hint(&self) -> (usize, Option<usize>) {
228 let volume = (self.size.x * self.size.y * self.size.z) as usize;
229 let remaining = volume - self.index as usize;
230 (remaining, Some(remaining))
231 }
232}
233
234impl ExactSizeIterator for FieldPositionIter {}
235
236pub trait FieldSphereOps<T: Copy + Default>: Field<T> {
238 fn apply_sphere<F>(&mut self, center: Vec3, radius: f32, op: F)
245 where
246 F: Fn(T, f32) -> T,
247 {
248 let min = (center - Vec3::splat(radius + 1.0))
249 .max(Vec3::ZERO)
250 .as_ivec3();
251 let max = (center + Vec3::splat(radius + 1.0))
252 .min(Self::SIZE.as_vec3() - Vec3::ONE)
253 .as_ivec3();
254
255 for z in min.z..=max.z {
256 for y in min.y..=max.y {
257 for x in min.x..=max.x {
258 let pos = vec3(x as f32, y as f32, z as f32);
259 let dist = pos.distance(center);
260 if dist <= radius {
261 let current = self.get(x as u32, y as u32, z as u32);
262 let new_value = op(current, dist);
263 self.set(x as u32, y as u32, z as u32, new_value);
264 }
265 }
266 }
267 }
268 }
269
270 fn fill_sphere(&mut self, center: Vec3, radius: f32, value: T) {
272 self.apply_sphere(center, radius, |_, _| value);
273 }
274}
275
276pub trait FieldBoxOps<T: Copy + Default>: Field<T> {
278 fn apply_box<F>(&mut self, min: IVec3, max: IVec3, op: F)
285 where
286 F: Fn(T) -> T,
287 {
288 let min = min.max(IVec3::ZERO);
289 let max = max.min(Self::SIZE.as_ivec3() - IVec3::ONE);
290
291 for z in min.z..=max.z {
292 for y in min.y..=max.y {
293 for x in min.x..=max.x {
294 let current = self.get(x as u32, y as u32, z as u32);
295 let new_value = op(current);
296 self.set(x as u32, y as u32, z as u32, new_value);
297 }
298 }
299 }
300 }
301
302 fn fill_box(&mut self, min: IVec3, max: IVec3, value: T) {
304 self.apply_box(min, max, |_| value);
305 }
306}
307
308impl<T: Copy + Default, F: Field<T>> FieldSphereOps<T> for F {}
310impl<T: Copy + Default, F: Field<T>> FieldBoxOps<T> for F {}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315
316 struct TestField(Vec<f32>);
318
319 impl Field<f32> for TestField {
320 const SIZE: UVec3 = uvec3(8, 8, 8);
321 const DEFAULT: f32 = 0.0;
322
323 fn data(&self) -> &[f32] {
324 &self.0
325 }
326
327 fn data_mut(&mut self) -> &mut [f32] {
328 &mut self.0
329 }
330 }
331
332 #[test]
333 fn test_index_coords_roundtrip() {
334 for z in 0..8u32 {
335 for y in 0..8u32 {
336 for x in 0..8u32 {
337 let idx = TestField::index(x, y, z);
338 let coords = TestField::coords(idx);
339 assert_eq!(coords, uvec3(x, y, z));
340 }
341 }
342 }
343 }
344
345 #[test]
346 fn test_get_set() {
347 let mut field = TestField(vec![0.0; 512]);
348 field.set(3, 4, 5, 42.0);
349 assert_eq!(field.get(3, 4, 5), 42.0);
350 assert_eq!(field.get(0, 0, 0), 0.0);
351 }
352
353 #[test]
354 fn test_out_of_bounds() {
355 let field = TestField(vec![1.0; 512]);
356 assert_eq!(field.get(100, 0, 0), 0.0); assert_eq!(field.get_signed(-1, 0, 0), None);
358 }
359
360 #[test]
361 fn test_fill_sphere() {
362 let mut field = TestField(vec![0.0; 512]);
363 field.fill_sphere(vec3(4.0, 4.0, 4.0), 2.0, 1.0);
364 assert_eq!(field.get(4, 4, 4), 1.0); assert_eq!(field.get(0, 0, 0), 0.0); }
367
368 #[test]
369 fn test_iter() {
370 let field = TestField(vec![0.0; 512]);
371 assert_eq!(field.iter().count(), 512);
372 }
373}