@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.
Files changed (213) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +231 -0
  3. package/native/android/Cargo.lock +1848 -0
  4. package/native/android/Cargo.toml +24 -0
  5. package/native/android/src/lib.rs +702 -0
  6. package/native/ios/Cargo.lock +1690 -0
  7. package/native/ios/Cargo.toml +32 -0
  8. package/native/ios/src/lib.rs +1267 -0
  9. package/native/linux/Cargo.lock +3279 -0
  10. package/native/linux/Cargo.toml +29 -0
  11. package/native/linux/src/lib.rs +1331 -0
  12. package/native/macos/Cargo.lock +3310 -0
  13. package/native/macos/Cargo.toml +46 -0
  14. package/native/macos/src/lib.rs +1302 -0
  15. package/native/shared/Cargo.lock +1899 -0
  16. package/native/shared/Cargo.toml +62 -0
  17. package/native/shared/assets/default_font.ttf +0 -0
  18. package/native/shared/build.rs +270 -0
  19. package/native/shared/shaders/common/clouds.wgsl +122 -0
  20. package/native/shared/shaders/common/fog.wgsl +16 -0
  21. package/native/shared/shaders/common/foliage_wind.wgsl +98 -0
  22. package/native/shared/shaders/common/imposter.wgsl +112 -0
  23. package/native/shared/shaders/common/pbr.wgsl +186 -0
  24. package/native/shared/shaders/common/shadows.wgsl +186 -0
  25. package/native/shared/shaders/common/sky.wgsl +8 -0
  26. package/native/shared/shaders/common/tonemap.wgsl +25 -0
  27. package/native/shared/shaders/impulse_field.wgsl +57 -0
  28. package/native/shared/shaders/material_abi.wgsl +383 -0
  29. package/native/shared/shaders/materials/test_minimal.wgsl +42 -0
  30. package/native/shared/src/anim_mixer.rs +61 -0
  31. package/native/shared/src/attach.rs +263 -0
  32. package/native/shared/src/audio/decode.rs +123 -0
  33. package/native/shared/src/audio/mod.rs +863 -0
  34. package/native/shared/src/audio/render.rs +892 -0
  35. package/native/shared/src/audio/spsc.rs +156 -0
  36. package/native/shared/src/audio/stream.rs +226 -0
  37. package/native/shared/src/custom_shaders.rs +104 -0
  38. package/native/shared/src/decals.rs +245 -0
  39. package/native/shared/src/drs.rs +211 -0
  40. package/native/shared/src/engine.rs +261 -0
  41. package/native/shared/src/ffi.rs +116 -0
  42. package/native/shared/src/ffi_core/assets.rs +388 -0
  43. package/native/shared/src/ffi_core/audio_ffi.rs +184 -0
  44. package/native/shared/src/ffi_core/draw.rs +334 -0
  45. package/native/shared/src/ffi_core/game_loop.rs +577 -0
  46. package/native/shared/src/ffi_core/input.rs +234 -0
  47. package/native/shared/src/ffi_core/mod.rs +127 -0
  48. package/native/shared/src/ffi_core/models.rs +1154 -0
  49. package/native/shared/src/ffi_core/ragdoll_ffi.rs +261 -0
  50. package/native/shared/src/ffi_core/scene.rs +626 -0
  51. package/native/shared/src/ffi_core/vfx.rs +212 -0
  52. package/native/shared/src/ffi_core/visual.rs +691 -0
  53. package/native/shared/src/frame_callbacks.rs +122 -0
  54. package/native/shared/src/geometry.rs +236 -0
  55. package/native/shared/src/handles.rs +182 -0
  56. package/native/shared/src/input.rs +448 -0
  57. package/native/shared/src/jolt_sys.rs +822 -0
  58. package/native/shared/src/lib.rs +55 -0
  59. package/native/shared/src/models.rs +1093 -0
  60. package/native/shared/src/models_gltf.rs +1280 -0
  61. package/native/shared/src/particles.rs +391 -0
  62. package/native/shared/src/physics_jolt.rs +1908 -0
  63. package/native/shared/src/picking.rs +298 -0
  64. package/native/shared/src/postfx.rs +345 -0
  65. package/native/shared/src/profiler.rs +492 -0
  66. package/native/shared/src/ragdoll.rs +474 -0
  67. package/native/shared/src/renderer/atmosphere_lut.rs +573 -0
  68. package/native/shared/src/renderer/brdf_lut.rs +154 -0
  69. package/native/shared/src/renderer/draw2d.rs +143 -0
  70. package/native/shared/src/renderer/formats.rs +822 -0
  71. package/native/shared/src/renderer/froxel.rs +421 -0
  72. package/native/shared/src/renderer/gi_bake.rs +653 -0
  73. package/native/shared/src/renderer/graph.rs +462 -0
  74. package/native/shared/src/renderer/hiz.rs +269 -0
  75. package/native/shared/src/renderer/hot_reload.rs +390 -0
  76. package/native/shared/src/renderer/impulse_field.rs +456 -0
  77. package/native/shared/src/renderer/lighting.rs +154 -0
  78. package/native/shared/src/renderer/material_instancing.rs +171 -0
  79. package/native/shared/src/renderer/material_pipeline.rs +700 -0
  80. package/native/shared/src/renderer/material_system.rs +1996 -0
  81. package/native/shared/src/renderer/material_system_tests.rs +601 -0
  82. package/native/shared/src/renderer/material_system_wasm.rs +41 -0
  83. package/native/shared/src/renderer/mod.rs +12556 -0
  84. package/native/shared/src/renderer/model_draw.rs +641 -0
  85. package/native/shared/src/renderer/occlusion.rs +429 -0
  86. package/native/shared/src/renderer/planar_pass.rs +593 -0
  87. package/native/shared/src/renderer/planar_reflection.rs +499 -0
  88. package/native/shared/src/renderer/post_pass.rs +249 -0
  89. package/native/shared/src/renderer/postfx_chain.rs +728 -0
  90. package/native/shared/src/renderer/pt_pass.rs +577 -0
  91. package/native/shared/src/renderer/scene_pass.rs +607 -0
  92. package/native/shared/src/renderer/shader_include.rs +205 -0
  93. package/native/shared/src/renderer/shader_library.rs +135 -0
  94. package/native/shared/src/renderer/shaders/ao.rs +570 -0
  95. package/native/shared/src/renderer/shaders/core.rs +1243 -0
  96. package/native/shared/src/renderer/shaders/env.rs +907 -0
  97. package/native/shared/src/renderer/shaders/gi.rs +810 -0
  98. package/native/shared/src/renderer/shaders/mod.rs +19 -0
  99. package/native/shared/src/renderer/shaders/post.rs +1558 -0
  100. package/native/shared/src/renderer/shaders/pt.rs +1859 -0
  101. package/native/shared/src/renderer/shaders/ssgi.rs +1586 -0
  102. package/native/shared/src/renderer/shadow_pass.rs +731 -0
  103. package/native/shared/src/renderer/ssgi_pass.rs +392 -0
  104. package/native/shared/src/renderer/ssr_pass.rs +188 -0
  105. package/native/shared/src/renderer/texture_store.rs +473 -0
  106. package/native/shared/src/renderer/transient.rs +591 -0
  107. package/native/shared/src/renderer/types.rs +941 -0
  108. package/native/shared/src/renderer/util.rs +152 -0
  109. package/native/shared/src/scene.rs +1362 -0
  110. package/native/shared/src/sdf_cache.rs +274 -0
  111. package/native/shared/src/shadows.rs +1036 -0
  112. package/native/shared/src/staging.rs +102 -0
  113. package/native/shared/src/string_header.rs +266 -0
  114. package/native/shared/src/text_renderer.rs +502 -0
  115. package/native/shared/src/textures.rs +197 -0
  116. package/native/tvos/Cargo.lock +1693 -0
  117. package/native/tvos/Cargo.toml +36 -0
  118. package/native/tvos/metal-patched/Cargo.toml +178 -0
  119. package/native/tvos/metal-patched/LICENSE-APACHE +201 -0
  120. package/native/tvos/metal-patched/LICENSE-MIT +25 -0
  121. package/native/tvos/metal-patched/src/acceleration_structure.rs +667 -0
  122. package/native/tvos/metal-patched/src/acceleration_structure_pass.rs +108 -0
  123. package/native/tvos/metal-patched/src/argument.rs +366 -0
  124. package/native/tvos/metal-patched/src/blitpass.rs +102 -0
  125. package/native/tvos/metal-patched/src/buffer.rs +71 -0
  126. package/native/tvos/metal-patched/src/capturedescriptor.rs +76 -0
  127. package/native/tvos/metal-patched/src/capturemanager.rs +113 -0
  128. package/native/tvos/metal-patched/src/commandbuffer.rs +192 -0
  129. package/native/tvos/metal-patched/src/commandqueue.rs +44 -0
  130. package/native/tvos/metal-patched/src/computepass.rs +107 -0
  131. package/native/tvos/metal-patched/src/constants.rs +152 -0
  132. package/native/tvos/metal-patched/src/counters.rs +119 -0
  133. package/native/tvos/metal-patched/src/depthstencil.rs +190 -0
  134. package/native/tvos/metal-patched/src/device.rs +2134 -0
  135. package/native/tvos/metal-patched/src/drawable.rs +39 -0
  136. package/native/tvos/metal-patched/src/encoder.rs +2041 -0
  137. package/native/tvos/metal-patched/src/heap.rs +281 -0
  138. package/native/tvos/metal-patched/src/indirect_encoder.rs +344 -0
  139. package/native/tvos/metal-patched/src/lib.rs +657 -0
  140. package/native/tvos/metal-patched/src/library.rs +902 -0
  141. package/native/tvos/metal-patched/src/mps.rs +575 -0
  142. package/native/tvos/metal-patched/src/pipeline/compute.rs +475 -0
  143. package/native/tvos/metal-patched/src/pipeline/mod.rs +71 -0
  144. package/native/tvos/metal-patched/src/pipeline/render.rs +762 -0
  145. package/native/tvos/metal-patched/src/renderpass.rs +443 -0
  146. package/native/tvos/metal-patched/src/resource.rs +182 -0
  147. package/native/tvos/metal-patched/src/sampler.rs +165 -0
  148. package/native/tvos/metal-patched/src/sync.rs +178 -0
  149. package/native/tvos/metal-patched/src/texture.rs +352 -0
  150. package/native/tvos/metal-patched/src/types.rs +90 -0
  151. package/native/tvos/metal-patched/src/vertexdescriptor.rs +250 -0
  152. package/native/tvos/src/audio_backend.rs +197 -0
  153. package/native/tvos/src/lib.rs +1891 -0
  154. package/native/visionos/Cargo.lock +1693 -0
  155. package/native/visionos/Cargo.toml +40 -0
  156. package/native/visionos/src/audio_backend.rs +197 -0
  157. package/native/visionos/src/lib.rs +1887 -0
  158. package/native/watchos/Cargo.lock +16 -0
  159. package/native/watchos/Cargo.toml +19 -0
  160. package/native/watchos/shaders/bloom_postfx.metal +99 -0
  161. package/native/watchos/src/BloomWatchApp.swift +1267 -0
  162. package/native/watchos/src/BloomWatchAudio.swift +179 -0
  163. package/native/watchos/src/audio.rs +55 -0
  164. package/native/watchos/src/draw_list.rs +229 -0
  165. package/native/watchos/src/ffi_stubs.rs +915 -0
  166. package/native/watchos/src/ffi_stubs_manual.rs +35 -0
  167. package/native/watchos/src/lib.rs +1124 -0
  168. package/native/watchos/src/models.rs +746 -0
  169. package/native/watchos/src/postfx.rs +95 -0
  170. package/native/watchos/src/scene.rs +534 -0
  171. package/native/watchos/src/textures.rs +184 -0
  172. package/native/web/Cargo.lock +1657 -0
  173. package/native/web/Cargo.toml +43 -0
  174. package/native/web/bloom_glue.js +695 -0
  175. package/native/web/build.sh +131 -0
  176. package/native/web/index.html +35 -0
  177. package/native/web/jolt_bridge.js +1519 -0
  178. package/native/web/src/input_ffi.rs +286 -0
  179. package/native/web/src/lib.rs +1796 -0
  180. package/native/web/src/material_ffi.rs +710 -0
  181. package/native/web/src/parity_ffi.rs +343 -0
  182. package/native/web/src/physics_ffi.rs +643 -0
  183. package/native/web/src/ragdoll_ffi.rs +250 -0
  184. package/native/web/src/render_settings.rs +98 -0
  185. package/native/windows/Cargo.lock +1815 -0
  186. package/native/windows/Cargo.toml +68 -0
  187. package/native/windows/src/lib.rs +1486 -0
  188. package/package.json +4279 -0
  189. package/src/audio/index.ts +315 -0
  190. package/src/core/colors.ts +63 -0
  191. package/src/core/index.ts +1206 -0
  192. package/src/core/keys.ts +63 -0
  193. package/src/core/types.ts +104 -0
  194. package/src/index.ts +171 -0
  195. package/src/math/index.ts +516 -0
  196. package/src/mobile/index.ts +294 -0
  197. package/src/models/index.ts +1258 -0
  198. package/src/physics/index.ts +1134 -0
  199. package/src/scene/index.ts +698 -0
  200. package/src/shapes/index.ts +120 -0
  201. package/src/text/index.ts +48 -0
  202. package/src/textures/index.ts +187 -0
  203. package/src/vfx/index.ts +191 -0
  204. package/src/world/index.ts +24 -0
  205. package/src/world/loader.ts +423 -0
  206. package/src/world/prefab.ts +217 -0
  207. package/src/world/render.ts +172 -0
  208. package/src/world/saver.ts +108 -0
  209. package/src/world/serialize.ts +301 -0
  210. package/src/world/terrain.ts +355 -0
  211. package/src/world/types.ts +160 -0
  212. package/src/world/validate.ts +319 -0
  213. package/src/world/version.ts +114 -0
