primase-core 0.2.0

primase core: the world store, core components, frames, the pass manager and gates
Documentation
// The reading of a pixel program's outputs as a surface (`primase_core::shader::surface`), for a composite that
// decodes a G-buffer on the GPU as the CPU reading does. A program's surface is `primase_surface_rows` rows of four
// words (`primase_core::shader::surface::rows`), one per term at the index its constant below names:
//
//   x  the render target the term is in, plus one; 0 where no output has a role for the term (the caller takes its
//      own default and calls none of these functions with the row)
//   y  bits 0 and 1 the term's first lane, 4 to 7 how many lanes it has, 8 to 15 its kind, 16 to 23 and 24 to 31 the
//      power and the root of its scalar encoding (`ScalarEncoding`: the value is `stored^power`, its root-th root,
//      times the scale)
//   z  the scale's f32 bits, or a normal encoding's first number
//   w  a normal encoding's second number
//
// Each function takes the row and the four values of the target it names (the caller reads them, at `row.x - 1`).

const primase_surface_rows: u32 = 9u;
const primase_surface_base: u32 = 0u;
const primase_surface_normal: u32 = 1u;
const primase_surface_roughness: u32 = 2u;
const primase_surface_metallic: u32 = 3u;
const primase_surface_reflectance: u32 = 4u;
const primase_surface_specular: u32 = 5u;
const primase_surface_emission: u32 = 6u;
const primase_surface_occlusion: u32 = 7u;
// The occlusion of the environment's ambient light alone (`Surface::ambient_occlusion`): it scales the ambient light,
// not the other lights; a surface has this row or the occlusion row, not both.
const primase_surface_ambient_occlusion: u32 = 8u;

fn primase_kind(row: vec4<u32>) -> u32 {
    return (row.y >> 8u) & 0xffu;
}

// Lane `k` of the term (0 its first lane), 0 past the target's four.
fn primase_lane(row: vec4<u32>, value: vec4<f32>, k: u32) -> f32 {
    let lane = (row.y & 0x3u) + k;
    if (lane > 3u) {
        return 0.0;
    }
    return value[lane];
}

// The term's lanes as the program stored them, undecoded (a role shown as written): three or more lanes their first
// three as a colour, one or two lanes the first as grey.
fn primase_stored(row: vec4<u32>, value: vec4<f32>) -> vec3<f32> {
    if (((row.y >> 4u) & 0xfu) >= 3u) {
        return vec3<f32>(primase_lane(row, value, 0u), primase_lane(row, value, 1u), primase_lane(row, value, 2u));
    }
    return vec3<f32>(primase_lane(row, value, 0u));
}

// `ScalarEncoding::decode`: the stored value to the power, its root (of 0 where negative), times the scale.
fn primase_decode(row: vec4<u32>, stored: f32) -> f32 {
    let power = (row.y >> 16u) & 0xffu;
    let root = (row.y >> 24u) & 0xffu;
    var raised = 1.0;
    for (var i = 0u; i < power; i = i + 1u) {
        raised = raised * stored;
    }
    var value = raised;
    if (root == 2u) {
        value = sqrt(max(raised, 0.0));
    } else if (root > 2u) {
        value = pow(max(raised, 0.0), 1.0 / f32(root));
    }
    return value * bitcast<f32>(row.z);
}

// A one-lane term, decoded (the metallic, the specular strength, either occlusion).
fn primase_scalar(row: vec4<u32>, value: vec4<f32>) -> f32 {
    return primase_decode(row, primase_lane(row, value, 0u));
}

// A three-lane term, each lane decoded (the reflectance).
fn primase_colour(row: vec4<u32>, value: vec4<f32>) -> vec3<f32> {
    return vec3<f32>(
        primase_decode(row, primase_lane(row, value, 0u)),
        primase_decode(row, primase_lane(row, value, 1u)),
        primase_decode(row, primase_lane(row, value, 2u)),
    );
}

// The surface's colour (`Base`), its first three lanes as stored. Kind 1 an albedo, 2 a forward program's finished
// colour.
fn primase_base(row: vec4<u32>, value: vec4<f32>) -> vec3<f32> {
    return vec3<f32>(primase_lane(row, value, 0u), primase_lane(row, value, 1u), primase_lane(row, value, 2u));
}

// The perceptual roughness (`Roughness::decode`), unclamped. Kind 1 the roughness stored, 2 a gloss (one minus it),
// 3 a specular exponent n, `(2 / (n + 2))^(1/4)`.
fn primase_roughness(row: vec4<u32>, value: vec4<f32>) -> f32 {
    let v = primase_scalar(row, value);
    let kind = primase_kind(row);
    if (kind == 2u) {
        return 1.0 - v;
    }
    if (kind == 3u) {
        return pow(2.0 / (max(v, 0.0) + 2.0), 0.25);
    }
    return v;
}

// The light the surface gives off (`Emission::decode`). Kind 1 a colour in three lanes, 2 one lane scaling `albedo`.
fn primase_emission(row: vec4<u32>, value: vec4<f32>, albedo: vec3<f32>) -> vec3<f32> {
    if (primase_kind(row) == 2u) {
        return albedo * primase_scalar(row, value);
    }
    return primase_colour(row, value);
}

