dynamis-world 0.6.0

GPU-driven physics engine
Documentation
@group(0) @binding(0) var<storage, read> resting: array<Contact>;
@group(0) @binding(1) var<storage, read_write> resting_live: array<u32>;
@group(0) @binding(2) var<storage, read_write> resting_next: array<u32>;
@group(0) @binding(3) var<storage, read_write> resting_free: array<atomic<u32>>;
@group(0) @binding(4) var<storage, read_write> resting_count: array<atomic<u32>>;
@group(0) @binding(5) var<storage, read> body_states: array<BodyState>;
@group(0) @binding(6) var<storage, read> body_rows: array<u32>;
@group(0) @binding(7) var<storage, read> body_activity: array<u32>;
@group(0) @binding(8) var<storage, read> contacts: array<Contact>;
@group(0) @binding(9) var<storage, read_write> contact_count: array<atomic<u32>>;
@group(0) @binding(10) var<storage, read_write> events: array<ContactEvent>;
@group(0) @binding(11) var<storage, read_write> event_count: array<atomic<u32>>;
@group(0) @binding(12) var<storage, read_write> spillover: array<atomic<u32>>;
@group(0) @binding(13) var<uniform> params: StepParams;

fn resolve_row(body_id: u32, generation: u32) -> u32 {
    if (body_id >= arrayLength(&body_rows)) {
        return NO_BODY;
    }
    let row = body_rows[body_id];
    if (row >= arrayLength(&body_states) || !contact_row_matches(body_states[row], body_id, generation)) {
        return NO_BODY;
    }
    return row;
}

fn current_holds(key_hi: u32, key_lo: u32) -> bool {
    let count = min(atomicLoad(&contact_count[0]), arrayLength(&contacts));
    var lo = 0u;
    var hi = count;
    while (lo < hi) {
        let mid = (lo + hi) / 2u;
        let candidate = contacts[mid];
        if (candidate.a < key_hi || (candidate.a == key_hi && candidate.b < key_lo)) {
            lo = mid + 1u;
        } else {
            hi = mid;
        }
    }
    return lo < count && contacts[lo].a == key_hi && contacts[lo].b == key_lo;
}

fn release(index: u32) {
    resting_live[index] = 0u;
    resting_next[index] = atomicExchange(&resting_free[0], index);
}

@compute @workgroup_size(WORKGROUP_SIZE)
fn main(@builtin(global_invocation_id) gid: vec3u) {
    let index = gid.y * (WORKGROUPS_PER_ROW * WORKGROUP_SIZE) + gid.x;
    if (index >= min(atomicLoad(&resting_count[0]), arrayLength(&resting_live))) {
        return;
    }
    if (resting_live[index] == 0u) {
        return;
    }
    let contact = resting[index];
    let first_row = resolve_row(contact.first_body_id, contact.first_generation);
    let second_row = resolve_row(contact.second_body_id, contact.second_generation);
    if (first_row == NO_BODY || second_row == NO_BODY) {
        release(index);
        announce(COLLIDER_EVENT_BEGIN_END, EVENT_END, contact);
        return;
    }
    if (body_activity[first_row] == 0u && body_activity[second_row] == 0u) {
        return;
    }
    release(index);
    let key = contact_row_key(contact, first_row, second_row);
    if (current_holds(key.x, key.y)) {
        return;
    }
    announce(COLLIDER_EVENT_BEGIN_END, EVENT_END, contact);
}