diff --git a/Metaballs-macOS/ViewController.swift b/Metaballs-macOS/ViewController.swift index c01a6b3..8a95c48 100644 --- a/Metaballs-macOS/ViewController.swift +++ b/Metaballs-macOS/ViewController.swift @@ -38,6 +38,8 @@ class ViewController: NSViewController, RendererDelegate { } } + var marchingSquares: MarchingSquares + private var renderer: Renderer! internal var metalView: MTKView { @@ -47,12 +49,14 @@ class ViewController: NSViewController, RendererDelegate { override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { let params = ViewController.defaultParameters() field = Field(parameters: params) + marchingSquares = MarchingSquares(field: field) super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init?(coder: NSCoder) { let params = ViewController.defaultParameters() field = Field(parameters: params) + marchingSquares = MarchingSquares(field: field) super.init(coder: coder) } @@ -112,6 +116,7 @@ class ViewController: NSViewController, RendererDelegate { } set { field.size = newValue + marchingSquares.fieldDidResize() } } } diff --git a/MetaballsKit/Metaballs.swift b/MetaballsKit/Metaballs.swift index 5557bb0..be1d494 100644 --- a/MetaballsKit/Metaballs.swift +++ b/MetaballsKit/Metaballs.swift @@ -109,7 +109,6 @@ public class Field { // Update Metal state as needed. populateParametersBuffer() populateBallBuffer() - marchingSquares.fieldDidResize() parameters.size = newValue } @@ -120,9 +119,6 @@ public class Field { public var defaults = UserDefaults.standard private var parameters: Parameters - lazy var marchingSquares: MarchingSquares = { - return MarchingSquares(field: self) - }() internal var bounds: CGRect { return CGRect(origin: CGPoint(), size: CGSize(size: size)) @@ -263,7 +259,7 @@ public class Field { return ptr.advanced(by: sizeOfType) } - public func setupMetal(withDevice device: MTLDevice) throws { + func setupMetal(withDevice device: MTLDevice) { guard self.device == nil else { return } @@ -271,7 +267,6 @@ public class Field { self.device = device populateParametersBuffer() populateBallBuffer() - marchingSquares.setupMetal(withDevice: device) } // MARK: - Notifications diff --git a/MetaballsKit/Renderer.swift b/MetaballsKit/Renderer.swift index d68f902..c850a2a 100644 --- a/MetaballsKit/Renderer.swift +++ b/MetaballsKit/Renderer.swift @@ -13,9 +13,10 @@ public enum RendererError: Error { case MetalError(String) } -public protocol RendererDelegate { +protocol RendererDelegate { var renderSize: Size { get set } var field: Field { get } + var marchingSquares: MarchingSquares { get } var metalView: MTKView { get } } @@ -29,7 +30,7 @@ struct Vertex { } public class Renderer: NSObject, MTKViewDelegate { - public var delegate: RendererDelegate? = nil { + var delegate: RendererDelegate? = nil { didSet { guard let delegate = delegate else { return @@ -41,7 +42,8 @@ public class Renderer: NSObject, MTKViewDelegate { configurePixelPipeline(withPixelFormat: view.colorPixelFormat) configureMarchingSquaresPipeline(withPixelFormat: view.colorPixelFormat) - try! delegate.field.setupMetal(withDevice: device) + delegate.field.setupMetal(withDevice: device) + delegate.marchingSquares.setupMetal(withDevice: device) } } @@ -80,7 +82,7 @@ public class Renderer: NSObject, MTKViewDelegate { super.init() } - public convenience init(delegate: RendererDelegate) throws { + convenience init(delegate: RendererDelegate) throws { self.init() self.delegate = delegate } @@ -223,19 +225,21 @@ public class Renderer: NSObject, MTKViewDelegate { didEncode = true } - // Render the marching squares version over top of the pixel version. - // We need our own render pass descriptor that specifies that we load the results of the previous pass to make this render pass appear on top of the other. - let pass = renderPass.copy() as! MTLRenderPassDescriptor - pass.colorAttachments[0].loadAction = .load - if let pipeline = marchingSquaresPipeline, - let encoder = buffer.makeRenderCommandEncoder(descriptor: pass) { - encoder.label = "Marching Squares Render" - encoder.setRenderPipelineState(pipeline) - encoder.setVertexBuffer(field.marchingSquares.gridGeometry, offset: 0, index: 0) - encoder.setVertexBuffer(parametersBuffer, offset: 0, index: 1) - encoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: field.marchingSquares.gridVertexCount) - encoder.endEncoding() - didEncode = true + if let marchingSquares = delegate?.marchingSquares { + // Render the marching squares version over top of the pixel version. + // We need our own render pass descriptor that specifies that we load the results of the previous pass to make this render pass appear on top of the other. + let pass = renderPass.copy() as! MTLRenderPassDescriptor + pass.colorAttachments[0].loadAction = .load + if let pipeline = marchingSquaresPipeline, + let encoder = buffer.makeRenderCommandEncoder(descriptor: pass) { + encoder.label = "Marching Squares Render" + encoder.setRenderPipelineState(pipeline) + encoder.setVertexBuffer(marchingSquares.gridGeometry, offset: 0, index: 0) + encoder.setVertexBuffer(parametersBuffer, offset: 0, index: 1) + encoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: marchingSquares.gridVertexCount) + encoder.endEncoding() + didEncode = true + } } }