Oops fix my algorithm and update the tests
This commit is contained in:
parent
359c7ef987
commit
5233a94fec
2 changed files with 62 additions and 63 deletions
|
@ -17,10 +17,12 @@ enum KernelError: Error {
|
||||||
|
|
||||||
protocol TerrainGenerator {
|
protocol TerrainGenerator {
|
||||||
var name: String { get }
|
var name: String { get }
|
||||||
|
var needsGPU: Bool { get }
|
||||||
var outTexture: MTLTexture { get }
|
var outTexture: MTLTexture { get }
|
||||||
|
|
||||||
func updateUniforms()
|
func updateUniforms()
|
||||||
func encode(in encoder: MTLComputeCommandEncoder)
|
func encode(in encoder: MTLComputeCommandEncoder)
|
||||||
|
func render()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Kernel {
|
class Kernel {
|
||||||
|
@ -79,6 +81,8 @@ class Kernel {
|
||||||
class ZeroAlgorithm: Kernel, TerrainGenerator {
|
class ZeroAlgorithm: Kernel, TerrainGenerator {
|
||||||
let name = "Zero"
|
let name = "Zero"
|
||||||
|
|
||||||
|
let needsGPU: Bool = true
|
||||||
|
|
||||||
init?(device: MTLDevice, library: MTLLibrary) {
|
init?(device: MTLDevice, library: MTLLibrary) {
|
||||||
do {
|
do {
|
||||||
try super.init(device: device, library: library, functionName: "zeroKernel")
|
try super.init(device: device, library: library, functionName: "zeroKernel")
|
||||||
|
@ -91,12 +95,16 @@ class ZeroAlgorithm: Kernel, TerrainGenerator {
|
||||||
// MARK: Algorithm
|
// MARK: Algorithm
|
||||||
|
|
||||||
func updateUniforms() { }
|
func updateUniforms() { }
|
||||||
|
|
||||||
|
func render() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Randomly generate heights that are independent of all others.
|
/// Randomly generate heights that are independent of all others.
|
||||||
class RandomAlgorithm: Kernel, TerrainGenerator {
|
class RandomAlgorithm: Kernel, TerrainGenerator {
|
||||||
let name = "Random"
|
let name = "Random"
|
||||||
|
|
||||||
|
let needsGPU: Bool = true
|
||||||
|
|
||||||
private var uniforms: UnsafeMutablePointer<RandomAlgorithmUniforms>
|
private var uniforms: UnsafeMutablePointer<RandomAlgorithmUniforms>
|
||||||
|
|
||||||
init?(device: MTLDevice, library: MTLLibrary) {
|
init?(device: MTLDevice, library: MTLLibrary) {
|
||||||
|
@ -121,6 +129,8 @@ class RandomAlgorithm: Kernel, TerrainGenerator {
|
||||||
func updateUniforms() {
|
func updateUniforms() {
|
||||||
RandomAlgorithmUniforms_refreshRandoms(uniforms)
|
RandomAlgorithmUniforms_refreshRandoms(uniforms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func render() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of the Diamond-Squares algorithm.
|
/// Implementation of the Diamond-Squares algorithm.
|
||||||
|
@ -162,19 +172,19 @@ public class DiamondSquareGenerator: TerrainGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
var north: Point {
|
var north: Point {
|
||||||
return Point(x: origin.x + (size.w / 2 + 1), y: origin.y)
|
return Point(x: origin.x + size.w / 2, y: origin.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
var west: Point {
|
var west: Point {
|
||||||
return Point(x: origin.x, y: origin.y + (size.h / 2 + 1))
|
return Point(x: origin.x, y: origin.y + size.h / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
var south: Point {
|
var south: Point {
|
||||||
return Point(x: origin.x + (size.w / 2 + 1), y: origin.y + size.h)
|
return Point(x: origin.x + size.w / 2, y: origin.y + size.h - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var east: Point {
|
var east: Point {
|
||||||
return Point(x: origin.x + size.w, y: origin.y + (size.h / 2 + 1))
|
return Point(x: origin.x + size.w - 1, y: origin.y + size.h / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
var northwest: Point {
|
var northwest: Point {
|
||||||
|
@ -182,32 +192,32 @@ public class DiamondSquareGenerator: TerrainGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
var southwest: Point {
|
var southwest: Point {
|
||||||
return Point(x: origin.x, y: origin.y + size.h)
|
return Point(x: origin.x, y: origin.y + size.h - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var northeast: Point {
|
var northeast: Point {
|
||||||
return Point(x: origin.x + size.w, y: origin.y)
|
return Point(x: origin.x + size.w - 1, y: origin.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
var southeast: Point {
|
var southeast: Point {
|
||||||
return Point(x: origin.x + size.w, y: origin.y + size.h)
|
return Point(x: origin.x + size.w - 1, y: origin.y + size.h - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var midpoint: Point {
|
var midpoint: Point {
|
||||||
return Point(x: origin.x + (size.w / 2 + 1), y: origin.y + (size.h / 2 + 1))
|
return Point(x: origin.x + (size.w / 2), y: origin.y + (size.h / 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
var subdivisions: [Box] {
|
var subdivisions: [Box] {
|
||||||
guard size.w > 2 && size.h > 2 else {
|
guard size.w > 2 && size.h > 2 else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
let midp = midpoint
|
let halfSize = size.half
|
||||||
let newSize = Size(w: midp.x - origin.x, h: midp.y - origin.y)
|
let newSize = Size(w: halfSize.w + 1, h: halfSize.h + 1)
|
||||||
return [
|
return [
|
||||||
Box(origin: origin, size: newSize),
|
Box(origin: origin, size: newSize),
|
||||||
Box(origin: Point(x: origin.x + newSize.w, y: origin.y), size: newSize),
|
Box(origin: Point(x: origin.x + halfSize.w, y: origin.y), size: newSize),
|
||||||
Box(origin: Point(x: origin.x, y: origin.y + newSize.h), size: newSize),
|
Box(origin: Point(x: origin.x, y: origin.y + halfSize.h), size: newSize),
|
||||||
Box(origin: Point(x: origin.x + newSize.w, y: origin.y + newSize.h), size: newSize)
|
Box(origin: Point(x: origin.x + halfSize.w, y: origin.y + halfSize.h), size: newSize)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,6 +303,7 @@ public class DiamondSquareGenerator: TerrainGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = "Diamond-Square"
|
let name = "Diamond-Square"
|
||||||
|
let needsGPU: Bool = false
|
||||||
|
|
||||||
class var textureSize: MTLSize {
|
class var textureSize: MTLSize {
|
||||||
// Needs to 2n + 1 on each side.
|
// Needs to 2n + 1 on each side.
|
||||||
|
@ -307,7 +318,6 @@ public class DiamondSquareGenerator: TerrainGenerator {
|
||||||
let size = DiamondSquareGenerator.textureSize
|
let size = DiamondSquareGenerator.textureSize
|
||||||
let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .r32Float, width: size.width, height: size.height, mipmapped: false)
|
let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .r32Float, width: size.width, height: size.height, mipmapped: false)
|
||||||
desc.usage = [.shaderRead, .shaderWrite]
|
desc.usage = [.shaderRead, .shaderWrite]
|
||||||
desc.resourceOptions = .storageModeShared
|
|
||||||
guard let tex = device.makeTexture(descriptor: desc) else {
|
guard let tex = device.makeTexture(descriptor: desc) else {
|
||||||
print("Couldn't create texture for Diamond-Squares algorithm.")
|
print("Couldn't create texture for Diamond-Squares algorithm.")
|
||||||
return nil
|
return nil
|
||||||
|
@ -320,7 +330,7 @@ public class DiamondSquareGenerator: TerrainGenerator {
|
||||||
func render() {
|
func render() {
|
||||||
let heightMap = algorithm.render()
|
let heightMap = algorithm.render()
|
||||||
let region = MTLRegion(origin: MTLOrigin(), size: DiamondSquareGenerator.textureSize)
|
let region = MTLRegion(origin: MTLOrigin(), size: DiamondSquareGenerator.textureSize)
|
||||||
texture.replace(region: region, mipmapLevel: 0, withBytes: heightMap, bytesPerRow: MemoryLayout<Float>.stride * size.width)
|
texture.replace(region: region, mipmapLevel: 0, withBytes: heightMap, bytesPerRow: MemoryLayout<Float>.stride * DiamondSquareGenerator.textureSize.width)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Algorithm
|
// MARK: Algorithm
|
||||||
|
|
|
@ -65,50 +65,51 @@ class DiamondSquareAlgorithmTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiamondSquareBoxTests: XCTestCase {
|
class DiamondSquareBoxTests: XCTestCase {
|
||||||
fileprivate let box = Box(origin: Point(x: 3, y: 4), size: Size(w: 5, h: 5))
|
fileprivate let box = Box(origin: Point(x: 0, y: 0), size: Size(w: 5, h: 5))
|
||||||
|
|
||||||
func testMidpoint() {
|
func testMidpoint() {
|
||||||
let midpoint = box.midpoint
|
let midpoint = box.midpoint
|
||||||
XCTAssertEqual(midpoint.x, 6)
|
XCTAssertEqual(midpoint.x, 2)
|
||||||
XCTAssertEqual(midpoint.y, 7)
|
XCTAssertEqual(midpoint.y, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSubdivision() {
|
func testSubdivision() {
|
||||||
let subdivs = box.subdivisions
|
let subdivs = box.subdivisions
|
||||||
XCTAssertEqual(subdivs.count, 4)
|
XCTAssertEqual(subdivs.count, 4)
|
||||||
XCTAssertEqual(subdivs[0], Box(origin: Point(x: 3, y: 4), size: Size(w: 3, h: 3)))
|
XCTAssertEqual(subdivs[0], Box(origin: Point(x: 0, y: 0), size: Size(w: 3, h: 3)))
|
||||||
XCTAssertEqual(subdivs[1], Box(origin: Point(x: 6, y: 4), size: Size(w: 3, h: 3)))
|
XCTAssertEqual(subdivs[1], Box(origin: Point(x: 2, y: 0), size: Size(w: 3, h: 3)))
|
||||||
XCTAssertEqual(subdivs[2], Box(origin: Point(x: 3, y: 7), size: Size(w: 3, h: 3)))
|
XCTAssertEqual(subdivs[2], Box(origin: Point(x: 0, y: 2), size: Size(w: 3, h: 3)))
|
||||||
XCTAssertEqual(subdivs[3], Box(origin: Point(x: 6, y: 7), size: Size(w: 3, h: 3)))
|
XCTAssertEqual(subdivs[3], Box(origin: Point(x: 2, y: 2), size: Size(w: 3, h: 3)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBFS() {
|
func testBFS() {
|
||||||
var expectedBoxes: [Box] = [
|
var expectedBoxes: [Box] = [
|
||||||
box,
|
box,
|
||||||
Box(origin: Point(x: 3, y: 4), size: Size(w: 3, h: 3)),
|
|
||||||
Box(origin: Point(x: 6, y: 4), size: Size(w: 3, h: 3)),
|
|
||||||
Box(origin: Point(x: 3, y: 7), size: Size(w: 3, h: 3)),
|
|
||||||
Box(origin: Point(x: 6, y: 7), size: Size(w: 3, h: 3)),
|
|
||||||
|
|
||||||
Box(origin: Point(x: 3, y: 4), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 0, y: 0), size: Size(w: 3, h: 3)),
|
||||||
Box(origin: Point(x: 5, y: 4), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 2, y: 0), size: Size(w: 3, h: 3)),
|
||||||
Box(origin: Point(x: 3, y: 6), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 0, y: 2), size: Size(w: 3, h: 3)),
|
||||||
Box(origin: Point(x: 5, y: 6), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 2, y: 2), size: Size(w: 3, h: 3)),
|
||||||
|
|
||||||
Box(origin: Point(x: 6, y: 4), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 0, y: 0), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 8, y: 4), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 1, y: 0), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 6, y: 6), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 0, y: 1), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 8, y: 6), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 1, y: 1), size: Size(w: 2, h: 2)),
|
||||||
|
|
||||||
Box(origin: Point(x: 3, y: 7), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 2, y: 0), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 5, y: 7), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 3, y: 0), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 3, y: 9), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 2, y: 1), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 5, y: 9), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 3, y: 1), size: Size(w: 2, h: 2)),
|
||||||
|
|
||||||
Box(origin: Point(x: 6, y: 7), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 0, y: 2), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 8, y: 7), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 1, y: 2), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 6, y: 9), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 0, y: 3), size: Size(w: 2, h: 2)),
|
||||||
Box(origin: Point(x: 8, y: 9), size: Size(w: 2, h: 2)),
|
Box(origin: Point(x: 1, y: 3), size: Size(w: 2, h: 2)),
|
||||||
|
|
||||||
|
Box(origin: Point(x: 2, y: 2), size: Size(w: 2, h: 2)),
|
||||||
|
Box(origin: Point(x: 3, y: 2), size: Size(w: 2, h: 2)),
|
||||||
|
Box(origin: Point(x: 2, y: 3), size: Size(w: 2, h: 2)),
|
||||||
|
Box(origin: Point(x: 3, y: 3), size: Size(w: 2, h: 2)),
|
||||||
].reversed()
|
].reversed()
|
||||||
|
|
||||||
box.breadthFirstSearch { (box: Box) -> (Void) in
|
box.breadthFirstSearch { (box: Box) -> (Void) in
|
||||||
|
@ -122,52 +123,40 @@ class DiamondSquareBoxTests: XCTestCase {
|
||||||
// MARK: Sides
|
// MARK: Sides
|
||||||
|
|
||||||
func testNorth() {
|
func testNorth() {
|
||||||
let pt = box.north
|
XCTAssertEqual(box.north, Point(x: 2, y: 0))
|
||||||
XCTAssertEqual(pt.x, 6)
|
|
||||||
XCTAssertEqual(pt.y, 4)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWest() {
|
func testWest() {
|
||||||
let pt = box.west
|
XCTAssertEqual(box.west, Point(x: 0, y: 2))
|
||||||
XCTAssertEqual(pt.x, 3)
|
|
||||||
XCTAssertEqual(pt.y, 7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSouth() {
|
func testSouth() {
|
||||||
let pt = box.south
|
XCTAssertEqual(box.south, Point(x: 2, y: 4))
|
||||||
XCTAssertEqual(pt.x, 6)
|
|
||||||
XCTAssertEqual(pt.y, 9)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEast() {
|
func testEast() {
|
||||||
let pt = box.east
|
XCTAssertEqual(box.east, Point(x: 4, y: 2))
|
||||||
XCTAssertEqual(pt.x, 8)
|
|
||||||
XCTAssertEqual(pt.y, 7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Corners
|
// MARK: Corners
|
||||||
|
|
||||||
func testNorthwest() {
|
func testNorthwest() {
|
||||||
let pt = box.northwest
|
let pt = box.northwest
|
||||||
XCTAssertEqual(pt.x, 3)
|
XCTAssertEqual(pt, Point())
|
||||||
XCTAssertEqual(pt.y, 4)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNortheast() {
|
func testNortheast() {
|
||||||
let pt = box.northeast
|
let pt = box.northeast
|
||||||
XCTAssertEqual(pt.x, 8)
|
XCTAssertEqual(pt, Point(x: 4, y: 0))
|
||||||
XCTAssertEqual(pt.y, 4)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSouthwest() {
|
func testSouthwest() {
|
||||||
let pt = box.southwest
|
let pt = box.southwest
|
||||||
XCTAssertEqual(pt.x, 3)
|
XCTAssertEqual(pt, Point(x: 0, y: 4))
|
||||||
XCTAssertEqual(pt.y, 9)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSoutheast() {
|
func testSoutheast() {
|
||||||
let pt = box.southeast
|
let pt = box.southeast
|
||||||
XCTAssertEqual(pt.x, 8)
|
XCTAssertEqual(pt, Point(x: 4, y: 4))
|
||||||
XCTAssertEqual(pt.y, 9)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue