git.iko.soy/metal-metaballs
on master help sign in
Added state machine and internal loop.
aee469bvinivendra
PixelImage/MetalMetaballRenderer.swift+35−9
@@ -1,5 +1,3 @@
1−// TODO: Create state machine
2−// TODO: Make draw calls auto-loop, conditioned to the state machine
3// TODO: Create compute context to contain texture and imageBuffer
1// TODO: Create compute context to contain texture and imageBuffer
4// TOOD: Use two compute contexts and double recursion
2// TOOD: Use two compute contexts and double recursion
5
3
@@ -12,6 +10,8 @@
12import Metal
10import Metal
13import UIKit
11import UIKit
14
12
13+var i = 0
14+
15class MetalMetaballRenderer: MetaballRenderer {
15class MetalMetaballRenderer: MetaballRenderer {
16
16
17 typealias TargetView = UIImageView
17 typealias TargetView = UIImageView
@@ -33,12 +33,32 @@ class MetalMetaballRenderer: MetaballRenderer {
33 var dirty = false
33 var dirty = false
34 var metalIsBusy = false
34 var metalIsBusy = false
35
35
36+ enum RendererState {
37+ case Idle
38+ case Running
39+ case Ending
40+ }
41+
42+ var state: RendererState = .Idle {
43+ willSet {
44+ if state == .Idle {
45+ if newValue == .Running {
46+ updateTargetView()
47+ }
48+ }
49+ }
50+ }
51+
36 required init(dataSource: MetaballDataSource) {
52 required init(dataSource: MetaballDataSource) {
37 self.dataSource = dataSource
53 self.dataSource = dataSource
38 }
54 }
39
55
40 func updateTargetView() {
56 func updateTargetView() {
41
57
58+ print("Update \(i++)!")
59+
60+ state = .Ending
61+
42 // Re-alloc buffers if the size has changed
62 // Re-alloc buffers if the size has changed
43 if previousSize != targetView.size {
63 if previousSize != targetView.size {
44 previousSize = targetView.size
64 previousSize = targetView.size
@@ -56,6 +76,12 @@ class MetalMetaballRenderer: MetaballRenderer {
56 dispatch_async(dispatch_get_main_queue(), { () -> Void in
76 dispatch_async(dispatch_get_main_queue(), { () -> Void in
57 // Send image to view
77 // Send image to view
58 self.targetView.image = uiimage
78 self.targetView.image = uiimage
79+
80+ if self.state != .Running {
81+ self.state = .Idle
82+ } else {
83+ self.updateTargetView()
84+ }
59 })
85 })
60 }
86 }
61 }
87 }
@@ -97,7 +123,7 @@ class MetalMetaballRenderer: MetaballRenderer {
97
123
98 commandBuffer.commit()
124 commandBuffer.commit()
99 commandBuffer.waitUntilCompleted()
125 commandBuffer.waitUntilCompleted()
100−
126+
101 } catch _ {
127 } catch _ {
102 print("Error!")
128 print("Error!")
103 }
129 }
@@ -155,9 +181,9 @@ class MetalMetaballRenderer: MetaballRenderer {
155 let x = CGFloat(metaball.midX)
181 let x = CGFloat(metaball.midX)
156 let y = CGFloat(metaball.midY)
182 let y = CGFloat(metaball.midY)
157 if -border < x ≤ targetView.width + border &&
183 if -border < x ≤ targetView.width + border &&
158− -border < y ≤ targetView.height + border {
184+ -border < y ≤ targetView.height + border {
159− array.append(Float(x))
185+ array.append(Float(x))
160− array.append(Float(y))
186+ array.append(Float(y))
161 }
187 }
162 return array
188 return array
163 }
189 }
@@ -166,17 +192,17 @@ class MetalMetaballRenderer: MetaballRenderer {
166
192
167 // Create buffer
193 // Create buffer
168 let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
194 let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
169−
195+
170 return buffer
196 return buffer
171 }
197 }
172−
198+
173 func updateFrame() {
199 func updateFrame() {
174 if imageBuffer != nil {
200 if imageBuffer != nil {
175 free(imageBuffer)
201 free(imageBuffer)
176 }
202 }
177 imageBuffer = nil
203 imageBuffer = nil
178 }
204 }
179−
205+
180 deinit {
206 deinit {
181 free(imageBuffer)
207 free(imageBuffer)
182 }
208 }
PixelImage/ViewController.swift+2−9
@@ -36,13 +36,11 @@ class ViewController: UIViewController, MetaballDataSource {
36 bigView.addSubview(metaballView)
36 bigView.addSubview(metaballView)
37 view.addSubview(bigView)
37 view.addSubview(bigView)
38
38
39−
40 for metaball in metaballs {
39 for metaball in metaballs {
41 metaballView.addSubview(metaball)
40 metaballView.addSubview(metaball)
42 }
41 }
43
42
44−
43+ renderer.state = .Running
45− renderer.updateTargetView()
46 }
44 }
47
45
48 func handlePan(recognizer: UIPanGestureRecognizer) {
46 func handlePan(recognizer: UIPanGestureRecognizer) {
@@ -58,12 +56,7 @@ class ViewController: UIViewController, MetaballDataSource {
58
56
59 selectedMetaball?.middle = location
57 selectedMetaball?.middle = location
60
58
61− if recognizer.state == .Changed && renderer.supportsDynamicRendering {
59+ renderer.state = .Running
62− renderer.updateTargetView()
63− }
64− if recognizer.state == .Ended {
65− renderer.updateTargetView()
66− }
67 }
60 }
68}
61}
69
62