@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,154 @@
|
|
|
1
|
+
//! Split-sum BRDF LUT generator.
|
|
2
|
+
//!
|
|
3
|
+
//! Pre-integrates the GGX BRDF into a 2D `Rg16Float` table indexed by
|
|
4
|
+
//! `(NdotV, roughness)` that the PBR shader samples at runtime via
|
|
5
|
+
//! the Karis-2013 split-sum approximation. Entirely CPU-side —
|
|
6
|
+
//! builds once at startup via `build_brdf_lut(size)` and hands the
|
|
7
|
+
//! result to `queue.write_texture` in `Renderer::new`.
|
|
8
|
+
//!
|
|
9
|
+
//! Private helpers (Hammersley, GGX importance sampling, Smith
|
|
10
|
+
//! geometry) stay module-scoped; only `build_brdf_lut` is `pub` so
|
|
11
|
+
//! `Renderer::new` can reach it.
|
|
12
|
+
|
|
13
|
+
// ============================================================
|
|
14
|
+
// Split-sum BRDF LUT
|
|
15
|
+
// ============================================================
|
|
16
|
+
//
|
|
17
|
+
// Pre-integrate the GGX BRDF over hemisphere directions. The output
|
|
18
|
+
// 2D table is sampled at runtime as `brdf_lut(NdotV, roughness)` and
|
|
19
|
+
// gives a (scale, bias) pair such that:
|
|
20
|
+
// IBL_specular = prefiltered_env_sample * (F0 * scale + bias)
|
|
21
|
+
// This is the second sum of the Karis 2013 split-sum approximation.
|
|
22
|
+
//
|
|
23
|
+
// Importance-samples GGX in the H direction, integrates the visibility
|
|
24
|
+
// × Fresnel(VdotH) part. The Fresnel split into scale (F0) and bias
|
|
25
|
+
// (1) lets us factor F0 out of the integral.
|
|
26
|
+
|
|
27
|
+
const BRDF_LUT_SAMPLES: u32 = 1024;
|
|
28
|
+
|
|
29
|
+
fn radical_inverse_vdc(mut bits: u32) -> f32 {
|
|
30
|
+
bits = (bits << 16) | (bits >> 16);
|
|
31
|
+
bits = ((bits & 0x55555555) << 1) | ((bits & 0xAAAAAAAA) >> 1);
|
|
32
|
+
bits = ((bits & 0x33333333) << 2) | ((bits & 0xCCCCCCCC) >> 2);
|
|
33
|
+
bits = ((bits & 0x0F0F0F0F) << 4) | ((bits & 0xF0F0F0F0) >> 4);
|
|
34
|
+
bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8);
|
|
35
|
+
(bits as f32) * 2.328_306_4e-10
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fn hammersley(i: u32, n: u32) -> (f32, f32) {
|
|
39
|
+
(i as f32 / n as f32, radical_inverse_vdc(i))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fn importance_sample_ggx(xi: (f32, f32), n: [f32; 3], roughness: f32) -> [f32; 3] {
|
|
43
|
+
let a = roughness * roughness;
|
|
44
|
+
let phi = 2.0 * std::f32::consts::PI * xi.0;
|
|
45
|
+
let cos_theta = ((1.0 - xi.1) / (1.0 + (a * a - 1.0) * xi.1)).sqrt();
|
|
46
|
+
let sin_theta = (1.0 - cos_theta * cos_theta).max(0.0).sqrt();
|
|
47
|
+
let h_local = [sin_theta * phi.cos(), sin_theta * phi.sin(), cos_theta];
|
|
48
|
+
|
|
49
|
+
// Build TBN around N.
|
|
50
|
+
let up = if n[2].abs() < 0.999 { [0.0, 0.0, 1.0] } else { [1.0, 0.0, 0.0] };
|
|
51
|
+
let t = normalize3(cross3(up, n));
|
|
52
|
+
let b = cross3(n, t);
|
|
53
|
+
[
|
|
54
|
+
t[0] * h_local[0] + b[0] * h_local[1] + n[0] * h_local[2],
|
|
55
|
+
t[1] * h_local[0] + b[1] * h_local[1] + n[1] * h_local[2],
|
|
56
|
+
t[2] * h_local[0] + b[2] * h_local[1] + n[2] * h_local[2],
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fn cross3(a: [f32; 3], b: [f32; 3]) -> [f32; 3] {
|
|
61
|
+
[a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fn normalize3(v: [f32; 3]) -> [f32; 3] {
|
|
65
|
+
let l = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt().max(1e-8);
|
|
66
|
+
[v[0] / l, v[1] / l, v[2] / l]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn dot3(a: [f32; 3], b: [f32; 3]) -> f32 {
|
|
70
|
+
a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn geometry_smith_ggx_ibl(n_dot_v: f32, n_dot_l: f32, roughness: f32) -> f32 {
|
|
74
|
+
// IBL geometry uses k = (alpha²)/2 (Disney) — different from
|
|
75
|
+
// direct-lighting k. Returns G1(V) * G1(L).
|
|
76
|
+
let a = roughness;
|
|
77
|
+
let k = (a * a) / 2.0;
|
|
78
|
+
let g1v = n_dot_v / (n_dot_v * (1.0 - k) + k);
|
|
79
|
+
let g1l = n_dot_l / (n_dot_l * (1.0 - k) + k);
|
|
80
|
+
g1v * g1l
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn build_brdf_lut_row(y: usize, size: usize) -> Vec<u16> {
|
|
84
|
+
let n = [0.0_f32, 0.0, 1.0];
|
|
85
|
+
let roughness = ((y as f32) + 0.5) / size as f32;
|
|
86
|
+
let mut row = Vec::with_capacity(size * 2);
|
|
87
|
+
for x in 0..size {
|
|
88
|
+
let n_dot_v = ((x as f32) + 0.5) / size as f32;
|
|
89
|
+
let v = [
|
|
90
|
+
(1.0 - n_dot_v * n_dot_v).max(0.0).sqrt(),
|
|
91
|
+
0.0,
|
|
92
|
+
n_dot_v,
|
|
93
|
+
];
|
|
94
|
+
let mut a_sum = 0.0_f32;
|
|
95
|
+
let mut b_sum = 0.0_f32;
|
|
96
|
+
for i in 0..BRDF_LUT_SAMPLES {
|
|
97
|
+
let xi = hammersley(i, BRDF_LUT_SAMPLES);
|
|
98
|
+
let h = importance_sample_ggx(xi, n, roughness);
|
|
99
|
+
let v_dot_h = dot3(v, h).max(0.0);
|
|
100
|
+
let l = [
|
|
101
|
+
2.0 * v_dot_h * h[0] - v[0],
|
|
102
|
+
2.0 * v_dot_h * h[1] - v[1],
|
|
103
|
+
2.0 * v_dot_h * h[2] - v[2],
|
|
104
|
+
];
|
|
105
|
+
let n_dot_l = l[2].max(0.0);
|
|
106
|
+
let n_dot_h = h[2].max(0.0);
|
|
107
|
+
if n_dot_l > 0.0 {
|
|
108
|
+
let g = geometry_smith_ggx_ibl(n_dot_v, n_dot_l, roughness);
|
|
109
|
+
let g_vis = (g * v_dot_h) / (n_dot_h * n_dot_v + 1e-6);
|
|
110
|
+
let fc = (1.0 - v_dot_h).powi(5);
|
|
111
|
+
a_sum += (1.0 - fc) * g_vis;
|
|
112
|
+
b_sum += fc * g_vis;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
let scale = a_sum / BRDF_LUT_SAMPLES as f32;
|
|
116
|
+
let bias = b_sum / BRDF_LUT_SAMPLES as f32;
|
|
117
|
+
row.push(half::f16::from_f32(scale).to_bits());
|
|
118
|
+
row.push(half::f16::from_f32(bias).to_bits());
|
|
119
|
+
}
|
|
120
|
+
row
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Build a `size × size` BRDF LUT as packed Rg16Float texels. Each
|
|
124
|
+
/// row is constant `roughness` (v axis), each column constant `NdotV`
|
|
125
|
+
/// (u axis). Output is row-major suitable for write_texture. Splits
|
|
126
|
+
/// across `available_parallelism()` threads since cells are
|
|
127
|
+
/// independent — keeps startup latency manageable even at 1024 spp.
|
|
128
|
+
pub fn build_brdf_lut(size: usize) -> Vec<u16> {
|
|
129
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
130
|
+
{
|
|
131
|
+
let nthreads = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(4);
|
|
132
|
+
let rows_per_thread = (size + nthreads - 1) / nthreads;
|
|
133
|
+
let mut all_rows: Vec<Option<Vec<Vec<u16>>>> = (0..nthreads).map(|_| None).collect();
|
|
134
|
+
std::thread::scope(|s| {
|
|
135
|
+
let mut handles = Vec::with_capacity(nthreads);
|
|
136
|
+
for t in 0..nthreads {
|
|
137
|
+
let y_start = t * rows_per_thread;
|
|
138
|
+
let y_end = ((t + 1) * rows_per_thread).min(size);
|
|
139
|
+
let h = s.spawn(move || {
|
|
140
|
+
(y_start..y_end).map(|y| build_brdf_lut_row(y, size)).collect::<Vec<_>>()
|
|
141
|
+
});
|
|
142
|
+
handles.push(h);
|
|
143
|
+
}
|
|
144
|
+
for (t, h) in handles.into_iter().enumerate() {
|
|
145
|
+
all_rows[t] = Some(h.join().unwrap());
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
all_rows.into_iter().flatten().flatten().flatten().collect()
|
|
149
|
+
}
|
|
150
|
+
#[cfg(target_arch = "wasm32")]
|
|
151
|
+
{
|
|
152
|
+
(0..size).flat_map(|y| build_brdf_lut_row(y, size)).collect()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//! Immediate-mode 2D shape drawing (rect/line/circle — batched quads
|
|
2
|
+
//! over the white texture) and this-frame output plumbing
|
|
3
|
+
//! (FrameTarget: swapchain frame or the headless offscreen target).
|
|
4
|
+
//! Split out of renderer/mod.rs (2000-line file policy).
|
|
5
|
+
|
|
6
|
+
use super::types::Vertex2D;
|
|
7
|
+
use super::Renderer;
|
|
8
|
+
|
|
9
|
+
impl Renderer {
|
|
10
|
+
|
|
11
|
+
pub fn draw_rect(&mut self, x: f64, y: f64, w: f64, h: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
12
|
+
self.ensure_draw_state(0);
|
|
13
|
+
let color = Self::color_to_f32_srgb(r, g, b, a);
|
|
14
|
+
let base = self.vertices_2d.len() as u32;
|
|
15
|
+
let (x, y, w, h) = (x as f32, y as f32, w as f32, h as f32);
|
|
16
|
+
|
|
17
|
+
self.vertices_2d.push(Vertex2D { position: [x, y], uv: [0.0, 0.0], color });
|
|
18
|
+
self.vertices_2d.push(Vertex2D { position: [x + w, y], uv: [0.0, 0.0], color });
|
|
19
|
+
self.vertices_2d.push(Vertex2D { position: [x + w, y + h], uv: [0.0, 0.0], color });
|
|
20
|
+
self.vertices_2d.push(Vertex2D { position: [x, y + h], uv: [0.0, 0.0], color });
|
|
21
|
+
|
|
22
|
+
self.indices_2d.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pub fn draw_rect_lines(&mut self, x: f64, y: f64, w: f64, h: f64, thickness: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
26
|
+
let t = thickness;
|
|
27
|
+
self.draw_rect(x, y, w, t, r, g, b, a);
|
|
28
|
+
self.draw_rect(x, y + h - t, w, t, r, g, b, a);
|
|
29
|
+
self.draw_rect(x, y + t, t, h - 2.0 * t, r, g, b, a);
|
|
30
|
+
self.draw_rect(x + w - t, y + t, t, h - 2.0 * t, r, g, b, a);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn draw_line(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, thickness: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
34
|
+
self.ensure_draw_state(0);
|
|
35
|
+
let color = Self::color_to_f32_srgb(r, g, b, a);
|
|
36
|
+
let dx = (x2 - x1) as f32;
|
|
37
|
+
let dy = (y2 - y1) as f32;
|
|
38
|
+
let len = (dx * dx + dy * dy).sqrt();
|
|
39
|
+
if len == 0.0 { return; }
|
|
40
|
+
let half_t = (thickness as f32) * 0.5;
|
|
41
|
+
let nx = -dy / len * half_t;
|
|
42
|
+
let ny = dx / len * half_t;
|
|
43
|
+
let (x1, y1, x2, y2) = (x1 as f32, y1 as f32, x2 as f32, y2 as f32);
|
|
44
|
+
let base = self.vertices_2d.len() as u32;
|
|
45
|
+
|
|
46
|
+
self.vertices_2d.push(Vertex2D { position: [x1 + nx, y1 + ny], uv: [0.0, 0.0], color });
|
|
47
|
+
self.vertices_2d.push(Vertex2D { position: [x1 - nx, y1 - ny], uv: [0.0, 0.0], color });
|
|
48
|
+
self.vertices_2d.push(Vertex2D { position: [x2 - nx, y2 - ny], uv: [0.0, 0.0], color });
|
|
49
|
+
self.vertices_2d.push(Vertex2D { position: [x2 + nx, y2 + ny], uv: [0.0, 0.0], color });
|
|
50
|
+
|
|
51
|
+
self.indices_2d.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub fn draw_circle(&mut self, cx: f64, cy: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
55
|
+
self.ensure_draw_state(0);
|
|
56
|
+
let color = Self::color_to_f32_srgb(r, g, b, a);
|
|
57
|
+
let segments = 36u32;
|
|
58
|
+
let base = self.vertices_2d.len() as u32;
|
|
59
|
+
let (cx, cy, radius) = (cx as f32, cy as f32, radius as f32);
|
|
60
|
+
|
|
61
|
+
self.vertices_2d.push(Vertex2D { position: [cx, cy], uv: [0.0, 0.0], color });
|
|
62
|
+
for i in 0..segments {
|
|
63
|
+
let angle = (i as f32) / (segments as f32) * std::f32::consts::TAU;
|
|
64
|
+
self.vertices_2d.push(Vertex2D {
|
|
65
|
+
position: [cx + radius * angle.cos(), cy + radius * angle.sin()],
|
|
66
|
+
uv: [0.0, 0.0],
|
|
67
|
+
color,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
for i in 0..segments {
|
|
71
|
+
let next = if i + 1 < segments { i + 1 } else { 0 };
|
|
72
|
+
self.indices_2d.extend_from_slice(&[base, base + 1 + i, base + 1 + next]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
pub fn draw_circle_lines(&mut self, cx: f64, cy: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
77
|
+
let segments = 36;
|
|
78
|
+
for i in 0..segments {
|
|
79
|
+
let a1 = (i as f64) / (segments as f64) * std::f64::consts::TAU;
|
|
80
|
+
let a2 = ((i + 1) as f64) / (segments as f64) * std::f64::consts::TAU;
|
|
81
|
+
self.draw_line(
|
|
82
|
+
cx + radius * a1.cos(), cy + radius * a1.sin(),
|
|
83
|
+
cx + radius * a2.cos(), cy + radius * a2.sin(),
|
|
84
|
+
1.0, r, g, b, a,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// This frame's output: a swapchain frame, or the persistent offscreen
|
|
91
|
+
/// texture in headless mode.
|
|
92
|
+
pub(crate) enum FrameTarget {
|
|
93
|
+
Surface(wgpu::SurfaceTexture),
|
|
94
|
+
Headless,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
impl Renderer {
|
|
98
|
+
/// Acquire the frame target. `None` means the swapchain was lost and
|
|
99
|
+
/// has been reconfigured — skip this frame.
|
|
100
|
+
pub(super) fn acquire_frame(&self) -> Option<FrameTarget> {
|
|
101
|
+
match &self.surface {
|
|
102
|
+
Some(surface) => match surface.get_current_texture() {
|
|
103
|
+
wgpu::CurrentSurfaceTexture::Success(t)
|
|
104
|
+
| wgpu::CurrentSurfaceTexture::Suboptimal(t) => Some(FrameTarget::Surface(t)),
|
|
105
|
+
_ => {
|
|
106
|
+
// Diagnostic (title-freeze investigation): this path used
|
|
107
|
+
// to fail silently; an eternal acquire failure looks like
|
|
108
|
+
// a frozen game (headless spin, last frame stays on
|
|
109
|
+
// screen). One-shot + periodic so a wedged swapchain is
|
|
110
|
+
// visible in stderr.
|
|
111
|
+
static ACQ_FAILS: std::sync::atomic::AtomicU32 =
|
|
112
|
+
std::sync::atomic::AtomicU32::new(0);
|
|
113
|
+
let n = ACQ_FAILS.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
|
|
114
|
+
if n == 1 || n % 300 == 0 {
|
|
115
|
+
crate::ffi::log_error(&format!(
|
|
116
|
+
"bloom: surface acquire failed (count={n}) — reconfiguring and skipping frame"
|
|
117
|
+
));
|
|
118
|
+
}
|
|
119
|
+
surface.configure(&self.device, &self.surface_config);
|
|
120
|
+
None
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
None => Some(FrameTarget::Headless),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
pub(super) fn frame_texture<'a>(&'a self, target: &'a FrameTarget) -> &'a wgpu::Texture {
|
|
128
|
+
match target {
|
|
129
|
+
FrameTarget::Surface(t) => &t.texture,
|
|
130
|
+
FrameTarget::Headless => self
|
|
131
|
+
.headless_target
|
|
132
|
+
.as_ref()
|
|
133
|
+
.expect("headless renderer always owns a headless_target"),
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
pub(super) fn present_frame(&self, target: FrameTarget) {
|
|
138
|
+
if let FrameTarget::Surface(t) = target {
|
|
139
|
+
t.present();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|