1#![cfg_attr(not(feature = "std"), no_std)]
9
10extern crate alloc;
11
12mod propagate;
13mod remove;
14#[cfg(feature = "sky")]
15pub mod sky;
16#[cfg(feature = "colored")]
17pub mod colored;
18mod traits;
19mod types;
20
21pub use propagate::propagate;
22pub use remove::remove;
23pub use traits::{VoxelAccess, VoxelInfo};
24pub use types::LightUpdate;
25
26pub struct LightEngine {
27 propagation_queue: alloc::collections::VecDeque<types::LightNode>,
28 removal_queue: alloc::collections::VecDeque<types::RemovalNode>,
29}
30
31impl LightEngine {
32 pub fn new() -> Self {
33 Self {
34 propagation_queue: alloc::collections::VecDeque::with_capacity(512),
35 removal_queue: alloc::collections::VecDeque::with_capacity(512),
36 }
37 }
38
39 pub fn place_light(
40 &mut self,
41 access: &impl VoxelAccess,
42 pos: [i32; 3],
43 level: u8,
44 ) -> alloc::vec::Vec<LightUpdate> {
45 propagate::propagate_reuse(access, pos, level, &mut self.propagation_queue)
46 }
47
48 pub fn remove_light(
49 &mut self,
50 access: &impl VoxelAccess,
51 pos: [i32; 3],
52 ) -> alloc::vec::Vec<LightUpdate> {
53 remove::remove_reuse(
54 access,
55 pos,
56 &mut self.removal_queue,
57 &mut self.propagation_queue,
58 )
59 }
60
61 pub fn block_placed(
62 &mut self,
63 access: &impl VoxelAccess,
64 pos: [i32; 3],
65 ) -> alloc::vec::Vec<LightUpdate> {
66 remove::block_placed(access, pos, &mut self.removal_queue, &mut self.propagation_queue)
67 }
68
69 pub fn block_removed(
70 &mut self,
71 access: &impl VoxelAccess,
72 pos: [i32; 3],
73 ) -> alloc::vec::Vec<LightUpdate> {
74 propagate::block_removed(access, pos, &mut self.propagation_queue)
75 }
76
77 pub fn recalculate_area(
82 &mut self,
83 access: &impl VoxelAccess,
84 center: [i32; 3],
85 radius: i32,
86 ) -> alloc::vec::Vec<LightUpdate> {
87 use alloc::vec::Vec;
88
89 let mut updates = Vec::new();
90 let mut emitters: Vec<([i32; 3], u8)> = Vec::new();
91
92 for z in (center[2] - radius)..=(center[2] + radius) {
94 for y in (center[1] - radius)..=(center[1] + radius) {
95 for x in (center[0] - radius)..=(center[0] + radius) {
96 if let Some(voxel) = access.get_voxel(x, y, z) {
97 if voxel.emission > 0 {
98 emitters.push(([x, y, z], voxel.emission));
99 }
100 if voxel.block_light > 0 {
101 updates.push(LightUpdate::new([x, y, z], 0));
102 }
103 }
104 }
105 }
106 }
107
108 let mut reprop_updates = Vec::new();
110 {
111 let cleared = ClearedOverlay { inner: access, clears: &updates };
112 for (pos, emission) in emitters {
113 let prop = propagate::propagate_reuse(
114 &cleared,
115 pos,
116 emission,
117 &mut self.propagation_queue,
118 );
119 reprop_updates.extend(prop);
120 }
121 }
122
123 updates.extend(reprop_updates);
124 updates
125 }
126}
127
128impl Default for LightEngine {
129 fn default() -> Self {
130 Self::new()
131 }
132}
133
134struct ClearedOverlay<'a, A: VoxelAccess> {
135 inner: &'a A,
136 clears: &'a [LightUpdate],
137}
138
139impl<A: VoxelAccess> VoxelAccess for ClearedOverlay<'_, A> {
140 fn get_voxel(&self, x: i32, y: i32, z: i32) -> Option<VoxelInfo> {
141 let mut voxel = self.inner.get_voxel(x, y, z)?;
142 if self.clears.iter().any(|u| u.x == x && u.y == y && u.z == z) {
143 voxel.block_light = 0;
144 }
145 Some(voxel)
146 }
147}