Scripting files for Arbgeom, August 13, 2024


Since I haven't put out an update in a long time, I wanted to show off what the scripting files will look like for Arbgeom.  I've attached the current assets file and pasted some of the .  I'm still developing right now so some of these files might be a little jank/incomplete/broken. Also it looks like itch.io mangled some of the generic arguments on the geometry description files, so it should look like this: <shape: Proj+Sdf>.  

Geometry Descriptions: Structured Scaffolding Language

Language Requirements:

  • Needs to be interpreted by rust (for physics) and compiled into wgsl (for rendering) -- CHECK
  • Allow for nesting of different objects -- CHECK
  • Lightweight -- CHECK
  • Fast & Optimized -- CHECK-ish, WIP (much faster than using rhai for this though)
    • Hard to do since the optimizations need to be done at the AST level for rust to interpret and to be turned into WGSL which is then compiled.

Basic shapes:

class Plane4D {
    normal: vec4,
    Proj::proj(vector: vec4) -> vec4 {
        vector - normal * dot(vector, normal)
    },
    Sdf::sdf(vector: vec4) -> f32 {
        dot(vector, normal)
    },
    Aabb::aabb() -> (vec4, vec4) {
        (-INFINITY * ONES, INFINITY * ONES)
    }
}
class Box4D {
    size: vec4,
    Proj::proj(vector: vec4) -> vec4 {
        let q: vec4 = abs(vector) - size;
        let add_to_proj: vec4 = select(
            select(
                select(vec4(0, 0, 0, -q.w), vec4(0, 0, -q.z, 0),
                    q.z > q.w
                ), vec4(0, -q.y, 0, 0),
                (q.y > q.z) && (q.y > q.w)
            ), vec4(-q.x, 0, 0, 0),
            q.x > q.y && q.x > q.z && q.x > q.w
        );
        select(
            {
                let proj: vec4 = abs(vector);
                proj = proj + add_to_proj;
                proj * sign(vector)
            },
            min(abs(vector), size) * sign(vector),
            length(max(q, vec4(0, 0, 0, 0))) > 0.0000001
        )
    },
    Sdf::sdf(vector: vec4) -> f32 {
        let q: vec4 = abs(vector) - size;
        let max_q: f32 = max(
            max(q.x, q.y),
            max(q.z, q.w)
        );
        length(max(q, vec4(0, 0, 0, 0))) + min(max_q, 0.0)
    },
    Aabb::aabb() -> (vec4, vec4) {
        (-size, size)
    }
}
class Sphere4D {
    radius: f32,
    Proj::proj(vector: vec4) -> vec4 {
        radius * normalize(vector + vec4(0.000001, 0.0, 0.0, 0.0))
    },
    Sdf::sdf(vector: vec4) -> f32 {
        length(vector) - radius
    },
    Aabb::aabb() -> (vec4, vec4) {
        (-radius * ONES, radius * ONES)
    }
}
class Ditorus {
    r01: f32,
    r012: f32,
    r0123: f32,
    Proj::proj(vector: vec4) -> vec4 {
        let proj1: vec4 = r01 * normalize(vec4(vector.x, vector.y, 0.0, 0.0));
        let proj2: vec4 = r012 * normalize(vec4(vector.x, vector.y, vector.z, 0.0) - proj1);
        let proj3: vec4 = r0123 * normalize(vector - proj2 - proj1);
        proj3 + proj2 + proj1
    },
    Sdf::sdf(vector: vec4) -> f32 {
        let proj1: vec4 = r01 * normalize(vec4(vector.x, vector.y, 0.0, 0.0));
        let proj2: vec4 = r012 * normalize(vec4(vector.x, vector.y, vector.z, 0.0) - proj1);
        length(vector - proj1 - proj2) - r0123
    },
    Aabb::aabb() -> (vec4, vec4) {
        (-r01 - r012 - r0123, r01 + r012 + r0123)
    }
}
class Torisphere {
    r012: f32,
    r0123: f32,
    Proj::proj(vector: vec4) -> vec4 {
        let proj1: vec4 = r012 * normalize(vec4(vector.x, vector.y, vector.z, 0.0));
        proj1 + r0123 * normalize(vector - proj1)
    },
    Sdf::sdf(vector: vec4) -> f32 {
        let proj1: vec4 = r012 * normalize(vec4(vector.x, vector.y, vector.z, 0.0));
        length(vector - proj1) - r0123
    },
    Aabb::aabb() -> (vec4, vec4) {
        ((-r012 - r0123) * ONES, (r012 + r0123) * ONES)
    }
}
class Spheritorus {
    r01: f32,
    r0123: f32,
    Proj::proj(vector: vec4) -> vec4 {
        let proj1: vec4 = r01 * normalize(vec4(vector.x, vector.y, 0.0, 0.0));
        proj1 + r0123 * normalize(vector - proj1)
    },
    Sdf::sdf(vector: vec4) -> f32 {
        let proj1: vec4 = r01 * normalize(vec4(vector.x, vector.y, 0.0, 0.0));
        length(vector - proj1) - r0123
    },
    Aabb::aabb() -> (vec4, vec4) {
        ((-r01 - r0123) * ONES, (r01 + r0123) * ONES)
    }
}
class Nothing {
    Proj::proj(vector: vec4) -> vec4 {
        vec4(1000000, 10000000, 1000000, 1000000)
    },
    Sdf::sdf(vector: vec4) -> f32 {
        1000000000.0
    },
    Aabb::aabb() -> (vec4, vec4) {
        (INFINITY * ONES, -INFINITY * ONES)
    }
}
class Marker {
    Proj::proj(vector: vec4) -> vec4 {
        vec4(0, 0, 0, 0)
    },
    Sdf::sdf(vector: vec4) -> f32 {
        length(vector)
    },
    Aabb::aabb() -> (vec4, vec4) {
        (vec4(0, 0, 0, 0), vec4(0, 0, 0, 0))
    }
}

