@bloomengine/engine 0.4.9 → 0.4.11
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/native/android/src/lib.rs +4 -0
- package/native/ios/Cargo.toml +1 -1
- package/native/ios/src/lib.rs +8 -0
- package/native/linux/src/lib.rs +8 -0
- package/native/macos/Cargo.toml +1 -1
- package/native/macos/src/lib.rs +19 -0
- package/native/tvos/Cargo.toml +1 -1
- package/native/tvos/src/lib.rs +143 -1
- package/native/watchos/src/lib.rs +4 -0
- package/native/web/src/lib.rs +3 -0
- package/native/windows/src/lib.rs +4 -0
- package/package.json +2 -1
- package/src/core/index.ts +6 -0
|
@@ -1393,6 +1393,10 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
|
1393
1393
|
}
|
|
1394
1394
|
#[no_mangle]
|
|
1395
1395
|
pub extern "C" fn bloom_get_platform() -> f64 { 5.0 }
|
|
1396
|
+
|
|
1397
|
+
/// Preferred OS language packed as `c0*256+c1`. TODO: real per-OS detection; returns "en" for now.
|
|
1398
|
+
#[no_mangle]
|
|
1399
|
+
pub extern "C" fn bloom_get_language() -> f64 { 25966.0 }
|
|
1396
1400
|
#[no_mangle]
|
|
1397
1401
|
pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
|
|
1398
1402
|
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
package/native/ios/Cargo.toml
CHANGED
|
@@ -23,6 +23,6 @@ panic = "abort"
|
|
|
23
23
|
image = { version = "0.25", default-features = false, features = ["hdr"] }
|
|
24
24
|
bloom-shared = { path = "../shared", default-features = false, features = ["mp3"] }
|
|
25
25
|
objc2 = "0.6"
|
|
26
|
-
objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject"] }
|
|
26
|
+
objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject", "NSLocale", "NSArray"] }
|
|
27
27
|
raw-window-handle = "0.6"
|
|
28
28
|
wgpu = "29"
|
package/native/ios/src/lib.rs
CHANGED
|
@@ -2078,6 +2078,14 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
|
2078
2078
|
}
|
|
2079
2079
|
#[no_mangle]
|
|
2080
2080
|
pub extern "C" fn bloom_get_platform() -> f64 { 2.0 }
|
|
2081
|
+
|
|
2082
|
+
/// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag). See macos lib for format.
|
|
2083
|
+
#[no_mangle]
|
|
2084
|
+
pub extern "C" fn bloom_get_language() -> f64 {
|
|
2085
|
+
fn pack(code: &str) -> f64 { let l = code.to_ascii_lowercase(); let b = l.as_bytes(); if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 } }
|
|
2086
|
+
let langs = objc2_foundation::NSLocale::preferredLanguages();
|
|
2087
|
+
match langs.firstObject() { Some(s) => pack(&s.to_string()), None => 25966.0 }
|
|
2088
|
+
}
|
|
2081
2089
|
#[no_mangle]
|
|
2082
2090
|
pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
|
|
2083
2091
|
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
package/native/linux/src/lib.rs
CHANGED
|
@@ -1846,6 +1846,14 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
|
1846
1846
|
}
|
|
1847
1847
|
#[no_mangle]
|
|
1848
1848
|
pub extern "C" fn bloom_get_platform() -> f64 { 4.0 }
|
|
1849
|
+
|
|
1850
|
+
/// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag), from $LANG/$LC_*.
|
|
1851
|
+
#[no_mangle]
|
|
1852
|
+
pub extern "C" fn bloom_get_language() -> f64 {
|
|
1853
|
+
fn pack(code: &str) -> f64 { let l = code.to_ascii_lowercase(); let b = l.as_bytes(); if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 } }
|
|
1854
|
+
let v = std::env::var("LANG").or_else(|_| std::env::var("LC_ALL")).or_else(|_| std::env::var("LC_MESSAGES")).unwrap_or_default();
|
|
1855
|
+
if v.len() >= 2 && !v.starts_with('C') && !v.starts_with("POSIX") { pack(&v) } else { 25966.0 }
|
|
1856
|
+
}
|
|
1849
1857
|
#[no_mangle]
|
|
1850
1858
|
pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
|
|
1851
1859
|
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
package/native/macos/Cargo.toml
CHANGED
|
@@ -27,7 +27,7 @@ panic = "abort"
|
|
|
27
27
|
bloom-shared = { path = "../shared", default-features = false, features = ["mp3"] }
|
|
28
28
|
image = { version = "0.25", default-features = false, features = ["hdr"] }
|
|
29
29
|
objc2 = "0.6"
|
|
30
|
-
objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread"] }
|
|
30
|
+
objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSLocale", "NSArray"] }
|
|
31
31
|
objc2-app-kit = { version = "0.3", features = ["NSWindow", "NSView", "NSEvent", "NSApplication", "NSScreen", "NSGraphicsContext", "NSRunningApplication", "NSResponder"] }
|
|
32
32
|
objc2-quartz-core = { version = "0.3", features = ["CAMetalLayer"] }
|
|
33
33
|
raw-window-handle = "0.6"
|
package/native/macos/src/lib.rs
CHANGED
|
@@ -2415,6 +2415,25 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
|
2415
2415
|
}
|
|
2416
2416
|
#[no_mangle]
|
|
2417
2417
|
pub extern "C" fn bloom_get_platform() -> f64 { 1.0 }
|
|
2418
|
+
|
|
2419
|
+
/// Return the user's preferred OS language as a packed 2-letter code:
|
|
2420
|
+
/// `c0 * 256 + c1`, where c0/c1 are the ASCII bytes of the lowercased
|
|
2421
|
+
/// ISO-639 primary subtag (e.g. "en-US" -> "en" -> 101*256+110). The script
|
|
2422
|
+
/// subtag is dropped (zh-Hans/zh-Hant both pack as "zh"); callers map that to
|
|
2423
|
+
/// their supported variant. Falls back to "en" when no preference is set.
|
|
2424
|
+
#[no_mangle]
|
|
2425
|
+
pub extern "C" fn bloom_get_language() -> f64 {
|
|
2426
|
+
fn pack(code: &str) -> f64 {
|
|
2427
|
+
let lower = code.to_ascii_lowercase();
|
|
2428
|
+
let b = lower.as_bytes();
|
|
2429
|
+
if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 101.0 * 256.0 + 110.0 }
|
|
2430
|
+
}
|
|
2431
|
+
let langs = objc2_foundation::NSLocale::preferredLanguages();
|
|
2432
|
+
match langs.firstObject() {
|
|
2433
|
+
Some(s) => pack(&s.to_string()),
|
|
2434
|
+
None => pack("en"),
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2418
2437
|
#[no_mangle]
|
|
2419
2438
|
pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
|
|
2420
2439
|
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
package/native/tvos/Cargo.toml
CHANGED
|
@@ -22,7 +22,7 @@ panic = "abort"
|
|
|
22
22
|
[dependencies]
|
|
23
23
|
bloom-shared = { path = "../shared", default-features = false, features = ["mp3"] }
|
|
24
24
|
objc2 = "0.6"
|
|
25
|
-
objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject"] }
|
|
25
|
+
objc2-foundation = { version = "0.3", features = ["NSDate", "NSRunLoop", "NSString", "NSThread", "NSObject", "NSLocale", "NSArray"] }
|
|
26
26
|
raw-window-handle = "0.6"
|
|
27
27
|
wgpu = "29"
|
|
28
28
|
# Needed by bloom_set_env_clear_from_hdr (HDR env-map decode); mirrors macOS.
|
package/native/tvos/src/lib.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use bloom_shared::engine::EngineState;
|
|
2
2
|
use bloom_shared::renderer::Renderer;
|
|
3
|
-
use bloom_shared::string_header::str_from_header;
|
|
3
|
+
use bloom_shared::string_header::{str_from_header, alloc_perry_string};
|
|
4
4
|
use bloom_shared::audio::{parse_wav, parse_ogg, parse_mp3, SoundData};
|
|
5
5
|
|
|
6
6
|
use objc2::encode::{Encode, Encoding, RefEncode};
|
|
@@ -3046,6 +3046,14 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
|
3046
3046
|
}
|
|
3047
3047
|
#[no_mangle]
|
|
3048
3048
|
pub extern "C" fn bloom_get_platform() -> f64 { 6.0 }
|
|
3049
|
+
|
|
3050
|
+
/// Preferred OS language packed as `c0*256+c1` (ISO-639 primary subtag). See macos lib for format.
|
|
3051
|
+
#[no_mangle]
|
|
3052
|
+
pub extern "C" fn bloom_get_language() -> f64 {
|
|
3053
|
+
fn pack(code: &str) -> f64 { let l = code.to_ascii_lowercase(); let b = l.as_bytes(); if b.len() >= 2 { (b[0] as f64) * 256.0 + (b[1] as f64) } else { 25966.0 } }
|
|
3054
|
+
let langs = objc2_foundation::NSLocale::preferredLanguages();
|
|
3055
|
+
match langs.firstObject() { Some(s) => pack(&s.to_string()), None => 25966.0 }
|
|
3056
|
+
}
|
|
3049
3057
|
#[no_mangle]
|
|
3050
3058
|
pub extern "C" fn bloom_get_crown_rotation() -> f64 {
|
|
3051
3059
|
engine().input.consume_crown_rotation()
|
|
@@ -3328,3 +3336,137 @@ pub extern "C" fn bloom_set_ssgi_enabled(enabled: f64) {
|
|
|
3328
3336
|
pub extern "C" fn bloom_set_ssgi_intensity(intensity: f64) {
|
|
3329
3337
|
engine().renderer.set_ssgi_intensity(intensity as f32);
|
|
3330
3338
|
}
|
|
3339
|
+
|
|
3340
|
+
// ── Ported from native/macos for tvOS FFI parity (render textures, profiler, DOF/SSGI, splat) ──
|
|
3341
|
+
#[no_mangle]
|
|
3342
|
+
pub extern "C" fn bloom_begin_texture_mode(handle: f64) {
|
|
3343
|
+
let eng = engine();
|
|
3344
|
+
let (w, h, bg_idx) = match eng.textures.render_textures.get(handle) {
|
|
3345
|
+
Some(rt) => {
|
|
3346
|
+
let tex_handle = rt.texture_handle;
|
|
3347
|
+
match eng.textures.textures.get(tex_handle) {
|
|
3348
|
+
Some(td) => (rt.width, rt.height, td.bind_group_idx as usize),
|
|
3349
|
+
None => return,
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
None => return,
|
|
3353
|
+
};
|
|
3354
|
+
if let Some(texture) = eng.renderer.get_texture_ref(bg_idx) {
|
|
3355
|
+
// We need to call begin_texture_mode with a reference to the texture,
|
|
3356
|
+
// but get_texture_ref borrows renderer immutably. Clone the texture view
|
|
3357
|
+
// data we need first, then call the mutable method.
|
|
3358
|
+
let color_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
3359
|
+
// Create depth texture for this RT.
|
|
3360
|
+
let depth_tex = eng.renderer.device.create_texture(&wgpu::TextureDescriptor {
|
|
3361
|
+
label: Some("rt_depth"), size: wgpu::Extent3d { width: w, height: h, depth_or_array_layers: 1 },
|
|
3362
|
+
mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2,
|
|
3363
|
+
format: wgpu::TextureFormat::Depth32Float, usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
3364
|
+
view_formats: &[],
|
|
3365
|
+
});
|
|
3366
|
+
let depth_view = depth_tex.create_view(&wgpu::TextureViewDescriptor::default());
|
|
3367
|
+
eng.renderer.rt_color_view = Some(color_view);
|
|
3368
|
+
eng.renderer.rt_depth_view = Some(depth_view);
|
|
3369
|
+
eng.renderer.rt_depth_texture = Some(depth_tex);
|
|
3370
|
+
eng.renderer.rt_width = w;
|
|
3371
|
+
eng.renderer.rt_height = h;
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
#[no_mangle]
|
|
3376
|
+
pub extern "C" fn bloom_end_texture_mode() {
|
|
3377
|
+
engine().renderer.end_texture_mode();
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
#[no_mangle]
|
|
3381
|
+
pub extern "C" fn bloom_get_render_texture_texture(handle: f64) -> f64 {
|
|
3382
|
+
engine().textures.get_render_texture_texture(handle)
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
// Q1: Render texture FFI — create GPU textures for render-to-texture.
|
|
3386
|
+
#[no_mangle]
|
|
3387
|
+
pub extern "C" fn bloom_load_render_texture(width: f64, height: f64) -> f64 {
|
|
3388
|
+
let w = width as u32;
|
|
3389
|
+
let h = height as u32;
|
|
3390
|
+
let eng = engine();
|
|
3391
|
+
let rt_handle = eng.textures.load_render_texture(w, h);
|
|
3392
|
+
|
|
3393
|
+
// Create the GPU texture via the renderer's public method.
|
|
3394
|
+
let (bind_group_idx, _tex_vec_idx) = eng.renderer.create_render_texture(w, h);
|
|
3395
|
+
|
|
3396
|
+
// Register as a texture handle so drawTexture can sample it.
|
|
3397
|
+
let tex_handle = eng.textures.textures.alloc(bloom_shared::textures::TextureData {
|
|
3398
|
+
bind_group_idx, width: w, height: h,
|
|
3399
|
+
});
|
|
3400
|
+
eng.textures.set_render_texture_handle(rt_handle, tex_handle);
|
|
3401
|
+
|
|
3402
|
+
rt_handle
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
#[no_mangle]
|
|
3406
|
+
pub extern "C" fn bloom_unload_render_texture(handle: f64) {
|
|
3407
|
+
engine().textures.unload_render_texture(handle);
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
/// Phase 8 — frame history for the histogram. Header-prefixed string,
|
|
3411
|
+
/// one line per frame "<cpu_us>|<gpu_us>", oldest first, up to 120
|
|
3412
|
+
/// lines.
|
|
3413
|
+
#[no_mangle]
|
|
3414
|
+
pub extern "C" fn bloom_profiler_frame_history() -> *const u8 {
|
|
3415
|
+
let hist = engine().profiler.frame_history();
|
|
3416
|
+
let mut s = String::with_capacity(hist.len() * 24);
|
|
3417
|
+
for (cpu, gpu) in &hist {
|
|
3418
|
+
s.push_str(&format!("{:.2}|{:.2}\n", cpu, gpu));
|
|
3419
|
+
}
|
|
3420
|
+
alloc_perry_string(&s)
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
#[no_mangle]
|
|
3424
|
+
pub extern "C" fn bloom_profiler_overlay_text() -> *const u8 {
|
|
3425
|
+
let snap = engine().profiler.snapshot();
|
|
3426
|
+
let mut s = String::with_capacity(snap.len() * 48);
|
|
3427
|
+
for (label, cpu, gpu) in &snap {
|
|
3428
|
+
s.push_str(label);
|
|
3429
|
+
s.push('|');
|
|
3430
|
+
s.push_str(&format!("{:.2}", cpu));
|
|
3431
|
+
s.push('|');
|
|
3432
|
+
match gpu {
|
|
3433
|
+
Some(g) => s.push_str(&format!("{:.2}", g)),
|
|
3434
|
+
None => s.push_str("-1"),
|
|
3435
|
+
}
|
|
3436
|
+
s.push('\n');
|
|
3437
|
+
}
|
|
3438
|
+
alloc_perry_string(&s)
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
#[no_mangle]
|
|
3442
|
+
pub extern "C" fn bloom_set_dof(enabled: f64, focus_distance: f64, aperture: f64) {
|
|
3443
|
+
let r = &mut engine().renderer;
|
|
3444
|
+
r.set_dof_enabled(enabled != 0.0);
|
|
3445
|
+
r.set_dof_focus_distance(focus_distance as f32);
|
|
3446
|
+
r.set_dof_aperture(aperture as f32);
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3449
|
+
#[no_mangle]
|
|
3450
|
+
pub extern "C" fn bloom_set_ssgi_radius(radius: f64) {
|
|
3451
|
+
engine().renderer.set_ssgi_radius(radius as f32);
|
|
3452
|
+
}
|
|
3453
|
+
|
|
3454
|
+
/// Phase 8 — formatted per-pass overlay text. Returns a Perry-style
|
|
3455
|
+
/// header-prefixed string (12-byte header: len, cap, flags, then
|
|
3456
|
+
/// UTF-8 bytes) with one line per pass sorted by CPU time descending:
|
|
3457
|
+
///
|
|
3458
|
+
/// "<label>|<cpu_us>|<gpu_us_or_-1>\n..."
|
|
3459
|
+
///
|
|
3460
|
+
/// The TS overlay splits on \n then | per line. Games call this once
|
|
3461
|
+
/// per overlay-draw frame.
|
|
3462
|
+
/// Phase 7 — submit a world-space impulse. The renderer's per-frame
|
|
3463
|
+
/// compute pass decays + accumulates submissions into a 256×256
|
|
3464
|
+
/// R32Float texture covering a 128 m centred square; materials that
|
|
3465
|
+
/// sample `impulse_tex` (group 4 binding 4) read the result. Up to 16
|
|
3466
|
+
/// splats per frame are accepted — overflow is dropped silently.
|
|
3467
|
+
#[no_mangle]
|
|
3468
|
+
pub extern "C" fn bloom_splat_impulse(x: f64, z: f64, radius: f64, strength: f64) {
|
|
3469
|
+
engine().renderer.impulse_field.submit_splat(
|
|
3470
|
+
x as f32, z as f32, radius as f32, strength as f32,
|
|
3471
|
+
);
|
|
3472
|
+
}
|
|
@@ -206,6 +206,10 @@ pub extern "C" fn perry_scene_will_connect(_scene: *const c_void) {}
|
|
|
206
206
|
#[no_mangle]
|
|
207
207
|
pub extern "C" fn bloom_get_platform() -> f64 { 8.0 }
|
|
208
208
|
|
|
209
|
+
/// Preferred OS language packed as `c0*256+c1`. TODO: real per-OS detection; returns "en" for now.
|
|
210
|
+
#[no_mangle]
|
|
211
|
+
pub extern "C" fn bloom_get_language() -> f64 { 25966.0 }
|
|
212
|
+
|
|
209
213
|
#[no_mangle]
|
|
210
214
|
pub extern "C" fn bloom_get_crown_rotation() -> f64 { consume_crown() }
|
|
211
215
|
|
package/native/web/src/lib.rs
CHANGED
|
@@ -1937,6 +1937,9 @@ pub fn bloom_get_platform() -> f64 {
|
|
|
1937
1937
|
7.0 // Web platform ID
|
|
1938
1938
|
}
|
|
1939
1939
|
|
|
1940
|
+
#[wasm_bindgen]
|
|
1941
|
+
pub fn bloom_get_language() -> f64 { 25966.0 } // TODO: navigator.language via JS host glue
|
|
1942
|
+
|
|
1940
1943
|
#[wasm_bindgen]
|
|
1941
1944
|
pub fn bloom_is_any_input_pressed() -> f64 {
|
|
1942
1945
|
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
|
@@ -1635,6 +1635,10 @@ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
|
1635
1635
|
}
|
|
1636
1636
|
#[no_mangle]
|
|
1637
1637
|
pub extern "C" fn bloom_get_platform() -> f64 { 3.0 }
|
|
1638
|
+
|
|
1639
|
+
/// Preferred OS language packed as `c0*256+c1`. TODO: real per-OS detection; returns "en" for now.
|
|
1640
|
+
#[no_mangle]
|
|
1641
|
+
pub extern "C" fn bloom_get_language() -> f64 { 25966.0 }
|
|
1638
1642
|
#[no_mangle]
|
|
1639
1643
|
pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
|
|
1640
1644
|
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloomengine/engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"description": "Bloom Engine: native TypeScript game engine compiled by Perry",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -251,6 +251,7 @@
|
|
|
251
251
|
{ "name": "bloom_inject_gamepad_button_down","params": ["f64"], "returns": "void" },
|
|
252
252
|
{ "name": "bloom_inject_gamepad_button_up","params": ["f64"], "returns": "void" },
|
|
253
253
|
{ "name": "bloom_get_platform", "params": [], "returns": "f64" },
|
|
254
|
+
{ "name": "bloom_get_language", "params": [], "returns": "f64" },
|
|
254
255
|
{ "name": "bloom_is_any_input_pressed", "params": [], "returns": "f64" },
|
|
255
256
|
{ "name": "bloom_get_crown_rotation", "params": [], "returns": "f64" },
|
|
256
257
|
|
package/src/core/index.ts
CHANGED
|
@@ -97,6 +97,7 @@ declare function bloom_inject_gamepad_axis(axis: number, value: number): void;
|
|
|
97
97
|
declare function bloom_inject_gamepad_button_down(button: number): void;
|
|
98
98
|
declare function bloom_inject_gamepad_button_up(button: number): void;
|
|
99
99
|
declare function bloom_get_platform(): number;
|
|
100
|
+
declare function bloom_get_language(): number;
|
|
100
101
|
declare function bloom_is_any_input_pressed(): number;
|
|
101
102
|
declare function bloom_get_crown_rotation(): number;
|
|
102
103
|
|
|
@@ -822,6 +823,11 @@ export const Platform = { UNKNOWN: 0, MACOS: 1, IOS: 2, WINDOWS: 3, LINUX: 4, AN
|
|
|
822
823
|
|
|
823
824
|
export function getPlatform(): number { return bloom_get_platform(); }
|
|
824
825
|
|
|
826
|
+
/// User's preferred OS language as a packed 2-letter code (`c0 * 256 + c1`,
|
|
827
|
+
/// ASCII of the lowercased ISO-639 primary subtag, e.g. "en" = 101*256+110).
|
|
828
|
+
/// Script subtags are dropped (zh-Hans -> "zh"); callers map to their variant.
|
|
829
|
+
export function getLanguage(): number { return bloom_get_language(); }
|
|
830
|
+
|
|
825
831
|
export function isMobile(): boolean {
|
|
826
832
|
const p = bloom_get_platform();
|
|
827
833
|
return p === 2 || p === 5;
|