1use std::cell::RefCell;
2use std::rc::Rc;
3
4use deno_core::OpState;
5
6use crate::physics::types::*;
7use crate::physics::world::PhysicsWorld;
8
9pub struct PhysicsState(pub Option<PhysicsWorld>);
11
12#[deno_core::op2(fast)]
13fn op_create_physics_world(state: &mut OpState, gravity_x: f64, gravity_y: f64) {
14 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
15 physics.borrow_mut().0 = Some(PhysicsWorld::new(gravity_x as f32, gravity_y as f32));
16}
17
18#[deno_core::op2(fast)]
19fn op_destroy_physics_world(state: &mut OpState) {
20 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
21 physics.borrow_mut().0 = None;
22}
23
24#[deno_core::op2(fast)]
25fn op_physics_step(state: &mut OpState, dt: f64) {
26 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
27 if let Some(world) = physics.borrow_mut().0.as_mut() {
28 world.step(dt as f32);
29 }
30}
31
32#[deno_core::op2(fast)]
36fn op_create_body(
37 state: &mut OpState,
38 body_type: u32,
39 shape_type: u32,
40 shape_p1: f64,
41 shape_p2: f64,
42 x: f64,
43 y: f64,
44 mass: f64,
45 restitution: f64,
46 friction: f64,
47 layer: u32,
48 mask: u32,
49) -> u32 {
50 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
51 let mut ps = physics.borrow_mut();
52 let world = match ps.0.as_mut() {
53 Some(w) => w,
54 None => return u32::MAX,
55 };
56
57 let bt = match body_type {
58 0 => BodyType::Static,
59 1 => BodyType::Dynamic,
60 2 => BodyType::Kinematic,
61 _ => return u32::MAX,
62 };
63
64 let shape = match shape_type {
65 0 => Shape::Circle {
66 radius: shape_p1 as f32,
67 },
68 1 => Shape::AABB {
69 half_w: shape_p1 as f32,
70 half_h: shape_p2 as f32,
71 },
72 _ => return u32::MAX,
73 };
74
75 let material = Material {
76 restitution: restitution as f32,
77 friction: friction as f32,
78 };
79
80 world.add_body(bt, shape, x as f32, y as f32, mass as f32, material, layer as u16, mask as u16)
81}
82
83#[deno_core::op2(fast)]
84fn op_remove_body(state: &mut OpState, id: u32) {
85 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
86 let mut ps = physics.borrow_mut();
87 if let Some(world) = ps.0.as_mut() {
88 world.remove_body(id);
89 }
90}
91
92#[deno_core::op2]
94#[serde]
95fn op_get_body_state(state: &mut OpState, id: u32) -> Vec<f64> {
96 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
97 let ps = physics.borrow();
98 match ps.0.as_ref().and_then(|w| w.get_body(id)) {
99 Some(body) => vec![
100 body.x as f64,
101 body.y as f64,
102 body.angle as f64,
103 body.vx as f64,
104 body.vy as f64,
105 body.angular_velocity as f64,
106 if body.sleeping { 1.0 } else { 0.0 },
107 ],
108 None => vec![],
109 }
110}
111
112#[deno_core::op2(fast)]
113fn op_set_body_velocity(state: &mut OpState, id: u32, vx: f64, vy: f64) {
114 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
115 let mut ps = physics.borrow_mut();
116 if let Some(world) = ps.0.as_mut() {
117 world.set_velocity(id, vx as f32, vy as f32);
118 }
119}
120
121#[deno_core::op2(fast)]
122fn op_set_body_angular_velocity(state: &mut OpState, id: u32, av: f64) {
123 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
124 let mut ps = physics.borrow_mut();
125 if let Some(world) = ps.0.as_mut() {
126 world.set_angular_velocity(id, av as f32);
127 }
128}
129
130#[deno_core::op2(fast)]
131fn op_apply_force(state: &mut OpState, id: u32, fx: f64, fy: f64) {
132 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
133 let mut ps = physics.borrow_mut();
134 if let Some(world) = ps.0.as_mut() {
135 world.apply_force(id, fx as f32, fy as f32);
136 }
137}
138
139#[deno_core::op2(fast)]
140fn op_apply_impulse(state: &mut OpState, id: u32, ix: f64, iy: f64) {
141 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
142 let mut ps = physics.borrow_mut();
143 if let Some(world) = ps.0.as_mut() {
144 world.apply_impulse(id, ix as f32, iy as f32);
145 }
146}
147
148#[deno_core::op2(fast)]
149fn op_set_body_position(state: &mut OpState, id: u32, x: f64, y: f64) {
150 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
151 let mut ps = physics.borrow_mut();
152 if let Some(world) = ps.0.as_mut() {
153 world.set_position(id, x as f32, y as f32);
154 }
155}
156
157#[deno_core::op2(fast)]
158fn op_set_collision_layers(state: &mut OpState, id: u32, layer: u32, mask: u32) {
159 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
160 let mut ps = physics.borrow_mut();
161 if let Some(world) = ps.0.as_mut() {
162 world.set_collision_layers(id, layer as u16, mask as u16);
163 }
164}
165
166#[deno_core::op2(fast)]
167fn op_create_distance_joint(
168 state: &mut OpState,
169 body_a: u32,
170 body_b: u32,
171 distance: f64,
172) -> u32 {
173 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
174 let mut ps = physics.borrow_mut();
175 match ps.0.as_mut() {
176 Some(world) => world.add_constraint(Constraint::Distance {
177 id: 0,
178 body_a,
179 body_b,
180 distance: distance as f32,
181 anchor_a: (0.0, 0.0),
182 anchor_b: (0.0, 0.0),
183 soft: None,
184 accumulated_impulse: 0.0,
185 }),
186 None => u32::MAX,
187 }
188}
189
190#[deno_core::op2(fast)]
191fn op_create_revolute_joint(
192 state: &mut OpState,
193 body_a: u32,
194 body_b: u32,
195 pivot_x: f64,
196 pivot_y: f64,
197) -> u32 {
198 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
199 let mut ps = physics.borrow_mut();
200 match ps.0.as_mut() {
201 Some(world) => {
202 let (anchor_a, anchor_b) = {
204 let ba = world.get_body(body_a);
205 let bb = world.get_body(body_b);
206 let pivot = (pivot_x as f32, pivot_y as f32);
207 let anchor_a = match ba {
208 Some(b) => {
209 let cos = b.angle.cos();
210 let sin = b.angle.sin();
211 let dx = pivot.0 - b.x;
212 let dy = pivot.1 - b.y;
213 (dx * cos + dy * sin, -dx * sin + dy * cos)
215 }
216 None => (0.0, 0.0),
217 };
218 let anchor_b = match bb {
219 Some(b) => {
220 let cos = b.angle.cos();
221 let sin = b.angle.sin();
222 let dx = pivot.0 - b.x;
223 let dy = pivot.1 - b.y;
224 (dx * cos + dy * sin, -dx * sin + dy * cos)
226 }
227 None => (0.0, 0.0),
228 };
229 (anchor_a, anchor_b)
230 };
231 world.add_constraint(Constraint::Revolute {
232 id: 0,
233 body_a,
234 body_b,
235 anchor_a,
236 anchor_b,
237 soft: None,
238 accumulated_impulse: (0.0, 0.0),
239 })
240 },
241 None => u32::MAX,
242 }
243}
244
245#[deno_core::op2(fast)]
249fn op_create_soft_distance_joint(
250 state: &mut OpState,
251 body_a: u32,
252 body_b: u32,
253 distance: f64,
254 frequency_hz: f64,
255 damping_ratio: f64,
256) -> u32 {
257 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
258 let mut ps = physics.borrow_mut();
259 match ps.0.as_mut() {
260 Some(world) => world.add_constraint(Constraint::Distance {
261 id: 0,
262 body_a,
263 body_b,
264 distance: distance as f32,
265 anchor_a: (0.0, 0.0),
266 anchor_b: (0.0, 0.0),
267 soft: Some(SoftConstraintParams::soft(frequency_hz as f32, damping_ratio as f32)),
268 accumulated_impulse: 0.0,
269 }),
270 None => u32::MAX,
271 }
272}
273
274#[deno_core::op2(fast)]
276fn op_create_soft_revolute_joint(
277 state: &mut OpState,
278 body_a: u32,
279 body_b: u32,
280 pivot_x: f64,
281 pivot_y: f64,
282 frequency_hz: f64,
283 damping_ratio: f64,
284) -> u32 {
285 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
286 let mut ps = physics.borrow_mut();
287 match ps.0.as_mut() {
288 Some(world) => {
289 let (anchor_a, anchor_b) = {
290 let ba = world.get_body(body_a);
291 let bb = world.get_body(body_b);
292 let pivot = (pivot_x as f32, pivot_y as f32);
293 let anchor_a = match ba {
294 Some(b) => {
295 let cos = b.angle.cos();
296 let sin = b.angle.sin();
297 let dx = pivot.0 - b.x;
298 let dy = pivot.1 - b.y;
299 (dx * cos + dy * sin, -dx * sin + dy * cos)
300 }
301 None => (0.0, 0.0),
302 };
303 let anchor_b = match bb {
304 Some(b) => {
305 let cos = b.angle.cos();
306 let sin = b.angle.sin();
307 let dx = pivot.0 - b.x;
308 let dy = pivot.1 - b.y;
309 (dx * cos + dy * sin, -dx * sin + dy * cos)
310 }
311 None => (0.0, 0.0),
312 };
313 (anchor_a, anchor_b)
314 };
315 world.add_constraint(Constraint::Revolute {
316 id: 0,
317 body_a,
318 body_b,
319 anchor_a,
320 anchor_b,
321 soft: Some(SoftConstraintParams::soft(frequency_hz as f32, damping_ratio as f32)),
322 accumulated_impulse: (0.0, 0.0),
323 })
324 },
325 None => u32::MAX,
326 }
327}
328
329#[deno_core::op2(fast)]
330fn op_remove_constraint(state: &mut OpState, id: u32) {
331 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
332 let mut ps = physics.borrow_mut();
333 if let Some(world) = ps.0.as_mut() {
334 world.remove_constraint(id);
335 }
336}
337
338#[deno_core::op2]
340#[serde]
341fn op_query_aabb(
342 state: &mut OpState,
343 min_x: f64,
344 min_y: f64,
345 max_x: f64,
346 max_y: f64,
347) -> Vec<u32> {
348 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
349 let ps = physics.borrow();
350 match ps.0.as_ref() {
351 Some(world) => world.query_aabb(min_x as f32, min_y as f32, max_x as f32, max_y as f32),
352 None => vec![],
353 }
354}
355
356#[deno_core::op2]
358#[serde]
359fn op_raycast(
360 state: &mut OpState,
361 origin_x: f64,
362 origin_y: f64,
363 dir_x: f64,
364 dir_y: f64,
365 max_dist: f64,
366) -> Vec<f64> {
367 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
368 let ps = physics.borrow();
369 match ps.0.as_ref() {
370 Some(world) => {
371 match world.raycast(
372 origin_x as f32,
373 origin_y as f32,
374 dir_x as f32,
375 dir_y as f32,
376 max_dist as f32,
377 ) {
378 Some((id, hx, hy, dist)) => {
379 vec![id as f64, hx as f64, hy as f64, dist as f64]
380 }
381 None => vec![],
382 }
383 }
384 None => vec![],
385 }
386}
387
388#[deno_core::op2]
391fn op_create_polygon_body(
392 state: &mut OpState,
393 body_type: u32,
394 #[serde] vertices: Vec<f64>,
395 x: f64,
396 y: f64,
397 mass: f64,
398 restitution: f64,
399 friction: f64,
400 layer: u32,
401 mask: u32,
402) -> u32 {
403 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
404 let mut ps = physics.borrow_mut();
405 let world = match ps.0.as_mut() {
406 Some(w) => w,
407 None => return u32::MAX,
408 };
409
410 let bt = match body_type {
411 0 => BodyType::Static,
412 1 => BodyType::Dynamic,
413 2 => BodyType::Kinematic,
414 _ => return u32::MAX,
415 };
416
417 if vertices.len() < 6 || vertices.len() % 2 != 0 {
419 return u32::MAX; }
421 let polygon_verts: Vec<(f32, f32)> = vertices
422 .chunks(2)
423 .map(|c| (c[0] as f32, c[1] as f32))
424 .collect();
425
426 let shape = Shape::Polygon { vertices: polygon_verts };
427
428 let material = Material {
429 restitution: restitution as f32,
430 friction: friction as f32,
431 };
432
433 world.add_body(bt, shape, x as f32, y as f32, mass as f32, material, layer as u16, mask as u16)
434}
435
436#[deno_core::op2]
438#[serde]
439fn op_get_contacts(state: &mut OpState) -> Vec<f64> {
440 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
441 let ps = physics.borrow();
442 match ps.0.as_ref() {
443 Some(world) => {
444 let contacts = world.get_contacts();
445 let mut result = Vec::with_capacity(contacts.len() * 7);
446 for c in contacts {
447 result.push(c.body_a as f64);
448 result.push(c.body_b as f64);
449 result.push(c.normal.0 as f64);
450 result.push(c.normal.1 as f64);
451 result.push(c.penetration as f64);
452 result.push(c.contact_point.0 as f64);
453 result.push(c.contact_point.1 as f64);
454 }
455 result
456 }
457 None => vec![],
458 }
459}
460
461#[deno_core::op2]
466#[serde]
467fn op_get_manifolds(state: &mut OpState) -> Vec<f64> {
468 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
469 let ps = physics.borrow();
470 match ps.0.as_ref() {
471 Some(world) => {
472 let manifolds = world.get_manifolds();
473 let mut result = Vec::with_capacity(manifolds.len() * 10);
475 for m in manifolds {
476 result.push(m.body_a as f64);
477 result.push(m.body_b as f64);
478 result.push(m.normal.0 as f64);
479 result.push(m.normal.1 as f64);
480 result.push(m.points.len() as f64);
481 for point in &m.points {
482 result.push(point.local_a.0 as f64);
483 result.push(point.local_a.1 as f64);
484 result.push(point.local_b.0 as f64);
485 result.push(point.local_b.1 as f64);
486 result.push(point.penetration as f64);
487 }
488 }
489 result
490 }
491 None => vec![],
492 }
493}
494
495#[deno_core::op2]
499#[serde]
500fn op_get_all_body_states(state: &mut OpState) -> Vec<f64> {
501 let physics = state.borrow_mut::<Rc<RefCell<PhysicsState>>>();
502 let ps = physics.borrow();
503 match ps.0.as_ref() {
504 Some(world) => {
505 let bodies = world.all_bodies();
506 let mut result = Vec::with_capacity(bodies.len() * 8);
507 for body in bodies {
508 result.push(body.id as f64);
509 result.push(body.x as f64);
510 result.push(body.y as f64);
511 result.push(body.vx as f64);
512 result.push(body.vy as f64);
513 result.push(body.angle as f64);
514 result.push(body.angular_velocity as f64);
515 result.push(if body.sleeping { 1.0 } else { 0.0 });
516 }
517 result
518 }
519 None => vec![],
520 }
521}
522
523deno_core::extension!(
524 physics_ext,
525 ops = [
526 op_create_physics_world,
527 op_destroy_physics_world,
528 op_physics_step,
529 op_create_body,
530 op_create_polygon_body,
531 op_remove_body,
532 op_get_body_state,
533 op_set_body_velocity,
534 op_set_body_angular_velocity,
535 op_apply_force,
536 op_apply_impulse,
537 op_set_body_position,
538 op_set_collision_layers,
539 op_create_distance_joint,
540 op_create_revolute_joint,
541 op_create_soft_distance_joint,
542 op_create_soft_revolute_joint,
543 op_remove_constraint,
544 op_query_aabb,
545 op_raycast,
546 op_get_contacts,
547 op_get_manifolds,
548 op_get_all_body_states,
549 ],
550);