git.iko.soy/metal-metaballs
on master help sign in
Merged feature-colors into dev
21443eavinivendra
.gitignore+5−1
@@ -1,3 +1,7 @@
1.DS*
1.DS*
2PixelImage.xcodeproj/xcuserdata/*
2PixelImage.xcodeproj/xcuserdata/*
3−PixelImage.xcodeproj/project.xcworkspace/xcuserdata/*
3+PixelImage.xcodeproj/project.xcworkspace/xcuserdata/*
4+
5+Pods/*
6+
7+
PixelImage.xcodeproj/project.pbxproj+96
@@ -13,6 +13,7 @@
13 2426868F1C63B72A00D62456 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2426868E1C63B72A00D62456 /* Assets.xcassets */; };
13 2426868F1C63B72A00D62456 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2426868E1C63B72A00D62456 /* Assets.xcassets */; };
14 242686921C63B72A00D62456 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 242686901C63B72A00D62456 /* LaunchScreen.storyboard */; };
14 242686921C63B72A00D62456 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 242686901C63B72A00D62456 /* LaunchScreen.storyboard */; };
15 2461651B1C6DA4F400A913C8 /* Interpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461651A1C6DA4F400A913C8 /* Interpolation.swift */; };
15 2461651B1C6DA4F400A913C8 /* Interpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461651A1C6DA4F400A913C8 /* Interpolation.swift */; };
16+ 246B0F831C70635D00A71D05 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 246B0F821C70635D00A71D05 /* UIColor.swift */; };
16 249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249CF84B1C6D113C008B0C78 /* Matrix.swift */; };
17 249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249CF84B1C6D113C008B0C78 /* Matrix.swift */; };
17 24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */; };
18 24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */; };
18 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */; };
19 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */; };
@@ -49,6 +50,7 @@
49 24FFA8841C6BA038005ACD60 /* TakeDrop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */; };
50 24FFA8841C6BA038005ACD60 /* TakeDrop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */; };
50 24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8691C6BA038005ACD60 /* Zip.swift */; };
51 24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8691C6BA038005ACD60 /* Zip.swift */; };
51 24FFA8861C6BA038005ACD60 /* TestCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */; };
52 24FFA8861C6BA038005ACD60 /* TestCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */; };
53+ 2BF7957B6518CA68241BB2CE /* Pods_PixelImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C55F9558B3B267413C3A07A6 /* Pods_PixelImage.framework */; };
52/* End PBXBuildFile section */
54/* End PBXBuildFile section */
53
55
54/* Begin PBXFileReference section */
56/* Begin PBXFileReference section */
@@ -60,6 +62,7 @@
60 242686911C63B72A00D62456 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
62 242686911C63B72A00D62456 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
61 242686931C63B72A00D62456 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
63 242686931C63B72A00D62456 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
62 2461651A1C6DA4F400A913C8 /* Interpolation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Interpolation.swift; path = PixelImage/Interpolation.swift; sourceTree = SOURCE_ROOT; };
64 2461651A1C6DA4F400A913C8 /* Interpolation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Interpolation.swift; path = PixelImage/Interpolation.swift; sourceTree = SOURCE_ROOT; };
65+ 246B0F821C70635D00A71D05 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = "<group>"; };
63 249CF84B1C6D113C008B0C78 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
66 249CF84B1C6D113C008B0C78 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
64 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIKit.swift; sourceTree = "<group>"; };
67 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIKit.swift; sourceTree = "<group>"; };
65 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
68 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
@@ -96,6 +99,9 @@
96 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TakeDrop.swift; sourceTree = "<group>"; };
99 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TakeDrop.swift; sourceTree = "<group>"; };
97 24FFA8691C6BA038005ACD60 /* Zip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Zip.swift; sourceTree = "<group>"; };
100 24FFA8691C6BA038005ACD60 /* Zip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Zip.swift; sourceTree = "<group>"; };
98 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCommons.swift; sourceTree = "<group>"; };
101 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCommons.swift; sourceTree = "<group>"; };
102+ B1A755EFC03DA2A172C2B82F /* Pods-PixelImage.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.debug.xcconfig"; sourceTree = "<group>"; };
103+ C419D37C90A6BE8B5139806A /* Pods-PixelImage.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.release.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.release.xcconfig"; sourceTree = "<group>"; };
104+ C55F9558B3B267413C3A07A6 /* Pods_PixelImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PixelImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
99/* End PBXFileReference section */
105/* End PBXFileReference section */
100
106
101/* Begin PBXFrameworksBuildPhase section */
107/* Begin PBXFrameworksBuildPhase section */
@@ -105,6 +111,7 @@
105 files = (
111 files = (
106 24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */,
112 24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */,
107 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */,
113 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */,
114+ 2BF7957B6518CA68241BB2CE /* Pods_PixelImage.framework in Frameworks */,
108 );
115 );
109 runOnlyForDeploymentPostprocessing = 0;
116 runOnlyForDeploymentPostprocessing = 0;
110 };
117 };
@@ -118,6 +125,8 @@
118 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */,
125 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */,
119 242686861C63B72A00D62456 /* PixelImage */,
126 242686861C63B72A00D62456 /* PixelImage */,
120 242686851C63B72A00D62456 /* Products */,
127 242686851C63B72A00D62456 /* Products */,
128+ F1933B48ED44BA9FCD7A4A1F /* Pods */,
129+ 588576572D7A188031904848 /* Frameworks */,
121 );
130 );
122 sourceTree = "<group>";
131 sourceTree = "<group>";
123 };
132 };
@@ -136,6 +145,7 @@
136 242686871C63B72A00D62456 /* AppDelegate.swift */,
145 242686871C63B72A00D62456 /* AppDelegate.swift */,
137 242686891C63B72A00D62456 /* ViewController.swift */,
146 242686891C63B72A00D62456 /* ViewController.swift */,
138 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */,
147 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */,
148+ 246B0F821C70635D00A71D05 /* UIColor.swift */,
139 24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */,
149 24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */,
140 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */,
150 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */,
141 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */,
151 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */,
@@ -209,6 +219,23 @@
209 path = SwiftSequences;
219 path = SwiftSequences;
210 sourceTree = "<group>";
220 sourceTree = "<group>";
211 };
221 };
222+ 588576572D7A188031904848 /* Frameworks */ = {
223+ isa = PBXGroup;
224+ children = (
225+ C55F9558B3B267413C3A07A6 /* Pods_PixelImage.framework */,
226+ );
227+ name = Frameworks;
228+ sourceTree = "<group>";
229+ };
230+ F1933B48ED44BA9FCD7A4A1F /* Pods */ = {
231+ isa = PBXGroup;
232+ children = (
233+ B1A755EFC03DA2A172C2B82F /* Pods-PixelImage.debug.xcconfig */,
234+ C419D37C90A6BE8B5139806A /* Pods-PixelImage.release.xcconfig */,
235+ );
236+ name = Pods;
237+ sourceTree = "<group>";
238+ };
212/* End PBXGroup section */
239/* End PBXGroup section */
213
240
214/* Begin PBXNativeTarget section */
241/* Begin PBXNativeTarget section */
@@ -216,9 +243,13 @@
216 isa = PBXNativeTarget;
243 isa = PBXNativeTarget;
217 buildConfigurationList = 242686961C63B72A00D62456 /* Build configuration list for PBXNativeTarget "PixelImage" */;
244 buildConfigurationList = 242686961C63B72A00D62456 /* Build configuration list for PBXNativeTarget "PixelImage" */;
218 buildPhases = (
245 buildPhases = (
246+ EF55C7246917A184756D93D8 /* Check Pods Manifest.lock */,
219 242686801C63B72A00D62456 /* Sources */,
247 242686801C63B72A00D62456 /* Sources */,
220 242686811C63B72A00D62456 /* Frameworks */,
248 242686811C63B72A00D62456 /* Frameworks */,
221 242686821C63B72A00D62456 /* Resources */,
249 242686821C63B72A00D62456 /* Resources */,
250+ C7A2DF67265A9D17DEFBD193 /* Embed Pods Frameworks */,
251+ FADC01F75BFAC01F0260D1C9 /* Copy Pods Resources */,
252+ DD0396CE594E3EAC8D18CC6C /* Tailor */,
222 );
253 );
223 buildRules = (
254 buildRules = (
224 );
255 );
@@ -276,6 +307,68 @@
276 };
307 };
277/* End PBXResourcesBuildPhase section */
308/* End PBXResourcesBuildPhase section */
278
309
310+/* Begin PBXShellScriptBuildPhase section */
311+ C7A2DF67265A9D17DEFBD193 /* Embed Pods Frameworks */ = {
312+ isa = PBXShellScriptBuildPhase;
313+ buildActionMask = 2147483647;
314+ files = (
315+ );
316+ inputPaths = (
317+ );
318+ name = "Embed Pods Frameworks";
319+ outputPaths = (
320+ );
321+ runOnlyForDeploymentPostprocessing = 0;
322+ shellPath = /bin/sh;
323+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage-frameworks.sh\"\n";
324+ showEnvVarsInLog = 0;
325+ };
326+ DD0396CE594E3EAC8D18CC6C /* Tailor */ = {
327+ isa = PBXShellScriptBuildPhase;
328+ buildActionMask = 2147483647;
329+ files = (
330+ );
331+ inputPaths = (
332+ );
333+ name = Tailor;
334+ outputPaths = (
335+ );
336+ runOnlyForDeploymentPostprocessing = 0;
337+ shellPath = /bin/sh;
338+ shellScript = "if hash tailor 2>/dev/null; then\n tailor --except=function-whitespace,leading-whitespace,constant-k-prefix --max-severity error\nelse\n echo \"warning: Please install Tailor from https://tailor.sh\"\nfi";
339+ };
340+ EF55C7246917A184756D93D8 /* Check Pods Manifest.lock */ = {
341+ isa = PBXShellScriptBuildPhase;
342+ buildActionMask = 2147483647;
343+ files = (
344+ );
345+ inputPaths = (
346+ );
347+ name = "Check Pods Manifest.lock";
348+ outputPaths = (
349+ );
350+ runOnlyForDeploymentPostprocessing = 0;
351+ shellPath = /bin/sh;
352+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
353+ showEnvVarsInLog = 0;
354+ };
355+ FADC01F75BFAC01F0260D1C9 /* Copy Pods Resources */ = {
356+ isa = PBXShellScriptBuildPhase;
357+ buildActionMask = 2147483647;
358+ files = (
359+ );
360+ inputPaths = (
361+ );
362+ name = "Copy Pods Resources";
363+ outputPaths = (
364+ );
365+ runOnlyForDeploymentPostprocessing = 0;
366+ shellPath = /bin/sh;
367+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage-resources.sh\"\n";
368+ showEnvVarsInLog = 0;
369+ };
370+/* End PBXShellScriptBuildPhase section */
371+
279/* Begin PBXSourcesBuildPhase section */
372/* Begin PBXSourcesBuildPhase section */
280 242686801C63B72A00D62456 /* Sources */ = {
373 242686801C63B72A00D62456 /* Sources */ = {
281 isa = PBXSourcesBuildPhase;
374 isa = PBXSourcesBuildPhase;
@@ -308,6 +401,7 @@
308 24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */,
401 24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */,
309 24FFA87D1C6BA038005ACD60 /* Hopping.swift in Sources */,
402 24FFA87D1C6BA038005ACD60 /* Hopping.swift in Sources */,
310 24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */,
403 24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */,
404+ 246B0F831C70635D00A71D05 /* UIColor.swift in Sources */,
311 24FFA87A1C6BA038005ACD60 /* Enumerate.swift in Sources */,
405 24FFA87A1C6BA038005ACD60 /* Enumerate.swift in Sources */,
312 242686881C63B72A00D62456 /* AppDelegate.swift in Sources */,
406 242686881C63B72A00D62456 /* AppDelegate.swift in Sources */,
313 24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */,
407 24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */,
@@ -428,6 +522,7 @@
428 };
522 };
429 242686971C63B72A00D62456 /* Debug */ = {
523 242686971C63B72A00D62456 /* Debug */ = {
430 isa = XCBuildConfiguration;
524 isa = XCBuildConfiguration;
525+ baseConfigurationReference = B1A755EFC03DA2A172C2B82F /* Pods-PixelImage.debug.xcconfig */;
431 buildSettings = {
526 buildSettings = {
432 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
527 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
433 INFOPLIST_FILE = PixelImage/Info.plist;
528 INFOPLIST_FILE = PixelImage/Info.plist;
@@ -439,6 +534,7 @@
439 };
534 };
440 242686981C63B72A00D62456 /* Release */ = {
535 242686981C63B72A00D62456 /* Release */ = {
441 isa = XCBuildConfiguration;
536 isa = XCBuildConfiguration;
537+ baseConfigurationReference = C419D37C90A6BE8B5139806A /* Pods-PixelImage.release.xcconfig */;
442 buildSettings = {
538 buildSettings = {
443 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
539 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
444 INFOPLIST_FILE = PixelImage/Info.plist;
540 INFOPLIST_FILE = PixelImage/Info.plist;
PixelImage.xcworkspace/contents.xcworkspacedatanew file+10
@@ -0,0 +1,10 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "group:PixelImage.xcodeproj">
6+ </FileRef>
7+ <FileRef
8+ location = "group:Pods/Pods.xcodeproj">
9+ </FileRef>
10+</Workspace>
PixelImage.xcworkspace/xcuserdata/vini.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

PixelImage.xcworkspace/xcuserdata/vini.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Bucket
3+ type = "0"
4+ version = "2.0">
5+</Bucket>
PixelImage/AppDelegate.swift−4
@@ -13,7 +13,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
13
13
14 var window: UIWindow?
14 var window: UIWindow?
15
15
16−
17 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
16 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 // Override point for customization after application launch.
17 // Override point for customization after application launch.
19 return true
18 return true
@@ -40,7 +39,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
40 func applicationWillTerminate(application: UIApplication) {
39 func applicationWillTerminate(application: UIApplication) {
41 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
40 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 }
41 }
43−
44−
45}
42}
46−
PixelImage/Interpolation.swift−2
@@ -1,4 +1,3 @@
1−
2func interpolateCubeEaseIn<T: Numeric>(linear: T) -> T {
1func interpolateCubeEaseIn<T: Numeric>(linear: T) -> T {
3 return linear ^ 3
2 return linear ^ 3
4}
3}
@@ -14,4 +13,3 @@ func interpolateSquareEaseOut<T: Numeric>(linear: T) -> T {
14func interpolateSmooth<T: Numeric>(linear: T) -> T {
13func interpolateSmooth<T: Numeric>(linear: T) -> T {
15 return ((linear) * (linear) * (linear) * ((linear) * ((linear) * 6 - 15) + 10))
14 return ((linear) * (linear) * (linear) * ((linear) * ((linear) * 6 - 15) + 10))
16}
15}
17−
PixelImage/Matrix.swift+1−1
@@ -1,4 +1,3 @@
1−
2import UIKit
1import UIKit
3
2
4class Graph<T> {
3class Graph<T> {
@@ -27,6 +26,7 @@ class Graph<T> {
27 adjacencyMatrix.reset(i, j)
26 adjacencyMatrix.reset(i, j)
28 adjacencyMatrix.reset(j, i)
27 adjacencyMatrix.reset(j, i)
29 }
28 }
29+
30}
30}
31
31
32struct Matrix: CustomStringConvertible {
32struct Matrix: CustomStringConvertible {
PixelImage/MetaballDataSource.swift+2−2
@@ -1,4 +1,3 @@
1−
2import Metal
1import Metal
3
2
4protocol MetaballDataSource {
3protocol MetaballDataSource {
@@ -11,4 +10,5 @@ extension MetaballDataSource {
11 return metaballGraph.vertices
10 return metaballGraph.vertices
12 }
11 }
13 }
12 }
13+
14−}
14+}
PixelImage/Metal.swift+1−1
@@ -40,4 +40,4 @@ class MTLComputeContext {
40 deinit {
40 deinit {
41 free(imageBuffer)
41 free(imageBuffer)
42 }
42 }
43−}
43+}
PixelImage/MetalMetaballRenderer.swift+34−28
@@ -1,5 +1,6 @@
1import Metal
1import Metal
2import UIKit
2import UIKit
3+import ChameleonFramework
3
4
4class MetalMetaballRenderer {
5class MetalMetaballRenderer {
5
6
@@ -38,8 +39,7 @@ class MetalMetaballRenderer {
38
39
39 let width = Int(frame.width)
40 let width = Int(frame.width)
40 let height = Int(frame.height)
41 let height = Int(frame.height)
41− let textureDescriptor =
42− MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
42+ let textureDescriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
43
43
44 let texture1 = context.device.newTextureWithDescriptor(textureDescriptor)
44 let texture1 = context.device.newTextureWithDescriptor(textureDescriptor)
45 activeComputeContext = MTLComputeContext(size: targetView.size, texture: texture1)
45 activeComputeContext = MTLComputeContext(size: targetView.size, texture: texture1)
@@ -54,7 +54,8 @@ class MetalMetaballRenderer {
54
54
55 state = .Ending
55 state = .Ending
56
56
57− dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)) { () -> Void in
57+ let userInteractiveQueue = dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)
58+ dispatch_async(userInteractiveQueue) { () -> Void in
58
59
59 let computeContext = self.activeComputeContext
60 let computeContext = self.activeComputeContext
60 swap(&self.activeComputeContext, &self.idleComputeContext)
61 swap(&self.activeComputeContext, &self.idleComputeContext)
@@ -73,10 +74,10 @@ class MetalMetaballRenderer {
73
74
74 dispatch_semaphore_signal(self.semaphore)
75 dispatch_semaphore_signal(self.semaphore)
75
76
76− dispatch_async(dispatch_get_main_queue(), { () -> Void in
77+ dispatch_async(dispatch_get_main_queue()) { () -> Void in
77 // Send image to view
78 // Send image to view
78 self.targetView.image = uiimage
79 self.targetView.image = uiimage
79− })
80+ }
80 }
81 }
81 }
82 }
82
83
@@ -93,8 +94,7 @@ class MetalMetaballRenderer {
93
94
94 // Configure info for computing
95 // Configure info for computing
95 let threadGroupCounts = MTLSizeMake(8, 8, 1)
96 let threadGroupCounts = MTLSizeMake(8, 8, 1)
96− let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
97+ let threadGroups = MTLSizeMake(width / threadGroupCounts.width, height / threadGroupCounts.height, 1)
97− height / threadGroupCounts.height, 1)
98
98
99 // Send commands to metal and render
99 // Send commands to metal and render
100 let commandBuffer = context.commandQueue.commandBuffer()
100 let commandBuffer = context.commandQueue.commandBuffer()
@@ -112,7 +112,6 @@ class MetalMetaballRenderer {
112
112
113 commandBuffer.commit()
113 commandBuffer.commit()
114 commandBuffer.waitUntilCompleted()
114 commandBuffer.waitUntilCompleted()
115−
116 } catch _ {
115 } catch _ {
117 print("Error!")
116 print("Error!")
118 }
117 }
@@ -122,8 +121,7 @@ class MetalMetaballRenderer {
122 let texture = computeContext.texture
121 let texture = computeContext.texture
123
122
124 // Get image info
123 // Get image info
125− let imageSize = CGSizeMake(CGFloat(texture.width),
124+ let imageSize = CGSizeMake(CGFloat(texture.width), CGFloat(texture.height))
126− CGFloat(texture.height))
127 let width = Int(imageSize.width)
125 let width = Int(imageSize.width)
128 let height = Int(imageSize.height)
126 let height = Int(imageSize.height)
129 let imageByteCount = width * height * 4
127 let imageByteCount = width * height * 4
@@ -136,27 +134,20 @@ class MetalMetaballRenderer {
136 }
134 }
137
135
138 // Transfer texture info into image buffer
136 // Transfer texture info into image buffer
139− texture.getBytes(computeContext.imageBuffer, bytesPerRow: bytesPerRow,
137+ texture.getBytes(computeContext.imageBuffer, bytesPerRow: bytesPerRow, fromRegion: region, mipmapLevel: 0)
140− fromRegion: region, mipmapLevel: 0)
141
138
142 // Get info for UIImage
139 // Get info for UIImage
143− let provider = CGDataProviderCreateWithData(nil, computeContext.imageBuffer,
140+ let provider = CGDataProviderCreateWithData(nil, computeContext.imageBuffer, imageByteCount, nil)
144− imageByteCount, nil)
145 let bitsPerComponent = 8
141 let bitsPerComponent = 8
146 let bitsperPixel = 32
142 let bitsperPixel = 32
147 let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
143 let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
148− let bitmapInfo = CGBitmapInfo(rawValue:
149− CGImageAlphaInfo.PremultipliedLast.rawValue |
144+ let bitmapInfoRaw = CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Big.rawValue
150− CGBitmapInfo.ByteOrder32Big.rawValue)
145+ let bitmapInfo = CGBitmapInfo(rawValue: bitmapInfoRaw)
151 let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
146 let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
152
147
153 // Create UIImage from image buffer
148 // Create UIImage from image buffer
154− let imageRef = CGImageCreate(width, height,
155− bitsPerComponent, bitsperPixel, bytesPerRow,
149+ let imageRef = CGImageCreate(width, height, bitsPerComponent, bitsperPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, nil, false, renderingIntent)
156− colorSpaceRef, bitmapInfo, provider,
157− nil, false, renderingIntent)
158− let image = UIImage(CGImage: imageRef!, scale: 0.0,
150+ let image = UIImage(CGImage: imageRef!, scale: 0.0, orientation: .Up)
159− orientation: UIImageOrientation.Up)
160
151
161 return image
152 return image
162 }
153 }
@@ -164,7 +155,9 @@ class MetalMetaballRenderer {
164 func metaballEdgesBuffer() -> MTLBuffer {
155 func metaballEdgesBuffer() -> MTLBuffer {
165 let floats = dataSource.metaballGraph.adjacencyMatrix.buffer
156 let floats = dataSource.metaballGraph.adjacencyMatrix.buffer
166
157
167− let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
158+ let bufferLength = floats.count * sizeof(Float)
159+ let device = context.device
160+ let buffer = device.newBufferWithBytes(floats, length: bufferLength, options: .StorageModeShared)
168
161
169 return buffer
162 return buffer
170 }
163 }
@@ -174,22 +167,35 @@ class MetalMetaballRenderer {
174 // Exclude metaballs far from the view's bounds
167 // Exclude metaballs far from the view's bounds
175 let border: CGFloat = 100
168 let border: CGFloat = 100
176 let metaballs = self.dataSource.metaballs
169 let metaballs = self.dataSource.metaballs
170+
171+ var floats = [Float](count: 5, repeatedValue: 0)
172+ floats = metaballs.reduce(floats) {
177− var floats: [Float] = metaballs.reduce([Float(0)]) { (var array, metaball) -> [Float] in
173+ (var array, metaball) -> [Float] in
174+
178 let x = CGFloat(metaball.midX)
175 let x = CGFloat(metaball.midX)
179 let y = CGFloat(metaball.midY)
176 let y = CGFloat(metaball.midY)
180 if -border < x ≤ targetView.width + border &&
177 if -border < x ≤ targetView.width + border &&
181 -border < y ≤ targetView.height + border {
178 -border < y ≤ targetView.height + border {
182 array.append(Float(x))
179 array.append(Float(x))
183 array.append(Float(y))
180 array.append(Float(y))
181+
182+ let color = metaball.backgroundColor!
183+ let components = color.components
184+ array.append(Float(components.red))
185+ array.append(Float(components.green))
186+ array.append(Float(components.blue))
184 }
187 }
185 return array
188 return array
186 }
189 }
190+
187 // Add array size to start of array so metal knows how far to go
191 // Add array size to start of array so metal knows how far to go
188− floats[0] = Float(floats.count) / 2
192+ floats[0] = Float(floats.count) / 5
189
193
190 // Create buffer
194 // Create buffer
191− let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
195+ let bufferLength = floats.count * sizeof(Float)
192−
196+ let device = context.device
197+ let buffer = device.newBufferWithBytes(floats, length: bufferLength, options: .StorageModeShared)
198+
193 return buffer
199 return buffer
194 }
200 }
195}
201}
PixelImage/SwiftSugar/Dictionary.swift+1−1
@@ -1,7 +1,7 @@
1extension Dictionary {
1extension Dictionary {
2 subscript(keys: [Key]) -> [Value] {
2 subscript(keys: [Key]) -> [Value] {
3 get {
3 get {
4− return keys.unwrappedMap({ self[$0] })
4+ return keys.unwrappedMap { self[$0] }
5 }
5 }
6 set (values) {
6 set (values) {
7 for (key, value) in zip(keys, values) {
7 for (key, value) in zip(keys, values) {
PixelImage/SwiftSugar/Foundation/NSNumber.swift+4−1
@@ -2,10 +2,13 @@ import Foundation
2
2
3extension NSNumber: DoubleValuable {
3extension NSNumber: DoubleValuable {
4 var toDouble: Double {
4 var toDouble: Double {
5+ get {
5− get { return self.doubleValue }
6+ return self.doubleValue
7+ }
6 }
8 }
7
9
8 static func fromDouble(double: Double) -> Self {
10 static func fromDouble(double: Double) -> Self {
9 return self.init(double: double)
11 return self.init(double: double)
10 }
12 }
13+
11}
14}
PixelImage/SwiftSugar/Numeric.swift+15−4
@@ -20,43 +20,54 @@ protocol Numeric: DoubleValuable, Incrementable, Comparable,
20 postfix func ++ (inout _: Self) -> Self
20 postfix func ++ (inout _: Self) -> Self
21}
21}
22
22
23−protocol FastNumeric: Numeric { }
23+protocol FastNumeric: Numeric {}
24
24
25extension Double: FastNumeric {
25extension Double: FastNumeric {
26 var toDouble: Double {
26 var toDouble: Double {
27+ get {
27− get { return self }
28+ return self
29+ }
28 }
30 }
29
31
30 static func fromDouble(double: Double) -> Double {
32 static func fromDouble(double: Double) -> Double {
31 return double
33 return double
32 }
34 }
35+
33}
36}
34
37
35extension Float: FastNumeric {
38extension Float: FastNumeric {
36 var toDouble: Double {
39 var toDouble: Double {
40+ get {
37− get { return Double(self) }
41+ return Double(self)
42+ }
38 }
43 }
39
44
40 static func fromDouble(double: Double) -> Float {
45 static func fromDouble(double: Double) -> Float {
41 return Float(double)
46 return Float(double)
42 }
47 }
48+
43}
49}
44
50
45extension Int: FastNumeric {
51extension Int: FastNumeric {
46 var toDouble: Double {
52 var toDouble: Double {
53+ get {
47− get { return Double(self) }
54+ return Double(self)
55+ }
48 }
56 }
49
57
50 static func fromDouble(double: Double) -> Int {
58 static func fromDouble(double: Double) -> Int {
51 return Int(double)
59 return Int(double)
52 }
60 }
61+
53}
62}
54
63
55//
64//
56extension Int {
65extension Int {
66+
57 func times(@noescape block: () throws -> ()) rethrows {
67 func times(@noescape block: () throws -> ()) rethrows {
58 for _ in 1...self {
68 for _ in 1...self {
59 try block()
69 try block()
60 }
70 }
61 }
71 }
72+
62}
73}
PixelImage/SwiftSugar/PowerOperator.swift+1−1
@@ -2,7 +2,7 @@ import Darwin
2
2
3infix operator ^ { associativity right precedence 131 }
3infix operator ^ { associativity right precedence 131 }
4
4
5−func ^<T: DoubleValuable>(left: T, right: T) -> T {
5+func ^ <T: DoubleValuable>(left: T, right: T) -> T {
6 return T.fromDouble(pow(left.toDouble, right.toDouble))
6 return T.fromDouble(pow(left.toDouble, right.toDouble))
7}
7}
8
8
PixelImage/SwiftSugar/Sequences/Memoize.swift+51−46
@@ -7,62 +7,66 @@ protocol MemoizedSequence: LazySequenceType {
7 memoizedFunction: (IndexType -> ReturnType))
7 memoizedFunction: (IndexType -> ReturnType))
8}
8}
9
9
10+struct HashMemoizedSequence<IndexType: Hashable, ReturnType>:
11+ MemoizedSequence {
10
12
11−struct HashMemoizedSequence <IndexType: Hashable, ReturnType>:
13+ let memoizedFunction: (IndexType -> ReturnType)
12−MemoizedSequence {
14+ let increment: ((inout IndexType) -> Void)
15+ let firstIndex: IndexType
13
16
14− let memoizedFunction: (IndexType -> ReturnType)
15− let increment: ((inout IndexType) -> Void)
16− let firstIndex: IndexType
17+ var index: IndexType
17
18
18− var index: IndexType
19+ init(first: IndexType,
20+ incrementer: ((inout IndexType) -> Void),
21+ memoizedFunction: (IndexType -> ReturnType)) {
19
22
20− init(first: IndexType,
23+ self.firstIndex = first
21− incrementer: ((inout IndexType) -> Void),
22− memoizedFunction: (IndexType -> ReturnType)) {
23
24
24− self.firstIndex = first
25+ self.index = first
26+ self.increment = incrementer
27+ self.memoizedFunction = memoizedFunction
28+ }
25
29
26− self.index = first
30+ init(first: IndexType,
27− self.increment = incrementer
31+ incrementer: ((inout IndexType) -> Void),
32+ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
28− self.memoizedFunction = memoizedFunction
33+ let memoizedFunction = memoize(closure)
29− }
30
34
31− init(first: IndexType,
32− incrementer: ((inout IndexType) -> Void),
33− closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
34− let memoizedFunction = memoize(closure)
35−
36− self.init(first: first, incrementer: incrementer,
35+ self.init(first: first, incrementer: incrementer,
37− memoizedFunction: memoizedFunction)
36+ memoizedFunction: memoizedFunction)
38− }
37+ }
39
38
40− init(first: IndexType,
39+ init(first: IndexType,
41− incrementer: ((inout IndexType) -> Void),
40+ incrementer: ((inout IndexType) -> Void),
42− function: (IndexType -> ReturnType)) {
41+ function: (IndexType -> ReturnType)) {
43
42
44− let memoizedFunction = memoize(function)
43+ let memoizedFunction = memoize(function)
45
44
46− self.init(first: first, incrementer: incrementer,
45+ self.init(first: first, incrementer: incrementer,
47− memoizedFunction: memoizedFunction)
46+ memoizedFunction: memoizedFunction)
48− }
47+ }
49}
48}
50
49
51extension HashMemoizedSequence: GeneratorType {
50extension HashMemoizedSequence: GeneratorType {
51+
52 mutating func next() -> ReturnType? {
52 mutating func next() -> ReturnType? {
53 let result = memoizedFunction(index)
53 let result = memoizedFunction(index)
54 increment(&index)
54 increment(&index)
55 return result
55 return result
56 }
56 }
57+
57}
58}
58
59
59extension HashMemoizedSequence: LazySequenceType {
60extension HashMemoizedSequence: LazySequenceType {
61+
60 func generate() -> HashMemoizedSequence {
62 func generate() -> HashMemoizedSequence {
61 return self
63 return self
62 }
64 }
65+
63}
66}
64
67
65extension HashMemoizedSequence where ReturnType: Comparable {
68extension HashMemoizedSequence where ReturnType: Comparable {
69+
66 @warn_unused_result
70 @warn_unused_result
67 func contains(element: ReturnType) -> Bool {
71 func contains(element: ReturnType) -> Bool {
68 var index = firstIndex
72 var index = firstIndex
@@ -79,6 +83,7 @@ extension HashMemoizedSequence where ReturnType: Comparable {
79 increment(&index)
83 increment(&index)
80 }
84 }
81 }
85 }
86+
82}
87}
83
88
84extension HashMemoizedSequence where IndexType: Incrementable {
89extension HashMemoizedSequence where IndexType: Incrementable {
@@ -104,29 +109,29 @@ extension HashMemoizedSequence where IndexType: Incrementable {
104}
109}
105
110
106extension HashMemoizedSequence where IndexType: Incrementable,
111extension HashMemoizedSequence where IndexType: Incrementable,
107− IndexType: IntegerLiteralConvertible {
112+IndexType: IntegerLiteralConvertible {
108 init(_ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
113 init(_ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
109− self.firstIndex = 1
114+ self.firstIndex = 1
110− self.index = 1
115+ self.index = 1
111− self.increment = { (inout index: IndexType) in
116+ self.increment = { (inout index: IndexType) in
112− index++
117+ index++
113− }
118+ }
114− self.memoizedFunction = memoize(closure)
119+ self.memoizedFunction = memoize(closure)
115 }
120 }
116
121
117 init(_ function: (IndexType -> ReturnType)) {
122 init(_ function: (IndexType -> ReturnType)) {
118− self.firstIndex = 1
123+ self.firstIndex = 1
119− self.index = 1
124+ self.index = 1
120− self.increment = { (inout index: IndexType) in
125+ self.increment = { (inout index: IndexType) in
121− index++
126+ index++
122− }
127+ }
123− self.memoizedFunction = memoize(function)
128+ self.memoizedFunction = memoize(function)
124 }
129 }
125}
130}
126
131
127−func memoize <H: Hashable, R> (closure: ((H -> R, H) -> R) ) -> (H -> R) {
132+func memoize<H: Hashable, R>(closure: ((H -> R, H) -> R)) -> (H -> R) {
128
133
129− var table = [H : R]()
134+ var table = [H: R]()
130
135
131 var auxiliaryFunction: (H -> R)!
136 var auxiliaryFunction: (H -> R)!
132 auxiliaryFunction = { index in
137 auxiliaryFunction = { index in
@@ -143,9 +148,9 @@ func memoize <H: Hashable, R> (closure: ((H -> R, H) -> R) ) -> (H -> R) {
143 return auxiliaryFunction
148 return auxiliaryFunction
144}
149}
145
150
146−func memoize <H: Hashable, R> (function: (H -> R) ) -> (H -> R) {
151+func memoize<H: Hashable, R>(function: (H -> R)) -> (H -> R) {
147
152
148− var table = [H : R]()
153+ var table = [H: R]()
149
154
150 let result: (H -> R) = { index in
155 let result: (H -> R) = { index in
151 if let result = table[index] {
156 if let result = table[index] {
PixelImage/SwiftSugar/SignOperator.swift+8−9
@@ -1,13 +1,12 @@
1−
2prefix operator ± { }
1prefix operator ± { }
3
2
4−prefix func ± <T: Numeric> (number: T) -> T {
3+prefix func ± <T: Numeric>(number: T) -> T {
5
4
6− if number > 0 {
5+ if number > 0 {
7− return 1
6+ return 1
8− } else if number == 0 {
7+ } else if number == 0 {
9− return 0
8+ return 0
10− } else {
9+ } else {
11− return -1
10+ return -1
12− }
11+ }
13}
12}
PixelImage/SwiftSugar/String.swift+4−1
@@ -1,9 +1,12 @@
1extension String: DoubleValuable {
1extension String: DoubleValuable {
2 var toDouble: Double {
2 var toDouble: Double {
3+ get {
3− get { return Double(self) ?? Double(0) }
4+ return Double(self) ?? Double(0)
5+ }
4 }
6 }
5
7
6 static func fromDouble(double: Double) -> String {
8 static func fromDouble(double: Double) -> String {
7 return "\(double)"
9 return "\(double)"
8 }
10 }
11+
9}
12}
PixelImage/SwiftSugar/TestCommons.swift+2−1
@@ -8,7 +8,7 @@
8
8
9import Darwin
9import Darwin
10
10
11−class Random <T: Numeric> {
11+class Random<T: Numeric> {
12
12
13 let max: Double = Double(INT32_MAX)
13 let max: Double = Double(INT32_MAX)
14 let exponent: Double = 7
14 let exponent: Double = 7
@@ -92,4 +92,5 @@ class Random <T: Numeric> {
92 let result = Double((2 * rawRandom) - 1)
92 let result = Double((2 * rawRandom) - 1)
93 return T.fromDouble(result)
93 return T.fromDouble(result)
94 }
94 }
95+
95}
96}
PixelImage/UIColor.swiftnew file+9
@@ -0,0 +1,9 @@
1+import UIKit
2+
3+extension UIColor {
4+ var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
5+ var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
6+ getRed(&r, green: &g, blue: &b, alpha: &a)
7+ return (r, g, b, a)
8+ }
9+}
PixelImage/UIKit.swift+52−18
@@ -31,6 +31,7 @@ extension CGVector {
31 dx = dx / norm
31 dx = dx / norm
32 dy = dy / norm
32 dy = dy / norm
33 }
33 }
34+
34}
35}
35
36
36extension CGFloat: DoubleValuable {
37extension CGFloat: DoubleValuable {
@@ -42,19 +43,28 @@ extension CGFloat: DoubleValuable {
42 static func fromDouble(double: Double) -> CGFloat {
43 static func fromDouble(double: Double) -> CGFloat {
43 return CGFloat(double)
44 return CGFloat(double)
44 }
45 }
46+
45}
47}
46
48
47extension CGFloat: Numeric {}
49extension CGFloat: Numeric {}
48
50
49extension CGRect {
51extension CGRect {
50 var x: CGFloat {
52 var x: CGFloat {
53+ get {
51− get { return origin.x }
54+ return origin.x
55+ }
56+ set {
52− set { origin.x = newValue }
57+ origin.x = newValue
58+ }
53 }
59 }
54
60
55 var y: CGFloat {
61 var y: CGFloat {
62+ get {
56− get { return origin.y }
63+ return origin.y
64+ }
65+ set {
57− set { origin.y = newValue }
66+ origin.y = newValue
67+ }
58 }
68 }
59}
69}
60
70
@@ -66,41 +76,65 @@ extension CGSize {
66
76
67extension UIView {
77extension UIView {
68 var origin: CGPoint {
78 var origin: CGPoint {
79+ get {
69− get { return frame.origin }
80+ return frame.origin
81+ }
82+ set {
70− set { frame.origin = newValue }
83+ frame.origin = newValue
84+ }
71 }
85 }
72
86
73 var size: CGSize {
87 var size: CGSize {
88+ get {
74− get { return frame.size }
89+ return frame.size
90+ }
91+ set {
75− set { frame.size = newValue }
92+ frame.size = newValue
93+ }
76 }
94 }
77
95
78 var width: CGFloat {
96 var width: CGFloat {
97+ get {
79− get { return frame.width }
98+ return frame.width
99+ }
100+ set {
80− set { frame.size = CGSize(width: newValue, height: height) }
101+ frame.size = CGSize(width: newValue, height: height)
102+ }
81 }
103 }
82
104
83 var height: CGFloat {
105 var height: CGFloat {
106+ get {
84− get { return frame.height }
107+ return frame.height
108+ }
109+ set {
85− set { frame.size = CGSize(width: width, height: newValue) }
110+ frame.size = CGSize(width: width, height: newValue)
111+ }
86 }
112 }
87
113
88 var middle: CGPoint {
114 var middle: CGPoint {
89 get {
115 get {
90− return CGPoint(x: origin.x + width/2, y: origin.y + height/2)
116+ return CGPoint(x: origin.x + width / 2, y: origin.y + height / 2)
91 }
117 }
92 set {
118 set {
93− origin = CGPoint(x: newValue.x - width/2, y: newValue.y - height/2)
119+ origin = CGPoint(x: newValue.x - width / 2, y: newValue.y - height / 2)
94 }
120 }
95 }
121 }
96
122
97 var midX: CGFloat {
123 var midX: CGFloat {
124+ get {
98− get { return middle.x }
125+ return middle.x
126+ }
127+ set {
99− set { middle = CGPoint(x: newValue, y: midY) }
128+ middle = CGPoint(x: newValue, y: midY)
129+ }
100 }
130 }
101
131
102 var midY: CGFloat {
132 var midY: CGFloat {
133+ get {
103− get { return middle.y }
134+ return middle.y
135+ }
136+ set {
104− set { middle = CGPoint(x: midX, y: newValue) }
137+ middle = CGPoint(x: midX, y: newValue)
138+ }
105 }
139 }
106}
140}
PixelImage/ViewController.swift+9−8
@@ -1,4 +1,3 @@
1−
2import UIKit
1import UIKit
3
2
4class ViewController: UIViewController, MetaballDataSource {
3class ViewController: UIViewController, MetaballDataSource {
@@ -33,7 +32,7 @@ class ViewController: UIViewController, MetaballDataSource {
33 metaballGraph.addEdge(2, 3)
32 metaballGraph.addEdge(2, 3)
34
33
35 let border = 20
34 let border = 20
36− let metaballViewFrame = CGRect(x: border/2, y: border/2, width: width, height: height)
35+ let metaballViewFrame = CGRect(x: border / 2, y: border / 2, width: width, height: height)
37 renderer = MetalMetaballRenderer(dataSource: self, frame: metaballViewFrame)
36 renderer = MetalMetaballRenderer(dataSource: self, frame: metaballViewFrame)
38 metaballView = renderer.targetView
37 metaballView = renderer.targetView
39
38
@@ -61,11 +60,12 @@ class ViewController: UIViewController, MetaballDataSource {
61
60
62 func animateEdge(i: Int, _ j: Int, fadeIn: Bool) {
61 func animateEdge(i: Int, _ j: Int, fadeIn: Bool) {
63 let parameters = EdgeAnimationParameters(startDate: NSDate(), duration: edgeAnimationDuration, fadeIn: fadeIn, i: i, j: j)
62 let parameters = EdgeAnimationParameters(startDate: NSDate(), duration: edgeAnimationDuration, fadeIn: fadeIn, i: i, j: j)
64− NSTimer.scheduledTimerWithTimeInterval(1.0/60.0, target: self, selector: "animateEdgeWithTimer:", userInfo: parameters, repeats: true)
63+ NSTimer.scheduledTimerWithTimeInterval(1.0 / 60.0, target: self, selector: "animateEdgeWithTimer:", userInfo: parameters, repeats: true)
65 }
64 }
66
65
67 func animateEdge(withTimer timer: NSTimer) {
66 func animateEdge(withTimer timer: NSTimer) {
67+ guard let userInfo = timer.userInfo as? EdgeAnimationParameters else { preconditionFailure() }
68− let (animationStart, duration, fadeIn, i, j) = (timer.userInfo as! EdgeAnimationParameters).unpack()
68+ let (animationStart, duration, fadeIn, i, j) = (userInfo).unpack()
69
69
70 let now = NSDate()
70 let now = NSDate()
71 var timeElapsed = Float(now.timeIntervalSinceDate(animationStart))
71 var timeElapsed = Float(now.timeIntervalSinceDate(animationStart))
@@ -89,9 +89,9 @@ class ViewController: UIViewController, MetaballDataSource {
89
89
90 if selectedMetaball == nil {
90 if selectedMetaball == nil {
91 for metaball in metaballs where
91 for metaball in metaballs where
92− abs(metaball.midX - location.x) < 50 && abs(metaball.midY - location.y) < 50 {
92+ abs(metaball.midX - location.x) < 50 && abs(metaball.midY - location.y) < 50 {
93− selectedMetaball = metaball
93+ selectedMetaball = metaball
94− break
94+ break
95 }
95 }
96 }
96 }
97
97
@@ -105,6 +105,7 @@ class ViewController: UIViewController, MetaballDataSource {
105 selectedMetaball = nil
105 selectedMetaball = nil
106 }
106 }
107 }
107 }
108+
108}
109}
109
110
110class Metaball: UIView {
111class Metaball: UIView {
@@ -114,7 +115,7 @@ class Metaball: UIView {
114
115
115 size = CGSize(50)
116 size = CGSize(50)
116 middle = position
117 middle = position
117− backgroundColor = UIColor(red: 0.1306, green: 0.7522, blue: 0.0307, alpha: 0.3)
118+ backgroundColor = UIColor(randomFlatColorOfShadeStyle: .Light)
118 }
119 }
119
120
120 required init?(coder aDecoder: NSCoder) {
121 required init?(coder aDecoder: NSCoder) {
PixelImage/shaders.metal+58−14
@@ -3,36 +3,61 @@
3
3
4using namespace metal;
4using namespace metal;
5
5
6+struct metaballData {
7+ float x;
8+ float y;
9+ float r;
10+ float g;
11+ float b;
12+};
13+
14+kernel void
6−kernel void drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]], constant float *edgesBuffer[[buffer(1)]], constant float *metaballBuffer[[buffer(0)]], uint2 gid[[thread_position_in_grid]]) {
15+ drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]],
7−
16+ constant float *edgesBuffer[[buffer(1)]],
17+ constant metaballData *metaballBuffer[[buffer(0)]],
18+ uint2 gid[[thread_position_in_grid]]) {
19+
8− char numberOfMetaballs = metaballBuffer[0];
20+ char numberOfMetaballs = metaballBuffer[0].x - 1;
9− char metaballArraySize = numberOfMetaballs * 2 + 1;
10
21
11 float sum = 0;
22 float sum = 0;
23+ float3 colorSum = float3(0, 0, 0);
24+ float colorAccumulation = 0;
25+ float3 colorSumLink = float3(0, 0, 0);
12
26
13 char x, y;
27 char x, y;
14
28
15 float metaballDistances[10];
29 float metaballDistances[10];
16 float2 metaballDirections[10];
30 float2 metaballDirections[10];
31+ float3 metaballColors[10];
17
32
18− for (y = 1, x = 0; y < metaballArraySize; y += 2, x += 1) {
33+ for (x = 1; x <= numberOfMetaballs; x += 1) {
19− float2 metaball = float2(metaballBuffer[y], metaballBuffer[y + 1]);
34+ metaballData metaball = metaballBuffer[x];
35+ float2 metaballPosition = float2(metaball.x, metaball.y);
20− float2 vector = float2(metaball.x - gid.x, metaball.y - gid.y);
36+ float2 vector
37+ = float2(metaballPosition.x - gid.x, metaballPosition.y - gid.y);
21 float squaredDistance = dot(vector, vector);
38 float squaredDistance = dot(vector, vector);
22 float realDistance = sqrt(squaredDistance);
39 float realDistance = sqrt(squaredDistance);
23− metaballDistances[x] = squaredDistance;
40+ metaballDistances[x - 1] = squaredDistance;
24− metaballDirections[x] = vector/realDistance;
41+ metaballDirections[x - 1] = vector / realDistance;
42+ metaballColors[x - 1] = float3(metaball.r, metaball.g, metaball.b);
25 }
43 }
26
44
27 float bendClose = 0.0;
45 float bendClose = 0.0;
28 float bendCloseCount = 0.0;
46 float bendCloseCount = 0.0;
47+ float ball = 0.0;
29
48
30 for (x = 0; x < numberOfMetaballs; x += 1) {
49 for (x = 0; x < numberOfMetaballs; x += 1) {
31− float value1 = 2048 / (metaballDistances[x] + 1);
50+ float distance1 = metaballDistances[x];
51+ float value1 = 2048 / (distance1 + 1);
32 float2 direction1 = metaballDirections[x];
52 float2 direction1 = metaballDirections[x];
33
53
54+ float colorContribution = 1 / distance1;
55+ colorAccumulation += colorContribution;
56+ colorSum += metaballColors[x] * colorContribution;
57+
34 for (y = x + 1; y < numberOfMetaballs; y += 1) {
58 for (y = x + 1; y < numberOfMetaballs; y += 1) {
35− float value2 = 2048 / (metaballDistances[y] + 1);
59+ float distance2 = metaballDistances[y];
60+ float value2 = 2048 / (distance2 + 1);
36 float2 direction2 = metaballDirections[y];
61 float2 direction2 = metaballDirections[y];
37
62
38 float v = value1 + value2;
63 float v = value1 + value2;
@@ -51,14 +76,25 @@ kernel void drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)
51 bendCloseCount += 1.0;
76 bendCloseCount += 1.0;
52 }
77 }
53
78
79+ ball += step(0.4, weightedValue);
80+
54− sum += step(0.5, weightedValue + weightedLink);
81+ float metaballValue = step(0.5, weightedValue + weightedLink);
82+
83+ if (metaballValue > 0.0) {
84+ colorSumLink = float3(0.0, 0.0, 0.0);
85+ colorSumLink += metaballColors[x] / distance1;
86+ colorSumLink += metaballColors[y] / distance2;
87+ colorSumLink /= (1 / distance1) + (1 / distance2);
88+ }
89+
90+ sum += metaballValue;
55 }
91 }
56 }
92 }
57
93
58 bendClose = bendClose / bendCloseCount;
94 bendClose = bendClose / bendCloseCount;
59
95
60 if (bendClose != 0.0) {
96 if (bendClose != 0.0) {
61− bendClose = (bendClose - 0.4) * (1/(0.6-0.4));
97+ bendClose = (bendClose - 0.4) * (1 / (0.6 - 0.4));
62 } else {
98 } else {
63 bendClose = 0.0;
99 bendClose = 0.0;
64 }
100 }
@@ -67,5 +103,13 @@ kernel void drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)
67 result += bendClose * 10;
103 result += bendClose * 10;
68 result = clamp(result, 0.0, 1.0);
104 result = clamp(result, 0.0, 1.0);
69
105
106+ colorSum = colorSum / colorAccumulation;
107+
108+ if (result > 0.0 && ball < 1.0) {
109+ colorSum = colorSumLink;
110+ }
111+
112+ colorSum *= result;
113+
70− outTexture.write(float4(result, result / 2, 0.0, 1), gid);
114+ outTexture.write(float4(colorSum.bgr, 1), gid);
71}
115}
Podfilenew file+6
@@ -0,0 +1,6 @@
1+platform :ios, '9.2'
2+use_frameworks!
3+
4+target 'PixelImage' do
5+ pod 'ChameleonFramework/Swift'
6+end
Podfile.locknew file+12
@@ -0,0 +1,12 @@
1+PODS:
2+ - ChameleonFramework/Default (2.1.0)
3+ - ChameleonFramework/Swift (2.1.0):
4+ - ChameleonFramework/Default
5+
6+DEPENDENCIES:
7+ - ChameleonFramework/Swift
8+
9+SPEC CHECKSUMS:
10+ ChameleonFramework: d21a3cc247abfe5e37609a283a8238b03575cf64
11+
12+COCOAPODS: 0.39.0