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}