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}