1use crate::collision::{
10 Capsule, ChainSegment, Circle, MassData, Polygon, Segment, WorldCastOutput,
11};
12use crate::distance::ShapeProxy;
13use crate::dynamic_tree::TreeStats;
14use crate::hull::MAX_POLYGON_VERTICES;
15use crate::id::{BodyId, ChainId, JointId, ShapeId, WorldId};
16use crate::math_functions::{Aabb, Pos, Rot, Transform, Vec2, WorldTransform};
17use crate::types::{
18 BodyDef, ChainDef, DistanceJointDef, ExplosionDef, Filter, FilterJointDef, JointDef,
19 MotionLocks, MotorJointDef, PrismaticJointDef, QueryFilter, RayResult, RevoluteJointDef,
20 ShapeDef, SurfaceMaterial, WeldJointDef, WheelJointDef,
21};
22
23pub fn rec_w_u8(buf: &mut Vec<u8>, v: u8) {
24 buf.push(v);
25}
26
27pub fn rec_w_u16(buf: &mut Vec<u8>, v: u16) {
28 buf.extend_from_slice(&v.to_le_bytes());
29}
30
31pub fn rec_w_u32(buf: &mut Vec<u8>, v: u32) {
32 buf.extend_from_slice(&v.to_le_bytes());
33}
34
35pub fn rec_w_u64(buf: &mut Vec<u8>, v: u64) {
36 buf.extend_from_slice(&v.to_le_bytes());
37}
38
39pub fn rec_w_i32(buf: &mut Vec<u8>, v: i32) {
40 rec_w_u32(buf, v as u32);
41}
42
43pub fn rec_w_f32(buf: &mut Vec<u8>, v: f32) {
44 rec_w_u32(buf, v.to_bits());
45}
46
47pub fn rec_w_f64(buf: &mut Vec<u8>, v: f64) {
48 rec_w_u64(buf, v.to_bits());
49}
50
51pub fn rec_w_bool(buf: &mut Vec<u8>, v: bool) {
52 rec_w_u8(buf, if v { 1 } else { 0 });
53}
54
55pub fn rec_w_vec2(buf: &mut Vec<u8>, v: Vec2) {
56 rec_w_f32(buf, v.x);
57 rec_w_f32(buf, v.y);
58}
59
60pub fn rec_w_rot(buf: &mut Vec<u8>, v: Rot) {
61 rec_w_f32(buf, v.c);
62 rec_w_f32(buf, v.s);
63}
64
65pub fn rec_w_xf(buf: &mut Vec<u8>, v: Transform) {
66 rec_w_vec2(buf, v.p);
67 rec_w_rot(buf, v.q);
68}
69
70#[cfg(feature = "double-precision")]
74pub fn rec_w_position(buf: &mut Vec<u8>, v: Pos) {
75 rec_w_f64(buf, v.x);
76 rec_w_f64(buf, v.y);
77}
78
79#[cfg(not(feature = "double-precision"))]
80pub fn rec_w_position(buf: &mut Vec<u8>, v: Pos) {
81 rec_w_f32(buf, v.x);
82 rec_w_f32(buf, v.y);
83}
84
85pub fn rec_w_worldxf(buf: &mut Vec<u8>, v: WorldTransform) {
86 rec_w_position(buf, v.p);
87 rec_w_rot(buf, v.q);
88}
89
90pub fn rec_w_worldid(buf: &mut Vec<u8>, v: WorldId) {
91 rec_w_u32(buf, v.store());
92}
93
94pub fn rec_w_bodyid(buf: &mut Vec<u8>, v: BodyId) {
95 rec_w_u64(buf, v.store());
96}
97
98pub fn rec_w_shapeid(buf: &mut Vec<u8>, v: ShapeId) {
99 rec_w_u64(buf, v.store());
100}
101
102pub fn rec_w_chainid(buf: &mut Vec<u8>, v: ChainId) {
103 rec_w_u64(buf, v.store());
104}
105
106pub fn rec_w_jointid(buf: &mut Vec<u8>, v: JointId) {
107 rec_w_u64(buf, v.store());
108}
109
110pub fn rec_w_circle(buf: &mut Vec<u8>, v: Circle) {
114 rec_w_vec2(buf, v.center);
115 rec_w_f32(buf, v.radius);
116}
117
118pub fn rec_w_capsule(buf: &mut Vec<u8>, v: Capsule) {
119 rec_w_vec2(buf, v.center1);
120 rec_w_vec2(buf, v.center2);
121 rec_w_f32(buf, v.radius);
122}
123
124pub fn rec_w_segment(buf: &mut Vec<u8>, v: Segment) {
125 rec_w_vec2(buf, v.point1);
126 rec_w_vec2(buf, v.point2);
127}
128
129pub fn rec_w_polygon(buf: &mut Vec<u8>, v: &Polygon) {
130 for vertex in v.vertices.iter() {
131 rec_w_vec2(buf, *vertex);
132 }
133 for normal in v.normals.iter() {
134 rec_w_vec2(buf, *normal);
135 }
136 rec_w_vec2(buf, v.centroid);
137 rec_w_f32(buf, v.radius);
138 rec_w_i32(buf, v.count);
139}
140
141pub fn rec_w_chainseg(buf: &mut Vec<u8>, v: ChainSegment) {
142 rec_w_vec2(buf, v.ghost1);
143 rec_w_segment(buf, v.segment);
144 rec_w_vec2(buf, v.ghost2);
145 rec_w_i32(buf, v.chain_id);
146}
147
148pub fn rec_w_filter(buf: &mut Vec<u8>, v: Filter) {
149 rec_w_u64(buf, v.category_bits);
150 rec_w_u64(buf, v.mask_bits);
151 rec_w_i32(buf, v.group_index);
152}
153
154pub fn rec_w_material(buf: &mut Vec<u8>, v: SurfaceMaterial) {
155 rec_w_f32(buf, v.friction);
156 rec_w_f32(buf, v.restitution);
157 rec_w_f32(buf, v.rolling_resistance);
158 rec_w_f32(buf, v.tangent_speed);
159 rec_w_u64(buf, v.user_material_id);
160 rec_w_u32(buf, v.custom_color);
161}
162
163pub fn rec_w_massdata(buf: &mut Vec<u8>, v: MassData) {
164 rec_w_f32(buf, v.mass);
165 rec_w_vec2(buf, v.center);
166 rec_w_f32(buf, v.rotational_inertia);
167}
168
169pub fn rec_w_locks(buf: &mut Vec<u8>, v: MotionLocks) {
170 rec_w_bool(buf, v.linear_x);
171 rec_w_bool(buf, v.linear_y);
172 rec_w_bool(buf, v.angular_z);
173}
174
175pub fn rec_w_str(buf: &mut Vec<u8>, s: &str) {
179 let bytes = s.as_bytes();
180 let len = bytes.len().min(65534);
181 rec_w_u16(buf, len as u16);
182 buf.extend_from_slice(&bytes[..len]);
183}
184
185pub fn rec_w_explosiondef(buf: &mut Vec<u8>, v: &ExplosionDef) {
186 rec_w_u64(buf, v.mask_bits);
187 rec_w_position(buf, v.position);
188 rec_w_f32(buf, v.radius);
189 rec_w_f32(buf, v.falloff);
190 rec_w_f32(buf, v.impulse_per_length);
191}
192
193pub fn rec_w_bodydef(buf: &mut Vec<u8>, v: &BodyDef) {
197 rec_w_i32(buf, v.type_ as i32);
198 rec_w_position(buf, v.position);
199 rec_w_rot(buf, v.rotation);
200 rec_w_vec2(buf, v.linear_velocity);
201 rec_w_f32(buf, v.angular_velocity);
202 rec_w_f32(buf, v.linear_damping);
203 rec_w_f32(buf, v.angular_damping);
204 rec_w_f32(buf, v.gravity_scale);
205 rec_w_f32(buf, v.sleep_threshold);
206 rec_w_str(buf, &v.name);
207 rec_w_u64(buf, 0);
209 rec_w_locks(buf, v.motion_locks);
210 rec_w_bool(buf, v.enable_sleep);
211 rec_w_bool(buf, v.is_awake);
212 rec_w_bool(buf, v.is_bullet);
213 rec_w_bool(buf, v.is_enabled);
214 rec_w_bool(buf, v.allow_fast_rotation);
215 rec_w_bool(buf, v.enable_contact_recycling);
216}
217
218pub fn rec_w_shapedef(buf: &mut Vec<u8>, v: &ShapeDef) {
219 rec_w_u64(buf, 0);
221 rec_w_material(buf, v.material);
222 rec_w_f32(buf, v.density);
223 rec_w_filter(buf, v.filter);
224 rec_w_bool(buf, v.enable_custom_filtering);
225 rec_w_bool(buf, v.is_sensor);
226 rec_w_bool(buf, v.enable_sensor_events);
227 rec_w_bool(buf, v.enable_contact_events);
228 rec_w_bool(buf, v.enable_hit_events);
229 rec_w_bool(buf, v.enable_pre_solve_events);
230 rec_w_bool(buf, v.invoke_contact_creation);
231 rec_w_bool(buf, v.update_body_mass);
232}
233
234pub fn rec_w_chaindef(buf: &mut Vec<u8>, v: &ChainDef) {
237 rec_w_u64(buf, 0);
239 rec_w_i32(buf, v.points.len() as i32);
240 for point in v.points.iter() {
241 rec_w_vec2(buf, *point);
242 }
243 rec_w_i32(buf, v.materials.len() as i32);
244 for material in v.materials.iter() {
245 rec_w_material(buf, *material);
246 }
247 rec_w_filter(buf, v.filter);
248 rec_w_bool(buf, v.is_loop);
249 rec_w_bool(buf, v.enable_sensor_events);
250}
251
252fn rec_w_joint_base(buf: &mut Vec<u8>, base: &JointDef) {
255 rec_w_u64(buf, 0); rec_w_bodyid(buf, base.body_id_a);
257 rec_w_bodyid(buf, base.body_id_b);
258 rec_w_xf(buf, base.local_frame_a);
259 rec_w_xf(buf, base.local_frame_b);
260 rec_w_f32(buf, base.force_threshold);
261 rec_w_f32(buf, base.torque_threshold);
262 rec_w_f32(buf, base.constraint_hertz);
263 rec_w_f32(buf, base.constraint_damping_ratio);
264 rec_w_f32(buf, base.draw_scale);
265 rec_w_bool(buf, base.collide_connected);
266}
267
268pub fn rec_w_distancejointdef(buf: &mut Vec<u8>, v: &DistanceJointDef) {
269 rec_w_joint_base(buf, &v.base);
270 rec_w_f32(buf, v.length);
271 rec_w_bool(buf, v.enable_spring);
272 rec_w_f32(buf, v.lower_spring_force);
273 rec_w_f32(buf, v.upper_spring_force);
274 rec_w_f32(buf, v.hertz);
275 rec_w_f32(buf, v.damping_ratio);
276 rec_w_bool(buf, v.enable_limit);
277 rec_w_f32(buf, v.min_length);
278 rec_w_f32(buf, v.max_length);
279 rec_w_bool(buf, v.enable_motor);
280 rec_w_f32(buf, v.max_motor_force);
281 rec_w_f32(buf, v.motor_speed);
282}
283
284pub fn rec_w_motorjointdef(buf: &mut Vec<u8>, v: &MotorJointDef) {
285 rec_w_joint_base(buf, &v.base);
286 rec_w_vec2(buf, v.linear_velocity);
287 rec_w_f32(buf, v.max_velocity_force);
288 rec_w_f32(buf, v.angular_velocity);
289 rec_w_f32(buf, v.max_velocity_torque);
290 rec_w_f32(buf, v.linear_hertz);
291 rec_w_f32(buf, v.linear_damping_ratio);
292 rec_w_f32(buf, v.max_spring_force);
293 rec_w_f32(buf, v.angular_hertz);
294 rec_w_f32(buf, v.angular_damping_ratio);
295 rec_w_f32(buf, v.max_spring_torque);
296}
297
298pub fn rec_w_filterjointdef(buf: &mut Vec<u8>, v: &FilterJointDef) {
299 rec_w_joint_base(buf, &v.base);
300}
301
302pub fn rec_w_prismaticjointdef(buf: &mut Vec<u8>, v: &PrismaticJointDef) {
303 rec_w_joint_base(buf, &v.base);
304 rec_w_bool(buf, v.enable_spring);
305 rec_w_f32(buf, v.hertz);
306 rec_w_f32(buf, v.damping_ratio);
307 rec_w_f32(buf, v.target_translation);
308 rec_w_bool(buf, v.enable_limit);
309 rec_w_f32(buf, v.lower_translation);
310 rec_w_f32(buf, v.upper_translation);
311 rec_w_bool(buf, v.enable_motor);
312 rec_w_f32(buf, v.max_motor_force);
313 rec_w_f32(buf, v.motor_speed);
314}
315
316pub fn rec_w_revolutejointdef(buf: &mut Vec<u8>, v: &RevoluteJointDef) {
317 rec_w_joint_base(buf, &v.base);
318 rec_w_f32(buf, v.target_angle);
319 rec_w_bool(buf, v.enable_spring);
320 rec_w_f32(buf, v.hertz);
321 rec_w_f32(buf, v.damping_ratio);
322 rec_w_bool(buf, v.enable_limit);
323 rec_w_f32(buf, v.lower_angle);
324 rec_w_f32(buf, v.upper_angle);
325 rec_w_bool(buf, v.enable_motor);
326 rec_w_f32(buf, v.max_motor_torque);
327 rec_w_f32(buf, v.motor_speed);
328}
329
330pub fn rec_w_weldjointdef(buf: &mut Vec<u8>, v: &WeldJointDef) {
331 rec_w_joint_base(buf, &v.base);
332 rec_w_f32(buf, v.linear_hertz);
333 rec_w_f32(buf, v.angular_hertz);
334 rec_w_f32(buf, v.linear_damping_ratio);
335 rec_w_f32(buf, v.angular_damping_ratio);
336}
337
338pub fn rec_w_wheeljointdef(buf: &mut Vec<u8>, v: &WheelJointDef) {
339 rec_w_joint_base(buf, &v.base);
340 rec_w_bool(buf, v.enable_spring);
341 rec_w_f32(buf, v.hertz);
342 rec_w_f32(buf, v.damping_ratio);
343 rec_w_bool(buf, v.enable_limit);
344 rec_w_f32(buf, v.lower_translation);
345 rec_w_f32(buf, v.upper_translation);
346 rec_w_bool(buf, v.enable_motor);
347 rec_w_f32(buf, v.max_motor_torque);
348 rec_w_f32(buf, v.motor_speed);
349}
350
351pub fn rec_w_aabb(buf: &mut Vec<u8>, v: Aabb) {
352 rec_w_vec2(buf, v.lower_bound);
353 rec_w_vec2(buf, v.upper_bound);
354}
355
356pub fn rec_w_queryfilter(buf: &mut Vec<u8>, v: QueryFilter) {
357 rec_w_u64(buf, v.category_bits);
358 rec_w_u64(buf, v.mask_bits);
359}
360
361pub fn rec_w_shapeproxy(buf: &mut Vec<u8>, v: &ShapeProxy) {
362 let count = v.count.clamp(0, MAX_POLYGON_VERTICES as i32);
363 rec_w_i32(buf, count);
364 for point in v.points[..count as usize].iter() {
365 rec_w_vec2(buf, *point);
366 }
367 rec_w_f32(buf, v.radius);
368}
369
370pub fn rec_w_worldcastoutput(buf: &mut Vec<u8>, v: WorldCastOutput) {
371 rec_w_vec2(buf, v.normal);
372 rec_w_position(buf, v.point);
373 rec_w_f32(buf, v.fraction);
374 rec_w_i32(buf, v.iterations);
375 rec_w_bool(buf, v.hit);
376}
377
378pub fn rec_w_rayresult(buf: &mut Vec<u8>, v: &RayResult) {
379 rec_w_shapeid(buf, v.shape_id);
380 rec_w_position(buf, v.point);
381 rec_w_vec2(buf, v.normal);
382 rec_w_f32(buf, v.fraction);
383 rec_w_i32(buf, v.node_visits);
384 rec_w_i32(buf, v.leaf_visits);
385 rec_w_bool(buf, v.hit);
386}
387
388pub fn rec_w_planeresult(buf: &mut Vec<u8>, v: &crate::collision::PlaneResult) {
389 rec_w_vec2(buf, v.plane.normal);
390 rec_w_f32(buf, v.plane.offset);
391 rec_w_vec2(buf, v.point);
392 rec_w_bool(buf, v.hit);
393}
394
395pub fn rec_w_treestats(buf: &mut Vec<u8>, v: TreeStats) {
396 rec_w_i32(buf, v.node_visits);
397 rec_w_i32(buf, v.leaf_visits);
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403 use crate::recording::{rec_patch_u32, rec_reserve_u32, RecHeader, Recording};
404
405 #[test]
408 fn wire_primitives_and_framing() {
409 let mut buf = Vec::new();
410 rec_w_u16(&mut buf, 0x1234);
411 rec_w_u32(&mut buf, 0xAABBCCDD);
412 rec_w_f32(&mut buf, 1.0);
413 rec_w_bool(&mut buf, true);
414 assert_eq!(
415 buf,
416 [0x34, 0x12, 0xDD, 0xCC, 0xBB, 0xAA, 0x00, 0x00, 0x80, 0x3F, 0x01]
417 );
418
419 let mut rec = Recording::new(64);
421 rec.begin_record(0x80);
422 rec_w_f32(&mut rec.buffer, 1.0 / 60.0);
423 rec_w_i32(&mut rec.buffer, 4);
424 rec.end_record();
425 assert_eq!(rec.buffer[0], 0x80);
426 assert_eq!(&rec.buffer[1..4], &[8, 0, 0]); assert_eq!(rec.buffer.len(), 12);
428
429 let mut rec2 = Recording::new(64);
431 rec2.commit_record(0x80, &rec.buffer[4..12]);
432 assert_eq!(rec2.buffer, rec.buffer);
433
434 let mut qbuf = Vec::new();
436 let offset = rec_reserve_u32(&mut qbuf);
437 rec_w_u8(&mut qbuf, 7);
438 rec_patch_u32(&mut qbuf, offset, 3);
439 assert_eq!(qbuf, [3, 0, 0, 0, 7]);
440 }
441
442 #[test]
444 fn header_round_trip() {
445 let header = RecHeader {
446 magic: crate::recording::REC_MAGIC,
447 version_major: crate::recording::REC_VERSION_MAJOR,
448 version_minor: crate::recording::REC_VERSION_MINOR,
449 length_scale: 1.0,
450 pointer_width: 8,
451 big_endian: 0,
452 validation_enabled: 1,
453 snapshot_size: 1234,
454 };
455 let mut buf = Vec::new();
456 header.write(&mut buf);
457 assert_eq!(buf.len(), RecHeader::SIZE);
458 assert_eq!(&buf[0..4], b"B2RC");
459 assert_eq!(RecHeader::read(&buf), Some(header));
460 }
461
462 #[test]
464 fn string_writer() {
465 let mut buf = Vec::new();
466 rec_w_str(&mut buf, "box");
467 assert_eq!(buf, [3, 0, b'b', b'o', b'x']);
468
469 let mut empty = Vec::new();
470 rec_w_str(&mut empty, "");
471 assert_eq!(empty, [0, 0]);
472 }
473}