Operations:

class Shell {
    offset: f32,
    shape: Class,
    Proj::proj<shape: Proj>(vector: vec4) -> vec4 {
        let proj: vec4 = shape.proj(vector);
        proj + offset * normalize(vector - proj)
    },
    Sdf::sdf<shape: Sdf>(vector: vec4) -> f32 {
        abs(shape.sdf(vector)) - offset
    },
    Aabb::aabb<shape: Aabb>() -> (vec4, vec4) {
        let aabb: (vec4, vec4) = shape.aabb();
        (-offset * ONES + aabb.0, offset * ONES + aabb.1)
    }
}
class Extrude {
    direction: vec4,
    shape: Class,
    Proj::proj<shape: proj="">(vector: vec4) -> vec4 {
        let dot: f32 = dot(vector, direction);
        direction * dot + shape.proj(vector - direction * dot)
    },
    Sdf::sdf<shape: sdf="">(vector: vec4) -> f32 {
        let dot: f32 = dot(vector, direction);
        shape.sdf(vector - direction * dot)
    },
    Aabb::aabb() -> (vec4, vec4) {
        (-INFINITY * ONES, INFINITY * ONES)
    }
}
class Shift {
    shift: vec4,
    shape: Class,
    Proj::proj<shape: proj="">(vector: vec4) -> vec4 {
        shape.proj(vector - shift) + shift
    },
    Sdf::sdf<shape: sdf="">(vector: vec4) -> f32 {
        shape.sdf(vector - shift)
    },
    Aabb::aabb<shape: aabb="">() -> (vec4, vec4) {
        let aabb: (vec4, vec4) = shape.aabb();
        (aabb.0 + shift, aabb.1 + shift)
    }
}
// TODO: Need to add support for precomputed data like orientation & inverted_orientation
class Reorient {
    inv_orientation: mat4x4,
    shape: Class,
    Proj::proj<shape: proj="">(vector: vec4) -> vec4 {
        shape.proj(inv_orientation * vector)
    },
    Sdf::sdf<shape: sdf="">(vector: vec4) -> f32 {
        shape.sdf(inv_orientation * vector)
    },
    // TODO: Improve this later, by actually computing the new AABB
    Aabb::aabb<shape: aabb="">() -> (vec4, vec4) {
        (-INFINITY * ONES, INFINITY * ONES)
    }
}
class Invert {
    shape: Class,
    Proj::proj<shape: proj="">(vector: vec4) -> vec4 {
        shape.proj(vector)
    },
    Sdf::sdf<shape: sdf="">(vector: vec4) -> f32 {
        -shape.sdf(vector)
    },
    Aabb::aabb<shape: aabb="">() -> (vec4, vec4) {
        shape.aabb()
    }
}
// TODO: Falls apart in some cases, needs improvement
class Intersect {
    shape1: Class,
    shape2: Class,
    Proj::proj<shape1: proj="" +="" sdf,="" shape2:="" sdf="">(vector: vec4) -> vec4 {
        let proj1: vec4 = shape1.proj(vector);
        let proj2: vec4 = shape2.proj(vector);
        let proj3: vec4 = shape2.proj(proj1);
        let sdf1: f32 = shape1.sdf(vector);
        let sdf2: f32 = shape2.sdf(vector);
        select(
            select(proj2, proj1, sdf1 > sdf2),
            proj3,
            sign(sdf1) == sign(sdf2)
        )
    },
    Sdf::sdf<shape1: sdf="" +="" proj,="" shape2:="" proj="">(vector: vec4) -> f32 {
        let proj1: vec4 = shape1.proj(vector);
        let proj2: vec4 = shape2.proj(vector);
        let proj3: vec4 = shape2.proj(proj1);
        let sdf1: f32 = shape1.sdf(vector);
        let sdf2: f32 = shape2.sdf(vector);
        select(
            select(length(proj2) * sign(sdf2), length(proj1) * sign(sdf1), sdf1 > sdf2),
            length(proj3) * sign(sdf1),
            sign(sdf1) == sign(sdf2)
        )
    },
    Aabb::aabb<shape1: aabb,="" shape2:="" aabb="">() -> (vec4, vec4) {
        let aabb1: (vec4, vec4) = shape1.aabb();
        let aabb2: (vec4, vec4) = shape2.aabb();
        (max(aabb1.0, aabb2.0), min(aabb1.1, aabb2.1))
    }
}
// TODO: Doesn't work at all :(
class Interpolate {
    shape1: Class,
    shape2: Class,
    t: f32,
    Proj::proj<shape1: Proj + sdf, shape2= Sdf>(vector: vec4) -> vec4 {
        let d1: vec4 = vector - shape1.proj(vector);
        let l1: f32 = shape1.sdf(vector);
        let d2: vec4 = vector - shape2.proj(vector);
        let l2: f32 = shape2.sdf(vector);
        let cur_t: f32 = l1 / (l1 + l2);
        let dot: f32 = dot(d1, d2) / (l1 * l2);
        select(
            vector + d1 / l1 * (l2 * t - l1 * (1 - t)) / (1 - t - dot * t),
            vector + d2 / l2 * (l2 * t - l1 * (1 - t)) / (dot - dot * t - t),
            cur_t < t
        )
    },
}
/*
[IGNORE]
OLD operations.rhai FILE:
//! shell { offset: f32, shape: Shape }
fn shell_proj(shape_proj, offset, vector) {
    let proj = shape_proj.call(vector);
    proj + offset * (vector - proj).normalize()
}
fn shell_sdf(shape_sdf, offset, vector) {
    -offset + abs(shape_sdf.call(vector))
}
//! extrude { direction: Vec4, shape: Shape }
fn extrude_proj(shape_proj, direction, vector) {
    let dot = vector.dot(direction);
    direction * dot + shape_proj.call(vector - direction * dot)
}
fn extrude_sdf(shape_sdf, direction, vector) {
    let dot = vector.dot(direction);
    shape_sdf.call(vector - direction * dot)
}
//! shift { shift: Vec4, shape: Shape }
fn shift_proj(shape_proj, shift, vector) {
    shift + shape_proj.call(vector - shift)
}
fn shift_sdf(shape_sdf, shift, vector) {
    shape_sdf.call(vector - shift)
}
//! reorient { inv_orientation: Mat4, shape: Shape }
fn reorient_proj(shape_proj, inv_orientation, vector) {
    shape_proj.call(inv_orientation * vector)
}
fn reorient_sdf(shape_sdf, inv_orientation, vector) {
    shape_sdf.call(inv_orientation * vector)
}
//! invert { shape: Shape }
fn invert_proj(shape_proj, vector) {
    shape_proj.call(vector)
}
fn invert_sdf(shape_sdf, vector) {
    -shape_sdf.call(vector)
}
fn invert_aabb() {
    [vec4(-100000000, -100000000, -100000000, -100000000), vec4(100000000, 100000000, 100000000, 100000000)]
}
//! intersection { shape1: Shape, shape2: Shape }
fn intersection_proj(shape1_proj, shape2_proj, shape1_sdf, shape2_sdf, vector) {
    let proj1 = shape1_proj.call(vector);
    let proj2 = shape2_proj.call(vector);
    let proj3 = shape2_proj.call(proj1);
    let sdf1 = shape1_sdf.call(vector);
    let sdf2 = shape2_sdf.call(vector);
    select(
        select(proj2, proj1, sdf1 > sdf2),
        proj3,
        sign(sdf1) == sign(sdf2)
    )
}
fn intersection_sdf(shape1_proj, shape2_proj, shape1_sdf, shape2_sdf, vector) {
    let proj1 = shape1_proj.call(vector);
    let proj2 = shape2_proj.call(vector);
    let proj3 = shape2_proj.call(proj1);
    let sdf1 = shape1_sdf.call(vector);
    let sdf2 = shape2_sdf.call(vector);
    select(
        select(length(proj2) * sign(sdf2), length(proj1) * sign(sdf1), sdf1 > sdf2),
        length(proj3) * sign(sdf1),
        sign(sdf1) == sign(sdf2)
    )
}
fn intersection_aabb() {
    [vec4(-100000000, -100000000, -100000000, -100000000), vec4(100000000, 100000000, 100000000, 100000000)]
}
*/
</shape1:></shape1:></shape1:></shape1:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:></shape:>

