@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,2258 @@
|
|
|
1
|
+
use bloom_shared::engine::EngineState;
|
|
2
|
+
use bloom_shared::renderer::Renderer;
|
|
3
|
+
use bloom_shared::string_header::str_from_header;
|
|
4
|
+
use bloom_shared::audio::{parse_wav, parse_ogg, parse_mp3, SoundData};
|
|
5
|
+
|
|
6
|
+
use objc2::encode::{Encode, Encoding, RefEncode};
|
|
7
|
+
use objc2::rc::{Allocated, Retained};
|
|
8
|
+
use objc2::runtime::{AnyClass, AnyObject, Bool, Sel};
|
|
9
|
+
use objc2::{msg_send, sel};
|
|
10
|
+
|
|
11
|
+
use raw_window_handle::{RawDisplayHandle, RawWindowHandle, UiKitDisplayHandle, UiKitWindowHandle};
|
|
12
|
+
|
|
13
|
+
use std::ffi::c_void;
|
|
14
|
+
use std::sync::OnceLock;
|
|
15
|
+
|
|
16
|
+
static mut ENGINE: OnceLock<EngineState> = OnceLock::new();
|
|
17
|
+
static mut UI_WINDOW: Option<Retained<AnyObject>> = None;
|
|
18
|
+
static mut UI_VIEW: Option<Retained<AnyObject>> = None;
|
|
19
|
+
static mut TOUCH_MAP: [*const c_void; 10] = [std::ptr::null(); 10];
|
|
20
|
+
static mut BUNDLE_PATH: Option<String> = None;
|
|
21
|
+
static mut SCREEN_SCALE: f64 = 1.0;
|
|
22
|
+
/// UIInterfaceOrientationMask for the root view controller.
|
|
23
|
+
/// Default: all (0x1E). Set to landscape (0x18) from bloom_init_window when width > height.
|
|
24
|
+
static mut ORIENTATION_MASK: u64 = 0x1E; // UIInterfaceOrientationMaskAll
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/// Resolve a relative asset path to the app bundle path.
|
|
28
|
+
fn resolve_path(path: &str) -> String {
|
|
29
|
+
if path.starts_with('/') {
|
|
30
|
+
return path.to_string();
|
|
31
|
+
}
|
|
32
|
+
unsafe {
|
|
33
|
+
if let Some(ref base) = BUNDLE_PATH {
|
|
34
|
+
format!("{}/{}", base, path)
|
|
35
|
+
} else {
|
|
36
|
+
path.to_string()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn engine() -> &'static mut EngineState {
|
|
42
|
+
unsafe { ENGINE.get_mut().expect("Engine not initialized") }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ============================================================
|
|
46
|
+
// CG types with objc2 Encode
|
|
47
|
+
// ============================================================
|
|
48
|
+
|
|
49
|
+
#[repr(C)]
|
|
50
|
+
#[derive(Copy, Clone)]
|
|
51
|
+
struct CGPoint { x: f64, y: f64 }
|
|
52
|
+
|
|
53
|
+
unsafe impl Encode for CGPoint {
|
|
54
|
+
const ENCODING: Encoding = Encoding::Struct("CGPoint", &[Encoding::Double, Encoding::Double]);
|
|
55
|
+
}
|
|
56
|
+
unsafe impl RefEncode for CGPoint {
|
|
57
|
+
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[repr(C)]
|
|
61
|
+
#[derive(Copy, Clone)]
|
|
62
|
+
struct CGSize { width: f64, height: f64 }
|
|
63
|
+
|
|
64
|
+
unsafe impl Encode for CGSize {
|
|
65
|
+
const ENCODING: Encoding = Encoding::Struct("CGSize", &[Encoding::Double, Encoding::Double]);
|
|
66
|
+
}
|
|
67
|
+
unsafe impl RefEncode for CGSize {
|
|
68
|
+
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#[repr(C)]
|
|
72
|
+
#[derive(Copy, Clone)]
|
|
73
|
+
struct CGRect { origin: CGPoint, size: CGSize }
|
|
74
|
+
|
|
75
|
+
unsafe impl Encode for CGRect {
|
|
76
|
+
const ENCODING: Encoding = Encoding::Struct("CGRect", &[CGPoint::ENCODING, CGSize::ENCODING]);
|
|
77
|
+
}
|
|
78
|
+
unsafe impl RefEncode for CGRect {
|
|
79
|
+
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ============================================================
|
|
83
|
+
// ObjC runtime
|
|
84
|
+
// ============================================================
|
|
85
|
+
|
|
86
|
+
extern "C" {
|
|
87
|
+
fn objc_allocateClassPair(superclass: *const AnyClass, name: *const u8, extra_bytes: usize) -> *mut AnyClass;
|
|
88
|
+
fn objc_registerClassPair(cls: *mut AnyClass);
|
|
89
|
+
fn class_addMethod(cls: *mut AnyClass, sel: Sel, imp: *const c_void, types: *const u8) -> bool;
|
|
90
|
+
|
|
91
|
+
fn CFRunLoopRunInMode(mode: *const c_void, seconds: f64, return_after: u8) -> i32;
|
|
92
|
+
static kCFRunLoopDefaultMode: *const c_void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn pump_run_loop(seconds: f64) {
|
|
96
|
+
unsafe { CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 0); }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ============================================================
|
|
100
|
+
// Register BloomMetalView — UIView subclass with +layerClass = CAMetalLayer
|
|
101
|
+
// ============================================================
|
|
102
|
+
|
|
103
|
+
unsafe extern "C" fn bloom_layer_class(_cls: *const c_void, _sel: Sel) -> *const c_void {
|
|
104
|
+
AnyClass::get(c"CAMetalLayer").unwrap() as *const AnyClass as *const c_void
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
unsafe extern "C" fn bloom_touches_began(_this: *mut c_void, _sel: Sel, touches: *const AnyObject, _event: *const AnyObject) {
|
|
108
|
+
handle_touches(touches, TouchPhase::Began);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
unsafe extern "C" fn bloom_touches_moved(_this: *mut c_void, _sel: Sel, touches: *const AnyObject, _event: *const AnyObject) {
|
|
112
|
+
handle_touches(touches, TouchPhase::Moved);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
unsafe extern "C" fn bloom_touches_ended(_this: *mut c_void, _sel: Sel, touches: *const AnyObject, _event: *const AnyObject) {
|
|
116
|
+
handle_touches(touches, TouchPhase::Ended);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
unsafe extern "C" fn bloom_touches_cancelled(_this: *mut c_void, _sel: Sel, touches: *const AnyObject, _event: *const AnyObject) {
|
|
120
|
+
handle_touches(touches, TouchPhase::Ended);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
enum TouchPhase { Began, Moved, Ended }
|
|
124
|
+
|
|
125
|
+
unsafe fn handle_touches(touches: *const AnyObject, phase: TouchPhase) {
|
|
126
|
+
if touches.is_null() { return; }
|
|
127
|
+
|
|
128
|
+
let view_ptr: *const AnyObject = match UI_VIEW.as_ref() {
|
|
129
|
+
Some(v) => Retained::as_ptr(v),
|
|
130
|
+
None => std::ptr::null(),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
let enumerator: Retained<AnyObject> = msg_send![&*touches, objectEnumerator];
|
|
134
|
+
loop {
|
|
135
|
+
let touch: *const AnyObject = msg_send![&*enumerator, nextObject];
|
|
136
|
+
if touch.is_null() { break; }
|
|
137
|
+
|
|
138
|
+
let touch_id = touch as *const c_void;
|
|
139
|
+
let loc: CGPoint = msg_send![&*touch, locationInView: view_ptr];
|
|
140
|
+
|
|
141
|
+
let index = match phase {
|
|
142
|
+
TouchPhase::Began => {
|
|
143
|
+
let mut slot = None;
|
|
144
|
+
for i in 0..10 {
|
|
145
|
+
if TOUCH_MAP[i].is_null() {
|
|
146
|
+
TOUCH_MAP[i] = touch_id;
|
|
147
|
+
slot = Some(i);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
match slot {
|
|
152
|
+
Some(i) => i,
|
|
153
|
+
None => continue,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
TouchPhase::Moved => {
|
|
157
|
+
match TOUCH_MAP.iter().position(|&p| p == touch_id) {
|
|
158
|
+
Some(i) => i,
|
|
159
|
+
None => continue,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
TouchPhase::Ended => {
|
|
163
|
+
match TOUCH_MAP.iter().position(|&p| p == touch_id) {
|
|
164
|
+
Some(i) => {
|
|
165
|
+
TOUCH_MAP[i] = std::ptr::null();
|
|
166
|
+
i
|
|
167
|
+
}
|
|
168
|
+
None => continue,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
if let Some(eng) = ENGINE.get_mut() {
|
|
174
|
+
let active = !matches!(phase, TouchPhase::Ended);
|
|
175
|
+
// Scale touch from points to pixels to match getScreenWidth/Height
|
|
176
|
+
let sx = loc.x * SCREEN_SCALE;
|
|
177
|
+
let sy = loc.y * SCREEN_SCALE;
|
|
178
|
+
eng.input.set_touch(index, sx, sy, active);
|
|
179
|
+
|
|
180
|
+
if index == 0 {
|
|
181
|
+
eng.input.set_mouse_position(sx, sy);
|
|
182
|
+
if active {
|
|
183
|
+
eng.input.set_mouse_button_down(0);
|
|
184
|
+
} else {
|
|
185
|
+
eng.input.set_mouse_button_up(0);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
fn register_metal_view_class() {
|
|
193
|
+
if AnyClass::get(c"BloomMetalView").is_some() { return; }
|
|
194
|
+
|
|
195
|
+
unsafe {
|
|
196
|
+
let superclass = AnyClass::get(c"UIView").unwrap();
|
|
197
|
+
let cls = objc_allocateClassPair(superclass as *const AnyClass, b"BloomMetalView\0".as_ptr(), 0);
|
|
198
|
+
if cls.is_null() { return; }
|
|
199
|
+
|
|
200
|
+
extern "C" { fn object_getClass(obj: *const c_void) -> *mut AnyClass; }
|
|
201
|
+
let meta = object_getClass(cls as *const c_void);
|
|
202
|
+
|
|
203
|
+
class_addMethod(meta, sel!(layerClass), bloom_layer_class as *const c_void, b"#8@0:8\0".as_ptr());
|
|
204
|
+
|
|
205
|
+
let touch_types = b"v32@0:8@16@24\0".as_ptr();
|
|
206
|
+
class_addMethod(cls, sel!(touchesBegan:withEvent:), bloom_touches_began as *const c_void, touch_types);
|
|
207
|
+
class_addMethod(cls, sel!(touchesMoved:withEvent:), bloom_touches_moved as *const c_void, touch_types);
|
|
208
|
+
class_addMethod(cls, sel!(touchesEnded:withEvent:), bloom_touches_ended as *const c_void, touch_types);
|
|
209
|
+
class_addMethod(cls, sel!(touchesCancelled:withEvent:), bloom_touches_cancelled as *const c_void, touch_types);
|
|
210
|
+
|
|
211
|
+
objc_registerClassPair(cls);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ============================================================
|
|
216
|
+
// Register BloomViewController — UIViewController with orientation lock
|
|
217
|
+
// ============================================================
|
|
218
|
+
|
|
219
|
+
unsafe extern "C" fn bloom_vc_supported_orientations(_this: *const c_void, _sel: Sel) -> u64 {
|
|
220
|
+
unsafe { ORIENTATION_MASK }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fn register_view_controller_class() {
|
|
224
|
+
if AnyClass::get(c"BloomViewController").is_some() { return; }
|
|
225
|
+
|
|
226
|
+
unsafe {
|
|
227
|
+
let superclass = AnyClass::get(c"UIViewController").unwrap();
|
|
228
|
+
let cls = objc_allocateClassPair(superclass as *const AnyClass, b"BloomViewController\0".as_ptr(), 0);
|
|
229
|
+
if cls.is_null() { return; }
|
|
230
|
+
|
|
231
|
+
let sel = Sel::register(c"supportedInterfaceOrientations");
|
|
232
|
+
class_addMethod(cls, sel, bloom_vc_supported_orientations as *const c_void, b"Q16@0:8\0".as_ptr());
|
|
233
|
+
|
|
234
|
+
objc_registerClassPair(cls);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ============================================================
|
|
239
|
+
// Scene delegate — creates UIWindow + Metal view + wgpu engine
|
|
240
|
+
// ============================================================
|
|
241
|
+
|
|
242
|
+
unsafe extern "C" fn scene_will_connect(
|
|
243
|
+
_this: *mut c_void,
|
|
244
|
+
_sel: Sel,
|
|
245
|
+
scene: *const AnyObject,
|
|
246
|
+
_session: *const AnyObject,
|
|
247
|
+
_options: *const AnyObject,
|
|
248
|
+
) {
|
|
249
|
+
if scene.is_null() { return; }
|
|
250
|
+
|
|
251
|
+
// Get screen bounds from UIScreen.mainScreen (simpler than scene.screen)
|
|
252
|
+
let screen_cls = AnyClass::get(c"UIScreen").unwrap();
|
|
253
|
+
let screen: Retained<AnyObject> = msg_send![screen_cls, mainScreen];
|
|
254
|
+
let bounds: CGRect = msg_send![&*screen, bounds];
|
|
255
|
+
let scale: f64 = msg_send![&*screen, scale];
|
|
256
|
+
|
|
257
|
+
let pixel_width = (bounds.size.width * scale) as u32;
|
|
258
|
+
let pixel_height = (bounds.size.height * scale) as u32;
|
|
259
|
+
|
|
260
|
+
// Create UIWindow attached to the scene
|
|
261
|
+
let window_cls = AnyClass::get(c"UIWindow").unwrap();
|
|
262
|
+
let window: Allocated<AnyObject> = msg_send![window_cls, alloc];
|
|
263
|
+
let window: Retained<AnyObject> = msg_send![window, initWithWindowScene: scene];
|
|
264
|
+
|
|
265
|
+
// Create BloomViewController (with orientation lock support)
|
|
266
|
+
let vc_cls = AnyClass::get(c"BloomViewController")
|
|
267
|
+
.unwrap_or_else(|| AnyClass::get(c"UIViewController").unwrap());
|
|
268
|
+
let vc: Allocated<AnyObject> = msg_send![vc_cls, alloc];
|
|
269
|
+
let vc: Retained<AnyObject> = msg_send![vc, init];
|
|
270
|
+
|
|
271
|
+
// Create BloomMetalView
|
|
272
|
+
let view_cls = AnyClass::get(c"BloomMetalView").unwrap();
|
|
273
|
+
let view: Allocated<AnyObject> = msg_send![view_cls, alloc];
|
|
274
|
+
let view: Retained<AnyObject> = msg_send![view, initWithFrame: bounds];
|
|
275
|
+
|
|
276
|
+
// Set background to green (diagnostic — visible if Metal isn't rendering)
|
|
277
|
+
let color_cls = AnyClass::get(c"UIColor").unwrap();
|
|
278
|
+
let green: Retained<AnyObject> = msg_send![color_cls, greenColor];
|
|
279
|
+
let _: () = msg_send![&*view, setBackgroundColor: &*green];
|
|
280
|
+
|
|
281
|
+
// Configure CAMetalLayer
|
|
282
|
+
let layer: Retained<AnyObject> = msg_send![&*view, layer];
|
|
283
|
+
let drawable_size = CGSize { width: pixel_width as f64, height: pixel_height as f64 };
|
|
284
|
+
let _: () = msg_send![&*layer, setDrawableSize: drawable_size];
|
|
285
|
+
let _: () = msg_send![&*layer, setContentsScale: scale];
|
|
286
|
+
let _: () = msg_send![&*layer, setOpaque: Bool::NO]; // Non-opaque so green shows if Metal fails
|
|
287
|
+
|
|
288
|
+
// Enable touches
|
|
289
|
+
let _: () = msg_send![&*view, setUserInteractionEnabled: Bool::YES];
|
|
290
|
+
let _: () = msg_send![&*view, setMultipleTouchEnabled: Bool::YES];
|
|
291
|
+
|
|
292
|
+
// Set up window hierarchy
|
|
293
|
+
let _: () = msg_send![&*vc, setView: &*view];
|
|
294
|
+
let _: () = msg_send![&*window, setRootViewController: &*vc];
|
|
295
|
+
let _: () = msg_send![&*window, makeKeyAndVisible];
|
|
296
|
+
|
|
297
|
+
// Store references
|
|
298
|
+
UI_VIEW = Some(view.clone());
|
|
299
|
+
UI_WINDOW = Some(window);
|
|
300
|
+
|
|
301
|
+
// Create wgpu surface
|
|
302
|
+
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
|
303
|
+
backends: wgpu::Backends::METAL,
|
|
304
|
+
..wgpu::InstanceDescriptor::new_without_display_handle()
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
let view_ptr = Retained::as_ptr(&view) as *mut c_void;
|
|
308
|
+
let handle = UiKitWindowHandle::new(
|
|
309
|
+
std::ptr::NonNull::new(view_ptr).unwrap(),
|
|
310
|
+
);
|
|
311
|
+
let raw = RawWindowHandle::UiKit(handle);
|
|
312
|
+
let surface = instance.create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle {
|
|
313
|
+
raw_display_handle: Some(RawDisplayHandle::UiKit(UiKitDisplayHandle::new())),
|
|
314
|
+
raw_window_handle: raw,
|
|
315
|
+
}).expect("Failed to create wgpu surface");
|
|
316
|
+
|
|
317
|
+
let adapter = pollster_block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
|
318
|
+
compatible_surface: Some(&surface),
|
|
319
|
+
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
320
|
+
..Default::default()
|
|
321
|
+
})).expect("No GPU adapter found");
|
|
322
|
+
|
|
323
|
+
// Ticket 007b: opt into HW ray-query on RT-capable Apple Silicon
|
|
324
|
+
// devices. `BLOOM_FORCE_SW_GI=1` forces the SW path for bench parity.
|
|
325
|
+
let supported = adapter.features();
|
|
326
|
+
let force_sw_gi = std::env::var("BLOOM_FORCE_SW_GI")
|
|
327
|
+
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
|
|
328
|
+
.unwrap_or(false);
|
|
329
|
+
let rt_mask = wgpu::Features::EXPERIMENTAL_RAY_QUERY;
|
|
330
|
+
let mut required_features = wgpu::Features::empty();
|
|
331
|
+
// Ticket 011: request TIMESTAMP_QUERY when supported so the profiler
|
|
332
|
+
// can record GPU timings. Optional — profiler falls back to CPU-only
|
|
333
|
+
// when the adapter doesn't grant it.
|
|
334
|
+
if supported.contains(wgpu::Features::TIMESTAMP_QUERY) {
|
|
335
|
+
required_features |= wgpu::Features::TIMESTAMP_QUERY;
|
|
336
|
+
}
|
|
337
|
+
if !force_sw_gi && supported.contains(rt_mask) {
|
|
338
|
+
required_features |= rt_mask;
|
|
339
|
+
}
|
|
340
|
+
let experimental_features = if required_features.intersects(rt_mask) {
|
|
341
|
+
unsafe { wgpu::ExperimentalFeatures::enabled() }
|
|
342
|
+
} else {
|
|
343
|
+
wgpu::ExperimentalFeatures::disabled()
|
|
344
|
+
};
|
|
345
|
+
let mut required_limits = wgpu::Limits::default();
|
|
346
|
+
if required_features.intersects(rt_mask) {
|
|
347
|
+
required_limits = required_limits
|
|
348
|
+
.using_minimum_supported_acceleration_structure_values();
|
|
349
|
+
}
|
|
350
|
+
let (device, queue) = pollster_block_on(adapter.request_device(
|
|
351
|
+
&wgpu::DeviceDescriptor {
|
|
352
|
+
label: Some("bloom_device"),
|
|
353
|
+
required_features,
|
|
354
|
+
required_limits,
|
|
355
|
+
experimental_features,
|
|
356
|
+
..Default::default()
|
|
357
|
+
},
|
|
358
|
+
)).expect("Failed to create device");
|
|
359
|
+
|
|
360
|
+
let surface_caps = surface.get_capabilities(&adapter);
|
|
361
|
+
let format = surface_caps.formats.iter()
|
|
362
|
+
.find(|f| f.is_srgb()).copied()
|
|
363
|
+
.unwrap_or(surface_caps.formats[0]);
|
|
364
|
+
|
|
365
|
+
let surface_config = wgpu::SurfaceConfiguration {
|
|
366
|
+
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
367
|
+
format,
|
|
368
|
+
width: pixel_width,
|
|
369
|
+
height: pixel_height,
|
|
370
|
+
present_mode: wgpu::PresentMode::Fifo,
|
|
371
|
+
alpha_mode: surface_caps.alpha_modes[0],
|
|
372
|
+
view_formats: vec![],
|
|
373
|
+
desired_maximum_frame_latency: 2,
|
|
374
|
+
};
|
|
375
|
+
surface.configure(&device, &surface_config);
|
|
376
|
+
|
|
377
|
+
let renderer = Renderer::new(device, queue, surface, surface_config, pixel_width, pixel_height);
|
|
378
|
+
let _ = ENGINE.set(EngineState::new(renderer));
|
|
379
|
+
|
|
380
|
+
// Write debug info to app container tmp
|
|
381
|
+
{
|
|
382
|
+
let ns_cls = AnyClass::get(c"NSTemporaryDirectory").unwrap_or(AnyClass::get(c"NSString").unwrap());
|
|
383
|
+
// Use NSFileManager to get tmp dir
|
|
384
|
+
extern "C" { fn NSTemporaryDirectory() -> *const AnyObject; }
|
|
385
|
+
let tmp_dir: *const AnyObject = NSTemporaryDirectory();
|
|
386
|
+
if !tmp_dir.is_null() {
|
|
387
|
+
let utf8: *const u8 = msg_send![&*tmp_dir, UTF8String];
|
|
388
|
+
if !utf8.is_null() {
|
|
389
|
+
let cstr_val = std::ffi::CStr::from_ptr(utf8 as *const i8);
|
|
390
|
+
if let Ok(tmp_path) = cstr_val.to_str() {
|
|
391
|
+
let _ = std::fs::write(format!("{}bloom_debug.txt", tmp_path),
|
|
392
|
+
format!("scene_will_connect OK\npixels={}x{} scale={}\nwindow_scene={}\n",
|
|
393
|
+
pixel_width, pixel_height, scale, !scene.is_null()));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ENGINE is now set — bloom_init_window polls for this on the game thread
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/// Called by the perry runtime's main() before UIApplicationMain to register
|
|
403
|
+
/// ObjC classes needed for the scene lifecycle.
|
|
404
|
+
#[no_mangle]
|
|
405
|
+
pub unsafe extern "C" fn perry_register_native_classes() {
|
|
406
|
+
register_metal_view_class();
|
|
407
|
+
register_view_controller_class();
|
|
408
|
+
register_scene_delegate();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/// Called by the runtime's scene delegate when the UIWindowScene connects.
|
|
412
|
+
/// This runs on the main thread — safe for all UIKit operations.
|
|
413
|
+
#[no_mangle]
|
|
414
|
+
pub unsafe extern "C" fn perry_scene_will_connect(scene: *const c_void) {
|
|
415
|
+
let screen_cls = AnyClass::get(c"UIScreen").unwrap();
|
|
416
|
+
let screen: Retained<AnyObject> = msg_send![screen_cls, mainScreen];
|
|
417
|
+
let bounds: CGRect = msg_send![&*screen, bounds];
|
|
418
|
+
let scale: f64 = msg_send![&*screen, scale];
|
|
419
|
+
|
|
420
|
+
let pixel_width = (bounds.size.width * scale) as u32;
|
|
421
|
+
let pixel_height = (bounds.size.height * scale) as u32;
|
|
422
|
+
|
|
423
|
+
// Store scale for touch coordinate conversion (points → pixels)
|
|
424
|
+
SCREEN_SCALE = scale;
|
|
425
|
+
|
|
426
|
+
// Create UIWindow — attached to scene if available, otherwise plain
|
|
427
|
+
let window_cls = AnyClass::get(c"UIWindow").unwrap();
|
|
428
|
+
let window: Retained<AnyObject> = if !scene.is_null() {
|
|
429
|
+
let w: Allocated<AnyObject> = msg_send![window_cls, alloc];
|
|
430
|
+
msg_send![w, initWithWindowScene: scene as *const AnyObject]
|
|
431
|
+
} else {
|
|
432
|
+
let w: Allocated<AnyObject> = msg_send![window_cls, alloc];
|
|
433
|
+
msg_send![w, initWithFrame: bounds]
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
// Create BloomViewController (with orientation lock support)
|
|
437
|
+
let vc_cls = AnyClass::get(c"BloomViewController")
|
|
438
|
+
.unwrap_or_else(|| AnyClass::get(c"UIViewController").unwrap());
|
|
439
|
+
let vc: Allocated<AnyObject> = msg_send![vc_cls, alloc];
|
|
440
|
+
let vc: Retained<AnyObject> = msg_send![vc, init];
|
|
441
|
+
|
|
442
|
+
// Create BloomMetalView
|
|
443
|
+
let view_cls = AnyClass::get(c"BloomMetalView").unwrap();
|
|
444
|
+
let view: Allocated<AnyObject> = msg_send![view_cls, alloc];
|
|
445
|
+
let view: Retained<AnyObject> = msg_send![view, initWithFrame: bounds];
|
|
446
|
+
|
|
447
|
+
// Set background to black
|
|
448
|
+
let color_cls = AnyClass::get(c"UIColor").unwrap();
|
|
449
|
+
let black: Retained<AnyObject> = msg_send![color_cls, blackColor];
|
|
450
|
+
let _: () = msg_send![&*view, setBackgroundColor: &*black];
|
|
451
|
+
|
|
452
|
+
// Configure CAMetalLayer
|
|
453
|
+
let layer: Retained<AnyObject> = msg_send![&*view, layer];
|
|
454
|
+
let drawable_size = CGSize { width: pixel_width as f64, height: pixel_height as f64 };
|
|
455
|
+
let _: () = msg_send![&*layer, setDrawableSize: drawable_size];
|
|
456
|
+
let _: () = msg_send![&*layer, setContentsScale: scale];
|
|
457
|
+
let _: () = msg_send![&*layer, setOpaque: Bool::YES];
|
|
458
|
+
|
|
459
|
+
// Enable touches
|
|
460
|
+
let _: () = msg_send![&*view, setUserInteractionEnabled: Bool::YES];
|
|
461
|
+
let _: () = msg_send![&*view, setMultipleTouchEnabled: Bool::YES];
|
|
462
|
+
|
|
463
|
+
// Set up window hierarchy
|
|
464
|
+
let _: () = msg_send![&*vc, setView: &*view];
|
|
465
|
+
let _: () = msg_send![&*window, setRootViewController: &*vc];
|
|
466
|
+
let _: () = msg_send![&*window, makeKeyAndVisible];
|
|
467
|
+
|
|
468
|
+
// Store references
|
|
469
|
+
UI_VIEW = Some(view.clone());
|
|
470
|
+
UI_WINDOW = Some(window);
|
|
471
|
+
|
|
472
|
+
// Create wgpu surface and engine
|
|
473
|
+
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
|
474
|
+
backends: wgpu::Backends::METAL,
|
|
475
|
+
..wgpu::InstanceDescriptor::new_without_display_handle()
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
let view_ptr = Retained::as_ptr(&view) as *mut c_void;
|
|
479
|
+
let handle = UiKitWindowHandle::new(
|
|
480
|
+
std::ptr::NonNull::new(view_ptr).unwrap(),
|
|
481
|
+
);
|
|
482
|
+
let raw = RawWindowHandle::UiKit(handle);
|
|
483
|
+
let surface = instance.create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle {
|
|
484
|
+
raw_display_handle: Some(RawDisplayHandle::UiKit(UiKitDisplayHandle::new())),
|
|
485
|
+
raw_window_handle: raw,
|
|
486
|
+
}).expect("Failed to create wgpu surface");
|
|
487
|
+
|
|
488
|
+
let adapter = pollster_block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
|
489
|
+
compatible_surface: Some(&surface),
|
|
490
|
+
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
491
|
+
..Default::default()
|
|
492
|
+
})).expect("No GPU adapter found");
|
|
493
|
+
|
|
494
|
+
// Ticket 007b: opt into HW ray-query on RT-capable Apple Silicon
|
|
495
|
+
// devices. `BLOOM_FORCE_SW_GI=1` forces the SW path for bench parity.
|
|
496
|
+
let supported = adapter.features();
|
|
497
|
+
let force_sw_gi = std::env::var("BLOOM_FORCE_SW_GI")
|
|
498
|
+
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
|
|
499
|
+
.unwrap_or(false);
|
|
500
|
+
let rt_mask = wgpu::Features::EXPERIMENTAL_RAY_QUERY;
|
|
501
|
+
let mut required_features = wgpu::Features::empty();
|
|
502
|
+
// Ticket 011: request TIMESTAMP_QUERY when supported so the profiler
|
|
503
|
+
// can record GPU timings. Optional — profiler falls back to CPU-only
|
|
504
|
+
// when the adapter doesn't grant it.
|
|
505
|
+
if supported.contains(wgpu::Features::TIMESTAMP_QUERY) {
|
|
506
|
+
required_features |= wgpu::Features::TIMESTAMP_QUERY;
|
|
507
|
+
}
|
|
508
|
+
if !force_sw_gi && supported.contains(rt_mask) {
|
|
509
|
+
required_features |= rt_mask;
|
|
510
|
+
}
|
|
511
|
+
let experimental_features = if required_features.intersects(rt_mask) {
|
|
512
|
+
unsafe { wgpu::ExperimentalFeatures::enabled() }
|
|
513
|
+
} else {
|
|
514
|
+
wgpu::ExperimentalFeatures::disabled()
|
|
515
|
+
};
|
|
516
|
+
let mut required_limits = wgpu::Limits::default();
|
|
517
|
+
if required_features.intersects(rt_mask) {
|
|
518
|
+
required_limits = required_limits
|
|
519
|
+
.using_minimum_supported_acceleration_structure_values();
|
|
520
|
+
}
|
|
521
|
+
let (device, queue) = pollster_block_on(adapter.request_device(
|
|
522
|
+
&wgpu::DeviceDescriptor {
|
|
523
|
+
label: Some("bloom_device"),
|
|
524
|
+
required_features,
|
|
525
|
+
required_limits,
|
|
526
|
+
experimental_features,
|
|
527
|
+
..Default::default()
|
|
528
|
+
},
|
|
529
|
+
)).expect("Failed to create device");
|
|
530
|
+
|
|
531
|
+
let surface_caps = surface.get_capabilities(&adapter);
|
|
532
|
+
let format = surface_caps.formats.iter()
|
|
533
|
+
.find(|f| f.is_srgb()).copied()
|
|
534
|
+
.unwrap_or(surface_caps.formats[0]);
|
|
535
|
+
|
|
536
|
+
let surface_config = wgpu::SurfaceConfiguration {
|
|
537
|
+
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
538
|
+
format,
|
|
539
|
+
width: pixel_width,
|
|
540
|
+
height: pixel_height,
|
|
541
|
+
present_mode: wgpu::PresentMode::Fifo,
|
|
542
|
+
alpha_mode: surface_caps.alpha_modes[0],
|
|
543
|
+
view_formats: vec![],
|
|
544
|
+
desired_maximum_frame_latency: 2,
|
|
545
|
+
};
|
|
546
|
+
surface.configure(&device, &surface_config);
|
|
547
|
+
|
|
548
|
+
let renderer = Renderer::new(device, queue, surface, surface_config, pixel_width, pixel_height);
|
|
549
|
+
let _ = ENGINE.set(EngineState::new(renderer));
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
fn register_scene_delegate() {
|
|
553
|
+
if AnyClass::get(c"PerrySceneDelegate").is_some() { return; }
|
|
554
|
+
|
|
555
|
+
unsafe {
|
|
556
|
+
let superclass = AnyClass::get(c"UIResponder").unwrap();
|
|
557
|
+
let cls = objc_allocateClassPair(superclass as *const AnyClass, b"PerrySceneDelegate\0".as_ptr(), 0);
|
|
558
|
+
if cls.is_null() { return; }
|
|
559
|
+
|
|
560
|
+
// scene:willConnectToSession:connectionOptions:
|
|
561
|
+
let sel = Sel::register(c"scene:willConnectToSession:connectionOptions:");
|
|
562
|
+
let types = b"v48@0:8@16@24@32\0".as_ptr();
|
|
563
|
+
class_addMethod(cls, sel, scene_will_connect as *const c_void, types);
|
|
564
|
+
|
|
565
|
+
// Add UIWindowSceneDelegate protocol
|
|
566
|
+
extern "C" { fn objc_getProtocol(name: *const u8) -> *const c_void; }
|
|
567
|
+
let protocol = objc_getProtocol(b"UIWindowSceneDelegate\0".as_ptr());
|
|
568
|
+
if !protocol.is_null() {
|
|
569
|
+
extern "C" { fn class_addProtocol(cls: *mut AnyClass, protocol: *const c_void) -> bool; }
|
|
570
|
+
class_addProtocol(cls, protocol);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
objc_registerClassPair(cls);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ============================================================
|
|
578
|
+
// Minimal pollster
|
|
579
|
+
// ============================================================
|
|
580
|
+
|
|
581
|
+
fn pollster_block_on<F: std::future::Future>(future: F) -> F::Output {
|
|
582
|
+
use std::task::{Context, Poll, Wake, Waker};
|
|
583
|
+
use std::pin::Pin;
|
|
584
|
+
use std::sync::Arc;
|
|
585
|
+
struct NoopWaker;
|
|
586
|
+
impl Wake for NoopWaker { fn wake(self: Arc<Self>) {} }
|
|
587
|
+
let waker = Waker::from(Arc::new(NoopWaker));
|
|
588
|
+
let mut cx = Context::from_waker(&waker);
|
|
589
|
+
let mut future = unsafe { Pin::new_unchecked(Box::new(future)) };
|
|
590
|
+
loop {
|
|
591
|
+
match future.as_mut().poll(&mut cx) {
|
|
592
|
+
Poll::Ready(result) => return result,
|
|
593
|
+
Poll::Pending => {
|
|
594
|
+
pump_run_loop(0.001);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// ============================================================
|
|
601
|
+
// FFI entry points
|
|
602
|
+
// ============================================================
|
|
603
|
+
|
|
604
|
+
#[no_mangle]
|
|
605
|
+
pub extern "C" fn bloom_init_window(_width: f64, _height: f64, title_ptr: *const u8, _fullscreen: f64) {
|
|
606
|
+
let _title = str_from_header(title_ptr);
|
|
607
|
+
|
|
608
|
+
// Set orientation mask based on requested dimensions
|
|
609
|
+
// width > height → landscape, otherwise all orientations
|
|
610
|
+
if _width > _height {
|
|
611
|
+
unsafe { ORIENTATION_MASK = 0x18; } // UIInterfaceOrientationMaskLandscape
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Register ObjC classes for the scene delegate (window/view creation)
|
|
615
|
+
register_metal_view_class();
|
|
616
|
+
register_view_controller_class();
|
|
617
|
+
register_scene_delegate();
|
|
618
|
+
|
|
619
|
+
// Signal the main thread that our ObjC classes are ready.
|
|
620
|
+
// UIApplicationMain (on main thread) waits for this before starting.
|
|
621
|
+
extern "C" { fn perry_ios_classes_registered(); }
|
|
622
|
+
unsafe { perry_ios_classes_registered(); }
|
|
623
|
+
|
|
624
|
+
// Debug: write marker to confirm we reached this point
|
|
625
|
+
let _ = std::fs::write("/tmp/bloom_checkpoint_1.txt", "classes registered\n");
|
|
626
|
+
|
|
627
|
+
// Get app bundle path for resolving relative asset paths
|
|
628
|
+
unsafe {
|
|
629
|
+
let bundle_cls = AnyClass::get(c"NSBundle").unwrap();
|
|
630
|
+
let main_bundle: Retained<AnyObject> = msg_send![bundle_cls, mainBundle];
|
|
631
|
+
let resource_path: *const AnyObject = msg_send![&*main_bundle, resourcePath];
|
|
632
|
+
if !resource_path.is_null() {
|
|
633
|
+
let utf8: *const u8 = msg_send![&*resource_path, UTF8String];
|
|
634
|
+
if !utf8.is_null() {
|
|
635
|
+
let cstr = std::ffi::CStr::from_ptr(utf8 as *const i8);
|
|
636
|
+
if let Ok(s) = cstr.to_str() {
|
|
637
|
+
BUNDLE_PATH = Some(s.to_string());
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// With --features ios-game-loop, this function runs on the game thread.
|
|
644
|
+
// UIApplicationMain runs on the main thread. The runtime's scene delegate
|
|
645
|
+
// calls perry_scene_will_connect() which creates the window, view, wgpu
|
|
646
|
+
// surface, and ENGINE — all on the main thread. We just wait for it.
|
|
647
|
+
unsafe {
|
|
648
|
+
for _ in 0..1000 {
|
|
649
|
+
if ENGINE.get().is_some() { break; }
|
|
650
|
+
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if unsafe { ENGINE.get().is_none() } {
|
|
655
|
+
panic!("[bloom-ios] Engine not initialized after 10s. \
|
|
656
|
+
Compile with: perry compile --target ios-simulator --features ios-game-loop");
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
#[no_mangle]
|
|
661
|
+
pub extern "C" fn bloom_close_window() {
|
|
662
|
+
unsafe { UI_VIEW = None; UI_WINDOW = None; }
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
#[no_mangle]
|
|
666
|
+
pub extern "C" fn bloom_window_should_close() -> f64 {
|
|
667
|
+
if engine().should_close { 1.0 } else { 0.0 }
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
#[no_mangle]
|
|
671
|
+
pub extern "C" fn bloom_begin_drawing() {
|
|
672
|
+
// No run loop pumping needed — UIApplicationMain handles the main run loop
|
|
673
|
+
// on its own thread. The game runs on the game thread.
|
|
674
|
+
|
|
675
|
+
// Update drawable size to match actual view bounds (handles orientation changes)
|
|
676
|
+
unsafe {
|
|
677
|
+
if let Some(view) = &UI_VIEW {
|
|
678
|
+
let view_ptr = Retained::as_ptr(view);
|
|
679
|
+
let layer: Retained<AnyObject> = msg_send![&*view_ptr, layer];
|
|
680
|
+
let view_bounds: CGRect = msg_send![&*view_ptr, bounds];
|
|
681
|
+
let scale = SCREEN_SCALE;
|
|
682
|
+
let pw = (view_bounds.size.width * scale) as u32;
|
|
683
|
+
let ph = (view_bounds.size.height * scale) as u32;
|
|
684
|
+
let eng = engine();
|
|
685
|
+
if pw > 0 && ph > 0 && (pw != eng.renderer.width() || ph != eng.renderer.height()) {
|
|
686
|
+
let ds = CGSize { width: pw as f64, height: ph as f64 };
|
|
687
|
+
let _: () = msg_send![&*layer, setDrawableSize: ds];
|
|
688
|
+
eng.renderer.resize(pw, ph, pw, ph);
|
|
689
|
+
} else {
|
|
690
|
+
eng.begin_frame();
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
engine().begin_frame();
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
#[no_mangle]
|
|
699
|
+
pub extern "C" fn bloom_end_drawing() {
|
|
700
|
+
engine().end_frame();
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
#[no_mangle]
|
|
704
|
+
pub extern "C" fn bloom_clear_background(r: f64, g: f64, b: f64, a: f64) {
|
|
705
|
+
engine().renderer.set_clear_color(r, g, b, a);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
#[no_mangle]
|
|
709
|
+
pub extern "C" fn bloom_set_target_fps(fps: f64) { engine().target_fps = fps; }
|
|
710
|
+
|
|
711
|
+
#[no_mangle]
|
|
712
|
+
pub extern "C" fn bloom_set_direct_2d_mode(on: f64) { engine().direct_2d_mode = on > 0.5; }
|
|
713
|
+
|
|
714
|
+
#[no_mangle]
|
|
715
|
+
pub extern "C" fn bloom_get_delta_time() -> f64 { engine().delta_time }
|
|
716
|
+
|
|
717
|
+
#[no_mangle]
|
|
718
|
+
pub extern "C" fn bloom_get_fps() -> f64 { engine().get_fps() }
|
|
719
|
+
|
|
720
|
+
#[no_mangle]
|
|
721
|
+
pub extern "C" fn bloom_get_screen_width() -> f64 { engine().screen_width() }
|
|
722
|
+
|
|
723
|
+
#[no_mangle]
|
|
724
|
+
pub extern "C" fn bloom_get_screen_height() -> f64 { engine().screen_height() }
|
|
725
|
+
|
|
726
|
+
// ============================================================
|
|
727
|
+
// Keyboard input
|
|
728
|
+
// ============================================================
|
|
729
|
+
|
|
730
|
+
#[no_mangle]
|
|
731
|
+
pub extern "C" fn bloom_is_key_pressed(key: f64) -> f64 {
|
|
732
|
+
if engine().input.is_key_pressed(key as usize) { 1.0 } else { 0.0 }
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
#[no_mangle]
|
|
736
|
+
pub extern "C" fn bloom_is_key_down(key: f64) -> f64 {
|
|
737
|
+
if engine().input.is_key_down(key as usize) { 1.0 } else { 0.0 }
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
#[no_mangle]
|
|
741
|
+
pub extern "C" fn bloom_is_key_released(key: f64) -> f64 {
|
|
742
|
+
if engine().input.is_key_released(key as usize) { 1.0 } else { 0.0 }
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// ============================================================
|
|
746
|
+
// Mouse input
|
|
747
|
+
// ============================================================
|
|
748
|
+
|
|
749
|
+
#[no_mangle]
|
|
750
|
+
pub extern "C" fn bloom_get_mouse_x() -> f64 { engine().input.mouse_x }
|
|
751
|
+
|
|
752
|
+
#[no_mangle]
|
|
753
|
+
pub extern "C" fn bloom_get_mouse_y() -> f64 { engine().input.mouse_y }
|
|
754
|
+
|
|
755
|
+
#[no_mangle]
|
|
756
|
+
pub extern "C" fn bloom_is_mouse_button_pressed(btn: f64) -> f64 {
|
|
757
|
+
if engine().input.is_mouse_button_pressed(btn as usize) { 1.0 } else { 0.0 }
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
#[no_mangle]
|
|
761
|
+
pub extern "C" fn bloom_is_mouse_button_down(btn: f64) -> f64 {
|
|
762
|
+
if engine().input.is_mouse_button_down(btn as usize) { 1.0 } else { 0.0 }
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
#[no_mangle]
|
|
766
|
+
pub extern "C" fn bloom_is_mouse_button_released(btn: f64) -> f64 {
|
|
767
|
+
if engine().input.is_mouse_button_released(btn as usize) { 1.0 } else { 0.0 }
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// ============================================================
|
|
771
|
+
// Shape drawing
|
|
772
|
+
// ============================================================
|
|
773
|
+
|
|
774
|
+
#[no_mangle]
|
|
775
|
+
pub extern "C" fn bloom_draw_line(x1: f64, y1: f64, x2: f64, y2: f64, thickness: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
776
|
+
engine().renderer.draw_line(x1, y1, x2, y2, thickness, r, g, b, a);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
#[no_mangle]
|
|
780
|
+
pub extern "C" fn bloom_draw_rect(x: f64, y: f64, w: f64, h: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
781
|
+
engine().renderer.draw_rect(x, y, w, h, r, g, b, a);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
#[no_mangle]
|
|
785
|
+
pub extern "C" fn bloom_draw_rect_lines(x: f64, y: f64, w: f64, h: f64, thickness: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
786
|
+
engine().renderer.draw_rect_lines(x, y, w, h, thickness, r, g, b, a);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
#[no_mangle]
|
|
790
|
+
pub extern "C" fn bloom_draw_circle(cx: f64, cy: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
791
|
+
engine().renderer.draw_circle(cx, cy, radius, r, g, b, a);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
#[no_mangle]
|
|
795
|
+
pub extern "C" fn bloom_draw_circle_lines(cx: f64, cy: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
796
|
+
engine().renderer.draw_circle_lines(cx, cy, radius, r, g, b, a);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
#[no_mangle]
|
|
800
|
+
pub extern "C" fn bloom_draw_triangle(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
801
|
+
engine().renderer.draw_triangle(x1, y1, x2, y2, x3, y3, r, g, b, a);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
#[no_mangle]
|
|
805
|
+
pub extern "C" fn bloom_draw_poly(cx: f64, cy: f64, sides: f64, radius: f64, rotation: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
806
|
+
engine().renderer.draw_poly(cx, cy, sides, radius, rotation, r, g, b, a);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// ============================================================
|
|
810
|
+
// Text
|
|
811
|
+
// ============================================================
|
|
812
|
+
|
|
813
|
+
#[no_mangle]
|
|
814
|
+
pub extern "C" fn bloom_draw_text(text_ptr: *const u8, x: f64, y: f64, size: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
815
|
+
let text = str_from_header(text_ptr);
|
|
816
|
+
let eng = engine();
|
|
817
|
+
let mut text_renderer = std::mem::replace(&mut eng.text, bloom_shared::text_renderer::TextRenderer::empty());
|
|
818
|
+
text_renderer.draw_text(&mut eng.renderer, text, x, y, size as u32, r, g, b, a);
|
|
819
|
+
eng.text = text_renderer;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
#[no_mangle]
|
|
823
|
+
pub extern "C" fn bloom_measure_text(text_ptr: *const u8, size: f64) -> f64 {
|
|
824
|
+
let text = str_from_header(text_ptr);
|
|
825
|
+
engine().text.measure_text(text, size as u32)
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
#[no_mangle]
|
|
829
|
+
pub extern "C" fn bloom_load_font(path_ptr: *const u8, _size: f64) -> f64 {
|
|
830
|
+
let path = str_from_header(path_ptr);
|
|
831
|
+
match std::fs::read(resolve_path(path)) { Ok(data) => engine().text.load_font(&data) as f64, Err(_) => 0.0 }
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
#[no_mangle]
|
|
835
|
+
pub extern "C" fn bloom_unload_font(font_handle: f64) {
|
|
836
|
+
engine().text.unload_font(font_handle as usize);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
#[no_mangle]
|
|
840
|
+
pub extern "C" fn bloom_draw_text_ex(font_handle: f64, text_ptr: *const u8, x: f64, y: f64, size: f64, spacing: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
841
|
+
let text = str_from_header(text_ptr);
|
|
842
|
+
let eng = engine();
|
|
843
|
+
let mut text_renderer = std::mem::replace(&mut eng.text, bloom_shared::text_renderer::TextRenderer::empty());
|
|
844
|
+
text_renderer.draw_text_ex(&mut eng.renderer, font_handle as usize, text, x, y, size as u32, spacing as f32, r, g, b, a);
|
|
845
|
+
eng.text = text_renderer;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
#[no_mangle]
|
|
849
|
+
pub extern "C" fn bloom_measure_text_ex(font_handle: f64, text_ptr: *const u8, size: f64, spacing: f64) -> f64 {
|
|
850
|
+
let text = str_from_header(text_ptr);
|
|
851
|
+
engine().text.measure_text_ex(font_handle as usize, text, size as u32, spacing as f32)
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// ============================================================
|
|
855
|
+
// Textures
|
|
856
|
+
// ============================================================
|
|
857
|
+
|
|
858
|
+
#[no_mangle]
|
|
859
|
+
pub extern "C" fn bloom_load_texture(path_ptr: *const u8) -> f64 {
|
|
860
|
+
let path = str_from_header(path_ptr);
|
|
861
|
+
match std::fs::read(resolve_path(path)) {
|
|
862
|
+
Ok(data) => {
|
|
863
|
+
let eng = engine();
|
|
864
|
+
let renderer_ptr = &mut eng.renderer as *mut Renderer;
|
|
865
|
+
eng.textures.load_texture(unsafe { &mut *renderer_ptr }, &data)
|
|
866
|
+
}
|
|
867
|
+
Err(_) => 0.0,
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
#[no_mangle]
|
|
872
|
+
pub extern "C" fn bloom_unload_texture(handle: f64) {
|
|
873
|
+
let eng = engine();
|
|
874
|
+
let renderer_ptr = &mut eng.renderer as *mut Renderer;
|
|
875
|
+
eng.textures.unload_texture(handle, unsafe { &mut *renderer_ptr });
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
#[no_mangle]
|
|
879
|
+
pub extern "C" fn bloom_draw_texture(handle: f64, x: f64, y: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
880
|
+
let eng = engine();
|
|
881
|
+
if let Some(tex) = eng.textures.get(handle) {
|
|
882
|
+
let idx = tex.bind_group_idx;
|
|
883
|
+
eng.renderer.draw_texture(idx, x, y, r, g, b, a);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
#[no_mangle]
|
|
888
|
+
pub extern "C" fn bloom_draw_texture_pro(
|
|
889
|
+
handle: f64,
|
|
890
|
+
src_x: f64, src_y: f64, src_w: f64, src_h: f64,
|
|
891
|
+
dst_x: f64, dst_y: f64, dst_w: f64, dst_h: f64,
|
|
892
|
+
origin_x: f64, origin_y: f64, rotation: f64,
|
|
893
|
+
r: f64, g: f64, b: f64, a: f64,
|
|
894
|
+
) {
|
|
895
|
+
let eng = engine();
|
|
896
|
+
if let Some(tex) = eng.textures.get(handle) {
|
|
897
|
+
let idx = tex.bind_group_idx;
|
|
898
|
+
eng.renderer.draw_texture_pro(idx, src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h, origin_x, origin_y, rotation, r, g, b, a);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
#[no_mangle]
|
|
903
|
+
pub extern "C" fn bloom_draw_texture_rec(
|
|
904
|
+
handle: f64,
|
|
905
|
+
src_x: f64, src_y: f64, src_w: f64, src_h: f64,
|
|
906
|
+
dst_x: f64, dst_y: f64,
|
|
907
|
+
r: f64, g: f64, b: f64, a: f64,
|
|
908
|
+
) {
|
|
909
|
+
let eng = engine();
|
|
910
|
+
if let Some(tex) = eng.textures.get(handle) {
|
|
911
|
+
let idx = tex.bind_group_idx;
|
|
912
|
+
eng.renderer.draw_texture_rec(idx, src_x, src_y, src_w, src_h, dst_x, dst_y, r, g, b, a);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
#[no_mangle]
|
|
917
|
+
pub extern "C" fn bloom_get_texture_width(handle: f64) -> f64 {
|
|
918
|
+
engine().textures.get(handle).map(|t| t.width as f64).unwrap_or(0.0)
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
#[no_mangle]
|
|
922
|
+
pub extern "C" fn bloom_get_texture_height(handle: f64) -> f64 {
|
|
923
|
+
engine().textures.get(handle).map(|t| t.height as f64).unwrap_or(0.0)
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
#[no_mangle]
|
|
927
|
+
pub extern "C" fn bloom_gen_texture_mipmaps(_handle: f64) {}
|
|
928
|
+
|
|
929
|
+
#[no_mangle]
|
|
930
|
+
pub extern "C" fn bloom_set_texture_filter(handle: f64, mode: f64) {
|
|
931
|
+
let eng = engine();
|
|
932
|
+
if let Some(tex) = eng.textures.get(handle) {
|
|
933
|
+
let bind_group_idx = tex.bind_group_idx;
|
|
934
|
+
eng.renderer.set_texture_filter(bind_group_idx, mode > 0.5);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
#[no_mangle]
|
|
939
|
+
pub extern "C" fn bloom_load_image(path_ptr: *const u8) -> f64 {
|
|
940
|
+
let path = str_from_header(path_ptr);
|
|
941
|
+
match std::fs::read(resolve_path(path)) {
|
|
942
|
+
Ok(data) => engine().textures.load_image(&data),
|
|
943
|
+
Err(_) => 0.0,
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
#[no_mangle]
|
|
948
|
+
pub extern "C" fn bloom_image_resize(handle: f64, w: f64, h: f64) {
|
|
949
|
+
engine().textures.image_resize(handle, w as u32, h as u32);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
#[no_mangle]
|
|
953
|
+
pub extern "C" fn bloom_image_crop(handle: f64, x: f64, y: f64, w: f64, h: f64) {
|
|
954
|
+
engine().textures.image_crop(handle, x as u32, y as u32, w as u32, h as u32);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
#[no_mangle]
|
|
958
|
+
pub extern "C" fn bloom_image_flip_h(handle: f64) {
|
|
959
|
+
engine().textures.image_flip_h(handle);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
#[no_mangle]
|
|
963
|
+
pub extern "C" fn bloom_image_flip_v(handle: f64) {
|
|
964
|
+
engine().textures.image_flip_v(handle);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
#[no_mangle]
|
|
968
|
+
pub extern "C" fn bloom_load_texture_from_image(handle: f64) -> f64 {
|
|
969
|
+
let eng = engine();
|
|
970
|
+
let renderer_ptr = &mut eng.renderer as *mut Renderer;
|
|
971
|
+
eng.textures.load_texture_from_image(handle, unsafe { &mut *renderer_ptr })
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// ============================================================
|
|
975
|
+
// Camera 2D
|
|
976
|
+
// ============================================================
|
|
977
|
+
|
|
978
|
+
#[no_mangle]
|
|
979
|
+
pub extern "C" fn bloom_begin_mode_2d(offset_x: f64, offset_y: f64, target_x: f64, target_y: f64, rotation: f64, zoom: f64) {
|
|
980
|
+
engine().renderer.begin_mode_2d(
|
|
981
|
+
offset_x as f32, offset_y as f32,
|
|
982
|
+
target_x as f32, target_y as f32,
|
|
983
|
+
rotation as f32, zoom as f32,
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
#[no_mangle]
|
|
988
|
+
pub extern "C" fn bloom_end_mode_2d() {
|
|
989
|
+
engine().renderer.end_mode_2d();
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// ============================================================
|
|
993
|
+
// 3D Camera and Drawing
|
|
994
|
+
// ============================================================
|
|
995
|
+
|
|
996
|
+
#[no_mangle]
|
|
997
|
+
pub extern "C" fn bloom_begin_mode_3d(
|
|
998
|
+
pos_x: f64, pos_y: f64, pos_z: f64,
|
|
999
|
+
target_x: f64, target_y: f64, target_z: f64,
|
|
1000
|
+
up_x: f64, up_y: f64, up_z: f64,
|
|
1001
|
+
fovy: f64, projection: f64,
|
|
1002
|
+
) {
|
|
1003
|
+
engine().renderer.begin_mode_3d(
|
|
1004
|
+
pos_x as f32, pos_y as f32, pos_z as f32,
|
|
1005
|
+
target_x as f32, target_y as f32, target_z as f32,
|
|
1006
|
+
up_x as f32, up_y as f32, up_z as f32,
|
|
1007
|
+
fovy as f32, projection as f32,
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
#[no_mangle]
|
|
1012
|
+
pub extern "C" fn bloom_end_mode_3d() {
|
|
1013
|
+
engine().renderer.end_mode_3d();
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
#[no_mangle]
|
|
1017
|
+
pub extern "C" fn bloom_draw_cube(x: f64, y: f64, z: f64, w: f64, h: f64, d: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1018
|
+
engine().renderer.draw_cube(x, y, z, w, h, d, r, g, b, a);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
#[no_mangle]
|
|
1022
|
+
pub extern "C" fn bloom_draw_cube_wires(x: f64, y: f64, z: f64, w: f64, h: f64, d: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1023
|
+
engine().renderer.draw_cube_wires(x, y, z, w, h, d, r, g, b, a);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
#[no_mangle]
|
|
1027
|
+
pub extern "C" fn bloom_draw_sphere(cx: f64, cy: f64, cz: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1028
|
+
engine().renderer.draw_sphere(cx, cy, cz, radius, r, g, b, a);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
#[no_mangle]
|
|
1032
|
+
pub extern "C" fn bloom_draw_sphere_wires(cx: f64, cy: f64, cz: f64, radius: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1033
|
+
engine().renderer.draw_sphere_wires(cx, cy, cz, radius, r, g, b, a);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
#[no_mangle]
|
|
1037
|
+
pub extern "C" fn bloom_draw_cylinder(x: f64, y: f64, z: f64, radius_top: f64, radius_bottom: f64, height: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1038
|
+
engine().renderer.draw_cylinder(x, y, z, radius_top, radius_bottom, height, r, g, b, a);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
#[no_mangle]
|
|
1042
|
+
pub extern "C" fn bloom_draw_plane(cx: f64, cy: f64, cz: f64, w: f64, d: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1043
|
+
engine().renderer.draw_plane(cx, cy, cz, w, d, r, g, b, a);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
#[no_mangle]
|
|
1047
|
+
pub extern "C" fn bloom_draw_grid(slices: f64, spacing: f64) {
|
|
1048
|
+
engine().renderer.draw_grid(slices as i32, spacing);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
#[no_mangle]
|
|
1052
|
+
pub extern "C" fn bloom_draw_ray(origin_x: f64, origin_y: f64, origin_z: f64, dir_x: f64, dir_y: f64, dir_z: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1053
|
+
engine().renderer.draw_ray(origin_x, origin_y, origin_z, dir_x, dir_y, dir_z, r, g, b, a);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// ============================================================
|
|
1057
|
+
// Joint test (skeletal animation debug)
|
|
1058
|
+
// ============================================================
|
|
1059
|
+
|
|
1060
|
+
#[no_mangle]
|
|
1061
|
+
pub extern "C" fn bloom_set_joint_test(_joint: f64, _angle: f64) {
|
|
1062
|
+
// No-op for now — skeletal animation testing
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// ============================================================
|
|
1066
|
+
// Lighting
|
|
1067
|
+
// ============================================================
|
|
1068
|
+
|
|
1069
|
+
#[no_mangle]
|
|
1070
|
+
pub extern "C" fn bloom_set_ambient_light(r: f64, g: f64, b: f64, intensity: f64) {
|
|
1071
|
+
engine().renderer.set_ambient_light(r, g, b, intensity);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
#[no_mangle]
|
|
1075
|
+
pub extern "C" fn bloom_set_directional_light(dx: f64, dy: f64, dz: f64, r: f64, g: f64, b: f64, intensity: f64) {
|
|
1076
|
+
engine().renderer.set_directional_light(dx, dy, dz, r, g, b, intensity);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
#[no_mangle]
|
|
1080
|
+
pub extern "C" fn bloom_set_procedural_sky(enabled: f64, rayleigh_density: f64, mie_density: f64, ground_albedo: f64) {
|
|
1081
|
+
engine().renderer.set_procedural_sky(
|
|
1082
|
+
enabled != 0.0,
|
|
1083
|
+
rayleigh_density as f32,
|
|
1084
|
+
mie_density as f32,
|
|
1085
|
+
ground_albedo as f32,
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
#[no_mangle]
|
|
1090
|
+
pub extern "C" fn bloom_set_sun_direction(dx: f64, dy: f64, dz: f64, intensity: f64) {
|
|
1091
|
+
engine().renderer.set_sun_direction(dx as f32, dy as f32, dz as f32, intensity as f32);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// ============================================================
|
|
1095
|
+
// Models
|
|
1096
|
+
// ============================================================
|
|
1097
|
+
|
|
1098
|
+
#[no_mangle]
|
|
1099
|
+
pub extern "C" fn bloom_load_model(path_ptr: *const u8) -> f64 {
|
|
1100
|
+
let path = str_from_header(path_ptr);
|
|
1101
|
+
match std::fs::read(resolve_path(path)) {
|
|
1102
|
+
Ok(data) => {
|
|
1103
|
+
let eng = engine();
|
|
1104
|
+
let renderer_ptr = &mut eng.renderer as *mut crate::Renderer;
|
|
1105
|
+
eng.models.load_model_with_textures(&data, unsafe { &mut *renderer_ptr })
|
|
1106
|
+
}
|
|
1107
|
+
Err(_) => 0.0,
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
#[no_mangle]
|
|
1112
|
+
pub extern "C" fn bloom_draw_model(handle: f64, x: f64, y: f64, z: f64, scale: f64, r: f64, g: f64, b: f64, a: f64) {
|
|
1113
|
+
let eng = engine();
|
|
1114
|
+
if let Some(model) = eng.models.get(handle) {
|
|
1115
|
+
let tint = [(r / 255.0) as f32, (g / 255.0) as f32, (b / 255.0) as f32, (a / 255.0) as f32];
|
|
1116
|
+
let position = [x as f32, y as f32, z as f32];
|
|
1117
|
+
let handle_bits = handle.to_bits();
|
|
1118
|
+
if eng.renderer.cache_model_if_static(handle_bits, &model.meshes) {
|
|
1119
|
+
eng.renderer.draw_model_cached(handle_bits, position, scale as f32, tint);
|
|
1120
|
+
} else {
|
|
1121
|
+
for mesh in &model.meshes {
|
|
1122
|
+
let tex_idx = mesh.texture_idx.unwrap_or(0);
|
|
1123
|
+
eng.renderer.draw_model_mesh_tinted(&mesh.vertices, &mesh.indices, position, scale as f32, tint, tex_idx);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
#[no_mangle]
|
|
1130
|
+
pub extern "C" fn bloom_draw_model_rotated(
|
|
1131
|
+
handle: f64, x: f64, y: f64, z: f64,
|
|
1132
|
+
scale: f64, rot_y: f64,
|
|
1133
|
+
color_packed_argb: f64,
|
|
1134
|
+
) {
|
|
1135
|
+
let bits = color_packed_argb as u32;
|
|
1136
|
+
let a = ((bits >> 24) & 0xff) as f32 / 255.0;
|
|
1137
|
+
let r = ((bits >> 16) & 0xff) as f32 / 255.0;
|
|
1138
|
+
let g = ((bits >> 8) & 0xff) as f32 / 255.0;
|
|
1139
|
+
let b = ( bits & 0xff) as f32 / 255.0;
|
|
1140
|
+
let eng = engine();
|
|
1141
|
+
if let Some(model) = eng.models.get(handle) {
|
|
1142
|
+
let position = [x as f32, y as f32, z as f32];
|
|
1143
|
+
let scale = scale as f32;
|
|
1144
|
+
let tint = [r, g, b, a];
|
|
1145
|
+
for mesh in &model.meshes {
|
|
1146
|
+
let tex_idx = mesh.texture_idx.unwrap_or(0);
|
|
1147
|
+
eng.renderer.draw_model_mesh_tinted_rotated(
|
|
1148
|
+
&mesh.vertices, &mesh.indices, position, scale, tint, tex_idx, rot_y as f32,
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
#[no_mangle]
|
|
1155
|
+
pub extern "C" fn bloom_unload_model(handle: f64) {
|
|
1156
|
+
engine().models.unload_model(handle);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
#[no_mangle]
|
|
1160
|
+
pub extern "C" fn bloom_gen_mesh_cube(w: f64, h: f64, d: f64) -> f64 {
|
|
1161
|
+
engine().models.gen_mesh_cube(w as f32, h as f32, d as f32)
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
#[no_mangle]
|
|
1165
|
+
pub extern "C" fn bloom_gen_mesh_heightmap(image_handle: f64, size_x: f64, size_y: f64, size_z: f64) -> f64 {
|
|
1166
|
+
let eng = engine();
|
|
1167
|
+
if let Some(img) = eng.textures.images.get(image_handle) {
|
|
1168
|
+
let data = img.data.clone();
|
|
1169
|
+
let w = img.width;
|
|
1170
|
+
let h = img.height;
|
|
1171
|
+
eng.models.gen_mesh_heightmap(&data, w, h, size_x as f32, size_y as f32, size_z as f32)
|
|
1172
|
+
} else {
|
|
1173
|
+
0.0
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
#[no_mangle]
|
|
1178
|
+
pub extern "C" fn bloom_load_shader(source_ptr: *const u8) -> f64 {
|
|
1179
|
+
let source = str_from_header(source_ptr);
|
|
1180
|
+
engine().renderer.load_custom_shader(source) as f64
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
#[no_mangle]
|
|
1184
|
+
pub extern "C" fn bloom_create_mesh(vertex_ptr: *const f32, vertex_count: f64, index_ptr: *const u32, index_count: f64) -> f64 {
|
|
1185
|
+
if vertex_ptr.is_null() || index_ptr.is_null() { return 0.0; }
|
|
1186
|
+
let vcount = vertex_count as usize;
|
|
1187
|
+
let icount = index_count as usize;
|
|
1188
|
+
let vertex_data = unsafe { std::slice::from_raw_parts(vertex_ptr, vcount * 12) };
|
|
1189
|
+
let index_data = unsafe { std::slice::from_raw_parts(index_ptr, icount) };
|
|
1190
|
+
engine().models.create_mesh(vertex_data, index_data)
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// ============================================================
|
|
1194
|
+
// Phase 1c — material system FFI
|
|
1195
|
+
// ============================================================
|
|
1196
|
+
|
|
1197
|
+
#[no_mangle]
|
|
1198
|
+
pub extern "C" fn bloom_set_material_params(
|
|
1199
|
+
handle: f64,
|
|
1200
|
+
params_ptr: *const f64,
|
|
1201
|
+
param_count: f64,
|
|
1202
|
+
) {
|
|
1203
|
+
let count = param_count as usize;
|
|
1204
|
+
if count > 64 {
|
|
1205
|
+
eprintln!("[material] set_material_params: param_count {} > 64 (256-byte UBO cap)", count);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
let mut bytes = vec![0u8; count * 4];
|
|
1209
|
+
if !params_ptr.is_null() && count > 0 {
|
|
1210
|
+
let slots = unsafe { std::slice::from_raw_parts(params_ptr, count) };
|
|
1211
|
+
for (i, &v) in slots.iter().enumerate() {
|
|
1212
|
+
let f = v as f32;
|
|
1213
|
+
bytes[i*4..i*4+4].copy_from_slice(&f.to_le_bytes());
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
let eng = engine();
|
|
1217
|
+
if let Err(e) = eng.renderer.material_system.set_user_params(
|
|
1218
|
+
&eng.renderer.device, &eng.renderer.queue,
|
|
1219
|
+
handle as u32, &bytes,
|
|
1220
|
+
) {
|
|
1221
|
+
eprintln!("[material] set_material_params failed: {}", e);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
#[no_mangle]
|
|
1226
|
+
pub extern "C" fn bloom_compile_material(source_ptr: *const u8) -> f64 {
|
|
1227
|
+
let source = str_from_header(source_ptr);
|
|
1228
|
+
match engine().renderer.compile_material(source) {
|
|
1229
|
+
Ok(handle) => handle as f64,
|
|
1230
|
+
Err(e) => {
|
|
1231
|
+
eprintln!("[material] compile failed: {:?}", e);
|
|
1232
|
+
0.0
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
#[no_mangle]
|
|
1238
|
+
pub extern "C" fn bloom_compile_material_refractive(source_ptr: *const u8) -> f64 {
|
|
1239
|
+
use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
|
|
1240
|
+
let source = str_from_header(source_ptr);
|
|
1241
|
+
match engine().renderer.compile_material_with_options(
|
|
1242
|
+
source, FragmentProfile::Translucent, Bucket::Refractive, true, false,
|
|
1243
|
+
) {
|
|
1244
|
+
Ok(handle) => handle as f64,
|
|
1245
|
+
Err(e) => { eprintln!("[refractive] compile failed: {:?}", e); 0.0 }
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
#[no_mangle]
|
|
1250
|
+
pub extern "C" fn bloom_compile_material_transparent(source_ptr: *const u8) -> f64 {
|
|
1251
|
+
use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
|
|
1252
|
+
let source = str_from_header(source_ptr);
|
|
1253
|
+
match engine().renderer.compile_material_with_options(
|
|
1254
|
+
source, FragmentProfile::Translucent, Bucket::Transparent, false, false,
|
|
1255
|
+
) {
|
|
1256
|
+
Ok(handle) => handle as f64,
|
|
1257
|
+
Err(e) => { eprintln!("[material] compile failed: {:?}", e); 0.0 }
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
#[no_mangle]
|
|
1262
|
+
pub extern "C" fn bloom_compile_material_additive(source_ptr: *const u8) -> f64 {
|
|
1263
|
+
use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
|
|
1264
|
+
let source = str_from_header(source_ptr);
|
|
1265
|
+
match engine().renderer.compile_material_with_options(
|
|
1266
|
+
source, FragmentProfile::Translucent, Bucket::Additive, false, false,
|
|
1267
|
+
) {
|
|
1268
|
+
Ok(handle) => handle as f64,
|
|
1269
|
+
Err(e) => { eprintln!("[material] compile failed: {:?}", e); 0.0 }
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
#[no_mangle]
|
|
1274
|
+
pub extern "C" fn bloom_compile_material_cutout(source_ptr: *const u8) -> f64 {
|
|
1275
|
+
use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
|
|
1276
|
+
let source = str_from_header(source_ptr);
|
|
1277
|
+
match engine().renderer.compile_material_with_options(
|
|
1278
|
+
source, FragmentProfile::Opaque, Bucket::Cutout, false, false,
|
|
1279
|
+
) {
|
|
1280
|
+
Ok(handle) => handle as f64,
|
|
1281
|
+
Err(e) => { eprintln!("[material] compile failed: {:?}", e); 0.0 }
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
#[no_mangle]
|
|
1286
|
+
pub extern "C" fn bloom_compile_material_instanced(source_ptr: *const u8) -> f64 {
|
|
1287
|
+
let source = str_from_header(source_ptr);
|
|
1288
|
+
match engine().renderer.compile_material_instanced(source) {
|
|
1289
|
+
Ok(handle) => handle as f64,
|
|
1290
|
+
Err(e) => { eprintln!("[material] instanced compile failed: {:?}", e); 0.0 }
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
#[no_mangle]
|
|
1295
|
+
pub extern "C" fn bloom_create_instance_buffer(
|
|
1296
|
+
data_ptr: *const f64, instance_count: f64,
|
|
1297
|
+
) -> f64 {
|
|
1298
|
+
if data_ptr.is_null() || instance_count <= 0.0 { return 0.0; }
|
|
1299
|
+
let count = instance_count as u32;
|
|
1300
|
+
let slot_count = (count as usize) * 9;
|
|
1301
|
+
let raw_f64 = unsafe { std::slice::from_raw_parts(data_ptr, slot_count) };
|
|
1302
|
+
let raw_f32: Vec<f32> = raw_f64.iter().map(|&v| v as f32).collect();
|
|
1303
|
+
engine().renderer.create_instance_buffer(&raw_f32, count) as f64
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
#[no_mangle]
|
|
1307
|
+
pub extern "C" fn bloom_submit_material_draw_instanced(
|
|
1308
|
+
material: f64, mesh_handle: f64, mesh_idx: f64,
|
|
1309
|
+
instance_buffer: f64, instance_count: f64,
|
|
1310
|
+
) {
|
|
1311
|
+
let eng = engine();
|
|
1312
|
+
let handle_bits = mesh_handle.to_bits();
|
|
1313
|
+
if let Some(model) = eng.models.get(mesh_handle) {
|
|
1314
|
+
eng.renderer.cache_model_if_static(handle_bits, &model.meshes);
|
|
1315
|
+
}
|
|
1316
|
+
eng.renderer.submit_material_draw_instanced(
|
|
1317
|
+
material as u32,
|
|
1318
|
+
handle_bits,
|
|
1319
|
+
mesh_idx as usize,
|
|
1320
|
+
instance_buffer as u32,
|
|
1321
|
+
instance_count as u32,
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
#[no_mangle]
|
|
1326
|
+
pub extern "C" fn bloom_destroy_instance_buffer(handle: f64) {
|
|
1327
|
+
engine().renderer.destroy_instance_buffer(handle as u32);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
/// EN-011 — create a planar reflection probe. See macOS lib.rs for the
|
|
1331
|
+
/// full doc comment; this entry-point exists on every native platform
|
|
1332
|
+
/// so games can target the same FFI surface across iOS/tvOS/Windows/
|
|
1333
|
+
/// Linux/Android.
|
|
1334
|
+
#[no_mangle]
|
|
1335
|
+
pub extern "C" fn bloom_create_planar_reflection(
|
|
1336
|
+
plane_y: f64, nx: f64, ny: f64, nz: f64, resolution: f64,
|
|
1337
|
+
) -> f64 {
|
|
1338
|
+
engine().renderer.create_planar_reflection(
|
|
1339
|
+
plane_y as f32,
|
|
1340
|
+
[nx as f32, ny as f32, nz as f32],
|
|
1341
|
+
resolution as u32,
|
|
1342
|
+
) as f64
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/// EN-011 — link a material to a planar reflection probe. `probe = 0`
|
|
1346
|
+
/// reverts the binding to the engine's default 1×1 black texture.
|
|
1347
|
+
#[no_mangle]
|
|
1348
|
+
pub extern "C" fn bloom_set_material_reflection_probe(
|
|
1349
|
+
material: f64, probe: f64,
|
|
1350
|
+
) {
|
|
1351
|
+
engine().renderer.set_material_reflection_probe(material as u32, probe as u32);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
/// EN-014 — create a texture array from concatenated RGBA8 byte data.
|
|
1355
|
+
/// See macOS lib.rs for the full doc comment; this entry-point exists
|
|
1356
|
+
/// on every native platform so a TS game targets the same FFI across
|
|
1357
|
+
/// iOS / tvOS / Windows / Linux / Android.
|
|
1358
|
+
#[no_mangle]
|
|
1359
|
+
pub extern "C" fn bloom_create_texture_array(
|
|
1360
|
+
data_ptr: *const u8,
|
|
1361
|
+
data_len: f64,
|
|
1362
|
+
width: f64,
|
|
1363
|
+
height: f64,
|
|
1364
|
+
layer_count: f64,
|
|
1365
|
+
) -> f64 {
|
|
1366
|
+
// EN-014 V2 — V1 forwards to _ex with default sRGB / no mips.
|
|
1367
|
+
bloom_create_texture_array_ex(data_ptr, data_len, width, height, layer_count, 0.0, 1.0)
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
/// EN-014 V2 — explicit format + mip control. See macOS lib.rs for the
|
|
1371
|
+
/// reference implementation; this entry-point exists on every native
|
|
1372
|
+
/// platform so a TS game targets the same FFI surface.
|
|
1373
|
+
#[no_mangle]
|
|
1374
|
+
pub extern "C" fn bloom_create_texture_array_ex(
|
|
1375
|
+
data_ptr: *const u8,
|
|
1376
|
+
data_len: f64,
|
|
1377
|
+
width: f64,
|
|
1378
|
+
height: f64,
|
|
1379
|
+
layer_count: f64,
|
|
1380
|
+
format: f64,
|
|
1381
|
+
mip_levels: f64,
|
|
1382
|
+
) -> f64 {
|
|
1383
|
+
if data_ptr.is_null() || data_len <= 0.0 { return 0.0; }
|
|
1384
|
+
let w = width as u32;
|
|
1385
|
+
let h = height as u32;
|
|
1386
|
+
if w == 0 || h == 0 { return 0.0; }
|
|
1387
|
+
let layers_count = (layer_count as u32)
|
|
1388
|
+
.min(bloom_shared::renderer::material_system::MAX_TEXTURE_ARRAY_LAYERS);
|
|
1389
|
+
if layers_count == 0 { return 0.0; }
|
|
1390
|
+
let layer_size = (w as usize) * (h as usize) * 4;
|
|
1391
|
+
let total_bytes = (data_len as usize)
|
|
1392
|
+
.min(layers_count as usize * layer_size);
|
|
1393
|
+
let bytes = unsafe { std::slice::from_raw_parts(data_ptr, total_bytes) };
|
|
1394
|
+
let mut layers: Vec<(&[u8], u32, u32)> = Vec::with_capacity(layers_count as usize);
|
|
1395
|
+
for i in 0..(layers_count as usize) {
|
|
1396
|
+
let start = i * layer_size;
|
|
1397
|
+
let end = start + layer_size;
|
|
1398
|
+
if end > bytes.len() { break; }
|
|
1399
|
+
layers.push((&bytes[start..end], w, h));
|
|
1400
|
+
}
|
|
1401
|
+
engine().renderer.create_texture_array_ex(&layers, format as u32, mip_levels as u32) as f64
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
/// EN-014 — link a texture-array handle to a material at one of three
|
|
1405
|
+
/// slots: 0 = albedo (binding 14), 1 = normal (binding 15),
|
|
1406
|
+
/// 2 = MR (binding 16). Pass `array = 0` to revert to the stub.
|
|
1407
|
+
#[no_mangle]
|
|
1408
|
+
pub extern "C" fn bloom_set_material_texture_array(
|
|
1409
|
+
material: f64, slot: f64, array: f64,
|
|
1410
|
+
) {
|
|
1411
|
+
engine().renderer.set_material_texture_array(
|
|
1412
|
+
material as u32, slot as u32, array as u32,
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
/// EN-012 — set the shading model for a material (0=default lit,
|
|
1417
|
+
/// 1=foliage, 2=subsurface V2 stub).
|
|
1418
|
+
#[no_mangle]
|
|
1419
|
+
pub extern "C" fn bloom_set_material_shading_model(
|
|
1420
|
+
material: f64, model: f64,
|
|
1421
|
+
) {
|
|
1422
|
+
engine().renderer.set_material_shading_model(material as u32, model as u32);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
/// EN-012 — set the foliage shading parameters for a material.
|
|
1426
|
+
/// Only takes effect when shading_model == 1 (foliage).
|
|
1427
|
+
#[no_mangle]
|
|
1428
|
+
pub extern "C" fn bloom_set_material_foliage(
|
|
1429
|
+
material: f64,
|
|
1430
|
+
trans_r: f64, trans_g: f64, trans_b: f64,
|
|
1431
|
+
trans_amount: f64, wrap_factor: f64,
|
|
1432
|
+
) {
|
|
1433
|
+
engine().renderer.set_material_foliage(
|
|
1434
|
+
material as u32,
|
|
1435
|
+
[trans_r as f32, trans_g as f32, trans_b as f32],
|
|
1436
|
+
trans_amount as f32, wrap_factor as f32,
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
#[no_mangle]
|
|
1441
|
+
pub extern "C" fn bloom_compile_material_from_file(
|
|
1442
|
+
path_ptr: *const u8,
|
|
1443
|
+
bucket_kind: f64,
|
|
1444
|
+
) -> f64 {
|
|
1445
|
+
use bloom_shared::renderer::material_pipeline::{FragmentProfile, Bucket};
|
|
1446
|
+
let path = str_from_header(path_ptr);
|
|
1447
|
+
let (profile, bucket, reads_scene) = match bucket_kind as u32 {
|
|
1448
|
+
0 => (FragmentProfile::Opaque, Bucket::Opaque, false),
|
|
1449
|
+
1 => (FragmentProfile::Translucent, Bucket::Transparent, false),
|
|
1450
|
+
2 => (FragmentProfile::Translucent, Bucket::Refractive, true),
|
|
1451
|
+
3 => (FragmentProfile::Translucent, Bucket::Additive, false),
|
|
1452
|
+
4 => (FragmentProfile::Opaque, Bucket::Cutout, false),
|
|
1453
|
+
_ => {
|
|
1454
|
+
eprintln!("[material] from_file: unknown bucket_kind {bucket_kind}");
|
|
1455
|
+
return 0.0;
|
|
1456
|
+
}
|
|
1457
|
+
};
|
|
1458
|
+
match engine().renderer.compile_material_from_file(
|
|
1459
|
+
std::path::Path::new(path), profile, bucket, reads_scene,
|
|
1460
|
+
) {
|
|
1461
|
+
Ok(handle) => handle as f64,
|
|
1462
|
+
Err(e) => { eprintln!("[material] from_file failed: {e}"); 0.0 }
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
/// EN-017 — compile + install a fullscreen post-pass material.
|
|
1467
|
+
/// See `bloom-macos::bloom_set_post_pass` for the full ABI.
|
|
1468
|
+
#[no_mangle]
|
|
1469
|
+
pub extern "C" fn bloom_set_post_pass(source_ptr: *const u8) -> f64 {
|
|
1470
|
+
let source = str_from_header(source_ptr);
|
|
1471
|
+
match engine().renderer.set_post_pass(source) {
|
|
1472
|
+
Ok(()) => 1.0,
|
|
1473
|
+
Err(e) => { eprintln!("[post_pass] compile failed: {:?}", e); 0.0 }
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
/// EN-017 — uninstall the active post-pass.
|
|
1478
|
+
#[no_mangle]
|
|
1479
|
+
pub extern "C" fn bloom_clear_post_pass() {
|
|
1480
|
+
engine().renderer.clear_post_pass();
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/// EN-017 V2 — append a post-pass to the stack.
|
|
1484
|
+
/// See `bloom-macos::bloom_add_post_pass` for the full ABI.
|
|
1485
|
+
#[no_mangle]
|
|
1486
|
+
pub extern "C" fn bloom_add_post_pass(source_ptr: *const u8) -> f64 {
|
|
1487
|
+
let source = str_from_header(source_ptr);
|
|
1488
|
+
match engine().renderer.add_post_pass(source) {
|
|
1489
|
+
Ok(h) => h as f64,
|
|
1490
|
+
Err(e) => { eprintln!("[post_pass] compile failed: {:?}", e); 0.0 }
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/// EN-017 V2 — wipe the entire post-pass stack.
|
|
1495
|
+
#[no_mangle]
|
|
1496
|
+
pub extern "C" fn bloom_clear_all_post_passes() {
|
|
1497
|
+
engine().renderer.clear_all_post_passes();
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
#[no_mangle]
|
|
1501
|
+
pub extern "C" fn bloom_draw_material(
|
|
1502
|
+
material: f64,
|
|
1503
|
+
mesh_handle: f64,
|
|
1504
|
+
mesh_idx: f64,
|
|
1505
|
+
x: f64, y: f64, z: f64, scale: f64,
|
|
1506
|
+
r: f64, g: f64, b: f64, a: f64,
|
|
1507
|
+
) {
|
|
1508
|
+
let eng = engine();
|
|
1509
|
+
let handle_bits = mesh_handle.to_bits();
|
|
1510
|
+
if let Some(model) = eng.models.get(mesh_handle) {
|
|
1511
|
+
eng.renderer.cache_model_if_static(handle_bits, &model.meshes);
|
|
1512
|
+
}
|
|
1513
|
+
eng.renderer.submit_material_draw(
|
|
1514
|
+
material as u32,
|
|
1515
|
+
handle_bits,
|
|
1516
|
+
mesh_idx as usize,
|
|
1517
|
+
[x as f32, y as f32, z as f32],
|
|
1518
|
+
scale as f32,
|
|
1519
|
+
[(r / 255.0) as f32, (g / 255.0) as f32, (b / 255.0) as f32, (a / 255.0) as f32],
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
#[no_mangle]
|
|
1524
|
+
pub extern "C" fn bloom_load_model_animation(path_ptr: *const u8) -> f64 {
|
|
1525
|
+
let path = str_from_header(path_ptr);
|
|
1526
|
+
match std::fs::read(resolve_path(path)) {
|
|
1527
|
+
Ok(data) => engine().models.load_model_animation(&data),
|
|
1528
|
+
Err(_) => 0.0,
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
#[no_mangle]
|
|
1533
|
+
pub extern "C" fn bloom_update_model_animation(handle: f64, anim_index: f64, time: f64, scale: f64, px: f64, py: f64, pz: f64, rot_sin: f64, rot_cos: f64) {
|
|
1534
|
+
let eng = engine();
|
|
1535
|
+
eng.models.update_model_animation(handle, anim_index as usize, time as f32);
|
|
1536
|
+
if let Some(anim) = eng.models.get_animation(handle) {
|
|
1537
|
+
if !anim.joint_matrices.is_empty() {
|
|
1538
|
+
eng.renderer.set_joint_matrices_scaled(&anim.joint_matrices, scale as f32, [px as f32, py as f32, pz as f32], rot_sin as f32, rot_cos as f32);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
#[no_mangle]
|
|
1544
|
+
pub extern "C" fn bloom_get_model_mesh_count(handle: f64) -> f64 {
|
|
1545
|
+
match engine().models.get(handle) {
|
|
1546
|
+
Some(model) => model.meshes.len() as f64,
|
|
1547
|
+
None => 0.0,
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
#[no_mangle]
|
|
1552
|
+
pub extern "C" fn bloom_get_model_material_count(handle: f64) -> f64 {
|
|
1553
|
+
match engine().models.get(handle) {
|
|
1554
|
+
Some(model) => model.meshes.len() as f64,
|
|
1555
|
+
None => 0.0,
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// ============================================================
|
|
1560
|
+
// CoreAudio (iOS) — RemoteIO Audio Unit
|
|
1561
|
+
// ============================================================
|
|
1562
|
+
|
|
1563
|
+
type AudioUnit = *mut c_void;
|
|
1564
|
+
type OSStatus = i32;
|
|
1565
|
+
type AudioUnitPropertyID = u32;
|
|
1566
|
+
type AudioUnitScope = u32;
|
|
1567
|
+
type AudioUnitElement = u32;
|
|
1568
|
+
|
|
1569
|
+
#[repr(C)]
|
|
1570
|
+
#[derive(Clone, Copy)]
|
|
1571
|
+
struct AudioComponentDescription {
|
|
1572
|
+
component_type: u32,
|
|
1573
|
+
component_sub_type: u32,
|
|
1574
|
+
component_manufacturer: u32,
|
|
1575
|
+
component_flags: u32,
|
|
1576
|
+
component_flags_mask: u32,
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
#[repr(C)]
|
|
1580
|
+
#[derive(Clone, Copy)]
|
|
1581
|
+
struct AudioStreamBasicDescription {
|
|
1582
|
+
sample_rate: f64,
|
|
1583
|
+
format_id: u32,
|
|
1584
|
+
format_flags: u32,
|
|
1585
|
+
bytes_per_packet: u32,
|
|
1586
|
+
frames_per_packet: u32,
|
|
1587
|
+
bytes_per_frame: u32,
|
|
1588
|
+
channels_per_frame: u32,
|
|
1589
|
+
bits_per_channel: u32,
|
|
1590
|
+
reserved: u32,
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
#[repr(C)]
|
|
1594
|
+
struct AudioBufferList {
|
|
1595
|
+
number_buffers: u32,
|
|
1596
|
+
buffers: [AudioBufferData; 1],
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
#[repr(C)]
|
|
1600
|
+
struct AudioBufferData {
|
|
1601
|
+
number_channels: u32,
|
|
1602
|
+
data_byte_size: u32,
|
|
1603
|
+
data: *mut c_void,
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
type AURenderCallback = unsafe extern "C" fn(
|
|
1607
|
+
in_ref_con: *mut c_void,
|
|
1608
|
+
io_action_flags: *mut u32,
|
|
1609
|
+
in_time_stamp: *const c_void,
|
|
1610
|
+
in_bus_number: u32,
|
|
1611
|
+
in_number_frames: u32,
|
|
1612
|
+
io_data: *mut AudioBufferList,
|
|
1613
|
+
) -> OSStatus;
|
|
1614
|
+
|
|
1615
|
+
#[repr(C)]
|
|
1616
|
+
struct AURenderCallbackStruct {
|
|
1617
|
+
input_proc: AURenderCallback,
|
|
1618
|
+
input_proc_ref_con: *mut c_void,
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
type AudioComponent = *mut c_void;
|
|
1622
|
+
|
|
1623
|
+
#[link(name = "AudioToolbox", kind = "framework")]
|
|
1624
|
+
extern "C" {
|
|
1625
|
+
fn AudioComponentFindNext(component: AudioComponent, desc: *const AudioComponentDescription) -> AudioComponent;
|
|
1626
|
+
fn AudioComponentInstanceNew(component: AudioComponent, out: *mut AudioUnit) -> OSStatus;
|
|
1627
|
+
fn AudioUnitSetProperty(
|
|
1628
|
+
unit: AudioUnit,
|
|
1629
|
+
property_id: AudioUnitPropertyID,
|
|
1630
|
+
scope: AudioUnitScope,
|
|
1631
|
+
element: AudioUnitElement,
|
|
1632
|
+
data: *const c_void,
|
|
1633
|
+
data_size: u32,
|
|
1634
|
+
) -> OSStatus;
|
|
1635
|
+
fn AudioUnitInitialize(unit: AudioUnit) -> OSStatus;
|
|
1636
|
+
fn AudioOutputUnitStart(unit: AudioUnit) -> OSStatus;
|
|
1637
|
+
fn AudioOutputUnitStop(unit: AudioUnit) -> OSStatus;
|
|
1638
|
+
fn AudioComponentInstanceDispose(unit: AudioUnit) -> OSStatus;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
const K_AUDIO_UNIT_TYPE_OUTPUT: u32 = u32::from_be_bytes(*b"auou");
|
|
1642
|
+
const K_AUDIO_UNIT_SUB_TYPE_REMOTE_IO: u32 = u32::from_be_bytes(*b"rioc");
|
|
1643
|
+
const K_AUDIO_UNIT_MANUFACTURER_APPLE: u32 = u32::from_be_bytes(*b"appl");
|
|
1644
|
+
|
|
1645
|
+
const K_AUDIO_UNIT_PROPERTY_STREAM_FORMAT: AudioUnitPropertyID = 8;
|
|
1646
|
+
const K_AUDIO_UNIT_PROPERTY_SET_RENDER_CALLBACK: AudioUnitPropertyID = 23;
|
|
1647
|
+
const K_AUDIO_UNIT_SCOPE_INPUT: AudioUnitScope = 1;
|
|
1648
|
+
|
|
1649
|
+
const K_AUDIO_FORMAT_LINEAR_PCM: u32 = u32::from_be_bytes(*b"lpcm");
|
|
1650
|
+
const K_AUDIO_FORMAT_FLAG_IS_FLOAT: u32 = 1;
|
|
1651
|
+
const K_AUDIO_FORMAT_FLAG_IS_PACKED: u32 = 8;
|
|
1652
|
+
|
|
1653
|
+
struct AudioUnitInstance { unit: AudioUnit }
|
|
1654
|
+
unsafe impl Send for AudioUnitInstance {}
|
|
1655
|
+
unsafe impl Sync for AudioUnitInstance {}
|
|
1656
|
+
|
|
1657
|
+
static mut AUDIO_UNIT: Option<AudioUnitInstance> = None;
|
|
1658
|
+
|
|
1659
|
+
unsafe extern "C" fn audio_render_callback(
|
|
1660
|
+
_in_ref_con: *mut c_void,
|
|
1661
|
+
_io_action_flags: *mut u32,
|
|
1662
|
+
_in_time_stamp: *const c_void,
|
|
1663
|
+
_in_bus_number: u32,
|
|
1664
|
+
in_number_frames: u32,
|
|
1665
|
+
io_data: *mut AudioBufferList,
|
|
1666
|
+
) -> OSStatus {
|
|
1667
|
+
let buffer_list = &mut *io_data;
|
|
1668
|
+
let buffer = &mut buffer_list.buffers[0];
|
|
1669
|
+
let num_samples = in_number_frames as usize * 2;
|
|
1670
|
+
let output = std::slice::from_raw_parts_mut(buffer.data as *mut f32, num_samples);
|
|
1671
|
+
ENGINE.get_mut().map(|eng| { eng.audio.mix_output(output); });
|
|
1672
|
+
0
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
#[no_mangle]
|
|
1676
|
+
pub extern "C" fn bloom_init_audio() {
|
|
1677
|
+
unsafe {
|
|
1678
|
+
let desc = AudioComponentDescription {
|
|
1679
|
+
component_type: K_AUDIO_UNIT_TYPE_OUTPUT,
|
|
1680
|
+
component_sub_type: K_AUDIO_UNIT_SUB_TYPE_REMOTE_IO,
|
|
1681
|
+
component_manufacturer: K_AUDIO_UNIT_MANUFACTURER_APPLE,
|
|
1682
|
+
component_flags: 0,
|
|
1683
|
+
component_flags_mask: 0,
|
|
1684
|
+
};
|
|
1685
|
+
|
|
1686
|
+
let component = AudioComponentFindNext(std::ptr::null_mut(), &desc);
|
|
1687
|
+
if component.is_null() { return; }
|
|
1688
|
+
|
|
1689
|
+
let mut unit: AudioUnit = std::ptr::null_mut();
|
|
1690
|
+
if AudioComponentInstanceNew(component, &mut unit) != 0 { return; }
|
|
1691
|
+
|
|
1692
|
+
let stream_desc = AudioStreamBasicDescription {
|
|
1693
|
+
sample_rate: 44100.0,
|
|
1694
|
+
format_id: K_AUDIO_FORMAT_LINEAR_PCM,
|
|
1695
|
+
format_flags: K_AUDIO_FORMAT_FLAG_IS_FLOAT | K_AUDIO_FORMAT_FLAG_IS_PACKED,
|
|
1696
|
+
bytes_per_packet: 8,
|
|
1697
|
+
frames_per_packet: 1,
|
|
1698
|
+
bytes_per_frame: 8,
|
|
1699
|
+
channels_per_frame: 2,
|
|
1700
|
+
bits_per_channel: 32,
|
|
1701
|
+
reserved: 0,
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
AudioUnitSetProperty(
|
|
1705
|
+
unit, K_AUDIO_UNIT_PROPERTY_STREAM_FORMAT, K_AUDIO_UNIT_SCOPE_INPUT, 0,
|
|
1706
|
+
&stream_desc as *const _ as *const c_void,
|
|
1707
|
+
std::mem::size_of::<AudioStreamBasicDescription>() as u32,
|
|
1708
|
+
);
|
|
1709
|
+
|
|
1710
|
+
let callback_struct = AURenderCallbackStruct {
|
|
1711
|
+
input_proc: audio_render_callback,
|
|
1712
|
+
input_proc_ref_con: std::ptr::null_mut(),
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1715
|
+
AudioUnitSetProperty(
|
|
1716
|
+
unit, K_AUDIO_UNIT_PROPERTY_SET_RENDER_CALLBACK, K_AUDIO_UNIT_SCOPE_INPUT, 0,
|
|
1717
|
+
&callback_struct as *const _ as *const c_void,
|
|
1718
|
+
std::mem::size_of::<AURenderCallbackStruct>() as u32,
|
|
1719
|
+
);
|
|
1720
|
+
|
|
1721
|
+
AudioUnitInitialize(unit);
|
|
1722
|
+
AudioOutputUnitStart(unit);
|
|
1723
|
+
AUDIO_UNIT = Some(AudioUnitInstance { unit });
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
#[no_mangle]
|
|
1728
|
+
pub extern "C" fn bloom_close_audio() {
|
|
1729
|
+
unsafe {
|
|
1730
|
+
if let Some(au) = AUDIO_UNIT.take() {
|
|
1731
|
+
AudioOutputUnitStop(au.unit);
|
|
1732
|
+
AudioComponentInstanceDispose(au.unit);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
#[no_mangle]
|
|
1738
|
+
pub extern "C" fn bloom_load_sound(path_ptr: *const u8) -> f64 {
|
|
1739
|
+
let path = str_from_header(path_ptr);
|
|
1740
|
+
match std::fs::read(resolve_path(path)) {
|
|
1741
|
+
Ok(data) => {
|
|
1742
|
+
if let Some(s) = parse_wav(&data) {
|
|
1743
|
+
engine().audio.load_sound(s)
|
|
1744
|
+
} else if let Some(s) = parse_ogg(&data) {
|
|
1745
|
+
engine().audio.load_sound(s)
|
|
1746
|
+
} else if let Some(s) = parse_mp3(&data) {
|
|
1747
|
+
engine().audio.load_sound(s)
|
|
1748
|
+
} else {
|
|
1749
|
+
0.0
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
Err(_) => 0.0,
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
#[no_mangle]
|
|
1757
|
+
pub extern "C" fn bloom_play_sound(handle: f64) { engine().audio.play_sound(handle); }
|
|
1758
|
+
#[no_mangle]
|
|
1759
|
+
pub extern "C" fn bloom_stop_sound(handle: f64) { engine().audio.stop_sound(handle); }
|
|
1760
|
+
#[no_mangle]
|
|
1761
|
+
pub extern "C" fn bloom_set_sound_volume(handle: f64, volume: f64) { engine().audio.set_sound_volume(handle, volume as f32); }
|
|
1762
|
+
#[no_mangle]
|
|
1763
|
+
pub extern "C" fn bloom_set_master_volume(volume: f64) { engine().audio.master_volume = volume as f32; }
|
|
1764
|
+
|
|
1765
|
+
#[no_mangle]
|
|
1766
|
+
pub extern "C" fn bloom_play_sound_3d(handle: f64, x: f64, y: f64, z: f64) {
|
|
1767
|
+
engine().audio.play_sound_3d(handle, x as f32, y as f32, z as f32);
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
#[no_mangle]
|
|
1771
|
+
pub extern "C" fn bloom_set_listener_position(x: f64, y: f64, z: f64, fx: f64, fy: f64, fz: f64) {
|
|
1772
|
+
engine().audio.set_listener_position(x as f32, y as f32, z as f32, fx as f32, fy as f32, fz as f32);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
// ============================================================
|
|
1776
|
+
// Music
|
|
1777
|
+
// ============================================================
|
|
1778
|
+
|
|
1779
|
+
#[no_mangle]
|
|
1780
|
+
pub extern "C" fn bloom_load_music(path_ptr: *const u8) -> f64 {
|
|
1781
|
+
let path = str_from_header(path_ptr);
|
|
1782
|
+
match std::fs::read(resolve_path(path)) {
|
|
1783
|
+
Ok(data) => {
|
|
1784
|
+
if let Some(s) = parse_ogg(&data) {
|
|
1785
|
+
engine().audio.load_music(s)
|
|
1786
|
+
} else if let Some(s) = parse_wav(&data) {
|
|
1787
|
+
engine().audio.load_music(s)
|
|
1788
|
+
} else if let Some(s) = parse_mp3(&data) {
|
|
1789
|
+
engine().audio.load_music(s)
|
|
1790
|
+
} else {
|
|
1791
|
+
0.0
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
Err(_) => 0.0,
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
#[no_mangle]
|
|
1799
|
+
pub extern "C" fn bloom_play_music(handle: f64) { engine().audio.play_music(handle); }
|
|
1800
|
+
#[no_mangle]
|
|
1801
|
+
pub extern "C" fn bloom_stop_music(handle: f64) { engine().audio.stop_music(handle); }
|
|
1802
|
+
#[no_mangle]
|
|
1803
|
+
pub extern "C" fn bloom_update_music_stream(handle: f64) { engine().audio.update_music_stream(handle); }
|
|
1804
|
+
#[no_mangle]
|
|
1805
|
+
pub extern "C" fn bloom_set_music_volume(handle: f64, volume: f64) { engine().audio.set_music_volume(handle, volume as f32); }
|
|
1806
|
+
#[no_mangle]
|
|
1807
|
+
pub extern "C" fn bloom_is_music_playing(handle: f64) -> f64 {
|
|
1808
|
+
if engine().audio.is_music_playing(handle) { 1.0 } else { 0.0 }
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
// ============================================================
|
|
1812
|
+
// Gamepad input
|
|
1813
|
+
// ============================================================
|
|
1814
|
+
|
|
1815
|
+
#[no_mangle]
|
|
1816
|
+
pub extern "C" fn bloom_is_gamepad_available(_gamepad: f64) -> f64 {
|
|
1817
|
+
if engine().input.is_gamepad_available() { 1.0 } else { 0.0 }
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
#[no_mangle]
|
|
1821
|
+
pub extern "C" fn bloom_get_gamepad_axis(_gamepad: f64, axis: f64) -> f64 {
|
|
1822
|
+
engine().input.get_gamepad_axis(axis as usize) as f64
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
#[no_mangle]
|
|
1826
|
+
pub extern "C" fn bloom_is_gamepad_button_pressed(_gamepad: f64, button: f64) -> f64 {
|
|
1827
|
+
if engine().input.is_gamepad_button_pressed(button as usize) { 1.0 } else { 0.0 }
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
#[no_mangle]
|
|
1831
|
+
pub extern "C" fn bloom_is_gamepad_button_down(_gamepad: f64, button: f64) -> f64 {
|
|
1832
|
+
if engine().input.is_gamepad_button_down(button as usize) { 1.0 } else { 0.0 }
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
#[no_mangle]
|
|
1836
|
+
pub extern "C" fn bloom_is_gamepad_button_released(_gamepad: f64, button: f64) -> f64 {
|
|
1837
|
+
if engine().input.is_gamepad_button_released(button as usize) { 1.0 } else { 0.0 }
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
#[no_mangle]
|
|
1841
|
+
pub extern "C" fn bloom_get_gamepad_axis_count(_gamepad: f64) -> f64 {
|
|
1842
|
+
engine().input.get_gamepad_axis_count() as f64
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
// ============================================================
|
|
1846
|
+
// Touch input
|
|
1847
|
+
// ============================================================
|
|
1848
|
+
|
|
1849
|
+
#[no_mangle]
|
|
1850
|
+
pub extern "C" fn bloom_get_touch_x(index: f64) -> f64 {
|
|
1851
|
+
engine().input.get_touch_x(index as usize)
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
#[no_mangle]
|
|
1855
|
+
pub extern "C" fn bloom_get_touch_y(index: f64) -> f64 {
|
|
1856
|
+
engine().input.get_touch_y(index as usize)
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
#[no_mangle]
|
|
1860
|
+
pub extern "C" fn bloom_get_touch_count() -> f64 {
|
|
1861
|
+
engine().input.get_touch_count() as f64
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
// ============================================================
|
|
1865
|
+
// Utility
|
|
1866
|
+
// ============================================================
|
|
1867
|
+
|
|
1868
|
+
#[no_mangle]
|
|
1869
|
+
pub extern "C" fn bloom_toggle_fullscreen() {}
|
|
1870
|
+
|
|
1871
|
+
#[no_mangle]
|
|
1872
|
+
pub extern "C" fn bloom_set_window_title(_title_ptr: *const u8) {}
|
|
1873
|
+
|
|
1874
|
+
#[no_mangle]
|
|
1875
|
+
pub extern "C" fn bloom_set_window_icon(_path_ptr: *const u8) {}
|
|
1876
|
+
|
|
1877
|
+
#[no_mangle]
|
|
1878
|
+
pub extern "C" fn bloom_disable_cursor() {
|
|
1879
|
+
engine().input.cursor_disabled = true;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
#[no_mangle]
|
|
1883
|
+
pub extern "C" fn bloom_enable_cursor() {
|
|
1884
|
+
engine().input.cursor_disabled = false;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
#[no_mangle]
|
|
1888
|
+
pub extern "C" fn bloom_get_mouse_delta_x() -> f64 {
|
|
1889
|
+
engine().input.mouse_delta_x
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
#[no_mangle]
|
|
1893
|
+
pub extern "C" fn bloom_get_mouse_delta_y() -> f64 {
|
|
1894
|
+
engine().input.mouse_delta_y
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
// Accumulated scroll wheel delta since the last call. Reading consumes the
|
|
1898
|
+
// value (returns 0 on the next call until the user scrolls again). Used by
|
|
1899
|
+
// the editor's orbit camera and any scrollable UI panel.
|
|
1900
|
+
#[no_mangle]
|
|
1901
|
+
pub extern "C" fn bloom_get_mouse_wheel() -> f64 {
|
|
1902
|
+
engine().input.consume_mouse_wheel()
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
#[no_mangle]
|
|
1906
|
+
pub extern "C" fn bloom_get_char_pressed() -> f64 {
|
|
1907
|
+
engine().input.pop_char() as f64
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// Q2: Cursor shape
|
|
1911
|
+
#[no_mangle]
|
|
1912
|
+
pub extern "C" fn bloom_set_cursor_shape(shape: f64) {
|
|
1913
|
+
engine().input.cursor_shape = shape as u32;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// E4: Clipboard (stub on this platform)
|
|
1917
|
+
#[no_mangle]
|
|
1918
|
+
pub extern "C" fn bloom_set_clipboard_text(_text_ptr: *const u8) {}
|
|
1919
|
+
#[no_mangle]
|
|
1920
|
+
pub extern "C" fn bloom_get_clipboard_text() -> *const u8 { std::ptr::null() }
|
|
1921
|
+
|
|
1922
|
+
// E5b: File dialogs (stub on this platform)
|
|
1923
|
+
#[no_mangle]
|
|
1924
|
+
pub extern "C" fn bloom_open_file_dialog(_filter_ptr: *const u8, _title_ptr: *const u8) -> *const u8 { std::ptr::null() }
|
|
1925
|
+
#[no_mangle]
|
|
1926
|
+
pub extern "C" fn bloom_save_file_dialog(_default_name_ptr: *const u8, _title_ptr: *const u8) -> *const u8 { std::ptr::null() }
|
|
1927
|
+
|
|
1928
|
+
// Model bounds accessors. Return the axis-aligned bounding box of a loaded
|
|
1929
|
+
// model in model-local coordinates. Editors use these to size gizmos, auto-
|
|
1930
|
+
// frame the camera on selection, and snap placed entities onto terrain.
|
|
1931
|
+
#[no_mangle]
|
|
1932
|
+
pub extern "C" fn bloom_get_model_bounds_min_x(model_handle: f64) -> f64 {
|
|
1933
|
+
engine().models.get_bounds(model_handle).0[0] as f64
|
|
1934
|
+
}
|
|
1935
|
+
#[no_mangle]
|
|
1936
|
+
pub extern "C" fn bloom_get_model_bounds_min_y(model_handle: f64) -> f64 {
|
|
1937
|
+
engine().models.get_bounds(model_handle).0[1] as f64
|
|
1938
|
+
}
|
|
1939
|
+
#[no_mangle]
|
|
1940
|
+
pub extern "C" fn bloom_get_model_bounds_min_z(model_handle: f64) -> f64 {
|
|
1941
|
+
engine().models.get_bounds(model_handle).0[2] as f64
|
|
1942
|
+
}
|
|
1943
|
+
#[no_mangle]
|
|
1944
|
+
pub extern "C" fn bloom_get_model_bounds_max_x(model_handle: f64) -> f64 {
|
|
1945
|
+
engine().models.get_bounds(model_handle).1[0] as f64
|
|
1946
|
+
}
|
|
1947
|
+
#[no_mangle]
|
|
1948
|
+
pub extern "C" fn bloom_get_model_bounds_max_y(model_handle: f64) -> f64 {
|
|
1949
|
+
engine().models.get_bounds(model_handle).1[1] as f64
|
|
1950
|
+
}
|
|
1951
|
+
#[no_mangle]
|
|
1952
|
+
pub extern "C" fn bloom_get_model_bounds_max_z(model_handle: f64) -> f64 {
|
|
1953
|
+
engine().models.get_bounds(model_handle).1[2] as f64
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
#[no_mangle]
|
|
1957
|
+
pub extern "C" fn bloom_write_file(path_ptr: *const u8, data_ptr: *const u8) -> f64 {
|
|
1958
|
+
let path = str_from_header(path_ptr);
|
|
1959
|
+
let data = str_from_header(data_ptr);
|
|
1960
|
+
match std::fs::write(path, data.as_bytes()) {
|
|
1961
|
+
Ok(_) => 1.0,
|
|
1962
|
+
Err(_) => 0.0,
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
#[no_mangle]
|
|
1967
|
+
pub extern "C" fn bloom_file_exists(path_ptr: *const u8) -> f64 {
|
|
1968
|
+
let path = str_from_header(path_ptr);
|
|
1969
|
+
let resolved = resolve_path(path);
|
|
1970
|
+
if std::path::Path::new(&resolved).exists() { 1.0 } else { 0.0 }
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
#[no_mangle]
|
|
1974
|
+
pub extern "C" fn bloom_read_file(path_ptr: *const u8) -> *const u8 {
|
|
1975
|
+
let path = str_from_header(path_ptr);
|
|
1976
|
+
match std::fs::read_to_string(resolve_path(path)) {
|
|
1977
|
+
Ok(contents) => {
|
|
1978
|
+
// Return Perry-format string: StringHeader (length u32 + capacity u32 + refcount u32) followed by UTF-8 data
|
|
1979
|
+
let bytes = contents.as_bytes();
|
|
1980
|
+
let len = bytes.len();
|
|
1981
|
+
let total = 12 + len; // 12 bytes header (3 × u32) + data
|
|
1982
|
+
let layout = std::alloc::Layout::from_size_align(total, 4).unwrap();
|
|
1983
|
+
unsafe {
|
|
1984
|
+
let ptr = std::alloc::alloc(layout);
|
|
1985
|
+
if ptr.is_null() { return std::ptr::null(); }
|
|
1986
|
+
*(ptr as *mut u32) = len as u32; // length
|
|
1987
|
+
*(ptr.add(4) as *mut u32) = len as u32; // capacity
|
|
1988
|
+
*(ptr.add(8) as *mut u32) = 1; // refcount (unique)
|
|
1989
|
+
std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(12), len);
|
|
1990
|
+
ptr
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
Err(_) => std::ptr::null(),
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
#[no_mangle]
|
|
1998
|
+
pub extern "C" fn bloom_get_time() -> f64 {
|
|
1999
|
+
engine().get_time()
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
// ============================================================
|
|
2003
|
+
// Input injection + platform detection
|
|
2004
|
+
// ============================================================
|
|
2005
|
+
|
|
2006
|
+
#[no_mangle]
|
|
2007
|
+
pub extern "C" fn bloom_inject_key_down(key: f64) {
|
|
2008
|
+
engine().input.set_key_down(key as usize);
|
|
2009
|
+
}
|
|
2010
|
+
#[no_mangle]
|
|
2011
|
+
pub extern "C" fn bloom_inject_key_up(key: f64) {
|
|
2012
|
+
engine().input.set_key_up(key as usize);
|
|
2013
|
+
}
|
|
2014
|
+
#[no_mangle]
|
|
2015
|
+
pub extern "C" fn bloom_inject_gamepad_axis(axis: f64, value: f64) {
|
|
2016
|
+
engine().input.set_gamepad_axis(axis as usize, value as f32);
|
|
2017
|
+
}
|
|
2018
|
+
#[no_mangle]
|
|
2019
|
+
pub extern "C" fn bloom_inject_gamepad_button_down(button: f64) {
|
|
2020
|
+
engine().input.set_gamepad_button_down(button as usize);
|
|
2021
|
+
}
|
|
2022
|
+
#[no_mangle]
|
|
2023
|
+
pub extern "C" fn bloom_inject_gamepad_button_up(button: f64) {
|
|
2024
|
+
engine().input.set_gamepad_button_up(button as usize);
|
|
2025
|
+
}
|
|
2026
|
+
#[no_mangle]
|
|
2027
|
+
pub extern "C" fn bloom_get_platform() -> f64 { 2.0 }
|
|
2028
|
+
#[no_mangle]
|
|
2029
|
+
pub extern "C" fn bloom_is_any_input_pressed() -> f64 {
|
|
2030
|
+
if engine().input.is_any_input_pressed() { 1.0 } else { 0.0 }
|
|
2031
|
+
}
|
|
2032
|
+
#[no_mangle]
|
|
2033
|
+
pub extern "C" fn bloom_get_crown_rotation() -> f64 {
|
|
2034
|
+
engine().input.consume_crown_rotation()
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
// ============================================================
|
|
2038
|
+
// Thread-safe staging (for async asset loading via Perry threads)
|
|
2039
|
+
// ============================================================
|
|
2040
|
+
|
|
2041
|
+
#[no_mangle]
|
|
2042
|
+
pub extern "C" fn bloom_stage_texture(path_ptr: *const u8) -> f64 {
|
|
2043
|
+
let path = str_from_header(path_ptr);
|
|
2044
|
+
match std::fs::read(resolve_path(path)) {
|
|
2045
|
+
Ok(data) => bloom_shared::staging::decode_and_stage_texture(&data),
|
|
2046
|
+
Err(_) => 0.0,
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
#[no_mangle]
|
|
2051
|
+
pub extern "C" fn bloom_stage_model(path_ptr: *const u8) -> f64 {
|
|
2052
|
+
let path = str_from_header(path_ptr);
|
|
2053
|
+
let data = match std::fs::read(resolve_path(path)) {
|
|
2054
|
+
Ok(d) => d,
|
|
2055
|
+
Err(_) => return 0.0,
|
|
2056
|
+
};
|
|
2057
|
+
match bloom_shared::models::load_gltf_staged(&data) {
|
|
2058
|
+
Some(staged) => bloom_shared::staging::stage_model(staged),
|
|
2059
|
+
None => 0.0,
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
#[no_mangle]
|
|
2064
|
+
pub extern "C" fn bloom_stage_sound(path_ptr: *const u8) -> f64 {
|
|
2065
|
+
let path = str_from_header(path_ptr);
|
|
2066
|
+
let data = match std::fs::read(resolve_path(path)) {
|
|
2067
|
+
Ok(d) => d,
|
|
2068
|
+
Err(_) => return 0.0,
|
|
2069
|
+
};
|
|
2070
|
+
let sound_data = if path.ends_with(".ogg") || path.ends_with(".OGG") {
|
|
2071
|
+
parse_ogg(&data)
|
|
2072
|
+
} else if path.ends_with(".mp3") || path.ends_with(".MP3") {
|
|
2073
|
+
parse_mp3(&data)
|
|
2074
|
+
} else {
|
|
2075
|
+
parse_wav(&data)
|
|
2076
|
+
};
|
|
2077
|
+
match sound_data {
|
|
2078
|
+
Some(sd) => bloom_shared::staging::stage_sound(sd),
|
|
2079
|
+
None => 0.0,
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
#[no_mangle]
|
|
2084
|
+
pub extern "C" fn bloom_commit_texture(staging_handle: f64) -> f64 {
|
|
2085
|
+
let staged = match bloom_shared::staging::take_texture(staging_handle) {
|
|
2086
|
+
Some(s) => s,
|
|
2087
|
+
None => return 0.0,
|
|
2088
|
+
};
|
|
2089
|
+
let eng = engine();
|
|
2090
|
+
let bind_group_idx = eng.renderer.register_texture(staged.width, staged.height, &staged.data);
|
|
2091
|
+
eng.textures.textures.alloc(bloom_shared::textures::TextureData {
|
|
2092
|
+
bind_group_idx, width: staged.width, height: staged.height,
|
|
2093
|
+
})
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
#[no_mangle]
|
|
2097
|
+
pub extern "C" fn bloom_commit_model(staging_handle: f64) -> f64 {
|
|
2098
|
+
let staged = match bloom_shared::staging::take_model(staging_handle) {
|
|
2099
|
+
Some(s) => s,
|
|
2100
|
+
None => return 0.0,
|
|
2101
|
+
};
|
|
2102
|
+
let eng = engine();
|
|
2103
|
+
let mut tex_map: Vec<u32> = Vec::with_capacity(staged.textures.len());
|
|
2104
|
+
for tex in &staged.textures {
|
|
2105
|
+
tex_map.push(eng.renderer.register_texture(tex.width, tex.height, &tex.data));
|
|
2106
|
+
}
|
|
2107
|
+
let mut model = staged.model;
|
|
2108
|
+
for mesh in &mut model.meshes {
|
|
2109
|
+
if let Some(ref mut idx) = mesh.texture_idx {
|
|
2110
|
+
let staged_idx = *idx as usize;
|
|
2111
|
+
if staged_idx > 0 && staged_idx <= tex_map.len() {
|
|
2112
|
+
*idx = tex_map[staged_idx - 1];
|
|
2113
|
+
} else {
|
|
2114
|
+
mesh.texture_idx = None;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
eng.models.models.alloc(model)
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
#[no_mangle]
|
|
2122
|
+
pub extern "C" fn bloom_commit_sound(staging_handle: f64) -> f64 {
|
|
2123
|
+
match bloom_shared::staging::take_sound(staging_handle) {
|
|
2124
|
+
Some(sd) => engine().audio.load_sound(sd),
|
|
2125
|
+
None => 0.0,
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
#[no_mangle]
|
|
2130
|
+
pub extern "C" fn bloom_commit_music(staging_handle: f64) -> f64 {
|
|
2131
|
+
match bloom_shared::staging::take_sound(staging_handle) {
|
|
2132
|
+
Some(sd) => engine().audio.load_music(sd),
|
|
2133
|
+
None => 0.0,
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
#[no_mangle]
|
|
2138
|
+
pub extern "C" fn bloom_run_game(_callback: extern "C" fn(f64)) {
|
|
2139
|
+
// No-op on native. The TypeScript runGame() helper provides the while loop.
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
|
|
2143
|
+
// Q6: Multi-hit picking
|
|
2144
|
+
static mut LAST_PICK_ALL: Vec<bloom_shared::picking::PickResult> = Vec::new();
|
|
2145
|
+
|
|
2146
|
+
#[no_mangle]
|
|
2147
|
+
pub extern "C" fn bloom_scene_pick_all(screen_x: f64, screen_y: f64, max_results: f64) -> f64 {
|
|
2148
|
+
let eng = engine();
|
|
2149
|
+
let inv_vp = eng.renderer.inverse_vp_matrix();
|
|
2150
|
+
let cam_pos = eng.renderer.camera_pos();
|
|
2151
|
+
let w = eng.renderer.width() as f32;
|
|
2152
|
+
let h = eng.renderer.height() as f32;
|
|
2153
|
+
let (origin, direction) = bloom_shared::picking::screen_to_ray(
|
|
2154
|
+
screen_x as f32, screen_y as f32, w, h, &inv_vp, &cam_pos,
|
|
2155
|
+
);
|
|
2156
|
+
let results = bloom_shared::picking::raycast_scene_all(&eng.scene, &origin, &direction, max_results as usize);
|
|
2157
|
+
let count = results.len();
|
|
2158
|
+
unsafe { LAST_PICK_ALL = results; }
|
|
2159
|
+
count as f64
|
|
2160
|
+
}
|
|
2161
|
+
#[no_mangle]
|
|
2162
|
+
pub extern "C" fn bloom_pick_all_handle(index: f64) -> f64 {
|
|
2163
|
+
let i = index as usize;
|
|
2164
|
+
unsafe { LAST_PICK_ALL.get(i).map(|r| r.handle).unwrap_or(0.0) }
|
|
2165
|
+
}
|
|
2166
|
+
#[no_mangle]
|
|
2167
|
+
pub extern "C" fn bloom_pick_all_distance(index: f64) -> f64 {
|
|
2168
|
+
let i = index as usize;
|
|
2169
|
+
unsafe { LAST_PICK_ALL.get(i).map(|r| r.distance as f64).unwrap_or(0.0) }
|
|
2170
|
+
}
|
|
2171
|
+
// ============================================================
|
|
2172
|
+
|
|
2173
|
+
// ============================================================
|
|
2174
|
+
// Render quality toggles (individual + preset) — ticket 011
|
|
2175
|
+
// Mirror of the macOS FFI surface added in commit 95da6af; previously
|
|
2176
|
+
// macOS-only, now exposed on every native platform so non-macOS builds
|
|
2177
|
+
// don't fail at runtime (missing symbol) when the TS API invokes them.
|
|
2178
|
+
// ============================================================
|
|
2179
|
+
|
|
2180
|
+
#[no_mangle]
|
|
2181
|
+
pub extern "C" fn bloom_set_quality_preset(preset: f64) {
|
|
2182
|
+
engine().renderer.apply_quality_preset(preset as u32);
|
|
2183
|
+
}
|
|
2184
|
+
#[no_mangle]
|
|
2185
|
+
pub extern "C" fn bloom_set_shadows_enabled(on: f64) {
|
|
2186
|
+
engine().renderer.set_shadows_enabled(on != 0.0);
|
|
2187
|
+
}
|
|
2188
|
+
#[no_mangle]
|
|
2189
|
+
pub extern "C" fn bloom_set_shadows_always_fresh(on: f64) {
|
|
2190
|
+
engine().renderer.set_shadows_always_fresh(on != 0.0);
|
|
2191
|
+
}
|
|
2192
|
+
#[no_mangle]
|
|
2193
|
+
pub extern "C" fn bloom_set_bloom_enabled(on: f64) {
|
|
2194
|
+
engine().renderer.set_bloom_enabled(on != 0.0);
|
|
2195
|
+
}
|
|
2196
|
+
#[no_mangle]
|
|
2197
|
+
pub extern "C" fn bloom_set_ssao_enabled(on: f64) {
|
|
2198
|
+
engine().renderer.set_ssao_enabled(on != 0.0);
|
|
2199
|
+
}
|
|
2200
|
+
#[no_mangle]
|
|
2201
|
+
pub extern "C" fn bloom_set_ssao_intensity(value: f64) {
|
|
2202
|
+
engine().renderer.set_ssao_strength(value as f32);
|
|
2203
|
+
}
|
|
2204
|
+
#[no_mangle]
|
|
2205
|
+
pub extern "C" fn bloom_set_ssao_radius(world_radius: f64) {
|
|
2206
|
+
engine().renderer.set_ssao_radius(world_radius as f32);
|
|
2207
|
+
}
|
|
2208
|
+
#[no_mangle]
|
|
2209
|
+
pub extern "C" fn bloom_set_wind(dir_x: f64, dir_z: f64, amplitude: f64, frequency: f64) {
|
|
2210
|
+
engine().renderer.set_wind(dir_x as f32, dir_z as f32, amplitude as f32, frequency as f32);
|
|
2211
|
+
}
|
|
2212
|
+
#[no_mangle]
|
|
2213
|
+
pub extern "C" fn bloom_set_ssr_enabled(on: f64) {
|
|
2214
|
+
engine().renderer.set_ssr_enabled(on != 0.0);
|
|
2215
|
+
}
|
|
2216
|
+
#[no_mangle]
|
|
2217
|
+
pub extern "C" fn bloom_set_motion_blur_enabled(on: f64) {
|
|
2218
|
+
engine().renderer.set_motion_blur_enabled(on != 0.0);
|
|
2219
|
+
}
|
|
2220
|
+
#[no_mangle]
|
|
2221
|
+
pub extern "C" fn bloom_set_sss_enabled(on: f64) {
|
|
2222
|
+
engine().renderer.set_sss_enabled(on != 0.0);
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
// ============================================================
|
|
2226
|
+
// Profiler — CPU phase timings (always available) + GPU timestamps
|
|
2227
|
+
// (when the adapter supports TIMESTAMP_QUERY). Disabled by default.
|
|
2228
|
+
// ============================================================
|
|
2229
|
+
|
|
2230
|
+
#[no_mangle]
|
|
2231
|
+
pub extern "C" fn bloom_set_profiler_enabled(on: f64) {
|
|
2232
|
+
engine().profiler.set_enabled(on != 0.0);
|
|
2233
|
+
}
|
|
2234
|
+
#[no_mangle]
|
|
2235
|
+
pub extern "C" fn bloom_get_profiler_frame_cpu_us() -> f64 {
|
|
2236
|
+
engine().profiler.avg_frame_cpu_us()
|
|
2237
|
+
}
|
|
2238
|
+
#[no_mangle]
|
|
2239
|
+
pub extern "C" fn bloom_get_profiler_frame_gpu_us() -> f64 {
|
|
2240
|
+
engine().profiler.avg_frame_gpu_us()
|
|
2241
|
+
}
|
|
2242
|
+
#[no_mangle]
|
|
2243
|
+
pub extern "C" fn bloom_print_profiler_summary() {
|
|
2244
|
+
print!("{}", engine().profiler.summary());
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
// ============================================================
|
|
2248
|
+
// Physics (Jolt 5.x) — FFI surface generated from shared macro
|
|
2249
|
+
// ============================================================
|
|
2250
|
+
|
|
2251
|
+
#[cfg(feature = "jolt")]
|
|
2252
|
+
#[inline]
|
|
2253
|
+
fn bloom_jolt_ffi_physics() -> &'static mut bloom_shared::physics_jolt::JoltPhysics {
|
|
2254
|
+
&mut engine().jolt
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
#[cfg(feature = "jolt")]
|
|
2258
|
+
bloom_shared::define_physics_ffi!();
|