125 lines
3.3 KiB
Swift
125 lines
3.3 KiB
Swift
//
|
|
// MetaballsSaverView.swift
|
|
// Metaballs
|
|
//
|
|
// Created by Eryn Wells on 8/16/17.
|
|
// Copyright © 2017 Eryn Wells. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import MetaballsKit
|
|
import MetalKit
|
|
import ScreenSaver
|
|
|
|
public class MetaballsSaverView: ScreenSaverView, RendererDelegate {
|
|
private static func defaultParameters() -> Parameters {
|
|
var p = Parameters()
|
|
let defaults = UserDefaults.standard
|
|
let style = defaults.colorStyle ?? .gradient2Horizontal
|
|
p.colorStyle = style
|
|
let color0 = defaults.color0 ?? Float4(0.50, 0.79, 1, 1)
|
|
p.color0 = color0
|
|
let color1 = defaults.color1 ?? Float4(0.88, 0.50, 1, 1)
|
|
p.color1 = color1
|
|
return p
|
|
}
|
|
|
|
public var metalView: MTKView
|
|
|
|
public var field: Field {
|
|
didSet {
|
|
field.size = Size(size: metalView.drawableSize)
|
|
}
|
|
}
|
|
|
|
internal var renderer: Renderer
|
|
|
|
override public init?(frame: NSRect, isPreview: Bool) {
|
|
let params = MetaballsSaverView.defaultParameters()
|
|
metalView = MetalView()
|
|
field = Field(parameters: params)
|
|
field.size = Size(size: frame.size)
|
|
renderer = Renderer()
|
|
|
|
super.init(frame: frame, isPreview: isPreview)
|
|
|
|
animationTimeInterval = 1 / 30.0
|
|
}
|
|
|
|
required public init?(coder: NSCoder) {
|
|
fatalError("initWithCoder: not implemented")
|
|
}
|
|
|
|
override public func startAnimation() {
|
|
if metalView.superview == nil {
|
|
metalView.isPaused = true // Don't use the Metal View's internal timer.
|
|
metalView.translatesAutoresizingMaskIntoConstraints = false
|
|
addSubview(metalView)
|
|
NSLayoutConstraint.activate([
|
|
metalView.topAnchor.constraint(equalTo: topAnchor),
|
|
metalView.leftAnchor.constraint(equalTo: leftAnchor),
|
|
metalView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
metalView.rightAnchor.constraint(equalTo: rightAnchor),
|
|
])
|
|
renderer.delegate = self
|
|
}
|
|
|
|
for _ in 1...10 {
|
|
addBallWithRandomRadius()
|
|
}
|
|
|
|
super.startAnimation()
|
|
}
|
|
|
|
override public func stopAnimation() {
|
|
super.stopAnimation()
|
|
}
|
|
|
|
override public func animateOneFrame() {
|
|
metalView.draw()
|
|
}
|
|
|
|
override public func hasConfigureSheet() -> Bool {
|
|
return true
|
|
}
|
|
|
|
override public func configureSheet() -> NSWindow? {
|
|
let prefs = PreferencesViewController()
|
|
prefs.showsCloseButton = true
|
|
let window = NSWindow(contentViewController: prefs)
|
|
return window
|
|
}
|
|
|
|
// MARK: - NSView
|
|
|
|
override public func setFrameSize(_ newSize: NSSize) {
|
|
super.setFrameSize(newSize)
|
|
NSLog("Resizing: \(newSize)")
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func addBallWithRandomRadius() {
|
|
let base = UInt32(bounds.width * 0.05)
|
|
let variance = UInt32(base * 2)
|
|
let r = Float(base + arc4random_uniform(variance))
|
|
field.add(ballWithRadius: r)
|
|
}
|
|
|
|
// MARK: - RendererDelegate
|
|
|
|
public var renderSize: Size {
|
|
get {
|
|
return field.size
|
|
}
|
|
set {
|
|
field.size = newValue
|
|
}
|
|
}
|
|
}
|
|
|
|
class MetalView: MTKView {
|
|
override var isOpaque: Bool {
|
|
return true
|
|
}
|
|
}
|