Combined:

class Wormhole {
    shape: Class,
    offset: f32,
} => Shell {
     offset,
     shape: Intersect {
         shape1: Shell {
             shape: Plane4D {
                 normal: vec4(0, 0, 0, 1)
             },
             offset: 0
         },
         shape2: Invert {
             shape: Extrude {
                 direction: vec4(0, 0, 0, 1),
                 shape
             }
         }
     }
 }
class WormholeWrapped {
    shape: Class,
    offset: f32,
    dist: f32
} => Shell {
    offset,
    shape: Intersect {
        shape1: Intersect {
            shape1: Shell {
                shape: Plane4D { normal: vec4(0, 0, 0, 1) },
                offset: 0
            },
            shape2: Shift {
                shift: vec4(0, 0, dist, 0),
                shape: Plane4D { normal: vec4(0, 0, 1, 0) }
            }
        },
        shape2: Invert {
            shape: Extrude {
                direction: vec4(0, 0, 0, 1),
                shape
            }
        }
    }
}

Complex: 

class Portal {
    width: f32,
    height: f32,
    bridge_radius: f32,
    cutout_size: f32,
    Proj::proj(vector: vec4) -> vec4 {
        let bend_proj: vec4 = bridge_radius * normalize(vec4(0.0, 0.0, vector.z, vector.w)) + vec4(vector.x, vector.y, 0.0, 0.0);
        let plane_proj: vec4 = vec4(vector.x, vector.y, vector.z, bridge_radius * sign(vector.w));
        let is_in_cutout: bool = abs(vector.x) < width &&
            abs(vector.y) < height &&
            0 < vector.z && vector.z < cutout_size;
        select(
            plane_proj, bend_proj,
            abs(vector.w) < bridge_radius - 0.1 || is_in_cutout
        )
    },
    // TODO: Sdf shouldn't be required just because the parent impls it! (Same for other fns)
    Sdf::sdf(vector: vec4) -> f32 {
        0
    },
    Aabb::aabb() -> (vec4, vec4) {
        (ZERO, ZERO)
    }
}

