I have been following this tutorial. I downloaded the source and tried "translating" it to Swift. This is my "translated" code:
import Cocoa
import AppKit
import MetalKit
import simd
class MetalViewController: NSViewController {
@IBOutlet var inview: MTKView!
override func viewDidLoad() {
super.viewDidLoad()
let _view: MTKView = self.inview
_view.device = MTLCreateSystemDefaultDevice()
let _renderer: Renderer=initView(view: _view)
_view.delegate=_renderer as? MTKViewDelegate
_view.preferredFramesPerSecond=60
}
}
class Renderer: NSObject {
init(device: MTLDevice){
self._device=device
self._commandQueue=_device.makeCommandQueue()!
super.init()
}
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
}
func draw(in view: MTKView) {
let color = Color(red: 1.0,green: 0.0,blue: 0.0,alpha: 0.0)
view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha)
let commandbuffer = _commandQueue.makeCommandBuffer()
let renderpassdescriptor: MTLRenderPassDescriptor = view.currentRenderPassDescriptor!
let renderencoder: MTLRenderCommandEncoder = (commandbuffer?.makeRenderCommandEncoder(descriptor: renderpassdescriptor))!
renderencoder.endEncoding()
commandbuffer!.present(view.currentDrawable!)
commandbuffer!.commit()
}
var _device: MTLDevice
var _commandQueue: MTLCommandQueue
}
struct Color{
var red, green, blue, alpha: Double
}
func initView(view: MTKView) -> Renderer{
var renderer: Renderer
renderer=Renderer(device: view.device!)
return renderer
}
So I put the AAPLRenderer and AAPLViewControllers into one file, and made it so that there are no header files. I linked the view with @IBOutlet to the view controller because the view was a NSView and I cannot cast it to MTKView without getting a compile time error. The AppDelegate is the original one and I do not have a main file.
I end up with a window that does not show red, but rather shows nothing. I do not understand why this is happening. Please help me, thank you.
I see two issues.
1) MTKView
's delegate
property is a weak var
, which means that if you don't hold onto an instance of your renderer, it'll be immediately deinited and never receive any delegate callbacks. Keep a reference to your renderer as a property on your view controller.
class MetalViewController: NSViewController {
@IBOutlet var inview: MTKView!
var renderer: Renderer!
override func viewDidLoad() {
// ...
let view: MTKView = self.inview
// ...
renderer = initView(view: view)
view.delegate = renderer
// ...
}
}
2) Because the Renderer
class doesn't explicitly declare conformance to the MTKViewDelegate
protocol, the conditional cast when assigning it as the view's delegate fails. Make Renderer
explicitly conform to the protocol, and remove the conditional cast as shown above.
class Renderer: NSObject, MTKViewDelegate