@@ -0,0 +1,698 @@
1
+ /**
2
+ * Bloom Scene Graph — Retained-mode 3D scene management.
3
+ *
4
+ * Unlike immediate-mode drawing (drawCube, drawModel), the scene graph holds
5
+ * persistent meshes that survive across frames. Systems update geometry and
6
+ * transforms; the renderer draws all visible nodes each frame automatically.
7
+ *
8
+ * Use immediate-mode for prototypes and small scenes; use the scene graph
9
+ * when you need persistence, picking, per-node materials, or hundreds of
10
+ * objects (nodes are frustum- and occlusion-culled automatically).
11
+ *
12
+ * Coordinate system: right-handed, Y-up, world units are meters.
13
+ * Surface colors are 0-255 per channel; light colors are 0-1 floats with
14
+ * a separate intensity (see addDirectionalLight).
15
+ *
16
+ * Designed for architecture/CAD editors compiled natively via Perry.
17
+ */
18
+
19
+ // ============================================================
20
+ // FFI declarations (match package.json nativeLibrary.functions)
21
+ // ============================================================
22
+
23
+ declare function bloom_scene_create_node(): number;
24
+ declare function bloom_scene_destroy_node(handle: number): void;
25
+ declare function bloom_scene_set_visible(handle: number, visible: number): void;
26
+ declare function bloom_scene_set_gi_only(handle: number, gi_only: number): void;
27
+ declare function bloom_scene_set_cast_shadow(handle: number, cast: number): void;
28
+ declare function bloom_scene_set_receive_shadow(handle: number, receive: number): void;
29
+ declare function bloom_scene_set_parent(handle: number, parent: number): void;
30
+ declare function bloom_scene_set_transform(handle: number, matrix: number): void;
31
+ // All-scalar transform + geometry entry points. Perry 0.5.x cannot pass a
32
+ // `number[]` into the i64 pointer params above, so these are the ones the
33
+ // wrappers actually call.
34
+ declare function bloom_scene_set_transform16(
35
+ handle: number,
36
+ m0: number, m1: number, m2: number, m3: number,
37
+ m4: number, m5: number, m6: number, m7: number,
38
+ m8: number, m9: number, m10: number, m11: number,
39
+ m12: number, m13: number, m14: number, m15: number,
40
+ ): void;
41
+ declare function bloom_scene_update_geometry_scratch(
42
+ handle: number,
43
+ vertexCount: number,
44
+ indexCount: number,
45
+ ): void;
46
+ declare function bloom_mesh_scratch_reset(): void;
47
+ declare function bloom_mesh_scratch_push_f32(v: number): void;
48
+ declare function bloom_mesh_scratch_push_u32(v: number): void;
49
+ declare function bloom_scene_set_trs(handle: number, px: number, py: number, pz: number, yaw: number, scale: number): void;
50
+ declare function bloom_scene_update_geometry(
51
+ handle: number,
52
+ vertices: number,
53
+ vertexCount: number,
54
+ indices: number,
55
+ indexCount: number,
56
+ ): void;
57
+ declare function bloom_scene_set_material_color(handle: number, r: number, g: number, b: number, a: number): void;
58
+ declare function bloom_scene_set_material_pbr(handle: number, roughness: number, metalness: number): void;
59
+ declare function bloom_scene_set_material_texture(handle: number, textureIdx: number): void;
60
+ declare function bloom_scene_node_count(): number;
61
+
62
+ // Frame callbacks
63
+ declare function bloom_register_frame_callback(priority: number, callback: number): number;
64
+ declare function bloom_unregister_frame_callback(id: number): void;
65
+
66
+ // Multiple lights
67
+ declare function bloom_add_directional_light(
68
+ dx: number, dy: number, dz: number,
69
+ r: number, g: number, b: number,
70
+ intensity: number,
71
+ ): void;
72
+ declare function bloom_add_point_light(
73
+ x: number, y: number, z: number, range: number,
74
+ r: number, g: number, b: number,
75
+ intensity: number,
76
+ ): void;
77
+
78
+ // Shadows
79
+ declare function bloom_enable_shadows(): void;
80
+ declare function bloom_disable_shadows(): void;
81
+ declare function bloom_dump_shadow_map(path: number): void;
82
+
83
+ // Post-processing
84
+ declare function bloom_enable_postfx(): void;
85
+ declare function bloom_disable_postfx(): void;
86
+ declare function bloom_postfx_set_selected(handle: number): void;
87
+ declare function bloom_postfx_set_hovered(handle: number): void;
88
+ declare function bloom_postfx_set_outline_color(r: number, g: number, b: number, a: number): void;
89
+ declare function bloom_postfx_set_outline_thickness(thickness: number): void;
90
+
91
+ // Model attachment
92
+ declare function bloom_scene_attach_model(nodeHandle: number, modelHandle: number, meshIndex: number): void;
93
+
94
+ // 3D→2D Projection
95
+ declare function bloom_project_to_screen(wx: number, wy: number, wz: number): number;
96
+ declare function bloom_project_screen_y(): number;
97
+
98
+ // Scene picking
99
+ declare function bloom_scene_pick(screenX: number, screenY: number): number;
100
+ declare function bloom_pick_hit_handle(): number;
101
+ declare function bloom_pick_hit_distance(): number;
102
+ declare function bloom_pick_hit_x(): number;
103
+ declare function bloom_pick_hit_y(): number;
104
+ declare function bloom_pick_hit_z(): number;
105
+ declare function bloom_pick_hit_normal_x(): number;
106
+ declare function bloom_pick_hit_normal_y(): number;
107
+ declare function bloom_pick_hit_normal_z(): number;
108
+
109
+ // Geometry generation
110
+ // Q6: multi-hit picking
111
+ declare function bloom_scene_pick_all(screenX: number, screenY: number, maxResults: number): number;
112
+ declare function bloom_pick_all_handle(index: number): number;
113
+ declare function bloom_pick_all_distance(index: number): number;
114
+
115
+ // Q8: water material
116
+ declare function bloom_scene_set_material_water(handle: number, waveAmp: number, waveSpeed: number, r: number, g: number, b: number, a: number): void;
117
+
118
+ // Q4: transform read-back
119
+ declare function bloom_scene_get_transform(handle: number, index: number): number;
120
+ // Q5: node bounds
121
+ declare function bloom_scene_get_bounds_min_x(handle: number): number;
122
+ declare function bloom_scene_get_bounds_min_y(handle: number): number;
123
+ declare function bloom_scene_get_bounds_min_z(handle: number): number;
124
+ declare function bloom_scene_get_bounds_max_x(handle: number): number;
125
+ declare function bloom_scene_get_bounds_max_y(handle: number): number;
126
+ declare function bloom_scene_get_bounds_max_z(handle: number): number;
127
+ // Q7: user data
128
+ declare function bloom_scene_set_user_data(handle: number, data: number): void;
129
+ declare function bloom_scene_get_user_data(handle: number): number;
130
+
131
+ declare function bloom_scene_extrude_polygon(
132
+ handle: number,
133
+ polygon: number,
134
+ pointCount: number,
135
+ depth: number,
136
+ ): void;
137
+ declare function bloom_scene_subtract_box(
138
+ handle: number,
139
+ minX: number, minY: number, minZ: number,
140
+ maxX: number, maxY: number, maxZ: number,
141
+ ): void;
142
+
143
+ // ============================================================
144
+ // Types
145
+ // ============================================================
146
+
147
+ export type SceneNodeHandle = number;
148
+
149
+ export interface PbrMaterial {
150
+ color?: [number, number, number];
151
+ roughness?: number;
152
+ metalness?: number;
153
+ opacity?: number;
154
+ textureIdx?: number;
155
+ }
156
+
157
+ // ============================================================
158
+ // Public API
159
+ // ============================================================
160
+
161
+ /**
162
+ * Create a new empty scene node. Returns a handle.
163
+ * The node is visible by default but has no geometry.
164
+ */
165
+ export function createSceneNode(): SceneNodeHandle {
166
+ return bloom_scene_create_node();
167
+ }
168
+
169
+ /**
170
+ * Destroy a scene node, freeing its GPU resources.
171
+ */
172
+ export function destroySceneNode(handle: SceneNodeHandle): void {
173
+ bloom_scene_destroy_node(handle);
174
+ }
175
+
176
+ /**
177
+ * Set visibility of a scene node.
178
+ */
179
+ export function setSceneNodeVisible(handle: SceneNodeHandle, visible: boolean): void {
180
+ bloom_scene_set_visible(handle, visible ? 1 : 0);
181
+ }
182
+
183
+ /**
184
+ * Set whether this node casts shadows.
185
+ */
186
+ export function setSceneNodeCastShadow(handle: SceneNodeHandle, cast: boolean): void {
187
+ bloom_scene_set_cast_shadow(handle, cast ? 1 : 0);
188
+ }
189
+
190
+ /**
191
+ * Set whether this node receives shadows.
192
+ */
193
+ export function setSceneNodeReceiveShadow(handle: SceneNodeHandle, receive: boolean): void {
194
+ bloom_scene_set_receive_shadow(handle, receive ? 1 : 0);
195
+ }
196
+
197
+ /**
198
+ * Mark a node as a GI proxy: it feeds the global-illumination inputs
199
+ * (ray-tracing BLAS/TLAS, mesh cards, SDF clipmap) but is skipped by the
200
+ * main render, planar reflections, and the sun-shadow pass.
201
+ *
202
+ * Use this when your world renders through the material system (custom
203
+ * WGSL materials, no scene nodes): register invisible duplicates of the
204
+ * big static geometry — terrain, buildings, tree trunks — so SSGI picks
205
+ * up bounce light from surfaces that are off-screen. Set an approximate
206
+ * flat base colour via setSceneNodeMaterialPbr so the bounce carries the
207
+ * right hue; leave the node visible (the flag handles exclusion).
208
+ */
209
+ export function setSceneNodeGiOnly(handle: SceneNodeHandle, giOnly: boolean): void {
210
+ bloom_scene_set_gi_only(handle, giOnly ? 1 : 0);
211
+ }
212
+
213
+ /**
214
+ * Set the parent of a scene node. Pass 0 for no parent (root node).
215
+ */
216
+ export function setSceneNodeParent(handle: SceneNodeHandle, parent: SceneNodeHandle): void {
217
+ bloom_scene_set_parent(handle, parent);
218
+ }
219
+
220
+ /**
221
+ * Set the 4x4 transform matrix for a scene node.
222
+ * Matrix is in column-major order (same as Three.js/glm).
223
+ *
224
+ * Takes a column-major 16-element matrix, so arbitrary rotation and
225
+ * non-uniform scale are expressible (`setSceneNodeTrs` covers only
226
+ * position + yaw + uniform scale).
227
+ *
228
+ * The matrix crosses the FFI as 16 scalars rather than a pointer: Perry
229
+ * 0.5.x refuses to pass a `number[]` into an `i64` pointer param
230
+ * ("Expected safe integer for native i64 parameter"), which made the old
231
+ * pointer-based entry point unreachable from TypeScript.
232
+ */
233
+ export function setSceneNodeTransform(handle: SceneNodeHandle, matrix: number[]): void {
234
+ bloom_scene_set_transform16(
235
+ handle,
236
+ matrix[0], matrix[1], matrix[2], matrix[3],
237
+ matrix[4], matrix[5], matrix[6], matrix[7],
238
+ matrix[8], matrix[9], matrix[10], matrix[11],
239
+ matrix[12], matrix[13], matrix[14], matrix[15],
240
+ );
241
+ }
242
+
243
+ /**
244
+ * Place a scene node with position + Y-axis rotation + uniform scale.
245
+ * All-scalar FFI (Perry 0.5.x safe). Yaw is radians, same convention as
246
+ * `drawModelRotated`.
247
+ */
248
+ export function setSceneNodeTrs(
249
+ handle: SceneNodeHandle,
250
+ x: number, y: number, z: number,
251
+ yaw: number = 0,
252
+ scale: number = 1,
253
+ ): void {
254
+ bloom_scene_set_trs(handle, x, y, z, yaw, scale);
255
+ }
256
+
257
+ /**
258
+ * Update the geometry of a scene node.
259
+ *
260
+ * @param vertices — Flat array of vertex data. Each vertex has 12 floats:
261
+ * [x, y, z, nx, ny, nz, r, g, b, a, u, v]
262
+ * @param indices — Flat array of triangle indices (3 per triangle).
263
+ *
264
+ * Uploads through the mesh scratch buffers (one scalar per FFI call) for the
265
+ * same reason as `createMesh`: Perry 0.5.x rejects `number[]` in an `i64`
266
+ * pointer param. Cost is linear in the mesh size, so this is for
267
+ * edit-time re-meshing (terrain sculpting), not per-frame streaming.
268
+ */
269
+ export function updateSceneNodeGeometry(
270
+ handle: SceneNodeHandle,
271
+ vertices: number[],
272
+ indices: number[],
273
+ ): void {
274
+ const vertexCount = Math.floor(vertices.length / 12);
275
+ const indexCount = indices.length;
276
+ if (vertexCount === 0 || indexCount === 0) return;
277
+
278
+ bloom_mesh_scratch_reset();
279
+ const floatCount = vertexCount * 12;
280
+ for (let i = 0; i < floatCount; i++) bloom_mesh_scratch_push_f32(vertices[i]);
281
+ for (let i = 0; i < indexCount; i++) bloom_mesh_scratch_push_u32(indices[i]);
282
+ bloom_scene_update_geometry_scratch(handle, vertexCount, indexCount);
283
+ }
284
+
285
+ /**
286
+ * Set the material color and opacity of a scene node.
287
+ * Color components are 0-1 (not 0-255).
288
+ */
289
+ /**
290
+ * Set a node's material base color.
291
+ *
292
+ * Color components are 0-255 (the engine-wide convention — same scale as
293
+ * the `Colors` presets and every draw* call). Before v0.5 this function
294
+ * alone took 0-1 floats; passing a `Colors` constant silently rendered
295
+ * white. Values are clamped; alpha defaults to opaque.
296
+ */
297
+ export function setSceneNodeColor(handle: SceneNodeHandle, r: number, g: number, b: number, a: number = 255): void {
298
+ bloom_scene_set_material_color(handle, r / 255, g / 255, b / 255, a / 255);
299
+ }
300
+
301
+ /**
302
+ * Set PBR material properties (roughness and metalness).
303
+ */
304
+ /**
305
+ * Add a reduced-detail geometry variant to a node. The node's normal
306
+ * geometry is the finest level; `lodIndex` 0,1,2… are progressively
307
+ * coarser variants. `maxCoverage` is the screen-coverage threshold
308
+ * (0..1, fraction of the viewport the node's bounds span) below which
309
+ * this variant renders — give coarser variants smaller values, e.g.
310
+ * LOD0 at 0.4, LOD1 at 0.15, LOD2 at 0.05. Selection has hysteresis to
311
+ * avoid flicker at boundaries. Shadows and picking always use the full
312
+ * geometry. Vertex layout matches updateSceneNodeGeometry (12 floats).
313
+ */
314
+ export function setSceneNodeLod(
315
+ handle: SceneNodeHandle, lodIndex: number,
316
+ vertices: number[], indices: number[], maxCoverage: number,
317
+ ): void {
318
+ bloom_scene_set_lod(handle, lodIndex, vertices as any, vertices.length / 12, indices as any, indices.length, maxCoverage);
319
+ }
320
+
321
+ /**
322
+ * Attach a mesh from a loaded model as a reduced-detail variant — the
323
+ * model-based counterpart of setSceneNodeLod. Export your LOD meshes as
324
+ * separate meshes (or models) and attach each with its threshold.
325
+ */
326
+ export function attachModelLodToNode(
327
+ node: SceneNodeHandle, model: { handle: number }, meshIndex: number,
328
+ lodIndex: number, maxCoverage: number,
329
+ ): void {
330
+ bloom_scene_attach_model_lod(node, model.handle, meshIndex, lodIndex, maxCoverage);
331
+ }
332
+
333
+ export function setSceneNodePbr(handle: SceneNodeHandle, roughness: number, metalness: number): void {
334
+ bloom_scene_set_material_pbr(handle, roughness, metalness);
335
+ }
336
+
337
+ /**
338
+ * Set the texture for a scene node's material.
339
+ * Pass 0 for the default white texture.
340
+ */
341
+ export function setSceneNodeTexture(handle: SceneNodeHandle, textureIdx: number): void {
342
+ bloom_scene_set_material_texture(handle, textureIdx);
343
+ }
344
+
345
+ /**
346
+ * Get the number of live scene nodes.
347
+ */
348
+ export function getSceneNodeCount(): number {
349
+ return bloom_scene_node_count();
350
+ }
351
+
352
+ // ============================================================
353
+ // Frame Callbacks (replaces R3F's useFrame)
354
+ // ============================================================
355
+
356
+ /**
357
+ * Register a callback that runs every frame, ordered by priority.
358
+ * Lower priority numbers run first (matching R3F convention:
359
+ * SlabSystem=1, ItemSystem=2, DoorSystem=3, WallSystem=4, RoofSystem=5).
360
+ *
361
+ * Returns an ID that can be used to unregister the callback.
362
+ */
363
+ export function registerFrameCallback(priority: number, callback: (deltaTime: number) => void): number {
364
+ return bloom_register_frame_callback(priority, callback as any);
365
+ }
366
+
367
+ /**
368
+ * Unregister a frame callback by ID.
369
+ */
370
+ export function unregisterFrameCallback(id: number): void {
371
+ bloom_unregister_frame_callback(id);
372
+ }
373
+
374
+ // ============================================================
375
+ // Multiple Lights
376
+ // ============================================================
377
+
378
+ /**
379
+ * Add a directional light. Color is 0-1 range. Up to 4 additional directional lights.
380
+ * Called each frame (lights are cleared at frame start).
381
+ */
382
+ /**
383
+ * Add a directional light. Light color is a 0-1 float per channel with a
384
+ * separate intensity multiplier (radiometric convention, like Unity and
385
+ * Unreal — light colors are not surface colors and may meaningfully
386
+ * exceed 1.0 via intensity). Direction need not be normalized.
387
+ */
388
+ export function addDirectionalLight(
389
+ dx: number, dy: number, dz: number,
390
+ r: number, g: number, b: number,
391
+ intensity: number,
392
+ ): void {
393
+ bloom_add_directional_light(dx, dy, dz, r, g, b, intensity);
394
+ }
395
+
396
+ /**
397
+ * Add a point light. Color is 0-1 range. Up to 16 point lights.
398
+ * Called each frame (lights are cleared at frame start).
399
+ */
400
+ // ============================================================
401
+ // Shadow Mapping
402
+ // ============================================================
403
+
404
+ /**
405
+ * Enable shadow mapping (single directional light).
406
+ * Shadows are rendered from the primary directional light's perspective.
407
+ */
408
+ export function enableShadows(): void {
409
+ bloom_enable_shadows();
410
+ }
411
+
412
+ /**
413
+ * Disable shadow mapping.
414
+ */
415
+ export function disableShadows(): void {
416
+ bloom_disable_shadows();
417
+ }
418
+
419
+ /**
420
+ * Dump the shadow map depth texture to a grayscale PNG for debugging.
421
+ */
422
+ export function dumpShadowMap(path: string): void {
423
+ bloom_dump_shadow_map(path as any);
424
+ }
425
+
426
+ // ============================================================
427
+ // Post-Processing (Outlines, SSAO)
428
+ // ============================================================
429
+
430
+ /**
431
+ * Enable the post-processing pipeline (outlines, SSAO).
432
+ * Must be called after initWindow.
433
+ */
434
+ export function enablePostFx(): void {
435
+ bloom_enable_postfx();
436
+ }
437
+
438
+ /**
439
+ * Disable post-processing (render directly to screen).
440
+ */
441
+ export function disablePostFx(): void {
442
+ bloom_disable_postfx();
443
+ }
444
+
445
+ /**
446
+ * Set the selected scene node for outline rendering.
447
+ * Pass 0 to clear selection. Matching Pascal Editor's outliner.selectedObjects.
448
+ */
449
+ export function setPostFxSelected(handle: SceneNodeHandle): void {
450
+ bloom_postfx_set_selected(handle);
451
+ }
452
+
453
+ /**
454
+ * Set the hovered scene node for outline rendering.
455
+ * Pass 0 to clear hover.
456
+ */
457
+ export function setPostFxHovered(handle: SceneNodeHandle): void {
458
+ bloom_postfx_set_hovered(handle);
459
+ }
460
+
461
+ /**
462
+ * Set the outline color for selected objects (0-1 range).
463
+ */
464
+ /** Selection-outline color, 0-255 per channel (engine-wide convention). */
465
+ export function setOutlineColor(r: number, g: number, b: number, a: number = 255): void {
466
+ bloom_postfx_set_outline_color(r / 255, g / 255, b / 255, a / 255);
467
+ }
468
+
469
+ /**
470
+ * Set the outline thickness in pixels.
471
+ */
472
+ export function setOutlineThickness(thickness: number): void {
473
+ bloom_postfx_set_outline_thickness(thickness);
474
+ }
475
+
476
+ // ============================================================
477
+ // Model Attachment (GLTF → Scene Node)
478
+ // ============================================================
479
+
480
+ /**
481
+ * Attach a loaded GLTF model's mesh to a scene node.
482
+ * Copies vertex/index data from the model into the scene node's geometry.
483
+ * This is the native equivalent of R3F's useGLTF + Clone.
484
+ *
485
+ * @param nodeHandle — scene node to receive the geometry
486
+ * @param modelHandle — loaded model handle (from loadModel())
487
+ * @param meshIndex — which mesh in the model (0 for single-mesh models)
488
+ */
489
+ export function attachModelToNode(
490
+ nodeHandle: SceneNodeHandle,
491
+ modelHandle: number,
492
+ meshIndex: number = 0,
493
+ ): void {
494
+ bloom_scene_attach_model(nodeHandle, modelHandle, meshIndex);
495
+ }
496
+
497
+ // ============================================================
498
+ // 3D → 2D Projection (for UI overlays in 3D space)
499
+ // ============================================================
500
+
501
+ /**
502
+ * Project a world-space 3D point to screen coordinates.
503
+ * Returns { x, y, visible }. If the point is behind the camera, visible is false.
504
+ *
505
+ * This is the native equivalent of R3F's drei Html component positioning.
506
+ * Used for zone labels, dimension references, interactive controls.
507
+ */
508
+ export function projectToScreen(
509
+ worldX: number, worldY: number, worldZ: number,
510
+ ): { x: number; y: number; visible: boolean } {
511
+ const sx = bloom_project_to_screen(worldX, worldY, worldZ);
512
+ const sy = bloom_project_screen_y();
513
+ return {
514
+ x: sx,
515
+ y: sy,
516
+ visible: sx > -9000,
517
+ };
518
+ }
519
+
520
+ // ============================================================
521
+ // Scene Picking (raycasting from screen)
522
+ // ============================================================
523
+
524
+ export interface PickHit {
525
+ hit: boolean;
526
+ handle: SceneNodeHandle;
527
+ distance: number;
528
+ point: { x: number; y: number; z: number };
529
+ normal: { x: number; y: number; z: number };
530
+ }
531
+
532
+ /**
533
+ * Raycast from screen coordinates against all visible scene nodes.
534
+ * Returns the closest hit with world-space point and normal.
535
+ *
536
+ * Must be called after beginMode3D() so the camera matrices are set.
537
+ */
538
+ export function pickScene(screenX: number, screenY: number): PickHit {
539
+ const hit = bloom_scene_pick(screenX, screenY) !== 0;
540
+ if (!hit) {
541
+ return {
542
+ hit: false,
543
+ handle: 0,
544
+ distance: 0,
545
+ point: { x: 0, y: 0, z: 0 },
546
+ normal: { x: 0, y: 0, z: 0 },
547
+ };
548
+ }
549
+ return {
550
+ hit: true,
551
+ handle: bloom_pick_hit_handle(),
552
+ distance: bloom_pick_hit_distance(),
553
+ point: {
554
+ x: bloom_pick_hit_x(),
555
+ y: bloom_pick_hit_y(),
556
+ z: bloom_pick_hit_z(),
557
+ },
558
+ normal: {
559
+ x: bloom_pick_hit_normal_x(),
560
+ y: bloom_pick_hit_normal_y(),
561
+ z: bloom_pick_hit_normal_z(),
562
+ },
563
+ };
564
+ }
565
+
566
+ // ============================================================
567
+ // Geometry Generation
568
+ // ============================================================
569
+
570
+ /**
571
+ * Extrude a 2D polygon along Y axis and set as the node's geometry.
572
+ * The polygon is a flat array of 2D points: [x0, z0, x1, z1, ...].
573
+ * Extrusion goes from Y=0 to Y=depth.
574
+ */
575
+ export function extrudePolygon(
576
+ handle: SceneNodeHandle,
577
+ polygon: number[],
578
+ depth: number,
579
+ ): void {
580
+ bloom_scene_extrude_polygon(handle, polygon as any, polygon.length / 2, depth);
581
+ }
582
+
583
+ /**
584
+ * Subtract an axis-aligned box from a scene node's geometry.
585
+ * Removes triangles fully inside the box (simplified CSG for door cutouts).
586
+ */
587
+ export function subtractBox(
588
+ handle: SceneNodeHandle,
589
+ minX: number, minY: number, minZ: number,
590
+ maxX: number, maxY: number, maxZ: number,
591
+ ): void {
592
+ bloom_scene_subtract_box(handle, minX, minY, minZ, maxX, maxY, maxZ);
593
+ }
594
+
595
+ // ============================================================
596
+ // Q4: Transform Read-back
597
+ // ============================================================
598
+
599
+ /**
600
+ * Read back the 4x4 transform matrix of a scene node as a flat 16-element
601
+ * array in column-major order (same layout as setSceneNodeTransform).
602
+ */
603
+ export function getSceneNodeTransform(handle: SceneNodeHandle): number[] {
604
+ const m: number[] = new Array(16);
605
+ for (let i = 0; i < 16; i++) {
606
+ m[i] = bloom_scene_get_transform(handle, i);
607
+ }
608
+ return m;
609
+ }
610
+
611
+ // ============================================================
612
+ // Q5: Scene Node Bounds
613
+ // ============================================================
614
+
615
+ /**
616
+ * Return the cached AABB of a scene node's geometry in local space.
617
+ * Recomputed automatically when geometry is updated via updateSceneNodeGeometry.
618
+ */
619
+ export function getSceneNodeBounds(handle: SceneNodeHandle): { min: { x: number; y: number; z: number }; max: { x: number; y: number; z: number } } {
620
+ return {
621
+ min: {
622
+ x: bloom_scene_get_bounds_min_x(handle),
623
+ y: bloom_scene_get_bounds_min_y(handle),
624
+ z: bloom_scene_get_bounds_min_z(handle),
625
+ },
626
+ max: {
627
+ x: bloom_scene_get_bounds_max_x(handle),
628
+ y: bloom_scene_get_bounds_max_y(handle),
629
+ z: bloom_scene_get_bounds_max_z(handle),
630
+ },
631
+ };
632
+ }
633
+
634
+ // ============================================================
635
+ // Q7: Scene Node User Data
636
+ // ============================================================
637
+
638
+ /**
639
+ * Attach an arbitrary integer to a scene node. Used by editors to associate
640
+ * entity ids with scene nodes so picking can return the entity id directly.
641
+ */
642
+ export function setSceneNodeUserData(handle: SceneNodeHandle, data: number): void {
643
+ bloom_scene_set_user_data(handle, data);
644
+ }
645
+
646
+ export function getSceneNodeUserData(handle: SceneNodeHandle): number {
647
+ return bloom_scene_get_user_data(handle);
648
+ }
649
+
650
+ // ============================================================
651
+ // Q6: Multi-Hit Picking
652
+ // ============================================================
653
+
654
+ /**
655
+ * Raycast against all visible scene nodes and return all hits sorted by
656
+ * distance (closest first). Used by editors for Alt-click cycling through
657
+ * occluded objects. Returns an array of { handle, distance }.
658
+ */
659
+ export function pickSceneAll(screenX: number, screenY: number, maxResults: number = 8): { handle: number; distance: number }[] {
660
+ const count = bloom_scene_pick_all(screenX, screenY, maxResults);
661
+ const results: { handle: number; distance: number }[] = [];
662
+ for (let i = 0; i < count; i++) {
663
+ results.push({
664
+ handle: bloom_pick_all_handle(i),
665
+ distance: bloom_pick_all_distance(i),
666
+ });
667
+ }
668
+ return results;
669
+ }
670
+
671
+ // ============================================================
672
+ // Q8: Water Material
673
+ // ============================================================
674
+
675
+ /**
676
+ * Set a water-like material on a scene node with translucent tint and
677
+ * low roughness. The wave parameters are stored for a future animated
678
+ * water shader; currently they're visual-only placeholders.
679
+ */
680
+ /**
681
+ * Water surface material. Color is 0-255 per channel (engine-wide
682
+ * convention; was 0-1 before v0.5).
683
+ */
684
+ export function setSceneNodeWaterMaterial(
685
+ handle: SceneNodeHandle,
686
+ waveAmplitude: number, waveSpeed: number,
687
+ r: number, g: number, b: number, a: number,
688
+ ): void {
689
+ bloom_scene_set_material_water(handle, waveAmplitude, waveSpeed, r / 255, g / 255, b / 255, a / 255);
690
+ }
691
+
692
+ export function addPointLight(
693
+ x: number, y: number, z: number, range: number,
694
+ r: number, g: number, b: number,
695
+ intensity: number,
696
+ ): void {
697
+ bloom_add_point_light(x, y, z, range, r, g, b, intensity);
698
+ }