Skip to main content

dynamis_abi/
query.rs

1use crate::QueryRecord;
2use crate::constant::NO_BODY;
3use crate::constant::{
4    FILTER_IGNORE_KINEMATIC, FILTER_IGNORE_SENSORS, FILTER_IGNORE_SLEEPING, FILTER_IGNORE_STATIC,
5    QUERY_CONVEX, QUERY_CUBOID, QUERY_POINT, QUERY_RAY, QUERY_SPHERE, QUERY_SWEEP, SHAPE_CAPSULE,
6    SHAPE_CUBOID, SHAPE_CYLINDER, SHAPE_HULL, SHAPE_SPHERE,
7};
8use bytemuck::Zeroable;
9use dynamis_model::{QueryFilter, Shape};
10struct FilterBasis {
11    flags: u32,
12    group: u32,
13    mask: u32,
14    exclude_id: u32,
15    exclude_generation: u32,
16    include_id: u32,
17    include_generation: u32,
18}
19
20impl FilterBasis {
21    fn of(filter: &QueryFilter) -> Self {
22        let exclude = filter
23            .exclude
24            .map_or((NO_BODY, 0), |handle| (handle.id, handle.generation));
25        let include = filter
26            .include
27            .map_or((NO_BODY, 0), |handle| (handle.id, handle.generation));
28        Self {
29            flags: filter_flags(filter),
30            group: filter.group,
31            mask: filter.mask,
32            exclude_id: exclude.0,
33            exclude_generation: exclude.1,
34            include_id: include.0,
35            include_generation: include.1,
36        }
37    }
38}
39
40fn query_record(kind: u32, filter: &QueryFilter) -> QueryRecord {
41    let basis = FilterBasis::of(filter);
42    let mut record = QueryRecord::zeroed();
43    record.kind = kind;
44    record.filter_flags = basis.flags;
45    record.group = basis.group;
46    record.mask = basis.mask;
47    record.max_hits = filter.max_hits;
48    record.exclude_id = basis.exclude_id;
49    record.exclude_generation = basis.exclude_generation;
50    record.include_id = basis.include_id;
51    record.include_generation = basis.include_generation;
52    record
53}
54
55fn shape_fields(record: &mut QueryRecord, shape: &Shape) {
56    let (shape_kind, source) = match shape {
57        Shape::Sphere { .. } => (SHAPE_SPHERE, 0),
58        Shape::Cuboid { .. } => (SHAPE_CUBOID, 0),
59        Shape::Capsule { .. } => (SHAPE_CAPSULE, 0),
60        Shape::Cylinder { .. } => (SHAPE_CYLINDER, 0),
61        Shape::Hull(handle) => (SHAPE_HULL, handle.id),
62        _ => panic!("shape queries require a convex shape"),
63    };
64    record.shape_kind = shape_kind;
65    record.source = source;
66    match shape {
67        Shape::Sphere { radius }
68        | Shape::Capsule { radius, .. }
69        | Shape::Cylinder { radius, .. } => {
70            record.radius = *radius;
71        }
72        _ => {}
73    }
74    match shape {
75        Shape::Capsule { half_height, .. } | Shape::Cylinder { half_height, .. } => {
76            record.half_height = *half_height;
77        }
78        _ => {}
79    }
80    if let Shape::Cuboid { half_extents } = shape {
81        record.half_extents = *half_extents;
82    }
83}
84
85impl QueryRecord {
86    pub fn ray(origin: [f32; 3], direction: [f32; 3], max_t: f32, filter: &QueryFilter) -> Self {
87        let mut record = query_record(QUERY_RAY, filter);
88        record.origin = origin;
89        record.direction = direction;
90        record.extent = max_t;
91        record
92    }
93
94    pub fn sphere(center: [f32; 3], radius: f32, filter: &QueryFilter) -> Self {
95        let mut record = query_record(QUERY_SPHERE, filter);
96        record.shape_kind = SHAPE_SPHERE;
97        record.origin = center;
98        record.extent = radius;
99        record.radius = radius;
100        record
101    }
102
103    pub fn point(origin: [f32; 3], filter: &QueryFilter) -> Self {
104        let mut record = query_record(QUERY_POINT, filter);
105        record.shape_kind = SHAPE_SPHERE;
106        record.origin = origin;
107        record
108    }
109
110    pub fn cuboid(center: [f32; 3], half_extents: [f32; 3], filter: &QueryFilter) -> Self {
111        let mut record = query_record(QUERY_CUBOID, filter);
112        record.shape_kind = SHAPE_CUBOID;
113        record.origin = center;
114        record.half_extents = half_extents;
115        record
116    }
117
118    pub fn convex(
119        shape: &Shape,
120        orientation: [f32; 4],
121        position: [f32; 3],
122        filter: &QueryFilter,
123    ) -> Self {
124        let mut record = query_record(QUERY_CONVEX, filter);
125        record.origin = position;
126        record.orientation = orientation;
127        shape_fields(&mut record, shape);
128        record
129    }
130
131    pub fn sweep(
132        shape: &Shape,
133        orientation: [f32; 4],
134        start: [f32; 3],
135        direction: [f32; 3],
136        length: f32,
137        filter: &QueryFilter,
138    ) -> Self {
139        let mut record = query_record(QUERY_SWEEP, filter);
140        record.origin = start;
141        record.direction = direction;
142        record.extent = length;
143        record.orientation = orientation;
144        shape_fields(&mut record, shape);
145        record
146    }
147}
148
149fn filter_flags(filter: &QueryFilter) -> u32 {
150    let mut flags = 0;
151    if filter.ignore_sensors {
152        flags |= FILTER_IGNORE_SENSORS;
153    }
154    if filter.ignore_sleeping {
155        flags |= FILTER_IGNORE_SLEEPING;
156    }
157    if filter.ignore_static {
158        flags |= FILTER_IGNORE_STATIC;
159    }
160    if filter.ignore_kinematic {
161        flags |= FILTER_IGNORE_KINEMATIC;
162    }
163    flags
164}