@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.
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/native/android/Cargo.lock +1848 -0
- package/native/android/Cargo.toml +20 -0
- package/native/android/src/lib.rs +1747 -0
- package/native/ios/Cargo.lock +1688 -0
- package/native/ios/Cargo.toml +19 -0
- package/native/ios/src/lib.rs +2258 -0
- package/native/linux/Cargo.lock +1719 -0
- package/native/linux/Cargo.toml +22 -0
- package/native/linux/src/lib.rs +2236 -0
- package/native/macos/Cargo.lock +3310 -0
- package/native/macos/Cargo.toml +29 -0
- package/native/macos/src/lib.rs +3444 -0
- package/native/shared/Cargo.lock +1898 -0
- package/native/shared/Cargo.toml +42 -0
- package/native/shared/assets/default_font.ttf +0 -0
- package/native/shared/build.rs +77 -0
- package/native/shared/shaders/common/fog.wgsl +16 -0
- package/native/shared/shaders/common/imposter.wgsl +112 -0
- package/native/shared/shaders/common/pbr.wgsl +186 -0
- package/native/shared/shaders/common/shadows.wgsl +77 -0
- package/native/shared/shaders/common/sky.wgsl +8 -0
- package/native/shared/shaders/common/tonemap.wgsl +25 -0
- package/native/shared/shaders/impulse_field.wgsl +53 -0
- package/native/shared/shaders/material_abi.wgsl +360 -0
- package/native/shared/shaders/materials/test_minimal.wgsl +42 -0
- package/native/shared/src/audio.rs +363 -0
- package/native/shared/src/custom_shaders.rs +104 -0
- package/native/shared/src/drs.rs +211 -0
- package/native/shared/src/engine.rs +186 -0
- package/native/shared/src/frame_callbacks.rs +88 -0
- package/native/shared/src/geometry.rs +236 -0
- package/native/shared/src/handles.rs +76 -0
- package/native/shared/src/input.rs +273 -0
- package/native/shared/src/jolt_sys.rs +822 -0
- package/native/shared/src/lib.rs +43 -0
- package/native/shared/src/models.rs +1941 -0
- package/native/shared/src/physics_jolt.rs +1528 -0
- package/native/shared/src/picking.rs +298 -0
- package/native/shared/src/postfx.rs +339 -0
- package/native/shared/src/profiler.rs +416 -0
- package/native/shared/src/renderer/atmosphere_lut.rs +573 -0
- package/native/shared/src/renderer/brdf_lut.rs +154 -0
- package/native/shared/src/renderer/formats.rs +778 -0
- package/native/shared/src/renderer/graph.rs +465 -0
- package/native/shared/src/renderer/hot_reload.rs +390 -0
- package/native/shared/src/renderer/impulse_field.rs +455 -0
- package/native/shared/src/renderer/material_pipeline.rs +604 -0
- package/native/shared/src/renderer/material_system.rs +2106 -0
- package/native/shared/src/renderer/mod.rs +13923 -0
- package/native/shared/src/renderer/planar_reflection.rs +458 -0
- package/native/shared/src/renderer/post_pass.rs +249 -0
- package/native/shared/src/renderer/shader_include.rs +205 -0
- package/native/shared/src/renderer/shader_library.rs +134 -0
- package/native/shared/src/renderer/shaders.rs +5855 -0
- package/native/shared/src/renderer/transient.rs +576 -0
- package/native/shared/src/renderer/types.rs +259 -0
- package/native/shared/src/renderer/util.rs +151 -0
- package/native/shared/src/scene.rs +1066 -0
- package/native/shared/src/sdf_cache.rs +274 -0
- package/native/shared/src/shadows.rs +551 -0
- package/native/shared/src/staging.rs +90 -0
- package/native/shared/src/string_header.rs +35 -0
- package/native/shared/src/text_renderer.rs +456 -0
- package/native/shared/src/textures.rs +154 -0
- package/native/third_party/JoltPhysics/Jolt/AABBTree/AABBTreeBuilder.cpp +242 -0
- package/native/third_party/JoltPhysics/Jolt/AABBTree/AABBTreeBuilder.h +121 -0
- package/native/third_party/JoltPhysics/Jolt/AABBTree/AABBTreeToBuffer.h +296 -0
- package/native/third_party/JoltPhysics/Jolt/AABBTree/NodeCodec/NodeCodecQuadTreeHalfFloat.h +323 -0
- package/native/third_party/JoltPhysics/Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h +555 -0
- package/native/third_party/JoltPhysics/Jolt/ConfigurationString.h +112 -0
- package/native/third_party/JoltPhysics/Jolt/Core/ARMNeon.h +94 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Array.h +713 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Atomics.h +44 -0
- package/native/third_party/JoltPhysics/Jolt/Core/BinaryHeap.h +96 -0
- package/native/third_party/JoltPhysics/Jolt/Core/ByteBuffer.h +74 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Color.cpp +38 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Color.h +98 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Core.h +652 -0
- package/native/third_party/JoltPhysics/Jolt/Core/FPControlWord.h +143 -0
- package/native/third_party/JoltPhysics/Jolt/Core/FPException.h +96 -0
- package/native/third_party/JoltPhysics/Jolt/Core/FPFlushDenormals.h +43 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Factory.cpp +92 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Factory.h +54 -0
- package/native/third_party/JoltPhysics/Jolt/Core/FixedSizeFreeList.h +122 -0
- package/native/third_party/JoltPhysics/Jolt/Core/FixedSizeFreeList.inl +215 -0
- package/native/third_party/JoltPhysics/Jolt/Core/HashCombine.h +234 -0
- package/native/third_party/JoltPhysics/Jolt/Core/HashTable.h +876 -0
- package/native/third_party/JoltPhysics/Jolt/Core/InsertionSort.h +58 -0
- package/native/third_party/JoltPhysics/Jolt/Core/IssueReporting.cpp +27 -0
- package/native/third_party/JoltPhysics/Jolt/Core/IssueReporting.h +38 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystem.h +311 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystem.inl +56 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystemSingleThreaded.cpp +65 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystemSingleThreaded.h +62 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystemThreadPool.cpp +364 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystemThreadPool.h +101 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystemWithBarrier.cpp +230 -0
- package/native/third_party/JoltPhysics/Jolt/Core/JobSystemWithBarrier.h +85 -0
- package/native/third_party/JoltPhysics/Jolt/Core/LinearCurve.cpp +51 -0
- package/native/third_party/JoltPhysics/Jolt/Core/LinearCurve.h +67 -0
- package/native/third_party/JoltPhysics/Jolt/Core/LockFreeHashMap.h +182 -0
- package/native/third_party/JoltPhysics/Jolt/Core/LockFreeHashMap.inl +351 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Memory.cpp +85 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Memory.h +85 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Mutex.h +223 -0
- package/native/third_party/JoltPhysics/Jolt/Core/MutexArray.h +98 -0
- package/native/third_party/JoltPhysics/Jolt/Core/NonCopyable.h +18 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Profiler.cpp +677 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Profiler.h +301 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Profiler.inl +90 -0
- package/native/third_party/JoltPhysics/Jolt/Core/QuickSort.h +137 -0
- package/native/third_party/JoltPhysics/Jolt/Core/RTTI.cpp +149 -0
- package/native/third_party/JoltPhysics/Jolt/Core/RTTI.h +436 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Reference.h +244 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Result.h +174 -0
- package/native/third_party/JoltPhysics/Jolt/Core/STLAlignedAllocator.h +72 -0
- package/native/third_party/JoltPhysics/Jolt/Core/STLAllocator.h +127 -0
- package/native/third_party/JoltPhysics/Jolt/Core/STLLocalAllocator.h +170 -0
- package/native/third_party/JoltPhysics/Jolt/Core/STLTempAllocator.h +80 -0
- package/native/third_party/JoltPhysics/Jolt/Core/ScopeExit.h +49 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Semaphore.cpp +135 -0
- package/native/third_party/JoltPhysics/Jolt/Core/Semaphore.h +68 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StaticArray.h +329 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StreamIn.h +120 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StreamOut.h +97 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StreamUtils.h +168 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StreamWrapper.h +53 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StridedPtr.h +63 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StringTools.cpp +101 -0
- package/native/third_party/JoltPhysics/Jolt/Core/StringTools.h +38 -0
- package/native/third_party/JoltPhysics/Jolt/Core/TempAllocator.h +209 -0
- package/native/third_party/JoltPhysics/Jolt/Core/TickCounter.cpp +37 -0
- package/native/third_party/JoltPhysics/Jolt/Core/TickCounter.h +58 -0
- package/native/third_party/JoltPhysics/Jolt/Core/UnorderedMap.h +80 -0
- package/native/third_party/JoltPhysics/Jolt/Core/UnorderedSet.h +32 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/AABox.h +313 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/AABox4.h +224 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ClipPoly.h +200 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ClosestPoint.h +498 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder.cpp +1467 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder.h +276 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder2D.cpp +335 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexHullBuilder2D.h +105 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/ConvexSupport.h +188 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/EPAConvexHullBuilder.h +845 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/EPAPenetrationDepth.h +557 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/Ellipse.h +77 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/GJKClosestPoint.h +945 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/IndexedTriangle.h +130 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/Indexify.cpp +222 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/Indexify.h +19 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/MortonCode.h +40 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/OrientedBox.cpp +178 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/OrientedBox.h +39 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/Plane.h +104 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/RayAABox.h +241 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/RayCapsule.h +37 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/RayCylinder.h +101 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/RaySphere.h +96 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/RayTriangle.h +158 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/Sphere.h +72 -0
- package/native/third_party/JoltPhysics/Jolt/Geometry/Triangle.h +34 -0
- package/native/third_party/JoltPhysics/Jolt/Jolt.cmake +703 -0
- package/native/third_party/JoltPhysics/Jolt/Jolt.h +16 -0
- package/native/third_party/JoltPhysics/Jolt/Jolt.natvis +116 -0
- package/native/third_party/JoltPhysics/Jolt/Math/BVec16.h +99 -0
- package/native/third_party/JoltPhysics/Jolt/Math/BVec16.inl +177 -0
- package/native/third_party/JoltPhysics/Jolt/Math/DMat44.h +158 -0
- package/native/third_party/JoltPhysics/Jolt/Math/DMat44.inl +310 -0
- package/native/third_party/JoltPhysics/Jolt/Math/DVec3.h +291 -0
- package/native/third_party/JoltPhysics/Jolt/Math/DVec3.inl +941 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Double3.h +48 -0
- package/native/third_party/JoltPhysics/Jolt/Math/DynMatrix.h +31 -0
- package/native/third_party/JoltPhysics/Jolt/Math/EigenValueSymmetric.h +177 -0
- package/native/third_party/JoltPhysics/Jolt/Math/FindRoot.h +42 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Float2.h +36 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Float3.h +50 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Float4.h +44 -0
- package/native/third_party/JoltPhysics/Jolt/Math/GaussianElimination.h +102 -0
- package/native/third_party/JoltPhysics/Jolt/Math/HalfFloat.h +208 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Mat44.h +243 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Mat44.inl +952 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Math.h +208 -0
- package/native/third_party/JoltPhysics/Jolt/Math/MathTypes.h +32 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Matrix.h +259 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Quat.h +268 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Quat.inl +406 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Real.h +44 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Swizzle.h +19 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Trigonometry.h +79 -0
- package/native/third_party/JoltPhysics/Jolt/Math/UVec4.h +232 -0
- package/native/third_party/JoltPhysics/Jolt/Math/UVec4.inl +636 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Vec3.cpp +71 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Vec3.h +308 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Vec3.inl +942 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Vec4.h +320 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Vec4.inl +1152 -0
- package/native/third_party/JoltPhysics/Jolt/Math/Vector.h +211 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/GetPrimitiveTypeOfType.h +54 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStream.cpp +38 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStream.h +337 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryIn.cpp +252 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryIn.h +57 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryOut.cpp +165 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamBinaryOut.h +57 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamIn.cpp +635 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamIn.h +148 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamOut.cpp +166 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamOut.h +101 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextIn.cpp +418 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextIn.h +55 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextOut.cpp +255 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTextOut.h +62 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/ObjectStreamTypes.h +26 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableAttribute.h +111 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableAttributeEnum.h +67 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableAttributeTyped.h +60 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableObject.cpp +15 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/SerializableObject.h +170 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/TypeDeclarations.cpp +70 -0
- package/native/third_party/JoltPhysics/Jolt/ObjectStream/TypeDeclarations.h +45 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/AllowedDOFs.h +68 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/Body.cpp +426 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/Body.h +452 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/Body.inl +197 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyAccess.h +68 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyActivationListener.h +28 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyCreationSettings.cpp +234 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyCreationSettings.h +124 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyFilter.h +130 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyID.h +101 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyInterface.cpp +1099 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyInterface.h +324 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyLock.h +111 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyLockInterface.h +134 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyLockMulti.h +120 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyManager.cpp +1220 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyManager.h +403 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyPair.h +36 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/BodyType.h +19 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MassProperties.cpp +185 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MassProperties.h +58 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionProperties.cpp +92 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionProperties.h +308 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionProperties.inl +178 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionQuality.h +31 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Body/MotionType.h +17 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/Character.cpp +354 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/Character.h +159 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterBase.cpp +59 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterBase.h +157 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterID.h +98 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterVirtual.cpp +1933 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Character/CharacterVirtual.h +752 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/AABoxCast.h +20 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ActiveEdgeMode.h +17 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ActiveEdges.h +114 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BackFaceMode.h +16 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhase.cpp +16 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhase.h +109 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.cpp +313 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.h +38 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h +148 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayerInterfaceMask.h +92 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayerInterfaceTable.h +64 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.cpp +629 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.h +108 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuery.h +56 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/ObjectVsBroadPhaseLayerFilterMask.h +35 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/ObjectVsBroadPhaseLayerFilterTable.h +66 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/QuadTree.cpp +1768 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/BroadPhase/QuadTree.h +389 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastConvexVsTriangles.cpp +107 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastConvexVsTriangles.h +46 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastResult.h +37 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastSphereVsTriangles.cpp +223 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CastSphereVsTriangles.h +49 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollectFacesMode.h +16 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideConvexVsTriangles.cpp +155 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideConvexVsTriangles.h +56 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollidePointResult.h +25 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideShape.h +106 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideShapeVsShapePerLeaf.h +94 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSoftBodyVertexIterator.h +110 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSoftBodyVerticesVsTriangles.h +102 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSphereVsTriangles.cpp +121 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollideSphereVsTriangles.h +50 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionCollector.h +109 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionCollectorImpl.h +219 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionDispatch.cpp +107 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionDispatch.h +97 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionGroup.cpp +35 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/CollisionGroup.h +97 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ContactListener.h +143 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/EstimateCollisionResponse.cpp +213 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/EstimateCollisionResponse.h +48 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilter.cpp +32 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilter.h +46 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilterTable.cpp +38 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/GroupFilterTable.h +130 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/InternalEdgeRemovingCollector.h +279 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ManifoldBetweenTwoFaces.cpp +271 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ManifoldBetweenTwoFaces.h +44 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp +448 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseQuery.h +77 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseStats.cpp +62 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/NarrowPhaseStats.h +110 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ObjectLayer.h +111 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ObjectLayerPairFilterMask.h +52 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ObjectLayerPairFilterTable.h +78 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterial.cpp +35 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterial.h +57 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterialSimple.cpp +38 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/PhysicsMaterialSimple.h +37 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/RayCast.h +87 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/BoxShape.cpp +318 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/BoxShape.h +115 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CapsuleShape.cpp +438 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CapsuleShape.h +129 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CompoundShape.cpp +433 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CompoundShape.h +354 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h +461 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexHullShape.cpp +1311 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexHullShape.h +202 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexShape.cpp +566 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ConvexShape.h +150 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CylinderShape.cpp +418 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/CylinderShape.h +126 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/DecoratedShape.cpp +87 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/DecoratedShape.h +80 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/EmptyShape.cpp +64 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/EmptyShape.h +75 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/GetTrianglesContext.h +248 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/HeightFieldShape.cpp +2754 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/HeightFieldShape.h +380 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MeshShape.cpp +1305 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MeshShape.h +228 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp +596 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/MutableCompoundShape.h +176 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.cpp +217 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h +140 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/PlaneShape.cpp +541 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/PlaneShape.h +147 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/PolyhedronSubmergedVolumeCalculator.h +319 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.cpp +333 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h +161 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ScaleHelpers.h +83 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ScaledShape.cpp +238 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/ScaledShape.h +145 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/Shape.cpp +325 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/Shape.h +466 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SphereShape.cpp +347 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SphereShape.h +125 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/StaticCompoundShape.cpp +674 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/StaticCompoundShape.h +139 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SubShapeID.h +138 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/SubShapeIDPair.h +65 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.cpp +453 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.gliffy +1 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h +135 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCylinderShape.cpp +691 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TaperedCylinderShape.h +132 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TriangleShape.cpp +430 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/Shape/TriangleShape.h +143 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ShapeCast.h +173 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/ShapeFilter.h +73 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/SimShapeFilter.h +40 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/SimShapeFilterWrapper.h +58 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/SortReverseAndStore.h +48 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/TransformedShape.cpp +180 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Collision/TransformedShape.h +194 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/CalculateSolverSteps.h +70 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConeConstraint.cpp +246 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConeConstraint.h +133 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/Constraint.cpp +73 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/Constraint.h +243 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintManager.cpp +289 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintManager.h +100 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/AngleConstraintPart.h +257 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/AxisConstraintPart.h +682 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/DualAxisConstraintPart.h +276 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/GearConstraintPart.h +195 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/HingeRotationConstraintPart.h +222 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/IndependentAxisConstraintPart.h +246 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h +239 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/RackAndPinionConstraintPart.h +196 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h +283 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/RotationQuatConstraintPart.h +246 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/SpringPart.h +169 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ConstraintPart/SwingTwistConstraintPart.h +597 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ContactConstraintManager.cpp +1804 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/ContactConstraintManager.h +524 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/DistanceConstraint.cpp +266 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/DistanceConstraint.h +120 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/FixedConstraint.cpp +215 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/FixedConstraint.h +96 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/GearConstraint.cpp +188 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/GearConstraint.h +116 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/HingeConstraint.cpp +443 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/HingeConstraint.h +205 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/MotorSettings.cpp +43 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/MotorSettings.h +66 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraint.cpp +458 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraint.h +191 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPath.cpp +85 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPath.h +76 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPathHermite.cpp +308 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PathConstraintPathHermite.h +54 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PointConstraint.cpp +157 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PointConstraint.h +94 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PulleyConstraint.cpp +253 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/PulleyConstraint.h +137 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/RackAndPinionConstraint.cpp +189 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/RackAndPinionConstraint.h +118 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SixDOFConstraint.cpp +900 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SixDOFConstraint.h +289 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SliderConstraint.cpp +501 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SliderConstraint.h +198 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SpringSettings.cpp +35 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SpringSettings.h +70 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SwingTwistConstraint.cpp +524 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/SwingTwistConstraint.h +197 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/TwoBodyConstraint.cpp +56 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Constraints/TwoBodyConstraint.h +65 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/DeterminismLog.cpp +17 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/DeterminismLog.h +159 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/EActivation.h +16 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/EPhysicsUpdateError.h +37 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/IslandBuilder.cpp +492 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/IslandBuilder.h +144 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/LargeIslandSplitter.cpp +582 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/LargeIslandSplitter.h +187 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsLock.h +169 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsScene.cpp +261 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsScene.h +104 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsSettings.h +125 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsStepListener.h +37 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsSystem.cpp +2915 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsSystem.h +391 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsUpdateContext.cpp +25 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/PhysicsUpdateContext.h +176 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Ragdoll/Ragdoll.cpp +744 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Ragdoll/Ragdoll.h +245 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyContactListener.h +55 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyCreationSettings.cpp +128 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyCreationSettings.h +75 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyManifold.h +74 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp +1501 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h +333 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyShape.cpp +354 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyShape.h +73 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp +1487 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodySharedSettings.h +390 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyUpdateContext.h +63 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/SoftBody/SoftBodyVertex.h +36 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/StateRecorder.h +136 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/StateRecorderImpl.cpp +90 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/StateRecorderImpl.h +50 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/MotorcycleController.cpp +306 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/MotorcycleController.h +119 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/TrackedVehicleController.cpp +547 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/TrackedVehicleController.h +169 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleAntiRollBar.cpp +33 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleAntiRollBar.h +33 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleCollisionTester.cpp +376 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleCollisionTester.h +146 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleConstraint.cpp +703 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleConstraint.h +252 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleController.cpp +17 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleController.h +87 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleDifferential.cpp +81 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleDifferential.h +39 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleEngine.cpp +122 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleEngine.h +93 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTrack.cpp +52 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTrack.h +56 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTransmission.cpp +159 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/VehicleTransmission.h +87 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/Wheel.cpp +93 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/Wheel.h +148 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/WheeledVehicleController.cpp +866 -0
- package/native/third_party/JoltPhysics/Jolt/Physics/Vehicle/WheeledVehicleController.h +205 -0
- package/native/third_party/JoltPhysics/Jolt/RegisterTypes.cpp +204 -0
- package/native/third_party/JoltPhysics/Jolt/RegisterTypes.h +29 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRenderer.cpp +1107 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRenderer.h +383 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererPlayback.cpp +168 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererPlayback.h +48 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererRecorder.cpp +158 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererRecorder.h +130 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererSimple.cpp +80 -0
- package/native/third_party/JoltPhysics/Jolt/Renderer/DebugRendererSimple.h +88 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletalAnimation.cpp +165 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletalAnimation.h +91 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/Skeleton.cpp +82 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/Skeleton.h +72 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonMapper.cpp +237 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonMapper.h +145 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonPose.cpp +87 -0
- package/native/third_party/JoltPhysics/Jolt/Skeleton/SkeletonPose.h +82 -0
- package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitter.cpp +73 -0
- package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitter.h +84 -0
- package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterBinning.cpp +139 -0
- package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterBinning.h +52 -0
- package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterMean.cpp +43 -0
- package/native/third_party/JoltPhysics/Jolt/TriangleSplitter/TriangleSplitterMean.h +28 -0
- package/native/third_party/JoltPhysics/LICENSE +7 -0
- package/native/third_party/JoltPhysics/README.md +173 -0
- package/native/third_party/bloom_jolt/CMakeLists.txt +78 -0
- package/native/third_party/bloom_jolt/include/bloom_jolt.h +519 -0
- package/native/third_party/bloom_jolt/src/bloom_jolt.cpp +1780 -0
- package/native/tvos/Cargo.lock +1692 -0
- package/native/tvos/Cargo.toml +22 -0
- package/native/tvos/src/lib.rs +3179 -0
- package/native/watchos/Cargo.lock +16 -0
- package/native/watchos/Cargo.toml +19 -0
- package/native/watchos/shaders/bloom_postfx.metal +99 -0
- package/native/watchos/src/BloomWatchApp.swift +1236 -0
- package/native/watchos/src/BloomWatchAudio.swift +179 -0
- package/native/watchos/src/audio.rs +55 -0
- package/native/watchos/src/draw_list.rs +223 -0
- package/native/watchos/src/ffi_stubs.rs +454 -0
- package/native/watchos/src/lib.rs +1013 -0
- package/native/watchos/src/models.rs +746 -0
- package/native/watchos/src/postfx.rs +91 -0
- package/native/watchos/src/scene.rs +534 -0
- package/native/watchos/src/textures.rs +184 -0
- package/native/web/Cargo.lock +1656 -0
- package/native/web/Cargo.toml +38 -0
- package/native/web/bloom_glue.js +218 -0
- package/native/web/build.sh +101 -0
- package/native/web/index.html +390 -0
- package/native/web/jolt_bridge.js +1311 -0
- package/native/web/src/lib.rs +2739 -0
- package/native/windows/Cargo.lock +1813 -0
- package/native/windows/Cargo.toml +31 -0
- package/native/windows/src/lib.rs +1933 -0
- package/package.json +558 -0
- package/src/audio/index.ts +151 -0
- package/src/core/colors.ts +56 -0
- package/src/core/index.ts +903 -0
- package/src/core/keys.ts +63 -0
- package/src/core/types.ts +102 -0
- package/src/index.ts +158 -0
- package/src/math/index.ts +502 -0
- package/src/mobile/index.ts +294 -0
- package/src/models/index.ts +859 -0
- package/src/physics/index.ts +1072 -0
- package/src/scene/index.ts +570 -0
- package/src/shapes/index.ts +120 -0
- package/src/text/index.ts +48 -0
- package/src/textures/index.ts +173 -0
- package/src/world/index.ts +22 -0
- package/src/world/loader.ts +385 -0
- package/src/world/prefab.ts +205 -0
- package/src/world/saver.ts +61 -0
- package/src/world/terrain.ts +254 -0
- package/src/world/types.ts +136 -0
- package/src/world/validate.ts +202 -0
- 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
|
+
}
|