@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,95 @@
|
|
|
1
|
+
//! Post-processing effect state. Atomic floats the Swift root view polls
|
|
2
|
+
//! each frame and pushes to either SwiftUI view modifiers (cheap effects)
|
|
3
|
+
//! or the SceneKit SCNTechnique uniform binding (Metal-shader effects).
|
|
4
|
+
//!
|
|
5
|
+
//! What maps cleanly onto built-in SwiftUI modifiers (applies over both
|
|
6
|
+
//! the 2D Canvas and 3D layers):
|
|
7
|
+
//! - vignette → `.overlay(RadialGradient)` (strength + softness)
|
|
8
|
+
//! - manual exposure → `.brightness(ev - 1.0)` approximation
|
|
9
|
+
//! - auto exposure → identity (SceneKit's own tone mapping handles most of it)
|
|
10
|
+
//!
|
|
11
|
+
//! What runs through the Metal shader in shaders/bloom_postfx.metal,
|
|
12
|
+
//! attached via SCNTechnique to the 3D SceneView (only affects the 3D
|
|
13
|
+
//! layer — 2D-only games see just the SwiftUI modifiers above):
|
|
14
|
+
//! - chromatic aberration (per-channel position offset)
|
|
15
|
+
//! - film grain (time-animated noise)
|
|
16
|
+
//! - sun shafts (radial blur + light scattering)
|
|
17
|
+
//!
|
|
18
|
+
//! See `BloomPostFXTechnique` in BloomWatchApp.swift — uniforms reach the
|
|
19
|
+
//! technique via keyed-subscript `technique[symbol] = NSData(...)`, the
|
|
20
|
+
//! one binding path that exists on watchOS (no SCNRenderer in the SDK).
|
|
21
|
+
|
|
22
|
+
use std::sync::atomic::{AtomicU64, AtomicBool, Ordering};
|
|
23
|
+
|
|
24
|
+
static ENABLED: AtomicBool = AtomicBool::new(true);
|
|
25
|
+
static VIGNETTE_STRENGTH: AtomicU64 = AtomicU64::new(0);
|
|
26
|
+
static VIGNETTE_SOFTNESS: AtomicU64 = AtomicU64::new(0);
|
|
27
|
+
static CA_STRENGTH: AtomicU64 = AtomicU64::new(0);
|
|
28
|
+
static FILM_GRAIN: AtomicU64 = AtomicU64::new(0);
|
|
29
|
+
static EXPOSURE: AtomicU64 = AtomicU64::new(1.0f64.to_bits());
|
|
30
|
+
static AUTO_EXPOSURE: AtomicBool = AtomicBool::new(false);
|
|
31
|
+
static SUN_STRENGTH: AtomicU64 = AtomicU64::new(0);
|
|
32
|
+
static SUN_DECAY: AtomicU64 = AtomicU64::new(0.85f64.to_bits());
|
|
33
|
+
static SUN_R: AtomicU64 = AtomicU64::new(1.0f64.to_bits());
|
|
34
|
+
static SUN_G: AtomicU64 = AtomicU64::new(0.9f64.to_bits());
|
|
35
|
+
static SUN_B: AtomicU64 = AtomicU64::new(0.7f64.to_bits());
|
|
36
|
+
|
|
37
|
+
fn store(a: &AtomicU64, v: f64) { a.store(v.to_bits(), Ordering::Relaxed); }
|
|
38
|
+
fn load(a: &AtomicU64) -> f64 { f64::from_bits(a.load(Ordering::Relaxed)) }
|
|
39
|
+
|
|
40
|
+
pub fn set_enabled(on: bool) { ENABLED.store(on, Ordering::Relaxed); }
|
|
41
|
+
pub fn set_vignette(strength: f64, softness: f64) {
|
|
42
|
+
store(&VIGNETTE_STRENGTH, strength);
|
|
43
|
+
store(&VIGNETTE_SOFTNESS, softness);
|
|
44
|
+
}
|
|
45
|
+
pub fn set_chromatic_aberration(s: f64) { store(&CA_STRENGTH, s); }
|
|
46
|
+
pub fn set_film_grain(s: f64) { store(&FILM_GRAIN, s); }
|
|
47
|
+
pub fn set_exposure(v: f64) {
|
|
48
|
+
store(&EXPOSURE, v);
|
|
49
|
+
AUTO_EXPOSURE.store(false, Ordering::Relaxed);
|
|
50
|
+
}
|
|
51
|
+
pub fn set_auto_exposure(on: bool) { AUTO_EXPOSURE.store(on, Ordering::Relaxed); }
|
|
52
|
+
|
|
53
|
+
pub fn set_sun_shafts(strength: f64, decay: f64, r: f64, g: f64, b: f64) {
|
|
54
|
+
store(&SUN_STRENGTH, strength);
|
|
55
|
+
store(&SUN_DECAY, decay);
|
|
56
|
+
store(&SUN_R, r);
|
|
57
|
+
store(&SUN_G, g);
|
|
58
|
+
store(&SUN_B, b);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[repr(C)]
|
|
62
|
+
#[derive(Clone, Copy)]
|
|
63
|
+
pub struct PostFxState {
|
|
64
|
+
pub enabled: u32,
|
|
65
|
+
pub auto_exposure: u32,
|
|
66
|
+
pub vignette_strength: f32,
|
|
67
|
+
pub vignette_softness: f32,
|
|
68
|
+
pub chromatic_aberration: f32,
|
|
69
|
+
pub film_grain: f32,
|
|
70
|
+
pub exposure: f32,
|
|
71
|
+
pub sun_strength: f32,
|
|
72
|
+
pub sun_decay: f32,
|
|
73
|
+
pub sun_r: f32,
|
|
74
|
+
pub sun_g: f32,
|
|
75
|
+
pub sun_b: f32,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pub fn snapshot(out: *mut PostFxState) {
|
|
79
|
+
if out.is_null() { return; }
|
|
80
|
+
let s = PostFxState {
|
|
81
|
+
enabled: if ENABLED.load(Ordering::Relaxed) { 1 } else { 0 },
|
|
82
|
+
auto_exposure: if AUTO_EXPOSURE.load(Ordering::Relaxed) { 1 } else { 0 },
|
|
83
|
+
vignette_strength: load(&VIGNETTE_STRENGTH) as f32,
|
|
84
|
+
vignette_softness: load(&VIGNETTE_SOFTNESS) as f32,
|
|
85
|
+
chromatic_aberration: load(&CA_STRENGTH) as f32,
|
|
86
|
+
film_grain: load(&FILM_GRAIN) as f32,
|
|
87
|
+
exposure: load(&EXPOSURE) as f32,
|
|
88
|
+
sun_strength: load(&SUN_STRENGTH) as f32,
|
|
89
|
+
sun_decay: load(&SUN_DECAY) as f32,
|
|
90
|
+
sun_r: load(&SUN_R) as f32,
|
|
91
|
+
sun_g: load(&SUN_G) as f32,
|
|
92
|
+
sun_b: load(&SUN_B) as f32,
|
|
93
|
+
};
|
|
94
|
+
unsafe { *out = s; }
|
|
95
|
+
}
|
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
//! Retained scene graph for `bloom_scene_*` FFI.
|
|
2
|
+
//!
|
|
3
|
+
//! Mirrors `bloom-shared/scene.rs` but stripped down to what SceneKit can
|
|
4
|
+
//! consume: nodes carry a 4x4 transform, color/PBR material, optional
|
|
5
|
+
//! texture handle, and an optional indexed triangle mesh. Swift polls a
|
|
6
|
+
//! snapshot each frame via `bloom_watchos_scene_*` FFI and mirrors the
|
|
7
|
+
//! graph into SCNNodes.
|
|
8
|
+
//!
|
|
9
|
+
//! `geometry_version` bumps on every `update_geometry` call so the Swift
|
|
10
|
+
//! side can cache `SCNGeometry` objects across frames — rebuilding geometry
|
|
11
|
+
//! each frame for static meshes would burn the watch's GPU.
|
|
12
|
+
|
|
13
|
+
use std::sync::Mutex;
|
|
14
|
+
|
|
15
|
+
// Dirty-flag bits — Node.dirty_flags is the bitwise-OR of these. Each Node
|
|
16
|
+
// mutator sets its corresponding bit; drain_dirty reports them to Swift and
|
|
17
|
+
// clears on consumption. Newly created nodes start with DIRTY_ALL so Swift
|
|
18
|
+
// sees every field on the first drain.
|
|
19
|
+
pub const DIRTY_TRANSFORM: u32 = 1 << 0;
|
|
20
|
+
pub const DIRTY_MATERIAL: u32 = 1 << 1;
|
|
21
|
+
pub const DIRTY_VISIBILITY: u32 = 1 << 2;
|
|
22
|
+
pub const DIRTY_PARENT: u32 = 1 << 3;
|
|
23
|
+
pub const DIRTY_GEOMETRY: u32 = 1 << 4;
|
|
24
|
+
pub const DIRTY_SKIN: u32 = 1 << 5;
|
|
25
|
+
pub const DIRTY_ALL: u32 = DIRTY_TRANSFORM | DIRTY_MATERIAL | DIRTY_VISIBILITY
|
|
26
|
+
| DIRTY_PARENT | DIRTY_GEOMETRY | DIRTY_SKIN;
|
|
27
|
+
|
|
28
|
+
#[repr(C)]
|
|
29
|
+
#[derive(Clone, Copy)]
|
|
30
|
+
pub struct SceneNodeInfo {
|
|
31
|
+
pub dirty_flags: u32,
|
|
32
|
+
pub handle: u32,
|
|
33
|
+
pub parent: u32,
|
|
34
|
+
pub visible: u32,
|
|
35
|
+
pub geometry_version: u32,
|
|
36
|
+
|
|
37
|
+
pub color: [f32; 4],
|
|
38
|
+
pub roughness: f32,
|
|
39
|
+
pub metalness: f32,
|
|
40
|
+
/// Legacy single-slot texture handle (diffuse / base color). Kept for
|
|
41
|
+
/// bloom_scene_set_material_texture which predates the PBR slot set.
|
|
42
|
+
pub texture: u32,
|
|
43
|
+
pub has_geometry: u32,
|
|
44
|
+
|
|
45
|
+
pub transform: [f32; 16],
|
|
46
|
+
|
|
47
|
+
/// PBR texture slots — set via bloom_scene_attach_model from a loaded
|
|
48
|
+
/// glTF material. 0 = not set (fall back to color / roughness /
|
|
49
|
+
/// metalness factors instead).
|
|
50
|
+
pub tex_base_color: u32,
|
|
51
|
+
pub tex_normal: u32,
|
|
52
|
+
pub tex_metallic_roughness: u32,
|
|
53
|
+
pub tex_emissive: u32,
|
|
54
|
+
pub tex_occlusion: u32,
|
|
55
|
+
/// Bumps whenever any skin_* data changes on this node. Swift rebuilds
|
|
56
|
+
/// the SCNSkinner when it sees a new version. 0 = no skin.
|
|
57
|
+
pub skin_version: u32,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
struct Node {
|
|
61
|
+
visible: bool,
|
|
62
|
+
parent: u32,
|
|
63
|
+
transform: [f32; 16],
|
|
64
|
+
color: [f32; 4],
|
|
65
|
+
roughness: f32,
|
|
66
|
+
metalness: f32,
|
|
67
|
+
texture: u32,
|
|
68
|
+
tex_base_color: u32,
|
|
69
|
+
tex_normal: u32,
|
|
70
|
+
tex_metallic_roughness: u32,
|
|
71
|
+
tex_emissive: u32,
|
|
72
|
+
tex_occlusion: u32,
|
|
73
|
+
positions: Vec<f32>,
|
|
74
|
+
normals: Vec<f32>,
|
|
75
|
+
uvs: Vec<f32>,
|
|
76
|
+
indices: Vec<u32>,
|
|
77
|
+
geometry_version: u32,
|
|
78
|
+
/// Bitmask of DIRTY_* flags that need to go out to Swift on the next
|
|
79
|
+
/// drain. Freshly created nodes start with DIRTY_ALL so Swift builds a
|
|
80
|
+
/// full SCNNode on first sight.
|
|
81
|
+
dirty_flags: u32,
|
|
82
|
+
|
|
83
|
+
// Skinning data (SCNSkinner). Present only on the mesh-carrying node of
|
|
84
|
+
// a skinned glTF primitive. skin_version bumps when any of the fields
|
|
85
|
+
// below change, signalling Swift to rebuild the skinner.
|
|
86
|
+
skin_joint_handles: Vec<u32>, // bloom scene handles of the bones
|
|
87
|
+
skin_inverse_bind: Vec<[f32; 16]>, // one per joint
|
|
88
|
+
skin_vertex_joints: Vec<u32>, // 4 per vertex (as in glTF JOINTS_0)
|
|
89
|
+
skin_vertex_weights: Vec<f32>, // 4 per vertex (as in glTF WEIGHTS_0)
|
|
90
|
+
skin_version: u32,
|
|
91
|
+
|
|
92
|
+
// Animation tracks attached to this skinned mesh. Each track targets a
|
|
93
|
+
// bone by bloom handle. Swift builds CAKeyframeAnimations from them when
|
|
94
|
+
// attaching the SCNSkinner. anim_version bumps alongside skin_version.
|
|
95
|
+
anim_tracks: Vec<AnimTrack>,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
pub struct AnimTrack {
|
|
99
|
+
pub bone_handle: u32,
|
|
100
|
+
pub path: u32, // 0 = translation, 1 = rotation, 2 = scale
|
|
101
|
+
pub times: Vec<f32>,
|
|
102
|
+
pub values: Vec<f32>,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
impl Node {
|
|
106
|
+
fn empty() -> Self {
|
|
107
|
+
let mut t = [0.0f32; 16];
|
|
108
|
+
t[0] = 1.0; t[5] = 1.0; t[10] = 1.0; t[15] = 1.0; // identity
|
|
109
|
+
Self {
|
|
110
|
+
visible: true,
|
|
111
|
+
parent: 0,
|
|
112
|
+
transform: t,
|
|
113
|
+
color: [1.0, 1.0, 1.0, 1.0],
|
|
114
|
+
roughness: 0.6,
|
|
115
|
+
metalness: 0.0,
|
|
116
|
+
texture: 0,
|
|
117
|
+
tex_base_color: 0, tex_normal: 0, tex_metallic_roughness: 0,
|
|
118
|
+
tex_emissive: 0, tex_occlusion: 0,
|
|
119
|
+
positions: Vec::new(),
|
|
120
|
+
normals: Vec::new(),
|
|
121
|
+
uvs: Vec::new(),
|
|
122
|
+
indices: Vec::new(),
|
|
123
|
+
geometry_version: 0,
|
|
124
|
+
dirty_flags: DIRTY_ALL,
|
|
125
|
+
skin_joint_handles: Vec::new(),
|
|
126
|
+
skin_inverse_bind: Vec::new(),
|
|
127
|
+
skin_vertex_joints: Vec::new(),
|
|
128
|
+
skin_vertex_weights: Vec::new(),
|
|
129
|
+
skin_version: 0,
|
|
130
|
+
anim_tracks: Vec::new(),
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#[repr(C)]
|
|
136
|
+
#[derive(Clone, Copy)]
|
|
137
|
+
pub struct Light {
|
|
138
|
+
pub kind: u32, // 1 = directional, 2 = point
|
|
139
|
+
pub _pad: u32,
|
|
140
|
+
pub pos_or_dir: [f32; 3],
|
|
141
|
+
pub range: f32,
|
|
142
|
+
pub color: [f32; 3],
|
|
143
|
+
pub intensity: f32,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
struct Inner {
|
|
147
|
+
nodes: Vec<Option<Node>>, // 1-based: nodes[0] is always None (handle 0 = "none")
|
|
148
|
+
lights: Vec<Light>,
|
|
149
|
+
/// Handles of nodes destroyed since the last Swift drain. Swift consumes
|
|
150
|
+
/// via drain_destroyed() and removes the matching SCNNodes from its cache.
|
|
151
|
+
destroyed_queue: Vec<u32>,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static INNER: Mutex<Inner> = Mutex::new(Inner {
|
|
155
|
+
nodes: Vec::new(),
|
|
156
|
+
lights: Vec::new(),
|
|
157
|
+
destroyed_queue: Vec::new(),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
fn with<F, R>(f: F) -> R where F: FnOnce(&mut Inner) -> R {
|
|
161
|
+
let mut g = INNER.lock().unwrap();
|
|
162
|
+
if g.nodes.is_empty() {
|
|
163
|
+
g.nodes.push(None); // sentinel at index 0
|
|
164
|
+
}
|
|
165
|
+
f(&mut *g)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ============================================================
|
|
169
|
+
// Mutations — called from bloom_scene_* FFI in lib.rs
|
|
170
|
+
// ============================================================
|
|
171
|
+
|
|
172
|
+
pub fn create() -> u32 {
|
|
173
|
+
with(|inner| {
|
|
174
|
+
// Reuse a freed slot if one exists.
|
|
175
|
+
for (i, slot) in inner.nodes.iter_mut().enumerate().skip(1) {
|
|
176
|
+
if slot.is_none() {
|
|
177
|
+
*slot = Some(Node::empty());
|
|
178
|
+
return i as u32;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
inner.nodes.push(Some(Node::empty()));
|
|
182
|
+
(inner.nodes.len() - 1) as u32
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
pub fn destroy(handle: u32) {
|
|
187
|
+
with(|inner| {
|
|
188
|
+
let existed = if let Some(slot) = inner.nodes.get_mut(handle as usize) {
|
|
189
|
+
if slot.is_some() { *slot = None; true } else { false }
|
|
190
|
+
} else { false };
|
|
191
|
+
if existed { inner.destroyed_queue.push(handle); }
|
|
192
|
+
// Any node with this as parent becomes a root — flag PARENT dirty
|
|
193
|
+
// so Swift reparents it.
|
|
194
|
+
for n in inner.nodes.iter_mut().flatten() {
|
|
195
|
+
if n.parent == handle {
|
|
196
|
+
n.parent = 0;
|
|
197
|
+
n.dirty_flags |= DIRTY_PARENT;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
fn mutate<F: FnOnce(&mut Node)>(handle: u32, f: F) {
|
|
204
|
+
with(|inner| {
|
|
205
|
+
if let Some(Some(n)) = inner.nodes.get_mut(handle as usize) {
|
|
206
|
+
f(n);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fn mark_dirty<F: FnOnce(&mut Node)>(handle: u32, bits: u32, f: F) {
|
|
212
|
+
mutate(handle, |n| {
|
|
213
|
+
f(n);
|
|
214
|
+
n.dirty_flags |= bits;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
pub fn set_visible(handle: u32, v: bool) {
|
|
219
|
+
mark_dirty(handle, DIRTY_VISIBILITY, |n| n.visible = v);
|
|
220
|
+
}
|
|
221
|
+
pub fn set_parent(handle: u32, parent: u32) {
|
|
222
|
+
mark_dirty(handle, DIRTY_PARENT, |n| n.parent = parent);
|
|
223
|
+
}
|
|
224
|
+
pub fn set_transform(handle: u32, m: [f32; 16]) {
|
|
225
|
+
mark_dirty(handle, DIRTY_TRANSFORM, |n| n.transform = m);
|
|
226
|
+
}
|
|
227
|
+
pub fn set_color(handle: u32, rgba: [f32; 4]) {
|
|
228
|
+
mark_dirty(handle, DIRTY_MATERIAL, |n| n.color = rgba);
|
|
229
|
+
}
|
|
230
|
+
pub fn set_pbr(handle: u32, rough: f32, metal: f32) {
|
|
231
|
+
mark_dirty(handle, DIRTY_MATERIAL, |n| { n.roughness = rough; n.metalness = metal; });
|
|
232
|
+
}
|
|
233
|
+
pub fn set_texture(handle: u32, tex: u32) {
|
|
234
|
+
mark_dirty(handle, DIRTY_MATERIAL, |n| n.texture = tex);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
pub fn set_pbr_textures(handle: u32,
|
|
238
|
+
base_color: u32, normal: u32, metallic_roughness: u32,
|
|
239
|
+
emissive: u32, occlusion: u32,
|
|
240
|
+
) {
|
|
241
|
+
mark_dirty(handle, DIRTY_MATERIAL, |n| {
|
|
242
|
+
n.tex_base_color = base_color;
|
|
243
|
+
n.tex_normal = normal;
|
|
244
|
+
n.tex_metallic_roughness = metallic_roughness;
|
|
245
|
+
n.tex_emissive = emissive;
|
|
246
|
+
n.tex_occlusion = occlusion;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
pub fn set_skin(handle: u32,
|
|
251
|
+
joint_handles: Vec<u32>, inverse_bind: Vec<[f32; 16]>,
|
|
252
|
+
vertex_joints: Vec<u32>, vertex_weights: Vec<f32>,
|
|
253
|
+
) {
|
|
254
|
+
mark_dirty(handle, DIRTY_SKIN, |n| {
|
|
255
|
+
n.skin_joint_handles = joint_handles;
|
|
256
|
+
n.skin_inverse_bind = inverse_bind;
|
|
257
|
+
n.skin_vertex_joints = vertex_joints;
|
|
258
|
+
n.skin_vertex_weights = vertex_weights;
|
|
259
|
+
n.skin_version = n.skin_version.wrapping_add(1);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/// Replace the animation tracks on a skinned mesh node. Bumps skin_version
|
|
264
|
+
/// so Swift re-picks them up alongside the skinner rebuild.
|
|
265
|
+
pub fn set_anim_tracks(handle: u32, tracks: Vec<AnimTrack>) {
|
|
266
|
+
mark_dirty(handle, DIRTY_SKIN, |n| {
|
|
267
|
+
n.anim_tracks = tracks;
|
|
268
|
+
n.skin_version = n.skin_version.wrapping_add(1);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/// TS → native FFI layout: 12 f64s per vertex — xyz, nx ny nz, rgba, uv.
|
|
273
|
+
/// Color is ignored (material color wins via bloom_scene_set_material_color).
|
|
274
|
+
/// Directly install pre-decoded geometry (from a loaded model) into a scene
|
|
275
|
+
/// node, bypassing the 12-f64-per-vertex TS FFI layout.
|
|
276
|
+
pub fn set_geometry(handle: u32,
|
|
277
|
+
positions: Vec<f32>, normals: Vec<f32>, uvs: Vec<f32>, indices: Vec<u32>,
|
|
278
|
+
) {
|
|
279
|
+
mark_dirty(handle, DIRTY_GEOMETRY, |n| {
|
|
280
|
+
n.positions = positions;
|
|
281
|
+
n.normals = normals;
|
|
282
|
+
n.uvs = uvs;
|
|
283
|
+
n.indices = indices;
|
|
284
|
+
n.geometry_version = n.geometry_version.wrapping_add(1);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
pub fn update_geometry_f64(handle: u32, verts: &[f64], indices: &[f64]) {
|
|
289
|
+
mark_dirty(handle, DIRTY_GEOMETRY, |n| {
|
|
290
|
+
let count = verts.len() / 12;
|
|
291
|
+
n.positions.clear();
|
|
292
|
+
n.normals.clear();
|
|
293
|
+
n.uvs.clear();
|
|
294
|
+
n.positions.reserve(count * 3);
|
|
295
|
+
n.normals.reserve(count * 3);
|
|
296
|
+
n.uvs.reserve(count * 2);
|
|
297
|
+
for i in 0..count {
|
|
298
|
+
let base = i * 12;
|
|
299
|
+
n.positions.push(verts[base] as f32);
|
|
300
|
+
n.positions.push(verts[base+1] as f32);
|
|
301
|
+
n.positions.push(verts[base+2] as f32);
|
|
302
|
+
n.normals.push(verts[base+3] as f32);
|
|
303
|
+
n.normals.push(verts[base+4] as f32);
|
|
304
|
+
n.normals.push(verts[base+5] as f32);
|
|
305
|
+
n.uvs.push(verts[base+10] as f32);
|
|
306
|
+
n.uvs.push(verts[base+11] as f32);
|
|
307
|
+
}
|
|
308
|
+
n.indices.clear();
|
|
309
|
+
n.indices.reserve(indices.len());
|
|
310
|
+
for &i in indices { n.indices.push(i as u32); }
|
|
311
|
+
n.geometry_version = n.geometry_version.wrapping_add(1);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
pub fn add_directional_light(dx: f32, dy: f32, dz: f32, r: f32, g: f32, b: f32, intensity: f32) {
|
|
316
|
+
with(|inner| {
|
|
317
|
+
inner.lights.push(Light {
|
|
318
|
+
kind: 1, _pad: 0,
|
|
319
|
+
pos_or_dir: [dx, dy, dz], range: 0.0,
|
|
320
|
+
color: [r, g, b], intensity,
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
pub fn add_point_light(x: f32, y: f32, z: f32, range: f32, r: f32, g: f32, b: f32, intensity: f32) {
|
|
326
|
+
with(|inner| {
|
|
327
|
+
inner.lights.push(Light {
|
|
328
|
+
kind: 2, _pad: 0,
|
|
329
|
+
pos_or_dir: [x, y, z], range,
|
|
330
|
+
color: [r, g, b], intensity,
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
pub fn clear_lights() {
|
|
336
|
+
with(|inner| inner.lights.clear());
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
pub fn node_count() -> usize {
|
|
340
|
+
with(|inner| inner.nodes.iter().filter(|n| n.is_some()).count())
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ============================================================
|
|
344
|
+
// Snapshot API — called from Swift each frame.
|
|
345
|
+
// ============================================================
|
|
346
|
+
|
|
347
|
+
/// Delta-sync: emit only nodes whose dirty_flags are non-zero, and clear
|
|
348
|
+
/// flags on the nodes we report. Swift calls this once per frame and
|
|
349
|
+
/// applies the reported changes — static scenes get O(0) cost, moving
|
|
350
|
+
/// scenes scale with the number of actually-changing nodes.
|
|
351
|
+
pub fn drain_dirty(dst: *mut SceneNodeInfo, max: i64) -> i64 {
|
|
352
|
+
if dst.is_null() || max <= 0 { return 0; }
|
|
353
|
+
with(|inner| {
|
|
354
|
+
let mut written = 0i64;
|
|
355
|
+
for (i, slot) in inner.nodes.iter_mut().enumerate() {
|
|
356
|
+
if written >= max { break; }
|
|
357
|
+
let Some(n) = slot else { continue };
|
|
358
|
+
if n.dirty_flags == 0 { continue; }
|
|
359
|
+
let info = SceneNodeInfo {
|
|
360
|
+
dirty_flags: n.dirty_flags,
|
|
361
|
+
handle: i as u32,
|
|
362
|
+
parent: n.parent,
|
|
363
|
+
visible: if n.visible { 1 } else { 0 },
|
|
364
|
+
geometry_version: n.geometry_version,
|
|
365
|
+
color: n.color,
|
|
366
|
+
roughness: n.roughness,
|
|
367
|
+
metalness: n.metalness,
|
|
368
|
+
texture: n.texture,
|
|
369
|
+
has_geometry: if n.indices.is_empty() { 0 } else { 1 },
|
|
370
|
+
transform: n.transform,
|
|
371
|
+
tex_base_color: n.tex_base_color,
|
|
372
|
+
tex_normal: n.tex_normal,
|
|
373
|
+
tex_metallic_roughness: n.tex_metallic_roughness,
|
|
374
|
+
tex_emissive: n.tex_emissive,
|
|
375
|
+
tex_occlusion: n.tex_occlusion,
|
|
376
|
+
skin_version: n.skin_version,
|
|
377
|
+
};
|
|
378
|
+
unsafe { *dst.add(written as usize) = info; }
|
|
379
|
+
n.dirty_flags = 0;
|
|
380
|
+
written += 1;
|
|
381
|
+
}
|
|
382
|
+
written
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/// Drain the list of handles destroyed since the last call. Swift pulls
|
|
387
|
+
/// these and removes the matching SCNNodes from its retainedNodes map.
|
|
388
|
+
pub fn drain_destroyed(dst: *mut u32, max: i64) -> i64 {
|
|
389
|
+
if dst.is_null() || max <= 0 { return 0; }
|
|
390
|
+
with(|inner| {
|
|
391
|
+
let n = inner.destroyed_queue.len().min(max as usize);
|
|
392
|
+
unsafe {
|
|
393
|
+
std::ptr::copy_nonoverlapping(inner.destroyed_queue.as_ptr(), dst, n);
|
|
394
|
+
}
|
|
395
|
+
inner.destroyed_queue.drain(..n);
|
|
396
|
+
n as i64
|
|
397
|
+
})
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
pub fn copy_lights(dst: *mut Light, max: i64) -> i64 {
|
|
401
|
+
if dst.is_null() || max <= 0 { return 0; }
|
|
402
|
+
with(|inner| {
|
|
403
|
+
let n = inner.lights.len().min(max as usize);
|
|
404
|
+
unsafe { std::ptr::copy_nonoverlapping(inner.lights.as_ptr(), dst, n); }
|
|
405
|
+
n as i64
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/// Pointer + counts for a node's geometry arrays. Pointers are valid as long
|
|
410
|
+
/// as the node exists and `update_geometry` isn't called on it — Swift reads
|
|
411
|
+
/// synchronously in one pass so this is safe for the sync protocol.
|
|
412
|
+
#[repr(C)]
|
|
413
|
+
#[derive(Clone, Copy)]
|
|
414
|
+
pub struct GeometryPtrs {
|
|
415
|
+
pub positions: *const f32,
|
|
416
|
+
pub position_count: u32,
|
|
417
|
+
pub normals: *const f32,
|
|
418
|
+
pub normal_count: u32,
|
|
419
|
+
pub uvs: *const f32,
|
|
420
|
+
pub uv_count: u32,
|
|
421
|
+
pub indices: *const u32,
|
|
422
|
+
pub index_count: u32,
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
#[repr(C)]
|
|
426
|
+
#[derive(Clone, Copy)]
|
|
427
|
+
pub struct SkinPtrs {
|
|
428
|
+
pub joint_handles: *const u32,
|
|
429
|
+
pub joint_count: u32,
|
|
430
|
+
pub inverse_bind: *const f32, // flat 16-float matrices
|
|
431
|
+
pub inverse_bind_matrix_count: u32,
|
|
432
|
+
pub vertex_joints: *const u32, // 4 per vertex
|
|
433
|
+
pub vertex_joint_count: u32, // total entries (= vertex_count * 4)
|
|
434
|
+
pub vertex_weights: *const f32, // 4 per vertex
|
|
435
|
+
pub vertex_weight_count: u32,
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
#[repr(C)]
|
|
439
|
+
#[derive(Clone, Copy)]
|
|
440
|
+
pub struct AnimTrackInfo {
|
|
441
|
+
pub bone_handle: u32,
|
|
442
|
+
pub path: u32, // 0 = translation, 1 = rotation, 2 = scale
|
|
443
|
+
pub key_count: u32,
|
|
444
|
+
pub _pad: u32,
|
|
445
|
+
pub times: *const f32, // length = key_count
|
|
446
|
+
pub values: *const f32, // length = key_count * (3 or 4)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
pub fn anim_track_count(handle: u32) -> i64 {
|
|
450
|
+
with(|inner| {
|
|
451
|
+
if let Some(Some(n)) = inner.nodes.get(handle as usize) {
|
|
452
|
+
n.anim_tracks.len() as i64
|
|
453
|
+
} else { 0 }
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
pub fn anim_track_info(handle: u32, idx: i64, out: *mut AnimTrackInfo) {
|
|
458
|
+
if out.is_null() { return; }
|
|
459
|
+
with(|inner| {
|
|
460
|
+
if let Some(Some(n)) = inner.nodes.get(handle as usize) {
|
|
461
|
+
if let Some(t) = n.anim_tracks.get(idx as usize) {
|
|
462
|
+
unsafe {
|
|
463
|
+
*out = AnimTrackInfo {
|
|
464
|
+
bone_handle: t.bone_handle,
|
|
465
|
+
path: t.path,
|
|
466
|
+
key_count: t.times.len() as u32,
|
|
467
|
+
_pad: 0,
|
|
468
|
+
times: t.times.as_ptr(),
|
|
469
|
+
values: t.values.as_ptr(),
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
pub fn skin_ptrs(handle: u32) -> SkinPtrs {
|
|
478
|
+
with(|inner| {
|
|
479
|
+
let empty = SkinPtrs {
|
|
480
|
+
joint_handles: std::ptr::null(), joint_count: 0,
|
|
481
|
+
inverse_bind: std::ptr::null(), inverse_bind_matrix_count: 0,
|
|
482
|
+
vertex_joints: std::ptr::null(), vertex_joint_count: 0,
|
|
483
|
+
vertex_weights: std::ptr::null(), vertex_weight_count: 0,
|
|
484
|
+
};
|
|
485
|
+
if let Some(Some(n)) = inner.nodes.get(handle as usize) {
|
|
486
|
+
SkinPtrs {
|
|
487
|
+
joint_handles: n.skin_joint_handles.as_ptr(),
|
|
488
|
+
joint_count: n.skin_joint_handles.len() as u32,
|
|
489
|
+
inverse_bind: n.skin_inverse_bind.as_ptr() as *const f32,
|
|
490
|
+
inverse_bind_matrix_count: n.skin_inverse_bind.len() as u32,
|
|
491
|
+
vertex_joints: n.skin_vertex_joints.as_ptr(),
|
|
492
|
+
vertex_joint_count: n.skin_vertex_joints.len() as u32,
|
|
493
|
+
vertex_weights: n.skin_vertex_weights.as_ptr(),
|
|
494
|
+
vertex_weight_count: n.skin_vertex_weights.len() as u32,
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
empty
|
|
498
|
+
}
|
|
499
|
+
})
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
pub fn geometry_ptrs(handle: u32) -> GeometryPtrs {
|
|
503
|
+
with(|inner| {
|
|
504
|
+
if let Some(Some(n)) = inner.nodes.get(handle as usize) {
|
|
505
|
+
GeometryPtrs {
|
|
506
|
+
positions: n.positions.as_ptr(),
|
|
507
|
+
position_count: n.positions.len() as u32,
|
|
508
|
+
normals: n.normals.as_ptr(),
|
|
509
|
+
normal_count: n.normals.len() as u32,
|
|
510
|
+
uvs: n.uvs.as_ptr(),
|
|
511
|
+
uv_count: n.uvs.len() as u32,
|
|
512
|
+
indices: n.indices.as_ptr(),
|
|
513
|
+
index_count: n.indices.len() as u32,
|
|
514
|
+
}
|
|
515
|
+
} else {
|
|
516
|
+
GeometryPtrs {
|
|
517
|
+
positions: std::ptr::null(), position_count: 0,
|
|
518
|
+
normals: std::ptr::null(), normal_count: 0,
|
|
519
|
+
uvs: std::ptr::null(), uv_count: 0,
|
|
520
|
+
indices: std::ptr::null(), index_count: 0,
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
})
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
pub fn get_transform(handle: u32) -> [f32; 16] {
|
|
527
|
+
with(|inner| {
|
|
528
|
+
if let Some(Some(n)) = inner.nodes.get(handle as usize) {
|
|
529
|
+
n.transform
|
|
530
|
+
} else {
|
|
531
|
+
let mut t = [0.0f32; 16]; t[0] = 1.0; t[5] = 1.0; t[10] = 1.0; t[15] = 1.0; t
|
|
532
|
+
}
|
|
533
|
+
})
|
|
534
|
+
}
|