diff --git a/CMakeLists.txt b/CMakeLists.txt index 9110d304ea1689ddf45538cf15e7252e2485ebd4..5da19acc7d5adfc6c1e759945451b1ea62234623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(plasma-luna3) @@ -7,4 +7,6 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) find_package(KF6Plasma REQUIRED) +add_custom_command(OUTPUT shadow.gsb COMMAND "/usr/lib/qt6/bin/qsb package/contents/ui/shadow.frag --qt6 -o shadow.gsb") + plasma_install_package(package org.kde.userbase.plasma.luna3) diff --git a/package/contents/ui/LunaIcon.qml b/package/contents/ui/LunaIcon.qml index 6da061d985f046693902a387b7d38dc3f0e6dbe5..2ffcaf9065a8dbf0b07af5cddac7e791ecd30cbc 100644 --- a/package/contents/ui/LunaIcon.qml +++ b/package/contents/ui/LunaIcon.qml @@ -21,8 +21,8 @@ */ -import Qt5Compat.GraphicalEffects -import QtQuick 2.1 +import QtQuick 2.14 +import QtQuick.Shapes import org.kde.ksvg as KSvg import org.kde.plasma.core as PlasmaCore import org.kde.plasma.plasmoid @@ -45,177 +45,241 @@ Item { Item { id: lunaBackground - visible: false anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: Math.min(parent.width, parent.height) + visible: false } - KSvg.SvgItem { - id: lunaSvgItem + Item { + id: lunaTexture - imagePath: lunarImage === '' ? '' : Qt.resolvedUrl("../data/" + lunarImage) - visible: false anchors.centerIn: parent width: lunaBackground.width height: lunaBackground.height - // Rotation to compensate the moon's image basic position to a north pole view - transformOrigin: Item.Center - rotation: -lunarImageTweak - } - - Canvas { - id: lunaCanvas + visible: false + layer.enabled: true + layer.smooth: true - property string lunarImage: lunaIcon.lunarImage - property string diskColor: lunaIcon.diskColor + KSvg.SvgItem { + id: lunaSvgItem - width: lunaBackground.width - height: lunaBackground.height - visible: false - anchors.centerIn: parent - contextType: "2d" - onLunarImageChanged: requestPaint() - onDiskColorChanged: requestPaint() - onPaint: { - var radius = Math.floor(height / 2); - context.reset(); - context.globalAlpha = (lunarImage === '') ? 1 : 0; - context.fillStyle = diskColor; - context.translate(radius, radius); - context.beginPath(); - context.arc(0, 0, radius, 0, 2 * Math.PI); - context.closePath(); - context.fill(); + imagePath: lunarImage === '' ? '' : Qt.resolvedUrl("../data/" + lunarImage) + visible: true + anchors.centerIn: parent + width: lunaBackground.width + height: lunaBackground.height + // Rotation to compensate the moon's image basic position to a north pole view + transformOrigin: Item.Center + rotation: latitude - 90 - lunarImageTweak } - } - Canvas { - id: shadow + Shape { + id: lunaCanvas - property int latitude: lunaIcon.latitude - property int theta: lunaIcon.theta - property bool showShadow: lunaIcon.showShadow - property bool showGrid: lunaIcon.showGrid - property bool showTycho: lunaIcon.showTycho - property bool showCopernicus: lunaIcon.showCopernicus + property string lunarImage: lunaIcon.lunarImage + property string diskColor: lunaIcon.diskColor - function radians(deg) { - return deg / 180 * Math.PI; - } + opacity: (lunarImage === '') ? 1 : 0 + width: lunaBackground.width + height: lunaBackground.height + visible: true + anchors.centerIn: parent + preferredRendererType: Shape.CurveRenderer - function marker(radius, latitude, longitude) { - var dy = radius * Math.sin(radians(latitude)); - var dx = radius * Math.cos(radians(latitude)) * Math.sin(radians(longitude)); - // console.log("dx: " + dx.toString()); - // console.log("dy: " + dy.toString()); - context.beginPath(); - context.strokeStyle = "#FF0000"; - context.arc(dx, -dy, 5, 0, 2 * Math.PI); - context.moveTo(dx - 5, -dy - 5); - context.lineTo(dx + 5, -dy + 5); - context.moveTo(dx - 5, -dy + 5); - context.lineTo(dx + 5, -dy - 5); - context.stroke(); - } + ShapePath { + fillColor: diskColor + strokeWidth: -1 //no stroke + + PathAngleArc { + property int radius: Math.floor(height / 2) + + centerX: radius + centerY: radius + radiusY: radius + radiusX: radius + startAngle: 0 + sweepAngle: 360 + } - function grid(radius) { - context.beginPath(); - context.strokeStyle = "#FF4040"; - context.moveTo(0, -radius); - context.lineTo(0, radius); - context.moveTo(-radius, 0); - context.lineTo(radius, 0); - context.stroke(); - context.beginPath(); - context.strokeStyle = "#40FF40"; - for (var ll = 10; ll < 65; ll += 10) { - var dy = radius * Math.sin(radians(ll)); - context.moveTo(-radius, dy); - context.lineTo(radius, dy); - context.moveTo(-radius, -dy); - context.lineTo(radius, -dy); } - context.stroke(); + } - width: lunaBackground.width - height: lunaBackground.height - visible: false - anchors.centerIn: parent - contextType: "2d" - onLatitudeChanged: requestPaint() - onThetaChanged: requestPaint() - onShowGridChanged: requestPaint() - onShowTychoChanged: requestPaint() - onShowCopernicusChanged: requestPaint() - onShowShadowChanged: requestPaint() - onPaint: { - var radius = Math.floor(height / 2); - var cosTheta = Math.cos(theta / 180 * Math.PI); - var counterclockwisep = (theta < 180); - context.reset(); - context.globalAlpha = 0.9; - context.translate(radius, radius); - if (showShadow) { - if (theta != 180) { - context.beginPath(); - context.fillStyle = '#000000'; - context.strokeStyle = '#000000'; - context.arc(0, 0, radius, -0.5 * Math.PI, 0.5 * Math.PI, counterclockwisep); - if ((theta % 180) != 90) { - context.scale(cosTheta, 1); - context.arc(0, 0, radius, 0.5 * Math.PI, -0.5 * Math.PI, counterclockwisep); + Canvas { + id: shadow + + property int latitude: lunaIcon.latitude + property int theta: lunaIcon.theta + property bool showShadow: lunaIcon.showShadow + + width: lunaBackground.width + height: lunaBackground.height + visible: true + anchors.centerIn: parent + contextType: "2d" + onLatitudeChanged: requestPaint() + onThetaChanged: requestPaint() + onShowShadowChanged: requestPaint() + onPaint: { + context.reset(); + if (showShadow) { + var radius = Math.floor(height / 2); + var cosTheta = Math.cos(theta / 180 * Math.PI); + var counterclockwisep = (theta < 180); + context.globalAlpha = 0.9; + context.translate(radius, radius); + context.rotate((latitude - 90) / 180 * Math.PI); + if (theta != 180) { + context.beginPath(); + context.fillStyle = '#000000'; + context.strokeStyle = '#000000'; + context.arc(0, 0, radius, -0.5 * Math.PI, 0.5 * Math.PI, counterclockwisep); + if ((theta % 180) != 90) { + context.scale(cosTheta, 1); + context.arc(0, 0, radius, 0.5 * Math.PI, -0.5 * Math.PI, counterclockwisep); + } + context.closePath(); + context.fill(); + context.stroke(); } - context.closePath(); - context.fill(); - context.stroke(); } - } else { - // Calibration markers - if (showGrid) - grid(radius); + } + } + + Canvas { + id: markers + + property int latitude: lunaIcon.latitude + property int theta: lunaIcon.theta + property bool showShadow: lunaIcon.showShadow + property bool showGrid: lunaIcon.showGrid + property bool showTycho: lunaIcon.showTycho + property bool showCopernicus: lunaIcon.showCopernicus + + function radians(deg) { + return deg / 180 * Math.PI; + } + + function marker(radius, latitude, longitude) { + var dy = radius * Math.sin(radians(latitude)); + var dx = radius * Math.cos(radians(latitude)) * Math.sin(radians(longitude)); + // console.log("dx: " + dx.toString()); + // console.log("dy: " + dy.toString()); + context.beginPath(); + context.strokeStyle = "#FF0000"; + context.arc(dx, -dy, 5, 0, 2 * Math.PI); + context.moveTo(dx - 5, -dy - 5); + context.lineTo(dx + 5, -dy + 5); + context.moveTo(dx - 5, -dy + 5); + context.lineTo(dx + 5, -dy - 5); + context.stroke(); + } + + function grid(radius) { + context.beginPath(); + context.strokeStyle = "#FF4040"; + context.moveTo(0, -radius); + context.lineTo(0, radius); + context.moveTo(-radius, 0); + context.lineTo(radius, 0); + context.stroke(); + context.beginPath(); + context.strokeStyle = "#40FF40"; + for (var ll = 10; ll < 65; ll += 10) { + var dy = radius * Math.sin(radians(ll)); + context.moveTo(-radius, dy); + context.lineTo(radius, dy); + context.moveTo(-radius, -dy); + context.lineTo(radius, -dy); + } + context.stroke(); + } + + width: lunaBackground.width + height: lunaBackground.height + visible: true + anchors.centerIn: parent + contextType: "2d" + onLatitudeChanged: requestPaint() + onThetaChanged: requestPaint() + onShowGridChanged: requestPaint() + onShowTychoChanged: requestPaint() + onShowCopernicusChanged: requestPaint() + onShowShadowChanged: requestPaint() + onPaint: { + context.reset(); + if (!showShadow) { + var radius = Math.floor(height / 2); + var cosTheta = Math.cos(theta / 180 * Math.PI); + var counterclockwisep = (theta < 180); + context.globalAlpha = 0.9; + context.translate(radius, radius); + context.rotate((latitude - 90) / 180 * Math.PI); + // Calibration markers + if (showGrid) + grid(radius); - // Tycho - if (showTycho) - marker(radius, -43, -11.5); + // Tycho + if (showTycho) + marker(radius, -43, -11.5); - // Copernicus - if (showCopernicus) - marker(radius, 9.6, -20); + // Copernicus + if (showCopernicus) + marker(radius, 9.6, -20); + } } } + } - Blend { - id: lunaSource + ShaderEffectSource { + id: lunaMask - anchors.fill: lunaBackground - source: lunaSvgItem - foregroundSource: lunaCanvas - mode: "normal" + anchors.centerIn: parent + width: lunaBackground.width + height: lunaBackground.height visible: false - } - // Shadow acts as a transparency mask - OpacityMask { - anchors.fill: lunaBackground - source: lunaSource - maskSource: shadow - invert: true - rotation: latitude - 90 - visible: transparentShadow + sourceItem: Shape { + opacity: 1 + width: lunaBackground.width + height: lunaBackground.height + visible: true + anchors.centerIn: parent + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: '#000000' + strokeWidth: -1 //no stroke + + PathAngleArc { + property int radius: Math.floor(height / 2) + + centerX: radius + centerY: radius + radiusY: radius + radiusX: radius + startAngle: 0 + sweepAngle: 360 + } + + } + + } + } - // Shadow is printed on top of the moon image - Blend { + ShaderEffect { + property variant source: lunaTexture + property variant shadow: shadow + property variant mask: lunaMask + property int transparent: transparentShadow + + visible: true anchors.fill: lunaBackground - source: lunaSource - foregroundSource: shadow - rotation: latitude - 90 - mode: "normal" - visible: !transparentShadow + fragmentShader: "shadow.gsb" } } diff --git a/package/contents/ui/shadow.frag b/package/contents/ui/shadow.frag new file mode 100644 index 0000000000000000000000000000000000000000..60b3f89d3654fab96016090eeadee5e4af4e493e --- /dev/null +++ b/package/contents/ui/shadow.frag @@ -0,0 +1,19 @@ +#version 440 +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + int transparent; + +}; +layout(binding = 1) uniform sampler2D source; +layout(binding = 2) uniform sampler2D shadow; +layout(binding = 3) uniform sampler2D mask; + +void main() { fragColor = texture(source, qt_TexCoord0) + * texture(mask, qt_TexCoord0).a + * (1 - texture(shadow, qt_TexCoord0).a * transparent) + * qt_Opacity ; +} +