dynamis-abi 0.7.0

Host to device record layouts, counters, and step parameters shared with WGSL
Documentation
use crate::QueryRecord;
use crate::constant::NO_BODY;
use crate::constant::{
    FILTER_IGNORE_KINEMATIC, FILTER_IGNORE_SENSORS, FILTER_IGNORE_SLEEPING, FILTER_IGNORE_STATIC,
    QUERY_CONVEX, QUERY_CUBOID, QUERY_POINT, QUERY_RAY, QUERY_SPHERE, QUERY_SWEEP, SHAPE_CAPSULE,
    SHAPE_CUBOID, SHAPE_CYLINDER, SHAPE_HULL, SHAPE_SPHERE,
};
use bytemuck::Zeroable;
use dynamis_model::{QueryFilter, Shape};
struct FilterBasis {
    flags: u32,
    group: u32,
    mask: u32,
    exclude_id: u32,
    exclude_generation: u32,
    include_id: u32,
    include_generation: u32,
}

impl FilterBasis {
    fn of(filter: &QueryFilter) -> Self {
        let exclude = filter
            .exclude
            .map_or((NO_BODY, 0), |handle| (handle.id, handle.generation));
        let include = filter
            .include
            .map_or((NO_BODY, 0), |handle| (handle.id, handle.generation));
        Self {
            flags: filter_flags(filter),
            group: filter.group,
            mask: filter.mask,
            exclude_id: exclude.0,
            exclude_generation: exclude.1,
            include_id: include.0,
            include_generation: include.1,
        }
    }
}

fn query_record(kind: u32, filter: &QueryFilter) -> QueryRecord {
    let basis = FilterBasis::of(filter);
    let mut record = QueryRecord::zeroed();
    record.kind = kind;
    record.filter_flags = basis.flags;
    record.group = basis.group;
    record.mask = basis.mask;
    record.max_hits = filter.max_hits;
    record.exclude_id = basis.exclude_id;
    record.exclude_generation = basis.exclude_generation;
    record.include_id = basis.include_id;
    record.include_generation = basis.include_generation;
    record
}

fn shape_fields(record: &mut QueryRecord, shape: &Shape) {
    let (shape_kind, source) = match shape {
        Shape::Sphere { .. } => (SHAPE_SPHERE, 0),
        Shape::Cuboid { .. } => (SHAPE_CUBOID, 0),
        Shape::Capsule { .. } => (SHAPE_CAPSULE, 0),
        Shape::Cylinder { .. } => (SHAPE_CYLINDER, 0),
        Shape::Hull(handle) => (SHAPE_HULL, handle.id),
        _ => panic!("shape queries require a convex shape"),
    };
    record.shape_kind = shape_kind;
    record.source = source;
    match shape {
        Shape::Sphere { radius }
        | Shape::Capsule { radius, .. }
        | Shape::Cylinder { radius, .. } => {
            record.radius = *radius;
        }
        _ => {}
    }
    match shape {
        Shape::Capsule { half_height, .. } | Shape::Cylinder { half_height, .. } => {
            record.half_height = *half_height;
        }
        _ => {}
    }
    if let Shape::Cuboid { half_extents } = shape {
        record.half_extents = *half_extents;
    }
}

impl QueryRecord {
    pub fn ray(origin: [f32; 3], direction: [f32; 3], max_t: f32, filter: &QueryFilter) -> Self {
        let mut record = query_record(QUERY_RAY, filter);
        record.origin = origin;
        record.direction = direction;
        record.extent = max_t;
        record
    }

    pub fn sphere(center: [f32; 3], radius: f32, filter: &QueryFilter) -> Self {
        let mut record = query_record(QUERY_SPHERE, filter);
        record.shape_kind = SHAPE_SPHERE;
        record.origin = center;
        record.extent = radius;
        record.radius = radius;
        record
    }

    pub fn point(origin: [f32; 3], filter: &QueryFilter) -> Self {
        let mut record = query_record(QUERY_POINT, filter);
        record.shape_kind = SHAPE_SPHERE;
        record.origin = origin;
        record
    }

    pub fn cuboid(center: [f32; 3], half_extents: [f32; 3], filter: &QueryFilter) -> Self {
        let mut record = query_record(QUERY_CUBOID, filter);
        record.shape_kind = SHAPE_CUBOID;
        record.origin = center;
        record.half_extents = half_extents;
        record
    }

    pub fn convex(
        shape: &Shape,
        orientation: [f32; 4],
        position: [f32; 3],
        filter: &QueryFilter,
    ) -> Self {
        let mut record = query_record(QUERY_CONVEX, filter);
        record.origin = position;
        record.orientation = orientation;
        shape_fields(&mut record, shape);
        record
    }

    pub fn sweep(
        shape: &Shape,
        orientation: [f32; 4],
        start: [f32; 3],
        direction: [f32; 3],
        length: f32,
        filter: &QueryFilter,
    ) -> Self {
        let mut record = query_record(QUERY_SWEEP, filter);
        record.origin = start;
        record.direction = direction;
        record.extent = length;
        record.orientation = orientation;
        shape_fields(&mut record, shape);
        record
    }
}

fn filter_flags(filter: &QueryFilter) -> u32 {
    let mut flags = 0;
    if filter.ignore_sensors {
        flags |= FILTER_IGNORE_SENSORS;
    }
    if filter.ignore_sleeping {
        flags |= FILTER_IGNORE_SLEEPING;
    }
    if filter.ignore_static {
        flags |= FILTER_IGNORE_STATIC;
    }
    if filter.ignore_kinematic {
        flags |= FILTER_IGNORE_KINEMATIC;
    }
    flags
}