Sdf_only:

class Fence {
    spacing: f32,
    thickness: f32,
    size: vec4,
    Sdf::sdf(vector: vec4) -> f32 {
        let v: vec4 = vector - spacing * round(clamp(vector, -size, size) / spacing);
        v = vec4(v.x, v.y, vector.z, v.w);
        let v1: vec4 = v - vec4(v.x, 0, 0, 0);
        let v2: vec4 = v - vec4(0, v.y, 0, 0);
        min(length(v1) - thickness, length(v2) - thickness)
    },
    // TODO: In the future you should only try to load what you can, but I'll just give a wrong implementation for now
    Proj::proj(vector: vec4) -> vec4 {
        vector
    },
}
class ReorientSdf {
    inv_orientation: mat4x4,
    shape: Class,
    Sdf::sdf<shape: sdf="">(vector: vec4) -> f32 {
        shape.sdf(inv_orientation * vector)
    },
}

Level Descriptions: Rusty Object Notation (RON) (with some pre-processing)

Language Requirements:

  • Customizable and able to ergonomically hold shape data -- CHECK
  • Easy to extend with preprocessor -- CHECK

Test world:

World(
    name: "Dev world",
    description: "A bunch of levels I created to help test/debug the game or just to explore what the system can do...",
    levels: [
        Level(
            name: "Plane",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Plane4D(normal: [0, 0, 0, 1]),
            spawn_pose: Pose(position: [30, 30, 0, 0]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "gray"
                ),
            ]
        ),
        Level(
            name: "Many much wormholen",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            // TODO: Because wormhole is an instance class it breaks when other classes use it
            manifold: Wormhole(
                shape: Sphere4D(radius: 20),
                offset: 10
            ),
            spawn_pose: Pose(position: [0, 10, 30, 10]),
            geometries: [
                /*Geometry(
                    pose: Pose(position: [0, 10, -30, 10]),
                    shape: Sphere4D(radius: 5),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),*/
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [60, 40, 60, 60])),
                    material: "basic",
                ),
            ]
        ),
        Level(
            name: "Cup",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Shell(
                offset: 5,
                shape: Intersect(
                    shape1: Plane4D( normal: [0, 0, 0, 1] ),
                    shape2: Invert(shape: Shell(
                        offset: 10,
                        shape: Box4D(size: [10, 5, 10, 40])
                    ))
                )
            ),
            spawn_pose: Pose(position: [80, 0, 0, 10]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, 0, 0, 0]),
                    shape: Invert(shape: Box4D(size: [90, 40, 60, 60])),
                    material: "basic"
                ),
            ]
        ),
        Level(
            name: "Bare Portal",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Portal( width: Expr("qe+10"), height: Expr("tg+20"), bridge_radius: Expr("ol+20"), cutout_size: Expr("uj+6") ),
            spawn_pose: Pose(position: [40, 10, 0, 30]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [90, 40, 60, 60])),
                    material: "basic"
                ),
                Geometry(
                    pose: Pose(position: [-40, 40, -40, 20]),
                    shape: ReorientSdf(
                        inv_orientation: [[.707107, .707107, 0, 0], [-.707107, .707107, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
                        shape: Fence(spacing: 2, thickness: 0.04, size: [100, 100, 100, 3])
                    ),
                    collider: Box4D(size: [100, 100, 0.1, 3]),
                    material: "basic",
                    color: "gray"
                ),
                /*Geometry(
                    pose: Pose(position: [-30, 10, 0, -30]),
                    shape: Sphere4D(radius: 5),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),*/
            ]
        ),
        Level(
            name: "Portal??",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Portal( width: 10.0, height: 20.0, bridge_radius: 20.0, cutout_size: 6.0 ),
            spawn_pose: Pose(position: [40, 10, 0, 30]),
            geometries: [
                Geometry(
                    pose: Pose(position: [10.0, 0.0, 3.4, 0]),
                    shape: Box4D(size: [0.4, 20.0, 3.4, 60]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [-10.0, 0.0, 3.4, 0]),
                    shape: Box4D(size: [0.4, 20.0, 3.4, 60]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [0.0, 20.0, 3.4, 0]),
                    shape: Box4D(size: [10.0, 0.4, 3.4, 60]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [-10.0, 0.0, 10.0, 0]),
                    shape: Box4D(size: [0.4, 20.0, 10.0, 19.0]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [10.0, 0.0, 10.0, 0]),
                    shape: Box4D(size: [0.4, 20.0, 10.0, 19.0]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [0.0, 20.0, 10.0, 0]),
                    shape: Box4D(size: [10.0, 0.4, 10.0, 19.0]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [0.0, 0.0, 6.0, 20]),
                    shape: Box4D(size: [10.4, 20.4, 0.7, 0.1]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [0.0, 0.0, 6.0, -20]),
                    shape: Box4D(size: [10.0, 20.0, 0.4, 0.1]),
                    material: "rough"
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [90, 40, 60, 60])),
                    material: "basic"
                ),
                Geometry(
                    pose: Pose(position: [-40, 40, -40, 20]),
                    shape: ReorientSdf(
                        inv_orientation: [[.707107, .707107, 0, 0], [-.707107, .707107, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
                        shape: Fence(spacing: 2, thickness: 0.04, size: [100, 100, 100, 3])
                    ),
                    collider: Box4D(size: [100, 100, 0.1, 3]),
                    material: "basic",
                    color: "gray"
                ),
                Geometry(
                    pose: Pose(position: [-30, 10, 0, -30]),
                    shape: Sphere4D(radius: 1),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
            ]
        ),
        Level(
            name: "Plane",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Plane4D(normal: [0, 0, 0, 1]),
            spawn_pose: Pose(position: [30, 30, 0, 0]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-30, 10, 0, 0]),
                    shape: Sphere4D(radius: Expr("0.5*sin(t)+3")),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "gray"
                ),
            ]
        ),
        Level(
            name: "Wormhole gun",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            // TODO: Because wormhole is an instance class it breaks when other classes use it
            manifold: Wormhole(
                shape: Shift(shift: Expr("(vec4(20, 0, select(-20, 20, sin(t) > 0), 0))"), shape: Sphere4D(radius: Expr("abs(20*sin(t))"))),
                offset: Expr("tg + 10")
            ),
            spawn_pose: Pose(position: [0, 10, 30, 10]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, 10, -30, 10]),
                    shape: Sphere4D(radius: 5),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [60, 40, 60, 60])),
                    material: "basic",
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 10]),
                    shape: ReorientSdf(
                        inv_orientation: [[.707107, .707107, 0, 0], [-.707107, .707107, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
                        shape: Fence(spacing: 2, thickness: 0.04, size: [100, 100, 100, 3])
                    ),
                    collider: Box4D(size: [100, 100, 0.1, 3]),
                    material: "basic",
                    color: "gray"
                ),
            ]
        ),
        Level(
            name: "Wormhole gun cube-ey",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            // TODO: Because wormhole is an instance class it breaks when other classes use it
            manifold: Wormhole(
                shape: Shift(
                    shift: Expr("(vec4(20, -10, select(-30, 30, sin(t/3) > 0), 0))"),
                    shape: Shell(
                        offset: 11,
                        shape: Box4D(size: Expr("vec4(0.1, 40*abs(sin(t/3)), 10, 100)"))
                    )
                ),
                offset: 10
            ),
            spawn_pose: Pose(position: [0, 10, 30, 10]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, 10, -30, 10]),
                    shape: Sphere4D(radius: 5),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [60, 40, 60, 60])),
                    material: "basic",
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 10]),
                    shape: ReorientSdf(
                        inv_orientation: [
                            [.707107, .707107, 0, 0],
                            [-.707107, .707107, 0, 0],
                            [0, 0, 1, 0],
                            [0, 0, 0, 1]
                        ],
                        shape: Fence(spacing: 2, thickness: 0.04, size: [100, 100, 100, 3])
                    ),
                    collider: Box4D(size: [100, 100, 0.1, 3]),
                    material: "basic",
                    color: "gray"
                ),
            ]
        ),
        Level(
            name: "Wormhole gun portally",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Shift(
                shift: Expr("vec4(select(-30, 30, sin(t/3) > 0), 0, 20, 0)"),
                shape: Portal( width: 10.0, height: Expr("30*abs(sin(t/3))"), bridge_radius: 10.0, cutout_size: 6.0 )
            ),
            spawn_pose: Pose(position: [30, 10, 0, 10]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-30, 10, 0, 10]),
                    shape: Sphere4D(radius: 5),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [60, 40, 60, 60])),
                    material: "basic",
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 10]),
                    shape: ReorientSdf(
                        inv_orientation: [
                            [0, 0, 1, 0],
                            [-.707107, .707107, 0, 0],
                            [.707107, .707107, 0, 0],
                            [0, 0, 0, 1]
                        ],
                        shape: Fence(spacing: 2, thickness: 0.04, size: [100, 100, 100, 3])
                    ),
                    collider: Box4D(size: [0.1, 100, 100.0, 3]),
                    material: "basic",
                    color: "gray"
                ),
            ]
        ),
        Level(
            name: "Interp pt.2",
            description: "more desc >:D muahahaha",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Shell(
                shape: Box4D(size: [25, 25, 25, 25]),
                offset: Expr("qe + 5")
            ),
            spawn_pose: Pose(position: [30, 30, 0, 0]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-100, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "pink"
                ),
                Geometry(
                    pose: Pose(position: [100, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "gray",
                    id: "floor"
                ),
            ]
        ),
        Level(
            name: "Wormulous Holicules",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: WormholeWrapped(
                shape: Sphere4D(radius: Expr("qe + 10")),
                offset: Expr("tg + 5"),
                dist: Expr("tg + 10")
            ),
            spawn_pose: Pose(position: [30, 30, 0, 5]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-30, 10, 0, -5]),
                    shape: Sphere4D(radius: Expr("0.5*sin(t)+3")),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "gray",
                    id: "floor"
                ),
            ]
        ),
        Level(
            name: "Wormulous Holicules -- Cube",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: WormholeWrapped(
                shape: Shell(offset: Expr("tg + 6 + qe"), shape: Box4D(size: Expr("vec4(ol + 5, 20 * yh + 5, ik + 5, 5)"))),
                offset: Expr("tg + 5"),
                dist: Expr("uj + 30")
            ),
            spawn_pose: Pose(position: [30, 30, 0, 5]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-30, 10, 0, -5]),
                    shape: Sphere4D(radius: Expr("0.5*sin(t)+3")),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [50, 40, 50, 50])),
                    material: "basic",
                    id: "floor"
                ),
            ]
        ),
        Level(
            name: "Wormulous Holicules -- Cube no rounding",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: WormholeWrapped(
                shape: Box4D(size: Expr("vec4(10*qe + 20, 20 * tg + 20, 10*yh + 20, 10)")),
                offset: Expr("uj + 5"),
                dist: Expr("ik + 40")
            ),
            spawn_pose: Pose(position: [30, 30, 0, 5]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-30, 10, 0, -5]),
                    shape: Sphere4D(radius: 3),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [60, 40, 60, 60])),
                    material: "basic",
                    id: "floor"
                ),
            ]
        ),
        Level(
            name: "Wormulous Holicules -- Torus",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: WormholeWrapped(
                shape: Shift(shift: Expr("vec4(5 * uj, 5 * qe, 5 * tg, 0)"), shape: Spheritorus(r01: 15, r012: 10, r0123: 10)),
                offset: Expr("ik + 5"),
                dist: 30
            ),
            spawn_pose: Pose(position: [30, 30, 0, 5]),
            geometries: [
                Geometry(
                    pose: Pose(position: [100, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "gray"
                ),
                Geometry(
                    pose: Pose(position: [-100, -3, 0, -100]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "purple"
                ),
                Geometry(
                    pose: Pose(position: [-100, -3, 100, 100]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "orange"
                ),
            ]
        ),
        Level(
            name: "Weird cut in box",
            description: "more desc >:D muahahaha",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Shell( offset: 10, shape: Intersect( shape1: Intersect(
                shape1: Box4D(size: [25, 25, 25, 25]),
                shape2: Invert( shape: Shell(
                    shape: Shift( shift: [25, 0, 25, 25], shape: Box4D(size: [30, 30, 30, 30])),
                    offset: 20
                ))
            ), shape2: Invert(shape: Shift(shift: [0, 0, 0, -25], shape: Sphere4D(radius: 15))))),
            spawn_pose: Pose(position: [-30, 30, 0, 0]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-100, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "pink"
                ),
                Geometry(
                    pose: Pose(position: [100, -3, 0, 0]),
                    shape: Box4D(size: [100, 3, 100, 100]),
                    material: "basic",
                    color: "gray"
                ),
                Geometry(
                    pose: Pose(position: [-30, 10, 0, 0]),
                    shape: Sphere4D(radius: 5),
                    material: "basic",
                    color: "yellow",
                    is_dynamic: true
                ),
            ]
        ),
        Level(
            name: "Spherical test",
            description: "ABCD",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Sphere4D(radius: 30),
            spawn_pose: Pose(position: [30, 30, 0, 0]),
            geometries: [
                Geometry(
                    pose: Pose(position: [-30, 0, 0, 0]),
                    shape: Sphere4D(radius: Expr("0.5*sin(t)+3")),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, -1000, 0, 0]),
                    shape: Sphere4D(radius: 1000),
                    material: "basic",
                    color: "gray"
                ),
                // Geometry(
                //     pose: Pose(position: [0, -3, 0, 0]),
                //     shape: Box4D(size: [100, 3, 100, 100]),
                //     material: "basic",
                //     color: "gray"
                // ),
            ]
        ),
        Level(
            name: "RUNNN!!",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Wormhole(
                shape: Sphere4D(radius: Expr("max(0, 200 * cos(2 * 3.141592 * t / 20))")),
                offset: 20
            ),
            spawn_pose: Pose(position: [0, 5, -150, 20]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, 5, -200, -20]),
                    shape: Sphere4D(radius: 3),
                    material: "basic",
                    color: "pink",
                    is_dynamic: true
                ),
                Geometry(
                    pose: Pose(position: [0, -0.5, 0, 0]),
                    shape: Box4D(size: [5, 0.5, 1000, 100]),
                    material: "basic",
                    color: "gray"
                ),
                Geometry(
                    pose: Pose(position: [0, -0.9999, -200, -200]),
                    shape: Box4D(size: [10, 1, 10, 200]),
                    material: "basic",
                    color: "red"
                ),
                Geometry(
                    pose: Pose(position: [0, 0, -110, 0]),
                    shape: Invert(shape: Box4D(size: [80, 80, 110, 80])),
                    material: "basic"
                ),
            ]
        ),
        Level(
            name: "Failed Tube -- intersection is hard :(",
            description: "more desc >:D",
            scripts: ["worlds/test_world/script1.rhai"],
            manifold: Plane4D(normal: [0, 0, 0, 1]),
            spawn_pose: Pose(position: [0, 10, 0, 0]),
            geometries: [
                Geometry(
                    pose: Pose(position: [0, 40, 0, 0]),
                    shape: Invert(shape: Box4D(size: [50, 40, 50, 80])),
                    material: "basic"
                ),
                Geometry(
                    pose: Pose(position: [30, 0, 0, 0]),
                    shape: Intersect(
                        shape1: Plane4D(normal: [0, 0, 1, 0]),
                        shape2: Shell(
                            offset: 1,
                            shape: Sphere4D(radius: 10)
                        )
                    ),
                    material: "basic"
                ),
            ]
        ),
    ]
)

