Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions native/shared/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,22 @@ fn build_jolt() {
.join(format!("{}Jolt.{}", lib_prefix, lib_ext));

if !(bloom_jolt_lib.exists() && jolt_lib.exists()) {
let _ = cmake::Config::new(&shim_dir)
.out_dir(&dst)
let mut cfg = cmake::Config::new(&shim_dir);
cfg.out_dir(&dst)
.profile("Release")
.define("CMAKE_BUILD_TYPE", "Release")
.build();
.define("CMAKE_BUILD_TYPE", "Release");
if target_os == "windows" {
// perry links the prebuilt Jolt archive with lld-link, which
// cannot read MSVC `/GL` (whole-program-optimization) object
// files — they're LTCG intermediates, not native COFF, and the
// link fails with "is not a native COFF file. Recompile without
// /GL?". Turn off Jolt's interprocedural optimization so the
// archive holds ordinary COFF objects perry can consume. (Costs
// a little Jolt codegen perf; physics is not the bottleneck.)
cfg.define("INTERPROCEDURAL_OPTIMIZATION", "OFF")
.define("CMAKE_INTERPROCEDURAL_OPTIMIZATION", "OFF");
}
let _ = cfg.build();
}

println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
Expand Down
56 changes: 56 additions & 0 deletions native/shared/src/ffi_core/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,62 @@ macro_rules! __bloom_ffi_models {
0.0
}

// Array-free mesh upload (Perry 0.5.1171 rejects number[] -> i64 pointer
// params; see ModelManager::scratch_f32). Push the 12-float vertex
// records + u32 indices one scalar at a time (all-f64 ABI), then build.
#[cfg(feature = "models3d")]
#[no_mangle]
pub extern "C" fn bloom_mesh_scratch_reset() {
$crate::ffi::guard("bloom_mesh_scratch_reset", move || {
engine().models.mesh_scratch_reset();
})
}
#[cfg(not(feature = "models3d"))]
#[no_mangle]
pub extern "C" fn bloom_mesh_scratch_reset() {
$crate::ffi::feature_off_warn_once("bloom_mesh_scratch_reset", "models3d");
}

#[cfg(feature = "models3d")]
#[no_mangle]
pub extern "C" fn bloom_mesh_scratch_push_f32(v: f64) {
$crate::ffi::guard("bloom_mesh_scratch_push_f32", move || {
engine().models.mesh_scratch_push_f32(v as f32);
})
}
#[cfg(not(feature = "models3d"))]
#[no_mangle]
pub extern "C" fn bloom_mesh_scratch_push_f32(_v: f64) {
$crate::ffi::feature_off_warn_once("bloom_mesh_scratch_push_f32", "models3d");
}

#[cfg(feature = "models3d")]
#[no_mangle]
pub extern "C" fn bloom_mesh_scratch_push_u32(v: f64) {
$crate::ffi::guard("bloom_mesh_scratch_push_u32", move || {
engine().models.mesh_scratch_push_u32(v as u32);
})
}
#[cfg(not(feature = "models3d"))]
#[no_mangle]
pub extern "C" fn bloom_mesh_scratch_push_u32(_v: f64) {
$crate::ffi::feature_off_warn_once("bloom_mesh_scratch_push_u32", "models3d");
}

#[cfg(feature = "models3d")]
#[no_mangle]
pub extern "C" fn bloom_create_mesh_scratch(vertex_count: f64, index_count: f64) -> f64 {
$crate::ffi::guard("bloom_create_mesh_scratch", move || {
engine().models.create_mesh_from_scratch(vertex_count as u32, index_count as u32)
})
}
#[cfg(not(feature = "models3d"))]
#[no_mangle]
pub extern "C" fn bloom_create_mesh_scratch(_vertex_count: f64, _index_count: f64) -> f64 {
$crate::ffi::feature_off_warn_once("bloom_create_mesh_scratch", "models3d");
0.0
}

// bloom_get_model_mesh_count [source: linux; gated: models3d]
#[cfg(feature = "models3d")]
#[no_mangle]
Expand Down
41 changes: 41 additions & 0 deletions native/shared/src/ffi_core/visual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,47 @@ macro_rules! __bloom_ffi_visual {
})
}

// bloom_set_bloom_intensity [source: art-direction]
// Scales the bloom contribution added to the HDR scene before tonemap
// (0 = none, ~0.04 subtle default, higher = stronger glow).
#[no_mangle]
pub extern "C" fn bloom_set_bloom_intensity(value: f64) {
$crate::ffi::guard("bloom_set_bloom_intensity", move || {
engine().renderer.set_bloom_intensity(value as f32);
})
}

