@@ -1,7 +1,12 @@
1−// TODO: Render metaballs on layer/view instead of image
1+// TODO: Optimize resources (don't allocate textures and images every frame)
2// TODO: Remove references to view size from shader
2// TODO: Remove references to view size from shader
3// TODO: Make shader ignore metaballs that are outside a certain area of tolerance (eg ±100 from borders)
3// TODO: Make shader ignore metaballs that are outside a certain area of tolerance (eg ±100 from borders)
5+// TODO: Metaballs from texture to buffer
6+// TODO: Use async dispatch to free up main queue
7+// TODO: Refactor update into 2 calls: metalRendering() and textureToImage()
8+// TODO: Use two textures/images to alternate the 2 calls (like OpenGL double buffers)
5// TODO: Make graphics have edges only according to graph (instead of being a complete graph)
10// TODO: Make graphics have edges only according to graph (instead of being a complete graph)
7// TODO: Interpolate metaball colors
12// TODO: Interpolate metaball colors
@@ -16,30 +21,34 @@ class MetalMetaballRenderer: MetaballRenderer {
16 typealias TargetView = UIImageView
21 typealias TargetView = UIImageView
18 static let context = MTLContext()
23 static let context = MTLContext()
24+ static var internalTexture: MTLTexture!
20 static func updateTargetView(imageView: UIImageView, dataSource: MetaballDataSource) {
26 static func updateTargetView(imageView: UIImageView, dataSource: MetaballDataSource) {
21 let metaballs = dataSource.metaballs
27 let metaballs = dataSource.metaballs
29+ let width = Int(imageView.width)
30+ let height = Int(imageView.height)
32+ if internalTexture == nil {
33+ let textureDescriptor =
34+ MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
36+ internalTexture = context.device.newTextureWithDescriptor(textureDescriptor)
23 let kernelFunction: MTLFunction?
39 let kernelFunction: MTLFunction?
24 let pipeline: MTLComputePipelineState
40 let pipeline: MTLComputePipelineState
25− var internalTexture: MTLTexture! = nil
42+ // Get long-lived objects
28 kernelFunction = context.library.newFunctionWithName("drawMetaballs")
43 kernelFunction = context.library.newFunctionWithName("drawMetaballs")
29 pipeline = try context.device.newComputePipelineStateWithFunction(kernelFunction!)
44 pipeline = try context.device.newComputePipelineStateWithFunction(kernelFunction!)
31− let width = Int(imageView.width)
46+ // Configure info for computing
32− let height = Int(imageView.height)
34− let textureDescriptor =
35− MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
37− internalTexture = context.device.newTextureWithDescriptor(textureDescriptor)
38 let threadGroupCounts = MTLSizeMake(8, 8, 1)
47 let threadGroupCounts = MTLSizeMake(8, 8, 1)
39 let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
48 let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
40 height / threadGroupCounts.height, 1)
49 height / threadGroupCounts.height, 1)
42− //
51+ // Create up-to-date metaball buffer
43 let metaballInfoTexture = metaballTexture(metaballs)
52 let metaballInfoTexture = metaballTexture(metaballs)