110 lines
3.6 KiB
Swift
110 lines
3.6 KiB
Swift
//
|
|
// Renderer.swift
|
|
// Terrain
|
|
//
|
|
// Created by Eryn Wells on 11/3/18.
|
|
// Copyright © 2018 Eryn Wells. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
import Metal
|
|
import MetalKit
|
|
|
|
class Renderer: NSObject, MTKViewDelegate {
|
|
|
|
var device: MTLDevice!
|
|
var library: MTLLibrary!
|
|
var commandQueue: MTLCommandQueue!
|
|
var renderPipeline: MTLRenderPipelineState!
|
|
|
|
var terrainGridSize = CGSize(width: 2, height: 2)
|
|
var terrain = Terrain()
|
|
|
|
func setupMetal(withView view: MTKView) {
|
|
guard let device = MTLCreateSystemDefaultDevice() else {
|
|
fatalError("Unable to create system Metal device")
|
|
}
|
|
self.device = device
|
|
|
|
setup(view: view, withDevice: device)
|
|
|
|
guard let queue = device.makeCommandQueue() else {
|
|
fatalError("Unable to create Metal command queue")
|
|
}
|
|
queue.label = "Terrain"
|
|
self.commandQueue = queue
|
|
|
|
let bundle = Bundle(for: type(of: self))
|
|
self.library = try! device.makeDefaultLibrary(bundle: bundle)
|
|
|
|
setupRenderPipeline(withDevice: device, library: library, view: view)
|
|
}
|
|
|
|
func setup(view: MTKView, withDevice device: MTLDevice) {
|
|
view.device = device
|
|
view.clearColor = MTLClearColor(red: 1, green: 0, blue: 0, alpha: 1)
|
|
view.colorPixelFormat = .bgra8Unorm
|
|
}
|
|
|
|
func setupRenderPipeline(withDevice device: MTLDevice, library: MTLLibrary, view: MTKView) {
|
|
let vertexShader = library.makeFunction(name: "passthroughVertex")
|
|
let fragmentShader = library.makeFunction(name: "passthroughFragment")
|
|
|
|
let desc = MTLRenderPipelineDescriptor()
|
|
desc.label = "Passthrough Pipeline"
|
|
desc.vertexFunction = vertexShader
|
|
desc.fragmentFunction = fragmentShader
|
|
desc.colorAttachments[0].pixelFormat = view.colorPixelFormat
|
|
desc.depthAttachmentPixelFormat = view.depthStencilPixelFormat
|
|
desc.stencilAttachmentPixelFormat = view.depthStencilPixelFormat
|
|
|
|
do {
|
|
renderPipeline = try device.makeRenderPipelineState(descriptor: desc)
|
|
} catch let e {
|
|
print("Couldn't set up pixel pipeline! \(e)")
|
|
renderPipeline = nil
|
|
}
|
|
}
|
|
|
|
func prepareToRender() {
|
|
guard let buffer = device.makeBuffer(length: terrain.minimumBufferSize(forGridSize: terrainGridSize), options: .storageModeShared) else {
|
|
fatalError("Couldn't create terrain buffer")
|
|
}
|
|
terrain.generateVertexes(intoBuffer: buffer, size: terrainGridSize)
|
|
}
|
|
|
|
// MARK: - MTKViewDelegate
|
|
|
|
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
|
|
print("Size of \(view.debugDescription) will change to \(size)")
|
|
}
|
|
|
|
func draw(in view: MTKView) {
|
|
guard let buffer = commandQueue.makeCommandBuffer() else {
|
|
return
|
|
}
|
|
|
|
var didEncode = false
|
|
buffer.label = "Terrain"
|
|
|
|
if let renderPass = view.currentRenderPassDescriptor {
|
|
if let encoder = buffer.makeRenderCommandEncoder(descriptor: renderPass) {
|
|
let vertexCount = terrain.vertexCount(forGridSize: terrainGridSize)
|
|
|
|
encoder.label = "Terrain"
|
|
encoder.setRenderPipelineState(renderPipeline)
|
|
encoder.setVertexBuffer(terrain.buffer, offset: 0, index: 0)
|
|
encoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: vertexCount)
|
|
encoder.setTriangleFillMode(.lines)
|
|
encoder.endEncoding()
|
|
didEncode = true
|
|
}
|
|
}
|
|
|
|
if didEncode, let drawable = view.currentDrawable {
|
|
buffer.present(drawable)
|
|
}
|
|
buffer.commit()
|
|
}
|
|
|
|
}
|