mirror of
https://github.com/ilyakooo0/metal-metaballs.git
synced 2024-09-11 10:35:56 +03:00
Code style refactor.
This commit is contained in:
parent
f3707d992f
commit
6b476b7ecb
@ -249,6 +249,7 @@
|
||||
242686821C63B72A00D62456 /* Resources */,
|
||||
C7A2DF67265A9D17DEFBD193 /* Embed Pods Frameworks */,
|
||||
FADC01F75BFAC01F0260D1C9 /* Copy Pods Resources */,
|
||||
DD0396CE594E3EAC8D18CC6C /* Tailor */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -322,6 +323,20 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DD0396CE594E3EAC8D18CC6C /* Tailor */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = Tailor;
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
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";
|
||||
};
|
||||
EF55C7246917A184756D93D8 /* Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
Binary file not shown.
@ -13,7 +13,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
@ -40,7 +39,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
func applicationWillTerminate(application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
func interpolateCubeEaseIn<T: Numeric>(linear: T) -> T {
|
||||
return linear ^ 3
|
||||
}
|
||||
@ -14,4 +13,3 @@ func interpolateSquareEaseOut<T: Numeric>(linear: T) -> T {
|
||||
func interpolateSmooth<T: Numeric>(linear: T) -> T {
|
||||
return ((linear) * (linear) * (linear) * ((linear) * ((linear) * 6 - 15) + 10))
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class Graph<T> {
|
||||
@ -27,6 +26,7 @@ class Graph<T> {
|
||||
adjacencyMatrix.reset(i, j)
|
||||
adjacencyMatrix.reset(j, i)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct Matrix: CustomStringConvertible {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import Metal
|
||||
|
||||
protocol MetaballDataSource {
|
||||
@ -11,4 +10,5 @@ extension MetaballDataSource {
|
||||
return metaballGraph.vertices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -40,4 +40,4 @@ class MTLComputeContext {
|
||||
deinit {
|
||||
free(imageBuffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,8 +39,7 @@ class MetalMetaballRenderer {
|
||||
|
||||
let width = Int(frame.width)
|
||||
let height = Int(frame.height)
|
||||
let textureDescriptor =
|
||||
MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
|
||||
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
|
||||
|
||||
let texture1 = context.device.newTextureWithDescriptor(textureDescriptor)
|
||||
activeComputeContext = MTLComputeContext(size: targetView.size, texture: texture1)
|
||||
@ -55,7 +54,8 @@ class MetalMetaballRenderer {
|
||||
|
||||
state = .Ending
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)) { () -> Void in
|
||||
let userInteractiveQueue = dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)
|
||||
dispatch_async(userInteractiveQueue) { () -> Void in
|
||||
|
||||
let computeContext = self.activeComputeContext
|
||||
swap(&self.activeComputeContext, &self.idleComputeContext)
|
||||
@ -74,10 +74,10 @@ class MetalMetaballRenderer {
|
||||
|
||||
dispatch_semaphore_signal(self.semaphore)
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), { () -> Void in
|
||||
dispatch_async(dispatch_get_main_queue()) { () -> Void in
|
||||
// Send image to view
|
||||
self.targetView.image = uiimage
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,8 +94,7 @@ class MetalMetaballRenderer {
|
||||
|
||||
// Configure info for computing
|
||||
let threadGroupCounts = MTLSizeMake(8, 8, 1)
|
||||
let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
|
||||
height / threadGroupCounts.height, 1)
|
||||
let threadGroups = MTLSizeMake(width / threadGroupCounts.width, height / threadGroupCounts.height, 1)
|
||||
|
||||
// Send commands to metal and render
|
||||
let commandBuffer = context.commandQueue.commandBuffer()
|
||||
@ -113,7 +112,6 @@ class MetalMetaballRenderer {
|
||||
|
||||
commandBuffer.commit()
|
||||
commandBuffer.waitUntilCompleted()
|
||||
|
||||
} catch _ {
|
||||
print("Error!")
|
||||
}
|
||||
@ -123,8 +121,7 @@ class MetalMetaballRenderer {
|
||||
let texture = computeContext.texture
|
||||
|
||||
// Get image info
|
||||
let imageSize = CGSizeMake(CGFloat(texture.width),
|
||||
CGFloat(texture.height))
|
||||
let imageSize = CGSizeMake(CGFloat(texture.width), CGFloat(texture.height))
|
||||
let width = Int(imageSize.width)
|
||||
let height = Int(imageSize.height)
|
||||
let imageByteCount = width * height * 4
|
||||
@ -137,27 +134,20 @@ class MetalMetaballRenderer {
|
||||
}
|
||||
|
||||
// Transfer texture info into image buffer
|
||||
texture.getBytes(computeContext.imageBuffer, bytesPerRow: bytesPerRow,
|
||||
fromRegion: region, mipmapLevel: 0)
|
||||
texture.getBytes(computeContext.imageBuffer, bytesPerRow: bytesPerRow, fromRegion: region, mipmapLevel: 0)
|
||||
|
||||
// Get info for UIImage
|
||||
let provider = CGDataProviderCreateWithData(nil, computeContext.imageBuffer,
|
||||
imageByteCount, nil)
|
||||
let provider = CGDataProviderCreateWithData(nil, computeContext.imageBuffer, imageByteCount, nil)
|
||||
let bitsPerComponent = 8
|
||||
let bitsperPixel = 32
|
||||
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGBitmapInfo(rawValue:
|
||||
CGImageAlphaInfo.PremultipliedLast.rawValue |
|
||||
CGBitmapInfo.ByteOrder32Big.rawValue)
|
||||
let bitmapInfoRaw = CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Big.rawValue
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: bitmapInfoRaw)
|
||||
let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
|
||||
|
||||
// Create UIImage from image buffer
|
||||
let imageRef = CGImageCreate(width, height,
|
||||
bitsPerComponent, bitsperPixel, bytesPerRow,
|
||||
colorSpaceRef, bitmapInfo, provider,
|
||||
nil, false, renderingIntent)
|
||||
let image = UIImage(CGImage: imageRef!, scale: 0.0,
|
||||
orientation: UIImageOrientation.Up)
|
||||
let imageRef = CGImageCreate(width, height, bitsPerComponent, bitsperPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, nil, false, renderingIntent)
|
||||
let image = UIImage(CGImage: imageRef!, scale: 0.0, orientation: .Up)
|
||||
|
||||
return image
|
||||
}
|
||||
@ -165,7 +155,9 @@ class MetalMetaballRenderer {
|
||||
func metaballEdgesBuffer() -> MTLBuffer {
|
||||
let floats = dataSource.metaballGraph.adjacencyMatrix.buffer
|
||||
|
||||
let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
|
||||
let bufferLength = floats.count * sizeof(Float)
|
||||
let device = context.device
|
||||
let buffer = device.newBufferWithBytes(floats, length: bufferLength, options: .StorageModeShared)
|
||||
|
||||
return buffer
|
||||
}
|
||||
@ -175,7 +167,11 @@ class MetalMetaballRenderer {
|
||||
// Exclude metaballs far from the view's bounds
|
||||
let border: CGFloat = 100
|
||||
let metaballs = self.dataSource.metaballs
|
||||
var floats: [Float] = metaballs.reduce([Float](count: 5, repeatedValue: 0)) { (var array, metaball) -> [Float] in
|
||||
|
||||
var floats = [Float](count: 5, repeatedValue: 0)
|
||||
floats = metaballs.reduce(floats) {
|
||||
(var array, metaball) -> [Float] in
|
||||
|
||||
let x = CGFloat(metaball.midX)
|
||||
let y = CGFloat(metaball.midY)
|
||||
if -border < x ≤ targetView.width + border &&
|
||||
@ -196,8 +192,10 @@ class MetalMetaballRenderer {
|
||||
floats[0] = Float(floats.count) / 5
|
||||
|
||||
// Create buffer
|
||||
let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
|
||||
|
||||
let bufferLength = floats.count * sizeof(Float)
|
||||
let device = context.device
|
||||
let buffer = device.newBufferWithBytes(floats, length: bufferLength, options: .StorageModeShared)
|
||||
|
||||
return buffer
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
extension Dictionary {
|
||||
subscript(keys: [Key]) -> [Value] {
|
||||
get {
|
||||
return keys.unwrappedMap({ self[$0] })
|
||||
return keys.unwrappedMap { self[$0] }
|
||||
}
|
||||
set (values) {
|
||||
for (key, value) in zip(keys, values) {
|
||||
|
@ -2,10 +2,13 @@ import Foundation
|
||||
|
||||
extension NSNumber: DoubleValuable {
|
||||
var toDouble: Double {
|
||||
get { return self.doubleValue }
|
||||
get {
|
||||
return self.doubleValue
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Self {
|
||||
return self.init(double: double)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,43 +20,54 @@ protocol Numeric: DoubleValuable, Incrementable, Comparable,
|
||||
postfix func ++ (inout _: Self) -> Self
|
||||
}
|
||||
|
||||
protocol FastNumeric: Numeric { }
|
||||
protocol FastNumeric: Numeric {}
|
||||
|
||||
extension Double: FastNumeric {
|
||||
var toDouble: Double {
|
||||
get { return self }
|
||||
get {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Double {
|
||||
return double
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Float: FastNumeric {
|
||||
var toDouble: Double {
|
||||
get { return Double(self) }
|
||||
get {
|
||||
return Double(self)
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Float {
|
||||
return Float(double)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Int: FastNumeric {
|
||||
var toDouble: Double {
|
||||
get { return Double(self) }
|
||||
get {
|
||||
return Double(self)
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Int {
|
||||
return Int(double)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
extension Int {
|
||||
|
||||
func times(@noescape block: () throws -> ()) rethrows {
|
||||
for _ in 1...self {
|
||||
try block()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import Darwin
|
||||
|
||||
infix operator ^ { associativity right precedence 131 }
|
||||
|
||||
func ^<T: DoubleValuable>(left: T, right: T) -> T {
|
||||
func ^ <T: DoubleValuable>(left: T, right: T) -> T {
|
||||
return T.fromDouble(pow(left.toDouble, right.toDouble))
|
||||
}
|
||||
|
||||
|
@ -7,62 +7,66 @@ protocol MemoizedSequence: LazySequenceType {
|
||||
memoizedFunction: (IndexType -> ReturnType))
|
||||
}
|
||||
|
||||
struct HashMemoizedSequence<IndexType: Hashable, ReturnType>:
|
||||
MemoizedSequence {
|
||||
|
||||
struct HashMemoizedSequence <IndexType: Hashable, ReturnType>:
|
||||
MemoizedSequence {
|
||||
let memoizedFunction: (IndexType -> ReturnType)
|
||||
let increment: ((inout IndexType) -> Void)
|
||||
let firstIndex: IndexType
|
||||
|
||||
let memoizedFunction: (IndexType -> ReturnType)
|
||||
let increment: ((inout IndexType) -> Void)
|
||||
let firstIndex: IndexType
|
||||
var index: IndexType
|
||||
|
||||
var index: IndexType
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
memoizedFunction: (IndexType -> ReturnType)) {
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
memoizedFunction: (IndexType -> ReturnType)) {
|
||||
self.firstIndex = first
|
||||
|
||||
self.firstIndex = first
|
||||
self.index = first
|
||||
self.increment = incrementer
|
||||
self.memoizedFunction = memoizedFunction
|
||||
}
|
||||
|
||||
self.index = first
|
||||
self.increment = incrementer
|
||||
self.memoizedFunction = memoizedFunction
|
||||
}
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
|
||||
let memoizedFunction = memoize(closure)
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
|
||||
let memoizedFunction = memoize(closure)
|
||||
self.init(first: first, incrementer: incrementer,
|
||||
memoizedFunction: memoizedFunction)
|
||||
}
|
||||
|
||||
self.init(first: first, incrementer: incrementer,
|
||||
memoizedFunction: memoizedFunction)
|
||||
}
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
function: (IndexType -> ReturnType)) {
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
function: (IndexType -> ReturnType)) {
|
||||
let memoizedFunction = memoize(function)
|
||||
|
||||
let memoizedFunction = memoize(function)
|
||||
|
||||
self.init(first: first, incrementer: incrementer,
|
||||
memoizedFunction: memoizedFunction)
|
||||
}
|
||||
self.init(first: first, incrementer: incrementer,
|
||||
memoizedFunction: memoizedFunction)
|
||||
}
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence: GeneratorType {
|
||||
|
||||
mutating func next() -> ReturnType? {
|
||||
let result = memoizedFunction(index)
|
||||
increment(&index)
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence: LazySequenceType {
|
||||
|
||||
func generate() -> HashMemoizedSequence {
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence where ReturnType: Comparable {
|
||||
|
||||
@warn_unused_result
|
||||
func contains(element: ReturnType) -> Bool {
|
||||
var index = firstIndex
|
||||
@ -79,6 +83,7 @@ extension HashMemoizedSequence where ReturnType: Comparable {
|
||||
increment(&index)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence where IndexType: Incrementable {
|
||||
@ -104,29 +109,29 @@ extension HashMemoizedSequence where IndexType: Incrementable {
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence where IndexType: Incrementable,
|
||||
IndexType: IntegerLiteralConvertible {
|
||||
IndexType: IntegerLiteralConvertible {
|
||||
init(_ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
|
||||
self.firstIndex = 1
|
||||
self.index = 1
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(closure)
|
||||
self.firstIndex = 1
|
||||
self.index = 1
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(closure)
|
||||
}
|
||||
|
||||
init(_ function: (IndexType -> ReturnType)) {
|
||||
self.firstIndex = 1
|
||||
self.index = 1
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(function)
|
||||
self.firstIndex = 1
|
||||
self.index = 1
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(function)
|
||||
}
|
||||
}
|
||||
|
||||
func memoize <H: Hashable, R> (closure: ((H -> R, H) -> R) ) -> (H -> R) {
|
||||
func memoize<H: Hashable, R>(closure: ((H -> R, H) -> R)) -> (H -> R) {
|
||||
|
||||
var table = [H : R]()
|
||||
var table = [H: R]()
|
||||
|
||||
var auxiliaryFunction: (H -> R)!
|
||||
auxiliaryFunction = { index in
|
||||
@ -143,9 +148,9 @@ func memoize <H: Hashable, R> (closure: ((H -> R, H) -> R) ) -> (H -> R) {
|
||||
return auxiliaryFunction
|
||||
}
|
||||
|
||||
func memoize <H: Hashable, R> (function: (H -> R) ) -> (H -> R) {
|
||||
func memoize<H: Hashable, R>(function: (H -> R)) -> (H -> R) {
|
||||
|
||||
var table = [H : R]()
|
||||
var table = [H: R]()
|
||||
|
||||
let result: (H -> R) = { index in
|
||||
if let result = table[index] {
|
||||
|
@ -1,13 +1,12 @@
|
||||
|
||||
prefix operator ± { }
|
||||
|
||||
prefix func ± <T: Numeric> (number: T) -> T {
|
||||
prefix func ± <T: Numeric>(number: T) -> T {
|
||||
|
||||
if number > 0 {
|
||||
return 1
|
||||
} else if number == 0 {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
if number > 0 {
|
||||
return 1
|
||||
} else if number == 0 {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
extension String: DoubleValuable {
|
||||
var toDouble: Double {
|
||||
get { return Double(self) ?? Double(0) }
|
||||
get {
|
||||
return Double(self) ?? Double(0)
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> String {
|
||||
return "\(double)"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import Darwin
|
||||
|
||||
class Random <T: Numeric> {
|
||||
class Random<T: Numeric> {
|
||||
|
||||
let max: Double = Double(INT32_MAX)
|
||||
let exponent: Double = 7
|
||||
@ -92,4 +92,5 @@ class Random <T: Numeric> {
|
||||
let result = Double((2 * rawRandom) - 1)
|
||||
return T.fromDouble(result)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ extension CGVector {
|
||||
dx = dx / norm
|
||||
dy = dy / norm
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CGFloat: DoubleValuable {
|
||||
@ -42,19 +43,28 @@ extension CGFloat: DoubleValuable {
|
||||
static func fromDouble(double: Double) -> CGFloat {
|
||||
return CGFloat(double)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CGFloat: Numeric {}
|
||||
|
||||
extension CGRect {
|
||||
var x: CGFloat {
|
||||
get { return origin.x }
|
||||
set { origin.x = newValue }
|
||||
get {
|
||||
return origin.x
|
||||
}
|
||||
set {
|
||||
origin.x = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var y: CGFloat {
|
||||
get { return origin.y }
|
||||
set { origin.y = newValue }
|
||||
get {
|
||||
return origin.y
|
||||
}
|
||||
set {
|
||||
origin.y = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,41 +76,65 @@ extension CGSize {
|
||||
|
||||
extension UIView {
|
||||
var origin: CGPoint {
|
||||
get { return frame.origin }
|
||||
set { frame.origin = newValue }
|
||||
get {
|
||||
return frame.origin
|
||||
}
|
||||
set {
|
||||
frame.origin = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var size: CGSize {
|
||||
get { return frame.size }
|
||||
set { frame.size = newValue }
|
||||
get {
|
||||
return frame.size
|
||||
}
|
||||
set {
|
||||
frame.size = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var width: CGFloat {
|
||||
get { return frame.width }
|
||||
set { frame.size = CGSize(width: newValue, height: height) }
|
||||
get {
|
||||
return frame.width
|
||||
}
|
||||
set {
|
||||
frame.size = CGSize(width: newValue, height: height)
|
||||
}
|
||||
}
|
||||
|
||||
var height: CGFloat {
|
||||
get { return frame.height }
|
||||
set { frame.size = CGSize(width: width, height: newValue) }
|
||||
get {
|
||||
return frame.height
|
||||
}
|
||||
set {
|
||||
frame.size = CGSize(width: width, height: newValue)
|
||||
}
|
||||
}
|
||||
|
||||
var middle: CGPoint {
|
||||
get {
|
||||
return CGPoint(x: origin.x + width/2, y: origin.y + height/2)
|
||||
return CGPoint(x: origin.x + width / 2, y: origin.y + height / 2)
|
||||
}
|
||||
set {
|
||||
origin = CGPoint(x: newValue.x - width/2, y: newValue.y - height/2)
|
||||
origin = CGPoint(x: newValue.x - width / 2, y: newValue.y - height / 2)
|
||||
}
|
||||
}
|
||||
|
||||
var midX: CGFloat {
|
||||
get { return middle.x }
|
||||
set { middle = CGPoint(x: newValue, y: midY) }
|
||||
get {
|
||||
return middle.x
|
||||
}
|
||||
set {
|
||||
middle = CGPoint(x: newValue, y: midY)
|
||||
}
|
||||
}
|
||||
|
||||
var midY: CGFloat {
|
||||
get { return middle.y }
|
||||
set { middle = CGPoint(x: midX, y: newValue) }
|
||||
get {
|
||||
return middle.y
|
||||
}
|
||||
set {
|
||||
middle = CGPoint(x: midX, y: newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class ViewController: UIViewController, MetaballDataSource {
|
||||
@ -33,7 +32,7 @@ class ViewController: UIViewController, MetaballDataSource {
|
||||
metaballGraph.addEdge(2, 3)
|
||||
|
||||
let border = 20
|
||||
let metaballViewFrame = CGRect(x: border/2, y: border/2, width: width, height: height)
|
||||
let metaballViewFrame = CGRect(x: border / 2, y: border / 2, width: width, height: height)
|
||||
renderer = MetalMetaballRenderer(dataSource: self, frame: metaballViewFrame)
|
||||
metaballView = renderer.targetView
|
||||
|
||||
@ -61,11 +60,12 @@ class ViewController: UIViewController, MetaballDataSource {
|
||||
|
||||
func animateEdge(i: Int, _ j: Int, fadeIn: Bool) {
|
||||
let parameters = EdgeAnimationParameters(startDate: NSDate(), duration: edgeAnimationDuration, fadeIn: fadeIn, i: i, j: j)
|
||||
NSTimer.scheduledTimerWithTimeInterval(1.0/60.0, target: self, selector: "animateEdgeWithTimer:", userInfo: parameters, repeats: true)
|
||||
NSTimer.scheduledTimerWithTimeInterval(1.0 / 60.0, target: self, selector: "animateEdgeWithTimer:", userInfo: parameters, repeats: true)
|
||||
}
|
||||
|
||||
func animateEdge(withTimer timer: NSTimer) {
|
||||
let (animationStart, duration, fadeIn, i, j) = (timer.userInfo as! EdgeAnimationParameters).unpack()
|
||||
guard let userInfo = timer.userInfo as? EdgeAnimationParameters else { preconditionFailure() }
|
||||
let (animationStart, duration, fadeIn, i, j) = (userInfo).unpack()
|
||||
|
||||
let now = NSDate()
|
||||
var timeElapsed = Float(now.timeIntervalSinceDate(animationStart))
|
||||
@ -89,9 +89,9 @@ class ViewController: UIViewController, MetaballDataSource {
|
||||
|
||||
if selectedMetaball == nil {
|
||||
for metaball in metaballs where
|
||||
abs(metaball.midX - location.x) < 50 && abs(metaball.midY - location.y) < 50 {
|
||||
selectedMetaball = metaball
|
||||
break
|
||||
abs(metaball.midX - location.x) < 50 && abs(metaball.midY - location.y) < 50 {
|
||||
selectedMetaball = metaball
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,6 +105,7 @@ class ViewController: UIViewController, MetaballDataSource {
|
||||
selectedMetaball = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Metaball: UIView {
|
||||
|
@ -11,7 +11,11 @@ struct metaballData {
|
||||
float b;
|
||||
};
|
||||
|
||||
kernel void drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]], constant float *edgesBuffer[[buffer(1)]], constant metaballData *metaballBuffer[[buffer(0)]], uint2 gid[[thread_position_in_grid]]) {
|
||||
kernel void
|
||||
drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]],
|
||||
constant float *edgesBuffer[[buffer(1)]],
|
||||
constant metaballData *metaballBuffer[[buffer(0)]],
|
||||
uint2 gid[[thread_position_in_grid]]) {
|
||||
|
||||
char numberOfMetaballs = metaballBuffer[0].x - 1;
|
||||
|
||||
@ -28,11 +32,12 @@ kernel void drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)
|
||||
for (x = 1; x <= numberOfMetaballs; x += 1) {
|
||||
metaballData metaball = metaballBuffer[x];
|
||||
float2 metaballPosition = float2(metaball.x, metaball.y);
|
||||
float2 vector = float2(metaballPosition.x - gid.x, metaballPosition.y - gid.y);
|
||||
float2 vector
|
||||
= float2(metaballPosition.x - gid.x, metaballPosition.y - gid.y);
|
||||
float squaredDistance = dot(vector, vector);
|
||||
float realDistance = sqrt(squaredDistance);
|
||||
metaballDistances[x - 1] = squaredDistance;
|
||||
metaballDirections[x - 1] = vector/realDistance;
|
||||
metaballDirections[x - 1] = vector / realDistance;
|
||||
metaballColors[x - 1] = float3(metaball.r, metaball.g, metaball.b);
|
||||
}
|
||||
|
||||
@ -71,14 +76,13 @@ kernel void drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)
|
||||
|
||||
float metaballValue = step(0.5, weightedValue + weightedLink);
|
||||
sum += metaballValue;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bendClose = bendClose / bendCloseCount;
|
||||
|
||||
if (bendClose != 0.0) {
|
||||
bendClose = (bendClose - 0.4) * (1/(0.6-0.4));
|
||||
bendClose = (bendClose - 0.4) * (1 / (0.6 - 0.4));
|
||||
} else {
|
||||
bendClose = 0.0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user