diff --git a/Foil.xcodeproj/project.pbxproj b/Foil.xcodeproj/project.pbxproj index b034bc8..70c0cc0 100644 --- a/Foil.xcodeproj/project.pbxproj +++ b/Foil.xcodeproj/project.pbxproj @@ -8,8 +8,8 @@ /* Begin PBXBuildFile section */ D42B958B24648E2900F4B5B0 /* FoilShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = D42B958A24648E2900F4B5B0 /* FoilShaders.metal */; }; - D462CC9B2464920600D79B48 /* FoilShaderTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D462CC9A2464920600D79B48 /* FoilShaderTypes.swift */; }; D462CC9D2466652400D79B48 /* LikeObjcSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = D462CC9C2466652400D79B48 /* LikeObjcSync.swift */; }; + D475693E2469259D000F87AE /* OFoilRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = D475693D2469259D000F87AE /* OFoilRenderer.m */; }; D4AC68B8245CF43F00917569 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AC68B7245CF43F00917569 /* AppDelegate.swift */; }; D4AC68BA245CF43F00917569 /* FoilViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AC68B9245CF43F00917569 /* FoilViewController.swift */; }; D4AC68BC245CF44000917569 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D4AC68BB245CF44000917569 /* Assets.xcassets */; }; @@ -17,17 +17,17 @@ D4AC68C9245CF57A00917569 /* FoilRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AC68C8245CF57A00917569 /* FoilRenderer.swift */; }; D4BE16FA2463D7390085FD3C /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4BE16F92463D7390085FD3C /* MetalKit.framework */; }; D4BE16FE2463F0E10085FD3C /* FoilKernels.metal in Sources */ = {isa = PBXBuildFile; fileRef = D4BE16FD2463F0E10085FD3C /* FoilKernels.metal */; }; - D4BE17002463F23C0085FD3C /* FoilKernelTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BE16FF2463F23C0085FD3C /* FoilKernelTypes.swift */; }; D4F680AC245FACB3000B8EF2 /* FoilSimulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F680AB245FACB3000B8EF2 /* FoilSimulation.swift */; }; - D4F680B02460A5E7000B8EF2 /* FoilKernelTypes.h in Sources */ = {isa = PBXBuildFile; fileRef = D4F680AF2460A5E7000B8EF2 /* FoilKernelTypes.h */; }; D4F680BE24639638000B8EF2 /* FoilMathUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F680BD24639638000B8EF2 /* FoilMathUtilities.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ D42B958A24648E2900F4B5B0 /* FoilShaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = FoilShaders.metal; sourceTree = ""; }; - D42B958C24648EDE00F4B5B0 /* FoilShaderTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FoilShaderTypes.h; sourceTree = ""; }; - D462CC9A2464920600D79B48 /* FoilShaderTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoilShaderTypes.swift; sourceTree = ""; }; D462CC9C2466652400D79B48 /* LikeObjcSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeObjcSync.swift; sourceTree = ""; }; + D475693C2469259D000F87AE /* Foil-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Foil-Bridging-Header.h"; sourceTree = ""; }; + D475693D2469259D000F87AE /* OFoilRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OFoilRenderer.m; sourceTree = ""; }; + D475693F24692638000F87AE /* FoilShaderTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FoilShaderTypes.h; sourceTree = ""; }; + D47569402469267E000F87AE /* FoilKernelTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FoilKernelTypes.h; sourceTree = ""; }; D4AC68B4245CF43F00917569 /* Foil.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Foil.app; sourceTree = BUILT_PRODUCTS_DIR; }; D4AC68B7245CF43F00917569 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; D4AC68B9245CF43F00917569 /* FoilViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoilViewController.swift; sourceTree = ""; }; @@ -38,9 +38,7 @@ D4AC68C8245CF57A00917569 /* FoilRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoilRenderer.swift; sourceTree = ""; }; D4BE16F92463D7390085FD3C /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; D4BE16FD2463F0E10085FD3C /* FoilKernels.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = FoilKernels.metal; sourceTree = ""; }; - D4BE16FF2463F23C0085FD3C /* FoilKernelTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoilKernelTypes.swift; sourceTree = ""; }; D4F680AB245FACB3000B8EF2 /* FoilSimulation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoilSimulation.swift; sourceTree = ""; }; - D4F680AF2460A5E7000B8EF2 /* FoilKernelTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FoilKernelTypes.h; sourceTree = ""; }; D4F680BD24639638000B8EF2 /* FoilMathUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoilMathUtilities.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -85,6 +83,8 @@ D4AC68C0245CF44000917569 /* Info.plist */, D462CC9C2466652400D79B48 /* LikeObjcSync.swift */, D4AC68BD245CF44000917569 /* Main.storyboard */, + D475693D2469259D000F87AE /* OFoilRenderer.m */, + D475693C2469259D000F87AE /* Foil-Bridging-Header.h */, ); path = Foil; sourceTree = ""; @@ -95,8 +95,7 @@ D4F680BD24639638000B8EF2 /* FoilMathUtilities.swift */, D4AC68C8245CF57A00917569 /* FoilRenderer.swift */, D42B958A24648E2900F4B5B0 /* FoilShaders.metal */, - D42B958C24648EDE00F4B5B0 /* FoilShaderTypes.h */, - D462CC9A2464920600D79B48 /* FoilShaderTypes.swift */, + D475693F24692638000F87AE /* FoilShaderTypes.h */, ); path = Renderer; sourceTree = ""; @@ -113,8 +112,7 @@ isa = PBXGroup; children = ( D4BE16FD2463F0E10085FD3C /* FoilKernels.metal */, - D4F680AF2460A5E7000B8EF2 /* FoilKernelTypes.h */, - D4BE16FF2463F23C0085FD3C /* FoilKernelTypes.swift */, + D47569402469267E000F87AE /* FoilKernelTypes.h */, D4F680AB245FACB3000B8EF2 /* FoilSimulation.swift */, ); path = Simulation; @@ -152,6 +150,7 @@ TargetAttributes = { D4AC68B3245CF43F00917569 = { CreatedOnToolsVersion = 11.2; + LastSwiftMigration = 1120; }; }; }; @@ -194,12 +193,10 @@ D4AC68C9245CF57A00917569 /* FoilRenderer.swift in Sources */, D462CC9D2466652400D79B48 /* LikeObjcSync.swift in Sources */, D4AC68BA245CF43F00917569 /* FoilViewController.swift in Sources */, - D4F680B02460A5E7000B8EF2 /* FoilKernelTypes.h in Sources */, D42B958B24648E2900F4B5B0 /* FoilShaders.metal in Sources */, - D4BE17002463F23C0085FD3C /* FoilKernelTypes.swift in Sources */, D4F680AC245FACB3000B8EF2 /* FoilSimulation.swift in Sources */, D4F680BE24639638000B8EF2 /* FoilMathUtilities.swift in Sources */, - D462CC9B2464920600D79B48 /* FoilShaderTypes.swift in Sources */, + D475693E2469259D000F87AE /* OFoilRenderer.m in Sources */, D4AC68B8245CF43F00917569 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -337,6 +334,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Foil/Foil.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; @@ -349,6 +347,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.boringsoftware.Foil; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Foil/Foil-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; @@ -357,6 +357,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Foil/Foil.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; @@ -369,6 +370,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.boringsoftware.Foil; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Foil/Foil-Bridging-Header.h"; SWIFT_VERSION = 5.0; }; name = Release; diff --git a/Foil/Foil-Bridging-Header.h b/Foil/Foil-Bridging-Header.h new file mode 100644 index 0000000..b7ce5a0 --- /dev/null +++ b/Foil/Foil-Bridging-Header.h @@ -0,0 +1,6 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "../Renderer/FoilShaderTypes.h" +#import "../Simulation/FoilKernelTypes.h" diff --git a/Foil/FoilViewController.swift b/Foil/FoilViewController.swift index 15670ea..1b84a42 100644 --- a/Foil/FoilViewController.swift +++ b/Foil/FoilViewController.swift @@ -108,16 +108,16 @@ class FoilViewController: NSViewController, MTKViewDelegate { precondition(!availableDevices.isEmpty, "Metal is not supported on this Mac") - computeDevice = availableDevices[RadeonGPUInMetalDevicesArray] + computeDevice = availableDevices[IntelGPUInMetalDevicesArray] NSLog("Selected compute device: \(computeDevice.name)") // Select renderer device - let rendererDevice = availableDevices[RadeonGPUInMetalDevicesArray] + let rendererDevice = availableDevices[IntelGPUInMetalDevicesArray] if rendererDevice !== _view.device { _view.device = rendererDevice; - NSLog("New render device: '\(rendererDevice.name)'") + NSLog("New render device: '\(rendererDevice.name)', drawableSize \(_view.drawableSize)") renderer = FoilRenderer(_view) renderer.drawableSizeWillChange(size: _view.drawableSize) @@ -293,7 +293,7 @@ class FoilViewController: NSViewController, MTKViewDelegate { // Simulate the frame and obtain the new positions for the update. If this is the final // frame positionBuffer will be filled with the all positions used for the simulation - let positionBuffer = simulation.simulateFrameWithCommandBuffer(commandBuffer: commandBuffer) + let positionBuffer = simulation.simulateFrame(commandBuffer: commandBuffer) // Render the updated positions (or all positions in the case that the simulation is complete) renderer.drawWithCommandBuffer( diff --git a/Foil/OFoilRenderer.m b/Foil/OFoilRenderer.m new file mode 100644 index 0000000..b7abd20 --- /dev/null +++ b/Foil/OFoilRenderer.m @@ -0,0 +1,9 @@ +// +// OFoilRenderer.m +// Foil +// +// Created by Rob Bishop on 5/10/20. +// Copyright © 2020 Boring Software. All rights reserved. +// + +#import diff --git a/Renderer/FoilRenderer.swift b/Renderer/FoilRenderer.swift index b16c899..1de3703 100644 --- a/Renderer/FoilRenderer.swift +++ b/Renderer/FoilRenderer.swift @@ -8,7 +8,7 @@ class FoilRenderer: NSObject { // Size of gaussian map to create rounded smooth points static let GaussianMapSize = 64 - let gaussianMap: MTLTexture + var gaussianMap: MTLTexture! var device: MTLDevice! var commandQueue: MTLCommandQueue! @@ -25,7 +25,7 @@ class FoilRenderer: NSObject { var currentBufferIndex = 0 // Projection matrix calculated as a function of view size - var projectionMatrix: matrix_float4x4! + var projectionMatrix = matrix_float4x4() var renderScale: Float = 0 @@ -38,13 +38,12 @@ class FoilRenderer: NSObject { /// object will also be used to set the pixelFormat and other properties of the drawable init(_ mtkView: MTKView) { self.device = mtkView.device! - self.commandQueue = self.device.makeCommandQueue()! - - self.gaussianMap = FoilRenderer.generateGaussianMap(self.device) super.init() self.loadMetal(mtkView: mtkView) + + self.gaussianMap = FoilRenderer.generateGaussianMap(self.device) } /// Update the projection matrix with a new drawable size @@ -78,21 +77,21 @@ class FoilRenderer: NSObject { // Synchronize since positions buffer may be created on another thread rendererDispatchQueue.sync { renderEncoder.setVertexBuffer( - positionsBuffer, offset: 0, index: FoilRenderBufferIndex.positions.rawValue + positionsBuffer, offset: 0, index: Int(FoilRenderBufferIndexPositions.rawValue) ) } renderEncoder.setVertexBuffer( - colorsBuffer, offset: 0, index: FoilRenderBufferIndex.colors.rawValue + colorsBuffer, offset: 0, index: Int(FoilRenderBufferIndexColors.rawValue) ) renderEncoder.setVertexBuffer( dynamicUniformBuffers[currentBufferIndex], - offset: 0, index: FoilRenderBufferIndex.uniforms.rawValue + offset: 0, index: Int(FoilRenderBufferIndexUniforms.rawValue) ) renderEncoder.setFragmentTexture( - gaussianMap, index: FoilTextureIndex.colorMap.rawValue + gaussianMap, index: Int(FoilTextureIndexColorMap.rawValue) ) renderEncoder.drawPrimitives( @@ -122,28 +121,26 @@ class FoilRenderer: NSObject { // Calculate the size of a RGBA8Unorm texture's data and allocate system memory buffer // used to fill the texture's memory - let dataSize = textureDescriptor.width * textureDescriptor.height + let dataSize = textureDescriptor.width * textureDescriptor.height * MemoryLayout.size let nDelta: vector_float2 = [2.0 / Float(textureDescriptor.width), 2.0 / Float(textureDescriptor.height)] var texelData = [UInt8](repeating: 0, count: dataSize) - var SNormCoordinate = vector_float2(repeating: -1) - var i = 0 // Procedurally generate data to fill the texture's buffer for y in 0...stride + bytesPerRow: textureDescriptor.width * MemoryLayout.size ) gaussianMap!.label = "Gaussian Map" @@ -207,23 +204,20 @@ class FoilRenderer: NSObject { // Indicate shared storage so that both the CPU can access the buffers let storageMode = MTLResourceOptions.storageModeShared - let stride = MemoryLayout.stride + let stride = MemoryLayout.stride guard let dub = device.makeBuffer(length: stride, options: storageMode) else { fatalError() } dub.label = "UniformBuffer" dynamicUniformBuffers.append(dub) - // Initialize number of bodies to render - setNumRenderBodies(64 * 1024) - commandQueue = device.makeCommandQueue() } /// Update any render state (including updating dynamically changing Metal buffers) func updateState() { let uniforms = dynamicUniformBuffers[currentBufferIndex].contents() - var u = uniforms.assumingMemoryBound(to: FoilUniform.self).pointee + var u = uniforms.assumingMemoryBound(to: FoilUniforms.self).pointee u.pointSize = FoilRenderer.bodyPointSize u.mvpMatrix = projectionMatrix diff --git a/Renderer/FoilShaderTypes.swift b/Renderer/FoilShaderTypes.swift deleted file mode 100644 index 6210ea3..0000000 --- a/Renderer/FoilShaderTypes.swift +++ /dev/null @@ -1,31 +0,0 @@ -import simd - -/* -typedef enum FoilRenderBufferIndex -{ - FoilRenderBufferIndexPositions = 0, - FoilRenderBufferIndexColors = 1, - FoilRenderBufferIndexUniforms = 2, -} FoilRenderBufferIndex; - -typedef enum FoilTextureIndex -{ - FoilTextureIndexColorMap = 0, -} FoilTextureIndex; - -typedef struct -{ - matrix_float4x4 mvpMatrix; - float pointSize; - -} FoilUniforms; - -*/ -enum FoilRenderBufferIndex: Int { case positions = 0, colors = 1, uniforms = 2 } - -enum FoilTextureIndex: Int { case colorMap = 0 } - -struct FoilUniform { - var mvpMatrix: matrix_float4x4 - var pointSize: Float -} diff --git a/Renderer/FoilShaders.metal b/Renderer/FoilShaders.metal index 350213e..1a08776 100644 --- a/Renderer/FoilShaders.metal +++ b/Renderer/FoilShaders.metal @@ -8,10 +8,9 @@ Metal shaders used for this sample #include #include -using namespace metal; +#include "FoilShaderTypes.h" -// Include header shared between this Metal shader code and C code executing Metal API commands -#import "FoilShaderTypes.h" +using namespace metal; // Vertex shader outputs and per-fragment inputs typedef struct diff --git a/Simulation/FoilKernelTypes.swift b/Simulation/FoilKernelTypes.swift deleted file mode 100644 index 2f27f25..0000000 --- a/Simulation/FoilKernelTypes.swift +++ /dev/null @@ -1,32 +0,0 @@ -/* - - typedef enum FoilComputeBufferIndex - { - FoilComputeBufferIndexOldPosition = 0, - FoilComputeBufferIndexOldVelocity = 1, - FoilComputeBufferIndexNewPosition = 2, - FoilComputeBufferIndexNewVelocity = 3, - FoilComputeBufferIndexParams = 4 - } FoilComputeBufferIndex; - - typedef struct FoilSimParams - { - float timestep; - float damping; - float softeningSqr; - - unsigned int numBodies; - } FoilSimParams; - - */ -enum FoilComputeBufferIndex: Int { - case oldPosition, oldVelocity, newPosition, newVelocity, params -} - -struct FoilSimParams { - var timestep: Float - var damping: Float - var softeningSqr: Float - - var numBodies: Int -} diff --git a/Simulation/FoilKernels.metal b/Simulation/FoilKernels.metal index eb72847..6c69bb8 100644 --- a/Simulation/FoilKernels.metal +++ b/Simulation/FoilKernels.metal @@ -2,8 +2,7 @@ using namespace metal; #include - -#import "FoilKernelTypes.h" +#include "FoilKernelTypes.h" static float3 computeAcceleration(const float4 vsPosition, const float4 oldPosition, diff --git a/Simulation/FoilSimulation.swift b/Simulation/FoilSimulation.swift index a87473c..ed559f1 100644 --- a/Simulation/FoilSimulation.swift +++ b/Simulation/FoilSimulation.swift @@ -1,7 +1,7 @@ import Foundation import MetalKit -let FoilNumUpdateBuffersStored = 3; +let FoilNumUpdateBuffersStored = 1; // Parameters to perform the N-Body simulation struct FoilSimulationConfig { @@ -39,13 +39,10 @@ class FoilSimulation { var computePipeline: MTLComputePipelineState! // Metal buffer backed with memory wrapped in an NSData object for updating client (renderer) - var updateBuffer = [MTLBuffer?](repeating: nil, count: FoilNumUpdateBuffersStored) + var updateBuffer: MTLBuffer! // Wrapper for system memory used to transfer to client (renderer) - var updateData = [NSData?](repeating: nil, count: FoilNumUpdateBuffersStored) - - // Current buffer to write update simulation data to - var currentBufferIndex = 0 + var updateData: NSData! // Two buffers to hold positions and velocity. One will hold data for the previous/initial // frame while the other will hold data for the current frame, which is generated using data @@ -127,7 +124,7 @@ class FoilSimulation { } // Execute a single frame of the simulation (on the current thread) - func simulateFrameWithCommandBuffer(commandBuffer: MTLCommandBuffer) -> MTLBuffer { + func simulateFrame(commandBuffer: MTLCommandBuffer) -> MTLBuffer { commandBuffer.pushDebugGroup("Simulation") guard let computeEncoder = commandBuffer.makeComputeCommandEncoder() @@ -137,18 +134,18 @@ class FoilSimulation { computeEncoder.setComputePipelineState(computePipeline) - computeEncoder.setBuffer(positions[newBufferIndex], offset: 0, index: FoilComputeBufferIndex.newPosition.rawValue) - computeEncoder.setBuffer(velocities[newBufferIndex], offset: 0, index: FoilComputeBufferIndex.newVelocity.rawValue) - computeEncoder.setBuffer(positions[oldBufferIndex], offset: 0, index: FoilComputeBufferIndex.oldPosition.rawValue) - computeEncoder.setBuffer(velocities[oldBufferIndex], offset: 0, index: FoilComputeBufferIndex.oldVelocity.rawValue) - computeEncoder.setBuffer(simulationParams, offset: 0, index: FoilComputeBufferIndex.params.rawValue) + computeEncoder.setBuffer(positions[newBufferIndex], offset: 0, index: Int(FoilComputeBufferIndexNewPosition.rawValue)) + computeEncoder.setBuffer(velocities[newBufferIndex], offset: 0, index: Int(FoilComputeBufferIndexNewVelocity.rawValue)) + computeEncoder.setBuffer(positions[oldBufferIndex], offset: 0, index: Int(FoilComputeBufferIndexOldPosition.rawValue)) + computeEncoder.setBuffer(velocities[oldBufferIndex], offset: 0, index: Int(FoilComputeBufferIndexOldVelocity.rawValue)) + computeEncoder.setBuffer(simulationParams, offset: 0, index: Int(FoilComputeBufferIndexParams.rawValue)) computeEncoder.setThreadgroupMemoryLength(threadgroupMemoryLength, index: 0) computeEncoder.dispatchThreads(dispatchExecutionSize, threadsPerThreadgroup: threadsPerThreadgroup) computeEncoder.endEncoding() - // Swap indices to use data generated this frame at _newBufferIndex to generate data for the - // next frame and write it to the buffer at _oldBufferIndex + // Swap indices to use data generated this frame at newBufferIndex to generate data for the + // next frame and write it to the buffer at oldBufferIndex let tmpIndex = oldBufferIndex; oldBufferIndex = newBufferIndex; newBufferIndex = tmpIndex; @@ -157,7 +154,7 @@ class FoilSimulation { self.simulationTime += Double(config.simInterval) - return positions[Int(newBufferIndex)] + return positions[newBufferIndex] } /// Initialize Metal objects and set simulation parameters @@ -205,18 +202,16 @@ class FoilSimulation { c.timestep = config.simInterval c.damping = config.damping c.softeningSqr = config.softeningSqr - c.numBodies = config.numBodies + c.numBodies = UInt32(config.numBodies) simulationParams.didModifyRange(0...stride) - for i in 0..