1use crate::math::Vec3;
2use crate::physics::{Collider, ColliderShape, GpuPhysicsLink, RigidBody, Transform};
3use crate::renderer::Renderer;
4
5pub fn physics_debug_system(world: &crate::core::World) {
6 if let Some(mut gizmos) = world.get_resource_mut::<crate::renderer::Gizmos>() {
7 let draw_collider = |trans: &Transform,
8 col: &Collider,
9 color: [f32; 4],
10 gizmos: &mut crate::renderer::Gizmos| {
11 match &col.shape {
12 gizmo_physics::ColliderShape::Box(b) => {
13 let h = b.half_extents;
14 let r = trans.rotation;
15 let p = trans.position;
16 let p0 = p + r.mul_vec3(Vec3::new(-h.x, -h.y, -h.z));
17 let p1 = p + r.mul_vec3(Vec3::new(h.x, -h.y, -h.z));
18 let p2 = p + r.mul_vec3(Vec3::new(h.x, h.y, -h.z));
19 let p3 = p + r.mul_vec3(Vec3::new(-h.x, h.y, -h.z));
20 let p4 = p + r.mul_vec3(Vec3::new(-h.x, -h.y, h.z));
21 let p5 = p + r.mul_vec3(Vec3::new(h.x, -h.y, h.z));
22 let p6 = p + r.mul_vec3(Vec3::new(h.x, h.y, h.z));
23 let p7 = p + r.mul_vec3(Vec3::new(-h.x, h.y, h.z));
24
25 gizmos.draw_line(p0, p1, color);
26 gizmos.draw_line(p1, p2, color);
27 gizmos.draw_line(p2, p3, color);
28 gizmos.draw_line(p3, p0, color);
29 gizmos.draw_line(p4, p5, color);
30 gizmos.draw_line(p5, p6, color);
31 gizmos.draw_line(p6, p7, color);
32 gizmos.draw_line(p7, p4, color);
33 gizmos.draw_line(p0, p4, color);
34 gizmos.draw_line(p1, p5, color);
35 gizmos.draw_line(p2, p6, color);
36 gizmos.draw_line(p3, p7, color);
37 }
38 gizmo_physics::ColliderShape::Sphere(s) => {
39 let r = s.radius;
40 let min = trans.position - Vec3::new(r, r, r);
41 let max = trans.position + Vec3::new(r, r, r);
42 gizmos.draw_box(min, max, color);
43 }
44 gizmo_physics::ColliderShape::ConvexHull(ch) => {
45 let r = trans.rotation;
46 let p = trans.position;
47 for face in ch.faces.iter() {
48 let p0 = p + r.mul_vec3(ch.vertices[face[0] as usize]);
49 let p1 = p + r.mul_vec3(ch.vertices[face[1] as usize]);
50 let p2 = p + r.mul_vec3(ch.vertices[face[2] as usize]);
51 gizmos.draw_line(p0, p1, color);
52 gizmos.draw_line(p1, p2, color);
53 gizmos.draw_line(p2, p0, color);
54 }
55 }
56 _ => {
57 let min = trans.position - Vec3::new(1.0, 1.0, 1.0);
58 let max = trans.position + Vec3::new(1.0, 1.0, 1.0);
59 gizmos.draw_box(min, max, color);
60 }
61 }
62 };
63
64 if let Some(q) = world.query::<(
65 &crate::physics::Transform,
66 &gizmo_physics::Collider,
67 &gizmo_physics::RigidBody,
68 )>() {
69 for (_, (trans, col, rb)) in q.iter() {
70 let color = if rb.is_static() {
71 [0.5, 0.5, 0.5, 1.0]
72 } else if rb.is_sleeping {
73 [0.9, 0.1, 0.1, 1.0]
74 } else {
75 [0.1, 0.9, 0.1, 1.0]
76 };
77 draw_collider(trans, col, color, &mut gizmos);
78 }
79 }
80
81 if let Some(q) = world.query::<(
82 &crate::physics::Transform,
83 &gizmo_physics::Collider,
84 crate::core::query::Without<gizmo_physics::RigidBody>,
85 )>() {
86 for (_, (trans, col, _)) in q.iter() {
87 draw_collider(trans, col, [0.5, 0.5, 0.5, 1.0], &mut gizmos);
88 }
89 }
90
91 let soft_color = [1.0, 0.4, 0.8, 1.0]; if let Some(q) = world.query::<&gizmo_physics::soft_body::SoftBodyMesh>() {
93 for (_, sm) in q.iter() {
94 for elem in &sm.elements {
95 let p0 = sm.nodes[elem.node_indices[0] as usize].position;
96 let p1 = sm.nodes[elem.node_indices[1] as usize].position;
97 let p2 = sm.nodes[elem.node_indices[2] as usize].position;
98 let p3 = sm.nodes[elem.node_indices[3] as usize].position;
99
100 gizmos.draw_line(p0, p1, soft_color);
102 gizmos.draw_line(p0, p2, soft_color);
103 gizmos.draw_line(p0, p3, soft_color);
104 gizmos.draw_line(p1, p2, soft_color);
105 gizmos.draw_line(p1, p3, soft_color);
106 gizmos.draw_line(p2, p3, soft_color);
107 }
108 }
109 }
110
111 if let Some(q) = world.query::<(
113 &crate::physics::Transform,
114 &gizmo_physics::vehicle::VehicleController,
115 )>() {
116 for (_, (trans, vehicle)) in q.iter() {
117 for wheel in &vehicle.wheels {
118 let attach_world =
119 trans.position + trans.rotation.mul_vec3(wheel.attachment_local_pos);
120 let ray_dir = trans.rotation.mul_vec3(wheel.direction_local).normalize();
121 let ray_end = attach_world
122 + ray_dir
123 * (wheel.suspension_rest_length
124 + wheel.suspension_max_travel
125 + wheel.radius);
126
127 gizmos.draw_line(attach_world, ray_end, [1.0, 1.0, 0.0, 1.0]);
129
130 if wheel.is_grounded {
131 if let Some(hit) = &wheel.ground_hit {
132 let force_dir = -ray_dir;
134 let force_len = (wheel.suspension_force / 10000.0).clamp(0.1, 2.0);
135 let arrow_end = hit.point + force_dir * force_len;
136 gizmos.draw_line(hit.point, arrow_end, [0.0, 0.0, 1.0, 1.0]);
137
138 let wheel_center = attach_world + ray_dir * wheel.suspension_length;
140 gizmos.draw_line(wheel_center, hit.point, [1.0, 0.5, 0.0, 1.0]);
141 }
142 }
143 }
144 }
145 }
146
147 if let Some(phys_world) = world.get_resource::<gizmo_physics::world::PhysicsWorld>() {
149 for event in phys_world.collision_events() {
150 for contact in &event.contact_points {
151 let p1 = contact.point;
152 let p2 = contact.point + contact.normal * 0.5; gizmos.draw_line(p1, p2, [1.0, 0.0, 0.0, 1.0]); let p_pen = contact.point - contact.normal * contact.penetration;
156 gizmos.draw_line(p1, p_pen, [1.0, 0.0, 1.0, 1.0]); }
158 }
159 }
160 tracing::info!(
161 "physics_debug_system: gizmos lines count = {}",
162 gizmos.lines.len()
163 );
164 }
165}
166
167static NEXT_STATIC_COLLIDER_SLOT: std::sync::atomic::AtomicU32 =
171 std::sync::atomic::AtomicU32::new(3);
172
173pub fn gpu_physics_submit_system(world: &mut crate::core::World, renderer: &Renderer) {
174 use crate::physics::Velocity;
175
176 if let Some(physics) = &renderer.gpu_physics {
177 let mut unlinked_entities = Vec::new();
178 if let Some(q) = world.query::<(&RigidBody, &Transform, &Collider)>() {
179 let links = world.borrow::<GpuPhysicsLink>();
180 let velocities = world.borrow::<Velocity>();
181 for (e, (rb, trans, col)) in q.iter() {
182 if links.get(e).is_none() {
183 let vel = velocities.get(e).copied().unwrap_or_default();
184 unlinked_entities.push((e, *rb, *trans, col.clone(), vel));
185 }
186 }
187 }
188
189 let mut next_dynamic_id = world
190 .query::<&GpuPhysicsLink>()
191 .map(|q| q.iter().count() as u32)
192 .unwrap_or(0);
193
194 for (e, rb, trans, col, vel) in unlinked_entities {
195 if matches!(col.shape, ColliderShape::Plane(_)) {
196 let slot =
198 NEXT_STATIC_COLLIDER_SLOT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
199 if slot >= 100 {
200 eprintln!("[GpuPhysics] Statik collider slot limiti (100) aşıldı, collider atlanıyor.");
201 NEXT_STATIC_COLLIDER_SLOT.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
202 continue;
203 }
204
205 let gpu_col = gizmo_renderer::gpu_physics::GpuCollider {
206 shape_type: match col.shape {
207 ColliderShape::Plane(_) => 1,
208 _ => 0, },
210 _pad1: [0; 3],
211 data1: match &col.shape {
212 ColliderShape::Plane(p) => [p.normal.x, p.normal.y, p.normal.z, 0.0],
213 ColliderShape::Box(b) => {
214 let min = trans.position - b.half_extents;
215 [min.x, min.y, min.z, 0.0]
216 }
217 _ => [0.0; 4],
218 },
219 data2: match &col.shape {
220 ColliderShape::Plane(p) => [p.distance, 0.0, 0.0, 0.0],
221 ColliderShape::Box(b) => {
222 let max = trans.position + b.half_extents;
223 [max.x, max.y, max.z, 0.0]
224 }
225 _ => [0.0; 4],
226 },
227 };
228 physics.update_collider(&renderer.queue, slot, &gpu_col);
229 } else {
230 let id = next_dynamic_id;
232 next_dynamic_id += 1;
233
234 let extents = match &col.shape {
235 ColliderShape::Box(b) => [b.half_extents.x, b.half_extents.y, b.half_extents.z],
236 _ => [0.5, 0.5, 0.5],
237 };
238
239 let gpu_box = gizmo_renderer::gpu_physics::GpuBox {
240 position: [trans.position.x, trans.position.y, trans.position.z],
241 mass: rb.mass,
242 velocity: [vel.linear.x, vel.linear.y, vel.linear.z],
243 state: 0,
244 rotation: [
245 trans.rotation.x,
246 trans.rotation.y,
247 trans.rotation.z,
248 trans.rotation.w,
249 ],
250 angular_velocity: [vel.angular.x, vel.angular.y, vel.angular.z],
251 sleep_counter: if rb.is_sleeping { 60 } else { 0 },
252 color: [0.3, 0.8, 1.0, 1.0],
253 half_extents: extents,
254 _pad: 0,
255 };
256 physics.update_box(&renderer.queue, id, &gpu_box);
257
258 world.add_component(world.get_entity(e).unwrap(), GpuPhysicsLink { id });
259 }
260 }
261 }
262}
263
264pub fn gpu_physics_readback_system(world: &mut crate::core::World, renderer: &Renderer) {
267 if let Some(physics) = &renderer.gpu_physics {
268 if let Some(gpu_data) = physics.poll_readback_data(&renderer.device) {
269 if let Some(mut q) =
270 world.query::<(gizmo_core::prelude::Mut<Transform>, &GpuPhysicsLink)>()
271 {
272 for (_, (mut trans, link)) in q.iter_mut() {
273 let idx = link.id as usize;
274 if idx < gpu_data.len() {
275 let box_data = &gpu_data[idx];
276 trans.position = gizmo_math::Vec3::new(
277 box_data.position[0],
278 box_data.position[1],
279 box_data.position[2],
280 );
281 trans.rotation = gizmo_math::Quat::from_xyzw(
282 box_data.rotation[0],
283 box_data.rotation[1],
284 box_data.rotation[2],
285 box_data.rotation[3],
286 );
287 trans.update_local_matrix();
288 }
289 }
290 }
291 }
292 }
293}
294
295pub fn cpu_physics_step_system(world: &crate::core::World, dt: f32) {
299 gizmo_physics::system::physics_step_system(world, dt);
300}