Generate terrain on a keypress
This commit is contained in:
parent
55a134882d
commit
8ffb0a1cfe
5 changed files with 44 additions and 11 deletions
|
@ -15,8 +15,10 @@ enum KernelError: Error {
|
|||
}
|
||||
|
||||
protocol Algorithm {
|
||||
static var name: String { get }
|
||||
var name: String { get }
|
||||
var outTexture: MTLTexture { get }
|
||||
|
||||
func encode(in encoder: MTLComputeCommandEncoder)
|
||||
}
|
||||
|
||||
class Kernel {
|
||||
|
@ -33,10 +35,10 @@ class Kernel {
|
|||
let textures: [MTLTexture]
|
||||
|
||||
var outTexture: MTLTexture {
|
||||
return textures[indexes.out]
|
||||
return textures[textureIndexes.out]
|
||||
}
|
||||
|
||||
private(set) var indexes: (`in`: Int, out: Int) = (in: 0, out: 1)
|
||||
private(set) var textureIndexes: (`in`: Int, out: Int) = (in: 0, out: 1)
|
||||
|
||||
init(device: MTLDevice, library: MTLLibrary, functionName: String) throws {
|
||||
guard let computeFunction = library.makeFunction(name: functionName) else {
|
||||
|
@ -56,17 +58,17 @@ class Kernel {
|
|||
self.textures = textures
|
||||
}
|
||||
|
||||
func encode(in encoder: MTLComputeCommandEncoder, inTexture: MTLTexture?, outTexture: MTLTexture?) {
|
||||
func encode(in encoder: MTLComputeCommandEncoder) {
|
||||
encoder.setComputePipelineState(pipeline)
|
||||
encoder.setTexture(inTexture, index: GeneratorTextureIndex.in.rawValue)
|
||||
encoder.setTexture(inTexture, index: GeneratorTextureIndex.out.rawValue)
|
||||
encoder.setTexture(textures[textureIndexes.in], index: textureIndexes.in)
|
||||
encoder.setTexture(textures[textureIndexes.out], index: textureIndexes.out)
|
||||
encoder.dispatchThreads(Kernel.textureSize, threadsPerThreadgroup: MTLSize(width: 8, height: 8, depth: 1))
|
||||
}
|
||||
}
|
||||
|
||||
/// "Compute" zero for every value of the height map.
|
||||
class ZeroAlgorithm: Kernel, Algorithm {
|
||||
static let name = "Zero"
|
||||
let name = "Zero"
|
||||
|
||||
init?(device: MTLDevice, library: MTLLibrary) {
|
||||
do {
|
||||
|
@ -80,7 +82,7 @@ class ZeroAlgorithm: Kernel, Algorithm {
|
|||
|
||||
/// Randomly generate heights that are independent of all others.
|
||||
class RandomAlgorithm: Kernel, Algorithm {
|
||||
static let name = "Random"
|
||||
let name = "Random"
|
||||
|
||||
init?(device: MTLDevice, library: MTLLibrary) {
|
||||
do {
|
||||
|
|
|
@ -42,4 +42,23 @@ class GameViewController: NSViewController {
|
|||
|
||||
mtkView.delegate = renderer
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
view.window?.makeFirstResponder(self)
|
||||
}
|
||||
|
||||
override var acceptsFirstResponder: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
print("key down: \(String(describing: event.charactersIgnoringModifiers))")
|
||||
switch event.charactersIgnoringModifiers {
|
||||
case .some("n"):
|
||||
renderer.iterateTerrainAlgorithm = true
|
||||
default:
|
||||
super.keyDown(with: event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ class Renderer: NSObject, MTKViewDelegate {
|
|||
|
||||
var terrain: Terrain
|
||||
|
||||
var iterateTerrainAlgorithm = true
|
||||
|
||||
init?(metalKitView: MTKView) {
|
||||
self.device = metalKitView.device!
|
||||
self.commandQueue = self.device.makeCommandQueue()!
|
||||
|
@ -167,19 +169,28 @@ class Renderer: NSObject, MTKViewDelegate {
|
|||
if let commandBuffer = commandQueue.makeCommandBuffer() {
|
||||
let semaphore = inFlightSemaphore
|
||||
commandBuffer.addCompletedHandler { (_ commandBuffer)-> Swift.Void in
|
||||
self.iterateTerrainAlgorithm = false
|
||||
semaphore.signal()
|
||||
}
|
||||
|
||||
self.updateDynamicBufferState()
|
||||
|
||||
self.updateGameState()
|
||||
|
||||
if iterateTerrainAlgorithm, let computeEncoder = commandBuffer.makeComputeCommandEncoder() {
|
||||
print("Scheduling terrain generator iteration with \(terrain.algorithm.name) algorithm")
|
||||
computeEncoder.label = "Generator Encoder"
|
||||
computeEncoder.pushDebugGroup("Generate Terrain: \(terrain.algorithm.name)")
|
||||
terrain.algorithm.encode(in: computeEncoder)
|
||||
computeEncoder.popDebugGroup()
|
||||
computeEncoder.endEncoding()
|
||||
}
|
||||
|
||||
/// Delay getting the currentRenderPassDescriptor until we absolutely need it to avoid
|
||||
/// holding onto the drawable and blocking the display pipeline any longer than necessary
|
||||
let renderPassDescriptor = view.currentRenderPassDescriptor
|
||||
|
||||
if let renderPassDescriptor = renderPassDescriptor {
|
||||
|
||||
/// Final pass rendering code here
|
||||
if let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
|
||||
renderEncoder.label = "Primary Render Encoder"
|
||||
|
|
|
@ -91,7 +91,7 @@ class Terrain: NSObject {
|
|||
return nil
|
||||
}
|
||||
|
||||
guard let alg = ZeroAlgorithm(device: device, library: library) else {
|
||||
guard let alg = RandomAlgorithm(device: device, library: library) else {
|
||||
print("Couldn't create algorithm")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@ kernel void zeroKernel(texture2d<float, access::write> outTexture [[texture(Gene
|
|||
kernel void randomKernel(texture2d<float, access::write> outTexture [[texture(GeneratorTextureIndexOut)]],
|
||||
uint2 tid [[thread_position_in_grid]])
|
||||
{
|
||||
|
||||
float x = 2.0 * M_PI_F * (tid.x / 128.0);
|
||||
outTexture.write(sin(x), tid);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue