diff --git a/src/MediaFX/CMakeLists.txt b/src/MediaFX/CMakeLists.txt
index 8200d4c..39f276c 100644
--- a/src/MediaFX/CMakeLists.txt
+++ b/src/MediaFX/CMakeLists.txt
@@ -57,10 +57,11 @@ qt_add_qml_module(mediafx
qml/effects/MediaMixer.qml
qml/effects/CrossFadeMixer.qml
qml/effects/LumaMixer.qml
+ qml/effects/LumaGradientMixer.qml
)
qt_add_shaders(mediafx "shaders"
PREFIX
- "/shaders"
+ "/"
FILES
qml/effects/crossfade.frag
qml/effects/luma.frag
diff --git a/src/MediaFX/qml/effects/CrossFadeMixer.qml b/src/MediaFX/qml/effects/CrossFadeMixer.qml
index 395a4e9..d1d7555 100644
--- a/src/MediaFX/qml/effects/CrossFadeMixer.qml
+++ b/src/MediaFX/qml/effects/CrossFadeMixer.qml
@@ -17,5 +17,5 @@ import MediaFX
MediaMixer {
//required source //XXX how to make this required for users of us?
- fragmentShader: "qrc:/shaders/qml/effects/crossfade.frag.qsb"
+ fragmentShader: "qrc:/qml/effects/crossfade.frag.qsb"
}
diff --git a/src/MediaFX/qml/effects/LumaGradientMixer.qml b/src/MediaFX/qml/effects/LumaGradientMixer.qml
new file mode 100644
index 0000000..e870a67
--- /dev/null
+++ b/src/MediaFX/qml/effects/LumaGradientMixer.qml
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 Andrew Wason
+//
+// This file is part of mediaFX.
+//
+// mediaFX is free software: you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// mediaFX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mediaFX.
+// If not, see .
+
+import QtQuick
+import QtQuick.Shapes
+import MediaFX
+
+LumaMixer {
+ id: root
+ property alias fillGradient: path.fillGradient
+ Shape {
+ ShapePath {
+ id: path
+ scale: Qt.size(root.width, root.height)
+ PathPolyline {
+ path: [Qt.point(0, 0), Qt.point(0, 1), Qt.point(1, 1), Qt.point(1, 0), Qt.point(0, 0)]
+ }
+ }
+ }
+}
diff --git a/src/MediaFX/qml/effects/LumaMixer.qml b/src/MediaFX/qml/effects/LumaMixer.qml
index a6f003c..8278fcc 100644
--- a/src/MediaFX/qml/effects/LumaMixer.qml
+++ b/src/MediaFX/qml/effects/LumaMixer.qml
@@ -20,10 +20,10 @@ MediaMixer {
id: root
default required property Item luma
- property real transitionWidth: root.width
- readonly property real premultipliedTransitionWidth: root.time * transitionWidth + 1.0
+ property real transitionWidth: 1.0
+ readonly property real premultipliedTransitionWidth: root.time * (transitionWidth + 1.0)
- fragmentShader: "qrc:/shaders/qml/effects/luma.frag.qsb"
+ fragmentShader: "qrc:/qml/effects/luma.frag.qsb"
state: "default"
states: State {
diff --git a/src/MediaFX/qml/effects/luma.frag b/src/MediaFX/qml/effects/luma.frag
index f104bab..f4d8ca8 100644
--- a/src/MediaFX/qml/effects/luma.frag
+++ b/src/MediaFX/qml/effects/luma.frag
@@ -18,7 +18,6 @@ layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
- float time;
float transitionWidth;
float premultipliedTransitionWidth;
};
@@ -30,27 +29,8 @@ void main() {
vec4 dp = texture(dest, qt_TexCoord0);
vec4 lp = texture(luma, qt_TexCoord0);
-
- vec4 m = clamp((lp * vec4(transitionWidth) - vec4(transitionWidth)) + vec4(premultipliedTransitionWidth), vec4(0.0), vec4(1.0));
+ // Based on https://github.com/j-b-m/movit/blob/master/luma_mix_effect.frag
+ // premultipliedTransitionWidth = time * (transitionWidth + 1.0)
+ float m = clamp((lp.r * transitionWidth - transitionWidth) + premultipliedTransitionWidth, 0.0, 1.0);
fragColor = mix(sp, dp, m) * qt_Opacity;
-
-
-/*
- float m = clamp((lp.r * transitionWidth - transitionWidth) + (premultipliedTransitionWidth), 0.0, 1.0);
- fragColor = mix(sp, dp, m) * qt_Opacity;
-*/
-
- //fragColor = vec4(lp.rgb, 1.0);
- //fragColor = vec4(mix(sp.rgb, dp.rgb, m.rgb), 1.0) * qt_Opacity;
- //fragColor = vec4(1.0, 0.0, 0.0, 1.0);
-
-/*XXX
- float w = PREFIX(transition_width);
- float luma = INPUT3(tc).x;
- if (PREFIX(bool_inverse)) {
- luma = 1.0 - luma;
- }
- float m = clamp((luma * w - w) + PREFIX(progress_mul_w_plus_one), 0.0, 1.0);
- return mix(first, second, m);
-*/
}
\ No newline at end of file
diff --git a/src/MediaFX/session.cpp b/src/MediaFX/session.cpp
index eab7dfa..f1b34f9 100644
--- a/src/MediaFX/session.cpp
+++ b/src/MediaFX/session.cpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -104,6 +105,7 @@ void Session::quickViewStatusChanged(QQuickView::Status status)
if (status == QQuickView::Error) {
emit exitApp(1);
} else if (status == QQuickView::Ready) {
+ quickView->rootObject()->setEnabled(false);
QCoreApplication::postEvent(this, new QEvent(renderEventType));
}
}
diff --git a/tools/qml/LumaMixerViewer.qml b/tools/qml/LumaMixerViewer.qml
new file mode 100644
index 0000000..5c63a2b
--- /dev/null
+++ b/tools/qml/LumaMixerViewer.qml
@@ -0,0 +1,160 @@
+// Copyright (C) 2024 Andrew Wason
+//
+// This file is part of mediaFX.
+//
+// mediaFX is free software: you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// mediaFX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mediaFX.
+// If not, see .
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Shapes
+import MediaFX
+import MediaFX.Viewer
+
+Rectangle {
+ SystemPalette {
+ id: palette
+ colorGroup: SystemPalette.Active
+ }
+ color: palette.window
+ width: layout.implicitWidth
+ height: layout.implicitHeight
+
+ ColumnLayout {
+ id: layout
+ MediaMixerViewer {
+ mixer: linearMixer
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ ColumnLayout {
+ anchors.fill: parent
+ LabeledSlider {
+ id: x1Slider
+ label: "x1"
+ to: linearMixer.width
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: y1Slider
+ label: "y1"
+ to: linearMixer.height
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: x2Slider
+ label: "x2"
+ to: linearMixer.width
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: y2Slider
+ label: "y2"
+ to: linearMixer.height
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: tw1Slider
+ label: "transitionWidth"
+ to: linearMixer.width
+ Layout.fillWidth: true
+ }
+ LumaGradientMixer {
+ id: linearMixer
+ transitionWidth: tw1Slider.value
+ fillGradient: LinearGradient {
+ x1: x1Slider.value
+ y1: y1Slider.value
+ x2: x2Slider.value
+ y2: y2Slider.value
+ GradientStop {
+ position: 0.0
+ color: "white"
+ }
+ GradientStop {
+ position: 1.0
+ color: "black"
+ }
+ }
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ MediaMixerViewer {
+ mixer: conicalMixer
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ ColumnLayout {
+ anchors.fill: parent
+ LabeledSlider {
+ id: angleSlider
+ label: "angle"
+ to: 360
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: centerXSlider
+ label: "centerX"
+ to: conicalMixer.width
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: centerYSlider
+ label: "centerY"
+ to: conicalMixer.height
+ Layout.fillWidth: true
+ }
+ LabeledSlider {
+ id: tw2Slider
+ label: "transitionWidth"
+ to: conicalMixer.width
+ Layout.fillWidth: true
+ }
+ LumaGradientMixer {
+ id: conicalMixer
+ transitionWidth: tw2Slider.value
+ fillGradient: ConicalGradient {
+ angle: angleSlider.value
+ centerX: centerXSlider.value
+ centerY: centerYSlider.value
+ GradientStop {
+ position: 0.0
+ color: "white"
+ }
+ GradientStop {
+ position: 1.0
+ color: "black"
+ }
+ }
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ component LabeledSlider: RowLayout {
+ property alias label: label.text
+ property alias from: slider.from
+ property alias to: slider.to
+ property alias value: slider.value
+ Label {
+ id: label
+ }
+ Slider {
+ id: slider
+ hoverEnabled: true
+ ToolTip.delay: 1000
+ ToolTip.visible: hovered
+ ToolTip.text: slider.value
+ Layout.fillWidth: true
+ }
+ }
+}
diff --git a/tools/viewer/CMakeLists.txt b/tools/viewer/CMakeLists.txt
index 677aba9..cbac996 100644
--- a/tools/viewer/CMakeLists.txt
+++ b/tools/viewer/CMakeLists.txt
@@ -22,7 +22,7 @@ target_link_libraries(mediafxviewer PUBLIC mediafx mediafxplugin)
qt_add_qml_module(mediafxviewer
URI MediaFX.Viewer
QML_FILES
- qml/MediaMixerHarness.qml
+ qml/MediaMixerViewer.qml
)
install(TARGETS mediafxviewer RUNTIME DESTINATION)
diff --git a/tools/viewer/qml/MediaMixerHarness.qml b/tools/viewer/qml/MediaMixerViewer.qml
similarity index 69%
rename from tools/viewer/qml/MediaMixerHarness.qml
rename to tools/viewer/qml/MediaMixerViewer.qml
index a590d0c..84fd1a4 100644
--- a/tools/viewer/qml/MediaMixerHarness.qml
+++ b/tools/viewer/qml/MediaMixerViewer.qml
@@ -1,3 +1,17 @@
+// Copyright (C) 2024 Andrew Wason
+//
+// This file is part of mediaFX.
+//
+// mediaFX is free software: you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// mediaFX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mediaFX.
+// If not, see .
import QtQuick
import QtQuick.Shapes
import QtQuick.Layouts
@@ -7,27 +21,25 @@ import MediaFX
Item {
id: root
- default property alias mixer: mixerContainer.data
+ default property alias data: mixerContainer.data
+ required property Item mixer
- height: 400
+ implicitHeight: 400
+ implicitWidth: 400
state: "default"
- width: 400
states: State {
name: "default"
PropertyChanges {
- anchors.fill: mixerContainer
dest: destItem
source: sourceItem
- target: root.mixer[0]
time: time.value
+ target: root.mixer
}
}
ColumnLayout {
- id: layout
-
anchors.fill: parent
Item {