1use super::instruction::Instruction;
9use crate::types::SdfNode;
10
11#[derive(Debug, thiserror::Error)]
13pub enum CompileError {
14 #[error(
16 "Unsupported primitive for bytecode compilation: {0}. Use eval() or transpiler instead."
17 )]
18 UnsupportedPrimitive(String),
19
20 #[error("SDF tree requires stack depth {required} but maximum is {limit} ({kind} stack)")]
22 StackOverflow {
23 kind: &'static str,
25 required: usize,
27 limit: usize,
29 },
30}
31
32#[derive(Clone, Debug)]
42pub struct CompiledSdf {
43 pub(crate) instructions: Vec<Instruction>,
45 pub(crate) aux_data: Vec<f32>,
48 pub(crate) node_count: usize,
50 pub(crate) lipschitz: f32,
52}
53
54impl CompiledSdf {
55 #[inline]
57 #[must_use]
58 pub fn instructions(&self) -> &[Instruction] {
59 &self.instructions
60 }
61
62 #[inline]
66 #[must_use]
67 pub fn aux_data(&self) -> &[f32] {
68 &self.aux_data
69 }
70
71 #[inline]
73 #[must_use]
74 pub const fn node_count(&self) -> usize {
75 self.node_count
76 }
77
78 #[inline]
84 #[must_use]
85 pub const fn lipschitz(&self) -> f32 {
86 self.lipschitz
87 }
88
89 pub fn compile(node: &SdfNode) -> Self {
96 Self::try_compile(node)
97 .expect("CompiledSdf::compile() failed: unsupported primitive in SDF tree")
98 }
99
100 pub fn try_compile(node: &SdfNode) -> Result<Self, CompileError> {
107 validate_for_compile(node)?;
108
109 let (value_depth, coord_depth) = compute_stack_depths(node);
110 if value_depth > MAX_VALUE_STACK {
111 return Err(CompileError::StackOverflow {
112 kind: "value",
113 required: value_depth,
114 limit: MAX_VALUE_STACK,
115 });
116 }
117 if coord_depth > MAX_COORD_STACK {
118 return Err(CompileError::StackOverflow {
119 kind: "coordinate",
120 required: coord_depth,
121 limit: MAX_COORD_STACK,
122 });
123 }
124
125 let mut compiler = Compiler::new();
126 compiler.compile_node(node);
127 compiler.instructions.push(Instruction::end());
128
129 Ok(Self {
130 instructions: compiler.instructions,
131 aux_data: compiler.aux_data,
132 node_count: compiler.node_count,
133 lipschitz: crate::interval::eval_lipschitz(node),
134 })
135 }
136
137 #[inline]
139 pub fn instruction_count(&self) -> usize {
140 self.instructions.len()
141 }
142
143 #[inline]
145 pub fn memory_size(&self) -> usize {
146 self.instructions.len() * std::mem::size_of::<Instruction>()
147 + self.aux_data.len() * std::mem::size_of::<f32>()
148 }
149}
150
151struct Compiler {
153 instructions: Vec<Instruction>,
154 aux_data: Vec<f32>,
155 node_count: usize,
156}
157
158impl Compiler {
159 fn new() -> Self {
160 Self {
161 instructions: Vec::with_capacity(256),
162 aux_data: Vec::new(),
163 node_count: 0,
164 }
165 }
166
167 fn push_aux(&mut self, data: &[f32]) -> (u32, u32) {
169 let offset = self.aux_data.len() as u32;
170 self.aux_data.extend_from_slice(data);
171 (offset, data.len() as u32)
172 }
173
174 fn compile_node(&mut self, node: &SdfNode) {
176 self.node_count += 1;
177
178 match node {
179 SdfNode::Sphere { radius } => {
181 self.instructions.push(Instruction::sphere(*radius));
182 }
183
184 SdfNode::Box3d { half_extents } => {
185 self.instructions.push(Instruction::box3d(
186 half_extents.x,
187 half_extents.y,
188 half_extents.z,
189 ));
190 }
191
192 SdfNode::Cylinder {
193 radius,
194 half_height,
195 } => {
196 self.instructions
197 .push(Instruction::cylinder(*radius, *half_height));
198 }
199
200 SdfNode::Torus {
201 major_radius,
202 minor_radius,
203 } => {
204 self.instructions
205 .push(Instruction::torus(*major_radius, *minor_radius));
206 }
207
208 SdfNode::Plane { normal, distance } => {
209 self.instructions
210 .push(Instruction::plane(normal.x, normal.y, normal.z, *distance));
211 }
212
213 SdfNode::Capsule {
214 point_a,
215 point_b,
216 radius,
217 } => {
218 self.instructions.push(Instruction::capsule(
219 point_a.x, point_a.y, point_a.z, point_b.x, point_b.y, point_b.z, *radius,
220 ));
221 }
222
223 SdfNode::Cone {
224 radius,
225 half_height,
226 } => {
227 self.instructions
228 .push(Instruction::cone(*radius, *half_height));
229 }
230
231 SdfNode::Ellipsoid { radii } => {
232 self.instructions
233 .push(Instruction::ellipsoid(radii.x, radii.y, radii.z));
234 }
235
236 SdfNode::RoundedCone {
237 r1,
238 r2,
239 half_height,
240 } => {
241 self.instructions
242 .push(Instruction::rounded_cone(*r1, *r2, *half_height));
243 }
244
245 SdfNode::Pyramid { half_height } => {
246 self.instructions.push(Instruction::pyramid(*half_height));
247 }
248
249 SdfNode::Octahedron { size } => {
250 self.instructions.push(Instruction::octahedron(*size));
251 }
252
253 SdfNode::HexPrism {
254 hex_radius,
255 half_height,
256 } => {
257 self.instructions
258 .push(Instruction::hex_prism(*hex_radius, *half_height));
259 }
260
261 SdfNode::Link {
262 half_length,
263 r1,
264 r2,
265 } => {
266 self.instructions
267 .push(Instruction::link(*half_length, *r1, *r2));
268 }
269
270 SdfNode::Triangle { .. } => {
271 unreachable!("Triangle: validated by validate_for_compile()");
272 }
273
274 SdfNode::Bezier { .. } => {
275 unreachable!("Bezier: validated by validate_for_compile()");
276 }
277
278 SdfNode::RoundedBox {
280 half_extents,
281 round_radius,
282 } => {
283 self.instructions.push(Instruction::rounded_box(
284 half_extents.x,
285 half_extents.y,
286 half_extents.z,
287 *round_radius,
288 ));
289 }
290
291 SdfNode::CappedCone {
292 half_height,
293 r1,
294 r2,
295 } => {
296 self.instructions
297 .push(Instruction::capped_cone(*half_height, *r1, *r2));
298 }
299
300 SdfNode::CappedTorus {
301 major_radius,
302 minor_radius,
303 cap_angle,
304 } => {
305 self.instructions.push(Instruction::capped_torus(
306 *major_radius,
307 *minor_radius,
308 *cap_angle,
309 ));
310 }
311
312 SdfNode::RoundedCylinder {
313 radius,
314 round_radius,
315 half_height,
316 } => {
317 self.instructions.push(Instruction::rounded_cylinder(
318 *radius,
319 *round_radius,
320 *half_height,
321 ));
322 }
323
324 SdfNode::TriangularPrism { width, half_depth } => {
325 self.instructions
326 .push(Instruction::triangular_prism(*width, *half_depth));
327 }
328
329 SdfNode::CutSphere { radius, cut_height } => {
330 self.instructions
331 .push(Instruction::cut_sphere(*radius, *cut_height));
332 }
333
334 SdfNode::CutHollowSphere {
335 radius,
336 cut_height,
337 thickness,
338 } => {
339 self.instructions.push(Instruction::cut_hollow_sphere(
340 *radius,
341 *cut_height,
342 *thickness,
343 ));
344 }
345
346 SdfNode::DeathStar { ra, rb, d } => {
347 self.instructions
348 .push(Instruction::death_star(*ra, *rb, *d));
349 }
350
351 SdfNode::SolidAngle { angle, radius } => {
352 self.instructions
353 .push(Instruction::solid_angle(*angle, *radius));
354 }
355
356 SdfNode::Rhombus {
357 la,
358 lb,
359 half_height,
360 round_radius,
361 } => {
362 self.instructions
363 .push(Instruction::rhombus(*la, *lb, *half_height, *round_radius));
364 }
365
366 SdfNode::Horseshoe {
367 angle,
368 radius,
369 half_length,
370 width,
371 thickness,
372 } => {
373 self.instructions.push(Instruction::horseshoe(
374 *angle,
375 *radius,
376 *half_length,
377 *width,
378 *thickness,
379 ));
380 }
381
382 SdfNode::Vesica { radius, half_dist } => {
383 self.instructions
384 .push(Instruction::vesica(*radius, *half_dist));
385 }
386
387 SdfNode::InfiniteCylinder { radius } => {
388 self.instructions
389 .push(Instruction::infinite_cylinder(*radius));
390 }
391
392 SdfNode::InfiniteCone { angle } => {
393 self.instructions.push(Instruction::infinite_cone(*angle));
394 }
395
396 SdfNode::Gyroid { scale, thickness } => {
397 self.instructions
398 .push(Instruction::gyroid(*scale, *thickness));
399 }
400
401 SdfNode::MetricBall {
402 radius,
403 w_l1,
404 w_l2,
405 w_linf,
406 } => {
407 self.instructions
408 .push(Instruction::metric_ball(*radius, *w_l1, *w_l2, *w_linf));
409 }
410
411 SdfNode::MetricBlend {
412 inner,
413 outer,
414 center,
415 radius,
416 skin,
417 } => {
418 self.compile_node(inner);
420 self.compile_node(outer);
421 self.instructions.push(Instruction::metric_blend(
422 center.x, center.y, center.z, *radius, *skin,
423 ));
424 }
425
426 SdfNode::Heart { size } => {
427 self.instructions.push(Instruction::heart(*size));
428 }
429
430 SdfNode::Tube {
431 outer_radius,
432 thickness,
433 half_height,
434 } => {
435 self.instructions
436 .push(Instruction::tube(*outer_radius, *thickness, *half_height));
437 }
438
439 SdfNode::Barrel {
440 radius,
441 half_height,
442 bulge,
443 } => {
444 self.instructions
445 .push(Instruction::barrel(*radius, *half_height, *bulge));
446 }
447
448 SdfNode::Diamond {
449 radius,
450 half_height,
451 } => {
452 self.instructions
453 .push(Instruction::diamond(*radius, *half_height));
454 }
455
456 SdfNode::ChamferedCube {
457 half_extents,
458 chamfer,
459 } => {
460 self.instructions.push(Instruction::chamfered_cube(
461 half_extents.x,
462 half_extents.y,
463 half_extents.z,
464 *chamfer,
465 ));
466 }
467
468 SdfNode::SchwarzP { scale, thickness } => {
469 self.instructions
470 .push(Instruction::schwarz_p(*scale, *thickness));
471 }
472
473 SdfNode::Superellipsoid {
474 half_extents,
475 e1,
476 e2,
477 } => {
478 self.instructions.push(Instruction::superellipsoid(
479 half_extents.x,
480 half_extents.y,
481 half_extents.z,
482 *e1,
483 *e2,
484 ));
485 }
486
487 SdfNode::RoundedX {
488 width,
489 round_radius,
490 half_height,
491 } => {
492 self.instructions
493 .push(Instruction::rounded_x(*width, *round_radius, *half_height));
494 }
495
496 SdfNode::Pie {
497 angle,
498 radius,
499 half_height,
500 } => {
501 self.instructions
502 .push(Instruction::pie(*angle, *radius, *half_height));
503 }
504
505 SdfNode::Trapezoid {
506 r1,
507 r2,
508 trap_height,
509 half_depth,
510 } => {
511 self.instructions
512 .push(Instruction::trapezoid(*r1, *r2, *trap_height, *half_depth));
513 }
514
515 SdfNode::Parallelogram {
516 width,
517 para_height,
518 skew,
519 half_depth,
520 } => {
521 self.instructions.push(Instruction::parallelogram(
522 *width,
523 *para_height,
524 *skew,
525 *half_depth,
526 ));
527 }
528
529 SdfNode::Tunnel {
530 width,
531 height_2d,
532 half_depth,
533 } => {
534 self.instructions
535 .push(Instruction::tunnel(*width, *height_2d, *half_depth));
536 }
537
538 SdfNode::UnevenCapsule {
539 r1,
540 r2,
541 cap_height,
542 half_depth,
543 } => {
544 self.instructions.push(Instruction::uneven_capsule(
545 *r1,
546 *r2,
547 *cap_height,
548 *half_depth,
549 ));
550 }
551
552 SdfNode::Egg { ra, rb } => {
553 self.instructions.push(Instruction::egg(*ra, *rb));
554 }
555
556 SdfNode::ArcShape {
557 aperture,
558 radius,
559 thickness,
560 half_height,
561 } => {
562 self.instructions.push(Instruction::arc_shape(
563 *aperture,
564 *radius,
565 *thickness,
566 *half_height,
567 ));
568 }
569
570 SdfNode::Moon {
571 d,
572 ra,
573 rb,
574 half_height,
575 } => {
576 self.instructions
577 .push(Instruction::moon(*d, *ra, *rb, *half_height));
578 }
579
580 SdfNode::CrossShape {
581 length,
582 thickness,
583 round_radius,
584 half_height,
585 } => {
586 self.instructions.push(Instruction::cross_shape(
587 *length,
588 *thickness,
589 *round_radius,
590 *half_height,
591 ));
592 }
593
594 SdfNode::BlobbyCross { size, half_height } => {
595 self.instructions
596 .push(Instruction::blobby_cross(*size, *half_height));
597 }
598
599 SdfNode::ParabolaSegment {
600 width,
601 para_height,
602 half_depth,
603 } => {
604 self.instructions.push(Instruction::parabola_segment(
605 *width,
606 *para_height,
607 *half_depth,
608 ));
609 }
610
611 SdfNode::RegularPolygon {
612 radius,
613 n_sides,
614 half_height,
615 } => {
616 self.instructions.push(Instruction::regular_polygon(
617 *radius,
618 *n_sides,
619 *half_height,
620 ));
621 }
622
623 SdfNode::StarPolygon {
624 radius,
625 n_points,
626 m,
627 half_height,
628 } => {
629 self.instructions.push(Instruction::star_polygon(
630 *radius,
631 *n_points,
632 *m,
633 *half_height,
634 ));
635 }
636
637 SdfNode::Stairs {
638 step_width,
639 step_height,
640 n_steps,
641 half_depth,
642 } => {
643 self.instructions.push(Instruction::stairs(
644 *step_width,
645 *step_height,
646 *n_steps,
647 *half_depth,
648 ));
649 }
650
651 SdfNode::Helix {
652 major_r,
653 minor_r,
654 pitch,
655 half_height,
656 } => {
657 self.instructions.push(Instruction::helix(
658 *major_r,
659 *minor_r,
660 *pitch,
661 *half_height,
662 ));
663 }
664
665 SdfNode::Tetrahedron { size } => {
666 self.instructions.push(Instruction::tetrahedron(*size));
667 }
668
669 SdfNode::Dodecahedron { radius } => {
670 self.instructions.push(Instruction::dodecahedron(*radius));
671 }
672
673 SdfNode::Icosahedron { radius } => {
674 self.instructions.push(Instruction::icosahedron(*radius));
675 }
676
677 SdfNode::TruncatedOctahedron { radius } => {
678 self.instructions
679 .push(Instruction::truncated_octahedron(*radius));
680 }
681
682 SdfNode::TruncatedIcosahedron { radius } => {
683 self.instructions
684 .push(Instruction::truncated_icosahedron(*radius));
685 }
686
687 SdfNode::BoxFrame { half_extents, edge } => {
688 self.instructions
689 .push(Instruction::box_frame(*half_extents, *edge));
690 }
691
692 SdfNode::DiamondSurface { scale, thickness } => {
693 self.instructions
694 .push(Instruction::diamond_surface(*scale, *thickness));
695 }
696
697 SdfNode::Neovius { scale, thickness } => {
698 self.instructions
699 .push(Instruction::neovius(*scale, *thickness));
700 }
701
702 SdfNode::Lidinoid { scale, thickness } => {
703 self.instructions
704 .push(Instruction::lidinoid(*scale, *thickness));
705 }
706
707 SdfNode::IWP { scale, thickness } => {
708 self.instructions.push(Instruction::iwp(*scale, *thickness));
709 }
710
711 SdfNode::FRD { scale, thickness } => {
712 self.instructions.push(Instruction::frd(*scale, *thickness));
713 }
714
715 SdfNode::FischerKochS { scale, thickness } => {
716 self.instructions
717 .push(Instruction::fischer_koch_s(*scale, *thickness));
718 }
719
720 SdfNode::PMY { scale, thickness } => {
721 self.instructions.push(Instruction::pmy(*scale, *thickness));
722 }
723
724 SdfNode::Union { a, b } => {
727 self.compile_node(a);
728 self.compile_node(b);
729 self.instructions.push(Instruction::union());
730 }
731
732 SdfNode::Intersection { a, b } => {
733 self.compile_node(a);
734 self.compile_node(b);
735 self.instructions.push(Instruction::intersection());
736 }
737
738 SdfNode::Subtraction { a, b } => {
739 self.compile_node(a);
740 self.compile_node(b);
741 self.instructions.push(Instruction::subtraction());
742 }
743
744 SdfNode::SmoothUnion { a, b, k } => {
745 self.compile_node(a);
746 self.compile_node(b);
747 self.instructions.push(Instruction::smooth_union(*k));
748 }
749
750 SdfNode::SmoothIntersection { a, b, k } => {
751 self.compile_node(a);
752 self.compile_node(b);
753 self.instructions.push(Instruction::smooth_intersection(*k));
754 }
755
756 SdfNode::SmoothSubtraction { a, b, k } => {
757 self.compile_node(a);
758 self.compile_node(b);
759 self.instructions.push(Instruction::smooth_subtraction(*k));
760 }
761
762 SdfNode::ChamferUnion { a, b, r } => {
763 self.compile_node(a);
764 self.compile_node(b);
765 self.instructions.push(Instruction::chamfer_union(*r));
766 }
767
768 SdfNode::ChamferIntersection { a, b, r } => {
769 self.compile_node(a);
770 self.compile_node(b);
771 self.instructions
772 .push(Instruction::chamfer_intersection(*r));
773 }
774
775 SdfNode::ChamferSubtraction { a, b, r } => {
776 self.compile_node(a);
777 self.compile_node(b);
778 self.instructions.push(Instruction::chamfer_subtraction(*r));
779 }
780
781 SdfNode::StairsUnion { a, b, r, n } => {
782 self.compile_node(a);
783 self.compile_node(b);
784 self.instructions.push(Instruction::stairs_union(*r, *n));
785 }
786
787 SdfNode::StairsIntersection { a, b, r, n } => {
788 self.compile_node(a);
789 self.compile_node(b);
790 self.instructions
791 .push(Instruction::stairs_intersection(*r, *n));
792 }
793
794 SdfNode::StairsSubtraction { a, b, r, n } => {
795 self.compile_node(a);
796 self.compile_node(b);
797 self.instructions
798 .push(Instruction::stairs_subtraction(*r, *n));
799 }
800
801 SdfNode::XOR { a, b } => {
802 self.compile_node(a);
803 self.compile_node(b);
804 self.instructions.push(Instruction::xor());
805 }
806
807 SdfNode::Morph { a, b, t } => {
808 self.compile_node(a);
809 self.compile_node(b);
810 self.instructions.push(Instruction::morph(*t));
811 }
812
813 SdfNode::ColumnsUnion { a, b, r, n } => {
814 self.compile_node(a);
815 self.compile_node(b);
816 self.instructions.push(Instruction::columns_union(*r, *n));
817 }
818
819 SdfNode::ColumnsIntersection { a, b, r, n } => {
820 self.compile_node(a);
821 self.compile_node(b);
822 self.instructions
823 .push(Instruction::columns_intersection(*r, *n));
824 }
825
826 SdfNode::ColumnsSubtraction { a, b, r, n } => {
827 self.compile_node(a);
828 self.compile_node(b);
829 self.instructions
830 .push(Instruction::columns_subtraction(*r, *n));
831 }
832
833 SdfNode::Pipe { a, b, r } => {
834 self.compile_node(a);
835 self.compile_node(b);
836 self.instructions.push(Instruction::pipe(*r));
837 }
838
839 SdfNode::Engrave { a, b, r } => {
840 self.compile_node(a);
841 self.compile_node(b);
842 self.instructions.push(Instruction::engrave(*r));
843 }
844
845 SdfNode::Groove { a, b, ra, rb } => {
846 self.compile_node(a);
847 self.compile_node(b);
848 self.instructions.push(Instruction::groove(*ra, *rb));
849 }
850
851 SdfNode::Tongue { a, b, ra, rb } => {
852 self.compile_node(a);
853 self.compile_node(b);
854 self.instructions.push(Instruction::tongue(*ra, *rb));
855 }
856
857 SdfNode::Translate { child, offset } => {
860 let inst_idx = self.instructions.len();
861 self.instructions
862 .push(Instruction::translate(offset.x, offset.y, offset.z));
863 self.compile_node(child);
864 self.instructions.push(Instruction::pop_transform());
865 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
867 }
868
869 SdfNode::Rotate { child, rotation } => {
870 let inst_idx = self.instructions.len();
871 self.instructions.push(Instruction::rotate(
872 rotation.x, rotation.y, rotation.z, rotation.w,
873 ));
874 self.compile_node(child);
875 self.instructions.push(Instruction::pop_transform());
876 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
877 }
878
879 SdfNode::Scale { child, factor } => {
880 let inst_idx = self.instructions.len();
881 self.instructions.push(Instruction::scale(*factor));
882 self.compile_node(child);
883 self.instructions.push(Instruction::pop_transform());
884 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
885 }
886
887 SdfNode::ScaleNonUniform { child, factors } => {
888 let inst_idx = self.instructions.len();
889 self.instructions.push(Instruction::scale_non_uniform(
890 factors.x, factors.y, factors.z,
891 ));
892 self.compile_node(child);
893 self.instructions.push(Instruction::pop_transform());
894 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
895 }
896
897 SdfNode::Twist { child, strength } => {
899 let inst_idx = self.instructions.len();
900 self.instructions.push(Instruction::twist(*strength));
901 self.compile_node(child);
902 self.instructions.push(Instruction::pop_transform());
903 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
904 }
905
906 SdfNode::Bend { child, curvature } => {
907 let inst_idx = self.instructions.len();
908 self.instructions.push(Instruction::bend(*curvature));
909 self.compile_node(child);
910 self.instructions.push(Instruction::pop_transform());
911 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
912 }
913
914 SdfNode::RepeatInfinite { child, spacing } => {
915 let inst_idx = self.instructions.len();
916 self.instructions.push(Instruction::repeat_infinite(
917 spacing.x, spacing.y, spacing.z,
918 ));
919 self.compile_node(child);
920 self.instructions.push(Instruction::pop_transform());
921 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
922 }
923
924 SdfNode::RepeatFinite {
925 child,
926 count,
927 spacing,
928 } => {
929 let inst_idx = self.instructions.len();
930 self.instructions.push(Instruction::repeat_finite(
931 count[0] as f32,
932 count[1] as f32,
933 count[2] as f32,
934 spacing.x,
935 spacing.y,
936 spacing.z,
937 ));
938 self.compile_node(child);
939 self.instructions.push(Instruction::pop_transform());
940 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
941 }
942
943 SdfNode::Noise {
944 child,
945 amplitude,
946 frequency,
947 seed,
948 } => {
949 let inst_idx = self.instructions.len();
951 self.instructions
952 .push(Instruction::noise(*amplitude, *frequency, *seed));
953 self.compile_node(child);
954 self.instructions.push(Instruction::pop_transform());
955 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
956 }
957
958 SdfNode::Round { child, radius } => {
959 let inst_idx = self.instructions.len();
960 self.instructions.push(Instruction::round(*radius));
961 self.compile_node(child);
962 self.instructions.push(Instruction::pop_transform());
963 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
964 }
965
966 SdfNode::Onion { child, thickness } => {
967 let inst_idx = self.instructions.len();
968 self.instructions.push(Instruction::onion(*thickness));
969 self.compile_node(child);
970 self.instructions.push(Instruction::pop_transform());
971 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
972 }
973
974 SdfNode::Elongate { child, amount } => {
975 let inst_idx = self.instructions.len();
976 self.instructions
977 .push(Instruction::elongate(amount.x, amount.y, amount.z));
978 self.compile_node(child);
979 self.instructions.push(Instruction::pop_transform());
980 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
981 }
982
983 SdfNode::Mirror { child, axes } => {
984 let inst_idx = self.instructions.len();
985 self.instructions
986 .push(Instruction::mirror(axes.x, axes.y, axes.z));
987 self.compile_node(child);
988 self.instructions.push(Instruction::pop_transform());
989 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
990 }
991
992 SdfNode::OctantMirror { child } => {
993 let inst_idx = self.instructions.len();
994 self.instructions.push(Instruction::octant_mirror());
995 self.compile_node(child);
996 self.instructions.push(Instruction::pop_transform());
997 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
998 }
999
1000 SdfNode::Revolution { child, offset } => {
1001 let inst_idx = self.instructions.len();
1002 self.instructions.push(Instruction::revolution(*offset));
1003 self.compile_node(child);
1004 self.instructions.push(Instruction::pop_transform());
1005 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1006 }
1007
1008 SdfNode::Extrude { child, half_height } => {
1009 let inst_idx = self.instructions.len();
1010 self.instructions.push(Instruction::extrude(*half_height));
1011 self.compile_node(child);
1012 self.instructions.push(Instruction::pop_transform());
1013 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1014 }
1015
1016 SdfNode::SweepBezier { child, p0, p1, p2 } => {
1017 let inst_idx = self.instructions.len();
1018 self.instructions.push(Instruction::sweep_bezier(
1019 p0.x, p0.y, p1.x, p1.y, p2.x, p2.y,
1020 ));
1021 self.compile_node(child);
1022 self.instructions.push(Instruction::pop_transform());
1023 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1024 }
1025
1026 SdfNode::Taper {
1027 child,
1028 factor,
1029 reach,
1030 } => {
1031 let inst_idx = self.instructions.len();
1032 self.instructions.push(Instruction::taper(*factor, *reach));
1033 self.compile_node(child);
1034 self.instructions.push(Instruction::pop_transform());
1035 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1036 }
1037
1038 SdfNode::Displacement { child, strength } => {
1039 let inst_idx = self.instructions.len();
1040 self.instructions.push(Instruction::displacement(*strength));
1041 self.compile_node(child);
1042 self.instructions.push(Instruction::pop_transform());
1043 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1044 }
1045
1046 SdfNode::SineDisplacement {
1050 child,
1051 amplitude,
1052 frequency,
1053 } => {
1054 let inst_idx = self.instructions.len();
1055 self.instructions.push(Instruction::sine_displacement(
1056 *amplitude,
1057 frequency.x,
1058 frequency.y,
1059 frequency.z,
1060 ));
1061 self.compile_node(child);
1062 self.instructions.push(Instruction::pop_transform());
1063 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1064 }
1065
1066 SdfNode::PolarRepeat { child, count } => {
1067 let inst_idx = self.instructions.len();
1068 self.instructions
1069 .push(Instruction::polar_repeat(*count as f32));
1070 self.compile_node(child);
1071 self.instructions.push(Instruction::pop_transform());
1072 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1073 }
1074
1075 SdfNode::WithMaterial { child, .. } => {
1077 self.compile_node(child);
1078 }
1079
1080 SdfNode::Circle2D {
1082 radius,
1083 half_height,
1084 } => {
1085 self.instructions
1086 .push(Instruction::circle_2d(*radius, *half_height));
1087 }
1088
1089 SdfNode::Rect2D {
1090 half_extents,
1091 half_height,
1092 } => {
1093 self.instructions
1094 .push(Instruction::rect_2d(*half_extents, *half_height));
1095 }
1096
1097 SdfNode::Segment2D {
1098 a,
1099 b,
1100 thickness,
1101 half_height,
1102 } => {
1103 self.instructions
1104 .push(Instruction::segment_2d(*a, *b, *thickness, *half_height));
1105 }
1106
1107 SdfNode::Polygon2D {
1108 vertices,
1109 half_height,
1110 } => {
1111 let flat: Vec<f32> = vertices.iter().flat_map(|v| [v.x, v.y]).collect();
1113 let (aux_off, aux_len) = self.push_aux(&flat);
1114 let mut inst = Instruction::polygon_2d(*half_height);
1115 inst.aux_offset = aux_off;
1116 inst.aux_len = aux_len;
1117 self.instructions.push(inst);
1118 }
1119
1120 SdfNode::RoundedRect2D {
1121 half_extents,
1122 round_radius,
1123 half_height,
1124 } => {
1125 self.instructions.push(Instruction::rounded_rect_2d(
1126 *half_extents,
1127 *round_radius,
1128 *half_height,
1129 ));
1130 }
1131
1132 SdfNode::Annular2D {
1133 outer_radius,
1134 thickness,
1135 half_height,
1136 } => {
1137 self.instructions.push(Instruction::annular_2d(
1138 *outer_radius,
1139 *thickness,
1140 *half_height,
1141 ));
1142 }
1143
1144 SdfNode::Terrain { .. } => {
1147 unreachable!("Terrain rejected by validate_for_compile()");
1148 }
1149
1150 SdfNode::ExpSmoothUnion { a, b, k } => {
1152 self.compile_node(a);
1153 self.compile_node(b);
1154 self.instructions.push(Instruction::exp_smooth_union(*k));
1155 }
1156
1157 SdfNode::ExpSmoothIntersection { a, b, k } => {
1158 self.compile_node(a);
1159 self.compile_node(b);
1160 self.instructions
1161 .push(Instruction::exp_smooth_intersection(*k));
1162 }
1163
1164 SdfNode::ExpSmoothSubtraction { a, b, k } => {
1165 self.compile_node(a);
1166 self.compile_node(b);
1167 self.instructions
1168 .push(Instruction::exp_smooth_subtraction(*k));
1169 }
1170
1171 SdfNode::Shear { child, shear } => {
1173 let inst_idx = self.instructions.len();
1174 self.instructions.push(Instruction::shear(*shear));
1175 self.compile_node(child);
1176 self.instructions.push(Instruction::pop_transform());
1177 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1178 }
1179
1180 SdfNode::Animated { child, .. } => {
1182 self.compile_node(child);
1183 }
1184
1185 SdfNode::ProjectiveTransform {
1187 child,
1188 inv_matrix,
1189 lipschitz_bound,
1190 } => {
1191 let (aux_off, aux_len) = self.push_aux(inv_matrix);
1192 let inst_idx = self.instructions.len();
1193 let mut inst = Instruction::projective_transform(*lipschitz_bound);
1194 inst.aux_offset = aux_off;
1195 inst.aux_len = aux_len;
1196 self.instructions.push(inst);
1197 self.compile_node(child);
1198 self.instructions.push(Instruction::pop_transform());
1199 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1200 }
1201
1202 SdfNode::LatticeDeform {
1203 child,
1204 control_points,
1205 nx,
1206 ny,
1207 nz,
1208 bbox_min,
1209 bbox_max,
1210 } => {
1211 let mut aux = Vec::with_capacity(9 + control_points.len() * 3);
1213 aux.push(*nx as f32);
1214 aux.push(*ny as f32);
1215 aux.push(*nz as f32);
1216 aux.push(bbox_min.x);
1217 aux.push(bbox_min.y);
1218 aux.push(bbox_min.z);
1219 aux.push(bbox_max.x);
1220 aux.push(bbox_max.y);
1221 aux.push(bbox_max.z);
1222 for cp in control_points {
1223 aux.push(cp.x);
1224 aux.push(cp.y);
1225 aux.push(cp.z);
1226 }
1227 let (aux_off, aux_len) = self.push_aux(&aux);
1228 let inst_idx = self.instructions.len();
1229 let mut inst = Instruction::lattice_deform();
1230 inst.aux_offset = aux_off;
1231 inst.aux_len = aux_len;
1232 self.instructions.push(inst);
1233 self.compile_node(child);
1234 self.instructions.push(Instruction::pop_transform());
1235 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1236 }
1237
1238 SdfNode::SdfSkinning { child, bones } => {
1239 let mut aux = Vec::with_capacity(1 + bones.len() * 33);
1241 aux.push(bones.len() as f32);
1242 for bone in bones {
1243 aux.extend_from_slice(&bone.inv_bind_pose);
1244 aux.extend_from_slice(&bone.current_pose);
1245 aux.push(bone.weight);
1246 }
1247 let (aux_off, aux_len) = self.push_aux(&aux);
1248 let inst_idx = self.instructions.len();
1249 let mut inst = Instruction::sdf_skinning();
1250 inst.aux_offset = aux_off;
1251 inst.aux_len = aux_len;
1252 self.instructions.push(inst);
1253 self.compile_node(child);
1254 self.instructions.push(Instruction::pop_transform());
1255 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1256 }
1257
1258 SdfNode::IcosahedralSymmetry { child } => {
1260 let inst_idx = self.instructions.len();
1261 self.instructions.push(Instruction::icosahedral_symmetry());
1262 self.compile_node(child);
1263 self.instructions.push(Instruction::pop_transform());
1264 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1265 }
1266
1267 SdfNode::IFS {
1268 child,
1269 transforms,
1270 iterations,
1271 } => {
1272 let mut aux = Vec::with_capacity(1 + transforms.len() * 16);
1274 aux.push(transforms.len() as f32);
1275 for t in transforms {
1276 aux.extend_from_slice(t);
1277 }
1278 let (aux_off, aux_len) = self.push_aux(&aux);
1279 let inst_idx = self.instructions.len();
1280 let mut inst = Instruction::ifs(*iterations);
1281 inst.aux_offset = aux_off;
1282 inst.aux_len = aux_len;
1283 self.instructions.push(inst);
1284 self.compile_node(child);
1285 self.instructions.push(Instruction::pop_transform());
1286 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1287 }
1288
1289 SdfNode::HeightmapDisplacement {
1290 child,
1291 heightmap,
1292 width,
1293 height,
1294 amplitude,
1295 scale,
1296 } => {
1297 let mut aux = Vec::with_capacity(2 + heightmap.len());
1299 aux.push(*width as f32);
1300 aux.push(*height as f32);
1301 aux.extend_from_slice(heightmap);
1302 let (aux_off, aux_len) = self.push_aux(&aux);
1303 let inst_idx = self.instructions.len();
1304 let mut inst = Instruction::heightmap_displacement(*amplitude, *scale);
1305 inst.aux_offset = aux_off;
1306 inst.aux_len = aux_len;
1307 self.instructions.push(inst);
1308 self.compile_node(child);
1309 self.instructions.push(Instruction::pop_transform());
1310 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1311 }
1312
1313 SdfNode::SurfaceRoughness {
1314 child,
1315 frequency,
1316 amplitude,
1317 octaves,
1318 } => {
1319 let inst_idx = self.instructions.len();
1320 self.instructions.push(Instruction::surface_roughness(
1321 *frequency, *amplitude, *octaves,
1322 ));
1323 self.compile_node(child);
1324 self.instructions.push(Instruction::pop_transform());
1325 self.instructions[inst_idx].skip_offset = self.instructions.len() as u32;
1326 }
1327 }
1328 }
1329}
1330
1331const MAX_VALUE_STACK: usize = 64;
1333const MAX_COORD_STACK: usize = 32;
1335
1336pub fn compute_stack_depths(node: &SdfNode) -> (usize, usize) {
1341 match node {
1342 SdfNode::Sphere { .. }
1344 | SdfNode::Box3d { .. }
1345 | SdfNode::Cylinder { .. }
1346 | SdfNode::Torus { .. }
1347 | SdfNode::Plane { .. }
1348 | SdfNode::Capsule { .. }
1349 | SdfNode::Cone { .. }
1350 | SdfNode::Ellipsoid { .. }
1351 | SdfNode::RoundedCone { .. }
1352 | SdfNode::Pyramid { .. }
1353 | SdfNode::Octahedron { .. }
1354 | SdfNode::HexPrism { .. }
1355 | SdfNode::Link { .. }
1356 | SdfNode::Triangle { .. }
1357 | SdfNode::Bezier { .. }
1358 | SdfNode::RoundedBox { .. }
1359 | SdfNode::CappedCone { .. }
1360 | SdfNode::CappedTorus { .. }
1361 | SdfNode::TriangularPrism { .. }
1362 | SdfNode::CutSphere { .. }
1363 | SdfNode::CutHollowSphere { .. }
1364 | SdfNode::DeathStar { .. }
1365 | SdfNode::SolidAngle { .. }
1366 | SdfNode::Rhombus { .. }
1367 | SdfNode::Horseshoe { .. }
1368 | SdfNode::Vesica { .. }
1369 | SdfNode::InfiniteCylinder { .. }
1370 | SdfNode::InfiniteCone { .. }
1371 | SdfNode::Gyroid { .. }
1372 | SdfNode::Heart { .. }
1373 | SdfNode::Tube { .. }
1374 | SdfNode::Barrel { .. }
1375 | SdfNode::Diamond { .. }
1376 | SdfNode::ChamferedCube { .. }
1377 | SdfNode::SchwarzP { .. }
1378 | SdfNode::Superellipsoid { .. }
1379 | SdfNode::RoundedX { .. }
1380 | SdfNode::Pie { .. }
1381 | SdfNode::Trapezoid { .. }
1382 | SdfNode::Parallelogram { .. }
1383 | SdfNode::Tunnel { .. }
1384 | SdfNode::UnevenCapsule { .. }
1385 | SdfNode::Egg { .. }
1386 | SdfNode::ArcShape { .. }
1387 | SdfNode::Moon { .. }
1388 | SdfNode::CrossShape { .. }
1389 | SdfNode::BlobbyCross { .. }
1390 | SdfNode::ParabolaSegment { .. }
1391 | SdfNode::RegularPolygon { .. }
1392 | SdfNode::StarPolygon { .. }
1393 | SdfNode::Stairs { .. }
1394 | SdfNode::Helix { .. }
1395 | SdfNode::Tetrahedron { .. }
1396 | SdfNode::Dodecahedron { .. }
1397 | SdfNode::Icosahedron { .. }
1398 | SdfNode::TruncatedOctahedron { .. }
1399 | SdfNode::TruncatedIcosahedron { .. }
1400 | SdfNode::BoxFrame { .. }
1401 | SdfNode::DiamondSurface { .. }
1402 | SdfNode::Neovius { .. }
1403 | SdfNode::Lidinoid { .. }
1404 | SdfNode::IWP { .. }
1405 | SdfNode::FRD { .. }
1406 | SdfNode::FischerKochS { .. }
1407 | SdfNode::PMY { .. }
1408 | SdfNode::Circle2D { .. }
1409 | SdfNode::Rect2D { .. }
1410 | SdfNode::Segment2D { .. }
1411 | SdfNode::Polygon2D { .. }
1412 | SdfNode::RoundedRect2D { .. }
1413 | SdfNode::Annular2D { .. }
1414 | SdfNode::Terrain { .. } => (1, 0),
1415
1416 SdfNode::Union { a, b }
1420 | SdfNode::Intersection { a, b }
1421 | SdfNode::Subtraction { a, b }
1422 | SdfNode::SmoothUnion { a, b, .. }
1423 | SdfNode::SmoothIntersection { a, b, .. }
1424 | SdfNode::SmoothSubtraction { a, b, .. }
1425 | SdfNode::ChamferUnion { a, b, .. }
1426 | SdfNode::ChamferIntersection { a, b, .. }
1427 | SdfNode::ChamferSubtraction { a, b, .. }
1428 | SdfNode::StairsUnion { a, b, .. }
1429 | SdfNode::StairsIntersection { a, b, .. }
1430 | SdfNode::StairsSubtraction { a, b, .. }
1431 | SdfNode::XOR { a, b }
1432 | SdfNode::Morph { a, b, .. }
1433 | SdfNode::ColumnsUnion { a, b, .. }
1434 | SdfNode::ColumnsIntersection { a, b, .. }
1435 | SdfNode::ColumnsSubtraction { a, b, .. }
1436 | SdfNode::Pipe { a, b, .. }
1437 | SdfNode::Engrave { a, b, .. }
1438 | SdfNode::Groove { a, b, .. }
1439 | SdfNode::Tongue { a, b, .. }
1440 | SdfNode::ExpSmoothUnion { a, b, .. }
1441 | SdfNode::ExpSmoothIntersection { a, b, .. }
1442 | SdfNode::ExpSmoothSubtraction { a, b, .. } => {
1443 let (va, ca) = compute_stack_depths(a);
1444 let (vb, cb) = compute_stack_depths(b);
1445 let value_depth = va.max(1 + vb);
1447 let coord_depth = ca.max(cb);
1448 (value_depth, coord_depth)
1449 }
1450
1451 SdfNode::Translate { child, .. }
1455 | SdfNode::Rotate { child, .. }
1456 | SdfNode::Scale { child, .. }
1457 | SdfNode::ScaleNonUniform { child, .. }
1458 | SdfNode::Twist { child, .. }
1459 | SdfNode::Bend { child, .. }
1460 | SdfNode::RepeatInfinite { child, .. }
1461 | SdfNode::RepeatFinite { child, .. }
1462 | SdfNode::Noise { child, .. }
1463 | SdfNode::Elongate { child, .. }
1464 | SdfNode::Mirror { child, .. }
1465 | SdfNode::OctantMirror { child }
1466 | SdfNode::Revolution { child, .. }
1467 | SdfNode::Extrude { child, .. }
1468 | SdfNode::SweepBezier { child, .. }
1469 | SdfNode::Taper { child, .. }
1470 | SdfNode::Displacement { child, .. }
1471 | SdfNode::SineDisplacement { child, .. }
1472 | SdfNode::PolarRepeat { child, .. }
1473 | SdfNode::Animated { child, .. }
1474 | SdfNode::Shear { child, .. }
1475 | SdfNode::ProjectiveTransform { child, .. }
1476 | SdfNode::LatticeDeform { child, .. }
1477 | SdfNode::SdfSkinning { child, .. }
1478 | SdfNode::IcosahedralSymmetry { child }
1479 | SdfNode::IFS { child, .. }
1480 | SdfNode::HeightmapDisplacement { child, .. }
1481 | SdfNode::SurfaceRoughness { child, .. } => {
1482 let (vc, cc) = compute_stack_depths(child);
1483 (vc, 1 + cc)
1484 }
1485
1486 SdfNode::Round { child, .. }
1488 | SdfNode::Onion { child, .. }
1489 | SdfNode::WithMaterial { child, .. } => compute_stack_depths(child),
1490
1491 #[allow(unreachable_patterns)]
1493 _ => (1, 0),
1494 }
1495}
1496
1497fn validate_for_compile(node: &SdfNode) -> Result<(), CompileError> {
1499 match node {
1500 SdfNode::MetricBall { .. } => {}
1503 SdfNode::MetricBlend { inner, outer, .. } => {
1504 validate_for_compile(inner)?;
1505 validate_for_compile(outer)?;
1506 }
1507 SdfNode::Triangle { .. } => {
1509 return Err(CompileError::UnsupportedPrimitive("Triangle".into()));
1510 }
1511 SdfNode::Bezier { .. } => {
1512 return Err(CompileError::UnsupportedPrimitive("Bezier".into()));
1513 }
1514 SdfNode::Terrain { .. } => {
1516 return Err(CompileError::UnsupportedPrimitive("Terrain".into()));
1517 }
1518 SdfNode::Union { a, b }
1520 | SdfNode::Intersection { a, b }
1521 | SdfNode::Subtraction { a, b }
1522 | SdfNode::SmoothUnion { a, b, .. }
1523 | SdfNode::SmoothIntersection { a, b, .. }
1524 | SdfNode::SmoothSubtraction { a, b, .. }
1525 | SdfNode::ChamferUnion { a, b, .. }
1526 | SdfNode::ChamferIntersection { a, b, .. }
1527 | SdfNode::ChamferSubtraction { a, b, .. }
1528 | SdfNode::StairsUnion { a, b, .. }
1529 | SdfNode::StairsIntersection { a, b, .. }
1530 | SdfNode::StairsSubtraction { a, b, .. }
1531 | SdfNode::XOR { a, b }
1532 | SdfNode::Morph { a, b, .. }
1533 | SdfNode::ColumnsUnion { a, b, .. }
1534 | SdfNode::ColumnsIntersection { a, b, .. }
1535 | SdfNode::ColumnsSubtraction { a, b, .. }
1536 | SdfNode::Pipe { a, b, .. }
1537 | SdfNode::Engrave { a, b, .. }
1538 | SdfNode::Groove { a, b, .. }
1539 | SdfNode::Tongue { a, b, .. }
1540 | SdfNode::ExpSmoothUnion { a, b, .. }
1541 | SdfNode::ExpSmoothIntersection { a, b, .. }
1542 | SdfNode::ExpSmoothSubtraction { a, b, .. } => {
1543 validate_for_compile(a)?;
1544 validate_for_compile(b)?;
1545 }
1546 SdfNode::Translate { child, .. }
1548 | SdfNode::Rotate { child, .. }
1549 | SdfNode::Scale { child, .. }
1550 | SdfNode::ScaleNonUniform { child, .. }
1551 | SdfNode::Twist { child, .. }
1552 | SdfNode::Bend { child, .. }
1553 | SdfNode::RepeatInfinite { child, .. }
1554 | SdfNode::RepeatFinite { child, .. }
1555 | SdfNode::Noise { child, .. }
1556 | SdfNode::Round { child, .. }
1557 | SdfNode::Onion { child, .. }
1558 | SdfNode::Elongate { child, .. }
1559 | SdfNode::Mirror { child, .. }
1560 | SdfNode::OctantMirror { child }
1561 | SdfNode::Revolution { child, .. }
1562 | SdfNode::Extrude { child, .. }
1563 | SdfNode::SweepBezier { child, .. }
1564 | SdfNode::Taper { child, .. }
1565 | SdfNode::Displacement { child, .. }
1566 | SdfNode::SineDisplacement { child, .. }
1567 | SdfNode::PolarRepeat { child, .. }
1568 | SdfNode::WithMaterial { child, .. }
1569 | SdfNode::Animated { child, .. }
1570 | SdfNode::Shear { child, .. }
1571 | SdfNode::ProjectiveTransform { child, .. }
1572 | SdfNode::LatticeDeform { child, .. }
1573 | SdfNode::SdfSkinning { child, .. }
1574 | SdfNode::IcosahedralSymmetry { child }
1575 | SdfNode::IFS { child, .. }
1576 | SdfNode::HeightmapDisplacement { child, .. }
1577 | SdfNode::SurfaceRoughness { child, .. } => {
1578 validate_for_compile(child)?;
1579 }
1580 SdfNode::Sphere { .. }
1582 | SdfNode::Box3d { .. }
1583 | SdfNode::Cylinder { .. }
1584 | SdfNode::Torus { .. }
1585 | SdfNode::Plane { .. }
1586 | SdfNode::Capsule { .. }
1587 | SdfNode::Cone { .. }
1588 | SdfNode::Ellipsoid { .. }
1589 | SdfNode::RoundedCone { .. }
1590 | SdfNode::Pyramid { .. }
1591 | SdfNode::Octahedron { .. }
1592 | SdfNode::HexPrism { .. }
1593 | SdfNode::Link { .. }
1594 | SdfNode::RoundedBox { .. }
1595 | SdfNode::CappedCone { .. }
1596 | SdfNode::CappedTorus { .. }
1597 | SdfNode::RoundedCylinder { .. }
1598 | SdfNode::TriangularPrism { .. }
1599 | SdfNode::CutSphere { .. }
1600 | SdfNode::CutHollowSphere { .. }
1601 | SdfNode::DeathStar { .. }
1602 | SdfNode::SolidAngle { .. }
1603 | SdfNode::Rhombus { .. }
1604 | SdfNode::Horseshoe { .. }
1605 | SdfNode::Vesica { .. }
1606 | SdfNode::InfiniteCylinder { .. }
1607 | SdfNode::InfiniteCone { .. }
1608 | SdfNode::Gyroid { .. }
1609 | SdfNode::Heart { .. }
1610 | SdfNode::Tube { .. }
1611 | SdfNode::Barrel { .. }
1612 | SdfNode::Diamond { .. }
1613 | SdfNode::ChamferedCube { .. }
1614 | SdfNode::SchwarzP { .. }
1615 | SdfNode::Superellipsoid { .. }
1616 | SdfNode::RoundedX { .. }
1617 | SdfNode::Pie { .. }
1618 | SdfNode::Trapezoid { .. }
1619 | SdfNode::Parallelogram { .. }
1620 | SdfNode::Tunnel { .. }
1621 | SdfNode::UnevenCapsule { .. }
1622 | SdfNode::Egg { .. }
1623 | SdfNode::ArcShape { .. }
1624 | SdfNode::Moon { .. }
1625 | SdfNode::CrossShape { .. }
1626 | SdfNode::BlobbyCross { .. }
1627 | SdfNode::ParabolaSegment { .. }
1628 | SdfNode::RegularPolygon { .. }
1629 | SdfNode::StarPolygon { .. }
1630 | SdfNode::Stairs { .. }
1631 | SdfNode::Helix { .. }
1632 | SdfNode::Tetrahedron { .. }
1633 | SdfNode::Dodecahedron { .. }
1634 | SdfNode::Icosahedron { .. }
1635 | SdfNode::TruncatedOctahedron { .. }
1636 | SdfNode::TruncatedIcosahedron { .. }
1637 | SdfNode::BoxFrame { .. }
1638 | SdfNode::DiamondSurface { .. }
1639 | SdfNode::Neovius { .. }
1640 | SdfNode::Lidinoid { .. }
1641 | SdfNode::IWP { .. }
1642 | SdfNode::FRD { .. }
1643 | SdfNode::FischerKochS { .. }
1644 | SdfNode::PMY { .. }
1645 | SdfNode::Circle2D { .. }
1646 | SdfNode::Rect2D { .. }
1647 | SdfNode::Segment2D { .. }
1648 | SdfNode::Polygon2D { .. }
1649 | SdfNode::RoundedRect2D { .. }
1650 | SdfNode::Annular2D { .. } => {}
1651 }
1652 Ok(())
1653}
1654
1655#[cfg(test)]
1656mod tests {
1657 use super::super::opcode::OpCode;
1658 use super::*;
1659
1660 #[test]
1661 fn test_compile_sphere() {
1662 let node = SdfNode::sphere(1.0);
1663 let compiled = CompiledSdf::compile(&node);
1664
1665 assert_eq!(compiled.node_count, 1);
1666 assert_eq!(compiled.instruction_count(), 2); assert_eq!(compiled.instructions[0].opcode, OpCode::Sphere);
1668 assert_eq!(compiled.instructions[0].params[0], 1.0);
1669 assert_eq!(compiled.instructions[1].opcode, OpCode::End);
1670 }
1671
1672 #[test]
1673 fn test_compile_union() {
1674 let a = SdfNode::sphere(1.0);
1675 let b = SdfNode::sphere(2.0);
1676 let node = a.union(b);
1677 let compiled = CompiledSdf::compile(&node);
1678
1679 assert_eq!(compiled.node_count, 3);
1680 assert_eq!(compiled.instruction_count(), 4);
1682 assert_eq!(compiled.instructions[0].opcode, OpCode::Sphere);
1683 assert_eq!(compiled.instructions[1].opcode, OpCode::Sphere);
1684 assert_eq!(compiled.instructions[2].opcode, OpCode::Union);
1685 assert_eq!(compiled.instructions[3].opcode, OpCode::End);
1686 }
1687
1688 #[test]
1689 fn test_compile_translate() {
1690 let node = SdfNode::sphere(1.0).translate(1.0, 2.0, 3.0);
1691 let compiled = CompiledSdf::compile(&node);
1692
1693 assert_eq!(compiled.instruction_count(), 4);
1695 assert_eq!(compiled.instructions[0].opcode, OpCode::Translate);
1696 assert_eq!(compiled.instructions[1].opcode, OpCode::Sphere);
1697 assert_eq!(compiled.instructions[2].opcode, OpCode::PopTransform);
1698 assert_eq!(compiled.instructions[3].opcode, OpCode::End);
1699 }
1700
1701 #[test]
1702 fn test_compile_complex() {
1703 let node = SdfNode::sphere(1.0)
1705 .subtract(SdfNode::box3d(0.5, 0.5, 0.5))
1706 .translate(1.0, 0.0, 0.0);
1707 let compiled = CompiledSdf::compile(&node);
1708
1709 assert_eq!(compiled.node_count, 4);
1710 assert_eq!(compiled.instruction_count(), 6);
1712 }
1713
1714 #[test]
1715 fn test_memory_size() {
1716 let node = SdfNode::sphere(1.0);
1717 let compiled = CompiledSdf::compile(&node);
1718
1719 assert_eq!(compiled.memory_size(), 128);
1721 }
1722
1723 fn assert_roundtrip(node: &crate::types::SdfNode, tolerance: f32) {
1725 use crate::compiled::eval::eval_compiled;
1726 use crate::eval::eval;
1727 use glam::Vec3;
1728
1729 let compiled = CompiledSdf::compile(node);
1730 let test_points = [
1731 Vec3::new(0.5, 0.3, 0.1),
1732 Vec3::new(-0.2, 0.8, -0.4),
1733 Vec3::new(1.0, 0.0, 0.0),
1734 Vec3::new(0.0, 0.0, 0.0),
1735 ];
1736 for pt in &test_points {
1737 let d_tree = eval(node, *pt);
1738 let d_compiled = eval_compiled(&compiled, *pt);
1739 assert!(
1740 (d_tree - d_compiled).abs() < tolerance,
1741 "Mismatch at {pt}: tree={d_tree}, compiled={d_compiled}"
1742 );
1743 }
1744 }
1745
1746 #[test]
1747 fn test_roundtrip_icosahedral_symmetry() {
1748 let node = crate::types::SdfNode::sphere(1.0).icosahedral_symmetry();
1749 assert_roundtrip(&node, 1e-5);
1750 }
1751
1752 #[test]
1753 fn test_roundtrip_surface_roughness() {
1754 let node = crate::types::SdfNode::sphere(1.0).surface_roughness(2.0, 0.05, 3);
1755 assert_roundtrip(&node, 1e-5);
1756 }
1757
1758 #[test]
1759 fn test_roundtrip_heightmap_displacement() {
1760 let heightmap = vec![0.0f32; 16];
1762 let node =
1763 crate::types::SdfNode::sphere(1.0).heightmap_displacement(heightmap, 4, 4, 0.1, 1.0);
1764 assert_roundtrip(&node, 1e-5);
1765 }
1766
1767 #[test]
1768 fn test_roundtrip_projective_transform() {
1769 #[rustfmt::skip]
1771 let identity = [
1772 1.0, 0.0, 0.0, 0.0,
1773 0.0, 1.0, 0.0, 0.0,
1774 0.0, 0.0, 1.0, 0.0,
1775 0.0, 0.0, 0.0, 1.0,
1776 ];
1777 let node = crate::types::SdfNode::sphere(1.0).projective_transform(identity, 1.0);
1778 assert_roundtrip(&node, 1e-5);
1779 }
1780
1781 #[test]
1782 fn test_roundtrip_ifs() {
1783 #[rustfmt::skip]
1785 let identity = [
1786 1.0, 0.0, 0.0, 0.0,
1787 0.0, 1.0, 0.0, 0.0,
1788 0.0, 0.0, 1.0, 0.0,
1789 0.0, 0.0, 0.0, 1.0,
1790 ];
1791 let node = crate::types::SdfNode::sphere(1.0).ifs(vec![identity], 1);
1792 assert_roundtrip(&node, 1e-5);
1793 }
1794
1795 #[test]
1796 fn test_compile_noise() {
1797 let node = SdfNode::sphere(1.0).noise(0.1, 2.0, 42);
1798 let compiled = CompiledSdf::compile(&node);
1799
1800 assert_eq!(compiled.instruction_count(), 4);
1802 assert_eq!(compiled.instructions[0].opcode, OpCode::Noise);
1803 assert_eq!(compiled.instructions[0].params[0], 0.1); assert_eq!(compiled.instructions[0].params[1], 2.0); assert_eq!(compiled.instructions[0].params[2], 42.0); assert_eq!(compiled.instructions[1].opcode, OpCode::Sphere);
1807 assert_eq!(compiled.instructions[2].opcode, OpCode::PopTransform);
1808 assert_eq!(compiled.instructions[3].opcode, OpCode::End);
1809 }
1810}