saft-sdf 0.2.1

Signed distance field function library
Documentation
#line 0

#define Opcode_Plane          0 // vec4
#define Opcode_Sphere         1 // center: vec3, radius: f32
#define Opcode_Capsule        2 // p0: vec3, p1: vec3, radius: f32
#define Opcode_TaperedCapsule 3 // p0: vec3, p1: vec3, radius: f32
#define Opcode_Material       4 // rgb: vec3

// Combinators:
#define Opcode_Union           5
#define Opcode_UnionSmooth     6
#define Opcode_Subtract        7
#define Opcode_SubtractSmooth  8
#define Opcode_Intersect       9
#define Opcode_IntersectSmooth 10

// Transforms:
#define Opcode_PushTranslation 11
#define Opcode_PushRotation    12
#define Opcode_PopTransform    13
#define Opcode_PushScale       14
#define Opcode_PopScale        15

#define Opcode_End 16

#define Opcode_RoundedBox      17
#define Opcode_BiconvexLens    18
#define Opcode_RoundedCylinder 19
#define Opcode_Torus           20
#define Opcode_TorusSector     21
#define Opcode_Cone            22

// Using a subset of opcodes here would allow to make a stackless
// batched interpreter that basically runs the vm at a kernel dispatch level
// and runs each instruction for every grid node.

float read_float(inout uint cp) {
    return SDF_CONSTANTS[cp++];
}

vec2 read_vec2(inout uint cp) {
    return vec2(SDF_CONSTANTS[cp++], SDF_CONSTANTS[cp++]);
}

vec3 read_vec3(inout uint cp) {
    return vec3(SDF_CONSTANTS[cp++], SDF_CONSTANTS[cp++], SDF_CONSTANTS[cp++]);
}

vec4 read_vec4(inout uint  cp) {
    return vec4(SDF_CONSTANTS[cp++], SDF_CONSTANTS[cp++], SDF_CONSTANTS[cp++], SDF_CONSTANTS[cp++]);
}

vec4 sdrgb_interpret(vec3 pos, uint opcodes_offset, uint constants_offset) {
    uint sp = 0;
    uint cp = constants_offset;
    uint pc = opcodes_offset;

    vec4 stack[64];

    uint transform_sp = 0;
    vec3 transform_stack[64];

    vec3 current_position = pos;

    while (true) {
    //while (pc < SDF_OPCODES.length()) {
        uint opcode = SDF_OPCODES[pc++];

        switch (opcode) {
            case Opcode_Plane: {
                vec4 plane = read_vec4(cp);
                stack[sp++] = sdrgb_plane(current_position, plane);
            }
            break;

            case Opcode_Sphere: {
                vec3 center = read_vec3(cp);
                float radius = read_float(cp);
                stack[sp++] = sdrgb_sphere(current_position, center, radius);
            }
            break;

            case Opcode_Capsule: {
                vec3 p0 = read_vec3(cp);
                vec3 p1 = read_vec3(cp);
                float radius = read_float(cp);
                stack[sp++] = sdrgb_capsule(current_position, p0, p1, radius);
            }
            break;

            case Opcode_RoundedCylinder: {
                float radius = read_float(cp);
                float height = read_float(cp);
                float rounding = read_float(cp);
                stack[sp++] = sdrgb_rounded_cylinder(current_position,
                                                   radius,
                                                   height,
                                                   rounding);
            }
            break;

            case Opcode_TaperedCapsule: {
                vec3 p0 = read_vec3(cp);
                float r0 = read_float(cp);
                vec3 p1 = read_vec3(cp);
                float r1 = read_float(cp);
                stack[sp++] = sdrgb_tapered_capsule(current_position, p0, p1, r0, r1);
            }
            break;

            case Opcode_Cone: {
                vec2 q = read_vec2(cp);
                stack[sp++] = sdrgb_cone(current_position, q.x, q.y);
            }
            break;

            case Opcode_RoundedBox: {
                vec3 half_size = read_vec3(cp);
                float radius = read_float(cp);
                stack[sp++] = sdrgb_rounded_box(current_position, half_size, radius);
            }
            break;

            case Opcode_Torus: {
                vec2 q = read_vec2(cp);
                stack[sp++] = sdrgb_torus(current_position, q.x, q.y);
            }
            break;

            case Opcode_TorusSector: {
                vec4 params = read_vec4(cp);
                stack[sp++] = sdrgb_torus_sector(current_position, params[0], params[1], vec2(params[2], params[3]));
            }
            break;

            case Opcode_BiconvexLens: {
                float lower = read_float(cp);
                float upper = read_float(cp);
                float chord = read_float(cp);
                stack[sp++] = sdrgb_biconvex_lens(current_position, lower, upper, chord);
            }
            break;

            case Opcode_Material: {
                vec3 rgb = read_vec3(cp);
                stack[sp - 1].rgb = rgb.rgb;
            }
            break;

            // Combinators:
            case Opcode_Union: {
                sp -= 1;
                stack[sp - 1] = sdrgb_op_union(stack[sp], stack[sp - 1]);
            }
            break;

            case Opcode_UnionSmooth: {
                float smoothness = read_float(cp);
                sp -= 1;
                stack[sp - 1] = sdrgb_op_union_smooth(stack[sp], stack[sp - 1], smoothness);
            }
            break;

            case Opcode_Subtract: {
                sp -= 1;
                stack[sp - 1] = sdrgb_op_subtract(stack[sp], stack[sp - 1]);
            }
            break;

            case Opcode_SubtractSmooth: {
                float smoothness = read_float(cp);
                sp -= 1;
                stack[sp - 1] = sdrgb_op_subtract_smooth(stack[sp], stack[sp - 1], smoothness);
            }
            break;

            case Opcode_Intersect: {
                sp -= 1;
                stack[sp - 1] = sdrgb_op_intersect(stack[sp], stack[sp - 1]);
            }
            break;

            case Opcode_IntersectSmooth: {
                float smoothness = read_float(cp);
                sp -= 1;
                stack[sp - 1] = sdrgb_op_intersect_smooth(stack[sp], stack[sp - 1], smoothness);
            }
            break;

                // Transforms:
            case Opcode_PushTranslation: {
                transform_stack[transform_sp++] = current_position;
                vec3 translation = read_vec3(cp);
                current_position += translation.xyz;
            }
            break;

            case Opcode_PushRotation: {
                transform_stack[transform_sp++] = current_position;
                vec4 quat = read_vec4(cp);
                current_position = mul_quat(quat, current_position);
            }
            break;

            case Opcode_PopTransform: {
                transform_sp -= 1;
                current_position = transform_stack[transform_sp];
            }
            break;

            case Opcode_PushScale: {
                transform_stack[transform_sp++] = current_position;

                float scale = read_float(cp);
                current_position *= scale;
            }
            break;

            case Opcode_PopScale: {
                transform_sp -= 1;
                current_position = transform_stack[transform_sp];

                float inv_scale = read_float(cp);
                stack[sp - 1].w *= inv_scale;
            }
            break;

            default:
            case Opcode_End: {
                return stack[sp - 1];
            }
        }
    }

    return vec4(0.0);
}