// // MarchingSquares.swift // Metaballs // // Created by Eryn Wells on 10/11/18. // Copyright © 2018 Eryn Wells. All rights reserved. // import Foundation import Metal class MarchingSquares { private var field: Field private var sampleGridSize: Size /// Samples of the field's current state. private(set) var samples: MTLTexture? /// Indexes of geometry to render. private(set) var indexes: MTLTexture? private(set) var gridGeometry: MTLBuffer? private var xSamples: Int { return Int(field.size.x / sampleGridSize.x) } private var ySamples: Int { return Int(field.size.y / sampleGridSize.y) } private var xGridlinesCount: Int { let xSamples = Int(field.size.x / sampleGridSize.x) return xSamples - 1 } private var yGridlinesCount: Int { let ySamples = Int(field.size.y / sampleGridSize.y) return ySamples - 1 } var gridVertexCount: Int { return xGridlinesCount * 2 + yGridlinesCount * 2 } init(field: Field) { self.field = field sampleGridSize = Size(16) } func setupMetal(withDevice device: MTLDevice) { guard xSamples > 1 && ySamples > 1 else { return } let samplesDesc = MTLTextureDescriptor() samplesDesc.textureType = .type2D samplesDesc.width = xSamples samplesDesc.height = ySamples samplesDesc.pixelFormat = .r32Float samples = device.makeTexture(descriptor: samplesDesc) let indexesDesc = MTLTextureDescriptor() indexesDesc.textureType = .type2D indexesDesc.width = xSamples - 1 indexesDesc.height = ySamples - 1 indexesDesc.pixelFormat = .a8Unorm indexes = device.makeTexture(descriptor: indexesDesc) let gridGeometryLength = MemoryLayout.stride * gridVertexCount gridGeometry = device.makeBuffer(length: gridGeometryLength, options: .storageModeShared) populateGridGeometryBuffer() } func fieldDidResize() { guard let gridGeometry = gridGeometry else { return } let gridGeometryLength = MemoryLayout.stride * gridVertexCount self.gridGeometry = gridGeometry.device.makeBuffer(length: gridGeometryLength, options: .storageModeShared) populateGridGeometryBuffer() } private func populateGridGeometryBuffer() { guard let gridGeometry = gridGeometry else { return } print("Rebuilding gridlines") var vertices = [Vertex]() let fieldSizeX = Float(field.size.x) let fieldSizeY = Float(field.size.y) for x in 1...stride * vertices.count) } func sampleField() { guard let samples = samples else { return } let bytesPerRow = samples.width * MemoryLayout.stride for xSample in 0...stride for x in 0.. 1.0 ? 0b1000 : 0) + (samples[1] > 1.0 ? 0b0100 : 0) + (samples[2] > 1.0 ? 0b0001 : 0) + (samples[3] > 1.0 ? 0b0010 : 0) let origin = MTLOrigin(x: x, y: y, z: 0) let size = MTLSize(width: 1, height: 1, depth: 1) let region = MTLRegion(origin: origin, size: size) let indexArr = [index] indexes.replace(region: region, mipmapLevel: 0, withBytes: indexArr, bytesPerRow: bytesPerRow) } } } private func getSampleBlock(x: Int, y: Int) -> [Float]? { guard let samples = samples else { return nil } var block: [Float] = [0, 0, 0, 0] let bytesPerRow = samples.width * MemoryLayout.stride let origin = MTLOrigin(x: x, y: y, z: 0) let size = MTLSize(width: 2, height: 2, depth: 1) let region = MTLRegion(origin: origin, size: size) samples.getBytes(&block, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0) return block } }