1use super::Opcode;
3use crate::sdf;
5use crate::structs::Material;
6use crate::structs::SignedDistance;
7use macaw::Quat;
8use macaw::Vec3;
9use macaw::Vec4;
10
11#[derive(Copy, Clone)]
12pub struct Interpreter<SD: SignedDistance, const STACK_DEPTH: usize = 64> {
13    marker: core::marker::PhantomData<SD>,
14}
15
16impl<SD: SignedDistance> Default for Interpreter<SD> {
17    fn default() -> Self {
18        Self {
19            marker: Default::default(),
20        }
21    }
22}
23
24pub struct InterpreterContext<'a, SD: SignedDistance, const STACK_DEPTH: usize = 64> {
25    opcodes: &'a [Opcode],
26    constants: &'a [f32],
27
28    stack: [SD; STACK_DEPTH],
29    stack_ptr: usize,
30    constant_idx: usize,
31    position_stack: [Vec3; STACK_DEPTH],
32    position_stack_ptr: usize,
33}
34
35fn uninit<T>(_t: T) -> T {
36    #[cfg(not(target_arch = "spirv"))]
37    let ret = unsafe { core::mem::MaybeUninit::<T>::zeroed().assume_init() };
39
40    #[cfg(target_arch = "spirv")]
41    let ret = _t; ret
44}
45
46impl<'a, SD: SignedDistance + Copy + Clone, const STACK_DEPTH: usize>
47    InterpreterContext<'a, SD, STACK_DEPTH>
48{
49    fn new(opcodes: &'a [Opcode], constants: &'a [f32]) -> Self {
50        Self {
51            opcodes,
52            constants,
53            stack: uninit([SignedDistance::infinity(); STACK_DEPTH]),
54            stack_ptr: 0,
55            constant_idx: 0,
56            position_stack: uninit([Vec3::ZERO; STACK_DEPTH]),
57            position_stack_ptr: 0,
58        }
59    }
60
61    fn reset(&mut self) {
62        self.stack_ptr = 0;
63        self.position_stack_ptr = 0;
64        self.constant_idx = 0;
65    }
66
67    fn float32(&mut self) -> f32 {
68        let ret = self.constants[self.constant_idx];
69        self.constant_idx += 1;
70        ret
71    }
72
73    fn vec3(&mut self) -> Vec3 {
74        Vec3::new(self.float32(), self.float32(), self.float32())
75    }
76
77    fn vec4(&mut self) -> Vec4 {
80        Vec4::new(
81            self.float32(),
82            self.float32(),
83            self.float32(),
84            self.float32(),
85        )
86    }
87
88    fn quat(&mut self) -> Quat {
89        Quat::from_xyzw(
90            self.float32(),
91            self.float32(),
92            self.float32(),
93            self.float32(),
94        )
95    }
96
97    fn material(&mut self) -> Material {
98        self.vec3().into()
99    }
100
101    fn push_sd(&mut self, v: SD) {
102        self.stack[self.stack_ptr] = v;
103        self.stack_ptr += 1;
104    }
105
106    fn pop_sd(&mut self) -> Option<SD> {
107        self.stack_ptr -= 1;
108        self.stack.get(self.stack_ptr).copied()
109    }
110
111    fn pop_sd_unchecked(&mut self) -> SD {
112        self.stack_ptr -= 1;
113        self.stack[self.stack_ptr]
114    }
115
116    fn push_position(&mut self, pos: Vec3) {
117        self.position_stack[self.position_stack_ptr] = pos;
118        self.position_stack_ptr += 1;
119    }
120
121    fn pop_position_unchecked(&mut self) -> Vec3 {
122        self.position_stack_ptr -= 1;
123        self.position_stack[self.position_stack_ptr]
124    }
125
126    #[allow(dead_code)]
128    fn top_is_finite(&self) -> bool {
129        if self.stack_ptr > 0 {
130            if let Some(value) = self.stack.get(self.stack_ptr - 1) {
131                value.is_distance_finite()
132            } else {
133                false
135            }
136        } else {
137            false
138        }
139    }
140}
141
142impl<SD: SignedDistance + Copy + Clone, const STACK_DEPTH: usize> Interpreter<SD, STACK_DEPTH> {
143    pub fn new_context<'a>(
144        opcodes: &'a [Opcode],
145        constants: &'a [f32],
146    ) -> InterpreterContext<'a, SD, STACK_DEPTH> {
147        InterpreterContext::<SD, STACK_DEPTH>::new(opcodes, constants)
148    }
149    pub fn interpret(
150        ctx: &mut InterpreterContext<'_, SD, STACK_DEPTH>,
151        position: Vec3,
152    ) -> Option<SD> {
153        Self::interpret_internal(ctx, position);
154        ctx.pop_sd()
155    }
156
157    pub fn interpret_unchecked(
158        ctx: &mut InterpreterContext<'_, SD, STACK_DEPTH>,
159        position: Vec3,
160    ) -> SD {
161        Self::interpret_internal(ctx, position);
162        ctx.pop_sd_unchecked()
163    }
164
165    fn interpret_internal(ctx: &mut InterpreterContext<'_, SD, STACK_DEPTH>, position: Vec3) {
166        #[allow(clippy::enum_glob_use)]
167        use Opcode::*;
168
169        let mut current_position = position;
170
171        ctx.reset();
172
173        let mut pc = 0;
174
175        loop {
176            let opcode = ctx.opcodes[pc];
177            pc += 1;
178
179            match opcode {
180                Plane => {
181                    let sd = sdf::sd_plane(current_position, ctx.vec4());
182                    ctx.push_sd(sd);
183                }
184                Sphere => {
185                    let sd = sdf::sd_sphere(current_position, ctx.vec3(), ctx.float32());
186                    ctx.push_sd(sd);
187                }
188                Capsule => {
189                    let sd =
190                        sdf::sd_capsule(current_position, &[ctx.vec3(), ctx.vec3()], ctx.float32());
191                    ctx.push_sd(sd);
192                }
193                RoundedCylinder => {
194                    let sd = sdf::sd_rounded_cylinder(
195                        current_position,
196                        ctx.float32(),
197                        ctx.float32(),
198                        ctx.float32(),
199                    );
200                    ctx.push_sd(sd);
201                }
202                TaperedCapsule => {
203                    let p0 = ctx.vec3();
204                    let r0 = ctx.float32();
205                    let p1 = ctx.vec3();
206                    let r1 = ctx.float32();
207                    let sd = sdf::sd_tapered_capsule(current_position, &[p0, p1], [r0, r1]);
208                    ctx.push_sd(sd);
209                }
210                Cone => {
211                    let r = ctx.float32();
212                    let h = ctx.float32();
213                    let sd = sdf::sd_cone(current_position, r, h);
214                    ctx.push_sd(sd);
215                }
216                RoundedBox => {
217                    let half_size = ctx.vec3();
218                    let radius = ctx.float32();
219                    let sd = sdf::sd_rounded_box(current_position, half_size, radius);
220                    ctx.push_sd(sd);
221                }
222                Torus => {
223                    let big_r = ctx.float32();
224                    let small_r = ctx.float32();
225                    ctx.push_sd(sdf::sd_torus(current_position, big_r, small_r));
226                }
227                TorusSector => {
228                    let big_r = ctx.float32();
229                    let small_r = ctx.float32();
230                    let sin_cos_half_angle = (ctx.float32(), ctx.float32());
231                    ctx.push_sd(sdf::sd_torus_sector(
232                        current_position,
233                        big_r,
234                        small_r,
235                        sin_cos_half_angle,
236                    ));
237                }
238                BiconvexLens => {
239                    let lower_sagitta = ctx.float32();
240                    let upper_sagitta = ctx.float32();
241                    let chord = ctx.float32();
242                    let sd = sdf::sd_biconvex_lens(
243                        current_position,
244                        lower_sagitta,
245                        upper_sagitta,
246                        chord,
247                    );
248                    ctx.push_sd(sd);
249                }
250                Material => {
251                    let sd = ctx.pop_sd_unchecked();
252                    let material = ctx.material();
253                    ctx.push_sd(sdf::sd_material(sd, material));
254                }
255                Union => {
256                    let sd1 = ctx.pop_sd_unchecked();
257                    let sd2 = ctx.pop_sd_unchecked();
258                    ctx.push_sd(sdf::sd_op_union(sd1, sd2));
259                }
260                UnionSmooth => {
261                    let sd1 = ctx.pop_sd_unchecked();
262                    let sd2 = ctx.pop_sd_unchecked();
263                    let width = ctx.float32();
264                    ctx.push_sd(sdf::sd_op_union_smooth(sd1, sd2, width));
265                }
266                Subtract => {
267                    let sd1 = ctx.pop_sd_unchecked();
268                    let sd2 = ctx.pop_sd_unchecked();
269                    ctx.push_sd(sdf::sd_op_subtract(sd1, sd2));
270                }
271                SubtractSmooth => {
272                    let sd1 = ctx.pop_sd_unchecked();
273                    let sd2 = ctx.pop_sd_unchecked();
274                    let width = ctx.float32();
275                    ctx.push_sd(sdf::sd_op_subtract_smooth(sd1, sd2, width));
276                }
277                Intersect => {
278                    let sd1 = ctx.pop_sd_unchecked();
279                    let sd2 = ctx.pop_sd_unchecked();
280                    ctx.push_sd(sdf::sd_op_intersect(sd1, sd2));
281                }
282                IntersectSmooth => {
283                    let sd1 = ctx.pop_sd_unchecked();
284                    let sd2 = ctx.pop_sd_unchecked();
285                    let width = ctx.float32();
286                    ctx.push_sd(sdf::sd_op_intersect_smooth(sd1, sd2, width));
287                }
288                PushTranslation => {
289                    let translation = ctx.vec3();
290                    ctx.push_position(current_position);
291                    current_position += translation;
292                }
293                PopTransform => {
294                    current_position = ctx.pop_position_unchecked();
295                }
296                PushRotation => {
297                    let rotation = ctx.quat();
298                    ctx.push_position(current_position);
299                    current_position = rotation * current_position;
300                }
301                PushScale => {
302                    let inv_scale = ctx.float32();
303                    ctx.push_position(current_position);
304                    current_position *= inv_scale;
305                }
306                PopScale => {
307                    current_position = ctx.pop_position_unchecked();
308                    let scale = ctx.float32();
309                    let sd = ctx.pop_sd_unchecked();
310                    ctx.push_sd(sd.copy_with_distance(scale * sd.distance()));
311                }
312                End => {
313                    break;
314                }
315            }
316
317            }
322    }
323}