@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,1236 @@
1
+ // BloomWatchApp — SwiftUI @main for bloom-backed watchOS games.
2
+ //
3
+ // Compiled by Perry when --features watchos-swift-app is on. Owns the process
4
+ // entry (@main), spawns the game thread calling _perry_user_main, and renders
5
+ // the bloom draw list through a SwiftUI Canvas. Input (Digital Crown + taps)
6
+ // feeds back into bloom via the C hooks in lib.rs.
7
+
8
+ import SwiftUI
9
+ import Foundation
10
+ import SceneKit
11
+ import ImageIO
12
+
13
+ // MARK: - FFI into the Rust side
14
+
15
+ // Perry's --features watchos-swift-app renames C-level `main` → `perry_user_main`
16
+ // (one Mach-O underscore is added by the linker; Swift's @_silgen_name adds
17
+ // another, matching the `__perry_user_main` actually emitted in the object).
18
+ @_silgen_name("_perry_user_main") func _perry_user_main()
19
+
20
+ // Inbound (Swift → Rust) — input and layout
21
+ @_silgen_name("bloom_watchos_crown_delta") func bloom_watchos_crown_delta(_ delta: Double)
22
+ @_silgen_name("bloom_watchos_touch") func bloom_watchos_touch(_ idx: Int64, _ x: Double, _ y: Double, _ active: Int64)
23
+ @_silgen_name("bloom_watchos_set_screen") func bloom_watchos_set_screen(_ w: Double, _ h: Double)
24
+ @_silgen_name("bloom_watchos_set_bundle_path") func bloom_watchos_set_bundle_path(_ path: UnsafePointer<CChar>)
25
+
26
+ // Outbound (Rust → Swift) — draw list snapshot
27
+ @_silgen_name("bloom_watchos_frame_count") func bloom_watchos_frame_count() -> UInt64
28
+ @_silgen_name("bloom_watchos_copy_draw_list") func bloom_watchos_copy_draw_list(_ dst: UnsafeMutablePointer<DrawCmd>, _ max: Int64) -> Int64
29
+ @_silgen_name("bloom_watchos_clear_color") func bloom_watchos_clear_color(_ out: UnsafeMutablePointer<Double>)
30
+ @_silgen_name("bloom_watchos_texture_path") func bloom_watchos_texture_path(_ handle: UInt32) -> UnsafePointer<CChar>?
31
+
32
+ // 3D camera + gate
33
+ @_silgen_name("bloom_watchos_camera_state") func bloom_watchos_camera_state(_ out: UnsafeMutablePointer<Double>)
34
+ @_silgen_name("bloom_watchos_has_3d") func bloom_watchos_has_3d() -> Double
35
+
36
+ // Retained scene graph accessors
37
+ @_silgen_name("bloom_watchos_scene_drain_dirty") func bloom_watchos_scene_drain_dirty(_ dst: UnsafeMutablePointer<SceneNodeInfo>, _ max: Int64) -> Int64
38
+ @_silgen_name("bloom_watchos_scene_drain_destroyed") func bloom_watchos_scene_drain_destroyed(_ dst: UnsafeMutablePointer<UInt32>, _ max: Int64) -> Int64
39
+
40
+ // Mirrors scene.rs DIRTY_* constants.
41
+ let DIRTY_TRANSFORM: UInt32 = 1 << 0
42
+ let DIRTY_MATERIAL: UInt32 = 1 << 1
43
+ let DIRTY_VISIBILITY: UInt32 = 1 << 2
44
+ let DIRTY_PARENT: UInt32 = 1 << 3
45
+ let DIRTY_GEOMETRY: UInt32 = 1 << 4
46
+ let DIRTY_SKIN: UInt32 = 1 << 5
47
+ @_silgen_name("bloom_watchos_scene_copy_lights") func bloom_watchos_scene_copy_lights(_ dst: UnsafeMutablePointer<SceneLight>, _ max: Int64) -> Int64
48
+ @_silgen_name("bloom_watchos_scene_geometry") func bloom_watchos_scene_geometry(_ handle: UInt32, _ out: UnsafeMutablePointer<SceneGeometryPtrs>)
49
+ @_silgen_name("bloom_watchos_scene_skin") func bloom_watchos_scene_skin(_ handle: UInt32, _ out: UnsafeMutablePointer<SceneSkinPtrs>)
50
+ @_silgen_name("bloom_watchos_scene_anim_track_count") func bloom_watchos_scene_anim_track_count(_ handle: UInt32) -> Int64
51
+ @_silgen_name("bloom_watchos_scene_anim_track_info") func bloom_watchos_scene_anim_track_info(_ handle: UInt32, _ idx: Int64, _ out: UnsafeMutablePointer<AnimTrackInfo>)
52
+
53
+ struct AnimTrackInfo {
54
+ var boneHandle: UInt32 = 0
55
+ var path: UInt32 = 0 // 0 = translation, 1 = rotation, 2 = scale
56
+ var keyCount: UInt32 = 0
57
+ var _pad: UInt32 = 0
58
+ var times: UnsafePointer<Float>? = nil
59
+ var values: UnsafePointer<Float>? = nil
60
+ }
61
+
62
+ struct SceneSkinPtrs {
63
+ var jointHandles: UnsafePointer<UInt32>? = nil
64
+ var jointCount: UInt32 = 0
65
+ var inverseBind: UnsafePointer<Float>? = nil
66
+ var inverseBindMatrixCount: UInt32 = 0
67
+ var vertexJoints: UnsafePointer<UInt32>? = nil
68
+ var vertexJointCount: UInt32 = 0
69
+ var vertexWeights: UnsafePointer<Float>? = nil
70
+ var vertexWeightCount: UInt32 = 0
71
+ }
72
+
73
+ // Post-FX state
74
+ @_silgen_name("bloom_watchos_postfx_state") func bloom_watchos_postfx_state(_ out: UnsafeMutablePointer<PostFxState>)
75
+
76
+ struct PostFxState {
77
+ var enabled: UInt32 = 1
78
+ var autoExposure: UInt32 = 0
79
+ var vignetteStrength: Float = 0
80
+ var vignetteSoftness: Float = 0
81
+ var chromaticAberration: Float = 0
82
+ var filmGrain: Float = 0
83
+ var exposure: Float = 1
84
+ var sunStrength: Float = 0
85
+ var sunDecay: Float = 0.85
86
+ var sunR: Float = 1.0
87
+ var sunG: Float = 0.9
88
+ var sunB: Float = 0.7
89
+ }
90
+
91
+ // SceneNodeInfo — must match Rust's #[repr(C)] struct in scene.rs.
92
+ struct SceneNodeInfo {
93
+ var dirtyFlags: UInt32 = 0
94
+ var handle: UInt32 = 0
95
+ var parent: UInt32 = 0
96
+ var visible: UInt32 = 0
97
+ var geometryVersion: UInt32 = 0
98
+
99
+ var color: (Float, Float, Float, Float) = (1, 1, 1, 1)
100
+ var roughness: Float = 0
101
+ var metalness: Float = 0
102
+ var texture: UInt32 = 0
103
+ var hasGeometry: UInt32 = 0
104
+
105
+ var transform: (
106
+ Float, Float, Float, Float,
107
+ Float, Float, Float, Float,
108
+ Float, Float, Float, Float,
109
+ Float, Float, Float, Float
110
+ ) = (1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)
111
+
112
+ // PBR texture slots (0 = unset).
113
+ var texBaseColor: UInt32 = 0
114
+ var texNormal: UInt32 = 0
115
+ var texMetallicRoughness: UInt32 = 0
116
+ var texEmissive: UInt32 = 0
117
+ var texOcclusion: UInt32 = 0
118
+ // Bumps when bloom sets skin data on this node. 0 = not skinned.
119
+ var skinVersion: UInt32 = 0
120
+ }
121
+
122
+ struct SceneLight {
123
+ var kind: UInt32 = 0
124
+ var _pad: UInt32 = 0
125
+ var posOrDir: (Float, Float, Float) = (0, 0, 0)
126
+ var range: Float = 0
127
+ var color: (Float, Float, Float) = (1, 1, 1)
128
+ var intensity: Float = 0
129
+ }
130
+
131
+ struct SceneGeometryPtrs {
132
+ var positions: UnsafePointer<Float>? = nil
133
+ var positionCount: UInt32 = 0
134
+ var normals: UnsafePointer<Float>? = nil
135
+ var normalCount: UInt32 = 0
136
+ var uvs: UnsafePointer<Float>? = nil
137
+ var uvCount: UInt32 = 0
138
+ var indices: UnsafePointer<UInt32>? = nil
139
+ var indexCount: UInt32 = 0
140
+ }
141
+
142
+ // MARK: - DrawCmd mirror (must match draw_list.rs #[repr(C)])
143
+
144
+ let TEXT_CAP = 256
145
+
146
+ struct DrawCmd {
147
+ var kind: Int32 = 0
148
+ var _pad0: Int32 = 0
149
+ var tex: UInt32 = 0
150
+ var _pad1: UInt32 = 0
151
+ var x: Double = 0, y: Double = 0, w: Double = 0, h: Double = 0
152
+ var srcX: Double = 0, srcY: Double = 0, srcW: Double = 0, srcH: Double = 0
153
+ var ox: Double = 0, oy: Double = 0
154
+ var r: Double = 255, g: Double = 255, b: Double = 255, a: Double = 255
155
+ var rot: Double = 0, size: Double = 0, thickness: Double = 1, _pad2: Double = 0
156
+ // Inline UTF-8 text — 256 bytes expressed as a 32-tuple of UInt64.
157
+ var t00: UInt64 = 0, t01: UInt64 = 0, t02: UInt64 = 0, t03: UInt64 = 0
158
+ var t04: UInt64 = 0, t05: UInt64 = 0, t06: UInt64 = 0, t07: UInt64 = 0
159
+ var t08: UInt64 = 0, t09: UInt64 = 0, t10: UInt64 = 0, t11: UInt64 = 0
160
+ var t12: UInt64 = 0, t13: UInt64 = 0, t14: UInt64 = 0, t15: UInt64 = 0
161
+ var t16: UInt64 = 0, t17: UInt64 = 0, t18: UInt64 = 0, t19: UInt64 = 0
162
+ var t20: UInt64 = 0, t21: UInt64 = 0, t22: UInt64 = 0, t23: UInt64 = 0
163
+ var t24: UInt64 = 0, t25: UInt64 = 0, t26: UInt64 = 0, t27: UInt64 = 0
164
+ var t28: UInt64 = 0, t29: UInt64 = 0, t30: UInt64 = 0, t31: UInt64 = 0
165
+ var textLen: UInt64 = 0
166
+ }
167
+
168
+ // Command kinds — keep in sync with draw_list::kind.
169
+ let K_RECT: Int32 = 1
170
+ let K_RECT_LINES: Int32 = 2
171
+ let K_CIRCLE: Int32 = 3
172
+ let K_CIRCLE_LINES: Int32 = 4
173
+ let K_LINE: Int32 = 5
174
+ let K_TRIANGLE: Int32 = 6
175
+ let K_TEXTURE: Int32 = 7
176
+ let K_TEXTURE_REC: Int32 = 8
177
+ let K_TEXTURE_PRO: Int32 = 9
178
+ let K_TEXT: Int32 = 10
179
+
180
+ // 3D primitives
181
+ let K_CUBE: Int32 = 20
182
+ let K_CUBE_WIRES: Int32 = 21
183
+ let K_SPHERE: Int32 = 22
184
+ let K_SPHERE_WIRES: Int32 = 23
185
+ let K_CYLINDER: Int32 = 24
186
+ let K_PLANE: Int32 = 25
187
+ let K_GRID: Int32 = 26
188
+
189
+ /// Decode the inline UTF-8 bytes at the struct's text region into a String.
190
+ /// Takes a pointer into the underlying draw-list buffer so we read the real
191
+ /// bytes, not a stack-copied value (Swift's withUnsafePointer(to:) on a let
192
+ /// field gives a local copy, which truncates anything past 8 bytes).
193
+ func cmdTextString(_ ptr: UnsafePointer<DrawCmd>) -> String {
194
+ let n = Int(min(ptr.pointee.textLen, UInt64(TEXT_CAP)))
195
+ if n == 0 { return "" }
196
+ return UnsafeRawPointer(ptr)
197
+ .advanced(by: MemoryLayout<DrawCmd>.offset(of: \.t00)!)
198
+ .withMemoryRebound(to: UInt8.self, capacity: n) { p in
199
+ let buf = UnsafeBufferPointer(start: p, count: n)
200
+ return String(decoding: buf, as: UTF8.self)
201
+ }
202
+ }
203
+
204
+ // MARK: - Texture cache (handle → CGImage)
205
+
206
+ final class TextureCache {
207
+ static let shared = TextureCache()
208
+ private var cache: [UInt32: CGImage] = [:]
209
+ private let lock = NSLock()
210
+
211
+ func image(for handle: UInt32) -> CGImage? {
212
+ lock.lock()
213
+ defer { lock.unlock() }
214
+ if let img = cache[handle] { return img }
215
+ guard let cpath = bloom_watchos_texture_path(handle) else { return nil }
216
+ let path = String(cString: cpath)
217
+ let url = URL(fileURLWithPath: path)
218
+ // Use CGImageSource so we transparently load PNG, JPEG, and anything
219
+ // else ImageIO understands — the glTF loader embeds JPEGs too.
220
+ guard let src = CGImageSourceCreateWithURL(url as CFURL, nil),
221
+ let img = CGImageSourceCreateImageAtIndex(src, 0, nil)
222
+ else { return nil }
223
+ cache[handle] = img
224
+ return img
225
+ }
226
+ }
227
+
228
+ // MARK: - @main
229
+
230
+ @main
231
+ struct BloomWatchApp: App {
232
+ init() {
233
+ // Hand bloom the bundle resource path so bloom_load_texture can
234
+ // resolve relative asset paths. Must happen before the game thread
235
+ // starts loading anything.
236
+ if let res = Bundle.main.resourcePath {
237
+ res.withCString { bloom_watchos_set_bundle_path($0) }
238
+ }
239
+ // Spawn the game thread. _perry_user_main blocks in runGame's while
240
+ // loop, so this must not run on the main thread.
241
+ let t = Thread(block: { _perry_user_main() })
242
+ t.name = "bloom-game"
243
+ t.stackSize = 2 * 1024 * 1024
244
+ t.start()
245
+ }
246
+
247
+ var body: some Scene {
248
+ WindowGroup {
249
+ BloomRootView()
250
+ }
251
+ }
252
+ }
253
+
254
+ // MARK: - Root view
255
+
256
+ struct BloomRootView: View {
257
+ // Accumulated crown value (Digital Crown is delta-based in SwiftUI).
258
+ @State private var crown: Double = 0.0
259
+ @State private var lastCrown: Double = 0.0
260
+ // Frame tick — incremented when bloom's frame counter changes. Triggers
261
+ // Canvas redraw.
262
+ @State private var frameTick: UInt64 = 0
263
+ // Reusable snapshot buffer to avoid per-frame allocation. 4096 cmds is
264
+ // generous for a watch-sized game.
265
+ @State private var drawBuf: UnsafeMutableBufferPointer<DrawCmd> = {
266
+ let p = UnsafeMutablePointer<DrawCmd>.allocate(capacity: 4096)
267
+ p.initialize(repeating: DrawCmd(), count: 4096)
268
+ return UnsafeMutableBufferPointer(start: p, count: 4096)
269
+ }()
270
+ @State private var fx: PostFxState = PostFxState()
271
+
272
+ let refresh = Timer.publish(every: 1.0 / 30.0, on: .main, in: .common).autoconnect()
273
+
274
+ var body: some View {
275
+ GeometryReader { geo in
276
+ ZStack {
277
+ // 3D layer — SceneView is always present so the first
278
+ // bloom_begin_mode_3d call can light it up without view
279
+ // reconstruction. The scene is empty (transparent) until a
280
+ // 3D command arrives.
281
+ BloomSceneView(frameTick: frameTick, drawBuf: drawBuf, fx: fx, viewSize: geo.size)
282
+ .ignoresSafeArea()
283
+
284
+ // 2D overlay — Canvas drives drawing from the snapshot and
285
+ // owns input because Canvas is the topmost responder.
286
+ Canvas { ctx, size in
287
+ _ = frameTick
288
+
289
+ // Clear (only when there's no 3D layer — otherwise the
290
+ // SceneView's clear owns the background and this would
291
+ // paint over it).
292
+ if bloom_watchos_has_3d() < 0.5 {
293
+ var cc = [Double](repeating: 0, count: 4)
294
+ cc.withUnsafeMutableBufferPointer { buf in
295
+ bloom_watchos_clear_color(buf.baseAddress!)
296
+ }
297
+ ctx.fill(
298
+ Path(CGRect(origin: .zero, size: size)),
299
+ with: .color(Color(.sRGB,
300
+ red: cc[0] / 255.0,
301
+ green: cc[1] / 255.0,
302
+ blue: cc[2] / 255.0,
303
+ opacity: cc[3] / 255.0))
304
+ )
305
+ }
306
+
307
+ // Pull this frame's commands. 2D draws render here; 3D
308
+ // commands are filtered by BloomSceneView.
309
+ let n = Int(bloom_watchos_copy_draw_list(drawBuf.baseAddress!, 4096))
310
+ for i in 0..<n {
311
+ let ptr = drawBuf.baseAddress!.advanced(by: i)
312
+ let k = ptr.pointee.kind
313
+ if k >= 20 && k <= 29 { continue } // 3D — handled by SceneView
314
+ drawOne(ctx: ctx, cmdPtr: ptr)
315
+ }
316
+ }
317
+ }
318
+ .onAppear {
319
+ bloom_watchos_set_screen(Double(geo.size.width), Double(geo.size.height))
320
+ }
321
+ .onChange(of: geo.size) { _, new in
322
+ bloom_watchos_set_screen(Double(new.width), Double(new.height))
323
+ }
324
+ .focusable()
325
+ .digitalCrownRotation(
326
+ $crown,
327
+ from: -1_000_000.0, through: 1_000_000.0, by: 0.001,
328
+ sensitivity: .medium,
329
+ isContinuous: true,
330
+ isHapticFeedbackEnabled: false
331
+ )
332
+ .onChange(of: crown) { _, new in
333
+ bloom_watchos_crown_delta(new - lastCrown)
334
+ lastCrown = new
335
+ }
336
+ .onTapGesture(coordinateSpace: .local) { loc in
337
+ bloom_watchos_touch(0, Double(loc.x), Double(loc.y), 1)
338
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.08) {
339
+ bloom_watchos_touch(0, Double(loc.x), Double(loc.y), 0)
340
+ }
341
+ }
342
+ .onReceive(refresh) { _ in
343
+ let f = bloom_watchos_frame_count()
344
+ if f != frameTick {
345
+ frameTick = f
346
+ withUnsafeMutablePointer(to: &fx) { bloom_watchos_postfx_state($0) }
347
+ }
348
+ }
349
+ // Post-FX modifiers — applied only when fx.enabled is set. Each
350
+ // effect also checks its own strength before costing anything.
351
+ .brightness(fx.enabled != 0 && fx.autoExposure == 0 ? Double(fx.exposure - 1.0) : 0)
352
+ .overlay {
353
+ if fx.enabled != 0 && fx.vignetteStrength > 0.001 {
354
+ // Vignette stays on pure SwiftUI — cheaper than a shader
355
+ // and identical visually.
356
+ let soft = max(0.0, min(0.95, Double(fx.vignetteSoftness)))
357
+ let str = min(1.0, Double(fx.vignetteStrength))
358
+ Canvas { ctx, size in
359
+ let c = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
360
+ let r = max(size.width, size.height) * 0.75
361
+ let g = Gradient(stops: [
362
+ .init(color: .black.opacity(0), location: soft),
363
+ .init(color: .black.opacity(str), location: 1.0),
364
+ ])
365
+ ctx.fill(
366
+ Path(CGRect(origin: .zero, size: size)),
367
+ with: .radialGradient(g, center: c, startRadius: 0, endRadius: r)
368
+ )
369
+ }
370
+ .allowsHitTesting(false)
371
+ }
372
+ }
373
+ }
374
+ .ignoresSafeArea()
375
+ .background(Color.black)
376
+ }
377
+ }
378
+
379
+ // MARK: - Metal-shader post-FX
380
+ //
381
+ // default.metallib is compiled + bundled by Perry (PerryTS/perry#124) and
382
+ // contains three [[ stitchable ]] shader functions (bloom_chromatic_aberration,
383
+ // bloom_film_grain, bloom_sun_shafts).
384
+ //
385
+ // HOWEVER: SwiftUI's Shader-consumer modifiers —
386
+ // `.colorEffect(Shader)` / `.layerEffect(Shader)` / `ShaderLibrary` —
387
+ // are iOS 17+ / tvOS 17+ / macOS 14+ ONLY. Apple explicitly did not ship
388
+ // them on watchOS, so even though the .metallib sits in the bundle
389
+ // (ShaderLibrary.default would resolve it correctly), there's no way to
390
+ // attach the shaders to a view on the watch today.
391
+ //
392
+ // Paths forward when we revisit:
393
+ // 1. SCNTechnique — SceneKit's pass-based Metal post-process. Works on
394
+ // watchOS and can load from default.metallib, but only applies to the
395
+ // SceneKit layer (not the 2D Canvas overlay). Follow-up ticket.
396
+ // 2. Raw MTLCommandQueue offscreen render + present through a custom
397
+ // SwiftUI view bridge — much more invasive, probably not worth it.
398
+ // 3. Wait for Apple to ship SwiftUI Shader support on watchOS (filed as
399
+ // a Feedback, no ETA).
400
+ //
401
+ // Today vignette + exposure continue to use pure-SwiftUI modifiers above.
402
+
403
+ // MARK: - 3D layer (SceneKit)
404
+
405
+ /// SceneView wrapper that rebuilds the SCNScene each frame from bloom's
406
+ /// immediate-mode 3D draw commands. Retained-mode scene graph (bloom_scene_*)
407
+ /// would use a delta-sync path — deferred until the retained API lands for
408
+ /// watchOS.
409
+ struct BloomSceneView: View {
410
+ let frameTick: UInt64
411
+ let drawBuf: UnsafeMutableBufferPointer<DrawCmd>
412
+ /// Caller passes the current PostFx state so we can keep the technique's
413
+ /// uniforms in sync each frame.
414
+ let fx: PostFxState
415
+ let viewSize: CGSize
416
+
417
+ @State private var scene: SCNScene = makeBaseScene()
418
+ @State private var contentRoot: SCNNode = SCNNode() // immediate-mode per-frame draws
419
+ @State private var retainedRoot: SCNNode = SCNNode() // bloom_scene_* retained nodes
420
+ @State private var lightsRoot: SCNNode = SCNNode() // bloom_add_*_light instances
421
+ @State private var cameraNode: SCNNode = SCNNode()
422
+ /// Built once from default.metallib. Uniforms are pushed per frame in
423
+ /// rebuild(); the technique itself is reused (rebuilding the dict each
424
+ /// frame would churn SceneKit's pipeline cache).
425
+ @State private var fxTechnique: SCNTechnique? = BloomPostFXTechnique.shared
426
+
427
+ /// Cache of SCNNodes for retained scene graph, keyed by bloom handle.
428
+ @State private var retainedNodes: [UInt32: SCNNode] = [:]
429
+ /// Geometry cache keyed by (handle, geometryVersion) so unchanged meshes
430
+ /// aren't rebuilt each frame.
431
+ @State private var retainedGeomVersions: [UInt32: UInt32] = [:]
432
+ /// Same pattern for skinning — we only rebuild SCNSkinner when the
433
+ /// bloom-side skin_version changes, since SCNSkinner carries GPU
434
+ /// resources and rebuilding every frame would churn them.
435
+ @State private var retainedSkinVersions: [UInt32: UInt32] = [:]
436
+
437
+ @State private var nodeBuf: UnsafeMutableBufferPointer<SceneNodeInfo> = {
438
+ let p = UnsafeMutablePointer<SceneNodeInfo>.allocate(capacity: 1024)
439
+ p.initialize(repeating: SceneNodeInfo(), count: 1024)
440
+ return UnsafeMutableBufferPointer(start: p, count: 1024)
441
+ }()
442
+ @State private var lightBuf: UnsafeMutableBufferPointer<SceneLight> = {
443
+ let p = UnsafeMutablePointer<SceneLight>.allocate(capacity: 64)
444
+ p.initialize(repeating: SceneLight(), count: 64)
445
+ return UnsafeMutableBufferPointer(start: p, count: 64)
446
+ }()
447
+
448
+ var body: some View {
449
+ SceneView(
450
+ scene: scene,
451
+ pointOfView: cameraNode,
452
+ options: [.rendersContinuously],
453
+ preferredFramesPerSecond: 30,
454
+ antialiasingMode: .none,
455
+ delegate: nil,
456
+ technique: anyEffectActive ? fxTechnique : nil
457
+ )
458
+ .onAppear {
459
+ if contentRoot.parent == nil {
460
+ scene.rootNode.addChildNode(contentRoot)
461
+ }
462
+ if retainedRoot.parent == nil {
463
+ scene.rootNode.addChildNode(retainedRoot)
464
+ }
465
+ if lightsRoot.parent == nil {
466
+ scene.rootNode.addChildNode(lightsRoot)
467
+ }
468
+ if cameraNode.parent == nil {
469
+ cameraNode.camera = SCNCamera()
470
+ scene.rootNode.addChildNode(cameraNode)
471
+ }
472
+ rebuild()
473
+ }
474
+ .onChange(of: frameTick) { _, _ in rebuild() }
475
+ }
476
+
477
+ /// True when at least one Metal-shader effect is on. Toggles whether
478
+ /// SceneView gets handed the technique at all — when nothing is enabled
479
+ /// SceneKit takes its default no-post-process path.
480
+ private var anyEffectActive: Bool {
481
+ fx.enabled != 0 && (
482
+ fx.chromaticAberration > 0.001 ||
483
+ fx.filmGrain > 0.001 ||
484
+ fx.sunStrength > 0.001
485
+ )
486
+ }
487
+
488
+ private func rebuild() {
489
+ // If the game hasn't opened a 3D section, hide the scene entirely.
490
+ if bloom_watchos_has_3d() < 0.5 {
491
+ contentRoot.isHidden = true
492
+ return
493
+ }
494
+ contentRoot.isHidden = false
495
+
496
+ // Clear previous frame's primitives. Reusing the same contentRoot
497
+ // avoids churn at the SCNScene.rootNode level.
498
+ contentRoot.childNodes.forEach { $0.removeFromParentNode() }
499
+
500
+ // Camera.
501
+ var camS = [Double](repeating: 0, count: 11)
502
+ camS.withUnsafeMutableBufferPointer { buf in bloom_watchos_camera_state(buf.baseAddress!) }
503
+ let px = camS[0], py = camS[1], pz = camS[2]
504
+ let tx = camS[3], ty = camS[4], tz = camS[5]
505
+ let fovy = camS[9], proj = camS[10]
506
+ cameraNode.position = SCNVector3(x: Float(px), y: Float(py), z: Float(pz))
507
+ // Guard against look(at: self.position) which produces a NaN orientation.
508
+ if abs(px - tx) < 1e-6 && abs(py - ty) < 1e-6 && abs(pz - tz) < 1e-6 {
509
+ // No explicit target — point down -Z like a default game camera.
510
+ cameraNode.eulerAngles = SCNVector3(0, 0, 0)
511
+ } else {
512
+ cameraNode.look(at: SCNVector3(x: Float(tx), y: Float(ty), z: Float(tz)))
513
+ }
514
+ if let cam = cameraNode.camera {
515
+ cam.fieldOfView = CGFloat(fovy)
516
+ cam.usesOrthographicProjection = proj < 0.5
517
+ cam.zNear = 0.01
518
+ cam.zFar = 10000
519
+ }
520
+
521
+ // Clear color for SceneKit background.
522
+ var cc = [Double](repeating: 0, count: 4)
523
+ cc.withUnsafeMutableBufferPointer { buf in bloom_watchos_clear_color(buf.baseAddress!) }
524
+ scene.background.contents = UIColor(
525
+ red: CGFloat(cc[0] / 255.0),
526
+ green: CGFloat(cc[1] / 255.0),
527
+ blue: CGFloat(cc[2] / 255.0),
528
+ alpha: CGFloat(cc[3] / 255.0)
529
+ )
530
+
531
+ // Walk the draw list for 3D commands only.
532
+ let n = Int(bloom_watchos_copy_draw_list(drawBuf.baseAddress!, 4096))
533
+ for i in 0..<n {
534
+ let cmd = drawBuf[i]
535
+ if cmd.kind < 20 || cmd.kind > 29 { continue }
536
+ if let node = makeSceneNode(for: cmd) {
537
+ contentRoot.addChildNode(node)
538
+ }
539
+ }
540
+
541
+ // Retained scene graph — delta-sync against the cached handle→SCNNode map.
542
+ syncRetainedNodes()
543
+ syncLights()
544
+ advanceAnimations()
545
+
546
+ // Push current PostFx state into the technique's uniform buffer so
547
+ // chromatic aberration / film grain / sun shafts all sample the
548
+ // up-to-date strengths and animation time.
549
+ if let tech = fxTechnique, anyEffectActive {
550
+ BloomPostFXTechnique.update(tech, fx: fx, viewSize: viewSize)
551
+ }
552
+ }
553
+
554
+ private func syncRetainedNodes() {
555
+ // Step 1: retire destroyed nodes first so their handles don't collide
556
+ // with new-node creations that may reuse slots.
557
+ var destroyed: [UInt32] = Array(repeating: 0, count: 256)
558
+ destroyed.withUnsafeMutableBufferPointer { buf in
559
+ while true {
560
+ let n = Int(bloom_watchos_scene_drain_destroyed(buf.baseAddress!, Int64(buf.count)))
561
+ if n == 0 { break }
562
+ for i in 0..<n {
563
+ let h = buf[i]
564
+ if let node = retainedNodes.removeValue(forKey: h) {
565
+ node.removeFromParentNode()
566
+ }
567
+ retainedGeomVersions.removeValue(forKey: h)
568
+ retainedSkinVersions.removeValue(forKey: h)
569
+ cachedAnimTracks.removeValue(forKey: h)
570
+ cachedAnimDuration.removeValue(forKey: h)
571
+ }
572
+ if n < buf.count { break }
573
+ }
574
+ }
575
+
576
+ // Step 2: drain dirty nodes. Each drain call reports nodes with
577
+ // non-zero dirty_flags and clears them, so we pull until empty. For
578
+ // a static scene this returns 0 on the first call — O(0) sync cost.
579
+ var allDirty: [SceneNodeInfo] = []
580
+ while true {
581
+ let count = Int(bloom_watchos_scene_drain_dirty(nodeBuf.baseAddress!, 1024))
582
+ if count == 0 { break }
583
+ for i in 0..<count { allDirty.append(nodeBuf[i]) }
584
+ if count < 1024 { break }
585
+ }
586
+
587
+ // Step 3: pass 1 — create-or-update nodes, apply dirty fields only.
588
+ for info in allDirty {
589
+ let node: SCNNode
590
+ if let existing = retainedNodes[info.handle] {
591
+ node = existing
592
+ } else {
593
+ node = SCNNode()
594
+ retainedNodes[info.handle] = node
595
+ retainedRoot.addChildNode(node)
596
+ }
597
+
598
+ if info.dirtyFlags & DIRTY_VISIBILITY != 0 {
599
+ node.isHidden = info.visible == 0
600
+ }
601
+ if info.dirtyFlags & DIRTY_TRANSFORM != 0 {
602
+ node.transform = scnMatrix4(from: info.transform)
603
+ }
604
+
605
+ if info.dirtyFlags & DIRTY_GEOMETRY != 0 {
606
+ let cached = retainedGeomVersions[info.handle] ?? .max
607
+ if info.hasGeometry != 0 && cached != info.geometryVersion {
608
+ node.geometry = buildGeometry(handle: info.handle)
609
+ retainedGeomVersions[info.handle] = info.geometryVersion
610
+ }
611
+ }
612
+
613
+ // Skinning: rebuild SCNSkinner when skin_version changes. Bones
614
+ // may not all exist in retainedNodes yet on the first sync — if
615
+ // so, buildSkinner returns nil and we retry on the next tick
616
+ // when all nodes have been created.
617
+ if info.dirtyFlags & DIRTY_SKIN != 0,
618
+ retainedSkinVersions[info.handle] != info.skinVersion {
619
+ if let skinner = buildSkinner(mesh: node, handle: info.handle) {
620
+ node.skinner = skinner
621
+ attachAnimations(handle: info.handle)
622
+ retainedSkinVersions[info.handle] = info.skinVersion
623
+ }
624
+ }
625
+
626
+ if info.dirtyFlags & DIRTY_MATERIAL != 0, let g = node.geometry {
627
+ let m = g.firstMaterial ?? SCNMaterial()
628
+ // PBR needs per-vertex normals. Some glTF exports (e.g. Fox)
629
+ // omit NORMAL entirely — fall back to constant lighting so
630
+ // the mesh still shows its base color / texture instead of
631
+ // rendering pitch black.
632
+ let hasNormals = g.sources(for: .normal).count > 0
633
+ m.lightingModel = hasNormals ? .physicallyBased : .constant
634
+
635
+ // Base color: texture wins over factor when present.
636
+ let baseColorTex = info.texBaseColor != 0 ? info.texBaseColor : info.texture
637
+ if baseColorTex != 0, let img = TextureCache.shared.image(for: baseColorTex) {
638
+ m.diffuse.contents = img
639
+ } else {
640
+ m.diffuse.contents = UIColor(
641
+ red: CGFloat(info.color.0),
642
+ green: CGFloat(info.color.1),
643
+ blue: CGFloat(info.color.2),
644
+ alpha: CGFloat(info.color.3)
645
+ )
646
+ }
647
+
648
+ // Normal map.
649
+ if info.texNormal != 0, let img = TextureCache.shared.image(for: info.texNormal) {
650
+ m.normal.contents = img
651
+ } else {
652
+ m.normal.contents = nil
653
+ }
654
+
655
+ // Metallic-roughness: glTF packs metalness in B, roughness in G
656
+ // into one texture. SceneKit's .metalness + .roughness channels
657
+ // pointing at the same image each sample the correct channel
658
+ // by convention when .textureComponents is set.
659
+ if info.texMetallicRoughness != 0,
660
+ let img = TextureCache.shared.image(for: info.texMetallicRoughness) {
661
+ m.metalness.contents = img
662
+ m.metalness.textureComponents = .blue
663
+ m.roughness.contents = img
664
+ m.roughness.textureComponents = .green
665
+ } else {
666
+ m.metalness.contents = NSNumber(value: info.metalness)
667
+ m.roughness.contents = NSNumber(value: info.roughness)
668
+ }
669
+
670
+ // Emissive.
671
+ if info.texEmissive != 0, let img = TextureCache.shared.image(for: info.texEmissive) {
672
+ m.emission.contents = img
673
+ } else {
674
+ m.emission.contents = nil
675
+ }
676
+
677
+ // AO.
678
+ if info.texOcclusion != 0, let img = TextureCache.shared.image(for: info.texOcclusion) {
679
+ m.ambientOcclusion.contents = img
680
+ } else {
681
+ m.ambientOcclusion.contents = nil
682
+ }
683
+
684
+ g.materials = [m]
685
+ }
686
+ }
687
+
688
+ // Step 4: parent fix-up — only for nodes whose PARENT bit was dirty.
689
+ // Done after the material/geometry pass so both parent and child
690
+ // exist when we reparent, even for newly-spawned subtrees.
691
+ for info in allDirty where info.dirtyFlags & DIRTY_PARENT != 0 {
692
+ guard let node = retainedNodes[info.handle] else { continue }
693
+ let desiredParent: SCNNode = info.parent == 0 ? retainedRoot
694
+ : (retainedNodes[info.parent] ?? retainedRoot)
695
+ if node.parent !== desiredParent {
696
+ node.removeFromParentNode()
697
+ desiredParent.addChildNode(node)
698
+ }
699
+ }
700
+ }
701
+
702
+ private func buildGeometry(handle: UInt32) -> SCNGeometry? {
703
+ var ptrs = SceneGeometryPtrs()
704
+ withUnsafeMutablePointer(to: &ptrs) { bloom_watchos_scene_geometry(handle, $0) }
705
+ guard let pos = ptrs.positions, let idx = ptrs.indices,
706
+ ptrs.positionCount > 0, ptrs.indexCount > 0 else { return nil }
707
+
708
+ let vcount = Int(ptrs.positionCount) / 3
709
+ let posData = Data(bytes: pos, count: Int(ptrs.positionCount) * MemoryLayout<Float>.size)
710
+ let posSrc = SCNGeometrySource(
711
+ data: posData,
712
+ semantic: .vertex,
713
+ vectorCount: vcount,
714
+ usesFloatComponents: true,
715
+ componentsPerVector: 3,
716
+ bytesPerComponent: MemoryLayout<Float>.size,
717
+ dataOffset: 0,
718
+ dataStride: 3 * MemoryLayout<Float>.size
719
+ )
720
+
721
+ var sources: [SCNGeometrySource] = [posSrc]
722
+ if let nrm = ptrs.normals, ptrs.normalCount >= ptrs.positionCount {
723
+ let nrmData = Data(bytes: nrm, count: Int(ptrs.normalCount) * MemoryLayout<Float>.size)
724
+ sources.append(SCNGeometrySource(
725
+ data: nrmData,
726
+ semantic: .normal,
727
+ vectorCount: vcount,
728
+ usesFloatComponents: true,
729
+ componentsPerVector: 3,
730
+ bytesPerComponent: MemoryLayout<Float>.size,
731
+ dataOffset: 0,
732
+ dataStride: 3 * MemoryLayout<Float>.size
733
+ ))
734
+ }
735
+ if let uv = ptrs.uvs, ptrs.uvCount >= UInt32(vcount * 2) {
736
+ let uvData = Data(bytes: uv, count: Int(ptrs.uvCount) * MemoryLayout<Float>.size)
737
+ sources.append(SCNGeometrySource(
738
+ data: uvData,
739
+ semantic: .texcoord,
740
+ vectorCount: vcount,
741
+ usesFloatComponents: true,
742
+ componentsPerVector: 2,
743
+ bytesPerComponent: MemoryLayout<Float>.size,
744
+ dataOffset: 0,
745
+ dataStride: 2 * MemoryLayout<Float>.size
746
+ ))
747
+ }
748
+
749
+ let idxData = Data(bytes: idx, count: Int(ptrs.indexCount) * MemoryLayout<UInt32>.size)
750
+ let element = SCNGeometryElement(
751
+ data: idxData,
752
+ primitiveType: .triangles,
753
+ primitiveCount: Int(ptrs.indexCount) / 3,
754
+ bytesPerIndex: MemoryLayout<UInt32>.size
755
+ )
756
+
757
+ return SCNGeometry(sources: sources, elements: [element])
758
+ }
759
+
760
+ private func buildSkinner(mesh: SCNNode, handle: UInt32) -> SCNSkinner? {
761
+ var ptrs = SceneSkinPtrs()
762
+ withUnsafeMutablePointer(to: &ptrs) { bloom_watchos_scene_skin(handle, $0) }
763
+ guard let jointsPtr = ptrs.jointHandles,
764
+ let ibmPtr = ptrs.inverseBind,
765
+ let vjPtr = ptrs.vertexJoints,
766
+ let vwPtr = ptrs.vertexWeights,
767
+ ptrs.jointCount > 0, ptrs.vertexJointCount > 0,
768
+ let geom = mesh.geometry
769
+ else { return nil }
770
+
771
+ // Resolve bone SCNNodes from bloom handles. Skip if any is missing
772
+ // — skinner without all bones would crash on draw.
773
+ var bones: [SCNNode] = []
774
+ bones.reserveCapacity(Int(ptrs.jointCount))
775
+ for i in 0..<Int(ptrs.jointCount) {
776
+ let h = jointsPtr[i]
777
+ guard let node = retainedNodes[h] else { return nil }
778
+ bones.append(node)
779
+ }
780
+
781
+ // Inverse-bind matrices wrapped as NSValue(SCNMatrix4).
782
+ var ibmValues: [NSValue] = []
783
+ ibmValues.reserveCapacity(Int(ptrs.inverseBindMatrixCount))
784
+ for i in 0..<Int(ptrs.inverseBindMatrixCount) {
785
+ let base = i * 16
786
+ let m = SCNMatrix4(
787
+ m11: ibmPtr[base+0], m12: ibmPtr[base+1], m13: ibmPtr[base+2], m14: ibmPtr[base+3],
788
+ m21: ibmPtr[base+4], m22: ibmPtr[base+5], m23: ibmPtr[base+6], m24: ibmPtr[base+7],
789
+ m31: ibmPtr[base+8], m32: ibmPtr[base+9], m33: ibmPtr[base+10], m34: ibmPtr[base+11],
790
+ m41: ibmPtr[base+12], m42: ibmPtr[base+13], m43: ibmPtr[base+14], m44: ibmPtr[base+15]
791
+ )
792
+ ibmValues.append(NSValue(scnMatrix4: m))
793
+ }
794
+
795
+ // Bone weights + indices as SCNGeometrySources. 4 per vertex.
796
+ let vertexCount = Int(ptrs.vertexWeightCount) / 4
797
+ let weightsData = Data(bytes: vwPtr, count: Int(ptrs.vertexWeightCount) * MemoryLayout<Float>.size)
798
+ let weightsSrc = SCNGeometrySource(
799
+ data: weightsData, semantic: .boneWeights, vectorCount: vertexCount,
800
+ usesFloatComponents: true, componentsPerVector: 4,
801
+ bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0,
802
+ dataStride: 4 * MemoryLayout<Float>.size
803
+ )
804
+ let indicesData = Data(bytes: vjPtr, count: Int(ptrs.vertexJointCount) * MemoryLayout<UInt32>.size)
805
+ let indicesSrc = SCNGeometrySource(
806
+ data: indicesData, semantic: .boneIndices, vectorCount: vertexCount,
807
+ usesFloatComponents: false, componentsPerVector: 4,
808
+ bytesPerComponent: MemoryLayout<UInt32>.size, dataOffset: 0,
809
+ dataStride: 4 * MemoryLayout<UInt32>.size
810
+ )
811
+
812
+ return SCNSkinner(
813
+ baseGeometry: geom,
814
+ bones: bones,
815
+ boneInverseBindTransforms: ibmValues,
816
+ boneWeights: weightsSrc,
817
+ boneIndices: indicesSrc
818
+ )
819
+ }
820
+
821
+ /// Cache of per-skinned-mesh animation tracks. CAKeyframeAnimation
822
+ /// isn't available on watchOS, so we drive the skeleton by hand each
823
+ /// frame via setBoneTransforms — this cache avoids rebuilding from
824
+ /// FFI pointers every tick.
825
+ private struct CachedTrack {
826
+ let boneHandle: UInt32
827
+ let path: UInt32 // 0 translation, 1 rotation, 2 scale
828
+ let times: [Float]
829
+ let values: [Float]
830
+ }
831
+ @State private var cachedAnimTracks: [UInt32: [CachedTrack]] = [:]
832
+ @State private var cachedAnimDuration: [UInt32: Float] = [:]
833
+
834
+ /// Cache the animation tracks for a skinned mesh. Called once alongside
835
+ /// skinner build; the per-frame loop (advanceAnimations) then drives
836
+ /// playback against these cached arrays.
837
+ private func attachAnimations(handle: UInt32) {
838
+ let n = bloom_watchos_scene_anim_track_count(handle)
839
+ if n <= 0 {
840
+ cachedAnimTracks.removeValue(forKey: handle)
841
+ cachedAnimDuration.removeValue(forKey: handle)
842
+ return
843
+ }
844
+
845
+ var tracks: [CachedTrack] = []
846
+ tracks.reserveCapacity(Int(n))
847
+ var duration: Float = 0
848
+ for i in 0..<n {
849
+ var info = AnimTrackInfo()
850
+ withUnsafeMutablePointer(to: &info) { bloom_watchos_scene_anim_track_info(handle, i, $0) }
851
+ let keyCount = Int(info.keyCount)
852
+ guard keyCount > 0, let tp = info.times, let vp = info.values else { continue }
853
+ let times = Array(UnsafeBufferPointer(start: tp, count: keyCount))
854
+ let valueWidth = info.path == 1 ? 4 : 3
855
+ let values = Array(UnsafeBufferPointer(start: vp, count: keyCount * valueWidth))
856
+ if let last = times.last, last > duration { duration = last }
857
+ tracks.append(CachedTrack(boneHandle: info.boneHandle, path: info.path, times: times, values: values))
858
+ }
859
+ cachedAnimTracks[handle] = tracks
860
+ cachedAnimDuration[handle] = duration
861
+ }
862
+
863
+ /// Advance every cached animation by scene-time, interpolating each
864
+ /// track between the bracketing keyframes and writing the result into
865
+ /// the corresponding bone's SCNNode.
866
+ private func advanceAnimations() {
867
+ // CACurrentMediaTime isn't on watchOS — use a Foundation clock.
868
+ // Relative-since-process-start is enough since we modulo by duration.
869
+ let now = Float(ProcessInfo.processInfo.systemUptime)
870
+ for (meshHandle, tracks) in cachedAnimTracks {
871
+ guard let dur = cachedAnimDuration[meshHandle], dur > 0 else { continue }
872
+ // Wrap to duration — looping playback.
873
+ var t = now.truncatingRemainder(dividingBy: dur)
874
+ if t < 0 { t += dur }
875
+ for track in tracks {
876
+ guard let bone = retainedNodes[track.boneHandle] else { continue }
877
+ applyTrackAt(t: t, track: track, bone: bone)
878
+ }
879
+ }
880
+ }
881
+
882
+ private func applyTrackAt(t: Float, track: CachedTrack, bone: SCNNode) {
883
+ let count = track.times.count
884
+ if count == 0 { return }
885
+
886
+ // Find the keyframe segment [i, i+1] where times[i] <= t < times[i+1].
887
+ // Clamp at the ends.
888
+ var i = 0
889
+ if t <= track.times[0] {
890
+ i = 0
891
+ } else if t >= track.times[count - 1] {
892
+ i = count - 1
893
+ } else {
894
+ // Linear scan — fine for <100 keys per track (typical).
895
+ while i + 1 < count && track.times[i + 1] < t { i += 1 }
896
+ }
897
+
898
+ let width = track.path == 1 ? 4 : 3
899
+ let base0 = i * width
900
+ let base1 = (i + 1 < count ? i + 1 : i) * width
901
+
902
+ let t0 = track.times[i]
903
+ let t1 = i + 1 < count ? track.times[i + 1] : t0
904
+ let alpha: Float = t1 > t0 ? (t - t0) / (t1 - t0) : 0
905
+
906
+ switch track.path {
907
+ case 0: // translation
908
+ let x = lerp(track.values[base0 + 0], track.values[base1 + 0], alpha)
909
+ let y = lerp(track.values[base0 + 1], track.values[base1 + 1], alpha)
910
+ let z = lerp(track.values[base0 + 2], track.values[base1 + 2], alpha)
911
+ bone.position = SCNVector3(x, y, z)
912
+ case 2: // scale
913
+ let x = lerp(track.values[base0 + 0], track.values[base1 + 0], alpha)
914
+ let y = lerp(track.values[base0 + 1], track.values[base1 + 1], alpha)
915
+ let z = lerp(track.values[base0 + 2], track.values[base1 + 2], alpha)
916
+ bone.scale = SCNVector3(x, y, z)
917
+ default: // rotation (quaternion xyzw) — slerp
918
+ let q0 = (track.values[base0 + 0], track.values[base0 + 1], track.values[base0 + 2], track.values[base0 + 3])
919
+ let q1 = (track.values[base1 + 0], track.values[base1 + 1], track.values[base1 + 2], track.values[base1 + 3])
920
+ let q = slerp(q0, q1, alpha)
921
+ bone.orientation = SCNQuaternion(q.0, q.1, q.2, q.3)
922
+ }
923
+ }
924
+
925
+ private func syncLights() {
926
+ let n = Int(bloom_watchos_scene_copy_lights(lightBuf.baseAddress!, 64))
927
+ // Simpler than delta sync for lights — there are few of them and
928
+ // bloom's intended use is setting them once on scene init. Rebuild
929
+ // each frame.
930
+ lightsRoot.childNodes.forEach { $0.removeFromParentNode() }
931
+ for i in 0..<n {
932
+ let l = lightBuf[i]
933
+ let node = SCNNode()
934
+ let light = SCNLight()
935
+ light.color = UIColor(
936
+ red: CGFloat(l.color.0),
937
+ green: CGFloat(l.color.1),
938
+ blue: CGFloat(l.color.2),
939
+ alpha: 1.0
940
+ )
941
+ light.intensity = CGFloat(l.intensity * 1000.0) // bloom's 0..1 → SceneKit lumens
942
+ if l.kind == 1 {
943
+ light.type = .directional
944
+ // Point light forward along `pos_or_dir`.
945
+ node.look(at: SCNVector3(
946
+ x: node.position.x + l.posOrDir.0,
947
+ y: node.position.y + l.posOrDir.1,
948
+ z: node.position.z + l.posOrDir.2
949
+ ))
950
+ } else if l.kind == 2 {
951
+ light.type = .omni
952
+ light.attenuationEndDistance = CGFloat(l.range)
953
+ node.position = SCNVector3(x: l.posOrDir.0, y: l.posOrDir.1, z: l.posOrDir.2)
954
+ }
955
+ node.light = light
956
+ lightsRoot.addChildNode(node)
957
+ }
958
+ }
959
+ }
960
+
961
+ /// Convert a column-major flat 16-float transform (bloom's layout) into an
962
+ /// SCNMatrix4. SCNMatrix4 is column-major too, so it's a direct mapping.
963
+ private func scnMatrix4(from m: (
964
+ Float, Float, Float, Float,
965
+ Float, Float, Float, Float,
966
+ Float, Float, Float, Float,
967
+ Float, Float, Float, Float
968
+ )) -> SCNMatrix4 {
969
+ return SCNMatrix4(
970
+ m11: m.0, m12: m.1, m13: m.2, m14: m.3,
971
+ m21: m.4, m22: m.5, m23: m.6, m24: m.7,
972
+ m31: m.8, m32: m.9, m33: m.10, m34: m.11,
973
+ m41: m.12, m42: m.13, m43: m.14, m44: m.15
974
+ )
975
+ }
976
+
977
+ private func lerp(_ a: Float, _ b: Float, _ t: Float) -> Float { a + (b - a) * t }
978
+
979
+ /// Spherical-linear interpolation between two quaternions (xyzw). Handles
980
+ /// the double-cover sign flip so the short arc wins.
981
+ private func slerp(_ q0: (Float, Float, Float, Float),
982
+ _ q1: (Float, Float, Float, Float),
983
+ _ t: Float) -> (Float, Float, Float, Float) {
984
+ var x1 = q1.0, y1 = q1.1, z1 = q1.2, w1 = q1.3
985
+ let dot = q0.0 * x1 + q0.1 * y1 + q0.2 * z1 + q0.3 * w1
986
+ var d = dot
987
+ if d < 0 {
988
+ x1 = -x1; y1 = -y1; z1 = -z1; w1 = -w1
989
+ d = -d
990
+ }
991
+ if d > 0.9995 {
992
+ // Nearly collinear — plain lerp avoids sin(0)/0.
993
+ let x = lerp(q0.0, x1, t); let y = lerp(q0.1, y1, t)
994
+ let z = lerp(q0.2, z1, t); let w = lerp(q0.3, w1, t)
995
+ let inv = 1.0 / (x * x + y * y + z * z + w * w).squareRoot()
996
+ return (x * inv, y * inv, z * inv, w * inv)
997
+ }
998
+ let theta = acos(d)
999
+ let sinTheta = sin(theta)
1000
+ let a = sin((1 - t) * theta) / sinTheta
1001
+ let b = sin(t * theta) / sinTheta
1002
+ return (q0.0 * a + x1 * b, q0.1 * a + y1 * b, q0.2 * a + z1 * b, q0.3 * a + w1 * b)
1003
+ }
1004
+
1005
+ // MARK: - Post-FX SCNTechnique
1006
+ //
1007
+ // SwiftUI's `.colorEffect(Shader)` / `.layerEffect(Shader)` aren't on
1008
+ // watchOS, but SCNTechnique IS — partially. Verified working:
1009
+ // - SCNTechnique(dictionary:) → builds the pass graph
1010
+ // - Attaching technique to SCNView via SwiftUI SceneView's `technique:`
1011
+ // parameter → applies the post-process pass
1012
+ // - Metal shaders compiled into default.metallib via Perry's
1013
+ // metal_sources pipeline → load and execute correctly (proven by a
1014
+ // debug shader that returns a constant red)
1015
+ // - COLOR-semantic input/output binding → routes the scene's main color
1016
+ // attachment in and back out
1017
+ //
1018
+ // What does NOT work on watchOS:
1019
+ // - Per-draw uniform push. SCNTechnique's
1020
+ // `handleBindingOfSymbol:usingBlock:` takes an `SCNRenderer` parameter,
1021
+ // and `SCNRenderer.h` simply isn't in the watchOS SDK — the method is
1022
+ // uncallable from Swift. SceneKit's `setObject(NSData,forKeyedSubscript:)`
1023
+ // route, which works for SCNProgram per-material shaders, doesn't
1024
+ // deliver values to SCNTechnique-bound Metal `[[buffer(N)]]` slots.
1025
+ //
1026
+ // So today the technique can run a fixed-strength post-process (hardcode
1027
+ // values in the shader, recompile to change them), but the
1028
+ // bloom_set_chromatic_aberration / _film_grain / _sun_shafts dynamic-knob
1029
+ // API has no path to drive its strengths on watchOS.
1030
+ //
1031
+ // Tracking: Bloom-Engine#16 stays open with this finding; Apple Feedback
1032
+ // filed for SCNRenderer / handleBinding parity on watchOS. See the
1033
+ // bloom_postfx.metal shader for the math — it's ready to wire up the
1034
+ // moment Apple ships either SCNRenderer or `.colorEffect(Shader)` on the
1035
+ // watch.
1036
+ enum BloomPostFXTechnique {
1037
+
1038
+ /// Built once on first access. Currently no-op on watchOS — the
1039
+ /// technique would attach and run, but with all uniform strengths
1040
+ /// stuck at zero (no per-draw push API), every effect short-circuits
1041
+ /// to pass-through. Returning nil signals BloomSceneView to skip the
1042
+ /// technique entirely until uniforms can be wired.
1043
+ static let shared: SCNTechnique? = nil
1044
+
1045
+ static func update(_ technique: SCNTechnique, fx: PostFxState, viewSize: CGSize) {
1046
+ // No-op until uniform binding lands. See file-level comment.
1047
+ _ = technique; _ = fx; _ = viewSize
1048
+ }
1049
+ }
1050
+
1051
+ private func makeBaseScene() -> SCNScene {
1052
+ let s = SCNScene()
1053
+ // Minimal default lighting so objects aren't pitch black before the game
1054
+ // adds its own lights.
1055
+ let ambient = SCNNode()
1056
+ ambient.light = SCNLight()
1057
+ ambient.light?.type = .ambient
1058
+ ambient.light?.intensity = 300
1059
+ s.rootNode.addChildNode(ambient)
1060
+
1061
+ let dir = SCNNode()
1062
+ dir.light = SCNLight()
1063
+ dir.light?.type = .directional
1064
+ dir.light?.intensity = 800
1065
+ dir.eulerAngles = SCNVector3(-Float.pi / 3, Float.pi / 6, 0)
1066
+ s.rootNode.addChildNode(dir)
1067
+ return s
1068
+ }
1069
+
1070
+ private func makeSceneNode(for cmd: DrawCmd) -> SCNNode? {
1071
+ let pos = SCNVector3(Float(cmd.x), Float(cmd.y), Float(cmd.srcX))
1072
+ let color = UIColor(
1073
+ red: CGFloat(cmd.r / 255.0),
1074
+ green: CGFloat(cmd.g / 255.0),
1075
+ blue: CGFloat(cmd.b / 255.0),
1076
+ alpha: CGFloat(cmd.a / 255.0)
1077
+ )
1078
+
1079
+ let geo: SCNGeometry?
1080
+ switch cmd.kind {
1081
+ case K_CUBE, K_CUBE_WIRES:
1082
+ geo = SCNBox(width: CGFloat(cmd.w), height: CGFloat(cmd.h),
1083
+ length: CGFloat(cmd.size), chamferRadius: 0)
1084
+ case K_SPHERE, K_SPHERE_WIRES:
1085
+ geo = SCNSphere(radius: CGFloat(cmd.w))
1086
+ case K_CYLINDER:
1087
+ geo = SCNCylinder(radius: CGFloat(cmd.w), height: CGFloat(cmd.h))
1088
+ case K_PLANE:
1089
+ geo = SCNPlane(width: CGFloat(cmd.w), height: CGFloat(cmd.h))
1090
+ case K_GRID:
1091
+ return makeGridNode(slices: Int(cmd.w), spacing: Float(cmd.h),
1092
+ color: color)
1093
+ default:
1094
+ return nil
1095
+ }
1096
+ guard let g = geo else { return nil }
1097
+ let m = SCNMaterial()
1098
+ m.lightingModel = .physicallyBased
1099
+ m.diffuse.contents = color
1100
+ m.roughness.contents = 0.6
1101
+ m.metalness.contents = 0.0
1102
+ if cmd.kind == K_CUBE_WIRES || cmd.kind == K_SPHERE_WIRES {
1103
+ m.fillMode = .lines
1104
+ }
1105
+ g.materials = [m]
1106
+
1107
+ let node = SCNNode(geometry: g)
1108
+ node.position = pos
1109
+ return node
1110
+ }
1111
+
1112
+ /// Build a grid as line segments — SceneKit doesn't have a built-in grid,
1113
+ /// so we construct two sets of parallel SCNGeometry lines.
1114
+ private func makeGridNode(slices: Int, spacing: Float, color: UIColor) -> SCNNode {
1115
+ let root = SCNNode()
1116
+ let s = slices < 1 ? 10 : slices
1117
+ let half = Float(s) * spacing / 2.0
1118
+
1119
+ var verts: [SCNVector3] = []
1120
+ var indices: [Int32] = []
1121
+ var idx: Int32 = 0
1122
+ for i in 0...s {
1123
+ let p = -half + Float(i) * spacing
1124
+ verts.append(SCNVector3(p, 0, -half))
1125
+ verts.append(SCNVector3(p, 0, half))
1126
+ indices.append(idx); indices.append(idx + 1); idx += 2
1127
+ verts.append(SCNVector3(-half, 0, p))
1128
+ verts.append(SCNVector3( half, 0, p))
1129
+ indices.append(idx); indices.append(idx + 1); idx += 2
1130
+ }
1131
+ let src = SCNGeometrySource(vertices: verts)
1132
+ let data = Data(bytes: indices, count: indices.count * MemoryLayout<Int32>.size)
1133
+ let el = SCNGeometryElement(data: data, primitiveType: .line,
1134
+ primitiveCount: indices.count / 2,
1135
+ bytesPerIndex: MemoryLayout<Int32>.size)
1136
+ let geom = SCNGeometry(sources: [src], elements: [el])
1137
+ let mat = SCNMaterial()
1138
+ mat.diffuse.contents = color
1139
+ mat.isDoubleSided = true
1140
+ mat.lightingModel = .constant
1141
+ geom.materials = [mat]
1142
+ root.geometry = geom
1143
+ return root
1144
+ }
1145
+
1146
+ // MARK: - Single-command draw
1147
+
1148
+ private func drawOne(ctx: GraphicsContext, cmdPtr: UnsafePointer<DrawCmd>) {
1149
+ let cmd = cmdPtr.pointee
1150
+ let color = Color(.sRGB,
1151
+ red: cmd.r / 255.0,
1152
+ green: cmd.g / 255.0,
1153
+ blue: cmd.b / 255.0,
1154
+ opacity: cmd.a / 255.0)
1155
+
1156
+ switch cmd.kind {
1157
+ case K_RECT:
1158
+ ctx.fill(Path(CGRect(x: cmd.x, y: cmd.y, width: cmd.w, height: cmd.h)),
1159
+ with: .color(color))
1160
+
1161
+ case K_RECT_LINES:
1162
+ ctx.stroke(Path(CGRect(x: cmd.x, y: cmd.y, width: cmd.w, height: cmd.h)),
1163
+ with: .color(color),
1164
+ lineWidth: cmd.thickness)
1165
+
1166
+ case K_CIRCLE:
1167
+ ctx.fill(Path(ellipseIn: CGRect(x: cmd.x - cmd.w, y: cmd.y - cmd.w,
1168
+ width: cmd.w * 2, height: cmd.w * 2)),
1169
+ with: .color(color))
1170
+
1171
+ case K_CIRCLE_LINES:
1172
+ ctx.stroke(Path(ellipseIn: CGRect(x: cmd.x - cmd.w, y: cmd.y - cmd.w,
1173
+ width: cmd.w * 2, height: cmd.w * 2)),
1174
+ with: .color(color),
1175
+ lineWidth: cmd.thickness)
1176
+
1177
+ case K_LINE:
1178
+ var path = Path()
1179
+ path.move(to: CGPoint(x: cmd.x, y: cmd.y))
1180
+ path.addLine(to: CGPoint(x: cmd.srcX, y: cmd.srcY))
1181
+ ctx.stroke(path, with: .color(color), lineWidth: cmd.thickness)
1182
+
1183
+ case K_TRIANGLE:
1184
+ var path = Path()
1185
+ path.move(to: CGPoint(x: cmd.x, y: cmd.y))
1186
+ path.addLine(to: CGPoint(x: cmd.srcX, y: cmd.srcY))
1187
+ path.addLine(to: CGPoint(x: cmd.srcW, y: cmd.srcH))
1188
+ path.closeSubpath()
1189
+ ctx.fill(path, with: .color(color))
1190
+
1191
+ case K_TEXTURE:
1192
+ drawTexture(ctx: ctx, cmd: cmd, dstRect: CGRect(x: cmd.x, y: cmd.y, width: cmd.w, height: cmd.h), srcRect: nil)
1193
+
1194
+ case K_TEXTURE_REC:
1195
+ let src = CGRect(x: cmd.srcX, y: cmd.srcY, width: cmd.srcW, height: cmd.srcH)
1196
+ let dst = CGRect(x: cmd.x, y: cmd.y, width: cmd.w, height: cmd.h)
1197
+ drawTexture(ctx: ctx, cmd: cmd, dstRect: dst, srcRect: src)
1198
+
1199
+ case K_TEXTURE_PRO:
1200
+ let src = CGRect(x: cmd.srcX, y: cmd.srcY, width: cmd.srcW, height: cmd.srcH)
1201
+ let dst = CGRect(x: cmd.x - cmd.ox, y: cmd.y - cmd.oy, width: cmd.w, height: cmd.h)
1202
+ if cmd.rot != 0 {
1203
+ var nested = ctx
1204
+ nested.translateBy(x: cmd.x, y: cmd.y)
1205
+ nested.rotate(by: .degrees(cmd.rot))
1206
+ nested.translateBy(x: -cmd.ox, y: -cmd.oy)
1207
+ drawTexture(ctx: nested, cmd: cmd,
1208
+ dstRect: CGRect(x: 0, y: 0, width: cmd.w, height: cmd.h),
1209
+ srcRect: src)
1210
+ } else {
1211
+ drawTexture(ctx: ctx, cmd: cmd, dstRect: dst, srcRect: src)
1212
+ }
1213
+
1214
+ case K_TEXT:
1215
+ let s = cmdTextString(cmdPtr)
1216
+ if s.isEmpty { return }
1217
+ let font = Font.system(size: cmd.size > 0 ? cmd.size : 14)
1218
+ let text = Text(s).font(font).foregroundColor(color)
1219
+ ctx.draw(text, at: CGPoint(x: cmd.x, y: cmd.y), anchor: .topLeading)
1220
+
1221
+ default:
1222
+ break
1223
+ }
1224
+ }
1225
+
1226
+ private func drawTexture(ctx: GraphicsContext, cmd: DrawCmd, dstRect: CGRect, srcRect: CGRect?) {
1227
+ guard let full = TextureCache.shared.image(for: cmd.tex) else { return }
1228
+ let cg: CGImage
1229
+ if let s = srcRect, let cropped = full.cropping(to: s) {
1230
+ cg = cropped
1231
+ } else {
1232
+ cg = full
1233
+ }
1234
+ let img = Image(cg, scale: 1.0, label: Text(""))
1235
+ ctx.draw(img, in: dstRect)
1236
+ }