// The animated picture, independent of Plasma so it can be rendered
// and tested on its own (tools/moire-preview.qml does).
//
// Motion is a handful of slow sines at unrelated periods, so it never
// visibly repeats. It is advanced here in JavaScript, in double
// precision, and handed to the shader as positions and a wrapped
// phase: the shader holds no clock that could lose precision.
import QtQuick 2.15
Item {
id: field
// "moire", "halftone", "both", or "alternate" (fading between the
// two every few minutes).
property string pattern: "both"
// Multiplies how fast everything drifts; 0 holds the picture still.
property real speed: 1
property int frameRate: 30
property color base: "#661e1e"
property color deep: "#470005"
property color ink: "#fdf2c6"
property color tone: "#b6797a"
// Theme changes arrive once a minute at most; ease into them.
Behavior on base { ColorAnimation { duration: 4000 } }
Behavior on deep { ColorAnimation { duration: 4000 } }
Behavior on ink { ColorAnimation { duration: 4000 } }
Behavior on tone { ColorAnimation { duration: 4000 } }
// Seconds of motion so far, scaled by speed. A fresh start picks a
// random point in the motion so two screens don't mirror each other.
property real clock: Math.random() * 10000
readonly property real aspect: height > 0 ? width / height : 16 / 9
function sweep(period, phase) {
return Math.sin(2 * Math.PI * (clock / period + phase))
}
ShaderEffect {
anchors.fill: parent
fragmentShader: "field.frag.qsb"
property size size: Qt.size(field.width, field.height)
// The hub, where the pattern is strongest, wanders around the
// right of centre; the ring centres circle it at a breathing
// distance, which walks the moire's beat around the rings.
property point hub: Qt.point(0.62 * field.aspect + 0.05 * field.sweep(97, 0),
0.46 + 0.04 * field.sweep(131, 0.3))
readonly property real spread: 0.03 * (1 + 0.35 * field.sweep(71, 0.1))
readonly property real turn: 2 * Math.PI * field.clock / 53
property point ringA: Qt.point(hub.x - spread * Math.cos(turn) / 2,
hub.y - spread * Math.sin(turn) / 2)
property point ringB: Qt.point(hub.x + spread * Math.cos(turn) / 2,
hub.y + spread * Math.sin(turn) / 2)
property real reach: 0.95 + 0.06 * field.sweep(43, 0.7)
property real period: 1 / 110
property real cell: 1 / 70
property real angle: 0.26 + 0.03 * field.sweep(211, 0.2)
property real wave: (2 * Math.PI * field.clock / 16) % (2 * Math.PI)
// Amounts ease so a pattern change fades rather than cuts.
readonly property real alternate: 0.5 + 0.5 * field.sweep(360, 0)
property real moire: field.pattern === "halftone" ? 0
: field.pattern === "alternate" ? alternate : 1
property real halftone: field.pattern === "moire" ? 0
: field.pattern === "alternate" ? 1 - alternate : 1
Behavior on moire { enabled: field.pattern !== "alternate"; NumberAnimation { duration: 1500 } }
Behavior on halftone { enabled: field.pattern !== "alternate"; NumberAnimation { duration: 1500 } }
property color base: field.base
property color deep: field.deep
property color ink: field.ink
property color tone: field.tone
}
Timer {
running: field.speed > 0 && field.visible
repeat: true
interval: Math.round(1000 / Math.max(1, field.frameRate))
onTriggered: field.clock += field.speed * interval / 1000
}
}
neiam
/neiam-devices
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
3.7 KiB · text
History
f629a67