use super::opcode::OpCode;
use crate::compiled::real::law_max_f32;
use crate::compiled::real::LawMinMax;
#[derive(Clone, Copy, Debug)]
#[repr(C, align(64))]
pub struct Instruction {
pub params: [f32; 7],
pub opcode: OpCode,
pub flags: u8,
pub child_count: u16,
pub skip_offset: u32,
pub aux_offset: u32,
pub aux_len: u32, }
impl Instruction {
#[inline]
pub const fn new(opcode: OpCode) -> Self {
Self {
params: [0.0; 7],
opcode,
flags: 0,
child_count: 0,
skip_offset: 0,
aux_offset: 0,
aux_len: 0,
}
}
#[inline]
pub const fn sphere(radius: f32) -> Self {
let mut inst = Self::new(OpCode::Sphere);
inst.params[0] = radius;
inst
}
#[inline]
pub const fn box3d(hx: f32, hy: f32, hz: f32) -> Self {
let mut inst = Self::new(OpCode::Box3d);
inst.params[0] = hx;
inst.params[1] = hy;
inst.params[2] = hz;
inst
}
#[inline]
pub const fn cylinder(radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Cylinder);
inst.params[0] = radius;
inst.params[1] = half_height;
inst
}
#[inline]
pub const fn torus(major_radius: f32, minor_radius: f32) -> Self {
let mut inst = Self::new(OpCode::Torus);
inst.params[0] = major_radius;
inst.params[1] = minor_radius;
inst
}
#[inline]
pub const fn plane(nx: f32, ny: f32, nz: f32, distance: f32) -> Self {
let mut inst = Self::new(OpCode::Plane);
inst.params[0] = nx;
inst.params[1] = ny;
inst.params[2] = nz;
inst.params[3] = distance;
inst
}
#[inline]
pub const fn capsule(
ax: f32,
ay: f32,
az: f32,
bx: f32,
by: f32,
bz: f32,
radius: f32,
) -> Self {
let mut inst = Self::new(OpCode::Capsule);
inst.params[0] = ax;
inst.params[1] = ay;
inst.params[2] = az;
inst.params[3] = bx;
inst.params[4] = by;
inst.params[5] = bz;
inst.params[6] = radius;
inst
}
#[inline]
pub fn get_capsule_radius(&self) -> f32 {
debug_assert_eq!(
self.opcode,
OpCode::Capsule,
"get_capsule_radius() called on non-Capsule instruction"
);
self.params[6]
}
#[inline]
pub const fn is_leaf(&self) -> bool {
self.opcode.is_primitive() || self.opcode.is_binary_op()
}
#[inline]
pub fn next_instruction_index(&self, current_index: usize) -> usize {
if self.is_leaf() || self.opcode == OpCode::PopTransform || self.opcode == OpCode::End {
current_index + 1
} else {
self.skip_offset as usize
}
}
#[inline]
pub const fn cone(radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Cone);
inst.params[0] = radius;
inst.params[1] = half_height;
inst
}
#[inline]
pub const fn ellipsoid(rx: f32, ry: f32, rz: f32) -> Self {
let mut inst = Self::new(OpCode::Ellipsoid);
inst.params[0] = rx;
inst.params[1] = ry;
inst.params[2] = rz;
inst
}
#[inline]
pub const fn rounded_cone(r1: f32, r2: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::RoundedCone);
inst.params[0] = r1;
inst.params[1] = r2;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn pyramid(half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Pyramid);
inst.params[0] = half_height;
inst
}
#[inline]
pub const fn octahedron(size: f32) -> Self {
let mut inst = Self::new(OpCode::Octahedron);
inst.params[0] = size;
inst
}
#[inline]
pub const fn hex_prism(hex_radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::HexPrism);
inst.params[0] = hex_radius;
inst.params[1] = half_height;
inst
}
#[inline]
pub const fn link(half_length: f32, r1: f32, r2: f32) -> Self {
let mut inst = Self::new(OpCode::Link);
inst.params[0] = half_length;
inst.params[1] = r1;
inst.params[2] = r2;
inst
}
#[inline]
pub const fn rounded_box(hx: f32, hy: f32, hz: f32, round_radius: f32) -> Self {
let mut inst = Self::new(OpCode::RoundedBox);
inst.params[0] = hx;
inst.params[1] = hy;
inst.params[2] = hz;
inst.params[3] = round_radius;
inst
}
#[inline]
pub const fn capped_cone(half_height: f32, r1: f32, r2: f32) -> Self {
let mut inst = Self::new(OpCode::CappedCone);
inst.params[0] = half_height;
inst.params[1] = r1;
inst.params[2] = r2;
inst
}
#[inline]
pub const fn capped_torus(major_radius: f32, minor_radius: f32, cap_angle: f32) -> Self {
let mut inst = Self::new(OpCode::CappedTorus);
inst.params[0] = major_radius;
inst.params[1] = minor_radius;
inst.params[2] = cap_angle;
inst
}
#[inline]
pub const fn rounded_cylinder(radius: f32, round_radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::RoundedCylinder);
inst.params[0] = radius;
inst.params[1] = round_radius;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn triangular_prism(width: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::TriangularPrism);
inst.params[0] = width;
inst.params[1] = half_depth;
inst
}
#[inline]
pub const fn cut_sphere(radius: f32, cut_height: f32) -> Self {
let mut inst = Self::new(OpCode::CutSphere);
inst.params[0] = radius;
inst.params[1] = cut_height;
inst
}
#[inline]
pub const fn cut_hollow_sphere(radius: f32, cut_height: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::CutHollowSphere);
inst.params[0] = radius;
inst.params[1] = cut_height;
inst.params[2] = thickness;
inst
}
#[inline]
pub const fn death_star(ra: f32, rb: f32, d: f32) -> Self {
let mut inst = Self::new(OpCode::DeathStar);
inst.params[0] = ra;
inst.params[1] = rb;
inst.params[2] = d;
inst
}
#[inline]
pub const fn solid_angle(angle: f32, radius: f32) -> Self {
let mut inst = Self::new(OpCode::SolidAngle);
inst.params[0] = angle;
inst.params[1] = radius;
inst
}
#[inline]
pub const fn rhombus(la: f32, lb: f32, half_height: f32, round_radius: f32) -> Self {
let mut inst = Self::new(OpCode::Rhombus);
inst.params[0] = la;
inst.params[1] = lb;
inst.params[2] = half_height;
inst.params[3] = round_radius;
inst
}
#[inline]
pub const fn horseshoe(
angle: f32,
radius: f32,
half_length: f32,
width: f32,
thickness: f32,
) -> Self {
let mut inst = Self::new(OpCode::Horseshoe);
inst.params[0] = angle;
inst.params[1] = radius;
inst.params[2] = half_length;
inst.params[3] = width;
inst.params[4] = thickness;
inst
}
#[inline]
pub const fn vesica(radius: f32, half_dist: f32) -> Self {
let mut inst = Self::new(OpCode::Vesica);
inst.params[0] = radius;
inst.params[1] = half_dist;
inst
}
#[inline]
pub const fn infinite_cylinder(radius: f32) -> Self {
let mut inst = Self::new(OpCode::InfiniteCylinder);
inst.params[0] = radius;
inst
}
#[inline]
pub const fn infinite_cone(angle: f32) -> Self {
let mut inst = Self::new(OpCode::InfiniteCone);
inst.params[0] = angle;
inst
}
#[inline]
pub const fn gyroid(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::Gyroid);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn metric_ball(radius: f32, w_l1: f32, w_l2: f32, w_linf: f32) -> Self {
let mut inst = Self::new(OpCode::MetricBall);
inst.params[0] = radius;
inst.params[1] = w_l1;
inst.params[2] = w_l2;
inst.params[3] = w_linf;
inst
}
#[inline]
pub const fn metric_blend(cx: f32, cy: f32, cz: f32, radius: f32, skin: f32) -> Self {
let mut inst = Self::new(OpCode::MetricBlend);
inst.params[0] = cx;
inst.params[1] = cy;
inst.params[2] = cz;
inst.params[3] = radius;
inst.params[4] = skin;
inst
}
#[inline]
pub const fn heart(size: f32) -> Self {
let mut inst = Self::new(OpCode::Heart);
inst.params[0] = size;
inst
}
#[inline]
pub const fn tube(outer_radius: f32, thickness: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Tube);
inst.params[0] = outer_radius;
inst.params[1] = thickness;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn barrel(radius: f32, half_height: f32, bulge: f32) -> Self {
let mut inst = Self::new(OpCode::Barrel);
inst.params[0] = radius;
inst.params[1] = half_height;
inst.params[2] = bulge;
inst
}
#[inline]
pub const fn diamond(radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Diamond);
inst.params[0] = radius;
inst.params[1] = half_height;
inst
}
#[inline]
pub const fn chamfered_cube(hx: f32, hy: f32, hz: f32, chamfer: f32) -> Self {
let mut inst = Self::new(OpCode::ChamferedCube);
inst.params[0] = hx;
inst.params[1] = hy;
inst.params[2] = hz;
inst.params[3] = chamfer;
inst
}
#[inline]
pub const fn schwarz_p(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::SchwarzP);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn superellipsoid(hx: f32, hy: f32, hz: f32, e1: f32, e2: f32) -> Self {
let mut inst = Self::new(OpCode::Superellipsoid);
inst.params[0] = hx;
inst.params[1] = hy;
inst.params[2] = hz;
inst.params[3] = e1;
inst.params[4] = e2;
inst
}
#[inline]
pub const fn rounded_x(width: f32, round_radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::RoundedX);
inst.params[0] = width;
inst.params[1] = round_radius;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn pie(angle: f32, radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Pie);
inst.params[0] = angle;
inst.params[1] = radius;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn trapezoid(r1: f32, r2: f32, trap_height: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::Trapezoid);
inst.params[0] = r1;
inst.params[1] = r2;
inst.params[2] = trap_height;
inst.params[3] = half_depth;
inst
}
#[inline]
pub const fn parallelogram(width: f32, para_height: f32, skew: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::Parallelogram);
inst.params[0] = width;
inst.params[1] = para_height;
inst.params[2] = skew;
inst.params[3] = half_depth;
inst
}
#[inline]
pub const fn tunnel(width: f32, height_2d: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::Tunnel);
inst.params[0] = width;
inst.params[1] = height_2d;
inst.params[2] = half_depth;
inst
}
#[inline]
pub const fn uneven_capsule(r1: f32, r2: f32, cap_height: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::UnevenCapsule);
inst.params[0] = r1;
inst.params[1] = r2;
inst.params[2] = cap_height;
inst.params[3] = half_depth;
inst
}
#[inline]
pub const fn egg(ra: f32, rb: f32) -> Self {
let mut inst = Self::new(OpCode::Egg);
inst.params[0] = ra;
inst.params[1] = rb;
inst
}
#[inline]
pub const fn arc_shape(aperture: f32, radius: f32, thickness: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::ArcShape);
inst.params[0] = aperture;
inst.params[1] = radius;
inst.params[2] = thickness;
inst.params[3] = half_height;
inst
}
#[inline]
pub const fn moon(d: f32, ra: f32, rb: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Moon);
inst.params[0] = d;
inst.params[1] = ra;
inst.params[2] = rb;
inst.params[3] = half_height;
inst
}
#[inline]
pub const fn cross_shape(
length: f32,
thickness: f32,
round_radius: f32,
half_height: f32,
) -> Self {
let mut inst = Self::new(OpCode::CrossShape);
inst.params[0] = length;
inst.params[1] = thickness;
inst.params[2] = round_radius;
inst.params[3] = half_height;
inst
}
#[inline]
pub const fn blobby_cross(size: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::BlobbyCross);
inst.params[0] = size;
inst.params[1] = half_height;
inst
}
#[inline]
pub const fn parabola_segment(width: f32, para_height: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::ParabolaSegment);
inst.params[0] = width;
inst.params[1] = para_height;
inst.params[2] = half_depth;
inst
}
#[inline]
pub const fn regular_polygon(radius: f32, n_sides: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::RegularPolygon);
inst.params[0] = radius;
inst.params[1] = n_sides;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn star_polygon(radius: f32, n_points: f32, m: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::StarPolygon);
inst.params[0] = radius;
inst.params[1] = n_points;
inst.params[2] = m;
inst.params[3] = half_height;
inst
}
#[inline]
pub const fn stairs(step_width: f32, step_height: f32, n_steps: f32, half_depth: f32) -> Self {
let mut inst = Self::new(OpCode::Stairs);
inst.params[0] = step_width;
inst.params[1] = step_height;
inst.params[2] = n_steps;
inst.params[3] = half_depth;
inst
}
#[inline]
pub const fn helix(major_r: f32, minor_r: f32, pitch: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Helix);
inst.params[0] = major_r;
inst.params[1] = minor_r;
inst.params[2] = pitch;
inst.params[3] = half_height;
inst
}
#[inline]
pub const fn tetrahedron(size: f32) -> Self {
let mut inst = Self::new(OpCode::Tetrahedron);
inst.params[0] = size;
inst
}
#[inline]
pub const fn dodecahedron(radius: f32) -> Self {
let mut inst = Self::new(OpCode::Dodecahedron);
inst.params[0] = radius;
inst
}
#[inline]
pub const fn icosahedron(radius: f32) -> Self {
let mut inst = Self::new(OpCode::Icosahedron);
inst.params[0] = radius;
inst
}
#[inline]
pub const fn truncated_octahedron(radius: f32) -> Self {
let mut inst = Self::new(OpCode::TruncatedOctahedron);
inst.params[0] = radius;
inst
}
#[inline]
pub const fn truncated_icosahedron(radius: f32) -> Self {
let mut inst = Self::new(OpCode::TruncatedIcosahedron);
inst.params[0] = radius;
inst
}
#[inline]
pub const fn box_frame(half_extents: glam::Vec3, edge: f32) -> Self {
let mut inst = Self::new(OpCode::BoxFrame);
inst.params[0] = half_extents.x;
inst.params[1] = half_extents.y;
inst.params[2] = half_extents.z;
inst.params[3] = edge;
inst
}
#[inline]
pub const fn diamond_surface(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::DiamondSurface);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn neovius(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::Neovius);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn lidinoid(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::Lidinoid);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn iwp(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::IWP);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn frd(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::FRD);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn fischer_koch_s(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::FischerKochS);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn pmy(scale: f32, thickness: f32) -> Self {
let mut inst = Self::new(OpCode::PMY);
inst.params[0] = scale;
inst.params[1] = thickness;
inst
}
#[inline]
pub const fn union() -> Self {
Self::new(OpCode::Union)
}
#[inline]
pub const fn intersection() -> Self {
Self::new(OpCode::Intersection)
}
#[inline]
pub const fn subtraction() -> Self {
Self::new(OpCode::Subtraction)
}
#[inline]
pub fn smooth_union(k: f32) -> Self {
let mut inst = Self::new(OpCode::SmoothUnion);
let k_safe = k.law_max(1e-10);
inst.params[0] = k_safe;
inst.params[1] = 1.0 / k_safe; inst
}
#[inline]
pub fn smooth_intersection(k: f32) -> Self {
let mut inst = Self::new(OpCode::SmoothIntersection);
let k_safe = k.law_max(1e-10);
inst.params[0] = k_safe;
inst.params[1] = 1.0 / k_safe; inst
}
#[inline]
pub fn smooth_subtraction(k: f32) -> Self {
let mut inst = Self::new(OpCode::SmoothSubtraction);
let k_safe = k.law_max(1e-10);
inst.params[0] = k_safe;
inst.params[1] = 1.0 / k_safe; inst
}
#[inline]
pub const fn chamfer_union(r: f32) -> Self {
let mut inst = Self::new(OpCode::ChamferUnion);
inst.params[0] = law_max_f32(r, 0.0);
inst
}
#[inline]
pub const fn chamfer_intersection(r: f32) -> Self {
let mut inst = Self::new(OpCode::ChamferIntersection);
inst.params[0] = law_max_f32(r, 0.0);
inst
}
#[inline]
pub const fn chamfer_subtraction(r: f32) -> Self {
let mut inst = Self::new(OpCode::ChamferSubtraction);
inst.params[0] = law_max_f32(r, 0.0);
inst
}
#[inline]
pub const fn stairs_union(r: f32, n: f32) -> Self {
let mut inst = Self::new(OpCode::StairsUnion);
inst.params[0] = law_max_f32(r, 1e-10);
inst.params[1] = law_max_f32(n, 1.0);
inst
}
#[inline]
pub const fn stairs_intersection(r: f32, n: f32) -> Self {
let mut inst = Self::new(OpCode::StairsIntersection);
inst.params[0] = law_max_f32(r, 1e-10);
inst.params[1] = law_max_f32(n, 1.0);
inst
}
#[inline]
pub const fn stairs_subtraction(r: f32, n: f32) -> Self {
let mut inst = Self::new(OpCode::StairsSubtraction);
inst.params[0] = law_max_f32(r, 1e-10);
inst.params[1] = law_max_f32(n, 1.0);
inst
}
#[inline]
pub const fn xor() -> Self {
Self::new(OpCode::XOR)
}
#[inline]
pub const fn morph(t: f32) -> Self {
let mut inst = Self::new(OpCode::Morph);
inst.params[0] = t;
inst
}
#[inline]
pub const fn columns_union(r: f32, n: f32) -> Self {
let mut inst = Self::new(OpCode::ColumnsUnion);
inst.params[0] = law_max_f32(r, 1e-10);
inst.params[1] = law_max_f32(n, 1.0);
inst
}
#[inline]
pub const fn columns_intersection(r: f32, n: f32) -> Self {
let mut inst = Self::new(OpCode::ColumnsIntersection);
inst.params[0] = law_max_f32(r, 1e-10);
inst.params[1] = law_max_f32(n, 1.0);
inst
}
#[inline]
pub const fn columns_subtraction(r: f32, n: f32) -> Self {
let mut inst = Self::new(OpCode::ColumnsSubtraction);
inst.params[0] = law_max_f32(r, 1e-10);
inst.params[1] = law_max_f32(n, 1.0);
inst
}
#[inline]
pub const fn pipe(r: f32) -> Self {
let mut inst = Self::new(OpCode::Pipe);
inst.params[0] = r;
inst
}
#[inline]
pub const fn engrave(r: f32) -> Self {
let mut inst = Self::new(OpCode::Engrave);
inst.params[0] = r;
inst
}
#[inline]
pub const fn groove(ra: f32, rb: f32) -> Self {
let mut inst = Self::new(OpCode::Groove);
inst.params[0] = ra;
inst.params[1] = rb;
inst
}
#[inline]
pub const fn tongue(ra: f32, rb: f32) -> Self {
let mut inst = Self::new(OpCode::Tongue);
inst.params[0] = ra;
inst.params[1] = rb;
inst
}
#[inline]
pub const fn translate(x: f32, y: f32, z: f32) -> Self {
let mut inst = Self::new(OpCode::Translate);
inst.params[0] = x;
inst.params[1] = y;
inst.params[2] = z;
inst.child_count = 1;
inst
}
#[inline]
pub const fn rotate(qx: f32, qy: f32, qz: f32, qw: f32) -> Self {
let mut inst = Self::new(OpCode::Rotate);
inst.params[0] = qx;
inst.params[1] = qy;
inst.params[2] = qz;
inst.params[3] = qw;
inst.child_count = 1;
inst
}
#[inline]
pub fn scale(factor: f32) -> Self {
let mut inst = Self::new(OpCode::Scale);
inst.params[0] = 1.0 / factor; inst.params[1] = factor; inst.flags = 1; inst.child_count = 1;
inst
}
#[inline]
pub fn scale_non_uniform(sx: f32, sy: f32, sz: f32) -> Self {
let mut inst = Self::new(OpCode::ScaleNonUniform);
inst.params[0] = 1.0 / sx; inst.params[1] = 1.0 / sy;
inst.params[2] = 1.0 / sz;
inst.params[3] = sx.law_min(sy).law_min(sz); inst.flags = 1; inst.child_count = 1;
inst
}
#[inline]
pub const fn twist(strength: f32) -> Self {
let mut inst = Self::new(OpCode::Twist);
inst.params[0] = strength;
inst.child_count = 1;
inst
}
#[inline]
pub const fn bend(curvature: f32) -> Self {
let mut inst = Self::new(OpCode::Bend);
inst.params[0] = curvature;
inst.child_count = 1;
inst
}
#[inline]
pub fn repeat_infinite(sx: f32, sy: f32, sz: f32) -> Self {
let mut inst = Self::new(OpCode::RepeatInfinite);
inst.params[0] = sx;
inst.params[1] = sy;
inst.params[2] = sz;
inst.params[3] = 1.0 / sx;
inst.params[4] = 1.0 / sy;
inst.params[5] = 1.0 / sz;
inst.child_count = 1;
inst
}
#[inline]
pub const fn repeat_finite(cx: f32, cy: f32, cz: f32, sx: f32, sy: f32, sz: f32) -> Self {
let mut inst = Self::new(OpCode::RepeatFinite);
inst.params[0] = cx;
inst.params[1] = cy;
inst.params[2] = cz;
inst.params[3] = sx;
inst.params[4] = sy;
inst.params[5] = sz;
inst.child_count = 1;
inst
}
#[inline]
pub const fn round(radius: f32) -> Self {
let mut inst = Self::new(OpCode::Round);
inst.params[0] = radius;
inst.child_count = 1;
inst
}
#[inline]
pub const fn onion(thickness: f32) -> Self {
let mut inst = Self::new(OpCode::Onion);
inst.params[0] = thickness;
inst.child_count = 1;
inst
}
#[inline]
pub const fn elongate(ax: f32, ay: f32, az: f32) -> Self {
let mut inst = Self::new(OpCode::Elongate);
inst.params[0] = ax;
inst.params[1] = ay;
inst.params[2] = az;
inst.child_count = 1;
inst
}
#[inline]
pub const fn noise(amplitude: f32, frequency: f32, seed: u32) -> Self {
let mut inst = Self::new(OpCode::Noise);
inst.params[0] = amplitude;
inst.params[1] = frequency;
inst.params[2] = seed as f32;
inst.child_count = 1;
inst
}
#[inline]
pub const fn mirror(ax: f32, ay: f32, az: f32) -> Self {
let mut inst = Self::new(OpCode::Mirror);
inst.params[0] = ax;
inst.params[1] = ay;
inst.params[2] = az;
inst.child_count = 1;
inst
}
#[inline]
pub const fn revolution(offset: f32) -> Self {
let mut inst = Self::new(OpCode::Revolution);
inst.params[0] = offset;
inst.child_count = 1;
inst
}
#[inline]
pub const fn extrude(half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Extrude);
inst.params[0] = half_height;
inst.child_count = 1;
inst
}
#[inline]
pub const fn sweep_bezier(p0x: f32, p0z: f32, p1x: f32, p1z: f32, p2x: f32, p2z: f32) -> Self {
let mut inst = Self::new(OpCode::SweepBezier);
inst.params[0] = p0x;
inst.params[1] = p0z;
inst.params[2] = p1x;
inst.params[3] = p1z;
inst.params[4] = p2x;
inst.params[5] = p2z;
inst.child_count = 1;
inst
}
#[inline]
pub const fn taper(factor: f32, reach: [f32; 2]) -> Self {
let mut inst = Self::new(OpCode::Taper);
inst.params[0] = factor;
inst.params[1] = reach[0];
inst.params[2] = reach[1];
inst.child_count = 1;
inst
}
#[inline]
pub const fn displacement(strength: f32) -> Self {
Self::sine_displacement(strength, 5.0, 5.0, 5.0)
}
#[inline]
pub const fn sine_displacement(amplitude: f32, fx: f32, fy: f32, fz: f32) -> Self {
let mut inst = Self::new(OpCode::Displacement);
inst.params[0] = amplitude;
inst.params[1] = fx;
inst.params[2] = fy;
inst.params[3] = fz;
inst.child_count = 1;
inst
}
#[inline]
pub fn polar_repeat(count: f32) -> Self {
let mut inst = Self::new(OpCode::PolarRepeat);
inst.params[0] = count;
let sector = std::f32::consts::TAU / count;
inst.params[1] = sector; inst.params[2] = count / std::f32::consts::TAU; inst.child_count = 1;
inst
}
#[inline]
pub const fn octant_mirror() -> Self {
let mut inst = Self::new(OpCode::OctantMirror);
inst.child_count = 1;
inst
}
#[inline]
pub const fn circle_2d(radius: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Circle2D);
inst.params[0] = radius;
inst.params[1] = half_height;
inst
}
#[inline]
pub const fn rect_2d(half_extents: glam::Vec2, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Rect2D);
inst.params[0] = half_extents.x;
inst.params[1] = half_extents.y;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn segment_2d(
a: glam::Vec2,
b: glam::Vec2,
thickness: f32,
half_height: f32,
) -> Self {
let mut inst = Self::new(OpCode::Segment2D);
inst.params[0] = a.x;
inst.params[1] = a.y;
inst.params[2] = b.x;
inst.params[3] = b.y;
inst.params[4] = thickness;
inst.params[5] = half_height;
inst
}
#[inline]
pub const fn polygon_2d(half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Polygon2D);
inst.params[0] = half_height;
inst
}
#[inline]
pub const fn rounded_rect_2d(
half_extents: glam::Vec2,
round_radius: f32,
half_height: f32,
) -> Self {
let mut inst = Self::new(OpCode::RoundedRect2D);
inst.params[0] = half_extents.x;
inst.params[1] = half_extents.y;
inst.params[2] = round_radius;
inst.params[3] = half_height;
inst
}
#[inline]
pub const fn annular_2d(outer_radius: f32, thickness: f32, half_height: f32) -> Self {
let mut inst = Self::new(OpCode::Annular2D);
inst.params[0] = outer_radius;
inst.params[1] = thickness;
inst.params[2] = half_height;
inst
}
#[inline]
pub const fn exp_smooth_union(k: f32) -> Self {
let mut inst = Self::new(OpCode::ExpSmoothUnion);
inst.params[0] = k;
inst.child_count = 2;
inst
}
#[inline]
pub const fn exp_smooth_intersection(k: f32) -> Self {
let mut inst = Self::new(OpCode::ExpSmoothIntersection);
inst.params[0] = k;
inst.child_count = 2;
inst
}
#[inline]
pub const fn exp_smooth_subtraction(k: f32) -> Self {
let mut inst = Self::new(OpCode::ExpSmoothSubtraction);
inst.params[0] = k;
inst.child_count = 2;
inst
}
#[inline]
pub const fn shear(shear: glam::Vec3) -> Self {
let mut inst = Self::new(OpCode::Shear);
inst.params[0] = shear.x;
inst.params[1] = shear.y;
inst.params[2] = shear.z;
inst.child_count = 1;
inst
}
#[inline]
pub const fn animated(speed: f32, amplitude: f32) -> Self {
let mut inst = Self::new(OpCode::Animated);
inst.params[0] = speed;
inst.params[1] = amplitude;
inst.child_count = 1;
inst
}
#[inline]
pub const fn projective_transform(lipschitz_bound: f32) -> Self {
let mut inst = Self::new(OpCode::ProjectiveTransform);
inst.params[0] = lipschitz_bound;
inst.child_count = 1;
inst
}
#[inline]
pub const fn lattice_deform() -> Self {
let mut inst = Self::new(OpCode::LatticeDeform);
inst.child_count = 1;
inst
}
#[inline]
pub const fn sdf_skinning() -> Self {
let mut inst = Self::new(OpCode::SdfSkinning);
inst.child_count = 1;
inst
}
#[inline]
pub const fn icosahedral_symmetry() -> Self {
let mut inst = Self::new(OpCode::IcosahedralSymmetry);
inst.child_count = 1;
inst
}
#[inline]
pub const fn ifs(iterations: u32) -> Self {
let mut inst = Self::new(OpCode::IFS);
inst.params[0] = iterations as f32;
inst.child_count = 1;
inst
}
#[inline]
pub const fn heightmap_displacement(amplitude: f32, scale: f32) -> Self {
let mut inst = Self::new(OpCode::HeightmapDisplacement);
inst.params[0] = amplitude;
inst.params[1] = scale;
inst.child_count = 1;
inst
}
#[inline]
pub const fn surface_roughness(frequency: f32, amplitude: f32, octaves: u32) -> Self {
let mut inst = Self::new(OpCode::SurfaceRoughness);
inst.params[0] = frequency;
inst.params[1] = amplitude;
inst.params[2] = octaves as f32;
inst.child_count = 1;
inst
}
#[inline]
pub const fn pop_transform() -> Self {
Self::new(OpCode::PopTransform)
}
#[inline]
pub const fn end() -> Self {
Self::new(OpCode::End)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
fn test_instruction_size() {
assert_eq!(mem::size_of::<Instruction>(), 64);
}
#[test]
fn test_instruction_alignment() {
assert_eq!(mem::align_of::<Instruction>(), 64);
}
#[test]
fn test_sphere_instruction() {
let inst = Instruction::sphere(1.5);
assert_eq!(inst.opcode, OpCode::Sphere);
assert_eq!(inst.params[0], 1.5);
}
#[test]
fn test_box_instruction() {
let inst = Instruction::box3d(1.0, 2.0, 3.0);
assert_eq!(inst.opcode, OpCode::Box3d);
assert_eq!(inst.params[0], 1.0);
assert_eq!(inst.params[1], 2.0);
assert_eq!(inst.params[2], 3.0);
}
#[test]
fn test_translate_instruction() {
let inst = Instruction::translate(1.0, 2.0, 3.0);
assert_eq!(inst.opcode, OpCode::Translate);
assert_eq!(inst.child_count, 1);
}
#[test]
fn test_capsule_stores_radius() {
let inst = Instruction::capsule(0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.5);
assert_eq!(inst.opcode, OpCode::Capsule);
assert!((inst.get_capsule_radius() - 0.5).abs() < 1e-10);
}
#[test]
fn test_is_leaf() {
assert!(Instruction::sphere(1.0).is_leaf());
assert!(Instruction::box3d(1.0, 1.0, 1.0).is_leaf());
assert!(Instruction::capsule(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.3).is_leaf());
assert!(Instruction::union().is_leaf());
assert!(Instruction::smooth_union(0.1).is_leaf());
assert!(!Instruction::translate(1.0, 0.0, 0.0).is_leaf());
assert!(!Instruction::scale(2.0).is_leaf());
assert!(!Instruction::twist(0.5).is_leaf());
}
#[test]
fn test_next_instruction_index() {
let sphere = Instruction::sphere(1.0);
assert_eq!(sphere.next_instruction_index(0), 1);
assert_eq!(sphere.next_instruction_index(5), 6);
let mut translate = Instruction::translate(1.0, 0.0, 0.0);
translate.skip_offset = 10;
assert_eq!(translate.next_instruction_index(0), 10);
assert_eq!(Instruction::pop_transform().next_instruction_index(7), 8);
assert_eq!(Instruction::end().next_instruction_index(3), 4);
}
}