@bloomengine/engine 0.3.1

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 (562) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/native/android/Cargo.lock +1848 -0
  4. package/native/android/Cargo.toml +20 -0
  5. package/native/android/src/lib.rs +1747 -0
  6. package/native/ios/Cargo.lock +1688 -0
  7. package/native/ios/Cargo.toml +19 -0
  8. package/native/ios/src/lib.rs +2258 -0
  9. package/native/linux/Cargo.lock +1719 -0
  10. package/native/linux/Cargo.toml +22 -0
  11. package/native/linux/src/lib.rs +2236 -0
  12. package/native/macos/Cargo.lock +3310 -0
  13. package/native/macos/Cargo.toml +29 -0
  14. package/native/macos/src/lib.rs +3444 -0
  15. package/native/shared/Cargo.lock +1898 -0
  16. package/native/shared/Cargo.toml +42 -0
  17. package/native/shared/assets/default_font.ttf +0 -0
  18. package/native/shared/build.rs +77 -0
  19. package/native/shared/shaders/common/fog.wgsl +16 -0
  20. package/native/shared/shaders/common/imposter.wgsl +112 -0
  21. package/native/shared/shaders/common/pbr.wgsl +186 -0
  22. package/native/shared/shaders/common/shadows.wgsl +77 -0
  23. package/native/shared/shaders/common/sky.wgsl +8 -0
  24. package/native/shared/shaders/common/tonemap.wgsl +25 -0
  25. package/native/shared/shaders/impulse_field.wgsl +53 -0
  26. package/native/shared/shaders/material_abi.wgsl +360 -0
  27. package/native/shared/shaders/materials/test_minimal.wgsl +42 -0
  28. package/native/shared/src/audio.rs +363 -0
  29. package/native/shared/src/custom_shaders.rs +104 -0
  30. package/native/shared/src/drs.rs +211 -0
  31. package/native/shared/src/engine.rs +186 -0
  32. package/native/shared/src/frame_callbacks.rs +88 -0
  33. package/native/shared/src/geometry.rs +236 -0
  34. package/native/shared/src/handles.rs +76 -0
  35. package/native/shared/src/input.rs +273 -0
  36. package/native/shared/src/jolt_sys.rs +822 -0
  37. package/native/shared/src/lib.rs +43 -0
  38. package/native/shared/src/models.rs +1941 -0
  39. package/native/shared/src/physics_jolt.rs +1528 -0
  40. package/native/shared/src/picking.rs +298 -0
  41. package/native/shared/src/postfx.rs +339 -0
  42. package/native/shared/src/profiler.rs +416 -0
  43. package/native/shared/src/renderer/atmosphere_lut.rs +573 -0
  44. package/native/shared/src/renderer/brdf_lut.rs +154 -0
  45. package/native/shared/src/renderer/formats.rs +778 -0
  46. package/native/shared/src/renderer/graph.rs +465 -0
  47. package/native/shared/src/renderer/hot_reload.rs +390 -0
  48. package/native/shared/src/renderer/impulse_field.rs +455 -0
  49. package/native/shared/src/renderer/material_pipeline.rs +604 -0
  50. package/native/shared/src/renderer/material_system.rs +2106 -0
  51. package/native/shared/src/renderer/mod.rs +13923 -0
  52. package/native/shared/src/renderer/planar_reflection.rs +458 -0
  53. package/native/shared/src/renderer/post_pass.rs +249 -0
  54. package/native/shared/src/renderer/shader_include.rs +205 -0
  55. package/native/shared/src/renderer/shader_library.rs +134 -0
  56. package/native/shared/src/renderer/shaders.rs +5855 -0
  57. package/native/shared/src/renderer/transient.rs +576 -0
  58. package/native/shared/src/renderer/types.rs +259 -0
  59. package/native/shared/src/renderer/util.rs +151 -0
  60. package/native/shared/src/scene.rs +1066 -0
  61. package/native/shared/src/sdf_cache.rs +274 -0
  62. package/native/shared/src/shadows.rs +551 -0
  63. package/native/shared/src/staging.rs +90 -0
  64. package/native/shared/src/string_header.rs +35 -0
  65. package/native/shared/src/text_renderer.rs +456 -0
  66. package/native/shared/src/textures.rs +154 -0
  67. package/native/third_party/JoltPhysics/Jolt/AABBTree/AABBTreeBuilder.cpp +242 -0
  68. package/native/third_party/JoltPhysics/Jolt/AABBTree/AABBTreeBuilder.h +121 -0
  69. package/native/third_party/JoltPhysics/Jolt/AABBTree/AABBTreeToBuffer.h +296 -0
  70. package/native/third_party/JoltPhysics/Jolt/AABBTree/NodeCodec/NodeCodecQuadTreeHalfFloat.h +323 -0
  71. package/native/third_party/JoltPhysics/Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h +555 -0
  72. package/native/third_party/JoltPhysics/Jolt/ConfigurationString.h +112 -0
  73. package/native/third_party/JoltPhysics/Jolt/Core/ARMNeon.h +94 -0
  74. package/native/third_party/JoltPhysics/Jolt/Core/Array.h +713 -0
  75. package/native/third_party/JoltPhysics/Jolt/Core/Atomics.h +44 -0
  76. package/native/third_party/JoltPhysics/Jolt/Core/BinaryHeap.h +96 -0
  77. package/native/third_party/JoltPhysics/Jolt/Core/ByteBuffer.h +74 -0
  78. package/native/third_party/JoltPhysics/Jolt/Core/Color.cpp +38 -0
  79. package/native/third_party/JoltPhysics/Jolt/Core/Color.h +98 -0
  80. package/native/third_party/JoltPhysics/Jolt/Core/Core.h +652 -0
  81. package/native/third_party/JoltPhysics/Jolt/Core/FPControlWord.h +143 -0
  82. package/native/third_party/JoltPhysics/Jolt/Core/FPException.h +96 -0
  83. package/native/third_party/JoltPhysics/Jolt/Core/FPFlushDenormals.h +43 -0
  84. package/native/third_party/JoltPhysics/Jolt/Core/Factory.cpp +92 -0
  85. package/native/third_party/JoltPhysics/Jolt/Core/Factory.h +54 -0
  86. package/native/third_party/JoltPhysics/Jolt/Core/FixedSizeFreeList.h +122 -0
  87. package/native/third_party/JoltPhysics/Jolt/Core/FixedSizeFreeList.inl +215 -0
  88. package/native/third_party/JoltPhysics/Jolt/Core/HashCombine.h +234 -0
  89. package/native/third_party/JoltPhysics/Jolt/Core/HashTable.h +876 -0
  90. package/native/third_party/JoltPhysics/Jolt/Core/InsertionSort.h +58 -0
  91. package/native/third_party/JoltPhysics/Jolt/Core/IssueReporting.cpp +27 -0
  92. package/native/third_party/JoltPhysics/Jolt/Core/IssueReporting.h +38 -0
  93. package/native/third_party/JoltPhysics/Jolt/Core/JobSystem.h +311 -0
  94. package/native/third_party/JoltPhysics/Jolt/Core/JobSystem.inl +56 -0
  95. package/native/third_party/JoltPhysics/Jolt/Core/JobSystemSingleThreaded.cpp +65 -0
  96. package/native/third_party/JoltPhysics/Jolt/Core/JobSystemSingleThreaded.h +62 -0
  97. package/native/third_party/JoltPhysics/Jolt/Core/JobSystemThreadPool.cpp +364 -0
  98. package/native/third_party/JoltPhysics/Jolt/Core/JobSystemThreadPool.h +101 -0
  99. package/native/third_party/JoltPhysics/Jolt/Core/JobSystemWithBarrier.cpp +230 -0
  100. package/native/third_party/JoltPhysics/Jolt/Core/JobSystemWithBarrier.h +85 -0
  101. package/native/third_party/JoltPhysics/Jolt/Core/LinearCurve.cpp +51 -0
  102. package/native/third_party/JoltPhysics/Jolt/Core/LinearCurve.h +67 -0
  103. package/native/third_party/JoltPhysics/Jolt/Core/LockFreeHashMap.h +182 -0
  104. package/native/third_party/JoltPhysics/Jolt/Core/LockFreeHashMap.inl +351 -0
  105. package/native/third_party/JoltPhysics/Jolt/Core/Memory.cpp +85 -0
  106. package/native/third_party/JoltPhysics/Jolt/Core/Memory.h +85 -0
  107. package/native/third_party/JoltPhysics/Jolt/Core/Mutex.h +223 -0
  108. package/native/third_party/JoltPhysics/Jolt/Core/MutexArray.h +98 -0
  109. package/native/third_party/JoltPhysics/Jolt/Core/NonCopyable.h +18 -0
  110. package/native/third_party/JoltPhysics/Jolt/Core/Profiler.cpp +677 -0
  111. package/native/third_party/JoltPhysics/Jolt/Core/Profiler.h +301 -0
  112. package/native/third_party/JoltPhysics/Jolt/Core/Profiler.inl +90 -0
  113. package/native/third_party/JoltPhysics/Jolt/Core/QuickSort.h +137 -0
  114. package/native/third_party/JoltPhysics/Jolt/Core/RTTI.cpp +149 -0
  115. package/native/third_party/JoltPhysics/Jolt/Core/RTTI.h +436 -0
  116. package/native/third_party/JoltPhysics/Jolt/Core/Reference.h +244 -0
  117. package/native/third_party/JoltPhysics/Jolt/Core/Result.h +174 -0
  118. package/native/third_party/JoltPhysics/Jolt/Core/STLAlignedAllocator.h +72 -0
  119. package/native/third_party/JoltPhysics/Jolt/Core/STLAllocator.h +127 -0
  120. package/native/third_party/JoltPhysics/Jolt/Core/STLLocalAllocator.h +170 -0
  121. package/native/third_party/JoltPhysics/Jolt/Core/STLTempAllocator.h +80 -0
  122. package/native/third_party/JoltPhysics/Jolt/Core/ScopeExit.h +49 -0
  123. package/native/third_party/JoltPhysics/Jolt/Core/Semaphore.cpp +135 -0
  124. package/native/third_party/JoltPhysics/Jolt/Core/Semaphore.h +68 -0
  125. package/native/third_party/JoltPhysics/Jolt/Core/StaticArray.h +329 -0
  126. package/native/third_party/JoltPhysics/Jolt/Core/StreamIn.h +120 -0
  127. package/native/third_party/JoltPhysics/Jolt/Core/StreamOut.h +97 -0
  128. package/native/third_party/JoltPhysics/Jolt/Core/StreamUtils.h +168 -0
  129. package/native/third_party/JoltPhysics/Jolt/Core/StreamWrapper.h +53 -0
  130. package/native/third_party/JoltPhysics/Jolt/Core/StridedPtr.h +63 -0
  131. package/native/third_party/JoltPhysics/Jolt/Core/StringTools.cpp +101 -0
  132. package/native/third_party/JoltPhysics/Jolt/Core/StringTools.h +38 -0
  133. package/native/third_party/JoltPhysics/Jolt/Core/TempAllocator.h +209 -0
  134. package/native/third_party/JoltPhysics/Jolt/Core/TickCounter.cpp +37 -0
  135. package/native/third_party/JoltPhysics/Jolt/Core/TickCounter.h +58 -0
  136. package/native/third_party/JoltPhysics/Jolt/Core/UnorderedMap.h +80 -0
  137. package/native/third_party/JoltPhysics/Jolt/Core/UnorderedSet.h +32 -0
  138. package/native/third_party/JoltPhysics/Jolt/Geometry/AABox.h +313 -0
  139. package/native/third_party/JoltPhysics/Jolt/Geometry/AABox4.h +224 -0
  140. package/native/third_party/JoltPhysics/Jolt/Geometry/ClipPoly.h +200 -0
  141. package/native/third_party/JoltPhysics/Jolt/Geometry/ClosestPoint.h +498 -0
  142. package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder.cpp +1467 -0
  143. package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder.h +276 -0
  144. package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder2D.cpp +335 -0
  145. package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder2D.h +105 -0
  146. package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexSupport.h +188 -0
  147. package/native/third_party/JoltPhysics/Jolt/Geometry/EPAConvexHullBuilder.h +845 -0
  148. package/native/third_party/JoltPhysics/Jolt/Geometry/EPAPenetrationDepth.h +557 -0
  149. package/native/third_party/JoltPhysics/Jolt/Geometry/Ellipse.h +77 -0
  150. package/native/third_party/JoltPhysics/Jolt/Geometry/GJKClosestPoint.h +945 -0
  151. package/native/third_party/JoltPhysics/Jolt/Geometry/IndexedTriangle.h +130 -0
  152. package/native/third_party/JoltPhysics/Jolt/Geometry/Indexify.cpp +222 -0
  153. package/native/third_party/JoltPhysics/Jolt/Geometry/Indexify.h +19 -0
  154. package/native/third_party/JoltPhysics/Jolt/Geometry/MortonCode.h +40 -0
  155. package/native/third_party/JoltPhysics/Jolt/Geometry/OrientedBox.cpp +178 -0
  156. package/native/third_party/JoltPhysics/Jolt/Geometry/OrientedBox.h +39 -0
  157. package/native/third_party/JoltPhysics/Jolt/Geometry/Plane.h +104 -0
  158. package/native/third_party/JoltPhysics/Jolt/Geometry/RayAABox.h +241 -0
  159. package/native/third_party/JoltPhysics/Jolt/Geometry/RayCapsule.h +37 -0
  160. package/native/third_party/JoltPhysics/Jolt/Geometry/RayCylinder.h +101 -0
  161. package/native/third_party/JoltPhysics/Jolt/Geometry/RaySphere.h +96 -0
  162. package/native/third_party/JoltPhysics/Jolt/Geometry/RayTriangle.h +158 -0
  163. package/native/third_party/JoltPhysics/Jolt/Geometry/Sphere.h +72 -0
  164. package/native/third_party/JoltPhysics/Jolt/Geometry/Triangle.h +34 -0
  165. package/native/third_party/JoltPhysics/Jolt/Jolt.cmake +703 -0
  166. package/native/third_party/JoltPhysics/Jolt/Jolt.h +16 -0
  167. package/native/third_party/JoltPhysics/Jolt/Jolt.natvis +116 -0
  168. package/native/third_party/JoltPhysics/Jolt/Math/BVec16.h +99 -0
  169. package/native/third_party/JoltPhysics/Jolt/Math/BVec16.inl +177 -0
  170. package/native/third_party/JoltPhysics/Jolt/Math/DMat44.h +158 -0
  171. package/native/third_party/JoltPhysics/Jolt/Math/DMat44.inl +310 -0
  172. package/native/third_party/JoltPhysics/Jolt/Math/DVec3.h +291 -0
  173. package/native/third_party/JoltPhysics/Jolt/Math/DVec3.inl +941 -0
  174. package/native/third_party/JoltPhysics/Jolt/Math/Double3.h +48 -0
  175. package/native/third_party/JoltPhysics/Jolt/Math/DynMatrix.h +31 -0
  176. package/native/third_party/JoltPhysics/Jolt/Math/EigenValueSymmetric.h +177 -0
  177. package/native/third_party/JoltPhysics/Jolt/Math/FindRoot.h +42 -0
  178. package/native/third_party/JoltPhysics/Jolt/Math/Float2.h +36 -0
  179. package/native/third_party/JoltPhysics/Jolt/Math/Float3.h +50 -0
  180. package/native/third_party/JoltPhysics/Jolt/Math/Float4.h +44 -0
  181. package/native/third_party/JoltPhysics/Jolt/Math/GaussianElimination.h +102 -0
  182. package/native/third_party/JoltPhysics/Jolt/Math/HalfFloat.h +208 -0
  183. package/native/third_party/JoltPhysics/Jolt/Math/Mat44.h +243 -0
  184. package/native/third_party/JoltPhysics/Jolt/Math/Mat44.inl +952 -0
  185. package/native/third_party/JoltPhysics/Jolt/Math/Math.h +208 -0
  186. package/native/third_party/JoltPhysics/Jolt/Math/MathTypes.h +32 -0
  187. package/native/third_party/JoltPhysics/Jolt/Math/Matrix.h +259 -0
  188. package/native/third_party/JoltPhysics/Jolt/Math/Quat.h +268 -0
  189. package/native/third_party/JoltPhysics/Jolt/Math/Quat.inl +406 -0
  190. package/native/third_party/JoltPhysics/Jolt/Math/Real.h +44 -0
  191. package/native/third_party/JoltPhysics/Jolt/Math/Swizzle.h +19 -0
  192. package/native/third_party/JoltPhysics/Jolt/Math/Trigonometry.h +79 -0
  193. package/native/third_party/JoltPhysics/Jolt/Math/UVec4.h +232 -0
  194. package/native/third_party/JoltPhysics/Jolt/Math/UVec4.inl +636 -0
  195. package/native/third_party/JoltPhysics/Jolt/Math/Vec3.cpp +71 -0
  196. package/native/third_party/JoltPhysics/Jolt/Math/Vec3.h +308 -0
  197. package/native/third_party/JoltPhysics/Jolt/Math/Vec3.inl +942 -0
  198. package/native/third_party/JoltPhysics/Jolt/Math/Vec4.h +320 -0
  199. package/native/third_party/JoltPhysics/Jolt/Math/Vec4.inl +1152 -0
  200. package/native/third_party/JoltPhysics/Jolt/Math/Vector.h +211 -0
  201. package/native/third_party/JoltPhysics/Jolt/ObjectStream/GetPrimitiveTypeOfType.h +54 -0
  202. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStream.cpp +38 -0
  203. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStream.h +337 -0
  204. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryIn.cpp +252 -0
  205. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryIn.h +57 -0
  206. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryOut.cpp +165 -0
  207. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryOut.h +57 -0
  208. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamIn.cpp +635 -0
  209. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamIn.h +148 -0
  210. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamOut.cpp +166 -0
  211. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamOut.h +101 -0
  212. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextIn.cpp +418 -0
  213. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextIn.h +55 -0
  214. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextOut.cpp +255 -0
  215. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextOut.h +62 -0
  216. package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTypes.h +26 -0
  217. package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableAttribute.h +111 -0
  218. package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableAttributeEnum.h +67 -0
  219. package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableAttributeTyped.h +60 -0
  220. package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableObject.cpp +15 -0
  221. package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableObject.h +170 -0
  222. package/native/third_party/JoltPhysics/Jolt/ObjectStream/TypeDeclarations.cpp +70 -0
  223. package/native/third_party/JoltPhysics/Jolt/ObjectStream/TypeDeclarations.h +45 -0
  224. package/native/third_party/JoltPhysics/Jolt/Physics/Body/AllowedDOFs.h +68 -0
  225. package/native/third_party/JoltPhysics/Jolt/Physics/Body/Body.cpp +426 -0
  226. package/native/third_party/JoltPhysics/Jolt/Physics/Body/Body.h +452 -0
  227. package/native/third_party/JoltPhysics/Jolt/Physics/Body/Body.inl +197 -0
  228. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyAccess.h +68 -0
  229. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyActivationListener.h +28 -0
  230. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyCreationSettings.cpp +234 -0
  231. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyCreationSettings.h +124 -0
  232. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyFilter.h +130 -0
  233. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyID.h +101 -0
  234. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyInterface.cpp +1099 -0
  235. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyInterface.h +324 -0
  236. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyLock.h +111 -0
  237. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyLockInterface.h +134 -0
  238. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyLockMulti.h +120 -0
  239. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyManager.cpp +1220 -0
  240. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyManager.h +403 -0
  241. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyPair.h +36 -0
  242. package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyType.h +19 -0
  243. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MassProperties.cpp +185 -0
  244. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MassProperties.h +58 -0
  245. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionProperties.cpp +92 -0
  246. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionProperties.h +308 -0
  247. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionProperties.inl +178 -0
  248. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionQuality.h +31 -0
  249. package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionType.h +17 -0
  250. package/native/third_party/JoltPhysics/Jolt/Physics/Character/Character.cpp +354 -0
  251. package/native/third_party/JoltPhysics/Jolt/Physics/Character/Character.h +159 -0
  252. package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterBase.cpp +59 -0
  253. package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterBase.h +157 -0
  254. package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterID.h +98 -0
  255. package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterVirtual.cpp +1933 -0
  256. package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterVirtual.h +752 -0
  257. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/AABoxCast.h +20 -0
  258. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ActiveEdgeMode.h +17 -0
  259. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ActiveEdges.h +114 -0
  260. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BackFaceMode.h +16 -0
  261. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhase.cpp +16 -0
  262. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhase.h +109 -0
  263. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.cpp +313 -0
  264. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.h +38 -0
  265. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h +148 -0
  266. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayerInterfaceMask.h +92 -0
  267. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayerInterfaceTable.h +64 -0
  268. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.cpp +629 -0
  269. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.h +108 -0
  270. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuery.h +56 -0
  271. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/ObjectVsBroadPhaseLayerFilterMask.h +35 -0
  272. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/ObjectVsBroadPhaseLayerFilterTable.h +66 -0
  273. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/QuadTree.cpp +1768 -0
  274. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/QuadTree.h +389 -0
  275. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastConvexVsTriangles.cpp +107 -0
  276. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastConvexVsTriangles.h +46 -0
  277. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastResult.h +37 -0
  278. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastSphereVsTriangles.cpp +223 -0
  279. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastSphereVsTriangles.h +49 -0
  280. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollectFacesMode.h +16 -0
  281. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideConvexVsTriangles.cpp +155 -0
  282. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideConvexVsTriangles.h +56 -0
  283. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollidePointResult.h +25 -0
  284. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideShape.h +106 -0
  285. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideShapeVsShapePerLeaf.h +94 -0
  286. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSoftBodyVertexIterator.h +110 -0
  287. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSoftBodyVerticesVsTriangles.h +102 -0
  288. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSphereVsTriangles.cpp +121 -0
  289. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSphereVsTriangles.h +50 -0
  290. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionCollector.h +109 -0
  291. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionCollectorImpl.h +219 -0
  292. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionDispatch.cpp +107 -0
  293. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionDispatch.h +97 -0
  294. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionGroup.cpp +35 -0
  295. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionGroup.h +97 -0
  296. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ContactListener.h +143 -0
  297. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/EstimateCollisionResponse.cpp +213 -0
  298. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/EstimateCollisionResponse.h +48 -0
  299. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilter.cpp +32 -0
  300. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilter.h +46 -0
  301. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilterTable.cpp +38 -0
  302. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilterTable.h +130 -0
  303. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/InternalEdgeRemovingCollector.h +279 -0
  304. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ManifoldBetweenTwoFaces.cpp +271 -0
  305. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ManifoldBetweenTwoFaces.h +44 -0
  306. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp +448 -0
  307. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseQuery.h +77 -0
  308. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseStats.cpp +62 -0
  309. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseStats.h +110 -0
  310. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ObjectLayer.h +111 -0
  311. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ObjectLayerPairFilterMask.h +52 -0
  312. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ObjectLayerPairFilterTable.h +78 -0
  313. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterial.cpp +35 -0
  314. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterial.h +57 -0
  315. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterialSimple.cpp +38 -0
  316. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterialSimple.h +37 -0
  317. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/RayCast.h +87 -0
  318. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/BoxShape.cpp +318 -0
  319. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/BoxShape.h +115 -0
  320. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CapsuleShape.cpp +438 -0
  321. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CapsuleShape.h +129 -0
  322. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CompoundShape.cpp +433 -0
  323. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CompoundShape.h +354 -0
  324. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h +461 -0
  325. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexHullShape.cpp +1311 -0
  326. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexHullShape.h +202 -0
  327. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexShape.cpp +566 -0
  328. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexShape.h +150 -0
  329. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CylinderShape.cpp +418 -0
  330. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CylinderShape.h +126 -0
  331. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/DecoratedShape.cpp +87 -0
  332. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/DecoratedShape.h +80 -0
  333. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/EmptyShape.cpp +64 -0
  334. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/EmptyShape.h +75 -0
  335. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/GetTrianglesContext.h +248 -0
  336. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/HeightFieldShape.cpp +2754 -0
  337. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/HeightFieldShape.h +380 -0
  338. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MeshShape.cpp +1305 -0
  339. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MeshShape.h +228 -0
  340. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp +596 -0
  341. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MutableCompoundShape.h +176 -0
  342. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.cpp +217 -0
  343. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h +140 -0
  344. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/PlaneShape.cpp +541 -0
  345. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/PlaneShape.h +147 -0
  346. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/PolyhedronSubmergedVolumeCalculator.h +319 -0
  347. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.cpp +333 -0
  348. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h +161 -0
  349. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ScaleHelpers.h +83 -0
  350. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ScaledShape.cpp +238 -0
  351. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ScaledShape.h +145 -0
  352. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/Shape.cpp +325 -0
  353. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/Shape.h +466 -0
  354. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SphereShape.cpp +347 -0
  355. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SphereShape.h +125 -0
  356. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/StaticCompoundShape.cpp +674 -0
  357. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/StaticCompoundShape.h +139 -0
  358. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SubShapeID.h +138 -0
  359. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SubShapeIDPair.h +65 -0
  360. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.cpp +453 -0
  361. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.gliffy +1 -0
  362. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h +135 -0
  363. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCylinderShape.cpp +691 -0
  364. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCylinderShape.h +132 -0
  365. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TriangleShape.cpp +430 -0
  366. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TriangleShape.h +143 -0
  367. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ShapeCast.h +173 -0
  368. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ShapeFilter.h +73 -0
  369. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/SimShapeFilter.h +40 -0
  370. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/SimShapeFilterWrapper.h +58 -0
  371. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/SortReverseAndStore.h +48 -0
  372. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/TransformedShape.cpp +180 -0
  373. package/native/third_party/JoltPhysics/Jolt/Physics/Collision/TransformedShape.h +194 -0
  374. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/CalculateSolverSteps.h +70 -0
  375. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConeConstraint.cpp +246 -0
  376. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConeConstraint.h +133 -0
  377. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/Constraint.cpp +73 -0
  378. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/Constraint.h +243 -0
  379. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintManager.cpp +289 -0
  380. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintManager.h +100 -0
  381. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/AngleConstraintPart.h +257 -0
  382. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/AxisConstraintPart.h +682 -0
  383. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/DualAxisConstraintPart.h +276 -0
  384. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/GearConstraintPart.h +195 -0
  385. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/HingeRotationConstraintPart.h +222 -0
  386. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/IndependentAxisConstraintPart.h +246 -0
  387. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h +239 -0
  388. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/RackAndPinionConstraintPart.h +196 -0
  389. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h +283 -0
  390. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/RotationQuatConstraintPart.h +246 -0
  391. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/SpringPart.h +169 -0
  392. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/SwingTwistConstraintPart.h +597 -0
  393. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ContactConstraintManager.cpp +1804 -0
  394. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ContactConstraintManager.h +524 -0
  395. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/DistanceConstraint.cpp +266 -0
  396. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/DistanceConstraint.h +120 -0
  397. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/FixedConstraint.cpp +215 -0
  398. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/FixedConstraint.h +96 -0
  399. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/GearConstraint.cpp +188 -0
  400. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/GearConstraint.h +116 -0
  401. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/HingeConstraint.cpp +443 -0
  402. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/HingeConstraint.h +205 -0
  403. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/MotorSettings.cpp +43 -0
  404. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/MotorSettings.h +66 -0
  405. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraint.cpp +458 -0
  406. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraint.h +191 -0
  407. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPath.cpp +85 -0
  408. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPath.h +76 -0
  409. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPathHermite.cpp +308 -0
  410. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPathHermite.h +54 -0
  411. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PointConstraint.cpp +157 -0
  412. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PointConstraint.h +94 -0
  413. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PulleyConstraint.cpp +253 -0
  414. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PulleyConstraint.h +137 -0
  415. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/RackAndPinionConstraint.cpp +189 -0
  416. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/RackAndPinionConstraint.h +118 -0
  417. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SixDOFConstraint.cpp +900 -0
  418. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SixDOFConstraint.h +289 -0
  419. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SliderConstraint.cpp +501 -0
  420. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SliderConstraint.h +198 -0
  421. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SpringSettings.cpp +35 -0
  422. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SpringSettings.h +70 -0
  423. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SwingTwistConstraint.cpp +524 -0
  424. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SwingTwistConstraint.h +197 -0
  425. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/TwoBodyConstraint.cpp +56 -0
  426. package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/TwoBodyConstraint.h +65 -0
  427. package/native/third_party/JoltPhysics/Jolt/Physics/DeterminismLog.cpp +17 -0
  428. package/native/third_party/JoltPhysics/Jolt/Physics/DeterminismLog.h +159 -0
  429. package/native/third_party/JoltPhysics/Jolt/Physics/EActivation.h +16 -0
  430. package/native/third_party/JoltPhysics/Jolt/Physics/EPhysicsUpdateError.h +37 -0
  431. package/native/third_party/JoltPhysics/Jolt/Physics/IslandBuilder.cpp +492 -0
  432. package/native/third_party/JoltPhysics/Jolt/Physics/IslandBuilder.h +144 -0
  433. package/native/third_party/JoltPhysics/Jolt/Physics/LargeIslandSplitter.cpp +582 -0
  434. package/native/third_party/JoltPhysics/Jolt/Physics/LargeIslandSplitter.h +187 -0
  435. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsLock.h +169 -0
  436. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsScene.cpp +261 -0
  437. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsScene.h +104 -0
  438. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsSettings.h +125 -0
  439. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsStepListener.h +37 -0
  440. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsSystem.cpp +2915 -0
  441. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsSystem.h +391 -0
  442. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsUpdateContext.cpp +25 -0
  443. package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsUpdateContext.h +176 -0
  444. package/native/third_party/JoltPhysics/Jolt/Physics/Ragdoll/Ragdoll.cpp +744 -0
  445. package/native/third_party/JoltPhysics/Jolt/Physics/Ragdoll/Ragdoll.h +245 -0
  446. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyContactListener.h +55 -0
  447. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyCreationSettings.cpp +128 -0
  448. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyCreationSettings.h +75 -0
  449. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyManifold.h +74 -0
  450. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp +1501 -0
  451. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h +333 -0
  452. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyShape.cpp +354 -0
  453. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyShape.h +73 -0
  454. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp +1487 -0
  455. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodySharedSettings.h +390 -0
  456. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyUpdateContext.h +63 -0
  457. package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyVertex.h +36 -0
  458. package/native/third_party/JoltPhysics/Jolt/Physics/StateRecorder.h +136 -0
  459. package/native/third_party/JoltPhysics/Jolt/Physics/StateRecorderImpl.cpp +90 -0
  460. package/native/third_party/JoltPhysics/Jolt/Physics/StateRecorderImpl.h +50 -0
  461. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/MotorcycleController.cpp +306 -0
  462. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/MotorcycleController.h +119 -0
  463. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/TrackedVehicleController.cpp +547 -0
  464. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/TrackedVehicleController.h +169 -0
  465. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleAntiRollBar.cpp +33 -0
  466. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleAntiRollBar.h +33 -0
  467. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleCollisionTester.cpp +376 -0
  468. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleCollisionTester.h +146 -0
  469. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleConstraint.cpp +703 -0
  470. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleConstraint.h +252 -0
  471. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleController.cpp +17 -0
  472. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleController.h +87 -0
  473. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleDifferential.cpp +81 -0
  474. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleDifferential.h +39 -0
  475. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleEngine.cpp +122 -0
  476. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleEngine.h +93 -0
  477. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTrack.cpp +52 -0
  478. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTrack.h +56 -0
  479. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTransmission.cpp +159 -0
  480. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTransmission.h +87 -0
  481. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/Wheel.cpp +93 -0
  482. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/Wheel.h +148 -0
  483. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/WheeledVehicleController.cpp +866 -0
  484. package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/WheeledVehicleController.h +205 -0
  485. package/native/third_party/JoltPhysics/Jolt/RegisterTypes.cpp +204 -0
  486. package/native/third_party/JoltPhysics/Jolt/RegisterTypes.h +29 -0
  487. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRenderer.cpp +1107 -0
  488. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRenderer.h +383 -0
  489. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererPlayback.cpp +168 -0
  490. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererPlayback.h +48 -0
  491. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererRecorder.cpp +158 -0
  492. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererRecorder.h +130 -0
  493. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererSimple.cpp +80 -0
  494. package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererSimple.h +88 -0
  495. package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletalAnimation.cpp +165 -0
  496. package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletalAnimation.h +91 -0
  497. package/native/third_party/JoltPhysics/Jolt/Skeleton/Skeleton.cpp +82 -0
  498. package/native/third_party/JoltPhysics/Jolt/Skeleton/Skeleton.h +72 -0
  499. package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonMapper.cpp +237 -0
  500. package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonMapper.h +145 -0
  501. package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonPose.cpp +87 -0
  502. package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonPose.h +82 -0
  503. package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitter.cpp +73 -0
  504. package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitter.h +84 -0
  505. package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterBinning.cpp +139 -0
  506. package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterBinning.h +52 -0
  507. package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterMean.cpp +43 -0
  508. package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterMean.h +28 -0
  509. package/native/third_party/JoltPhysics/LICENSE +7 -0
  510. package/native/third_party/JoltPhysics/README.md +173 -0
  511. package/native/third_party/bloom_jolt/CMakeLists.txt +78 -0
  512. package/native/third_party/bloom_jolt/include/bloom_jolt.h +519 -0
  513. package/native/third_party/bloom_jolt/src/bloom_jolt.cpp +1780 -0
  514. package/native/tvos/Cargo.lock +1692 -0
  515. package/native/tvos/Cargo.toml +22 -0
  516. package/native/tvos/src/lib.rs +3179 -0
  517. package/native/watchos/Cargo.lock +16 -0
  518. package/native/watchos/Cargo.toml +19 -0
  519. package/native/watchos/shaders/bloom_postfx.metal +99 -0
  520. package/native/watchos/src/BloomWatchApp.swift +1236 -0
  521. package/native/watchos/src/BloomWatchAudio.swift +179 -0
  522. package/native/watchos/src/audio.rs +55 -0
  523. package/native/watchos/src/draw_list.rs +223 -0
  524. package/native/watchos/src/ffi_stubs.rs +454 -0
  525. package/native/watchos/src/lib.rs +1013 -0
  526. package/native/watchos/src/models.rs +746 -0
  527. package/native/watchos/src/postfx.rs +91 -0
  528. package/native/watchos/src/scene.rs +534 -0
  529. package/native/watchos/src/textures.rs +184 -0
  530. package/native/web/Cargo.lock +1656 -0
  531. package/native/web/Cargo.toml +38 -0
  532. package/native/web/bloom_glue.js +218 -0
  533. package/native/web/build.sh +101 -0
  534. package/native/web/index.html +390 -0
  535. package/native/web/jolt_bridge.js +1311 -0
  536. package/native/web/src/lib.rs +2739 -0
  537. package/native/windows/Cargo.lock +1813 -0
  538. package/native/windows/Cargo.toml +31 -0
  539. package/native/windows/src/lib.rs +1933 -0
  540. package/package.json +558 -0
  541. package/src/audio/index.ts +151 -0
  542. package/src/core/colors.ts +56 -0
  543. package/src/core/index.ts +903 -0
  544. package/src/core/keys.ts +63 -0
  545. package/src/core/types.ts +102 -0
  546. package/src/index.ts +158 -0
  547. package/src/math/index.ts +502 -0
  548. package/src/mobile/index.ts +294 -0
  549. package/src/models/index.ts +859 -0
  550. package/src/physics/index.ts +1072 -0
  551. package/src/scene/index.ts +570 -0
  552. package/src/shapes/index.ts +120 -0
  553. package/src/text/index.ts +48 -0
  554. package/src/textures/index.ts +173 -0
  555. package/src/world/index.ts +22 -0
  556. package/src/world/loader.ts +385 -0
  557. package/src/world/prefab.ts +205 -0
  558. package/src/world/saver.ts +61 -0
  559. package/src/world/terrain.ts +254 -0
  560. package/src/world/types.ts +136 -0
  561. package/src/world/validate.ts +202 -0
  562. package/src/world/version.ts +47 -0
