From 1b8fc1feb7cd2eda1c00859e42709847d7ff9ba4 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Tue, 9 Oct 2018 16:51:35 -0700 Subject: [PATCH] Allow a slider to set the colorRotation in radians --- MetaballsKit/Math.swift | 16 +++++++--- MetaballsKit/Metaballs.swift | 15 ++++++++- MetaballsKit/Preferences.swift | 15 +++++++++ MetaballsKit/PreferencesViewController.swift | 32 ++++++++++++++++++++ MetaballsKit/Shaders.metal | 2 +- 5 files changed, 74 insertions(+), 6 deletions(-) diff --git a/MetaballsKit/Math.swift b/MetaballsKit/Math.swift index 0386bea..57a3640 100644 --- a/MetaballsKit/Math.swift +++ b/MetaballsKit/Math.swift @@ -43,13 +43,21 @@ extension Float4 { } } -extension Matrix2x2 { - static func rotation(theta: Float) -> Matrix2x2 { +extension Matrix3x3 { + static func rotation(angle theta: Float) -> Matrix3x3 { return self.init(rows: [ - Float2(cos(theta), -sin(theta)), - Float2(sin(theta), cos(theta)), + Float3(cos(theta), -sin(theta), 0.0), + Float3(sin(theta), cos(theta), 0.0), + Float3(0, 0, 1), ]) } + + static func translation(dx: Float, dy: Float) -> Matrix3x3 { + var mat = self.init(1.0) + mat.columns.2.x = dx + mat.columns.2.y = dy + return mat + } } extension Matrix4x4 { diff --git a/MetaballsKit/Metaballs.swift b/MetaballsKit/Metaballs.swift index a46e2a2..cceb5f1 100644 --- a/MetaballsKit/Metaballs.swift +++ b/MetaballsKit/Metaballs.swift @@ -49,7 +49,7 @@ public struct Parameters { public var color2 = Float4() public var color3 = Float4() - public var colorRotation = Matrix2x2(1.0) + public var colorTransform = Matrix3x3(1.0) public var colorStyle: ColorStyle { get { @@ -303,6 +303,19 @@ public class Field { didChange = true } + if let rotation = userInfo["colorRotation"] as? Float { + // Create a transform matrix to handle it + let dx = Float(size.x) / 2.0 + let dy = Float(size.y) / 2.0 + let translate = Matrix3x3.translation(dx: dx, dy: dy) + let rotate = Matrix3x3.rotation(angle: rotation) + let invTranslate = Matrix3x3.translation(dx: -dx, dy: -dy) + parameters.colorTransform = invTranslate * rotate * translate + // Save the value to defaults + defaults.colorRotation = rotation + didChange = true + } + if didChange { populateParametersBuffer() } diff --git a/MetaballsKit/Preferences.swift b/MetaballsKit/Preferences.swift index 2caab41..3577e58 100644 --- a/MetaballsKit/Preferences.swift +++ b/MetaballsKit/Preferences.swift @@ -92,6 +92,21 @@ extension UserDefaults { } } + public var colorRotation: Float { + get { + if let obj = object(forKey: "colorRotation") as? NSNumber { + return obj.floatValue + } else { + let defaultValue: Float = 0.0 + set(defaultValue, forKey: "colorRotation") + return defaultValue + } + } + set { + set(newValue, forKey: "colorRotation") + } + } + func float4(forKey key: String) -> Float4? { guard let values = array(forKey: key) as? [Float], values.count >= 4 else { return nil diff --git a/MetaballsKit/PreferencesViewController.swift b/MetaballsKit/PreferencesViewController.swift index fbde6de..d91a5f6 100644 --- a/MetaballsKit/PreferencesViewController.swift +++ b/MetaballsKit/PreferencesViewController.swift @@ -14,6 +14,10 @@ private struct StyleItem { let name: String let tag: Int let colorNames: [String] + + var allowsRotation: Bool { + return colorNames.count > 1 + } } public class PreferencesViewController: NSViewController { @@ -43,6 +47,14 @@ public class PreferencesViewController: NSViewController { private var colorStackView = NSStackView() private var colorViews = [ColorView]() + private lazy var colorRotationSlider: RotationSliderView = { + let rotationSlider = RotationSliderView(label: NSLocalizedString("Color θ", comment: "name of color rotation slider")) + rotationSlider.slider.target = self + rotationSlider.slider.action = #selector(PreferencesViewController.sliderDidUpdate(sender:)) + rotationSlider.slider.floatValue = self.defaults.colorRotation + return rotationSlider + }() + private lazy var targetSlider: SliderView = { let targetSlider = SliderView(label: NSLocalizedString("Target", comment: "name of the target slider")) if #available(OSX 10.12.2, *) { @@ -135,6 +147,7 @@ public class PreferencesViewController: NSViewController { colorStackView.addArrangedSubview(colorView) colorViews.append(colorView) } + colorStackView.addArrangedSubview(colorRotationSlider) colorStackView.addArrangedSubview(targetSlider) colorStackView.addArrangedSubview(featherSlider) @@ -217,6 +230,9 @@ public class PreferencesViewController: NSViewController { colorView.isHidden = true } } + + // Hide the color rotation slider if there's only one color + colorRotationSlider.isHidden = styleItem.colorNames.count == 1 } func postColorNotification() { @@ -229,6 +245,7 @@ public class PreferencesViewController: NSViewController { } info["target"] = targetSlider.slider.floatValue info["feather"] = featherSlider.slider.floatValue + info["colorRotation"] = colorRotationSlider.slider.floatValue NotificationCenter.default.post(name: PreferencesDidChange_Color, object: nil, userInfo: info) } } @@ -304,3 +321,18 @@ class SliderView: ParameterView { fatalError("init(coder:) has not been implemented") } } + +class RotationSliderView: SliderView { + override init(label: String) { + super.init(label: label) + + let slider = control as! NSSlider + slider.minValue = -Double.pi + slider.maxValue = Double.pi + slider.numberOfTickMarks = 5 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/MetaballsKit/Shaders.metal b/MetaballsKit/Shaders.metal index 28b5c47..ad1038a 100644 --- a/MetaballsKit/Shaders.metal +++ b/MetaballsKit/Shaders.metal @@ -44,7 +44,7 @@ typedef struct { float target; float feather; float4 colors[4]; - float2x2 colorRotation; + float3x3 colorTransform; } Parameters; typedef float3 Ball;