From 8ffb0a1cfec3458bb3fe68ba2525ab1cfa616f5d Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sun, 4 Nov 2018 14:19:02 -0500 Subject: [PATCH] Generate terrain on a keypress --- Terrain2/Algorithms.swift | 18 ++++++++++-------- Terrain2/GameViewController.swift | 19 +++++++++++++++++++ Terrain2/Renderer.swift | 13 ++++++++++++- Terrain2/Terrain.swift | 2 +- Terrain2/TerrainAlgorithms.metal | 3 ++- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Terrain2/Algorithms.swift b/Terrain2/Algorithms.swift index 1391a82..ea147a5 100644 --- a/Terrain2/Algorithms.swift +++ b/Terrain2/Algorithms.swift @@ -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 { diff --git a/Terrain2/GameViewController.swift b/Terrain2/GameViewController.swift index d3086bd..908dd0d 100644 --- a/Terrain2/GameViewController.swift +++ b/Terrain2/GameViewController.swift @@ -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) + } + } } diff --git a/Terrain2/Renderer.swift b/Terrain2/Renderer.swift index 18f4e79..8497345 100644 --- a/Terrain2/Renderer.swift +++ b/Terrain2/Renderer.swift @@ -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" diff --git a/Terrain2/Terrain.swift b/Terrain2/Terrain.swift index b412fd4..9185cf7 100644 --- a/Terrain2/Terrain.swift +++ b/Terrain2/Terrain.swift @@ -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 } diff --git a/Terrain2/TerrainAlgorithms.metal b/Terrain2/TerrainAlgorithms.metal index 1c9ce3f..a355873 100644 --- a/Terrain2/TerrainAlgorithms.metal +++ b/Terrain2/TerrainAlgorithms.metal @@ -19,5 +19,6 @@ kernel void zeroKernel(texture2d outTexture [[texture(Gene kernel void randomKernel(texture2d 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); }