nightshade 0.17.0

A cross-platform data-oriented game engine.
Documentation
struct ObjectData {
    transform_index: u32,
    mesh_id: u32,
    material_id: u32,
    batch_id: u32,
    morph_weights: array<f32, 8>,
    morph_target_count: u32,
    morph_displacement_offset: u32,
    mesh_vertex_offset: u32,
    mesh_vertex_count: u32,
    entity_id: u32,
    is_overlay: u32,
    skip_occlusion: u32,
    flip_winding: u32,
    culling_mask: u32,
    visible: u32,
    pipeline_class: u32,
    _pad_culling_2: u32,
};

struct BatchKey {
    pipeline_class: u32,
    mesh_id: u32,
    material_id: u32,
    base_slot: u32,
};

struct AssignParams {
    object_count: u32,
    key_count: u32,
    invalid_batch: u32,
    _pad: u32,
};

@group(0) @binding(0)
var<storage, read_write> objects: array<ObjectData>;

@group(0) @binding(1)
var<storage, read> keys: array<BatchKey>;

@group(0) @binding(2)
var<uniform> params: AssignParams;

fn key_less(object_class: u32, mesh: u32, material: u32, other: BatchKey) -> bool {
    if object_class != other.pipeline_class {
        return object_class < other.pipeline_class;
    }
    if mesh != other.mesh_id {
        return mesh < other.mesh_id;
    }
    return material < other.material_id;
}

fn key_equal(object_class: u32, mesh: u32, material: u32, other: BatchKey) -> bool {
    return object_class == other.pipeline_class && mesh == other.mesh_id && material == other.material_id;
}

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
    let object_index = global_id.x;
    if object_index >= params.object_count {
        return;
    }

    let object = objects[object_index];
    if object.batch_id == params.invalid_batch {
        return;
    }

    let object_class = object.pipeline_class;
    let mesh = object.mesh_id;
    let material = object.material_id;

    var low = 0u;
    var high = params.key_count;
    while low < high {
        let mid = (low + high) >> 1u;
        if key_less(object_class, mesh, material, keys[mid]) {
            high = mid;
        } else {
            low = mid + 1u;
        }
    }

    if low == 0u {
        objects[object_index].batch_id = params.invalid_batch;
        return;
    }
    let found = keys[low - 1u];
    if key_equal(object_class, mesh, material, found) {
        objects[object_index].batch_id = found.base_slot;
    } else {
        objects[object_index].batch_id = params.invalid_batch;
    }
}