diff --git a/MetaballsKit/Renderer.swift b/MetaballsKit/Renderer.swift index edc7684..3c5214a 100644 --- a/MetaballsKit/Renderer.swift +++ b/MetaballsKit/Renderer.swift @@ -25,59 +25,75 @@ struct Vertex { } public class Renderer: NSObject, MTKViewDelegate { - var delegate: RendererDelegate + public var delegate: RendererDelegate? = nil { + didSet { + guard let delegate = delegate else { + return + } + + let view = delegate.metalView + view.device = device + + do { + let library = try device.makeDefaultLibrary(bundle: Bundle.main) + let vertexShader = library.makeFunction(name: "passthroughVertexShader") + let fragmentShader = library.makeFunction(name: "sampleToColorShader") + + let pipelineStateDescriptor = MTLRenderPipelineDescriptor() + pipelineStateDescriptor.label = "Render Pipeline" + pipelineStateDescriptor.vertexFunction = vertexShader + pipelineStateDescriptor.fragmentFunction = fragmentShader + if let renderAttachment = pipelineStateDescriptor.colorAttachments[0] { + renderAttachment.pixelFormat = view.colorPixelFormat + // Pulled all this from SO. I don't know what all this does... + // https://stackoverflow.com/q/43727335/1174185 + renderAttachment.isBlendingEnabled = true + renderAttachment.alphaBlendOperation = .add + renderAttachment.rgbBlendOperation = .add + renderAttachment.sourceRGBBlendFactor = .sourceAlpha + renderAttachment.sourceAlphaBlendFactor = .sourceAlpha + renderAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha + renderAttachment.destinationAlphaBlendFactor = .oneMinusSourceAlpha + } + renderPipelineState = try device.makeRenderPipelineState(descriptor: pipelineStateDescriptor) + + try delegate.field.setupMetal(withDevice: device) + } catch let e { + fatalError("\(e)") + } + } + } private var device: MTLDevice private var commandQueue: MTLCommandQueue - private var renderPipelineState: MTLRenderPipelineState - - public init(delegate: RendererDelegate) throws { - self.delegate = delegate + private var renderPipelineState: MTLRenderPipelineState? = nil + override public init() { guard let device = MTLCreateSystemDefaultDevice() else { - throw RendererError.MetalError("Unable to create Metal system device") + fatalError("Unable to create Metal system device") } - let view = delegate.metalView self.device = device - view.device = device - - try delegate.field.setupMetal(withDevice: device) - - let library = try device.makeDefaultLibrary(bundle: Bundle.main) - let vertexShader = library.makeFunction(name: "passthroughVertexShader") - let fragmentShader = library.makeFunction(name: "sampleToColorShader") - - let pipelineStateDescriptor = MTLRenderPipelineDescriptor() - pipelineStateDescriptor.label = "Render Pipeline" - pipelineStateDescriptor.vertexFunction = vertexShader - pipelineStateDescriptor.fragmentFunction = fragmentShader - if let renderAttachment = pipelineStateDescriptor.colorAttachments[0] { - renderAttachment.pixelFormat = view.colorPixelFormat - // Pulled all this from SO. I don't know what all this does... - // https://stackoverflow.com/q/43727335/1174185 - renderAttachment.isBlendingEnabled = true - renderAttachment.alphaBlendOperation = .add - renderAttachment.rgbBlendOperation = .add - renderAttachment.sourceRGBBlendFactor = .sourceAlpha - renderAttachment.sourceAlphaBlendFactor = .sourceAlpha - renderAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha - renderAttachment.destinationAlphaBlendFactor = .oneMinusSourceAlpha - } - renderPipelineState = try device.makeRenderPipelineState(descriptor: pipelineStateDescriptor) - commandQueue = device.makeCommandQueue() + super.init() } + public convenience init(delegate: RendererDelegate) throws { + self.init() + self.delegate = delegate + } + /// MARK: - MTKViewDelegate public func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { - delegate.renderSize = Size(size: size) + delegate?.renderSize = Size(size: size) } public func draw(in view: MTKView) { - let field = delegate.field + guard let field = delegate?.field else { + return + } // Two triangles, plus texture coordinates. let points: [Vertex] = [ @@ -95,7 +111,7 @@ public class Renderer: NSObject, MTKViewDelegate { let buffer = commandQueue.makeCommandBuffer() buffer.label = "Render" - if let renderPass = view.currentRenderPassDescriptor { + if let renderPass = view.currentRenderPassDescriptor, let renderPipelineState = renderPipelineState { let encoder = buffer.makeRenderCommandEncoder(descriptor: renderPass) encoder.label = "Render Pass" encoder.setViewport(MTLViewport(originX: 0.0, originY: 0.0, width: Double(view.drawableSize.width), height: Double(view.drawableSize.height), znear: -1.0, zfar: 1.0))