@bornengine/engine 0.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +231 -0
- package/native/android/Cargo.lock +1848 -0
- package/native/android/Cargo.toml +24 -0
- package/native/android/src/lib.rs +702 -0
- package/native/ios/Cargo.lock +1690 -0
- package/native/ios/Cargo.toml +32 -0
- package/native/ios/src/lib.rs +1267 -0
- package/native/linux/Cargo.lock +3279 -0
- package/native/linux/Cargo.toml +29 -0
- package/native/linux/src/lib.rs +1331 -0
- package/native/macos/Cargo.lock +3310 -0
- package/native/macos/Cargo.toml +46 -0
- package/native/macos/src/lib.rs +1302 -0
- package/native/shared/Cargo.lock +1899 -0
- package/native/shared/Cargo.toml +62 -0
- package/native/shared/assets/default_font.ttf +0 -0
- package/native/shared/build.rs +270 -0
- package/native/shared/shaders/common/clouds.wgsl +122 -0
- package/native/shared/shaders/common/fog.wgsl +16 -0
- package/native/shared/shaders/common/foliage_wind.wgsl +98 -0
- package/native/shared/shaders/common/imposter.wgsl +112 -0
- package/native/shared/shaders/common/pbr.wgsl +186 -0
- package/native/shared/shaders/common/shadows.wgsl +186 -0
- package/native/shared/shaders/common/sky.wgsl +8 -0
- package/native/shared/shaders/common/tonemap.wgsl +25 -0
- package/native/shared/shaders/impulse_field.wgsl +57 -0
- package/native/shared/shaders/material_abi.wgsl +383 -0
- package/native/shared/shaders/materials/test_minimal.wgsl +42 -0
- package/native/shared/src/anim_mixer.rs +61 -0
- package/native/shared/src/attach.rs +263 -0
- package/native/shared/src/audio/decode.rs +123 -0
- package/native/shared/src/audio/mod.rs +863 -0
- package/native/shared/src/audio/render.rs +892 -0
- package/native/shared/src/audio/spsc.rs +156 -0
- package/native/shared/src/audio/stream.rs +226 -0
- package/native/shared/src/custom_shaders.rs +104 -0
- package/native/shared/src/decals.rs +245 -0
- package/native/shared/src/drs.rs +211 -0
- package/native/shared/src/engine.rs +261 -0
- package/native/shared/src/ffi.rs +116 -0
- package/native/shared/src/ffi_core/assets.rs +388 -0
- package/native/shared/src/ffi_core/audio_ffi.rs +184 -0
- package/native/shared/src/ffi_core/draw.rs +334 -0
- package/native/shared/src/ffi_core/game_loop.rs +577 -0
- package/native/shared/src/ffi_core/input.rs +234 -0
- package/native/shared/src/ffi_core/mod.rs +127 -0
- package/native/shared/src/ffi_core/models.rs +1154 -0
- package/native/shared/src/ffi_core/ragdoll_ffi.rs +261 -0
- package/native/shared/src/ffi_core/scene.rs +626 -0
- package/native/shared/src/ffi_core/vfx.rs +212 -0
- package/native/shared/src/ffi_core/visual.rs +691 -0
- package/native/shared/src/frame_callbacks.rs +122 -0
- package/native/shared/src/geometry.rs +236 -0
- package/native/shared/src/handles.rs +182 -0
- package/native/shared/src/input.rs +448 -0
- package/native/shared/src/jolt_sys.rs +822 -0
- package/native/shared/src/lib.rs +55 -0
- package/native/shared/src/models.rs +1093 -0
- package/native/shared/src/models_gltf.rs +1280 -0
- package/native/shared/src/particles.rs +391 -0
- package/native/shared/src/physics_jolt.rs +1908 -0
- package/native/shared/src/picking.rs +298 -0
- package/native/shared/src/postfx.rs +345 -0
- package/native/shared/src/profiler.rs +492 -0
- package/native/shared/src/ragdoll.rs +474 -0
- package/native/shared/src/renderer/atmosphere_lut.rs +573 -0
- package/native/shared/src/renderer/brdf_lut.rs +154 -0
- package/native/shared/src/renderer/draw2d.rs +143 -0
- package/native/shared/src/renderer/formats.rs +822 -0
- package/native/shared/src/renderer/froxel.rs +421 -0
- package/native/shared/src/renderer/gi_bake.rs +653 -0
- package/native/shared/src/renderer/graph.rs +462 -0
- package/native/shared/src/renderer/hiz.rs +269 -0
- package/native/shared/src/renderer/hot_reload.rs +390 -0
- package/native/shared/src/renderer/impulse_field.rs +456 -0
- package/native/shared/src/renderer/lighting.rs +154 -0
- package/native/shared/src/renderer/material_instancing.rs +171 -0
- package/native/shared/src/renderer/material_pipeline.rs +700 -0
- package/native/shared/src/renderer/material_system.rs +1996 -0
- package/native/shared/src/renderer/material_system_tests.rs +601 -0
- package/native/shared/src/renderer/material_system_wasm.rs +41 -0
- package/native/shared/src/renderer/mod.rs +12556 -0
- package/native/shared/src/renderer/model_draw.rs +641 -0
- package/native/shared/src/renderer/occlusion.rs +429 -0
- package/native/shared/src/renderer/planar_pass.rs +593 -0
- package/native/shared/src/renderer/planar_reflection.rs +499 -0
- package/native/shared/src/renderer/post_pass.rs +249 -0
- package/native/shared/src/renderer/postfx_chain.rs +728 -0
- package/native/shared/src/renderer/pt_pass.rs +577 -0
- package/native/shared/src/renderer/scene_pass.rs +607 -0
- package/native/shared/src/renderer/shader_include.rs +205 -0
- package/native/shared/src/renderer/shader_library.rs +135 -0
- package/native/shared/src/renderer/shaders/ao.rs +570 -0
- package/native/shared/src/renderer/shaders/core.rs +1243 -0
- package/native/shared/src/renderer/shaders/env.rs +907 -0
- package/native/shared/src/renderer/shaders/gi.rs +810 -0
- package/native/shared/src/renderer/shaders/mod.rs +19 -0
- package/native/shared/src/renderer/shaders/post.rs +1558 -0
- package/native/shared/src/renderer/shaders/pt.rs +1859 -0
- package/native/shared/src/renderer/shaders/ssgi.rs +1586 -0
- package/native/shared/src/renderer/shadow_pass.rs +731 -0
- package/native/shared/src/renderer/ssgi_pass.rs +392 -0
- package/native/shared/src/renderer/ssr_pass.rs +188 -0
- package/native/shared/src/renderer/texture_store.rs +473 -0
- package/native/shared/src/renderer/transient.rs +591 -0
- package/native/shared/src/renderer/types.rs +941 -0
- package/native/shared/src/renderer/util.rs +152 -0
- package/native/shared/src/scene.rs +1362 -0
- package/native/shared/src/sdf_cache.rs +274 -0
- package/native/shared/src/shadows.rs +1036 -0
- package/native/shared/src/staging.rs +102 -0
- package/native/shared/src/string_header.rs +266 -0
- package/native/shared/src/text_renderer.rs +502 -0
- package/native/shared/src/textures.rs +197 -0
- package/native/tvos/Cargo.lock +1693 -0
- package/native/tvos/Cargo.toml +36 -0
- package/native/tvos/metal-patched/Cargo.toml +178 -0
- package/native/tvos/metal-patched/LICENSE-APACHE +201 -0
- package/native/tvos/metal-patched/LICENSE-MIT +25 -0
- package/native/tvos/metal-patched/src/acceleration_structure.rs +667 -0
- package/native/tvos/metal-patched/src/acceleration_structure_pass.rs +108 -0
- package/native/tvos/metal-patched/src/argument.rs +366 -0
- package/native/tvos/metal-patched/src/blitpass.rs +102 -0
- package/native/tvos/metal-patched/src/buffer.rs +71 -0
- package/native/tvos/metal-patched/src/capturedescriptor.rs +76 -0
- package/native/tvos/metal-patched/src/capturemanager.rs +113 -0
- package/native/tvos/metal-patched/src/commandbuffer.rs +192 -0
- package/native/tvos/metal-patched/src/commandqueue.rs +44 -0
- package/native/tvos/metal-patched/src/computepass.rs +107 -0
- package/native/tvos/metal-patched/src/constants.rs +152 -0
- package/native/tvos/metal-patched/src/counters.rs +119 -0
- package/native/tvos/metal-patched/src/depthstencil.rs +190 -0
- package/native/tvos/metal-patched/src/device.rs +2134 -0
- package/native/tvos/metal-patched/src/drawable.rs +39 -0
- package/native/tvos/metal-patched/src/encoder.rs +2041 -0
- package/native/tvos/metal-patched/src/heap.rs +281 -0
- package/native/tvos/metal-patched/src/indirect_encoder.rs +344 -0
- package/native/tvos/metal-patched/src/lib.rs +657 -0
- package/native/tvos/metal-patched/src/library.rs +902 -0
- package/native/tvos/metal-patched/src/mps.rs +575 -0
- package/native/tvos/metal-patched/src/pipeline/compute.rs +475 -0
- package/native/tvos/metal-patched/src/pipeline/mod.rs +71 -0
- package/native/tvos/metal-patched/src/pipeline/render.rs +762 -0
- package/native/tvos/metal-patched/src/renderpass.rs +443 -0
- package/native/tvos/metal-patched/src/resource.rs +182 -0
- package/native/tvos/metal-patched/src/sampler.rs +165 -0
- package/native/tvos/metal-patched/src/sync.rs +178 -0
- package/native/tvos/metal-patched/src/texture.rs +352 -0
- package/native/tvos/metal-patched/src/types.rs +90 -0
- package/native/tvos/metal-patched/src/vertexdescriptor.rs +250 -0
- package/native/tvos/src/audio_backend.rs +197 -0
- package/native/tvos/src/lib.rs +1891 -0
- package/native/visionos/Cargo.lock +1693 -0
- package/native/visionos/Cargo.toml +40 -0
- package/native/visionos/src/audio_backend.rs +197 -0
- package/native/visionos/src/lib.rs +1887 -0
- package/native/watchos/Cargo.lock +16 -0
- package/native/watchos/Cargo.toml +19 -0
- package/native/watchos/shaders/bloom_postfx.metal +99 -0
- package/native/watchos/src/BloomWatchApp.swift +1267 -0
- package/native/watchos/src/BloomWatchAudio.swift +179 -0
- package/native/watchos/src/audio.rs +55 -0
- package/native/watchos/src/draw_list.rs +229 -0
- package/native/watchos/src/ffi_stubs.rs +915 -0
- package/native/watchos/src/ffi_stubs_manual.rs +35 -0
- package/native/watchos/src/lib.rs +1124 -0
- package/native/watchos/src/models.rs +746 -0
- package/native/watchos/src/postfx.rs +95 -0
- package/native/watchos/src/scene.rs +534 -0
- package/native/watchos/src/textures.rs +184 -0
- package/native/web/Cargo.lock +1657 -0
- package/native/web/Cargo.toml +43 -0
- package/native/web/bloom_glue.js +695 -0
- package/native/web/build.sh +131 -0
- package/native/web/index.html +35 -0
- package/native/web/jolt_bridge.js +1519 -0
- package/native/web/src/input_ffi.rs +286 -0
- package/native/web/src/lib.rs +1796 -0
- package/native/web/src/material_ffi.rs +710 -0
- package/native/web/src/parity_ffi.rs +343 -0
- package/native/web/src/physics_ffi.rs +643 -0
- package/native/web/src/ragdoll_ffi.rs +250 -0
- package/native/web/src/render_settings.rs +98 -0
- package/native/windows/Cargo.lock +1815 -0
- package/native/windows/Cargo.toml +68 -0
- package/native/windows/src/lib.rs +1486 -0
- package/package.json +4279 -0
- package/src/audio/index.ts +315 -0
- package/src/core/colors.ts +63 -0
- package/src/core/index.ts +1206 -0
- package/src/core/keys.ts +63 -0
- package/src/core/types.ts +104 -0
- package/src/index.ts +171 -0
- package/src/math/index.ts +516 -0
- package/src/mobile/index.ts +294 -0
- package/src/models/index.ts +1258 -0
- package/src/physics/index.ts +1134 -0
- package/src/scene/index.ts +698 -0
- package/src/shapes/index.ts +120 -0
- package/src/text/index.ts +48 -0
- package/src/textures/index.ts +187 -0
- package/src/vfx/index.ts +191 -0
- package/src/world/index.ts +24 -0
- package/src/world/loader.ts +423 -0
- package/src/world/prefab.ts +217 -0
- package/src/world/render.ts +172 -0
- package/src/world/saver.ts +108 -0
- package/src/world/serialize.ts +301 -0
- package/src/world/terrain.ts +355 -0
- package/src/world/types.ts +160 -0
- package/src/world/validate.ts +319 -0
- package/src/world/version.ts +114 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
//! EN-025 — ragdoll FFI.
|
|
2
|
+
//!
|
|
3
|
+
//! Section of [`define_core_ffi!`](crate::define_core_ffi).
|
|
4
|
+
//!
|
|
5
|
+
//! The shape of this API is deliberate. A ragdoll is not something a game
|
|
6
|
+
//! *configures*; it is something a game *triggers*, once, at the moment of
|
|
7
|
+
//! death, and then forgets about. So: one call to build it from a skeleton the
|
|
8
|
+
//! engine already has, one call to fire it with the killing impulse, one call
|
|
9
|
+
//! per frame to pull the pose back out, one to put it away.
|
|
10
|
+
//!
|
|
11
|
+
//! Everything else — which bones get bodies, how the capsules are sized, how the
|
|
12
|
+
//! joints are limited, how the simulated bodies map back onto skinning matrices
|
|
13
|
+
//! — is the engine's problem, because getting any of it wrong produces a corpse
|
|
14
|
+
//! that looks *nearly* right, which is worse than none.
|
|
15
|
+
|
|
16
|
+
#[doc(hidden)]
|
|
17
|
+
#[macro_export]
|
|
18
|
+
macro_rules! __bloom_ffi_ragdoll {
|
|
19
|
+
() => {
|
|
20
|
+
|
|
21
|
+
// bloom_ragdoll_create — allocate a slot. Returns a 1-based handle.
|
|
22
|
+
#[cfg(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32")))]
|
|
23
|
+
#[no_mangle]
|
|
24
|
+
pub extern "C" fn bloom_ragdoll_create() -> f64 {
|
|
25
|
+
$crate::ffi::guard("bloom_ragdoll_create", move || {
|
|
26
|
+
engine().ragdolls.create() as f64
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
#[cfg(not(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32"))))]
|
|
30
|
+
#[no_mangle]
|
|
31
|
+
pub extern "C" fn bloom_ragdoll_create() -> f64 { 0.0 }
|
|
32
|
+
|
|
33
|
+
// bloom_ragdoll_activate [EN-025]
|
|
34
|
+
//
|
|
35
|
+
// Build the bodies from the model's CURRENT pose and let go. Call it on
|
|
36
|
+
// the frame the thing dies, with the same (scale, position, yaw) you
|
|
37
|
+
// last passed to bloom_anim_update — that transform is what bridges
|
|
38
|
+
// model space and world space, and it is frozen here: the corpse's
|
|
39
|
+
// motion belongs to the bodies now, not to the dead enemy's position.
|
|
40
|
+
//
|
|
41
|
+
// 8 args (the ARM64 ceiling): the impulse direction and magnitude are
|
|
42
|
+
// set separately by bloom_ragdoll_push, so the killing blow's shove is
|
|
43
|
+
// a distinct decision from the corpse's construction.
|
|
44
|
+
#[cfg(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32")))]
|
|
45
|
+
#[no_mangle]
|
|
46
|
+
pub extern "C" fn bloom_ragdoll_activate(
|
|
47
|
+
rag: f64, anim: f64, world: f64,
|
|
48
|
+
scale: f64, px: f64, py: f64, pz: f64, rot_y: f64,
|
|
49
|
+
) -> f64 {
|
|
50
|
+
$crate::ffi::guard("bloom_ragdoll_activate", move || {
|
|
51
|
+
let mut eng = engine();
|
|
52
|
+
let $crate::engine::EngineState {
|
|
53
|
+
models,
|
|
54
|
+
jolt,
|
|
55
|
+
ragdolls,
|
|
56
|
+
..
|
|
57
|
+
} = &mut *eng;
|
|
58
|
+
|
|
59
|
+
let (builds, layer) = {
|
|
60
|
+
let Some(a) = models.get_animation(anim) else { return 0.0 };
|
|
61
|
+
// 12 bodies is the sweet spot for these skeletons: spine +
|
|
62
|
+
// limbs. Past that you start buying fingers, which cost
|
|
63
|
+
// solver time and buy jitter.
|
|
64
|
+
let builds = $crate::ragdoll::plan(
|
|
65
|
+
a, scale as f32,
|
|
66
|
+
[px as f32, py as f32, pz as f32],
|
|
67
|
+
rot_y as f32,
|
|
68
|
+
12, // max bodies
|
|
69
|
+
// Chunkier capsules. Thin ones interpenetrate and let
|
|
70
|
+
// the corpse fold flat through itself; a limb should
|
|
71
|
+
// have some volume to rest ON.
|
|
72
|
+
0.38, // capsule radius as a fraction of bone length
|
|
73
|
+
);
|
|
74
|
+
(builds, 1u32) // MOVING layer
|
|
75
|
+
};
|
|
76
|
+
if builds.is_empty() { return 0.0; }
|
|
77
|
+
|
|
78
|
+
// --- bodies
|
|
79
|
+
let mut bodies: Vec<f64> = Vec::with_capacity(builds.len());
|
|
80
|
+
for b in builds.iter() {
|
|
81
|
+
let shape = jolt.create_capsule_shape(b.half_height, b.radius);
|
|
82
|
+
if shape == 0.0 { bodies.push(0.0); continue; }
|
|
83
|
+
// Quaternion from the capsule's world basis.
|
|
84
|
+
let q = $crate::ragdoll::quat_from_mat(&b.world);
|
|
85
|
+
let body = jolt.create_body(
|
|
86
|
+
world, shape,
|
|
87
|
+
2, // DYNAMIC
|
|
88
|
+
b.world[3][0], b.world[3][1], b.world[3][2],
|
|
89
|
+
q[0], q[1], q[2], q[3],
|
|
90
|
+
0.0, 0.0, 0.0, // linear velocity
|
|
91
|
+
0.0, 0.0, 0.0, // angular velocity
|
|
92
|
+
layer,
|
|
93
|
+
false, // sensor
|
|
94
|
+
true, // allow sleeping — corpses settle
|
|
95
|
+
false, // ccd: not worth it here
|
|
96
|
+
true, // start awake
|
|
97
|
+
0.8, // friction: corpses do not skate
|
|
98
|
+
0.02, // restitution: they do not bounce
|
|
99
|
+
// Angular damping does most of the work of making this
|
|
100
|
+
// read as a body rather than a rag: without it the limbs
|
|
101
|
+
// keep windmilling long after the thing has landed.
|
|
102
|
+
0.20, 0.75, // lin / ang damping
|
|
103
|
+
1.0, // gravity factor
|
|
104
|
+
0.0, 0.0, 0.0, 0.0, // mass override + inertia
|
|
105
|
+
0,
|
|
106
|
+
);
|
|
107
|
+
bodies.push(body);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// --- joints
|
|
111
|
+
//
|
|
112
|
+
// Tight-ish, and deliberately so. Generous limits let the limbs
|
|
113
|
+
// splay and the corpse settles into a puddle rather than a body;
|
|
114
|
+
// the first pass used ±1.2 rad and looked exactly like that.
|
|
115
|
+
// Twist (y) is held hardest, because an over-twisted limb is the
|
|
116
|
+
// single most obviously WRONG thing a ragdoll can do.
|
|
117
|
+
let rot_limits: [f32; 6] = [
|
|
118
|
+
-0.8, 0.8, // x — bend
|
|
119
|
+
-0.25, 0.25, // y — twist
|
|
120
|
+
-0.8, 0.8, // z — bend
|
|
121
|
+
];
|
|
122
|
+
let mut constraints: Vec<f64> = Vec::new();
|
|
123
|
+
for (i, b) in builds.iter().enumerate() {
|
|
124
|
+
if b.parent_bone == usize::MAX { continue; }
|
|
125
|
+
let pa = bodies.get(b.parent_bone).copied().unwrap_or(0.0);
|
|
126
|
+
let pb = bodies.get(i).copied().unwrap_or(0.0);
|
|
127
|
+
if pa == 0.0 || pb == 0.0 { continue; }
|
|
128
|
+
let c = jolt.constraint_six_dof_locked_translation(
|
|
129
|
+
pa, pb,
|
|
130
|
+
b.anchor[0], b.anchor[1], b.anchor[2],
|
|
131
|
+
b.anchor[0], b.anchor[1], b.anchor[2],
|
|
132
|
+
rot_limits,
|
|
133
|
+
true, // anchors given in world space
|
|
134
|
+
);
|
|
135
|
+
if c != 0.0 { constraints.push(c); }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let Some(a) = models.get_animation(anim) else { return 0.0 };
|
|
139
|
+
let Some(r) = ragdolls.get_mut(rag as u32) else { return 0.0 };
|
|
140
|
+
r.attach(&builds, &bodies, constraints, a,
|
|
141
|
+
scale as f32, [px as f32, py as f32, pz as f32], rot_y as f32);
|
|
142
|
+
1.0
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
#[cfg(not(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32"))))]
|
|
146
|
+
#[no_mangle]
|
|
147
|
+
pub extern "C" fn bloom_ragdoll_activate(_r: f64, _a: f64, _w: f64, _s: f64, _x: f64, _y: f64, _z: f64, _ry: f64) -> f64 { 0.0 }
|
|
148
|
+
|
|
149
|
+
// bloom_ragdoll_push — the killing blow. Applied to every body, so the
|
|
150
|
+
// whole corpse is thrown rather than one limb being yanked off.
|
|
151
|
+
#[cfg(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32")))]
|
|
152
|
+
#[no_mangle]
|
|
153
|
+
pub extern "C" fn bloom_ragdoll_push(rag: f64, dx: f64, dy: f64, dz: f64, impulse: f64) {
|
|
154
|
+
$crate::ffi::guard("bloom_ragdoll_push", move || {
|
|
155
|
+
let mut eng = engine();
|
|
156
|
+
let $crate::engine::EngineState { ragdolls, jolt, .. } = &mut *eng;
|
|
157
|
+
let Some(r) = ragdolls.get(rag as u32) else { return };
|
|
158
|
+
if !r.active { return }
|
|
159
|
+
let bodies = r.bodies();
|
|
160
|
+
if bodies.is_empty() { return }
|
|
161
|
+
// Spread the impulse over the bodies so a 12-bone corpse and a
|
|
162
|
+
// 4-bone one take off at the same speed.
|
|
163
|
+
let per = (impulse as f32) / (bodies.len() as f32);
|
|
164
|
+
for b in bodies {
|
|
165
|
+
jolt.body_add_impulse(
|
|
166
|
+
b, dx as f32 * per, dy as f32 * per, dz as f32 * per);
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
#[cfg(not(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32"))))]
|
|
171
|
+
#[no_mangle]
|
|
172
|
+
pub extern "C" fn bloom_ragdoll_push(_r: f64, _x: f64, _y: f64, _z: f64, _i: f64) {}
|
|
173
|
+
|
|
174
|
+
// bloom_ragdoll_update — read the simulated bodies back into the model's
|
|
175
|
+
// joint matrices and upload them. Call once per frame per active
|
|
176
|
+
// ragdoll, then drawModel() as usual. `dt` only ages the ragdoll (the
|
|
177
|
+
// physics world is stepped by the game).
|
|
178
|
+
#[cfg(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32")))]
|
|
179
|
+
#[no_mangle]
|
|
180
|
+
pub extern "C" fn bloom_ragdoll_update(rag: f64, anim: f64, dt: f64) -> f64 {
|
|
181
|
+
$crate::ffi::guard("bloom_ragdoll_update", move || {
|
|
182
|
+
let mut eng = engine();
|
|
183
|
+
let $crate::engine::EngineState {
|
|
184
|
+
ragdolls,
|
|
185
|
+
jolt,
|
|
186
|
+
models,
|
|
187
|
+
renderer,
|
|
188
|
+
..
|
|
189
|
+
} = &mut *eng;
|
|
190
|
+
|
|
191
|
+
let (bodies, scale, pos, rot) = {
|
|
192
|
+
let Some(r) = ragdolls.get(rag as u32) else { return 0.0 };
|
|
193
|
+
if !r.active { return 0.0 }
|
|
194
|
+
let (s, p, ry) = r.upload_params();
|
|
195
|
+
(r.bodies(), s, p, ry)
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
let mut world: Vec<[[f32; 4]; 4]> = Vec::with_capacity(bodies.len());
|
|
199
|
+
for b in bodies.iter() {
|
|
200
|
+
match jolt.body_transform(*b) {
|
|
201
|
+
Some((p, q)) => world.push($crate::ragdoll::from_pos_quat(p, q)),
|
|
202
|
+
None => world.push([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,0.0],[0.0,0.0,0.0,1.0]]),
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
{
|
|
207
|
+
let Some(r) = ragdolls.get_mut(rag as u32) else { return 0.0 };
|
|
208
|
+
r.age += dt as f32;
|
|
209
|
+
}
|
|
210
|
+
let age = ragdolls.get(rag as u32).map(|r| r.age).unwrap_or(0.0);
|
|
211
|
+
|
|
212
|
+
// Split borrow: apply() needs &mut ModelAnimation and &Ragdoll.
|
|
213
|
+
let ragdoll_ptr: *const $crate::ragdoll::Ragdoll =
|
|
214
|
+
match ragdolls.get(rag as u32) { Some(r) => r, None => return 0.0 };
|
|
215
|
+
if let Some(a) = models.get_animation_mut(anim) {
|
|
216
|
+
unsafe { (*ragdoll_ptr).apply(a, &world) };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if let Some(a) = models.get_animation(anim) {
|
|
220
|
+
if !a.joint_matrices.is_empty() {
|
|
221
|
+
let (s, c) = (rot.sin(), rot.cos());
|
|
222
|
+
// PT-7: anim handle = prev-palette pairing key.
|
|
223
|
+
renderer.set_joint_matrices_scaled(
|
|
224
|
+
anim.to_bits(), &a.joint_matrices, scale, pos, s, c);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
age as f64
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
#[cfg(not(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32"))))]
|
|
231
|
+
#[no_mangle]
|
|
232
|
+
pub extern "C" fn bloom_ragdoll_update(_r: f64, _a: f64, _d: f64) -> f64 { 0.0 }
|
|
233
|
+
|
|
234
|
+
// bloom_ragdoll_release — destroy the bodies and constraints, free the
|
|
235
|
+
// slot for reuse. A pooled ragdoll that is never released leaks bodies
|
|
236
|
+
// into the physics world, which is a slow, invisible death.
|
|
237
|
+
#[cfg(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32")))]
|
|
238
|
+
#[no_mangle]
|
|
239
|
+
pub extern "C" fn bloom_ragdoll_release(rag: f64) {
|
|
240
|
+
$crate::ffi::guard("bloom_ragdoll_release", move || {
|
|
241
|
+
let mut eng = engine();
|
|
242
|
+
let $crate::engine::EngineState { ragdolls, jolt, .. } = &mut *eng;
|
|
243
|
+
let (bodies, cons) = {
|
|
244
|
+
let Some(r) = ragdolls.get(rag as u32) else { return };
|
|
245
|
+
(r.bodies(), r.constraint_handles().to_vec())
|
|
246
|
+
};
|
|
247
|
+
// Constraints first: destroying a body out from under a live
|
|
248
|
+
// constraint is how you get a use-after-free in the solver.
|
|
249
|
+
for c in cons { jolt.constraint_destroy(c); }
|
|
250
|
+
for b in bodies { jolt.destroy_body(b); }
|
|
251
|
+
if let Some(r) = ragdolls.get_mut(rag as u32) {
|
|
252
|
+
*r = $crate::ragdoll::Ragdoll::new();
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
#[cfg(not(all(feature = "models3d", feature = "jolt", not(target_arch = "wasm32"))))]
|
|
257
|
+
#[no_mangle]
|
|
258
|
+
pub extern "C" fn bloom_ragdoll_release(_r: f64) {}
|
|
259
|
+
|
|
260
|
+
};
|
|
261
|
+
}
|