metaballs/MetaballsSaver/MetaballsSaverView.swift

130 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 MetalKit
import ScreenSaver
@objc public class MetaballsSaverView: ScreenSaverView, RendererDelegate {
private static func defaultParameters() -> Parameters {
var p = Parameters()
let defaults = UserDefaults.standard
let style = defaults.colorStyle ?? .gradient2
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()
field = Field(parameters: params)
field.size = Size(size: frame.size)
metalView = MetalView()
metalView.isPaused = true // Don't use the Metal View's internal timer.
metalView.translatesAutoresizingMaskIntoConstraints = false
renderer = Renderer()
metalView.delegate = renderer
super.init(frame: frame, isPreview: isPreview)
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
animationTimeInterval = 1 / 30.0
metalView.preferredFramesPerSecond = 30
}
required public init?(coder: NSCoder) {
fatalError("initWithCoder: not implemented")
}
override public func startAnimation() {
for _ in 1...10 {
addBallWithRandomRadius()
}
super.startAnimation()
}
override public func stopAnimation() {
super.stopAnimation()
}
override public func animateOneFrame() {
metalView.draw()
}
override public func draw(_ rect: NSRect) {
metalView.draw()
}
override public var hasConfigureSheet: Bool {
return true
}
override public var 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
}
}