fn primase_length_or_zero(n: vec3<f32>) -> vec3<f32> {
    let length_squared = dot(n, n);
    if (length_squared > 1e-16) {
        return n * inverseSqrt(length_squared);
    }
    return n;
}

// The octahedral unfold: z = 1 - |x| - |y|, x and y folded back where z < 0, normalised.
fn primase_unfold(x: f32, y: f32) -> vec3<f32> {
    let z = 1.0 - abs(x) - abs(y);
    var fx = x;
    var fy = y;
    if (z < 0.0) {
        fx = (1.0 - abs(y)) * select(1.0, -1.0, x < 0.0);
        fy = (1.0 - abs(x)) * select(1.0, -1.0, y < 0.0);
    }
    return primase_length_or_zero(vec3<f32>(fx, fy, z));
}

// The diamond layout over three 8-bit lanes (`NormalEncoding::decode_octahedral_diamond`): lanes 0 and 1 the low eight
// bits of two 9-bit coordinates, lane 2's bits 1 and 2 their ninth bits and its bit 0 the sign of z.
fn primase_diamond(lanes: vec3<f32>) -> vec3<f32> {
    let bytes = vec3<u32>(round(clamp(lanes, vec3<f32>(0.0), vec3<f32>(1.0)) * 255.0));
    let u9 = f32(((bytes.z >> 1u) & 1u) * 256u + bytes.x);
    let v9 = f32(((bytes.z >> 2u) & 1u) * 256u + bytes.y);
    let pu = clamp(u9 / 255.0 - 1.0, -1.0, 1.0);
    let pv = clamp(v9 / 255.0 - 1.0, -1.0, 1.0);
    let x = (pu + pv) * 0.5;
    let y = (pu - pv) * 0.5;
    let z = (1.0 - abs(x) - abs(y)) * select(-1.0, 1.0, (bytes.z & 1u) == 1u);
    return primase_length_or_zero(vec3<f32>(x, y, z));
}

// The cube face (`NormalEncoding::CubeFace`): the nearest axis to lane 3 and the side of one half lane 2 is on; lanes 0
// and 1 the face's two minor components through the minor affine (z its scale, w its bias).
fn primase_cube_face(row: vec4<u32>, value: vec4<f32>) -> vec3<f32> {
    let scale = bitcast<f32>(row.z);
    let bias = bitcast<f32>(row.w);
    let sc = (primase_lane(row, value, 0u) - bias) / scale;
    let tc = (primase_lane(row, value, 1u) - bias) / scale;
    let axis = u32(clamp(round(primase_lane(row, value, 3u) * 3.0), 0.0, 2.0));
    let negative = primase_lane(row, value, 2u) > 0.5;
    let major = sqrt(max(1.0 - sc * sc - tc * tc, 0.0)) * select(1.0, -1.0, negative);
    var n = vec3<f32>(0.0);
    switch (axis * 2u + select(0u, 1u, negative)) {
        case 0u: { n = vec3<f32>(major, -tc, -sc); }
        case 1u: { n = vec3<f32>(major, -tc, sc); }
        case 2u: { n = vec3<f32>(sc, major, tc); }
        case 3u: { n = vec3<f32>(sc, major, -tc); }
        case 4u: { n = vec3<f32>(sc, -tc, major); }
        default: { n = vec3<f32>(-sc, -tc, major); }
    }
    return primase_length_or_zero(n);
}

// The normal the lanes store (`Normal::vector`): the three stored components unbiased (kinds 1 to 3, not normalised),
// the unit vector of the others. Kinds: 1 `Xyz`, 2 `XyzUnorm`, 3 `XyzBiased` (z the bias), 4 `Xy`, 5 `XyUnorm`,
// 6 `Octahedral` (z and w the read affine's scale and bias), 7 `OctahedralDiamond`, 8 `CubeFace` (z and w the minor
// affine's scale and bias).
fn primase_normal(row: vec4<u32>, value: vec4<f32>) -> vec3<f32> {
    let l0 = primase_lane(row, value, 0u);
    let l1 = primase_lane(row, value, 1u);
    let l2 = primase_lane(row, value, 2u);
    switch (primase_kind(row)) {
        case 1u: { return vec3<f32>(l0, l1, l2); }
        case 2u: { return (vec3<f32>(l0, l1, l2) - vec3<f32>(0.5)) * 2.0; }
        case 3u: { return (vec3<f32>(l0, l1, l2) - vec3<f32>(bitcast<f32>(row.z))) * 2.0; }
        case 4u: { return vec3<f32>(l0, l1, sqrt(max(1.0 - l0 * l0 - l1 * l1, 0.0))); }
        case 5u: {
            let x = l0 * 2.0 - 1.0;
            let y = l1 * 2.0 - 1.0;
            return vec3<f32>(x, y, sqrt(max(1.0 - x * x - y * y, 0.0)));
        }
        case 6u: {
            let scale = bitcast<f32>(row.z);
            let bias = bitcast<f32>(row.w);
            return primase_unfold(l0 * scale + bias, l1 * scale + bias);
        }
        case 7u: { return primase_diamond(vec3<f32>(l0, l1, l2)); }
        case 8u: { return primase_cube_face(row, value); }
        default: { return vec3<f32>(0.0); }
    }
}