@@ -0,0 +1,1933 @@
1
+ use bloom_shared::engine::EngineState;
2
+ use bloom_shared::renderer::Renderer;
3
+ use bloom_shared::string_header::str_from_header;
4
+ use bloom_shared::audio::{parse_wav, parse_ogg, parse_mp3};
5
+
6
+ use std::sync::OnceLock;
7
+
8
+ static mut ENGINE: OnceLock<EngineState> = OnceLock::new();
9
+
10
+ fn engine() -> &'static mut EngineState {
11
+ unsafe { ENGINE.get_mut().expect("Engine not initialized") }
12
+ }
13
+
14
+ /// Map Win32 virtual key code to Bloom key code.
15
+ fn map_keycode(vk: u32) -> usize {
16
+ match vk {
17
+ 0x41..=0x5A => vk as usize, // A-Z map directly (65-90)
18
+ 0x30..=0x39 => vk as usize, // 0-9 map directly (48-57)
19
+ 0x70..=0x7B => (vk - 0x70 + 112) as usize, // F1-F12
20
+ 0x26 => 256, // VK_UP
21
+ 0x28 => 257, // VK_DOWN
22
+ 0x25 => 258, // VK_LEFT
23
+ 0x27 => 259, // VK_RIGHT
24
+ 0x20 => 32, // VK_SPACE
25
+ 0x0D => 265, // VK_RETURN → Bloom ENTER
26
+ 0x1B => 27, // VK_ESCAPE
27
+ 0x09 => 9, // VK_TAB
28
+ 0x08 => 8, // VK_BACK
29
+ 0x2E => 127, // VK_DELETE
30
+ 0x2D => 260, // VK_INSERT
31
+ 0x24 => 261, // VK_HOME
32
+ 0x23 => 262, // VK_END
33
+ 0x21 => 263, // VK_PRIOR (Page Up)
34
+ 0x22 => 264, // VK_NEXT (Page Down)
35
+ 0xA0 => 280, // VK_LSHIFT
36
+ 0xA1 => 281, // VK_RSHIFT
37
+ 0xA2 => 282, // VK_LCONTROL
38
+ 0xA3 => 283, // VK_RCONTROL
39
+ 0xA4 => 284, // VK_LMENU (Left Alt)
40
+ 0xA5 => 285, // VK_RMENU (Right Alt)
41
+ 0x5B => 286, // VK_LWIN
42
+ 0x5C => 287, // VK_RWIN
43
+ _ => 0,
44
+ }
45
+ }
46
+
47
+ // Win32 windowing implementation
48
+ #[cfg(windows)]
49
+ mod win32 {
50
+ use super::*;
51
+ use windows::Win32::UI::WindowsAndMessaging::*;
52
+ use windows::Win32::UI::HiDpi::*;
53
+ use windows::Win32::Foundation::*;
54
+ use windows::Win32::System::LibraryLoader::GetModuleHandleW;
55
+ use windows::Win32::Graphics::Gdi::*;
56
+ use windows::core::*;
57
+ use raw_window_handle::{RawWindowHandle, Win32WindowHandle, RawDisplayHandle, WindowsDisplayHandle};
58
+
59
+ static mut HWND_GLOBAL: Option<HWND> = None;
60
+ static mut IS_FULLSCREEN: bool = false;
61
+ static mut WINDOWED_STYLE: u32 = 0;
62
+ static mut WINDOWED_RECT: RECT = RECT { left: 0, top: 0, right: 0, bottom: 0 };
63
+
64
+ pub fn set_fullscreen(fullscreen: bool) {
65
+ unsafe {
66
+ let Some(hwnd) = HWND_GLOBAL else { return };
67
+
68
+ if fullscreen && !IS_FULLSCREEN {
69
+ // Save current style and window rect for restore
70
+ WINDOWED_STYLE = GetWindowLongW(hwnd, GWL_STYLE) as u32;
71
+ let _ = GetWindowRect(hwnd, &mut WINDOWED_RECT);
72
+
73
+ // Get monitor dimensions
74
+ let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
75
+ let mut mi: MONITORINFO = std::mem::zeroed();
76
+ mi.cbSize = std::mem::size_of::<MONITORINFO>() as u32;
77
+ let _ = GetMonitorInfoW(monitor, &mut mi);
78
+
79
+ // Set borderless fullscreen
80
+ SetWindowLongW(hwnd, GWL_STYLE, (WS_POPUP | WS_VISIBLE).0 as i32);
81
+ let _ = SetWindowPos(
82
+ hwnd, HWND_TOP,
83
+ mi.rcMonitor.left, mi.rcMonitor.top,
84
+ mi.rcMonitor.right - mi.rcMonitor.left,
85
+ mi.rcMonitor.bottom - mi.rcMonitor.top,
86
+ SWP_FRAMECHANGED | SWP_NOOWNERZORDER,
87
+ );
88
+ IS_FULLSCREEN = true;
89
+ } else if !fullscreen && IS_FULLSCREEN {
90
+ // Restore windowed mode
91
+ SetWindowLongW(hwnd, GWL_STYLE, WINDOWED_STYLE as i32);
92
+ let _ = SetWindowPos(
93
+ hwnd, None,
94
+ WINDOWED_RECT.left, WINDOWED_RECT.top,
95
+ WINDOWED_RECT.right - WINDOWED_RECT.left,
96
+ WINDOWED_RECT.bottom - WINDOWED_RECT.top,
97
+ SWP_FRAMECHANGED | SWP_NOOWNERZORDER | SWP_NOZORDER,
98
+ );
99
+ IS_FULLSCREEN = false;
100
+ }
101
+ }
102
+ }
103
+
104
+ pub fn toggle_fullscreen() {
105
+ unsafe { set_fullscreen(!IS_FULLSCREEN); }
106
+ }
107
+
108
+ unsafe extern "system" fn wndproc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
109
+ match msg {
110
+ WM_DESTROY => {
111
+ PostQuitMessage(0);
112
+ if let Some(eng) = ENGINE.get_mut() {
113
+ eng.should_close = true;
114
+ }
115
+ LRESULT(0)
116
+ }
117
+ WM_KEYDOWN => {
118
+ let bloom_key = map_keycode(wparam.0 as u32);
119
+ if bloom_key > 0 {
120
+ if let Some(eng) = ENGINE.get_mut() {
121
+ eng.input.set_key_down(bloom_key);
122
+ }
123
+ }
124
+ DefWindowProcW(hwnd, msg, wparam, lparam)
125
+ }
126
+ WM_KEYUP => {
127
+ let bloom_key = map_keycode(wparam.0 as u32);
128
+ if bloom_key > 0 {
129
+ if let Some(eng) = ENGINE.get_mut() {
130
+ eng.input.set_key_up(bloom_key);
131
+ }
132
+ }
133
+ DefWindowProcW(hwnd, msg, wparam, lparam)
134
+ }
135
+ WM_MOUSEMOVE => {
136
+ let x = (lparam.0 & 0xFFFF) as i16 as f64;
137
+ let y = ((lparam.0 >> 16) & 0xFFFF) as i16 as f64;
138
+ if let Some(eng) = ENGINE.get_mut() {
139
+ eng.input.set_mouse_position(x, y);
140
+ }
141
+ DefWindowProcW(hwnd, msg, wparam, lparam)
142
+ }
143
+ WM_LBUTTONDOWN => {
144
+ if let Some(eng) = ENGINE.get_mut() {
145
+ eng.input.set_mouse_button_down(0);
146
+ }
147
+ DefWindowProcW(hwnd, msg, wparam, lparam)
148
+ }
149
+ WM_LBUTTONUP => {
150
+ if let Some(eng) = ENGINE.get_mut() {
151
+ eng.input.set_mouse_button_up(0);
152
+ }
153
+ DefWindowProcW(hwnd, msg, wparam, lparam)
154
+ }
155
+ WM_RBUTTONDOWN => {
156
+ if let Some(eng) = ENGINE.get_mut() {
157
+ eng.input.set_mouse_button_down(1);
158
+ }
159
+ DefWindowProcW(hwnd, msg, wparam, lparam)
160
+ }
161
+ WM_RBUTTONUP => {
162
+ if let Some(eng) = ENGINE.get_mut() {
163
+ eng.input.set_mouse_button_up(1);
164
+ }
165
+ DefWindowProcW(hwnd, msg, wparam, lparam)
166
+ }
167
+ 0x0005 /* WM_SIZE */ => {
168
+ // lParam carries the new client-area size in *physical*
169
+ // pixels (Per-Monitor-Aware-V2). Derive logical via
170
+ // current DPI so the rest of the engine sees the same
171
+ // logical/physical split macOS does.
172
+ let phys_w = (lparam.0 & 0xFFFF) as u32;
173
+ let phys_h = ((lparam.0 >> 16) & 0xFFFF) as u32;
174
+ if phys_w > 0 && phys_h > 0 {
175
+ if let Some(eng) = ENGINE.get_mut() {
176
+ if phys_w != eng.renderer.physical_width()
177
+ || phys_h != eng.renderer.physical_height()
178
+ {
179
+ let scale = dpi_scale(hwnd);
180
+ let log_w = ((phys_w as f64) / scale).round() as u32;
181
+ let log_h = ((phys_h as f64) / scale).round() as u32;
182
+ eng.renderer.resize(phys_w, phys_h, log_w, log_h);
183
+ }
184
+ }
185
+ }
186
+ DefWindowProcW(hwnd, msg, wparam, lparam)
187
+ }
188
+ 0x02E0 /* WM_DPICHANGED */ => {
189
+ // The window dragged onto a different-DPI monitor.
190
+ // lParam holds a suggested RECT — Windows wants us to
191
+ // accept this geometry to keep the window's apparent
192
+ // size constant across the DPI change. The follow-up
193
+ // WM_SIZE handles the renderer resize.
194
+ let suggested = &*(lparam.0 as *const RECT);
195
+ let _ = SetWindowPos(
196
+ hwnd, None,
197
+ suggested.left, suggested.top,
198
+ suggested.right - suggested.left,
199
+ suggested.bottom - suggested.top,
200
+ SWP_NOZORDER | SWP_NOACTIVATE,
201
+ );
202
+ LRESULT(0)
203
+ }
204
+ _ => DefWindowProcW(hwnd, msg, wparam, lparam),
205
+ }
206
+ }
207
+
208
+ /// Returns (hwnd, physical_w, physical_h). Caller's `width`/`height`
209
+ /// are *logical* — on a HiDPI monitor with scale 2.0 the window
210
+ /// will appear logically the right size while its client area is
211
+ /// scaled-up physical pixels for the renderer to fill.
212
+ pub fn create_window(width: f64, height: f64, title: &str) -> (HWND, u32, u32) {
213
+ unsafe {
214
+ // Per-Monitor-Aware-V2: the window's DPI tracks the monitor
215
+ // it's currently on, and Windows fires WM_DPICHANGED when
216
+ // it moves between monitors of different DPI. Without this
217
+ // call, Win32 silently virtualises us to 96 DPI on HiDPI
218
+ // displays — a 4K monitor would render at ~2560×1440.
219
+ // Safe to call early; ignored on pre-Win10 1703.
220
+ let _ = SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
221
+
222
+ let hmodule = GetModuleHandleW(None).unwrap();
223
+ let hinstance: HINSTANCE = hmodule.into();
224
+ let class_name = w!("BloomWindowClass");
225
+
226
+ let wc = WNDCLASSEXW {
227
+ cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
228
+ style: CS_HREDRAW | CS_VREDRAW,
229
+ lpfnWndProc: Some(wndproc),
230
+ hInstance: hinstance,
231
+ lpszClassName: class_name,
232
+ hCursor: LoadCursorW(None, IDC_ARROW).unwrap(),
233
+ ..Default::default()
234
+ };
235
+ RegisterClassExW(&wc);
236
+
237
+ let title_wide: Vec<u16> = title.encode_utf16().chain(std::iter::once(0)).collect();
238
+
239
+ // Initial window size in physical pixels. We don't have a
240
+ // window handle yet, so use the system DPI — close enough,
241
+ // and WM_DPICHANGED will resize on the first move if the
242
+ // user lands on a different-DPI monitor.
243
+ let system_dpi = GetDpiForSystem().max(96);
244
+ let scale = system_dpi as f64 / 96.0;
245
+ let phys_w = (width * scale).round() as i32;
246
+ let phys_h = (height * scale).round() as i32;
247
+
248
+ let hwnd = CreateWindowExW(
249
+ WINDOW_EX_STYLE::default(),
250
+ class_name,
251
+ PCWSTR(title_wide.as_ptr()),
252
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
253
+ CW_USEDEFAULT, CW_USEDEFAULT,
254
+ phys_w, phys_h,
255
+ None, None, Some(&hinstance), None,
256
+ ).unwrap();
257
+
258
+ ShowWindow(hwnd, SW_SHOW);
259
+ HWND_GLOBAL = Some(hwnd);
260
+
261
+ // After the window exists, query the actual client-area
262
+ // size. Includes whatever DWM trimmed for borders and
263
+ // reflects this monitor's DPI rather than the system one.
264
+ let mut rect = RECT::default();
265
+ let _ = GetClientRect(hwnd, &mut rect);
266
+ let actual_w = (rect.right - rect.left).max(1) as u32;
267
+ let actual_h = (rect.bottom - rect.top).max(1) as u32;
268
+ (hwnd, actual_w, actual_h)
269
+ }
270
+ }
271
+
272
+ /// Current per-monitor DPI scale for this window (1.0 on a 96-DPI
273
+ /// monitor, 2.0 on a Retina-class 192-DPI monitor, etc.). Falls
274
+ /// back to 1.0 if the API is missing (pre-Win10 1607).
275
+ pub fn dpi_scale(hwnd: HWND) -> f64 {
276
+ unsafe {
277
+ let dpi = GetDpiForWindow(hwnd);
278
+ if dpi == 0 { 1.0 } else { dpi as f64 / 96.0 }
279
+ }
280
+ }
281
+
282
+ pub fn poll_events() {
283
+ unsafe {
284
+ let mut msg = MSG::default();
285
+ while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).into() {
286
+ TranslateMessage(&msg);
287
+ DispatchMessageW(&msg);
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ #[no_mangle]
294
+ pub extern "C" fn bloom_init_window(width: f64, height: f64, title_ptr: *const u8, fullscreen: f64) {
295
+ let title = str_from_header(title_ptr);
296
+
297
+ #[cfg(windows)]
298
+ {
299
+ let (hwnd, phys_w, phys_h) = win32::create_window(width, height, title);
300
+
301
+ let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
302
+ backends: wgpu::Backends::DX12 | wgpu::Backends::VULKAN,
303
+ ..wgpu::InstanceDescriptor::new_without_display_handle()
304
+ });
305
+
306
+ let surface = unsafe {
307
+ let mut handle = raw_window_handle::Win32WindowHandle::new(
308
+ std::num::NonZeroIsize::new(hwnd.0 as isize).unwrap()
309
+ );
310
+ let raw = raw_window_handle::RawWindowHandle::Win32(handle);
311
+ instance.create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle {
312
+ raw_display_handle: Some(raw_window_handle::RawDisplayHandle::Windows(
313
+ raw_window_handle::WindowsDisplayHandle::new()
314
+ )),
315
+ raw_window_handle: raw,
316
+ }).expect("Failed to create surface")
317
+ };
318
+
319
+ let adapter = pollster_block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
320
+ compatible_surface: Some(&surface),
321
+ power_preference: wgpu::PowerPreference::HighPerformance,
322
+ ..Default::default()
323
+ })).expect("No adapter found");
324
+
325
+ // Ticket 007b: HW ray-query via DXR 1.1 / VK_KHR_ray_query.
326
+ let supported = adapter.features();
327
+ let force_sw_gi = std::env::var("BLOOM_FORCE_SW_GI")
328
+ .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
329
+ .unwrap_or(false);
330
+ let rt_mask = wgpu::Features::EXPERIMENTAL_RAY_QUERY;
331
+ let mut required_features = wgpu::Features::empty();
332
+ // Ticket 011: request TIMESTAMP_QUERY when supported so the profiler
333
+ // can record GPU timings. Optional — profiler falls back to CPU-only
334
+ // when the adapter doesn't grant it.
335
+ if supported.contains(wgpu::Features::TIMESTAMP_QUERY) {
336
+ required_features |= wgpu::Features::TIMESTAMP_QUERY;
337
+ }
338
+ if !force_sw_gi && supported.contains(rt_mask) {
339
+ required_features |= rt_mask;
340
+ }
341
+ let experimental_features = if required_features.intersects(rt_mask) {
342
+ unsafe { wgpu::ExperimentalFeatures::enabled() }
343
+ } else {
344
+ wgpu::ExperimentalFeatures::disabled()
345
+ };
346
+ let mut required_limits = wgpu::Limits::default();
347
+ if required_features.intersects(rt_mask) {
348
+ required_limits = required_limits
349
+ .using_minimum_supported_acceleration_structure_values();
350
+ }
351
+ let (device, queue) = pollster_block_on(adapter.request_device(
352
+ &wgpu::DeviceDescriptor {
353
+ label: Some("bloom_device"),
354
+ required_features,
355
+ required_limits,
356
+ experimental_features,
357
+ ..Default::default()
358
+ },
359
+ )).expect("Failed to create device");
360
+
361
+ let surface_caps = surface.get_capabilities(&adapter);
362
+ let format = surface_caps.formats[0];
363
+ // Surface is configured at the *physical* client-area size we
364
+ // got back from create_window; Renderer::new takes the
365
+ // caller's logical size separately so screenWidth() etc. keep
366
+ // returning DPI-independent numbers.
367
+ let surface_config = wgpu::SurfaceConfiguration {
368
+ usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
369
+ format,
370
+ width: phys_w,
371
+ height: phys_h,
372
+ present_mode: wgpu::PresentMode::Fifo,
373
+ alpha_mode: surface_caps.alpha_modes[0],
374
+ view_formats: vec![],
375
+ desired_maximum_frame_latency: 2,
376
+ };
377
+ surface.configure(&device, &surface_config);
378
+
379
+ let renderer = Renderer::new(device, queue, surface, surface_config, width as u32, height as u32);
380
+ unsafe { let _ = ENGINE.set(EngineState::new(renderer)); }
381
+
382
+ if fullscreen != 0.0 {
383
+ win32::set_fullscreen(true);
384
+ }
385
+ }
386
+
387
+ #[cfg(not(windows))]
388
+ {
389
+ panic!("bloom-windows can only run on Windows");
390
+ }
391
+ }
392
+
393
+ #[no_mangle]
394
+ pub extern "C" fn bloom_close_window() {}
395
+
396
+ #[no_mangle]
397
+ pub extern "C" fn bloom_window_should_close() -> f64 {
398
+ if engine().should_close { 1.0 } else { 0.0 }
399
+ }
400
+
401
+ #[cfg(windows)]
402
+ fn poll_xinput_gamepad() {
403
+ use windows::Win32::UI::Input::XboxController::*;
404
+ let eng = engine();
405
+ let mut state = XINPUT_STATE::default();
406
+ let result = unsafe { XInputGetState(0, &mut state) };
407
+ if result == 0 {
408
+ // ERROR_SUCCESS
409
+ eng.input.gamepad_available = true;
410
+ let gp = &state.Gamepad;
411
+
412
+ // Axes: left stick X/Y, right stick X/Y, triggers
413
+ let normalize = |v: i16| -> f32 {
414
+ if v > 0 { v as f32 / 32767.0 } else { v as f32 / 32768.0 }
415
+ };
416
+ eng.input.set_gamepad_axis(0, normalize(gp.sThumbLX));
417
+ eng.input.set_gamepad_axis(1, -normalize(gp.sThumbLY)); // invert Y
418
+ eng.input.set_gamepad_axis(2, normalize(gp.sThumbRX));
419
+ eng.input.set_gamepad_axis(3, -normalize(gp.sThumbRY));
420
+ eng.input.set_gamepad_axis(4, gp.bLeftTrigger as f32 / 255.0);
421
+ eng.input.set_gamepad_axis(5, gp.bRightTrigger as f32 / 255.0);
422
+ eng.input.gamepad_axis_count = 6;
423
+
424
+ // Buttons
425
+ let buttons = gp.wButtons;
426
+ let mappings: &[(u16, usize)] = &[
427
+ (0x1000, 0), // A
428
+ (0x2000, 1), // B
429
+ (0x4000, 2), // X
430
+ (0x8000, 3), // Y
431
+ (0x0100, 4), // Left bumper
432
+ (0x0200, 5), // Right bumper
433
+ (0x0020, 6), // Back/Select
434
+ (0x0010, 7), // Start
435
+ (0x0040, 8), // Left stick press
436
+ (0x0080, 9), // Right stick press
437
+ (0x0001, 10), // DPad Up
438
+ (0x0002, 11), // DPad Down
439
+ (0x0004, 12), // DPad Left
440
+ (0x0008, 13), // DPad Right
441
+ ];
442
+ for &(mask, idx) in mappings {
443
+ if buttons.0 & mask != 0 {
444
+ eng.input.set_gamepad_button_down(idx);
445
+ } else {
446
+ eng.input.set_gamepad_button_up(idx);
447
+ }
448
+ }
449
+ } else {
450
+ eng.input.gamepad_available = false;
451
+ }
452
+ }
453
+
454
+ #[no_mangle]
455
+ pub extern "C" fn bloom_begin_drawing() {
456
+ #[cfg(windows)]
457
+ {
458
+ win32::poll_events();
459
+ poll_xinput_gamepad();
460
+ }
461
+ engine().begin_frame();
462
+ }
463
+
464
+ #[no_mangle]
465
+ pub extern "C" fn bloom_end_drawing() { engine().end_frame(); }
466
+
467
+ #[no_mangle]
468
+ pub extern "C" fn bloom_clear_background(r: f64, g: f64, b: f64, a: f64) {
469
+ engine().renderer.set_clear_color(r, g, b, a);
470
+ }
471
+
472
+ #[no_mangle]
473
+ pub extern "C" fn bloom_set_target_fps(fps: f64) { engine().target_fps = fps; }
474
+
475
+ #[no_mangle]
476
+ pub extern "C" fn bloom_set_direct_2d_mode(on: f64) { engine().direct_2d_mode = on > 0.5; }
477
+
478
+ #[no_mangle]
479
+ pub extern "C" fn bloom_get_delta_time() -> f64 { engine().delta_time }
480
+
481
+ #[no_mangle]
482
+ pub extern "C" fn bloom_get_fps() -> f64 { engine().get_fps() }
483
+
484
+ #[no_mangle]
485
+ pub extern "C" fn bloom_get_screen_width() -> f64 { engine().screen_width() }
486
+
487
+ #[no_mangle]
488
+ pub extern "C" fn bloom_get_screen_height() -> f64 { engine().screen_height() }
489
+
490
+ #[no_mangle]
491
+ pub extern "C" fn bloom_is_key_pressed(key: f64) -> f64 {
492
+ if engine().input.is_key_pressed(key as usize) { 1.0 } else { 0.0 }
493
+ }
494
+
495
+ #[no_mangle]
496
+ pub extern "C" fn bloom_is_key_down(key: f64) -> f64 {
497
+ if engine().input.is_key_down(key as usize) { 1.0 } else { 0.0 }
498
+ }
499
+
500
+ #[no_mangle]
501
+ pub extern "C" fn bloom_is_key_released(key: f64) -> f64 {
502
+ if engine().input.is_key_released(key as usize) { 1.0 } else { 0.0 }
503
+ }
504
+
505
+ #[no_mangle]
506
+ pub extern "C" fn bloom_get_mouse_x() -> f64 { engine().input.mouse_x }
507
+
508
+ #[no_mangle]
509
+ pub extern "C" fn bloom_get_mouse_y() -> f64 { engine().input.mouse_y }
510
+
511
+ #[no_mangle]
512
+ pub extern "C" fn bloom_is_mouse_button_pressed(btn: f64) -> f64 {
513
+ if engine().input.is_mouse_button_pressed(btn as usize) { 1.0 } else { 0.0 }
514
+ }
515
+
516
+ #[no_mangle]
517
+ pub extern "C" fn bloom_is_mouse_button_down(btn: f64) -> f64 {
518
+ if engine().input.is_mouse_button_down(btn as usize) { 1.0 } else { 0.0 }
519
+ }
520
+
521
+ #[no_mangle]
522
+ pub extern "C" fn bloom_is_mouse_button_released(btn: f64) -> f64 {
523
+ if engine().input.is_mouse_button_released(btn as usize) { 1.0 } else { 0.0 }
524
+ }
525
+
526
+ #[no_mangle]
527
+ pub extern "C" fn bloom_draw_line(x1: f64, y1: f64, x2: f64, y2: f64, thickness: f64, r: f64, g: f64, b: f64, a: f64) {
528
+ engine().renderer.draw_line(x1, y1, x2, y2, thickness, r, g, b, a);
529
+ }
530
+
531
+ #[no_mangle]
532
+ pub extern "C" fn bloom_draw_rect(x: f64, y: f64, w: f64, h: f64, r: f64, g: f64, b: f64, a: f64) {
533
+ engine().renderer.draw_rect(x, y, w, h, r, g, b, a);
534
+ }
535
+
536
+ #[no_mangle]
537
+ pub extern "C" fn bloom_draw_rect_lines(x: f64, y: f64, w: f64, h: f64, thickness: f64, r: f64, g: f64, b: f64, a: f64) {
538
+ engine().renderer.draw_rect_lines(x, y, w, h, thickness, r, g, b, a);
539
+ }
540
+
541
+ #[no_mangle]
542
+ pub extern "C" fn bloom_draw_circle(cx: f64, cy: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
543
+ engine().renderer.draw_circle(cx, cy, radius, r, g, b, a);
544
+ }
545
+
546
+ #[no_mangle]
547
+ pub extern "C" fn bloom_draw_circle_lines(cx: f64, cy: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
548
+ engine().renderer.draw_circle_lines(cx, cy, radius, r, g, b, a);
549
+ }
550
+
551
+ #[no_mangle]
552
+ pub extern "C" fn bloom_draw_triangle(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, r: f64, g: f64, b: f64, a: f64) {
553
+ engine().renderer.draw_triangle(x1, y1, x2, y2, x3, y3, r, g, b, a);
554
+ }
555
+
556
+ #[no_mangle]
557
+ pub extern "C" fn bloom_draw_poly(cx: f64, cy: f64, sides: f64, radius: f64, rotation: f64, r: f64, g: f64, b: f64, a: f64) {
558
+ engine().renderer.draw_poly(cx, cy, sides, radius, rotation, r, g, b, a);
559
+ }
560
+
561
+ #[no_mangle]
562
+ pub extern "C" fn bloom_draw_text(text_ptr: *const u8, x: f64, y: f64, size: f64, r: f64, g: f64, b: f64, a: f64) {
563
+ let text = str_from_header(text_ptr);
564
+ let eng = engine();
565
+ let mut text_renderer = std::mem::replace(&mut eng.text, bloom_shared::text_renderer::TextRenderer::empty());
566
+ text_renderer.draw_text(&mut eng.renderer, text, x, y, size as u32, r, g, b, a);
567
+ eng.text = text_renderer;
568
+ }
569
+
570
+ #[no_mangle]
571
+ pub extern "C" fn bloom_measure_text(text_ptr: *const u8, size: f64) -> f64 {
572
+ let text = str_from_header(text_ptr);
573
+ engine().text.measure_text(text, size as u32)
574
+ }
575
+
576
+ #[no_mangle]
577
+ pub extern "C" fn bloom_load_font(path_ptr: *const u8, size: f64) -> f64 {
578
+ let path = str_from_header(path_ptr);
579
+ match std::fs::read(path) {
580
+ Ok(data) => engine().text.load_font(&data) as f64,
581
+ Err(_) => 0.0,
582
+ }
583
+ }
584
+
585
+ #[no_mangle]
586
+ pub extern "C" fn bloom_unload_font(font_handle: f64) {
587
+ engine().text.unload_font(font_handle as usize);
588
+ }
589
+
590
+ #[no_mangle]
591
+ pub extern "C" fn bloom_draw_text_ex(font_handle: f64, text_ptr: *const u8, x: f64, y: f64, size: f64, spacing: f64, r: f64, g: f64, b: f64, a: f64) {
592
+ let text = str_from_header(text_ptr);
593
+ let eng = engine();
594
+ let mut text_renderer = std::mem::replace(&mut eng.text, bloom_shared::text_renderer::TextRenderer::empty());
595
+ text_renderer.draw_text_ex(&mut eng.renderer, font_handle as usize, text, x, y, size as u32, spacing as f32, r, g, b, a);
596
+ eng.text = text_renderer;
597
+ }
598
+
599
+ #[no_mangle]
600
+ pub extern "C" fn bloom_measure_text_ex(font_handle: f64, text_ptr: *const u8, size: f64, spacing: f64) -> f64 {
601
+ let text = str_from_header(text_ptr);
602
+ engine().text.measure_text_ex(font_handle as usize, text, size as u32, spacing as f32)
603
+ }
604
+
605
+ static AUDIO_RUNNING: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
606
+
607
+ #[no_mangle]
608
+ pub extern "C" fn bloom_init_audio() {
609
+ #[cfg(windows)]
610
+ {
611
+ use std::sync::atomic::Ordering;
612
+ AUDIO_RUNNING.store(true, Ordering::SeqCst);
613
+
614
+ std::thread::spawn(|| {
615
+ unsafe { wasapi_audio_thread(); }
616
+ });
617
+ }
618
+ }
619
+
620
+ #[no_mangle]
621
+ pub extern "C" fn bloom_close_audio() {
622
+ AUDIO_RUNNING.store(false, std::sync::atomic::Ordering::SeqCst);
623
+ std::thread::sleep(std::time::Duration::from_millis(50));
624
+ }
625
+
626
+ #[cfg(windows)]
627
+ unsafe fn wasapi_audio_thread() {
628
+ use windows::Win32::Media::Audio::*;
629
+ use windows::Win32::System::Com::*;
630
+ use windows::core::*;
631
+ use std::sync::atomic::Ordering;
632
+
633
+ // Initialize COM on this thread
634
+ let _ = CoInitializeEx(None, COINIT_MULTITHREADED);
635
+
636
+ // Create device enumerator and get default output device
637
+ let enumerator: IMMDeviceEnumerator = match CoCreateInstance(
638
+ &MMDeviceEnumerator,
639
+ None,
640
+ CLSCTX_ALL,
641
+ ) {
642
+ Ok(e) => e,
643
+ Err(_) => return,
644
+ };
645
+
646
+ let device = match enumerator.GetDefaultAudioEndpoint(eRender, eConsole) {
647
+ Ok(d) => d,
648
+ Err(_) => return,
649
+ };
650
+
651
+ let audio_client: IAudioClient = match device.Activate(CLSCTX_ALL, None) {
652
+ Ok(c) => c,
653
+ Err(_) => return,
654
+ };
655
+
656
+ // Get mix format
657
+ let mix_format_ptr = match audio_client.GetMixFormat() {
658
+ Ok(f) => f,
659
+ Err(_) => return,
660
+ };
661
+ let mix_format = &*mix_format_ptr;
662
+ let sample_rate = mix_format.nSamplesPerSec;
663
+ let channels = mix_format.nChannels as usize;
664
+
665
+ // Initialize in shared mode with 20ms buffer
666
+ let buffer_duration = 200_000; // 20ms in 100-nanosecond units
667
+ if audio_client.Initialize(
668
+ AUDCLNT_SHAREMODE_SHARED,
669
+ 0,
670
+ buffer_duration,
671
+ 0,
672
+ mix_format_ptr,
673
+ None,
674
+ ).is_err() {
675
+ return;
676
+ }
677
+
678
+ let buffer_size = match audio_client.GetBufferSize() {
679
+ Ok(s) => s as usize,
680
+ Err(_) => return,
681
+ };
682
+
683
+ let render_client: IAudioRenderClient = match audio_client.GetService() {
684
+ Ok(r) => r,
685
+ Err(_) => return,
686
+ };
687
+
688
+ let _ = audio_client.Start();
689
+
690
+ // Temporary buffer for mixing (always stereo f32 from our mixer)
691
+ let mut mix_buf = vec![0.0f32; buffer_size * 2];
692
+
693
+ while AUDIO_RUNNING.load(Ordering::SeqCst) {
694
+ let padding = audio_client.GetCurrentPadding().unwrap_or(0) as usize;
695
+ let available = buffer_size - padding;
696
+ if available == 0 {
697
+ std::thread::sleep(std::time::Duration::from_millis(2));
698
+ continue;
699
+ }
700
+
701
+ let buffer_ptr = match render_client.GetBuffer(available as u32) {
702
+ Ok(p) => p,
703
+ Err(_) => { std::thread::sleep(std::time::Duration::from_millis(2)); continue; }
704
+ };
705
+
706
+ // Mix audio
707
+ let mix_samples = available * 2; // stereo
708
+ for i in 0..mix_samples { mix_buf[i] = 0.0; }
709
+ ENGINE.get_mut().map(|eng| {
710
+ eng.audio.mix_output(&mut mix_buf[..mix_samples]);
711
+ });
712
+
713
+ // Write to WASAPI buffer (format is typically f32 or i16, assume float since we requested shared mode)
714
+ let bits = mix_format.wBitsPerSample;
715
+ let out_channels = channels;
716
+ if bits == 32 {
717
+ let out = std::slice::from_raw_parts_mut(buffer_ptr as *mut f32, available * out_channels);
718
+ for i in 0..available {
719
+ let l = mix_buf[i * 2];
720
+ let r = if i * 2 + 1 < mix_samples { mix_buf[i * 2 + 1] } else { l };
721
+ if out_channels >= 2 {
722
+ out[i * out_channels] = l;
723
+ out[i * out_channels + 1] = r;
724
+ for c in 2..out_channels { out[i * out_channels + c] = 0.0; }
725
+ } else {
726
+ out[i] = (l + r) * 0.5;
727
+ }
728
+ }
729
+ } else if bits == 16 {
730
+ let out = std::slice::from_raw_parts_mut(buffer_ptr as *mut i16, available * out_channels);
731
+ for i in 0..available {
732
+ let l = mix_buf[i * 2];
733
+ let r = if i * 2 + 1 < mix_samples { mix_buf[i * 2 + 1] } else { l };
734
+ if out_channels >= 2 {
735
+ out[i * out_channels] = (l * 32767.0) as i16;
736
+ out[i * out_channels + 1] = (r * 32767.0) as i16;
737
+ for c in 2..out_channels { out[i * out_channels + c] = 0; }
738
+ } else {
739
+ out[i] = ((l + r) * 0.5 * 32767.0) as i16;
740
+ }
741
+ }
742
+ }
743
+
744
+ let _ = render_client.ReleaseBuffer(available as u32, 0);
745
+ std::thread::sleep(std::time::Duration::from_millis(2));
746
+ }
747
+
748
+ let _ = audio_client.Stop();
749
+ CoUninitialize();
750
+ }
751
+
752
+ #[no_mangle]
753
+ pub extern "C" fn bloom_load_sound(path_ptr: *const u8) -> f64 {
754
+ let path = str_from_header(path_ptr);
755
+ match std::fs::read(path) {
756
+ Ok(data) => {
757
+ if let Some(s) = parse_wav(&data) { engine().audio.load_sound(s) }
758
+ else if let Some(s) = parse_ogg(&data) { engine().audio.load_sound(s) }
759
+ else if let Some(s) = parse_mp3(&data) { engine().audio.load_sound(s) }
760
+ else { 0.0 }
761
+ }
762
+ Err(_) => 0.0,
763
+ }
764
+ }
765
+
766
+ #[no_mangle]
767
+ pub extern "C" fn bloom_play_sound(handle: f64) { engine().audio.play_sound(handle); }
768
+
769
+ #[no_mangle]
770
+ pub extern "C" fn bloom_stop_sound(handle: f64) { engine().audio.stop_sound(handle); }
771
+
772
+ #[no_mangle]
773
+ pub extern "C" fn bloom_set_sound_volume(handle: f64, volume: f64) {
774
+ engine().audio.set_sound_volume(handle, volume as f32);
775
+ }
776
+
777
+ #[no_mangle]
778
+ pub extern "C" fn bloom_set_master_volume(volume: f64) {
779
+ engine().audio.master_volume = volume as f32;
780
+ }
781
+
782
+ #[no_mangle]
783
+ pub extern "C" fn bloom_play_sound_3d(handle: f64, x: f64, y: f64, z: f64) {
784
+ engine().audio.play_sound_3d(handle, x as f32, y as f32, z as f32);
785
+ }
786
+
787
+ #[no_mangle]
788
+ pub extern "C" fn bloom_set_listener_position(x: f64, y: f64, z: f64, fx: f64, fy: f64, fz: f64) {
789
+ engine().audio.set_listener_position(x as f32, y as f32, z as f32, fx as f32, fy as f32, fz as f32);
790
+ }
791
+
792
+ // --- Texture FFI ---
793
+
794
+ #[no_mangle]
795
+ pub extern "C" fn bloom_load_texture(path_ptr: *const u8) -> f64 {
796
+ let path = str_from_header(path_ptr);
797
+ match std::fs::read(path) {
798
+ Ok(data) => {
799
+ let eng = engine();
800
+ let renderer_ptr = &mut eng.renderer as *mut bloom_shared::renderer::Renderer;
801
+ eng.textures.load_texture(unsafe { &mut *renderer_ptr }, &data)
802
+ }
803
+ Err(_) => 0.0,
804
+ }
805
+ }
806
+
807
+ #[no_mangle]
808
+ pub extern "C" fn bloom_unload_texture(handle: f64) {
809
+ let eng = engine();
810
+ let renderer_ptr = &mut eng.renderer as *mut bloom_shared::renderer::Renderer;
811
+ eng.textures.unload_texture(handle, unsafe { &mut *renderer_ptr });
812
+ }
813
+
814
+ #[no_mangle]
815
+ pub extern "C" fn bloom_draw_texture(handle: f64, x: f64, y: f64, r: f64, g: f64, b: f64, a: f64) {
816
+ let eng = engine();
817
+ if let Some(tex) = eng.textures.get(handle) {
818
+ let idx = tex.bind_group_idx;
819
+ eng.renderer.draw_texture(idx, x, y, r, g, b, a);
820
+ }
821
+ }
822
+
823
+ #[no_mangle]
824
+ pub extern "C" fn bloom_draw_texture_rec(handle: f64, src_x: f64, src_y: f64, src_w: f64, src_h: f64, dst_x: f64, dst_y: f64, r: f64, g: f64, b: f64, a: f64) {
825
+ let eng = engine();
826
+ if let Some(tex) = eng.textures.get(handle) {
827
+ let idx = tex.bind_group_idx;
828
+ eng.renderer.draw_texture_rec(idx, src_x, src_y, src_w, src_h, dst_x, dst_y, r, g, b, a);
829
+ }
830
+ }
831
+
832
+ #[no_mangle]
833
+ pub extern "C" fn bloom_draw_texture_pro(handle: f64, src_x: f64, src_y: f64, src_w: f64, src_h: f64, dst_x: f64, dst_y: f64, dst_w: f64, dst_h: f64, origin_x: f64, origin_y: f64, rotation: f64, r: f64, g: f64, b: f64, a: f64) {
834
+ let eng = engine();
835
+ if let Some(tex) = eng.textures.get(handle) {
836
+ let idx = tex.bind_group_idx;
837
+ eng.renderer.draw_texture_pro(idx, src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h, origin_x, origin_y, rotation, r, g, b, a);
838
+ }
839
+ }
840
+
841
+ #[no_mangle]
842
+ pub extern "C" fn bloom_get_texture_width(handle: f64) -> f64 {
843
+ engine().textures.get(handle).map(|t| t.width as f64).unwrap_or(0.0)
844
+ }
845
+
846
+ #[no_mangle]
847
+ pub extern "C" fn bloom_get_texture_height(handle: f64) -> f64 {
848
+ engine().textures.get(handle).map(|t| t.height as f64).unwrap_or(0.0)
849
+ }
850
+
851
+ #[no_mangle]
852
+ pub extern "C" fn bloom_gen_texture_mipmaps(_handle: f64) {
853
+ // No-op: wgpu handles mipmaps internally
854
+ }
855
+
856
+ #[no_mangle]
857
+ pub extern "C" fn bloom_set_texture_filter(handle: f64, mode: f64) {
858
+ let eng = engine();
859
+ if let Some(tex) = eng.textures.get(handle) {
860
+ let bind_group_idx = tex.bind_group_idx;
861
+ eng.renderer.set_texture_filter(bind_group_idx, mode > 0.5);
862
+ }
863
+ }
864
+
865
+ #[no_mangle]
866
+ pub extern "C" fn bloom_load_image(path_ptr: *const u8) -> f64 {
867
+ let path = str_from_header(path_ptr);
868
+ match std::fs::read(path) { Ok(data) => engine().textures.load_image(&data), Err(_) => 0.0 }
869
+ }
870
+
871
+ #[no_mangle]
872
+ pub extern "C" fn bloom_image_resize(handle: f64, w: f64, h: f64) {
873
+ engine().textures.image_resize(handle, w as u32, h as u32);
874
+ }
875
+
876
+ #[no_mangle]
877
+ pub extern "C" fn bloom_image_crop(handle: f64, x: f64, y: f64, w: f64, h: f64) {
878
+ engine().textures.image_crop(handle, x as u32, y as u32, w as u32, h as u32);
879
+ }
880
+
881
+ #[no_mangle]
882
+ pub extern "C" fn bloom_image_flip_h(handle: f64) {
883
+ engine().textures.image_flip_h(handle);
884
+ }
885
+
886
+ #[no_mangle]
887
+ pub extern "C" fn bloom_image_flip_v(handle: f64) {
888
+ engine().textures.image_flip_v(handle);
889
+ }
890
+
891
+ #[no_mangle]
892
+ pub extern "C" fn bloom_load_texture_from_image(handle: f64) -> f64 {
893
+ let eng = engine();
894
+ let renderer_ptr = &mut eng.renderer as *mut bloom_shared::renderer::Renderer;
895
+ eng.textures.load_texture_from_image(handle, unsafe { &mut *renderer_ptr })
896
+ }
897
+
898
+ // --- Camera FFI ---
899
+
900
+ #[no_mangle]
901
+ pub extern "C" fn bloom_begin_mode_2d(offset_x: f64, offset_y: f64, target_x: f64, target_y: f64, rotation: f64, zoom: f64) {
902
+ engine().renderer.begin_mode_2d(offset_x as f32, offset_y as f32, target_x as f32, target_y as f32, rotation as f32, zoom as f32);
903
+ }
904
+ #[no_mangle]
905
+ pub extern "C" fn bloom_end_mode_2d() { engine().renderer.end_mode_2d(); }
906
+
907
+ #[no_mangle]
908
+ pub extern "C" fn bloom_begin_mode_3d(pos_x: f64, pos_y: f64, pos_z: f64, target_x: f64, target_y: f64, target_z: f64, up_x: f64, up_y: f64, up_z: f64, fovy: f64, projection: f64) {
909
+ engine().renderer.begin_mode_3d(pos_x as f32, pos_y as f32, pos_z as f32, target_x as f32, target_y as f32, target_z as f32, up_x as f32, up_y as f32, up_z as f32, fovy as f32, projection as f32);
910
+ }
911
+ #[no_mangle]
912
+ pub extern "C" fn bloom_end_mode_3d() { engine().renderer.end_mode_3d(); }
913
+
914
+ // --- 3D Drawing FFI ---
915
+
916
+ #[no_mangle]
917
+ pub extern "C" fn bloom_draw_cube(x: f64, y: f64, z: f64, w: f64, h: f64, d: f64, r: f64, g: f64, b: f64, a: f64) {
918
+ engine().renderer.draw_cube(x, y, z, w, h, d, r, g, b, a);
919
+ }
920
+ #[no_mangle]
921
+ pub extern "C" fn bloom_draw_cube_wires(x: f64, y: f64, z: f64, w: f64, h: f64, d: f64, r: f64, g: f64, b: f64, a: f64) {
922
+ engine().renderer.draw_cube_wires(x, y, z, w, h, d, r, g, b, a);
923
+ }
924
+ #[no_mangle]
925
+ pub extern "C" fn bloom_draw_sphere(x: f64, y: f64, z: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
926
+ engine().renderer.draw_sphere(x, y, z, radius, r, g, b, a);
927
+ }
928
+ #[no_mangle]
929
+ pub extern "C" fn bloom_draw_sphere_wires(x: f64, y: f64, z: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
930
+ engine().renderer.draw_sphere_wires(x, y, z, radius, r, g, b, a);
931
+ }
932
+ #[no_mangle]
933
+ pub extern "C" fn bloom_draw_cylinder(x: f64, y: f64, z: f64, rt: f64, rb: f64, h: f64, r: f64, g: f64, b: f64, a: f64) {
934
+ engine().renderer.draw_cylinder(x, y, z, rt, rb, h, r, g, b, a);
935
+ }
936
+ #[no_mangle]
937
+ pub extern "C" fn bloom_draw_plane(x: f64, y: f64, z: f64, w: f64, d: f64, r: f64, g: f64, b: f64, a: f64) {
938
+ engine().renderer.draw_plane(x, y, z, w, d, r, g, b, a);
939
+ }
940
+ #[no_mangle]
941
+ pub extern "C" fn bloom_draw_grid(slices: f64, spacing: f64) {
942
+ engine().renderer.draw_grid(slices as i32, spacing);
943
+ }
944
+ #[no_mangle]
945
+ pub extern "C" fn bloom_draw_ray(ox: f64, oy: f64, oz: f64, dx: f64, dy: f64, dz: f64, r: f64, g: f64, b: f64, a: f64) {
946
+ engine().renderer.draw_ray(ox, oy, oz, dx, dy, dz, r, g, b, a);
947
+ }
948
+
949
+ // --- Model FFI ---
950
+
951
+ #[no_mangle]
952
+ pub extern "C" fn bloom_load_model(path_ptr: *const u8) -> f64 {
953
+ let path = str_from_header(path_ptr);
954
+ match std::fs::read(path) {
955
+ Ok(data) => {
956
+ let eng = engine();
957
+ let renderer_ptr = &mut eng.renderer as *mut Renderer;
958
+ eng.models.load_model_with_textures(&data, unsafe { &mut *renderer_ptr })
959
+ }
960
+ Err(_) => 0.0,
961
+ }
962
+ }
963
+ #[no_mangle]
964
+ pub extern "C" fn bloom_draw_model(handle: f64, x: f64, y: f64, z: f64, scale: f64, r: f64, g: f64, b: f64, a: f64) {
965
+ let eng = engine();
966
+ if let Some(model) = eng.models.get(handle) {
967
+ let tint = [(r / 255.0) as f32, (g / 255.0) as f32, (b / 255.0) as f32, (a / 255.0) as f32];
968
+ let position = [x as f32, y as f32, z as f32];
969
+ let handle_bits = handle.to_bits();
970
+ if eng.renderer.cache_model_if_static(handle_bits, &model.meshes) {
971
+ eng.renderer.draw_model_cached(handle_bits, position, scale as f32, tint);
972
+ } else {
973
+ for mesh in &model.meshes {
974
+ let tex_idx = mesh.texture_idx.unwrap_or(0);
975
+ eng.renderer.draw_model_mesh_tinted(&mesh.vertices, &mesh.indices, position, scale as f32, tint, tex_idx);
976
+ }
977
+ }
978
+ }
979
+ }
980
+ #[no_mangle]
981
+ pub extern "C" fn bloom_draw_model_rotated(
982
+ handle: f64, x: f64, y: f64, z: f64,
983
+ scale: f64, rot_y: f64,
984
+ color_packed_argb: f64,
985
+ ) {
986
+ let bits = color_packed_argb as u32;
987
+ let a = ((bits >> 24) & 0xff) as f32 / 255.0;
988
+ let r = ((bits >> 16) & 0xff) as f32 / 255.0;
989
+ let g = ((bits >> 8) & 0xff) as f32 / 255.0;
990
+ let b = ( bits & 0xff) as f32 / 255.0;
991
+ let eng = engine();
992
+ if let Some(model) = eng.models.get(handle) {
993
+ let position = [x as f32, y as f32, z as f32];
994
+ let scale = scale as f32;
995
+ let tint = [r, g, b, a];
996
+ for mesh in &model.meshes {
997
+ let tex_idx = mesh.texture_idx.unwrap_or(0);
998
+ eng.renderer.draw_model_mesh_tinted_rotated(
999
+ &mesh.vertices, &mesh.indices, position, scale, tint, tex_idx, rot_y as f32,
1000
+ );
1001
+ }
1002
+ }
1003
+ }
1004
+ #[no_mangle]
1005
+ pub extern "C" fn bloom_unload_model(handle: f64) { engine().models.unload_model(handle); }
1006
+
1007
+ #[no_mangle]
1008
+ pub extern "C" fn bloom_get_model_mesh_count(handle: f64) -> f64 {
1009
+ match engine().models.get(handle) {
1010
+ Some(model) => model.meshes.len() as f64,
1011
+ None => 0.0,
1012
+ }
1013
+ }
1014
+
1015
+ #[no_mangle]
1016
+ pub extern "C" fn bloom_get_model_material_count(handle: f64) -> f64 {
1017
+ match engine().models.get(handle) {
1018
+ Some(model) => model.meshes.len() as f64,
1019
+ None => 0.0,
1020
+ }
1021
+ }
1022
+
1023
+ #[no_mangle]
1024
+ pub extern "C" fn bloom_gen_mesh_cube(w: f64, h: f64, d: f64) -> f64 {
1025
+ engine().models.gen_mesh_cube(w as f32, h as f32, d as f32)
1026
+ }
1027
+
1028
+ #[no_mangle]
1029
+ pub extern "C" fn bloom_gen_mesh_heightmap(image_handle: f64, size_x: f64, size_y: f64, size_z: f64) -> f64 {
1030
+ let eng = engine();
1031
+ if let Some(img) = eng.textures.images.get(image_handle) {
1032
+ let data = img.data.clone();
1033
+ let w = img.width;
1034
+ let h = img.height;
1035
+ eng.models.gen_mesh_heightmap(&data, w, h, size_x as f32, size_y as f32, size_z as f32)
1036
+ } else {
1037
+ 0.0
1038
+ }
1039
+ }
1040
+
1041
+ #[no_mangle]
1042
+ pub extern "C" fn bloom_load_shader(source_ptr: *const u8) -> f64 {
1043
+ let source = str_from_header(source_ptr);
1044
+ engine().renderer.load_custom_shader(source) as f64
1045
+ }
1046
+
1047
+ #[no_mangle]
1048
+ pub extern "C" fn bloom_create_mesh(vertex_ptr: *const f32, vertex_count: f64, index_ptr: *const u32, index_count: f64) -> f64 {
1049
+ if vertex_ptr.is_null() || index_ptr.is_null() { return 0.0; }
1050
+ let vcount = vertex_count as usize;
1051
+ let icount = index_count as usize;
1052
+ let vertex_data = unsafe { std::slice::from_raw_parts(vertex_ptr, vcount * 12) }; // 12 floats per vertex
1053
+ let index_data = unsafe { std::slice::from_raw_parts(index_ptr, icount) };
1054
+ engine().models.create_mesh(vertex_data, index_data)
1055
+ }
1056
+
1057
+ // ============================================================
1058
+ // Phase 1c — material system FFI
1059
+ // ============================================================
1060
+
1061
+ #[no_mangle]
1062
+ pub extern "C" fn bloom_set_material_params(
1063
+ handle: f64,
1064
+ params_ptr: *const f64,
1065
+ param_count: f64,
1066
+ ) {
1067
+ let count = param_count as usize;
1068
+ if count > 64 {
1069
+ eprintln!("[material] set_material_params: param_count {} > 64 (256-byte UBO cap)", count);
1070
+ return;
1071
+ }
1072
+ let mut bytes = vec![0u8; count * 4];
1073
+ if !params_ptr.is_null() && count > 0 {
1074
+ let slots = unsafe { std::slice::from_raw_parts(params_ptr, count) };
1075
+ for (i, &v) in slots.iter().enumerate() {
1076
+ let f = v as f32;
1077
+ bytes[i*4..i*4+4].copy_from_slice(&f.to_le_bytes());
1078
+ }
1079
+ }
1080
+ let eng = engine();
1081
+ if let Err(e) = eng.renderer.material_system.set_user_params(
1082
+ &eng.renderer.device, &eng.renderer.queue,
1083
+ handle as u32, &bytes,
1084
+ ) {
1085
+ eprintln!("[material] set_material_params failed: {}", e);
1086
+ }
1087
+ }
1088
+
1089
+ #[no_mangle]
1090
+ pub extern "C" fn bloom_compile_material(source_ptr: *const u8) -> f64 {
1091
+ let source = str_from_header(source_ptr);
1092
+ match engine().renderer.compile_material(source) {
1093
+ Ok(handle) => handle as f64,
1094
+ Err(e) => {
1095
+ eprintln!("[material] compile failed: {:?}", e);
1096
+ 0.0
1097
+ }
1098
+ }
1099
+ }
1100
+
1101
+ #[no_mangle]
1102
+ pub extern "C" fn bloom_compile_material_refractive(source_ptr: *const u8) -> f64 {
1103
+ use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
1104
+ let source = str_from_header(source_ptr);
1105
+ match engine().renderer.compile_material_with_options(
1106
+ source, FragmentProfile::Translucent, Bucket::Refractive, true, false,
1107
+ ) {
1108
+ Ok(handle) => handle as f64,
1109
+ Err(e) => { eprintln!("[refractive] compile failed: {:?}", e); 0.0 }
1110
+ }
1111
+ }
1112
+
1113
+ #[no_mangle]
1114
+ pub extern "C" fn bloom_compile_material_transparent(source_ptr: *const u8) -> f64 {
1115
+ use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
1116
+ let source = str_from_header(source_ptr);
1117
+ match engine().renderer.compile_material_with_options(
1118
+ source, FragmentProfile::Translucent, Bucket::Transparent, false, false,
1119
+ ) {
1120
+ Ok(handle) => handle as f64,
1121
+ Err(e) => { eprintln!("[material] compile failed: {:?}", e); 0.0 }
1122
+ }
1123
+ }
1124
+
1125
+ #[no_mangle]
1126
+ pub extern "C" fn bloom_compile_material_additive(source_ptr: *const u8) -> f64 {
1127
+ use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
1128
+ let source = str_from_header(source_ptr);
1129
+ match engine().renderer.compile_material_with_options(
1130
+ source, FragmentProfile::Translucent, Bucket::Additive, false, false,
1131
+ ) {
1132
+ Ok(handle) => handle as f64,
1133
+ Err(e) => { eprintln!("[material] compile failed: {:?}", e); 0.0 }
1134
+ }
1135
+ }
1136
+
1137
+ #[no_mangle]
1138
+ pub extern "C" fn bloom_compile_material_cutout(source_ptr: *const u8) -> f64 {
1139
+ use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
1140
+ let source = str_from_header(source_ptr);
1141
+ match engine().renderer.compile_material_with_options(
1142
+ source, FragmentProfile::Opaque, Bucket::Cutout, false, false,
1143
+ ) {
1144
+ Ok(handle) => handle as f64,
1145
+ Err(e) => { eprintln!("[material] compile failed: {:?}", e); 0.0 }
1146
+ }
1147
+ }
1148
+
1149
+ #[no_mangle]
1150
+ pub extern "C" fn bloom_compile_material_instanced(source_ptr: *const u8) -> f64 {
1151
+ let source = str_from_header(source_ptr);
1152
+ match engine().renderer.compile_material_instanced(source) {
1153
+ Ok(handle) => handle as f64,
1154
+ Err(e) => { eprintln!("[material] instanced compile failed: {:?}", e); 0.0 }
1155
+ }
1156
+ }
1157
+
1158
+ #[no_mangle]
1159
+ pub extern "C" fn bloom_create_instance_buffer(
1160
+ data_ptr: *const f64, instance_count: f64,
1161
+ ) -> f64 {
1162
+ if data_ptr.is_null() || instance_count <= 0.0 { return 0.0; }
1163
+ let count = instance_count as u32;
1164
+ let slot_count = (count as usize) * 9;
1165
+ let raw_f64 = unsafe { std::slice::from_raw_parts(data_ptr, slot_count) };
1166
+ let raw_f32: Vec<f32> = raw_f64.iter().map(|&v| v as f32).collect();
1167
+ engine().renderer.create_instance_buffer(&raw_f32, count) as f64
1168
+ }
1169
+
1170
+ #[no_mangle]
1171
+ pub extern "C" fn bloom_submit_material_draw_instanced(
1172
+ material: f64, mesh_handle: f64, mesh_idx: f64,
1173
+ instance_buffer: f64, instance_count: f64,
1174
+ ) {
1175
+ let eng = engine();
1176
+ let handle_bits = mesh_handle.to_bits();
1177
+ if let Some(model) = eng.models.get(mesh_handle) {
1178
+ eng.renderer.cache_model_if_static(handle_bits, &model.meshes);
1179
+ }
1180
+ eng.renderer.submit_material_draw_instanced(
1181
+ material as u32,
1182
+ handle_bits,
1183
+ mesh_idx as usize,
1184
+ instance_buffer as u32,
1185
+ instance_count as u32,
1186
+ );
1187
+ }
1188
+
1189
+ #[no_mangle]
1190
+ pub extern "C" fn bloom_destroy_instance_buffer(handle: f64) {
1191
+ engine().renderer.destroy_instance_buffer(handle as u32);
1192
+ }
1193
+
1194
+ /// EN-011 — create a planar reflection probe. See macOS lib.rs for the
1195
+ /// full doc comment; this entry-point exists on every native platform
1196
+ /// so games can target the same FFI surface across iOS/tvOS/Windows/
1197
+ /// Linux/Android.
1198
+ #[no_mangle]
1199
+ pub extern "C" fn bloom_create_planar_reflection(
1200
+ plane_y: f64, nx: f64, ny: f64, nz: f64, resolution: f64,
1201
+ ) -> f64 {
1202
+ engine().renderer.create_planar_reflection(
1203
+ plane_y as f32,
1204
+ [nx as f32, ny as f32, nz as f32],
1205
+ resolution as u32,
1206
+ ) as f64
1207
+ }
1208
+
1209
+ /// EN-011 — link a material to a planar reflection probe. `probe = 0`
1210
+ /// reverts the binding to the engine's default 1×1 black texture.
1211
+ #[no_mangle]
1212
+ pub extern "C" fn bloom_set_material_reflection_probe(
1213
+ material: f64, probe: f64,
1214
+ ) {
1215
+ engine().renderer.set_material_reflection_probe(material as u32, probe as u32);
1216
+ }
1217
+
1218
+ /// EN-014 — create a texture array from concatenated RGBA8 byte data.
1219
+ /// See macOS lib.rs for the full doc comment; this entry-point exists
1220
+ /// on every native platform so a TS game targets the same FFI across
1221
+ /// iOS / tvOS / Windows / Linux / Android.
1222
+ #[no_mangle]
1223
+ pub extern "C" fn bloom_create_texture_array(
1224
+ data_ptr: *const u8,
1225
+ data_len: f64,
1226
+ width: f64,
1227
+ height: f64,
1228
+ layer_count: f64,
1229
+ ) -> f64 {
1230
+ // EN-014 V2 — V1 forwards to _ex with default sRGB / no mips.
1231
+ bloom_create_texture_array_ex(data_ptr, data_len, width, height, layer_count, 0.0, 1.0)
1232
+ }
1233
+
1234
+ /// EN-014 V2 — explicit format + mip control. See macOS lib.rs for docs.
1235
+ #[no_mangle]
1236
+ pub extern "C" fn bloom_create_texture_array_ex(
1237
+ data_ptr: *const u8,
1238
+ data_len: f64,
1239
+ width: f64,
1240
+ height: f64,
1241
+ layer_count: f64,
1242
+ format: f64,
1243
+ mip_levels: f64,
1244
+ ) -> f64 {
1245
+ if data_ptr.is_null() || data_len <= 0.0 { return 0.0; }
1246
+ let w = width as u32;
1247
+ let h = height as u32;
1248
+ if w == 0 || h == 0 { return 0.0; }
1249
+ let layers_count = (layer_count as u32)
1250
+ .min(bloom_shared::renderer::material_system::MAX_TEXTURE_ARRAY_LAYERS);
1251
+ if layers_count == 0 { return 0.0; }
1252
+ let layer_size = (w as usize) * (h as usize) * 4;
1253
+ let total_bytes = (data_len as usize)
1254
+ .min(layers_count as usize * layer_size);
1255
+ let bytes = unsafe { std::slice::from_raw_parts(data_ptr, total_bytes) };
1256
+ let mut layers: Vec<(&[u8], u32, u32)> = Vec::with_capacity(layers_count as usize);
1257
+ for i in 0..(layers_count as usize) {
1258
+ let start = i * layer_size;
1259
+ let end = start + layer_size;
1260
+ if end > bytes.len() { break; }
1261
+ layers.push((&bytes[start..end], w, h));
1262
+ }
1263
+ engine().renderer.create_texture_array_ex(&layers, format as u32, mip_levels as u32) as f64
1264
+ }
1265
+
1266
+ /// EN-014 — link a texture-array handle to a material at one of three
1267
+ /// slots: 0 = albedo (binding 14), 1 = normal (binding 15),
1268
+ /// 2 = MR (binding 16). Pass `array = 0` to revert to the stub.
1269
+ #[no_mangle]
1270
+ pub extern "C" fn bloom_set_material_texture_array(
1271
+ material: f64, slot: f64, array: f64,
1272
+ ) {
1273
+ engine().renderer.set_material_texture_array(
1274
+ material as u32, slot as u32, array as u32,
1275
+ );
1276
+ }
1277
+
1278
+ /// EN-012 — set the shading model for a material (0=default lit,
1279
+ /// 1=foliage, 2=subsurface V2 stub).
1280
+ #[no_mangle]
1281
+ pub extern "C" fn bloom_set_material_shading_model(
1282
+ material: f64, model: f64,
1283
+ ) {
1284
+ engine().renderer.set_material_shading_model(material as u32, model as u32);
1285
+ }
1286
+
1287
+ /// EN-012 — set the foliage shading parameters for a material.
1288
+ /// Only takes effect when shading_model == 1 (foliage).
1289
+ #[no_mangle]
1290
+ pub extern "C" fn bloom_set_material_foliage(
1291
+ material: f64,
1292
+ trans_r: f64, trans_g: f64, trans_b: f64,
1293
+ trans_amount: f64, wrap_factor: f64,
1294
+ ) {
1295
+ engine().renderer.set_material_foliage(
1296
+ material as u32,
1297
+ [trans_r as f32, trans_g as f32, trans_b as f32],
1298
+ trans_amount as f32, wrap_factor as f32,
1299
+ );
1300
+ }
1301
+
1302
+ #[no_mangle]
1303
+ pub extern "C" fn bloom_compile_material_from_file(
1304
+ path_ptr: *const u8,
1305
+ bucket_kind: f64,
1306
+ ) -> f64 {
1307
+ use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
1308
+ let path = str_from_header(path_ptr);
1309
+ let (profile, bucket, reads_scene) = match bucket_kind as u32 {
1310
+ 0 => (FragmentProfile::Opaque, Bucket::Opaque, false),
1311
+ 1 => (FragmentProfile::Translucent, Bucket::Transparent, false),
1312
+ 2 => (FragmentProfile::Translucent, Bucket::Refractive, true),
1313
+ 3 => (FragmentProfile::Translucent, Bucket::Additive, false),
1314
+ 4 => (FragmentProfile::Opaque, Bucket::Cutout, false),
1315
+ _ => {
1316
+ eprintln!("[material] from_file: unknown bucket_kind {bucket_kind}");
1317
+ return 0.0;
1318
+ }
1319
+ };
1320
+ match engine().renderer.compile_material_from_file(
1321
+ std::path::Path::new(path), profile, bucket, reads_scene,
1322
+ ) {
1323
+ Ok(handle) => handle as f64,
1324
+ Err(e) => { eprintln!("[material] from_file failed: {e}"); 0.0 }
1325
+ }
1326
+ }
1327
+
1328
+ /// EN-017 — compile + install a fullscreen post-pass material.
1329
+ /// See `bloom-macos::bloom_set_post_pass` for the full ABI.
1330
+ #[no_mangle]
1331
+ pub extern "C" fn bloom_set_post_pass(source_ptr: *const u8) -> f64 {
1332
+ let source = str_from_header(source_ptr);
1333
+ match engine().renderer.set_post_pass(source) {
1334
+ Ok(()) => 1.0,
1335
+ Err(e) => { eprintln!("[post_pass] compile failed: {:?}", e); 0.0 }
1336
+ }
1337
+ }
1338
+
1339
+ /// EN-017 — uninstall the active post-pass.
1340
+ #[no_mangle]
1341
+ pub extern "C" fn bloom_clear_post_pass() {
1342
+ engine().renderer.clear_post_pass();
1343
+ }
1344
+
1345
+ /// EN-017 V2 — append a post-pass to the stack.
1346
+ /// See `bloom-macos::bloom_add_post_pass` for the full ABI.
1347
+ #[no_mangle]
1348
+ pub extern "C" fn bloom_add_post_pass(source_ptr: *const u8) -> f64 {
1349
+ let source = str_from_header(source_ptr);
1350
+ match engine().renderer.add_post_pass(source) {
1351
+ Ok(h) => h as f64,
1352
+ Err(e) => { eprintln!("[post_pass] compile failed: {:?}", e); 0.0 }
1353
+ }
1354
+ }
1355
+
1356
+ /// EN-017 V2 — wipe the entire post-pass stack.
1357
+ #[no_mangle]
1358
+ pub extern "C" fn bloom_clear_all_post_passes() {
1359
+ engine().renderer.clear_all_post_passes();
1360
+ }
1361
+
1362
+ #[no_mangle]
1363
+ pub extern "C" fn bloom_draw_material(
1364
+ material: f64,
1365
+ mesh_handle: f64,
1366
+ mesh_idx: f64,
1367
+ x: f64, y: f64, z: f64, scale: f64,
1368
+ r: f64, g: f64, b: f64, a: f64,
1369
+ ) {
1370
+ let eng = engine();
1371
+ let handle_bits = mesh_handle.to_bits();
1372
+ if let Some(model) = eng.models.get(mesh_handle) {
1373
+ eng.renderer.cache_model_if_static(handle_bits, &model.meshes);
1374
+ }
1375
+ eng.renderer.submit_material_draw(
1376
+ material as u32,
1377
+ handle_bits,
1378
+ mesh_idx as usize,
1379
+ [x as f32, y as f32, z as f32],
1380
+ scale as f32,
1381
+ [(r / 255.0) as f32, (g / 255.0) as f32, (b / 255.0) as f32, (a / 255.0) as f32],
1382
+ );
1383
+ }
1384
+
1385
+ #[no_mangle]
1386
+ pub extern "C" fn bloom_load_model_animation(path_ptr: *const u8) -> f64 {
1387
+ let path = str_from_header(path_ptr);
1388
+ match std::fs::read(path) {
1389
+ Ok(data) => engine().models.load_model_animation(&data),
1390
+ Err(_) => 0.0,
1391
+ }
1392
+ }
1393
+
1394
+ #[no_mangle]
1395
+ pub extern "C" fn bloom_update_model_animation(handle: f64, anim_index: f64, time: f64, scale: f64, px: f64, py: f64, pz: f64, rot_sin: f64, rot_cos: f64) {
1396
+ let eng = engine();
1397
+ eng.models.update_model_animation(handle, anim_index as usize, time as f32);
1398
+ if let Some(anim) = eng.models.get_animation(handle) {
1399
+ if !anim.joint_matrices.is_empty() {
1400
+ eng.renderer.set_joint_matrices_scaled(&anim.joint_matrices, scale as f32, [px as f32, py as f32, pz as f32], rot_sin as f32, rot_cos as f32);
1401
+ }
1402
+ }
1403
+ }
1404
+
1405
+ // --- Music FFI ---
1406
+
1407
+ #[no_mangle]
1408
+ pub extern "C" fn bloom_load_music(path_ptr: *const u8) -> f64 {
1409
+ let path = str_from_header(path_ptr);
1410
+ match std::fs::read(path) {
1411
+ Ok(data) => {
1412
+ if let Some(s) = parse_ogg(&data) { engine().audio.load_music(s) }
1413
+ else if let Some(s) = parse_wav(&data) { engine().audio.load_music(s) }
1414
+ else if let Some(s) = parse_mp3(&data) { engine().audio.load_music(s) }
1415
+ else { 0.0 }
1416
+ }
1417
+ Err(_) => 0.0,
1418
+ }
1419
+ }
1420
+ #[no_mangle]
1421
+ pub extern "C" fn bloom_play_music(handle: f64) { engine().audio.play_music(handle); }
1422
+ #[no_mangle]
1423
+ pub extern "C" fn bloom_stop_music(handle: f64) { engine().audio.stop_music(handle); }
1424
+ #[no_mangle]
1425
+ pub extern "C" fn bloom_update_music_stream(handle: f64) { engine().audio.update_music_stream(handle); }
1426
+ #[no_mangle]
1427
+ pub extern "C" fn bloom_set_music_volume(handle: f64, volume: f64) { engine().audio.set_music_volume(handle, volume as f32); }
1428
+ #[no_mangle]
1429
+ pub extern "C" fn bloom_is_music_playing(handle: f64) -> f64 { if engine().audio.is_music_playing(handle) { 1.0 } else { 0.0 } }
1430
+
1431
+ // --- Gamepad FFI ---
1432
+
1433
+ #[no_mangle]
1434
+ pub extern "C" fn bloom_is_gamepad_available() -> f64 { if engine().input.is_gamepad_available() { 1.0 } else { 0.0 } }
1435
+ #[no_mangle]
1436
+ pub extern "C" fn bloom_get_gamepad_axis(axis: f64) -> f64 { engine().input.get_gamepad_axis(axis as usize) as f64 }
1437
+ #[no_mangle]
1438
+ pub extern "C" fn bloom_is_gamepad_button_pressed(btn: f64) -> f64 { if engine().input.is_gamepad_button_pressed(btn as usize) { 1.0 } else { 0.0 } }
1439
+ #[no_mangle]
1440
+ pub extern "C" fn bloom_is_gamepad_button_down(btn: f64) -> f64 { if engine().input.is_gamepad_button_down(btn as usize) { 1.0 } else { 0.0 } }
1441
+ #[no_mangle]
1442
+ pub extern "C" fn bloom_is_gamepad_button_released(btn: f64) -> f64 { if engine().input.is_gamepad_button_released(btn as usize) { 1.0 } else { 0.0 } }
1443
+ #[no_mangle]
1444
+ pub extern "C" fn bloom_get_gamepad_axis_count() -> f64 { engine().input.get_gamepad_axis_count() as f64 }
1445
+
1446
+ // --- Skeletal Animation Debug ---
1447
+
1448
+ #[no_mangle]
1449
+ pub extern "C" fn bloom_set_joint_test(_joint: f64, _angle: f64) {
1450
+ // No-op for now — skeletal animation testing
1451
+ }
1452
+
1453
+ // --- Lighting ---
1454
+
1455
+ #[no_mangle]
1456
+ pub extern "C" fn bloom_set_ambient_light(r: f64, g: f64, b: f64, intensity: f64) {
1457
+ engine().renderer.set_ambient_light(r, g, b, intensity);
1458
+ }
1459
+
1460
+ #[no_mangle]
1461
+ pub extern "C" fn bloom_set_directional_light(dx: f64, dy: f64, dz: f64, r: f64, g: f64, b: f64, intensity: f64) {
1462
+ engine().renderer.set_directional_light(dx, dy, dz, r, g, b, intensity);
1463
+ }
1464
+
1465
+ #[no_mangle]
1466
+ pub extern "C" fn bloom_set_procedural_sky(enabled: f64, rayleigh_density: f64, mie_density: f64, ground_albedo: f64) {
1467
+ engine().renderer.set_procedural_sky(
1468
+ enabled != 0.0,
1469
+ rayleigh_density as f32,
1470
+ mie_density as f32,
1471
+ ground_albedo as f32,
1472
+ );
1473
+ }
1474
+
1475
+ #[no_mangle]
1476
+ pub extern "C" fn bloom_set_sun_direction(dx: f64, dy: f64, dz: f64, intensity: f64) {
1477
+ engine().renderer.set_sun_direction(dx as f32, dy as f32, dz as f32, intensity as f32);
1478
+ }
1479
+
1480
+ // --- Utility FFI ---
1481
+
1482
+ #[no_mangle]
1483
+ pub extern "C" fn bloom_toggle_fullscreen() {
1484
+ #[cfg(windows)]
1485
+ win32::toggle_fullscreen();
1486
+ }
1487
+ #[no_mangle]
1488
+ pub extern "C" fn bloom_set_window_title(title_ptr: *const u8) { let _ = str_from_header(title_ptr); }
1489
+ #[no_mangle]
1490
+ pub extern "C" fn bloom_set_window_icon(path_ptr: *const u8) { let _ = str_from_header(path_ptr); }
1491
+
1492
+ #[no_mangle]
1493
+ pub extern "C" fn bloom_disable_cursor() {
1494
+ engine().input.cursor_disabled = true;
1495
+ }
1496
+
1497
+ #[no_mangle]
1498
+ pub extern "C" fn bloom_enable_cursor() {
1499
+ engine().input.cursor_disabled = false;
1500
+ }
1501
+
1502
+ #[no_mangle]
1503
+ pub extern "C" fn bloom_get_mouse_delta_x() -> f64 {
1504
+ engine().input.mouse_delta_x
1505
+ }
1506
+
1507
+ #[no_mangle]
1508
+ pub extern "C" fn bloom_get_mouse_delta_y() -> f64 {
1509
+ engine().input.mouse_delta_y
1510
+ }
1511
+
1512
+ // Accumulated scroll wheel delta since the last call. Reading consumes the
1513
+ // value (returns 0 on the next call until the user scrolls again). Used by
1514
+ // the editor's orbit camera and any scrollable UI panel.
1515
+ #[no_mangle]
1516
+ pub extern "C" fn bloom_get_mouse_wheel() -> f64 {
1517
+ engine().input.consume_mouse_wheel()
1518
+ }
1519
+
1520
+ #[no_mangle]
1521
+ pub extern "C" fn bloom_get_char_pressed() -> f64 {
1522
+ engine().input.pop_char() as f64
1523
+ }
1524
+
1525
+ // Q2: Cursor shape
1526
+ #[no_mangle]
1527
+ pub extern "C" fn bloom_set_cursor_shape(shape: f64) {
1528
+ engine().input.cursor_shape = shape as u32;
1529
+ }
1530
+
1531
+ // E4: Clipboard (stub on this platform)
1532
+ #[no_mangle]
1533
+ pub extern "C" fn bloom_set_clipboard_text(_text_ptr: *const u8) {}
1534
+ #[no_mangle]
1535
+ pub extern "C" fn bloom_get_clipboard_text() -> *const u8 { std::ptr::null() }
1536
+
1537
+ // E5b: File dialogs (stub on this platform)
1538
+ #[no_mangle]
1539
+ pub extern "C" fn bloom_open_file_dialog(_filter_ptr: *const u8, _title_ptr: *const u8) -> *const u8 { std::ptr::null() }
1540
+ #[no_mangle]
1541
+ pub extern "C" fn bloom_save_file_dialog(_default_name_ptr: *const u8, _title_ptr: *const u8) -> *const u8 { std::ptr::null() }
1542
+
1543
+ // Model bounds accessors. Return the axis-aligned bounding box of a loaded
1544
+ // model in model-local coordinates. Editors use these to size gizmos, auto-
1545
+ // frame the camera on selection, and snap placed entities onto terrain.
1546
+ #[no_mangle]
1547
+ pub extern "C" fn bloom_get_model_bounds_min_x(model_handle: f64) -> f64 {
1548
+ engine().models.get_bounds(model_handle).0[0] as f64
1549
+ }
1550
+ #[no_mangle]
1551
+ pub extern "C" fn bloom_get_model_bounds_min_y(model_handle: f64) -> f64 {
1552
+ engine().models.get_bounds(model_handle).0[1] as f64
1553
+ }
1554
+ #[no_mangle]
1555
+ pub extern "C" fn bloom_get_model_bounds_min_z(model_handle: f64) -> f64 {
1556
+ engine().models.get_bounds(model_handle).0[2] as f64
1557
+ }
1558
+ #[no_mangle]
1559
+ pub extern "C" fn bloom_get_model_bounds_max_x(model_handle: f64) -> f64 {
1560
+ engine().models.get_bounds(model_handle).1[0] as f64
1561
+ }
1562
+ #[no_mangle]
1563
+ pub extern "C" fn bloom_get_model_bounds_max_y(model_handle: f64) -> f64 {
1564
+ engine().models.get_bounds(model_handle).1[1] as f64
1565
+ }
1566
+ #[no_mangle]
1567
+ pub extern "C" fn bloom_get_model_bounds_max_z(model_handle: f64) -> f64 {
1568
+ engine().models.get_bounds(model_handle).1[2] as f64
1569
+ }
1570
+
1571
+ #[no_mangle]
1572
+ pub extern "C" fn bloom_write_file(path_ptr: *const u8, data_ptr: *const u8) -> f64 {
1573
+ let path = str_from_header(path_ptr);
1574
+ let data = str_from_header(data_ptr);
1575
+ match std::fs::write(path, data.as_bytes()) {
1576
+ Ok(_) => 1.0,
1577
+ Err(_) => 0.0,
1578
+ }
1579
+ }
1580
+
1581
+ #[no_mangle]
1582
+ pub extern "C" fn bloom_file_exists(path_ptr: *const u8) -> f64 {
1583
+ let path = str_from_header(path_ptr);
1584
+ if std::path::Path::new(path).exists() { 1.0 } else { 0.0 }
1585
+ }
1586
+
1587
+ #[no_mangle]
1588
+ pub extern "C" fn bloom_read_file(path_ptr: *const u8) -> *const u8 {
1589
+ let path = str_from_header(path_ptr);
1590
+ match std::fs::read_to_string(path) {
1591
+ Ok(contents) => {
1592
+ // Return Perry-format string: StringHeader (length u32 + capacity u32 + refcount u32) followed by UTF-8 data
1593
+ let bytes = contents.as_bytes();
1594
+ let len = bytes.len();
1595
+ let total = 12 + len; // 12 bytes header (3 × u32) + data
1596
+ let layout = std::alloc::Layout::from_size_align(total, 4).unwrap();
1597
+ unsafe {
1598
+ let ptr = std::alloc::alloc(layout);
1599
+ if ptr.is_null() { return std::ptr::null(); }
1600
+ *(ptr as *mut u32) = len as u32; // length
1601
+ *(ptr.add(4) as *mut u32) = len as u32; // capacity
1602
+ *(ptr.add(8) as *mut u32) = 1; // refcount (unique)
1603
+ std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(12), len);
1604
+ ptr
1605
+ }
1606
+ }
1607
+ Err(_) => std::ptr::null(),
1608
+ }
1609
+ }
1610
+
1611
+ #[no_mangle]
1612
+ pub extern "C" fn bloom_get_touch_x(index: f64) -> f64 { engine().input.get_touch_x(index as usize) }
1613
+ #[no_mangle]
1614
+ pub extern "C" fn bloom_get_touch_y(index: f64) -> f64 { engine().input.get_touch_y(index as usize) }
1615
+ #[no_mangle]
1616
+ pub extern "C" fn bloom_get_touch_count() -> f64 { engine().input.get_touch_count() as f64 }
1617
+ #[no_mangle]
1618
+ pub extern "C" fn bloom_get_time() -> f64 { engine().get_time() }
1619
+
1620
+ // Input injection + platform detection
1621
+ #[no_mangle]
1622
+ pub extern "C" fn bloom_inject_key_down(key: f64) {
1623
+ engine().input.set_key_down(key as usize);
1624
+ }
1625
+ #[no_mangle]
1626
+ pub extern "C" fn bloom_inject_key_up(key: f64) {
1627
+ engine().input.set_key_up(key as usize);
1628
+ }
1629
+ #[no_mangle]
1630
+ pub extern "C" fn bloom_inject_gamepad_axis(axis: f64, value: f64) {
1631
+ engine().input.set_gamepad_axis(axis as usize, value as f32);
1632
+ }
1633
+ #[no_mangle]
1634
+ pub extern "C" fn bloom_inject_gamepad_button_down(button: f64) {
1635
+ engine().input.set_gamepad_button_down(button as usize);
1636
+ }
1637
+ #[no_mangle]
1638
+ pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
1639
+ engine().input.set_gamepad_button_up(button as usize);
1640
+ }
1641
+ #[no_mangle]
1642
+ pub extern "C" fn bloom_get_platform() -> f64 { 3.0 }
1643
+ #[no_mangle]
1644
+ pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
1645
+ if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
1646
+ }
1647
+ #[no_mangle]
1648
+ pub extern "C" fn bloom_get_crown_rotation() -> f64 {
1649
+ engine().input.consume_crown_rotation()
1650
+ }
1651
+
1652
+ // ============================================================
1653
+ // Thread-safe staging (for async asset loading via Perry threads)
1654
+ // ============================================================
1655
+
1656
+ #[no_mangle]
1657
+ pub extern "C" fn bloom_stage_texture(path_ptr: *const u8) -> f64 {
1658
+ let path = str_from_header(path_ptr);
1659
+ match std::fs::read(path) {
1660
+ Ok(data) => bloom_shared::staging::decode_and_stage_texture(&data),
1661
+ Err(_) => 0.0,
1662
+ }
1663
+ }
1664
+
1665
+ #[no_mangle]
1666
+ pub extern "C" fn bloom_stage_model(path_ptr: *const u8) -> f64 {
1667
+ let path = str_from_header(path_ptr);
1668
+ let data = match std::fs::read(path) {
1669
+ Ok(d) => d,
1670
+ Err(_) => return 0.0,
1671
+ };
1672
+ match bloom_shared::models::load_gltf_staged(&data) {
1673
+ Some(staged) => bloom_shared::staging::stage_model(staged),
1674
+ None => 0.0,
1675
+ }
1676
+ }
1677
+
1678
+ #[no_mangle]
1679
+ pub extern "C" fn bloom_stage_sound(path_ptr: *const u8) -> f64 {
1680
+ let path = str_from_header(path_ptr);
1681
+ let data = match std::fs::read(path) {
1682
+ Ok(d) => d,
1683
+ Err(_) => return 0.0,
1684
+ };
1685
+ let sound_data = if path.ends_with(".ogg") || path.ends_with(".OGG") {
1686
+ parse_ogg(&data)
1687
+ } else if path.ends_with(".mp3") || path.ends_with(".MP3") {
1688
+ parse_mp3(&data)
1689
+ } else {
1690
+ parse_wav(&data)
1691
+ };
1692
+ match sound_data {
1693
+ Some(sd) => bloom_shared::staging::stage_sound(sd),
1694
+ None => 0.0,
1695
+ }
1696
+ }
1697
+
1698
+ #[no_mangle]
1699
+ pub extern "C" fn bloom_commit_texture(staging_handle: f64) -> f64 {
1700
+ let staged = match bloom_shared::staging::take_texture(staging_handle) {
1701
+ Some(s) => s,
1702
+ None => return 0.0,
1703
+ };
1704
+ let eng = engine();
1705
+ let bind_group_idx = eng.renderer.register_texture(staged.width, staged.height, &staged.data);
1706
+ eng.textures.textures.alloc(bloom_shared::textures::TextureData {
1707
+ bind_group_idx, width: staged.width, height: staged.height,
1708
+ })
1709
+ }
1710
+
1711
+ #[no_mangle]
1712
+ pub extern "C" fn bloom_commit_model(staging_handle: f64) -> f64 {
1713
+ let staged = match bloom_shared::staging::take_model(staging_handle) {
1714
+ Some(s) => s,
1715
+ None => return 0.0,
1716
+ };
1717
+ let eng = engine();
1718
+ let mut tex_map: Vec<u32> = Vec::with_capacity(staged.textures.len());
1719
+ for tex in &staged.textures {
1720
+ tex_map.push(eng.renderer.register_texture(tex.width, tex.height, &tex.data));
1721
+ }
1722
+ let mut model = staged.model;
1723
+ for mesh in &mut model.meshes {
1724
+ if let Some(ref mut idx) = mesh.texture_idx {
1725
+ let staged_idx = *idx as usize;
1726
+ if staged_idx > 0 && staged_idx <= tex_map.len() {
1727
+ *idx = tex_map[staged_idx - 1];
1728
+ } else {
1729
+ mesh.texture_idx = None;
1730
+ }
1731
+ }
1732
+ }
1733
+ eng.models.models.alloc(model)
1734
+ }
1735
+
1736
+ #[no_mangle]
1737
+ pub extern "C" fn bloom_commit_sound(staging_handle: f64) -> f64 {
1738
+ match bloom_shared::staging::take_sound(staging_handle) {
1739
+ Some(sd) => engine().audio.load_sound(sd),
1740
+ None => 0.0,
1741
+ }
1742
+ }
1743
+
1744
+ #[no_mangle]
1745
+ pub extern "C" fn bloom_commit_music(staging_handle: f64) -> f64 {
1746
+ match bloom_shared::staging::take_sound(staging_handle) {
1747
+ Some(sd) => engine().audio.load_music(sd),
1748
+ None => 0.0,
1749
+ }
1750
+ }
1751
+
1752
+ fn pollster_block_on<F: std::future::Future>(future: F) -> F::Output {
1753
+ use std::task::{Context, Poll, Wake, Waker};
1754
+ use std::pin::Pin;
1755
+ use std::sync::Arc;
1756
+ struct NoopWaker;
1757
+ impl Wake for NoopWaker { fn wake(self: Arc<Self>) {} }
1758
+ let waker = Waker::from(Arc::new(NoopWaker));
1759
+ let mut cx = Context::from_waker(&waker);
1760
+ let mut future = unsafe { Pin::new_unchecked(Box::new(future)) };
1761
+ loop {
1762
+ match future.as_mut().poll(&mut cx) {
1763
+ Poll::Ready(result) => return result,
1764
+ Poll::Pending => std::thread::yield_now(),
1765
+ }
1766
+ }
1767
+ }
1768
+
1769
+ // 3D engine stubs — not yet implemented on Windows
1770
+ #[no_mangle] pub extern "C" fn bloom_register_frame_callback(_priority: f64, _callback: extern "C" fn(f64)) -> f64 { 0.0 }
1771
+ #[no_mangle] pub extern "C" fn bloom_unregister_frame_callback(_id: f64) {}
1772
+
1773
+ #[no_mangle]
1774
+ pub extern "C" fn bloom_run_game(_callback: extern "C" fn(f64)) {
1775
+ // No-op on native. The TypeScript runGame() helper provides the while loop.
1776
+ }
1777
+
1778
+ #[no_mangle] pub extern "C" fn bloom_add_directional_light(_dx: f64, _dy: f64, _dz: f64, _r: f64, _g: f64, _b: f64, _intensity: f64) {}
1779
+ #[no_mangle] pub extern "C" fn bloom_add_point_light(_x: f64, _y: f64, _z: f64, _range: f64, _r: f64, _g: f64, _b: f64, _intensity: f64) {}
1780
+ #[no_mangle] pub extern "C" fn bloom_scene_create_node() -> f64 { 0.0 }
1781
+ #[no_mangle] pub extern "C" fn bloom_scene_destroy_node(_handle: f64) {}
1782
+ #[no_mangle] pub extern "C" fn bloom_scene_set_visible(_handle: f64, _visible: f64) {}
1783
+ #[no_mangle] pub extern "C" fn bloom_scene_set_cast_shadow(_handle: f64, _cast: f64) {}
1784
+ #[no_mangle] pub extern "C" fn bloom_scene_set_receive_shadow(_handle: f64, _receive: f64) {}
1785
+ #[no_mangle] pub extern "C" fn bloom_scene_set_parent(_handle: f64, _parent: f64) {}
1786
+ #[no_mangle] pub extern "C" fn bloom_scene_set_transform(_handle: f64, _mat_ptr: *const f64) {}
1787
+ #[no_mangle] pub extern "C" fn bloom_scene_update_geometry(_handle: f64, _vert_ptr: *const f64, _vert_count: f64, _idx_ptr: *const f64, _idx_count: f64) {}
1788
+ #[no_mangle] pub extern "C" fn bloom_scene_set_material_color(_handle: f64, _r: f64, _g: f64, _b: f64, _a: f64) {}
1789
+ #[no_mangle] pub extern "C" fn bloom_scene_set_material_pbr(_handle: f64, _roughness: f64, _metalness: f64) {}
1790
+ #[no_mangle] pub extern "C" fn bloom_scene_set_material_texture(_handle: f64, _texture_idx: f64) {}
1791
+ #[no_mangle] pub extern "C" fn bloom_scene_node_count() -> f64 { 0.0 }
1792
+ #[no_mangle] pub extern "C" fn bloom_scene_node_vertex_count(_handle: f64) -> f64 { 0.0 }
1793
+ #[no_mangle] pub extern "C" fn bloom_scene_node_index_count(_handle: f64) -> f64 { 0.0 }
1794
+ #[no_mangle] pub extern "C" fn bloom_scene_extrude_polygon(_handle: f64, _polygon_ptr: *const f64, _polygon_count: f64, _depth: f64) {}
1795
+ #[no_mangle] pub extern "C" fn bloom_scene_subtract_box(_handle: f64, _min_x: f64, _min_y: f64, _min_z: f64, _max_x: f64, _max_y: f64, _max_z: f64) {}
1796
+ #[no_mangle] pub extern "C" fn bloom_enable_shadows() {}
1797
+ #[no_mangle] pub extern "C" fn bloom_disable_shadows() {}
1798
+ #[no_mangle] pub extern "C" fn bloom_enable_postfx() {}
1799
+ #[no_mangle] pub extern "C" fn bloom_disable_postfx() {}
1800
+ #[no_mangle] pub extern "C" fn bloom_postfx_set_selected(_handle: f64) {}
1801
+ #[no_mangle] pub extern "C" fn bloom_postfx_set_hovered(_handle: f64) {}
1802
+ #[no_mangle] pub extern "C" fn bloom_postfx_set_outline_color(_r: f64, _g: f64, _b: f64, _a: f64) {}
1803
+ #[no_mangle] pub extern "C" fn bloom_postfx_set_outline_thickness(_thickness: f64) {}
1804
+ #[no_mangle] pub extern "C" fn bloom_project_to_screen(_wx: f64, _wy: f64, _wz: f64) -> f64 { 0.0 }
1805
+ #[no_mangle] pub extern "C" fn bloom_project_screen_y() -> f64 { 0.0 }
1806
+ #[no_mangle] pub extern "C" fn bloom_scene_attach_model(_node_handle: f64, _model_handle: f64, _mesh_index: f64) {}
1807
+ #[no_mangle] pub extern "C" fn bloom_scene_pick(_screen_x: f64, _screen_y: f64) -> f64 { 0.0 }
1808
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_handle() -> f64 { 0.0 }
1809
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_distance() -> f64 { 0.0 }
1810
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_x() -> f64 { 0.0 }
1811
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_y() -> f64 { 0.0 }
1812
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_z() -> f64 { 0.0 }
1813
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_normal_x() -> f64 { 0.0 }
1814
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_normal_y() -> f64 { 0.0 }
1815
+ #[no_mangle] pub extern "C" fn bloom_pick_hit_normal_z() -> f64 { 0.0 }
1816
+
1817
+
1818
+ // Q6: Multi-hit picking
1819
+ static mut LAST_PICK_ALL: Vec<bloom_shared::picking::PickResult> = Vec::new();
1820
+
1821
+ #[no_mangle]
1822
+ pub extern "C" fn bloom_scene_pick_all(screen_x: f64, screen_y: f64, max_results: f64) -> f64 {
1823
+ let eng = engine();
1824
+ let inv_vp = eng.renderer.inverse_vp_matrix();
1825
+ let cam_pos = eng.renderer.camera_pos();
1826
+ let w = eng.renderer.width() as f32;
1827
+ let h = eng.renderer.height() as f32;
1828
+ let (origin, direction) = bloom_shared::picking::screen_to_ray(
1829
+ screen_x as f32, screen_y as f32, w, h, &inv_vp, &cam_pos,
1830
+ );
1831
+ let results = bloom_shared::picking::raycast_scene_all(&eng.scene, &origin, &direction, max_results as usize);
1832
+ let count = results.len();
1833
+ unsafe { LAST_PICK_ALL = results; }
1834
+ count as f64
1835
+ }
1836
+ #[no_mangle]
1837
+ pub extern "C" fn bloom_pick_all_handle(index: f64) -> f64 {
1838
+ let i = index as usize;
1839
+ unsafe { LAST_PICK_ALL.get(i).map(|r| r.handle).unwrap_or(0.0) }
1840
+ }
1841
+ #[no_mangle]
1842
+ pub extern "C" fn bloom_pick_all_distance(index: f64) -> f64 {
1843
+ let i = index as usize;
1844
+ unsafe { LAST_PICK_ALL.get(i).map(|r| r.distance as f64).unwrap_or(0.0) }
1845
+ }
1846
+ // ============================================================
1847
+
1848
+ // ============================================================
1849
+ // Render quality toggles (individual + preset) — ticket 011
1850
+ // Mirror of the macOS FFI surface added in commit 95da6af; previously
1851
+ // macOS-only, now exposed on every native platform so non-macOS builds
1852
+ // don't fail at runtime (missing symbol) when the TS API invokes them.
1853
+ // ============================================================
1854
+
1855
+ #[no_mangle]
1856
+ pub extern "C" fn bloom_set_quality_preset(preset: f64) {
1857
+ engine().renderer.apply_quality_preset(preset as u32);
1858
+ }
1859
+ #[no_mangle]
1860
+ pub extern "C" fn bloom_set_shadows_enabled(on: f64) {
1861
+ engine().renderer.set_shadows_enabled(on != 0.0);
1862
+ }
1863
+ #[no_mangle]
1864
+ pub extern "C" fn bloom_set_shadows_always_fresh(on: f64) {
1865
+ engine().renderer.set_shadows_always_fresh(on != 0.0);
1866
+ }
1867
+ #[no_mangle]
1868
+ pub extern "C" fn bloom_set_bloom_enabled(on: f64) {
1869
+ engine().renderer.set_bloom_enabled(on != 0.0);
1870
+ }
1871
+ #[no_mangle]
1872
+ pub extern "C" fn bloom_set_ssao_enabled(on: f64) {
1873
+ engine().renderer.set_ssao_enabled(on != 0.0);
1874
+ }
1875
+ #[no_mangle]
1876
+ pub extern "C" fn bloom_set_ssao_intensity(value: f64) {
1877
+ engine().renderer.set_ssao_strength(value as f32);
1878
+ }
1879
+ #[no_mangle]
1880
+ pub extern "C" fn bloom_set_ssao_radius(world_radius: f64) {
1881
+ engine().renderer.set_ssao_radius(world_radius as f32);
1882
+ }
1883
+ #[no_mangle]
1884
+ pub extern "C" fn bloom_set_wind(dir_x: f64, dir_z: f64, amplitude: f64, frequency: f64) {
1885
+ engine().renderer.set_wind(dir_x as f32, dir_z as f32, amplitude as f32, frequency as f32);
1886
+ }
1887
+ #[no_mangle]
1888
+ pub extern "C" fn bloom_set_ssr_enabled(on: f64) {
1889
+ engine().renderer.set_ssr_enabled(on != 0.0);
1890
+ }
1891
+ #[no_mangle]
1892
+ pub extern "C" fn bloom_set_motion_blur_enabled(on: f64) {
1893
+ engine().renderer.set_motion_blur_enabled(on != 0.0);
1894
+ }
1895
+ #[no_mangle]
1896
+ pub extern "C" fn bloom_set_sss_enabled(on: f64) {
1897
+ engine().renderer.set_sss_enabled(on != 0.0);
1898
+ }
1899
+
1900
+ // ============================================================
1901
+ // Profiler — CPU phase timings (always available) + GPU timestamps
1902
+ // (when the adapter supports TIMESTAMP_QUERY). Disabled by default.
1903
+ // ============================================================
1904
+
1905
+ #[no_mangle]
1906
+ pub extern "C" fn bloom_set_profiler_enabled(on: f64) {
1907
+ engine().profiler.set_enabled(on != 0.0);
1908
+ }
1909
+ #[no_mangle]
1910
+ pub extern "C" fn bloom_get_profiler_frame_cpu_us() -> f64 {
1911
+ engine().profiler.avg_frame_cpu_us()
1912
+ }
1913
+ #[no_mangle]
1914
+ pub extern "C" fn bloom_get_profiler_frame_gpu_us() -> f64 {
1915
+ engine().profiler.avg_frame_gpu_us()
1916
+ }
1917
+ #[no_mangle]
1918
+ pub extern "C" fn bloom_print_profiler_summary() {
1919
+ print!("{}", engine().profiler.summary());
1920
+ }
1921
+
1922
+ // ============================================================
1923
+ // Physics (Jolt 5.x) — FFI surface generated from shared macro
1924
+ // ============================================================
1925
+
1926
+ #[cfg(feature = "jolt")]
1927
+ #[inline]
1928
+ fn bloom_jolt_ffi_physics() -> &'static mut bloom_shared::physics_jolt::JoltPhysics {
1929
+ &mut engine().jolt
1930
+ }
1931
+
1932
+ #[cfg(feature = "jolt")]
1933
+ bloom_shared::define_physics_ffi!();