// bloom_set_tonemap [source: art-direction]
// Selects the tonemap operator: 0 = ACES (default), 1 = AgX (more
// filmic, better highlight desaturation + a punchier look).
#[no_mangle]
pub extern "C" fn bloom_set_tonemap(kind: f64) {
$crate::ffi::guard("bloom_set_tonemap", move || {
engine().renderer.set_tonemap_kind(kind as u32);
})
}

// bloom_set_auto_exposure_key [source: art-direction]
// Target scene-average luma for auto-exposure. Lower = the auto-
// exposure aims for a darker, more saturated midpoint (less wash-out);
// higher = brighter.
#[no_mangle]
pub extern "C" fn bloom_set_auto_exposure_key(key: f64) {
$crate::ffi::guard("bloom_set_auto_exposure_key", move || {
engine().renderer.set_auto_exposure_key(key as f32);
})
}

// bloom_set_auto_exposure_rate [source: art-direction]
// Per-frame adaptation rate for auto-exposure (0 = frozen, ~0.05 = a
// smooth eye-adaptation feel, 1 = instant).
#[no_mangle]
pub extern "C" fn bloom_set_auto_exposure_rate(rate: f64) {
$crate::ffi::guard("bloom_set_auto_exposure_rate", move || {
engine().renderer.set_auto_exposure_rate(rate as f32);
})
}

// bloom_set_ssao_enabled [source: macos]
#[no_mangle]
pub extern "C" fn bloom_set_ssao_enabled(on: f64) {
Expand Down
31 changes: 31 additions & 0 deletions native/shared/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,47 @@ pub struct ModelAnimation {
pub struct ModelManager {
pub models: HandleRegistry<ModelData>,
pub animations: HandleRegistry<ModelAnimation>,
/// Scratch buffers for the array-free mesh-upload path. Perry 0.5.1171
/// rejects passing a JS `number[]` to a native `i64` pointer param
/// (strict safe-integer check), so `createMesh` instead pushes vertex
/// floats / indices one scalar at a time through `mesh_scratch_push_*`
/// (all `f64` ABI) and then builds the mesh from these. Mirrors the
/// physics subsystem's `scratch_*` shape-upload path.
pub scratch_f32: Vec<f32>,
pub scratch_u32: Vec<u32>,
}

impl ModelManager {
pub fn new() -> Self {
Self {
models: HandleRegistry::new(),
animations: HandleRegistry::new(),
scratch_f32: Vec::new(),
scratch_u32: Vec::new(),
}
}

pub fn mesh_scratch_reset(&mut self) {
self.scratch_f32.clear();
self.scratch_u32.clear();
}
pub fn mesh_scratch_push_f32(&mut self, v: f32) { self.scratch_f32.push(v); }
pub fn mesh_scratch_push_u32(&mut self, v: u32) { self.scratch_u32.push(v); }

/// Build a mesh from the scratch buffers: `vertex_count` vertices of 12
/// floats each in `scratch_f32`, `index_count` indices in `scratch_u32`.
pub fn create_mesh_from_scratch(&mut self, vertex_count: u32, index_count: u32) -> f64 {
let need_f = vertex_count as usize * 12;
let need_u = index_count as usize;
if vertex_count == 0 || self.scratch_f32.len() < need_f || self.scratch_u32.len() < need_u {
return 0.0;
}
// Clone out so create_mesh's &self borrow doesn't alias scratch.
let verts: Vec<f32> = self.scratch_f32[..need_f].to_vec();
let inds: Vec<u32> = self.scratch_u32[..need_u].to_vec();
self.create_mesh(&verts, &inds)
}

pub fn load_model(&mut self, file_data: &[u8]) -> f64 {
match load_gltf(file_data) {
Some(model) => self.models.alloc(model),
Expand Down
5 changes: 3 additions & 2 deletions native/shared/src/renderer/lighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ pub(super) fn create_lighting_layout(
};
let frag = wgpu::ShaderStages::FRAGMENT;
let mut entries = vec![
// 0: Lighting UBO
// 0: Lighting UBO. VERTEX_FRAGMENT so the scene vertex shader can read
// `wind` (foliage sway); the fragment stage uses the full struct.
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: frag,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
Expand Down
Loading
Loading