Scripting: Rhai

Language Requirements:

  • Easy to integrate into the game loop -- CHECK
  • Nice APIs -- CHECK
  • Able to interact nicely with rust structs and data -- CHECK

Test World Script (script1.rhai):

let qe = 0;
let tg = 0;
let yh = 0;
let uj = 0;
let ik = 0;
let ol = 0;
fn init() {
    print("init called from rhai");
}
fn update() {
    if "floor" in geometries {
        geometries["floor"].pose.position.y = ol;
    }
}
fn on_key_press_q() {
    print("q pressed");
    qe += 0.1;
}
fn on_key_press_e() {
    print("e pressed");
    qe -= 0.1;
}
fn on_key_press_t() {
    print("t pressed");
    tg += 0.1;
}
fn on_key_press_g() {
    print("g pressed");
    tg -= 0.1;
}
fn on_key_press_y() {
    print("y pressed");
    yh += 0.1;
}
fn on_key_press_h() {
    print("h pressed");
    yh -= 0.1;
}
fn on_key_press_u() {
    print("u pressed");
    uj += 0.1;
}
fn on_key_press_j() {
    print("j pressed");
    uj -= 0.1;
}
fn on_key_press_i() {
    print("i pressed");
    ik += 0.1;
}
fn on_key_press_k() {
    print("k pressed");
    ik -= 0.1;
}
fn on_key_press_o() {
    print("o pressed");
    ol += 0.1;
}
fn on_key_press_l() {
    print("l pressed");
    ol -= 0.1;
}

Assets Dowload

If you want to download the assets folder to play around with it is available here

Get Arbgeom beta

Comments

Log in with itch.io to leave a comment.

How do I enter the test/dev worlds exactly?

Wait i forgot it was hardcoded! never mind, take your time though