box3d_rust/shape/
mutators.rs1use super::dispatch::update_shape_aabbs;
7use super::lifecycle::get_shape;
8use crate::body::get_body_transform_quick;
9use crate::broad_phase::proxy_type;
10use crate::core::NULL_INDEX;
11use crate::geometry::{ShapeType, SurfaceMaterial};
12use crate::id::ShapeId;
13use crate::math_functions::{is_valid_float, is_valid_vec3};
14use crate::types::Filter;
15use crate::world::World;
16
17pub(crate) fn reset_proxy(
20 world: &mut World,
21 shape_index: i32,
22 wake_bodies: bool,
23 destroy_proxy: bool,
24) {
25 let body_id = world.shapes[shape_index as usize].body_id;
26 let shape_id = world.shapes[shape_index as usize].id;
27
28 let mut contact_key = world.bodies[body_id as usize].head_contact_key;
30 while contact_key != NULL_INDEX {
31 let contact_id = contact_key >> 1;
32 let edge_index = contact_key & 1;
33 let next_key = world.contacts[contact_id as usize].edges[edge_index as usize].next_key;
34 let shape_id_a = world.contacts[contact_id as usize].shape_id_a;
35 let shape_id_b = world.contacts[contact_id as usize].shape_id_b;
36 contact_key = next_key;
37
38 if shape_id_a == shape_id || shape_id_b == shape_id {
39 crate::contact::destroy_contact(world, contact_id, wake_bodies);
40 }
41 }
42
43 let transform = get_body_transform_quick(world, &world.bodies[body_id as usize]);
44 let proxy_key = world.shapes[shape_index as usize].proxy_key;
45
46 if proxy_key != NULL_INDEX {
47 let proxy_type_ = proxy_type(proxy_key);
48 update_shape_aabbs(
49 &mut world.shapes[shape_index as usize],
50 transform,
51 proxy_type_,
52 );
53
54 if destroy_proxy {
55 let fat_aabb = world.shapes[shape_index as usize].fat_aabb;
56 let category_bits = world.shapes[shape_index as usize].filter.category_bits;
57 world.broad_phase.destroy_proxy(proxy_key);
58
59 let force_pair_creation = true;
60 world.shapes[shape_index as usize].proxy_key = world.broad_phase.create_proxy(
61 proxy_type_,
62 fat_aabb,
63 category_bits,
64 shape_id,
65 force_pair_creation,
66 );
67 } else {
68 let fat_aabb = world.shapes[shape_index as usize].fat_aabb;
69 world.broad_phase.move_proxy(proxy_key, fat_aabb);
70 }
71 } else {
72 let proxy_type_ = world.bodies[body_id as usize].type_;
73 update_shape_aabbs(
74 &mut world.shapes[shape_index as usize],
75 transform,
76 proxy_type_,
77 );
78 }
79
80 world.validate_solver_sets();
81}
82
83pub fn shape_set_friction(world: &mut World, shape_id: ShapeId, friction: f32) {
85 crate::recording::with_recording(world, |rec| {
86 rec.write_shape_set_friction(shape_id, friction);
87 });
88 debug_assert!(is_valid_float(friction) && friction >= 0.0);
89 let index = get_shape(world, shape_id);
90 let shape = &mut world.shapes[index as usize];
91 debug_assert!(shape.shape_type() != ShapeType::Compound);
92 shape.shape_materials_mut()[0].friction = friction;
93}
94
95pub fn shape_get_friction(world: &World, shape_id: ShapeId) -> f32 {
97 let index = get_shape(world, shape_id);
98 world.shapes[index as usize].shape_materials()[0].friction
99}
100
101pub fn shape_set_restitution(world: &mut World, shape_id: ShapeId, restitution: f32) {
103 crate::recording::with_recording(world, |rec| {
104 rec.write_shape_set_restitution(shape_id, restitution);
105 });
106 debug_assert!(is_valid_float(restitution) && restitution >= 0.0);
107 let index = get_shape(world, shape_id);
108 let shape = &mut world.shapes[index as usize];
109 debug_assert!(shape.shape_type() != ShapeType::Compound);
110 shape.shape_materials_mut()[0].restitution = restitution;
111}
112
113pub fn shape_get_restitution(world: &World, shape_id: ShapeId) -> f32 {
115 let index = get_shape(world, shape_id);
116 world.shapes[index as usize].shape_materials()[0].restitution
117}
118
119pub fn shape_set_surface_material(
121 world: &mut World,
122 shape_id: ShapeId,
123 surface_material: SurfaceMaterial,
124) {
125 crate::recording::with_recording(world, |rec| {
126 rec.write_shape_set_surface_material(shape_id, surface_material);
127 });
128 debug_assert!(is_valid_float(surface_material.friction) && surface_material.friction >= 0.0);
129 debug_assert!(
130 is_valid_float(surface_material.restitution) && surface_material.restitution >= 0.0
131 );
132 debug_assert!(
133 is_valid_float(surface_material.rolling_resistance)
134 && surface_material.rolling_resistance >= 0.0
135 );
136 debug_assert!(is_valid_vec3(surface_material.tangent_velocity));
137
138 let index = get_shape(world, shape_id);
139 let shape = &mut world.shapes[index as usize];
140 debug_assert!(shape.shape_type() != ShapeType::Compound);
141 shape.shape_materials_mut()[0] = surface_material;
142}
143
144pub fn shape_get_surface_material(world: &World, shape_id: ShapeId) -> SurfaceMaterial {
146 let index = get_shape(world, shape_id);
147 world.shapes[index as usize].shape_materials()[0]
148}
149
150pub fn shape_get_mesh_material_count(world: &World, shape_id: ShapeId) -> i32 {
152 let index = get_shape(world, shape_id);
153 world.shapes[index as usize].material_count()
154}
155
156pub fn shape_set_mesh_material(
158 world: &mut World,
159 shape_id: ShapeId,
160 surface_material: SurfaceMaterial,
161 material_index: i32,
162) {
163 debug_assert!(is_valid_float(surface_material.friction) && surface_material.friction >= 0.0);
164 debug_assert!(
165 is_valid_float(surface_material.restitution) && surface_material.restitution >= 0.0
166 );
167 debug_assert!(
168 is_valid_float(surface_material.rolling_resistance)
169 && surface_material.rolling_resistance >= 0.0
170 );
171 debug_assert!(is_valid_vec3(surface_material.tangent_velocity));
172
173 let index = get_shape(world, shape_id);
174 let shape = &mut world.shapes[index as usize];
175 debug_assert!(0 <= material_index && material_index < shape.material_count());
176 debug_assert!(shape.shape_type() != ShapeType::Compound);
177 shape.shape_materials_mut()[material_index as usize] = surface_material;
178}
179
180pub fn shape_get_mesh_surface_material(
182 world: &World,
183 shape_id: ShapeId,
184 material_index: i32,
185) -> SurfaceMaterial {
186 let index = get_shape(world, shape_id);
187 let shape = &world.shapes[index as usize];
188 debug_assert!(0 <= material_index && material_index < shape.material_count());
189 shape.shape_materials()[material_index as usize]
190}
191
192pub fn shape_get_filter(world: &World, shape_id: ShapeId) -> Filter {
194 let index = get_shape(world, shape_id);
195 world.shapes[index as usize].filter
196}
197
198pub fn shape_set_filter(
203 world: &mut World,
204 shape_id: ShapeId,
205 filter: Filter,
206 invoke_contacts: bool,
207) {
208 crate::recording::with_recording(world, |rec| {
209 rec.write_shape_set_filter(shape_id, filter, invoke_contacts);
210 });
211 debug_assert!(!world.locked);
212 if world.locked {
213 return;
214 }
215
216 let index = get_shape(world, shape_id);
217 let shape = &mut world.shapes[index as usize];
218 if filter.mask_bits == shape.filter.mask_bits
219 && filter.category_bits == shape.filter.category_bits
220 && filter.group_index == shape.filter.group_index
221 {
222 return;
223 }
224
225 shape.filter = filter;
226
227 if invoke_contacts {
228 world.locked = true;
229 let wake_bodies = true;
230 let destroy_proxy =
233 filter.category_bits == world.shapes[index as usize].filter.category_bits;
234 reset_proxy(world, index, wake_bodies, destroy_proxy);
235 world.locked = false;
236 }
237
238 }